aboutsummaryrefslogtreecommitdiff
path: root/pkg/tbtables/cfitsio
diff options
context:
space:
mode:
authorJoe Hunkeler <jhunkeler@gmail.com>2015-08-11 16:51:37 -0400
committerJoe Hunkeler <jhunkeler@gmail.com>2015-08-11 16:51:37 -0400
commit40e5a5811c6ffce9b0974e93cdd927cbcf60c157 (patch)
tree4464880c571602d54f6ae114729bf62a89518057 /pkg/tbtables/cfitsio
downloadiraf-osx-40e5a5811c6ffce9b0974e93cdd927cbcf60c157.tar.gz
Repatch (from linux) of OSX IRAF
Diffstat (limited to 'pkg/tbtables/cfitsio')
-rw-r--r--pkg/tbtables/cfitsio/Licence.txt46
-rw-r--r--pkg/tbtables/cfitsio/Makefile.in145
-rw-r--r--pkg/tbtables/cfitsio/README151
-rw-r--r--pkg/tbtables/cfitsio/README.MacOS31
-rw-r--r--pkg/tbtables/cfitsio/buffers.c1448
-rw-r--r--pkg/tbtables/cfitsio/cfileio.c5572
-rw-r--r--pkg/tbtables/cfitsio/cfitsio.doc8406
-rw-r--r--pkg/tbtables/cfitsio/cfitsio.ps12896
-rw-r--r--pkg/tbtables/cfitsio/cfitsio.tex9422
-rw-r--r--pkg/tbtables/cfitsio/cfitsio.toc118
-rw-r--r--pkg/tbtables/cfitsio/cfitsio_mac.sit.hqx1
-rw-r--r--pkg/tbtables/cfitsio/cfortran.doc2051
-rw-r--r--pkg/tbtables/cfitsio/cfortran.h2397
-rw-r--r--pkg/tbtables/cfitsio/changes.txt2521
-rw-r--r--pkg/tbtables/cfitsio/checksum.c508
-rw-r--r--pkg/tbtables/cfitsio/compress.c155
-rw-r--r--pkg/tbtables/cfitsio/compress.h212
-rwxr-xr-xpkg/tbtables/cfitsio/configure1886
-rw-r--r--pkg/tbtables/cfitsio/configure.in352
-rw-r--r--pkg/tbtables/cfitsio/cookbook.c571
-rw-r--r--pkg/tbtables/cfitsio/cookbook.f772
-rw-r--r--pkg/tbtables/cfitsio/drvrfile.c730
-rw-r--r--pkg/tbtables/cfitsio/drvrmem.c1163
-rw-r--r--pkg/tbtables/cfitsio/drvrnet.c2587
-rw-r--r--pkg/tbtables/cfitsio/drvrsmem.c953
-rw-r--r--pkg/tbtables/cfitsio/drvrsmem.h179
-rw-r--r--pkg/tbtables/cfitsio/editcol.c2068
-rw-r--r--pkg/tbtables/cfitsio/edithdu.c793
-rw-r--r--pkg/tbtables/cfitsio/eval.l512
-rw-r--r--pkg/tbtables/cfitsio/eval.y5227
-rw-r--r--pkg/tbtables/cfitsio/eval_defs.h153
-rw-r--r--pkg/tbtables/cfitsio/eval_f.c2293
-rw-r--r--pkg/tbtables/cfitsio/eval_l.c2219
-rw-r--r--pkg/tbtables/cfitsio/eval_tab.h41
-rw-r--r--pkg/tbtables/cfitsio/eval_y.c6686
-rw-r--r--pkg/tbtables/cfitsio/f77.inc31
-rw-r--r--pkg/tbtables/cfitsio/f77_wrap.h278
-rw-r--r--pkg/tbtables/cfitsio/f77_wrap1.c960
-rw-r--r--pkg/tbtables/cfitsio/f77_wrap2.c1081
-rw-r--r--pkg/tbtables/cfitsio/fitscopy.c64
-rw-r--r--pkg/tbtables/cfitsio/fitscore.c7007
-rw-r--r--pkg/tbtables/cfitsio/fitsio.doc6137
-rw-r--r--pkg/tbtables/cfitsio/fitsio.h1565
-rw-r--r--pkg/tbtables/cfitsio/fitsio.ps9852
-rw-r--r--pkg/tbtables/cfitsio/fitsio.tex7203
-rw-r--r--pkg/tbtables/cfitsio/fitsio.toc90
-rw-r--r--pkg/tbtables/cfitsio/fitsio2.h1135
-rw-r--r--pkg/tbtables/cfitsio/getcol.c919
-rw-r--r--pkg/tbtables/cfitsio/getcolb.c2111
-rw-r--r--pkg/tbtables/cfitsio/getcold.c1768
-rw-r--r--pkg/tbtables/cfitsio/getcole.c1775
-rw-r--r--pkg/tbtables/cfitsio/getcoli.c2043
-rw-r--r--pkg/tbtables/cfitsio/getcolj.c3856
-rw-r--r--pkg/tbtables/cfitsio/getcolk.c2037
-rw-r--r--pkg/tbtables/cfitsio/getcoll.c612
-rw-r--r--pkg/tbtables/cfitsio/getcols.c743
-rw-r--r--pkg/tbtables/cfitsio/getcolsb.c2133
-rw-r--r--pkg/tbtables/cfitsio/getcolui.c2050
-rw-r--r--pkg/tbtables/cfitsio/getcoluj.c2044
-rw-r--r--pkg/tbtables/cfitsio/getcoluk.c2059
-rw-r--r--pkg/tbtables/cfitsio/getkey.c2544
-rw-r--r--pkg/tbtables/cfitsio/group.c6418
-rw-r--r--pkg/tbtables/cfitsio/group.h65
-rw-r--r--pkg/tbtables/cfitsio/grparser.c1365
-rw-r--r--pkg/tbtables/cfitsio/grparser.h185
-rw-r--r--pkg/tbtables/cfitsio/histo.c1300
-rw-r--r--pkg/tbtables/cfitsio/imcompress.c2997
-rw-r--r--pkg/tbtables/cfitsio/iraffits.c1975
-rw-r--r--pkg/tbtables/cfitsio/iter_a.c147
-rw-r--r--pkg/tbtables/cfitsio/iter_a.f224
-rw-r--r--pkg/tbtables/cfitsio/iter_a.fit1111
-rw-r--r--pkg/tbtables/cfitsio/iter_b.c114
-rw-r--r--pkg/tbtables/cfitsio/iter_b.f193
-rw-r--r--pkg/tbtables/cfitsio/iter_b.fitbin0 -> 408960 bytes
-rw-r--r--pkg/tbtables/cfitsio/iter_c.c171
-rw-r--r--pkg/tbtables/cfitsio/iter_c.f347
-rw-r--r--pkg/tbtables/cfitsio/iter_c.fit701
-rw-r--r--pkg/tbtables/cfitsio/listhead.c62
-rw-r--r--pkg/tbtables/cfitsio/longnam.h538
-rw-r--r--pkg/tbtables/cfitsio/make_dfloat.com83
-rw-r--r--pkg/tbtables/cfitsio/make_gfloat.com81
-rw-r--r--pkg/tbtables/cfitsio/make_ieee.com80
-rw-r--r--pkg/tbtables/cfitsio/makefile.bc496
-rw-r--r--pkg/tbtables/cfitsio/makefile.os222
-rw-r--r--pkg/tbtables/cfitsio/makefile.vcc691
-rw-r--r--pkg/tbtables/cfitsio/makepc.bat69
-rw-r--r--pkg/tbtables/cfitsio/mkpkg66
-rw-r--r--pkg/tbtables/cfitsio/modkey.c1614
-rw-r--r--pkg/tbtables/cfitsio/pctype.h155
-rw-r--r--pkg/tbtables/cfitsio/pliocomp.c331
-rw-r--r--pkg/tbtables/cfitsio/putcol.c1714
-rw-r--r--pkg/tbtables/cfitsio/putcolb.c1031
-rw-r--r--pkg/tbtables/cfitsio/putcold.c1147
-rw-r--r--pkg/tbtables/cfitsio/putcole.c1154
-rw-r--r--pkg/tbtables/cfitsio/putcoli.c1039
-rw-r--r--pkg/tbtables/cfitsio/putcolj.c2018
-rw-r--r--pkg/tbtables/cfitsio/putcolk.c1067
-rw-r--r--pkg/tbtables/cfitsio/putcoll.c355
-rw-r--r--pkg/tbtables/cfitsio/putcols.c284
-rw-r--r--pkg/tbtables/cfitsio/putcolsb.c1030
-rw-r--r--pkg/tbtables/cfitsio/putcolu.c587
-rw-r--r--pkg/tbtables/cfitsio/putcolui.c1022
-rw-r--r--pkg/tbtables/cfitsio/putcoluj.c1029
-rw-r--r--pkg/tbtables/cfitsio/putcoluk.c1046
-rw-r--r--pkg/tbtables/cfitsio/putkey.c2706
-rw-r--r--pkg/tbtables/cfitsio/quantize.c613
-rw-r--r--pkg/tbtables/cfitsio/quick.ps3850
-rw-r--r--pkg/tbtables/cfitsio/quick.tex2156
-rw-r--r--pkg/tbtables/cfitsio/quick.toc25
-rw-r--r--pkg/tbtables/cfitsio/region.c919
-rw-r--r--pkg/tbtables/cfitsio/region.h80
-rw-r--r--pkg/tbtables/cfitsio/ricecomp.c510
-rw-r--r--pkg/tbtables/cfitsio/ricecomp.h107
-rw-r--r--pkg/tbtables/cfitsio/sample.tpl121
-rw-r--r--pkg/tbtables/cfitsio/scalnull.c230
-rw-r--r--pkg/tbtables/cfitsio/smem.c67
-rw-r--r--pkg/tbtables/cfitsio/speed.c485
-rw-r--r--pkg/tbtables/cfitsio/swapproc.c98
-rw-r--r--pkg/tbtables/cfitsio/testf77.f2488
-rw-r--r--pkg/tbtables/cfitsio/testf77.out746
-rw-r--r--pkg/tbtables/cfitsio/testf77.stdbin0 -> 66240 bytes
-rw-r--r--pkg/tbtables/cfitsio/testprog.c2588
-rw-r--r--pkg/tbtables/cfitsio/testprog.out797
-rw-r--r--pkg/tbtables/cfitsio/testprog.std48
-rw-r--r--pkg/tbtables/cfitsio/testprog.tpt12
-rw-r--r--pkg/tbtables/cfitsio/vmsieee.c130
-rw-r--r--pkg/tbtables/cfitsio/vmsieeed.mar137
-rw-r--r--pkg/tbtables/cfitsio/vmsieeer.mar106
-rw-r--r--pkg/tbtables/cfitsio/wcssub.c327
-rw-r--r--pkg/tbtables/cfitsio/wcsutil.c72
-rw-r--r--pkg/tbtables/cfitsio/wcsutil.c.OLD786
-rw-r--r--pkg/tbtables/cfitsio/winDumpExts.mak191
-rw-r--r--pkg/tbtables/cfitsio/windumpexts.c503
133 files changed, 194384 insertions, 0 deletions
diff --git a/pkg/tbtables/cfitsio/Licence.txt b/pkg/tbtables/cfitsio/Licence.txt
new file mode 100644
index 00000000..f7698098
--- /dev/null
+++ b/pkg/tbtables/cfitsio/Licence.txt
@@ -0,0 +1,46 @@
+Copyright (Unpublished--all rights reserved under the copyright laws of
+the United States), U.S. Government as represented by the Administrator
+of the National Aeronautics and Space Administration. No copyright is
+claimed in the United States under Title 17, U.S. Code.
+
+Permission to freely use, copy, modify, and distribute this software
+and its documentation without fee is hereby granted, provided that this
+copyright notice and disclaimer of warranty appears in all copies.
+(However, see the restriction on the use of the gzip compression code,
+below).
+
+DISCLAIMER:
+
+THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND,
+EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO,
+ANY WARRANTY THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY
+IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE, AND FREEDOM FROM INFRINGEMENT, AND ANY WARRANTY THAT THE
+DOCUMENTATION WILL CONFORM TO THE SOFTWARE, OR ANY WARRANTY THAT THE
+SOFTWARE WILL BE ERROR FREE. IN NO EVENT SHALL NASA BE LIABLE FOR ANY
+DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, INDIRECT, SPECIAL OR
+CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, OR IN ANY WAY
+CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY,
+CONTRACT, TORT , OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY
+PERSONS OR PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED
+FROM, OR AROSE OUT OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR
+SERVICES PROVIDED HEREUNDER.
+
+The file compress.c contains (slightly modified) source code that
+originally came from gzip-1.2.4, copyright (C) 1992-1993 by Jean-loup
+Gailly. This gzip code is distributed under the GNU General Public
+Licence and thus requires that any software that uses the CFITSIO
+library (which in turn uses the gzip code) must conform to the
+provisions in the GNU General Public License. A copy of the GNU
+licence is included at the beginning of compress.c file.
+
+An alternate version of the compress.c file (called compress_alternate.c)
+is provided for users who want to use the CFITSIO library but are
+unwilling or unable to publicly release their software under the terms
+of the GNU General Public License. This alternate version contains
+non-functional stubs for the file compression and uncompression
+routines used by CFITSIO. Replace the file 'compress.c' with
+'compress_alternate.c' before compiling the CFITSIO library. This will
+produce a version of CFITSIO which does not support reading or writing
+compressed FITS files but is otherwise identical to the standard
+version.
diff --git a/pkg/tbtables/cfitsio/Makefile.in b/pkg/tbtables/cfitsio/Makefile.in
new file mode 100644
index 00000000..72ce5904
--- /dev/null
+++ b/pkg/tbtables/cfitsio/Makefile.in
@@ -0,0 +1,145 @@
+#
+# Makefile for cfitsio library:
+# libcfits.a
+#
+# Oct-96 : original version by
+#
+# JDD/WDP
+# NASA GSFC
+# Oct 1996
+#
+# 25-Jan-01 : removed conditional drvrsmem.c compilation because this
+# is now handled within the source file itself.
+# 09-Mar-98 : modified to conditionally compile drvrsmem.c. Also
+# changes to target all (deleted clean), added DEFS, LIBS, added
+# DEFS to .c.o, added SOURCES_SHMEM and MY_SHMEM, expanded getcol*
+# and putcol* in SOURCES, modified OBJECTS, mv changed to /bin/mv
+# (to bypass aliasing), cp changed to /bin/cp, add smem and
+# testprog targets. See also changes and comments in configure.in
+#
+
+CFITSIO_LIB = @CFITSIO_PREFIX@/lib
+CFITSIO_INCLUDE = @CFITSIO_PREFIX@/include
+
+SHELL = /bin/sh
+RANLIB = @RANLIB@
+CC = @CC@
+CFLAGS = @CFLAGS@
+FC = @FC@
+LDFLAGS = $(CFLAGS)
+DEFS = @DEFS@
+LIBS = @LIBS@
+FLEX = flex
+BISON = bison
+
+SHLIB_LD = @SHLIB_LD@
+SHLIB_SUFFIX = @SHLIB_SUFFIX@
+
+.c.o:
+ $(CC) -c $(CFLAGS) $(DEFS) $<
+
+
+CORE_SOURCES = buffers.c cfileio.c checksum.c compress.c drvrfile.c drvrmem.c \
+ drvrnet.c drvrsmem.c editcol.c edithdu.c eval_l.c eval_y.c \
+ eval_f.c fitscore.c getcol.c getcolb.c getcold.c getcole.c \
+ getcoli.c getcolj.c getcolk.c getcoll.c getcols.c getcolsb.c \
+ getcoluk.c getcolui.c getcoluj.c getkey.c group.c grparser.c \
+ histo.c iraffits.c \
+ modkey.c putcol.c putcolb.c putcold.c putcole.c putcoli.c \
+ putcolj.c putcolk.c putcoluk.c putcoll.c putcols.c putcolsb.c \
+ putcolu.c putcolui.c putcoluj.c putkey.c region.c scalnull.c \
+ swapproc.c wcssub.c wcsutil.c imcompress.c quantize.c ricecomp.c \
+ pliocomp.c
+
+SOURCES = ${CORE_SOURCES} @F77_WRAPPERS@
+
+OBJECTS = ${SOURCES:.c=.o}
+
+CORE_OBJECTS = ${CORE_SOURCES:.c=.o}
+
+
+FITSIO_SRC = f77_wrap1.c f77_wrap2.c f77_wrap3.c f77_wrap4.c
+
+# ============ description of all targets =============
+# - <<-- ignore error code
+
+all:
+ @if [ "x${FC}" = x ]; then \
+ ${MAKE} all-nofitsio; \
+ else \
+ ${MAKE} stand_alone; \
+ fi
+
+all-nofitsio:
+ ${MAKE} stand_alone "FITSIO_SRC="
+
+stand_alone: libcfitsio.a
+
+libcfitsio.a: ${OBJECTS}
+ ar rv libcfitsio.a ${OBJECTS}; \
+ ${RANLIB} libcfitsio.a;
+
+shared: libcfitsio${SHLIB_SUFFIX}
+
+libcfitsio${SHLIB_SUFFIX}: ${OBJECTS}
+ ${SHLIB_LD} -o $@ ${OBJECTS}
+
+install: libcfitsio.a ${CFITSIO_LIB} ${CFITSIO_INCLUDE}
+ @if [ -f libcfitsio.a ]; then \
+ /bin/mv libcfitsio.a ${CFITSIO_LIB}; \
+ fi; \
+ if [ -f libcfitsio${SHLIB_SUFFIX} ]; then \
+ /bin/mv libcfitsio${SHLIB_SUFFIX} ${CFITSIO_LIB}; \
+ fi; \
+ /bin/cp fitsio.h fitsio2.h longnam.h drvrsmem.h ${CFITSIO_INCLUDE}/
+
+smem: smem.o libcfitsio.a ${OBJECTS}
+ ${CC} $(CFLAGS) $(DEFS) -o smem smem.o -L. -lcfitsio -lm
+
+testprog: testprog.o libcfitsio.a ${OBJECTS}
+ ${CC} $(CFLAGS) $(DEFS) -o testprog testprog.o -L. -lcfitsio -lm ${LIBS}
+
+fitscopy: fitscopy.o libcfitsio.a ${OBJECTS}
+ ${CC} $(CFLAGS) $(DEFS) -o fitscopy fitscopy.o -L. -lcfitsio -lm ${LIBS}
+
+speed: speed.o libcfitsio.a ${OBJECTS}
+ ${CC} $(CFLAGS) $(DEFS) -o speed speed.o -L. -lcfitsio -lm ${LIBS}
+
+imcopy: imcopy.o libcfitsio.a ${OBJECTS}
+ ${CC} $(CFLAGS) $(DEFS) -o imcopy imcopy.o -L. -lcfitsio -lm ${LIBS}
+
+listhead: listhead.o libcfitsio.a ${OBJECTS}
+ ${CC} $(CFLAGS) $(DEFS) -o listhead listhead.o -L. -lcfitsio -lm ${LIBS}
+
+cookbook: cookbook.o libcfitsio.a ${OBJECTS}
+ ${CC} $(CFLAGS) $(DEFS) -o cookbook cookbook.o -L. -lcfitsio -lm ${LIBS}
+
+eval: # Rebuild eval_* files from flex/bison source
+ $(FLEX) -t eval.l > eval_l.c1
+ /bin/sed -e 's/yy/ff/g' -e 's/YY/FF/g' eval_l.c1 > eval_l.c
+ /bin/rm -f eval_l.c1
+ $(BISON) -d -v -y eval.y
+ /bin/sed -e 's/yy/ff/g' -e 's/YY/FF/g' y.tab.c > eval_y.c
+ /bin/sed -e 's/yy/ff/g' -e 's/YY/FF/g' y.tab.h > eval_tab.h
+ /bin/rm -f y.tab.c y.tab.h
+
+clean:
+ - /bin/rm -f *.o libcfitsio.a libcfitsio${SHLIB_SUFFIX} \
+ smem testprog y.output
+
+distclean: clean
+ - /bin/rm -f Makefile config.*
+
+# Make target which outputs the list of the .o contained in the cfitsio lib
+# usefull to build a single big shared library containing Tcl/Tk and other
+# extensions. used for the Tcl Plugin.
+
+cfitsioLibObjs:
+ @echo ${CORE_OBJECTS}
+
+# This target actually builds the objects needed for the lib in the above
+# case
+objs: ${CORE_OBJECTS}
+
+${CFITSIO_LIB} ${CFITSIO_INCLUDE}:
+ @if [ ! -d $@ ]; then mkdir $@; fi
diff --git a/pkg/tbtables/cfitsio/README b/pkg/tbtables/cfitsio/README
new file mode 100644
index 00000000..bcd3123e
--- /dev/null
+++ b/pkg/tbtables/cfitsio/README
@@ -0,0 +1,151 @@
+ CFITSIO Interface Library
+
+CFITSIO is a library of ANSI C routines for reading and writing FITS
+format data files. A set of Fortran-callable wrapper routines are also
+included for the convenience of Fortran programmers. This README file
+gives a brief summary of how to build and test CFITSIO, but the CFITSIO
+User's Guide, found in the files cfitsio.doc (plain text), cfitsio.tex
+(LaTeX source file), or cfitsio.ps (postscript format), should be
+referenced for the latest and most complete information.
+
+BUILDING CFITSIO
+----------------
+
+The CFITSIO code is contained in about 40 *.c source files and several *.h
+header files. The CFITSIO library is built on Unix systems by typing:
+
+ > ./configure [--prefix=/target/installation/path]
+ > make (or 'make shared')
+ > make install (this step is optional)
+
+at the operating system prompt. The configure command customizes the
+Makefile for the particular system, then the `make' command compiles the
+source files and builds the library. Type `./configure' and not simply
+`configure' to ensure that the configure script in the current directory
+is run and not some other system-wide configure script. The optional
+'prefix' argument to configure gives the path to the directory where
+the CFITSIO library and include files should be installed via the later
+'make install' command. For example,
+
+ > ./configure --prefix=/usr1/local
+
+will cause the 'make install' command to copy the CFITSIO libcfitsio file
+to /usr1/local/lib and the necessary include files to /usr1/local/include
+(assuming of course that the process has permission to write to these
+directories).
+
+On VAX/VMS and ALPHA/VMS systems the make.com command file may be used
+to build the cfitsio.olb object library using the default G-floating
+point option for double variables. The make\_dfloat.com and make\_ieee.com
+files may be used instead to build the library with the other floating
+point options.
+
+A precompiled DLL version of CFITSIO is available for IBM-PC users of
+the Borland or Microsoft Visual C++ compilers in the files
+cfitsiodll_2xxx_borland.zip and cfitsiodll_2xxx_vcc.zip, where '2xxx'
+represents the current release number. These zip archives also
+contains other files and instructions on how to use the CFITSIO DLL
+library. The CFITSIO library may also be built from the source code
+using the makefile.bc or makefile.vcc files. Finally, the makepc.bat
+file gives an example of building CFITSIO with the Borland C++ v4.5
+compiler using simpler DOS commands.
+
+On OS/2 systems, CFITSIO can be built using the supplied makefile by
+typing 'make -f makefile.os2'. This makefile requires the GCC compiler
+and EMX library, which are available from many Internet sites
+containing OS/2 software, such as
+ftp-os2.nmsu.edu/pub/os2/dev/emx/v0.9c and
+ftp.leo.org/pub/comp/os/os2/leo/devtools/emx+gcc.
+
+When building on Mac OS-X, users should follow the Unix instructions,
+above. Previous MacOS versions of the cfitsio library can be built by
+(1) un binhex and unstuff cfitsio_mac.sit.hqx, (2) put CFitsioPPC.mcp
+in the cfitsio directory, and (3) load CFitsioPPC.mcp into CodeWarrior
+Pro 5 and make. This builds the cfitsio library for PPC. There are
+also targets for both the test program and the speed test program.
+
+To use the MacOS port you can add Cfitsio PPC.lib to your Codewarrior
+Pro 5 project. Note that this only has been tested for the PPC and
+probably won't work
+ on 68k macs.
+
+TESTING CFITSIO
+---------------
+
+The CFITSIO library should be tested by building and running
+the testprog.c program that is included with the release.
+On Unix systems, type:
+-
+ % make testprog
+ % testprog > testprog.lis
+ % diff testprog.lis testprog.out
+ % cmp testprog.fit testprog.std
+-
+ On VMS systems,
+(assuming cc is the name of the C compiler command), type:
+-
+ $ cc testprog.c
+ $ link testprog, cfitsio/lib
+ $ run testprog
+-
+The testprog program should produce a FITS file called `testprog.fit'
+that is identical to the testprog.std FITS file included in this
+release. The diagnostic messages (which were piped to the file
+testprog.lis in the Unix example) should be identical to the listing
+contained in the file testprog.out. The 'diff' and 'cmp' commands
+shown above should not report any differences in the files.
+
+USING CFITSIO
+-------------
+
+The CFITSIO User's Guide, contained in the files cfitsio.doc (plain
+text file) and cfitsio.ps (postscript file), provides detailed
+documentation about how to build and use the CFITSIO library.
+It contains a description of every user-callable routine in the
+CFITSIO interface.
+
+The cookbook.c file provides some sample routines for performing common
+operations on various types of FITS files. Programmers are urged to
+examine these routines for recommended programming practices when using
+CFITSIO. Users are free to copy or modify these routines for their own
+purposes.
+
+SUPPORTED PLATFORMS
+-------------------
+
+CFITSIO has currently been tested on the following platforms:
+
+ Operating System Compiler
+ ---------------- --------
+ OPERATING SYSTEM COMPILER
+ Sun OS gcc and cc (3.0.1)
+ Sun Solaris gcc and cc
+ Silicon Graphics IRIX gcc and cc
+ Silicon Graphics IRIX64 MIPS
+ Dec Alpha OSF/1 gcc and cc
+ DECstation Ultrix gcc
+ Dec Alpha OpenVMS cc
+ DEC VAX/VMS gcc and cc
+ HP-UX gcc
+ IBM AIX gcc
+ Linux gcc
+ MkLinux DR3
+ Windows 95/98/NT Borland C++ V4.5
+ Windows 95/98/NT/ME/XP Microsoft/Compaq Visual C++ v5.0, v6.0
+ Windows 95/98/NT Cygwin gcc
+ OS/2 gcc + EMX
+ Mac OS 7.1 or greater Metrowerks 10.+
+ Mac OS-X 10.1 or greater cc (gcc)
+
+CFITSIO will probably run on most other Unix platforms without
+modification. Cray supercomputers and IBM mainframe computers are
+currently not supported.
+
+Reports of any success or failure to run CFITSIO on other platforms
+would be appreciated. Any problem reports or suggestions for
+improvements are also welcome and should be sent to the primary author.
+
+-------------------------------------------------------------------------
+William D. Pence
+pence@tetra.gsfc.nasa.gov
+HEASARC, NASA/GSFC
diff --git a/pkg/tbtables/cfitsio/README.MacOS b/pkg/tbtables/cfitsio/README.MacOS
new file mode 100644
index 00000000..6deedcff
--- /dev/null
+++ b/pkg/tbtables/cfitsio/README.MacOS
@@ -0,0 +1,31 @@
+To build the CFITSIO library on Mac OS-X systems, follow the
+instructions for Unix platforms given in the CFITSIO User's Reference
+Guide (cfitsio.doc).
+
+To build the MacOS port on classic Mac OS-9 or earlier:
+
+1. Un binhex and unstuff cfitsio_mac.sit.hqx
+2. put CFitsioPPC.mcp in the cfitsio directory.
+2. Load CFitsioPPC.mcp into CodeWarrior Pro 5 and make.
+ This builds the cfitsio library for PPC. There are also targets for both
+ the test program and the speed test program.
+
+To use the MacOS port you can add Cfitsio PPC.lib to your Codewarrior Pro 5
+project. Note that this only has been tested for the PPC. It probably
+won't work on 68k macs. Also note that the fortran bindings aren't
+included. I haven't worked with the codewarrior f2c plugin so I don't know
+how these would work. If one is interested, please write and I can look
+into this.
+
+bruce.oneel@obs.unige.ch
+
+Modifications...
+
+10/22/98: pwilson@sewanee.gsfc.nasa.gov
+ New files added for project. Converted to CodeWarrior Pro 3.
+ The speed test program does not run... complains about a missing library?
+11/09/98: pwilson@sewanee.gsfc.nasa.gov
+ Fixed speed test problem thanks to Tom Andersen.
+07/17/00: pwilson@milkyway.gsfc.nasa.gov
+ Updated to CodeWarrior Pro 5 and CFITSIO 2.037.
+
diff --git a/pkg/tbtables/cfitsio/buffers.c b/pkg/tbtables/cfitsio/buffers.c
new file mode 100644
index 00000000..914f674d
--- /dev/null
+++ b/pkg/tbtables/cfitsio/buffers.c
@@ -0,0 +1,1448 @@
+/* This file, buffers.c, contains the core set of FITSIO routines */
+/* that use or manage the internal set of IO buffers. */
+
+/* The FITSIO software was written by William Pence at the High Energy */
+/* Astrophysic Science Archive Research Center (HEASARC) at the NASA */
+/* Goddard Space Flight Center. */
+
+#include <string.h>
+#include <stdlib.h>
+#include "fitsio2.h"
+
+char iobuffer[NIOBUF][IOBUFLEN]; /* initialize to zero by default */
+FITSfile *bufptr[NIOBUF]; /* initialize to zero by default */
+long bufrecnum[NIOBUF]; /* initialize to zero by default */
+int dirty[NIOBUF], ageindex[NIOBUF]; /* ages get initialized in ffwhbf */
+
+/*--------------------------------------------------------------------------*/
+int ffmbyt(fitsfile *fptr, /* I - FITS file pointer */
+ OFF_T bytepos, /* I - byte position in file to move to */
+ int err_mode, /* I - 1=ignore error, 0 = return error */
+ int *status) /* IO - error status */
+{
+/*
+ Move to the input byte location in the file. When writing to a file, a move
+ may sometimes be made to a position beyond the current EOF. The err_mode
+ parameter determines whether such conditions should be returned as an error
+ or simply ignored.
+*/
+ long record;
+
+ if (*status > 0)
+ return(*status);
+
+ if (bytepos < 0)
+ return(*status = NEG_FILE_POS);
+
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+
+ record = bytepos / IOBUFLEN; /* zero-indexed record number */
+
+ /* if this is not the current record, then load it */
+ if ( ((fptr->Fptr)->curbuf < 0) ||
+ (record != bufrecnum[(fptr->Fptr)->curbuf]))
+ ffldrc(fptr, record, err_mode, status);
+
+ if (*status <= 0)
+ (fptr->Fptr)->bytepos = bytepos; /* save new file position */
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpbyt(fitsfile *fptr, /* I - FITS file pointer */
+ long nbytes, /* I - number of bytes to write */
+ void *buffer, /* I - buffer containing the bytes to write */
+ int *status) /* IO - error status */
+/*
+ put (write) the buffer of bytes to the output FITS file, starting at
+ the current file position. Write large blocks of data directly to disk;
+ write smaller segments to intermediate IO buffers to improve efficiency.
+*/
+{
+ int ii, nbuff;
+ OFF_T filepos;
+ long recstart, recend;
+ long ntodo, bufpos, nspace, nwrite;
+ char *cptr;
+
+ if (*status > 0)
+ return(*status);
+
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+
+ cptr = (char *)buffer;
+ ntodo = nbytes;
+
+ if ((fptr->Fptr)->curbuf < 0) /* no current data buffer for this file */
+ { /* so reload the last one that was used */
+ ffldrc(fptr, ((fptr->Fptr)->bytepos) / IOBUFLEN, REPORT_EOF, status);
+ }
+
+ if (nbytes >= MINDIRECT)
+ {
+ /* write large blocks of data directly to disk instead of via buffers */
+ /* first, fill up the current IO buffer before flushing it to disk */
+
+ nbuff = (fptr->Fptr)->curbuf; /* current IO buffer number */
+ filepos = (fptr->Fptr)->bytepos; /* save the write starting position */
+ recstart = bufrecnum[nbuff]; /* starting record */
+ recend = (filepos + nbytes - 1) / IOBUFLEN; /* ending record */
+
+ /* bufpos is the starting position within the IO buffer */
+ bufpos = filepos - ((OFF_T)recstart * IOBUFLEN);
+ nspace = IOBUFLEN - bufpos; /* amount of space left in the buffer */
+
+ if (nspace)
+ { /* fill up the IO buffer */
+ memcpy(iobuffer[nbuff] + bufpos, cptr, nspace);
+ ntodo -= nspace; /* decrement remaining number of bytes */
+ cptr += nspace; /* increment user buffer pointer */
+ filepos += nspace; /* increment file position pointer */
+ dirty[nbuff] = TRUE; /* mark record as having been modified */
+ }
+
+ for (ii = 0; ii < NIOBUF; ii++) /* flush any affected buffers to disk */
+ {
+ if (bufptr[ii] == fptr->Fptr && bufrecnum[ii] >= recstart
+ && bufrecnum[ii] <= recend )
+ {
+ if (dirty[ii]) /* flush modified buffer to disk */
+ ffbfwt(ii, status);
+
+ bufptr[ii] = NULL; /* disassociate buffer from the file */
+ }
+ }
+
+ /* move to the correct write position */
+ if ((fptr->Fptr)->io_pos != filepos)
+ ffseek(fptr->Fptr, filepos);
+
+ nwrite = ((ntodo - 1) / IOBUFLEN) * IOBUFLEN; /* don't write last buff */
+
+ ffwrite(fptr->Fptr, nwrite, cptr, status); /* write the data */
+ ntodo -= nwrite; /* decrement remaining number of bytes */
+ cptr += nwrite; /* increment user buffer pointer */
+ (fptr->Fptr)->io_pos = filepos + nwrite; /* update the file position */
+
+ if ((fptr->Fptr)->io_pos >= (fptr->Fptr)->filesize) /* at the EOF? */
+ {
+ (fptr->Fptr)->filesize = (fptr->Fptr)->io_pos; /* increment file size */
+
+ /* initialize the current buffer with the correct fill value */
+ if ((fptr->Fptr)->hdutype == ASCII_TBL)
+ memset(iobuffer[nbuff], 32, IOBUFLEN); /* blank fill */
+ else
+ memset(iobuffer[nbuff], 0, IOBUFLEN); /* zero fill */
+ }
+ else
+ {
+ /* read next record */
+ ffread(fptr->Fptr, IOBUFLEN, iobuffer[nbuff], status);
+ (fptr->Fptr)->io_pos += IOBUFLEN;
+ }
+
+ /* copy remaining bytes from user buffer into current IO buffer */
+ memcpy(iobuffer[nbuff], cptr, ntodo);
+ dirty[nbuff] = TRUE; /* mark record as having been modified */
+ bufrecnum[nbuff] = recend; /* record number */
+ bufptr[nbuff] = fptr->Fptr; /* file pointer associated with IO buffer */
+
+ (fptr->Fptr)->logfilesize = maxvalue((fptr->Fptr)->logfilesize,
+ (OFF_T)(recend + 1) * IOBUFLEN);
+ (fptr->Fptr)->bytepos = filepos + nwrite + ntodo;
+ }
+ else
+ {
+ /* bufpos is the starting position in IO buffer */
+ bufpos = (fptr->Fptr)->bytepos - ((OFF_T)bufrecnum[(fptr->Fptr)->curbuf] *
+ IOBUFLEN);
+ nspace = IOBUFLEN - bufpos; /* amount of space left in the buffer */
+
+ while (ntodo)
+ {
+ nwrite = minvalue(ntodo, nspace);
+
+ /* copy bytes from user's buffer to the IO buffer */
+ memcpy(iobuffer[(fptr->Fptr)->curbuf] + bufpos, cptr, nwrite);
+ ntodo -= nwrite; /* decrement remaining number of bytes */
+ cptr += nwrite;
+ (fptr->Fptr)->bytepos += nwrite; /* increment file position pointer */
+ dirty[(fptr->Fptr)->curbuf] = TRUE; /* mark record as modified */
+
+ if (ntodo) /* load next record into a buffer */
+ {
+ ffldrc(fptr, (fptr->Fptr)->bytepos / IOBUFLEN, IGNORE_EOF, status);
+ bufpos = 0;
+ nspace = IOBUFLEN;
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpbytoff(fitsfile *fptr, /* I - FITS file pointer */
+ long gsize, /* I - size of each group of bytes */
+ long ngroups, /* I - number of groups to write */
+ long offset, /* I - size of gap between groups */
+ void *buffer, /* I - buffer to be written */
+ int *status) /* IO - error status */
+/*
+ put (write) the buffer of bytes to the output FITS file, with an offset
+ between each group of bytes. This function combines ffmbyt and ffpbyt
+ for increased efficiency.
+*/
+{
+ int bcurrent;
+ long ii, bufpos, nspace, nwrite, record;
+ char *cptr, *ioptr;
+
+ if (*status > 0)
+ return(*status);
+
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+
+ if ((fptr->Fptr)->curbuf < 0) /* no current data buffer for this file */
+ { /* so reload the last one that was used */
+ ffldrc(fptr, ((fptr->Fptr)->bytepos) / IOBUFLEN, REPORT_EOF, status);
+ }
+
+ cptr = (char *)buffer;
+ bcurrent = (fptr->Fptr)->curbuf; /* number of the current IO buffer */
+ record = bufrecnum[bcurrent]; /* zero-indexed record number */
+ bufpos = (fptr->Fptr)->bytepos - ((OFF_T)record * IOBUFLEN); /* start pos */
+ nspace = IOBUFLEN - bufpos; /* amount of space left in buffer */
+ ioptr = iobuffer[bcurrent] + bufpos;
+
+ for (ii = 1; ii < ngroups; ii++) /* write all but the last group */
+ {
+ /* copy bytes from user's buffer to the IO buffer */
+ nwrite = minvalue(gsize, nspace);
+ memcpy(ioptr, cptr, nwrite);
+ cptr += nwrite; /* increment buffer pointer */
+
+ if (nwrite < gsize) /* entire group did not fit */
+ {
+ dirty[bcurrent] = TRUE; /* mark record as having been modified */
+ record++;
+ ffldrc(fptr, record, IGNORE_EOF, status); /* load next record */
+ bcurrent = (fptr->Fptr)->curbuf;
+ ioptr = iobuffer[bcurrent];
+
+ nwrite = gsize - nwrite;
+ memcpy(ioptr, cptr, nwrite);
+ cptr += nwrite; /* increment buffer pointer */
+ ioptr += (offset + nwrite); /* increment IO buffer pointer */
+ nspace = IOBUFLEN - offset - nwrite; /* amount of space left */
+ }
+ else
+ {
+ ioptr += (offset + nwrite); /* increment IO bufer pointer */
+ nspace -= (offset + nwrite);
+ }
+
+ if (nspace <= 0) /* beyond current record? */
+ {
+ dirty[bcurrent] = TRUE;
+ record += ((IOBUFLEN - nspace) / IOBUFLEN); /* new record number */
+ ffldrc(fptr, record, IGNORE_EOF, status);
+ bcurrent = (fptr->Fptr)->curbuf;
+
+ bufpos = (-nspace) % IOBUFLEN; /* starting buffer pos */
+ nspace = IOBUFLEN - bufpos;
+ ioptr = iobuffer[bcurrent] + bufpos;
+ }
+ }
+
+ /* now write the last group */
+ nwrite = minvalue(gsize, nspace);
+ memcpy(ioptr, cptr, nwrite);
+ cptr += nwrite; /* increment buffer pointer */
+
+ if (nwrite < gsize) /* entire group did not fit */
+ {
+ dirty[bcurrent] = TRUE; /* mark record as having been modified */
+ record++;
+ ffldrc(fptr, record, IGNORE_EOF, status); /* load next record */
+ bcurrent = (fptr->Fptr)->curbuf;
+ ioptr = iobuffer[bcurrent];
+
+ nwrite = gsize - nwrite;
+ memcpy(ioptr, cptr, nwrite);
+ }
+
+ dirty[bcurrent] = TRUE; /* mark record as having been modified */
+ (fptr->Fptr)->bytepos = (fptr->Fptr)->bytepos + (ngroups * gsize)
+ + (ngroups - 1) * offset;
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgbyt(fitsfile *fptr, /* I - FITS file pointer */
+ long nbytes, /* I - number of bytes to read */
+ void *buffer, /* O - buffer to read into */
+ int *status) /* IO - error status */
+/*
+ get (read) the requested number of bytes from the file, starting at
+ the current file position. Read large blocks of data directly from disk;
+ read smaller segments via intermediate IO buffers to improve efficiency.
+*/
+{
+ int ii;
+ OFF_T filepos;
+ long recstart, recend, ntodo, bufpos, nspace, nread;
+ char *cptr;
+
+ if (*status > 0)
+ return(*status);
+
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+ cptr = (char *)buffer;
+
+ if (nbytes >= MINDIRECT)
+ {
+ /* read large blocks of data directly from disk instead of via buffers */
+ filepos = (fptr->Fptr)->bytepos; /* save the read starting position */
+
+/* note that in this case, ffmbyt has not been called, and so */
+/* bufrecnum[(fptr->Fptr)->curbuf] does not point to the intended */
+/* output buffer */
+
+ recstart = filepos / IOBUFLEN; /* starting record */
+ recend = (filepos + nbytes - 1) / IOBUFLEN; /* ending record */
+
+ for (ii = 0; ii < NIOBUF; ii++) /* flush any affected buffers to disk */
+ {
+ if (dirty[ii] && bufptr[ii] == fptr->Fptr &&
+ bufrecnum[ii] >= recstart && bufrecnum[ii] <= recend)
+ {
+ ffbfwt(ii, status); /* flush modified buffer to disk */
+ }
+ }
+
+ /* move to the correct read position */
+ if ((fptr->Fptr)->io_pos != filepos)
+ ffseek(fptr->Fptr, filepos);
+
+ ffread(fptr->Fptr, nbytes, cptr, status); /* read the data */
+ (fptr->Fptr)->io_pos = filepos + nbytes; /* update the file position */
+ }
+ else
+ {
+ /* read small chucks of data using the IO buffers for efficiency */
+
+ if ((fptr->Fptr)->curbuf < 0) /* no current data buffer for this file */
+ { /* so reload the last one that was used */
+ ffldrc(fptr, ((fptr->Fptr)->bytepos) / IOBUFLEN, REPORT_EOF, status);
+ }
+
+ /* bufpos is the starting position in IO buffer */
+ bufpos = (fptr->Fptr)->bytepos - ((OFF_T)bufrecnum[(fptr->Fptr)->curbuf] *
+ IOBUFLEN);
+ nspace = IOBUFLEN - bufpos; /* amount of space left in the buffer */
+
+ ntodo = nbytes;
+ while (ntodo)
+ {
+ nread = minvalue(ntodo, nspace);
+
+ /* copy bytes from IO buffer to user's buffer */
+ memcpy(cptr, iobuffer[(fptr->Fptr)->curbuf] + bufpos, nread);
+ ntodo -= nread; /* decrement remaining number of bytes */
+ cptr += nread;
+ (fptr->Fptr)->bytepos += nread; /* increment file position pointer */
+
+ if (ntodo) /* load next record into a buffer */
+ {
+ ffldrc(fptr, (fptr->Fptr)->bytepos / IOBUFLEN, REPORT_EOF, status);
+ bufpos = 0;
+ nspace = IOBUFLEN;
+ }
+ }
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgbytoff(fitsfile *fptr, /* I - FITS file pointer */
+ long gsize, /* I - size of each group of bytes */
+ long ngroups, /* I - number of groups to read */
+ long offset, /* I - size of gap between groups (may be < 0) */
+ void *buffer, /* I - buffer to be filled */
+ int *status) /* IO - error status */
+/*
+ get (read) the requested number of bytes from the file, starting at
+ the current file position. This function combines ffmbyt and ffgbyt
+ for increased efficiency.
+*/
+{
+ int bcurrent;
+ long ii, bufpos, nspace, nread, record;
+ char *cptr, *ioptr;
+
+ if (*status > 0)
+ return(*status);
+
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+
+ if ((fptr->Fptr)->curbuf < 0) /* no current data buffer for this file */
+ { /* so reload the last one that was used */
+ ffldrc(fptr, ((fptr->Fptr)->bytepos) / IOBUFLEN, REPORT_EOF, status);
+ }
+
+ cptr = (char *)buffer;
+ bcurrent = (fptr->Fptr)->curbuf; /* number of the current IO buffer */
+ record = bufrecnum[bcurrent]; /* zero-indexed record number */
+ bufpos = (fptr->Fptr)->bytepos - ((OFF_T)record * IOBUFLEN); /* start pos */
+ nspace = IOBUFLEN - bufpos; /* amount of space left in buffer */
+ ioptr = iobuffer[bcurrent] + bufpos;
+
+ for (ii = 1; ii < ngroups; ii++) /* read all but the last group */
+ {
+ /* copy bytes from IO buffer to the user's buffer */
+ nread = minvalue(gsize, nspace);
+ memcpy(cptr, ioptr, nread);
+ cptr += nread; /* increment buffer pointer */
+
+ if (nread < gsize) /* entire group did not fit */
+ {
+ record++;
+ ffldrc(fptr, record, REPORT_EOF, status); /* load next record */
+ bcurrent = (fptr->Fptr)->curbuf;
+ ioptr = iobuffer[bcurrent];
+
+ nread = gsize - nread;
+ memcpy(cptr, ioptr, nread);
+ cptr += nread; /* increment buffer pointer */
+ ioptr += (offset + nread); /* increment IO buffer pointer */
+ nspace = IOBUFLEN - offset - nread; /* amount of space left */
+ }
+ else
+ {
+ ioptr += (offset + nread); /* increment IO bufer pointer */
+ nspace -= (offset + nread);
+ }
+
+ if (nspace <= 0 || nspace > IOBUFLEN) /* beyond current record? */
+ {
+ if (nspace <= 0)
+ {
+ record += ((IOBUFLEN - nspace) / IOBUFLEN); /* new record number */
+ bufpos = (-nspace) % IOBUFLEN; /* starting buffer pos */
+ }
+ else
+ {
+ record -= ((nspace - 1 ) / IOBUFLEN); /* new record number */
+ bufpos = IOBUFLEN - (nspace % IOBUFLEN); /* starting buffer pos */
+ }
+
+ ffldrc(fptr, record, REPORT_EOF, status);
+ bcurrent = (fptr->Fptr)->curbuf;
+
+ nspace = IOBUFLEN - bufpos;
+ ioptr = iobuffer[bcurrent] + bufpos;
+ }
+ }
+
+ /* now read the last group */
+ nread = minvalue(gsize, nspace);
+ memcpy(cptr, ioptr, nread);
+ cptr += nread; /* increment buffer pointer */
+
+ if (nread < gsize) /* entire group did not fit */
+ {
+ record++;
+ ffldrc(fptr, record, REPORT_EOF, status); /* load next record */
+ bcurrent = (fptr->Fptr)->curbuf;
+ ioptr = iobuffer[bcurrent];
+
+ nread = gsize - nread;
+ memcpy(cptr, ioptr, nread);
+ }
+
+ (fptr->Fptr)->bytepos = (fptr->Fptr)->bytepos + (ngroups * gsize)
+ + (ngroups - 1) * offset;
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffldrc(fitsfile *fptr, /* I - FITS file pointer */
+ long record, /* I - record number to be loaded */
+ int err_mode, /* I - 1=ignore EOF, 0 = return EOF error */
+ int *status) /* IO - error status */
+{
+/*
+ low-level routine to load a specified record from a file into
+ a physical buffer, if it is not already loaded. Reset all
+ pointers to make this the new current record for that file.
+ Update ages of all the physical buffers.
+*/
+ int ibuff, nbuff;
+ OFF_T rstart;
+
+ /* check if record is already loaded in one of the buffers */
+ /* search from youngest to oldest buffer for efficiency */
+
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+
+ for (ibuff = NIOBUF - 1; ibuff >= 0; ibuff--)
+ {
+ nbuff = ageindex[ibuff];
+ if (bufptr[nbuff] == fptr->Fptr && record == bufrecnum[nbuff])
+ goto updatebuf; /* use 'goto' for efficiency */
+ }
+
+ /* record is not already loaded */
+ rstart = (OFF_T)record * IOBUFLEN;
+
+ if ( !err_mode && (rstart >= (fptr->Fptr)->logfilesize) ) /* EOF? */
+ return(*status = END_OF_FILE);
+
+ if (ffwhbf(fptr, &nbuff) < 0) /* which buffer should we reuse? */
+ return(*status = TOO_MANY_FILES);
+
+ if (dirty[nbuff])
+ ffbfwt(nbuff, status); /* write dirty buffer to disk */
+
+ if (rstart >= (fptr->Fptr)->filesize) /* EOF? */
+ {
+ /* initialize an empty buffer with the correct fill value */
+ if ((fptr->Fptr)->hdutype == ASCII_TBL)
+ memset(iobuffer[nbuff], 32, IOBUFLEN); /* blank fill */
+ else
+ memset(iobuffer[nbuff], 0, IOBUFLEN); /* zero fill */
+
+ (fptr->Fptr)->logfilesize = maxvalue((fptr->Fptr)->logfilesize,
+ rstart + IOBUFLEN);
+
+ dirty[nbuff] = TRUE; /* mark record as having been modified */
+ }
+ else /* not EOF, so read record from disk */
+ {
+ if ((fptr->Fptr)->io_pos != rstart)
+ ffseek(fptr->Fptr, rstart);
+
+ ffread(fptr->Fptr, IOBUFLEN, iobuffer[nbuff], status);
+ (fptr->Fptr)->io_pos = rstart + IOBUFLEN; /* set new IO position */
+ }
+
+ bufptr[nbuff] = fptr->Fptr; /* file pointer for this buffer */
+ bufrecnum[nbuff] = record; /* record number contained in buffer */
+
+updatebuf:
+
+ (fptr->Fptr)->curbuf = nbuff; /* this is the current buffer for this file */
+
+ if (ibuff < 0)
+ {
+ /* find the current position of the buffer in the age index */
+ for (ibuff = 0; ibuff < NIOBUF; ibuff++)
+ if (ageindex[ibuff] == nbuff)
+ break;
+ }
+
+ /* increment the age of all the buffers that were younger than it */
+ for (ibuff++; ibuff < NIOBUF; ibuff++)
+ ageindex[ibuff - 1] = ageindex[ibuff];
+
+ ageindex[NIOBUF - 1] = nbuff; /* this is now the youngest buffer */
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffwhbf(fitsfile *fptr, /* I - FITS file pointer */
+ int *nbuff) /* O - which buffer to use */
+{
+/*
+ decide which buffer to (re)use to hold a new file record
+*/
+ int ii, ibuff;
+ static int ageinit = 0;
+
+ if (!ageinit) /* first time thru, initialize default age of buffers */
+ {
+ for (ii = 0; ii < NIOBUF; ii++)
+ ageindex[ii] = ii;
+ ageinit = 1;
+ }
+
+ for (ii = 0; ii < NIOBUF; ii++)
+ {
+ ibuff = ageindex[ii]; /* search from the oldest to youngest buffer */
+
+ if (bufptr[ibuff] == NULL || /* if buffer is empty, or */
+ bufptr[ibuff]->curbuf != ibuff) /* is not the current buffer */
+ return(*nbuff = ibuff); /* then choose this buffer */
+ }
+
+ /* all the buffers are locked, so we have to reuse the current one */
+ /* If there is no current buffer (e.g., file has just been opened) */
+ /* then use the oldest buffer. */
+
+ if ((fptr->Fptr)->curbuf < 0) {
+ bufptr[ageindex[0]]->curbuf = -1; /* this buffer no longer contains */
+ /* the current buffer of another file */
+ return(*nbuff = ageindex[0]); /* return oldest buffer */
+ } else {
+ return(*nbuff = (fptr->Fptr)->curbuf); /* return current buffer */
+ }
+}
+/*--------------------------------------------------------------------------*/
+int ffflus(fitsfile *fptr, /* I - FITS file pointer */
+ int *status) /* IO - error status */
+/*
+ Flush all the data in the current FITS file to disk. This ensures that if
+ the program subsequently dies, the disk FITS file will be closed correctly.
+*/
+{
+ int hdunum, hdutype;
+
+ if (*status > 0)
+ return(*status);
+
+ ffghdn(fptr, &hdunum); /* get the current HDU number */
+
+ if (ffchdu(fptr,status) > 0) /* close out the current HDU */
+ ffpmsg("ffflus could not close the current HDU.");
+
+ ffflsh(fptr, FALSE, status); /* flush any modified IO buffers to disk */
+
+ if (ffgext(fptr, hdunum - 1, &hdutype, status) > 0) /* reopen HDU */
+ ffpmsg("ffflus could not reopen the current HDU.");
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffflsh(fitsfile *fptr, /* I - FITS file pointer */
+ int clearbuf, /* I - also clear buffer contents? */
+ int *status) /* IO - error status */
+{
+/*
+ flush all dirty IO buffers associated with the file to disk
+*/
+ int ii;
+
+/*
+ no need to move to a different HDU
+
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+*/
+ for (ii = 0; ii < NIOBUF; ii++)
+ {
+ if (bufptr[ii] == fptr->Fptr)
+ {
+ if (dirty[ii]) /* flush modified buffer to disk */
+ ffbfwt(ii, status);
+
+ if (clearbuf)
+ bufptr[ii] = NULL; /* set contents of buffer as undefined */
+ }
+ }
+
+ if (*status != READONLY_FILE)
+ ffflushx(fptr->Fptr); /* flush system buffers to disk */
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffbfeof(fitsfile *fptr, /* I - FITS file pointer */
+ int *status) /* IO - error status */
+{
+/*
+ clear any buffers beyond the end of file
+*/
+ int ii;
+
+ for (ii = 0; ii < NIOBUF; ii++)
+ {
+ if (bufptr[ii] == fptr->Fptr)
+ {
+ if ( (OFF_T) bufrecnum[ii] * IOBUFLEN >= fptr->Fptr->filesize)
+ {
+ bufptr[ii] = NULL; /* set contents of buffer as undefined */
+ }
+ }
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffbfwt(int nbuff, /* I - which buffer to write */
+ int *status) /* IO - error status */
+{
+/*
+ write contents of buffer to file; If the position of the buffer
+ is beyond the current EOF, then the file may need to be extended
+ with fill values, and/or with the contents of some of the other
+ i/o buffers.
+*/
+ FITSfile *Fptr;
+ int ii,ibuff;
+ long jj, irec, minrec, nloop;
+ OFF_T filepos;
+
+ static char zeros[IOBUFLEN]; /* initialized to zero by default */
+
+ Fptr = bufptr[nbuff];
+ if (!(Fptr->writemode) )
+ {
+ ffpmsg("Error: trying to write to READONLY file.");
+ dirty[nbuff] = FALSE; /* reset buffer status to prevent later probs */
+ *status = READONLY_FILE;
+ return(*status);
+ }
+
+ filepos = (OFF_T)bufrecnum[nbuff] * IOBUFLEN;
+
+ if (filepos <= Fptr->filesize)
+ {
+ /* record is located within current file, so just write it */
+
+ /* move to the correct write position */
+ if (Fptr->io_pos != filepos)
+ ffseek(Fptr, filepos);
+
+ ffwrite(Fptr, IOBUFLEN, iobuffer[nbuff], status);
+ Fptr->io_pos = filepos + IOBUFLEN;
+
+ if (filepos == Fptr->filesize) /* appended new record? */
+ Fptr->filesize += IOBUFLEN; /* increment the file size */
+
+ dirty[nbuff] = FALSE;
+ }
+
+ else /* if record is beyond the EOF, append any other records */
+ /* and/or insert fill values if necessary */
+ {
+ /* move to EOF */
+ if (Fptr->io_pos != Fptr->filesize)
+ ffseek(Fptr, Fptr->filesize);
+
+ ibuff = NIOBUF; /* initialize to impossible value */
+ while(ibuff != nbuff) /* repeat until requested buffer is written */
+ {
+ minrec = Fptr->filesize / IOBUFLEN;
+
+ /* write lowest record beyond the EOF first */
+
+ irec = bufrecnum[nbuff]; /* initially point to the requested buffer */
+ ibuff = nbuff;
+
+ for (ii = 0; ii < NIOBUF; ii++)
+ {
+ if (bufptr[ii] == Fptr && bufrecnum[ii] >= minrec &&
+ bufrecnum[ii] < irec)
+ {
+ irec = bufrecnum[ii]; /* found a lower record */
+ ibuff = ii;
+ }
+ }
+
+ filepos = (OFF_T)irec * IOBUFLEN; /* byte offset of record in file */
+
+ /* append 1 or more fill records if necessary */
+ if (filepos > Fptr->filesize)
+ {
+ nloop = (filepos - (Fptr->filesize)) / IOBUFLEN;
+ for (jj = 0; jj < nloop && !(*status); jj++)
+ ffwrite(Fptr, IOBUFLEN, zeros, status);
+
+/*
+ffseek(Fptr, filepos);
+*/
+ Fptr->filesize = filepos; /* increment the file size */
+ }
+
+ /* write the buffer itself */
+ ffwrite(Fptr, IOBUFLEN, iobuffer[ibuff], status);
+ dirty[ibuff] = FALSE;
+
+ Fptr->filesize += IOBUFLEN; /* increment the file size */
+ } /* loop back if more buffers need to be written */
+
+ Fptr->io_pos = Fptr->filesize; /* currently positioned at EOF */
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgrsz( fitsfile *fptr, /* I - FITS file pionter */
+ long *ndata, /* O - optimal amount of data to access */
+ int *status) /* IO - error status */
+/*
+ Returns an optimal value for the number of rows in a binary table
+ or the number of pixels in an image that should be read or written
+ at one time for maximum efficiency. Accessing more data than this
+ may cause excessive flushing and rereading of buffers to/from disk.
+*/
+{
+ int nfiles, typecode, bytesperpixel;
+ long repeat, width;
+
+ /* There are NIOBUF internal buffers available each IOBUFLEN bytes long. */
+
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+ else if ((fptr->Fptr)->datastart == DATA_UNDEFINED)
+ if ( ffrdef(fptr, status) > 0) /* rescan header to get hdu struct */
+ return(*status);
+
+ /* determine how many different FITS files are currently open */
+ nfiles = fits_get_num_files();
+
+ /* one buffer (at least) is always allocated to each open file */
+
+ if ((fptr->Fptr)->hdutype == IMAGE_HDU ) /* calc pixels per buffer size */
+ {
+ /* image pixels are in column 2 of the 'table' */
+ ffgtcl(fptr, 2, &typecode, &repeat, &width, status);
+ bytesperpixel = typecode / 10;
+ *ndata = ((NIOBUF - nfiles) * IOBUFLEN) / bytesperpixel;
+ }
+ else /* calc number of rows that fit in buffers */
+ {
+ *ndata = ((NIOBUF - nfiles) * IOBUFLEN) / maxvalue(1,
+ (fptr->Fptr)->rowlength);
+ *ndata = maxvalue(1, *ndata);
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fits_get_num_files(void)
+/*
+ Returns the number of FITS files currently opened in CFITSIO
+*/
+{
+ int ii, jj, unique, nfiles;
+
+ /* determine how many different FITS files are currently open */
+ nfiles = 0;
+ for (ii = 0; ii < NIOBUF; ii++)
+ {
+ if (bufptr[ii])
+ {
+ unique = TRUE;
+
+ for (jj = 0; jj < ii; jj++)
+ {
+ if (bufptr[ii] == bufptr[jj])
+ {
+ unique = FALSE;
+ break;
+ }
+ }
+
+ if (unique)
+ nfiles++;
+ }
+ }
+ return(nfiles);
+}
+/*--------------------------------------------------------------------------*/
+int ffgtbb(fitsfile *fptr, /* I - FITS file pointer */
+ long firstrow, /* I - starting row (1 = first row) */
+ long firstchar, /* I - starting byte in row (1=first) */
+ long nchars, /* I - number of bytes to read */
+ unsigned char *values, /* I - array of bytes to read */
+ int *status) /* IO - error status */
+/*
+ read a consecutive string of bytes from an ascii or binary table.
+ This will span multiple rows of the table if nchars + firstchar is
+ greater than the length of a row.
+*/
+{
+ OFF_T bytepos;
+ long endrow;
+
+ if (*status > 0 || nchars <= 0)
+ return(*status);
+
+ else if (firstrow < 1)
+ return(*status=BAD_ROW_NUM);
+
+ else if (firstchar < 1)
+ return(*status=BAD_ELEM_NUM);
+
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+
+ /* check that we do not exceed number of rows in the table */
+ endrow = ((firstchar + nchars - 2) / (fptr->Fptr)->rowlength) + firstrow;
+ if (endrow > (fptr->Fptr)->numrows)
+ {
+ ffpmsg("attempt to read past end of table (ffgtbb)");
+ return(*status=BAD_ROW_NUM);
+ }
+
+ /* move the i/o pointer to the start of the sequence of characters */
+ bytepos = (fptr->Fptr)->datastart +
+ ((fptr->Fptr)->rowlength * (firstrow - 1)) +
+ firstchar - 1;
+
+ ffmbyt(fptr, bytepos, REPORT_EOF, status);
+ ffgbyt(fptr, nchars, values, status); /* read the bytes */
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgi1b(fitsfile *fptr, /* I - FITS file pointer */
+ OFF_T byteloc, /* I - position within file to start reading */
+ long nvals, /* I - number of pixels to read */
+ long incre, /* I - byte increment between pixels */
+ unsigned char *values, /* O - returned array of values */
+ int *status) /* IO - error status */
+/*
+ get (read) the array of values from the FITS file, doing machine dependent
+ format conversion (e.g. byte-swapping) if necessary.
+*/
+{
+ OFF_T postemp;
+
+ if (incre == 1) /* read all the values at once (contiguous bytes) */
+ {
+ if (nvals < MINDIRECT) /* read normally via IO buffers */
+ {
+ ffmbyt(fptr, byteloc, REPORT_EOF, status);
+ ffgbyt(fptr, nvals, values, status);
+ }
+ else /* read directly from disk, bypassing IO buffers */
+ {
+ postemp = (fptr->Fptr)->bytepos; /* store current file position */
+ (fptr->Fptr)->bytepos = byteloc; /* set to the desired position */
+ ffgbyt(fptr, nvals, values, status);
+ (fptr->Fptr)->bytepos = postemp; /* reset to original position */
+ }
+ }
+ else /* have to read each value individually (not contiguous ) */
+ {
+ ffmbyt(fptr, byteloc, REPORT_EOF, status);
+ ffgbytoff(fptr, 1, nvals, incre - 1, values, status);
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgi2b(fitsfile *fptr, /* I - FITS file pointer */
+ OFF_T byteloc, /* I - position within file to start reading */
+ long nvals, /* I - number of pixels to read */
+ long incre, /* I - byte increment between pixels */
+ short *values, /* O - returned array of values */
+ int *status) /* IO - error status */
+/*
+ get (read) the array of values from the FITS file, doing machine dependent
+ format conversion (e.g. byte-swapping) if necessary.
+*/
+{
+ OFF_T postemp;
+
+ if (incre == 2) /* read all the values at once (contiguous bytes) */
+ {
+ if (nvals * 2 < MINDIRECT) /* read normally via IO buffers */
+ {
+ ffmbyt(fptr, byteloc, REPORT_EOF, status);
+ ffgbyt(fptr, nvals * 2, values, status);
+ }
+ else /* read directly from disk, bypassing IO buffers */
+ {
+ postemp = (fptr->Fptr)->bytepos; /* store current file position */
+ (fptr->Fptr)->bytepos = byteloc; /* set to the desired position */
+ ffgbyt(fptr, nvals * 2, values, status);
+ (fptr->Fptr)->bytepos = postemp; /* reset to original position */
+ }
+ }
+ else /* have to read each value individually (not contiguous ) */
+ {
+ ffmbyt(fptr, byteloc, REPORT_EOF, status);
+ ffgbytoff(fptr, 2, nvals, incre - 2, values, status);
+ }
+
+#if BYTESWAPPED
+ ffswap2(values, nvals); /* reverse order of bytes in each value */
+#endif
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgi4b(fitsfile *fptr, /* I - FITS file pointer */
+ OFF_T byteloc, /* I - position within file to start reading */
+ long nvals, /* I - number of pixels to read */
+ long incre, /* I - byte increment between pixels */
+ INT32BIT *values, /* O - returned array of values */
+ int *status) /* IO - error status */
+/*
+ get (read) the array of values from the FITS file, doing machine dependent
+ format conversion (e.g. byte-swapping) if necessary.
+*/
+{
+ OFF_T postemp;
+
+ if (incre == 4) /* read all the values at once (contiguous bytes) */
+ {
+ if (nvals * 4 < MINDIRECT) /* read normally via IO buffers */
+ {
+ ffmbyt(fptr, byteloc, REPORT_EOF, status);
+ ffgbyt(fptr, nvals * 4, values, status);
+ }
+ else /* read directly from disk, bypassing IO buffers */
+ {
+ postemp = (fptr->Fptr)->bytepos; /* store current file position */
+ (fptr->Fptr)->bytepos = byteloc; /* set to the desired position */
+ ffgbyt(fptr, nvals * 4, values, status);
+ (fptr->Fptr)->bytepos = postemp; /* reset to original position */
+ }
+ }
+ else /* have to read each value individually (not contiguous ) */
+ {
+ ffmbyt(fptr, byteloc, REPORT_EOF, status);
+ ffgbytoff(fptr, 4, nvals, incre - 4, values, status);
+ }
+
+#if BYTESWAPPED
+ ffswap4(values, nvals); /* reverse order of bytes in each value */
+#endif
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgi8b(fitsfile *fptr, /* I - FITS file pointer */
+ OFF_T byteloc, /* I - position within file to start reading */
+ long nvals, /* I - number of pixels to read */
+ long incre, /* I - byte increment between pixels */
+ long *values, /* O - returned array of values */
+ int *status) /* IO - error status */
+/*
+ get (read) the array of values from the FITS file, doing machine dependent
+ format conversion (e.g. byte-swapping) if necessary.
+
+ !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ This routine reads 'nvals' 8-byte integers into 'values'.
+ This works both on platforms that have sizeof(long) = 64, and 32,
+ as long as 'values' has been allocated to large enough to hold
+ 8 * nvals bytes of data.
+ !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+*/
+{
+ OFF_T postemp;
+
+ if (incre == 8) /* read all the values at once (contiguous bytes) */
+ {
+ if (nvals * 8 < MINDIRECT) /* read normally via IO buffers */
+ {
+ ffmbyt(fptr, byteloc, REPORT_EOF, status);
+ ffgbyt(fptr, nvals * 8, values, status);
+ }
+ else /* read directly from disk, bypassing IO buffers */
+ {
+ postemp = (fptr->Fptr)->bytepos; /* store current file position */
+ (fptr->Fptr)->bytepos = byteloc; /* set to the desired position */
+ ffgbyt(fptr, nvals * 8, values, status);
+ (fptr->Fptr)->bytepos = postemp; /* reset to original position */
+ }
+ }
+ else /* have to read each value individually (not contiguous ) */
+ {
+ ffmbyt(fptr, byteloc, REPORT_EOF, status);
+ ffgbytoff(fptr, 8, nvals, incre - 8, values, status);
+ }
+
+#if BYTESWAPPED
+ ffswap8((double *) values, nvals); /* reverse bytes in each value */
+#endif
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgr4b(fitsfile *fptr, /* I - FITS file pointer */
+ OFF_T byteloc, /* I - position within file to start reading */
+ long nvals, /* I - number of pixels to read */
+ long incre, /* I - byte increment between pixels */
+ float *values, /* O - returned array of values */
+ int *status) /* IO - error status */
+/*
+ get (read) the array of values from the FITS file, doing machine dependent
+ format conversion (e.g. byte-swapping) if necessary.
+*/
+{
+ OFF_T postemp;
+
+#if MACHINE == VAXVMS
+ long ii;
+
+#elif (MACHINE == ALPHAVMS) && (FLOATTYPE == GFLOAT)
+ short *sptr;
+ long ii;
+
+#endif
+
+
+ if (incre == 4) /* read all the values at once (contiguous bytes) */
+ {
+ if (nvals * 4 < MINDIRECT) /* read normally via IO buffers */
+ {
+ ffmbyt(fptr, byteloc, REPORT_EOF, status);
+ ffgbyt(fptr, nvals * 4, values, status);
+ }
+ else /* read directly from disk, bypassing IO buffers */
+ {
+ postemp = (fptr->Fptr)->bytepos; /* store current file position */
+ (fptr->Fptr)->bytepos = byteloc; /* set to the desired position */
+ ffgbyt(fptr, nvals * 4, values, status);
+ (fptr->Fptr)->bytepos = postemp; /* reset to original position */
+ }
+ }
+ else /* have to read each value individually (not contiguous ) */
+ {
+ ffmbyt(fptr, byteloc, REPORT_EOF, status);
+ ffgbytoff(fptr, 4, nvals, incre - 4, values, status);
+ }
+
+
+#if MACHINE == VAXVMS
+
+ ii = nvals; /* call VAX macro routine to convert */
+ ieevur(values, values, &ii); /* from IEEE float -> F float */
+
+#elif (MACHINE == ALPHAVMS) && (FLOATTYPE == GFLOAT)
+
+ ffswap2( (short *) values, nvals * 2); /* swap pairs of bytes */
+
+ /* convert from IEEE float format to VMS GFLOAT float format */
+ sptr = (short *) values;
+ for (ii = 0; ii < nvals; ii++, sptr += 2)
+ {
+ if (!fnan(*sptr) ) /* test for NaN or underflow */
+ values[ii] *= 4.0;
+ }
+
+#elif BYTESWAPPED
+ ffswap4((INT32BIT *)values, nvals); /* reverse order of bytes in values */
+#endif
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgr8b(fitsfile *fptr, /* I - FITS file pointer */
+ OFF_T byteloc, /* I - position within file to start reading */
+ long nvals, /* I - number of pixels to read */
+ long incre, /* I - byte increment between pixels */
+ double *values, /* O - returned array of values */
+ int *status) /* IO - error status */
+/*
+ get (read) the array of values from the FITS file, doing machine dependent
+ format conversion (e.g. byte-swapping) if necessary.
+*/
+{
+ OFF_T postemp;
+
+#if MACHINE == VAXVMS
+ long ii;
+
+#elif (MACHINE == ALPHAVMS) && (FLOATTYPE == GFLOAT)
+ short *sptr;
+ long ii;
+
+#endif
+
+ if (incre == 8) /* read all the values at once (contiguous bytes) */
+ {
+ if (nvals * 8 < MINDIRECT) /* read normally via IO buffers */
+ {
+ ffmbyt(fptr, byteloc, REPORT_EOF, status);
+ ffgbyt(fptr, nvals * 8, values, status);
+ }
+ else /* read directly from disk, bypassing IO buffers */
+ {
+ postemp = (fptr->Fptr)->bytepos; /* store current file position */
+ (fptr->Fptr)->bytepos = byteloc; /* set to the desired position */
+ ffgbyt(fptr, nvals * 8, values, status);
+ (fptr->Fptr)->bytepos = postemp; /* reset to original position */
+ }
+ }
+ else /* have to read each value individually (not contiguous ) */
+ {
+ ffmbyt(fptr, byteloc, REPORT_EOF, status);
+ ffgbytoff(fptr, 8, nvals, incre - 8, values, status);
+ }
+
+#if MACHINE == VAXVMS
+ ii = nvals; /* call VAX macro routine to convert */
+ ieevud(values, values, &ii); /* from IEEE float -> D float */
+
+#elif (MACHINE == ALPHAVMS) && (FLOATTYPE == GFLOAT)
+ ffswap2( (short *) values, nvals * 4); /* swap pairs of bytes */
+
+ /* convert from IEEE float format to VMS GFLOAT float format */
+ sptr = (short *) values;
+ for (ii = 0; ii < nvals; ii++, sptr += 4)
+ {
+ if (!dnan(*sptr) ) /* test for NaN or underflow */
+ values[ii] *= 4.0;
+ }
+
+#elif BYTESWAPPED
+ ffswap8(values, nvals); /* reverse order of bytes in each value */
+#endif
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffptbb(fitsfile *fptr, /* I - FITS file pointer */
+ long firstrow, /* I - starting row (1 = first row) */
+ long firstchar, /* I - starting byte in row (1=first) */
+ long nchars, /* I - number of bytes to write */
+ unsigned char *values, /* I - array of bytes to write */
+ int *status) /* IO - error status */
+/*
+ write a consecutive string of bytes to an ascii or binary table.
+ This will span multiple rows of the table if nchars + firstchar is
+ greater than the length of a row.
+*/
+{
+ OFF_T bytepos;
+ long endrow, nrows;
+ char message[81];
+
+ if (*status > 0 || nchars <= 0)
+ return(*status);
+
+ else if (firstrow < 1)
+ return(*status=BAD_ROW_NUM);
+
+ else if (firstchar < 1)
+ return(*status=BAD_ELEM_NUM);
+
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+ else if ((fptr->Fptr)->datastart < 0) /* rescan header if data undefined */
+ ffrdef(fptr, status);
+
+ endrow = ((firstchar + nchars - 2) / (fptr->Fptr)->rowlength) + firstrow;
+
+ /* check if we are writing beyond the current end of table */
+ if (endrow > (fptr->Fptr)->numrows)
+ {
+ /* if there are more HDUs following the current one, or */
+ /* if there is a data heap, then we must insert space */
+ /* for the new rows. */
+ if ( !((fptr->Fptr)->lasthdu) || (fptr->Fptr)->heapsize > 0)
+ {
+ nrows = endrow - ((fptr->Fptr)->numrows);
+
+ /* ffirow also updates the heap address and numrows */
+ if (ffirow(fptr, (fptr->Fptr)->numrows, nrows, status) > 0)
+ {
+ sprintf(message,
+ "ffptbb failed to add space for %ld new rows in table.",
+ nrows);
+ ffpmsg(message);
+ return(*status);
+ }
+ }
+ else
+ {
+ /* manally update heap starting address */
+ (fptr->Fptr)->heapstart +=
+ ((OFF_T)(endrow - (fptr->Fptr)->numrows) *
+ (fptr->Fptr)->rowlength );
+
+ (fptr->Fptr)->numrows = endrow; /* update number of rows */
+ }
+ }
+
+ /* move the i/o pointer to the start of the sequence of characters */
+ bytepos = (fptr->Fptr)->datastart +
+ ((fptr->Fptr)->rowlength * (firstrow - 1)) +
+ firstchar - 1;
+
+ ffmbyt(fptr, bytepos, IGNORE_EOF, status);
+ ffpbyt(fptr, nchars, values, status); /* write the bytes */
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpi1b(fitsfile *fptr, /* I - FITS file pointer */
+ long nvals, /* I - number of pixels in the values array */
+ long incre, /* I - byte increment between pixels */
+ unsigned char *values, /* I - array of values to write */
+ int *status) /* IO - error status */
+/*
+ put (write) the array of values to the FITS file, doing machine dependent
+ format conversion (e.g. byte-swapping) if necessary.
+*/
+{
+ if (incre == 1) /* write all the values at once (contiguous bytes) */
+
+ ffpbyt(fptr, nvals, values, status);
+
+ else /* have to write each value individually (not contiguous ) */
+
+ ffpbytoff(fptr, 1, nvals, incre - 1, values, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpi2b(fitsfile *fptr, /* I - FITS file pointer */
+ long nvals, /* I - number of pixels in the values array */
+ long incre, /* I - byte increment between pixels */
+ short *values, /* I - array of values to write */
+ int *status) /* IO - error status */
+/*
+ put (write) the array of values to the FITS file, doing machine dependent
+ format conversion (e.g. byte-swapping) if necessary.
+*/
+{
+#if BYTESWAPPED
+ ffswap2(values, nvals); /* reverse order of bytes in each value */
+#endif
+
+ if (incre == 2) /* write all the values at once (contiguous bytes) */
+
+ ffpbyt(fptr, nvals * 2, values, status);
+
+ else /* have to write each value individually (not contiguous ) */
+
+ ffpbytoff(fptr, 2, nvals, incre - 2, values, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpi4b(fitsfile *fptr, /* I - FITS file pointer */
+ long nvals, /* I - number of pixels in the values array */
+ long incre, /* I - byte increment between pixels */
+ INT32BIT *values, /* I - array of values to write */
+ int *status) /* IO - error status */
+/*
+ put (write) the array of values to the FITS file, doing machine dependent
+ format conversion (e.g. byte-swapping) if necessary.
+*/
+{
+#if BYTESWAPPED
+ ffswap4(values, nvals); /* reverse order of bytes in each value */
+#endif
+
+ if (incre == 4) /* write all the values at once (contiguous bytes) */
+
+ ffpbyt(fptr, nvals * 4, values, status);
+
+ else /* have to write each value individually (not contiguous ) */
+
+ ffpbytoff(fptr, 4, nvals, incre - 4, values, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpi8b(fitsfile *fptr, /* I - FITS file pointer */
+ long nvals, /* I - number of pixels in the values array */
+ long incre, /* I - byte increment between pixels */
+ long *values, /* I - array of values to write */
+ int *status) /* IO - error status */
+/*
+ put (write) the array of values to the FITS file, doing machine dependent
+ format conversion (e.g. byte-swapping) if necessary.
+
+ !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ This routine writes 'nvals' 8-byte integers from 'values'.
+ This works both on platforms that have sizeof(long) = 64, and 32,
+ as long as 'values' has been allocated to large enough to hold
+ 8 * nvals bytes of data.
+ !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+*/
+{
+#if BYTESWAPPED
+ ffswap8((double *) values, nvals); /* reverse bytes in each value */
+#endif
+
+ if (incre == 8) /* write all the values at once (contiguous bytes) */
+
+ ffpbyt(fptr, nvals * 8, values, status);
+
+ else /* have to write each value individually (not contiguous ) */
+
+ ffpbytoff(fptr, 8, nvals, incre - 8, values, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpr4b(fitsfile *fptr, /* I - FITS file pointer */
+ long nvals, /* I - number of pixels in the values array */
+ long incre, /* I - byte increment between pixels */
+ float *values, /* I - array of values to write */
+ int *status) /* IO - error status */
+/*
+ put (write) the array of values to the FITS file, doing machine dependent
+ format conversion (e.g. byte-swapping) if necessary.
+*/
+{
+#if MACHINE == VAXVMS
+ long ii;
+
+ ii = nvals; /* call VAX macro routine to convert */
+ ieevpr(values, values, &ii); /* from F float -> IEEE float */
+
+#elif (MACHINE == ALPHAVMS) && (FLOATTYPE == GFLOAT)
+ long ii;
+
+ /* convert from VMS FFLOAT float format to IEEE float format */
+ for (ii = 0; ii < nvals; ii++)
+ values[ii] *= 0.25;
+
+ ffswap2( (short *) values, nvals * 2); /* swap pairs of bytes */
+
+#elif BYTESWAPPED
+ ffswap4((INT32BIT *) values, nvals); /* reverse order of bytes in values */
+#endif
+
+ if (incre == 4) /* write all the values at once (contiguous bytes) */
+
+ ffpbyt(fptr, nvals * 4, values, status);
+
+ else /* have to write each value individually (not contiguous ) */
+
+ ffpbytoff(fptr, 4, nvals, incre - 4, values, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpr8b(fitsfile *fptr, /* I - FITS file pointer */
+ long nvals, /* I - number of pixels in the values array */
+ long incre, /* I - byte increment between pixels */
+ double *values, /* I - array of values to write */
+ int *status) /* IO - error status */
+/*
+ put (write) the array of values to the FITS file, doing machine dependent
+ format conversion (e.g. byte-swapping) if necessary.
+*/
+{
+#if MACHINE == VAXVMS
+ long ii;
+
+ ii = nvals; /* call VAX macro routine to convert */
+ ieevpd(values, values, &ii); /* from D float -> IEEE float */
+
+#elif (MACHINE == ALPHAVMS) && (FLOATTYPE == GFLOAT)
+ long ii;
+
+ /* convert from VMS GFLOAT float format to IEEE float format */
+ for (ii = 0; ii < nvals; ii++)
+ values[ii] *= 0.25;
+
+ ffswap2( (short *) values, nvals * 4); /* swap pairs of bytes */
+
+#elif BYTESWAPPED
+ ffswap8(values, nvals); /* reverse order of bytes in each value */
+#endif
+
+ if (incre == 8) /* write all the values at once (contiguous bytes) */
+
+ ffpbyt(fptr, nvals * 8, values, status);
+
+ else /* have to write each value individually (not contiguous ) */
+
+ ffpbytoff(fptr, 8, nvals, incre - 8, values, status);
+
+ return(*status);
+}
+
diff --git a/pkg/tbtables/cfitsio/cfileio.c b/pkg/tbtables/cfitsio/cfileio.c
new file mode 100644
index 00000000..839350fd
--- /dev/null
+++ b/pkg/tbtables/cfitsio/cfileio.c
@@ -0,0 +1,5572 @@
+/* This file, cfileio.c, contains the low-level file access routines. */
+
+/* The FITSIO software was written by William Pence at the High Energy */
+/* Astrophysic Science Archive Research Center (HEASARC) at the NASA */
+/* Goddard Space Flight Center. */
+
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stddef.h> /* apparently needed to define size_t */
+#include "fitsio2.h"
+#include "group.h"
+
+#define MAX_PREFIX_LEN 20 /* max length of file type prefix (e.g. 'http://') */
+#define MAX_DRIVERS 22 /* max number of file I/O drivers */
+
+typedef struct /* structure containing pointers to I/O driver functions */
+{ char prefix[MAX_PREFIX_LEN];
+ int (*init)(void);
+ int (*shutdown)(void);
+ int (*setoptions)(int option);
+ int (*getoptions)(int *options);
+ int (*getversion)(int *version);
+ int (*checkfile)(char *urltype, char *infile, char *outfile);
+ int (*open)(char *filename, int rwmode, int *driverhandle);
+ int (*create)(char *filename, int *drivehandle);
+ int (*truncate)(int drivehandle, OFF_T size);
+ int (*close)(int drivehandle);
+ int (*remove)(char *filename);
+ int (*size)(int drivehandle, OFF_T *size);
+ int (*flush)(int drivehandle);
+ int (*seek)(int drivehandle, OFF_T offset);
+ int (*read)(int drivehandle, void *buffer, long nbytes);
+ int (*write)(int drivehandle, void *buffer, long nbytes);
+} fitsdriver;
+
+fitsdriver driverTable[MAX_DRIVERS]; /* allocate driver tables */
+
+FITSfile *FptrTable[NMAXFILES]; /* this table of Fptr pointers is */
+ /* used by fits_already_open */
+
+int need_to_initialize = 1; /* true if CFITSIO has not been initialized */
+int no_of_drivers = 0; /* number of currently defined I/O drivers */
+
+/*--------------------------------------------------------------------------*/
+int ffomem(fitsfile **fptr, /* O - FITS file pointer */
+ const char *name, /* I - name of file to open */
+ int mode, /* I - 0 = open readonly; 1 = read/write */
+ void **buffptr, /* I - address of memory pointer */
+ size_t *buffsize, /* I - size of buffer, in bytes */
+ size_t deltasize, /* I - increment for future realloc's */
+ void *(*mem_realloc)(void *p, size_t newsize), /* function */
+ int *status) /* IO - error status */
+/*
+ Open an existing FITS file in core memory. This is a specialized version
+ of ffopen.
+*/
+{
+ int driver, handle, hdutyp, slen, movetotype, extvers, extnum;
+ char extname[FLEN_VALUE];
+ OFF_T filesize;
+ char urltype[MAX_PREFIX_LEN], infile[FLEN_FILENAME], outfile[FLEN_FILENAME];
+ char extspec[FLEN_FILENAME], rowfilter[FLEN_FILENAME];
+ char binspec[FLEN_FILENAME], colspec[FLEN_FILENAME];
+ char imagecolname[FLEN_VALUE], rowexpress[FLEN_FILENAME];
+ char *url, errmsg[FLEN_ERRMSG];
+ char *hdtype[3] = {"IMAGE", "TABLE", "BINTABLE"};
+
+ if (*status > 0)
+ return(*status);
+
+ *fptr = 0; /* initialize null file pointer */
+
+ if (need_to_initialize) /* this is called only once */
+ {
+ *status = fits_init_cfitsio();
+
+ if (*status > 0)
+ return(*status);
+ }
+
+ url = (char *) name;
+ while (*url == ' ') /* ignore leading spaces in the file spec */
+ url++;
+
+ /* parse the input file specification */
+ ffiurl(url, urltype, infile, outfile, extspec,
+ rowfilter, binspec, colspec, status);
+
+ strcpy(urltype, "memkeep://"); /* URL type for pre-existing memory file */
+
+ *status = urltype2driver(urltype, &driver);
+
+ if (*status > 0)
+ {
+ ffpmsg("could not find driver for pre-existing memory file: (ffomem)");
+ return(*status);
+ }
+
+ /* call driver routine to open the memory file */
+ *status = mem_openmem( buffptr, buffsize,deltasize,
+ mem_realloc, &handle);
+
+ if (*status > 0)
+ {
+ ffpmsg("failed to open pre-existing memory file: (ffomem)");
+ return(*status);
+ }
+
+ /* get initial file size */
+ *status = (*driverTable[driver].size)(handle, &filesize);
+
+ if (*status > 0)
+ {
+ (*driverTable[driver].close)(handle); /* close the file */
+ ffpmsg("failed get the size of the memory file: (ffomem)");
+ return(*status);
+ }
+
+ /* allocate fitsfile structure and initialize = 0 */
+ *fptr = (fitsfile *) calloc(1, sizeof(fitsfile));
+
+ if (!(*fptr))
+ {
+ (*driverTable[driver].close)(handle); /* close the file */
+ ffpmsg("failed to allocate structure for following file: (ffomem)");
+ ffpmsg(url);
+ return(*status = MEMORY_ALLOCATION);
+ }
+
+ /* allocate FITSfile structure and initialize = 0 */
+ (*fptr)->Fptr = (FITSfile *) calloc(1, sizeof(FITSfile));
+
+ if (!((*fptr)->Fptr))
+ {
+ (*driverTable[driver].close)(handle); /* close the file */
+ ffpmsg("failed to allocate structure for following file: (ffomem)");
+ ffpmsg(url);
+ free(*fptr);
+ *fptr = 0;
+ return(*status = MEMORY_ALLOCATION);
+ }
+
+ slen = strlen(url) + 1;
+ slen = maxvalue(slen, 32); /* reserve at least 32 chars */
+ ((*fptr)->Fptr)->filename = (char *) malloc(slen); /* mem for file name */
+
+ if ( !(((*fptr)->Fptr)->filename) )
+ {
+ (*driverTable[driver].close)(handle); /* close the file */
+ ffpmsg("failed to allocate memory for filename: (ffomem)");
+ ffpmsg(url);
+ free((*fptr)->Fptr);
+ free(*fptr);
+ *fptr = 0; /* return null file pointer */
+ return(*status = MEMORY_ALLOCATION);
+ }
+
+ /* mem for headstart array */
+ ((*fptr)->Fptr)->headstart = (OFF_T *) calloc(1001, sizeof(OFF_T));
+
+ if ( !(((*fptr)->Fptr)->headstart) )
+ {
+ (*driverTable[driver].close)(handle); /* close the file */
+ ffpmsg("failed to allocate memory for headstart array: (ffomem)");
+ ffpmsg(url);
+ free( ((*fptr)->Fptr)->filename);
+ free((*fptr)->Fptr);
+ free(*fptr);
+ *fptr = 0; /* return null file pointer */
+ return(*status = MEMORY_ALLOCATION);
+ }
+
+ /* store the parameters describing the file */
+ ((*fptr)->Fptr)->MAXHDU = 1000; /* initial size of headstart */
+ ((*fptr)->Fptr)->filehandle = handle; /* file handle */
+ ((*fptr)->Fptr)->driver = driver; /* driver number */
+ strcpy(((*fptr)->Fptr)->filename, url); /* full input filename */
+ ((*fptr)->Fptr)->filesize = filesize; /* physical file size */
+ ((*fptr)->Fptr)->logfilesize = filesize; /* logical file size */
+ ((*fptr)->Fptr)->writemode = mode; /* read-write mode */
+ ((*fptr)->Fptr)->datastart = DATA_UNDEFINED; /* unknown start of data */
+ ((*fptr)->Fptr)->curbuf = -1; /* undefined current IO buffer */
+ ((*fptr)->Fptr)->open_count = 1; /* structure is currently used once */
+ ((*fptr)->Fptr)->validcode = VALIDSTRUC; /* flag denoting valid structure */
+
+ ffldrc(*fptr, 0, REPORT_EOF, status); /* load first record */
+
+ fits_store_Fptr( (*fptr)->Fptr, status); /* store Fptr address */
+
+ if (ffrhdu(*fptr, &hdutyp, status) > 0) /* determine HDU structure */
+ {
+ ffpmsg(
+ "ffomem could not interpret primary array header of file: (ffomem)");
+ ffpmsg(url);
+
+ if (*status == UNKNOWN_REC)
+ ffpmsg("This does not look like a FITS file.");
+
+ ffclos(*fptr, status);
+ *fptr = 0; /* return null file pointer */
+ }
+
+ /* ---------------------------------------------------------- */
+ /* move to desired extension, if specified as part of the URL */
+ /* ---------------------------------------------------------- */
+
+ imagecolname[0] = '\0';
+ rowexpress[0] = '\0';
+
+ if (*extspec)
+ {
+ /* parse the extension specifier into individual parameters */
+ ffexts(extspec, &extnum,
+ extname, &extvers, &movetotype, imagecolname, rowexpress, status);
+
+
+ if (*status > 0)
+ return(*status);
+
+ if (extnum)
+ {
+ ffmahd(*fptr, extnum + 1, &hdutyp, status);
+ }
+ else if (*extname) /* move to named extension, if specified */
+ {
+ ffmnhd(*fptr, movetotype, extname, extvers, status);
+ }
+
+ if (*status > 0)
+ {
+ ffpmsg("ffomem could not move to the specified extension:");
+ if (extnum > 0)
+ {
+ sprintf(errmsg,
+ " extension number %d doesn't exist or couldn't be opened.",extnum);
+ ffpmsg(errmsg);
+ }
+ else
+ {
+ sprintf(errmsg,
+ " extension with EXTNAME = %s,", extname);
+ ffpmsg(errmsg);
+
+ if (extvers)
+ {
+ sprintf(errmsg,
+ " and with EXTVERS = %d,", extvers);
+ ffpmsg(errmsg);
+ }
+
+ if (movetotype != ANY_HDU)
+ {
+ sprintf(errmsg,
+ " and with XTENSION = %s,", hdtype[movetotype]);
+ ffpmsg(errmsg);
+ }
+
+ ffpmsg(" doesn't exist or couldn't be opened.");
+ }
+ return(*status);
+ }
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffdkopn(fitsfile **fptr, /* O - FITS file pointer */
+ const char *name, /* I - full name of file to open */
+ int mode, /* I - 0 = open readonly; 1 = read/write */
+ int *status) /* IO - error status */
+/*
+ Open an existing FITS file on magnetic disk with either readonly or
+ read/write access. The routine does not support CFITSIO's extended
+ filename syntax and simply uses the entire input 'name' string as
+ the name of the file.
+*/
+{
+ if (*status > 0)
+ return(*status);
+
+ *status = OPEN_DISK_FILE;
+
+ ffopen(fptr, name, mode, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffdopn(fitsfile **fptr, /* O - FITS file pointer */
+ const char *name, /* I - full name of file to open */
+ int mode, /* I - 0 = open readonly; 1 = read/write */
+ int *status) /* IO - error status */
+/*
+ Open an existing FITS file with either readonly or read/write access. and
+ move to the first HDU that contains 'interesting' data, if the primary
+ array contains a null image (i.e., NAXIS = 0).
+*/
+{
+ if (*status > 0)
+ return(*status);
+
+ *status = SKIP_NULL_PRIMARY;
+
+ ffopen(fptr, name, mode, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fftopn(fitsfile **fptr, /* O - FITS file pointer */
+ const char *name, /* I - full name of file to open */
+ int mode, /* I - 0 = open readonly; 1 = read/write */
+ int *status) /* IO - error status */
+/*
+ Open an existing FITS file with either readonly or read/write access. and
+ move to the first HDU that contains 'interesting' table (not an image).
+*/
+{
+ int hdutype;
+
+ if (*status > 0)
+ return(*status);
+
+ *status = SKIP_IMAGE;
+
+ ffopen(fptr, name, mode, status);
+
+ if (ffghdt(*fptr, &hdutype, status) <= 0) {
+ if (hdutype == IMAGE_HDU)
+ *status = NOT_TABLE;
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffiopn(fitsfile **fptr, /* O - FITS file pointer */
+ const char *name, /* I - full name of file to open */
+ int mode, /* I - 0 = open readonly; 1 = read/write */
+ int *status) /* IO - error status */
+/*
+ Open an existing FITS file with either readonly or read/write access. and
+ move to the first HDU that contains 'interesting' image (not an table).
+*/
+{
+ int hdutype;
+
+ if (*status > 0)
+ return(*status);
+
+ *status = SKIP_TABLE;
+
+ ffopen(fptr, name, mode, status);
+
+ if (ffghdt(*fptr, &hdutype, status) <= 0) {
+ if (hdutype != IMAGE_HDU)
+ *status = NOT_IMAGE;
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffopen(fitsfile **fptr, /* O - FITS file pointer */
+ const char *name, /* I - full name of file to open */
+ int mode, /* I - 0 = open readonly; 1 = read/write */
+ int *status) /* IO - error status */
+/*
+ Open an existing FITS file with either readonly or read/write access.
+*/
+{
+ int driver, hdutyp, hdunum, slen, writecopy, isopen;
+ OFF_T filesize;
+ long rownum, nrows, goodrows;
+ int extnum, extvers, handle, movetotype, tstatus = 0;
+ char urltype[MAX_PREFIX_LEN], infile[FLEN_FILENAME], outfile[FLEN_FILENAME];
+ char origurltype[MAX_PREFIX_LEN], extspec[FLEN_FILENAME];
+ char extname[FLEN_VALUE], rowfilter[FLEN_FILENAME], tblname[FLEN_VALUE];
+ char imagecolname[FLEN_VALUE], rowexpress[FLEN_FILENAME];
+ char binspec[FLEN_FILENAME], colspec[FLEN_FILENAME];
+ char histfilename[FLEN_FILENAME];
+ char filtfilename[FLEN_FILENAME];
+ char wtcol[FLEN_VALUE];
+ char minname[4][FLEN_VALUE], maxname[4][FLEN_VALUE];
+ char binname[4][FLEN_VALUE];
+ char card[FLEN_CARD];
+
+ char *url;
+ double minin[4], maxin[4], binsizein[4], weight;
+ int imagetype, naxis = 1, haxis, recip;
+ int skip_null = 0, skip_image = 0, skip_table = 0, open_disk_file = 0;
+ char colname[4][FLEN_VALUE];
+ char errmsg[FLEN_ERRMSG];
+ char *hdtype[3] = {"IMAGE", "TABLE", "BINTABLE"};
+ char *rowselect = 0;
+
+ if (*status > 0)
+ return(*status);
+
+ if (*status == SKIP_NULL_PRIMARY)
+ {
+ /* this special status value is used as a flag by ffdopn to tell */
+ /* ffopen to skip over a null primary array when opening the file. */
+
+ skip_null = 1;
+ *status = 0;
+ }
+ else if (*status == SKIP_IMAGE)
+ {
+ /* this special status value is used as a flag by fftopn to tell */
+ /* ffopen to move to 1st significant table when opening the file. */
+
+ skip_image = 1;
+ *status = 0;
+ }
+ else if (*status == SKIP_TABLE)
+ {
+ /* this special status value is used as a flag by ffiopn to tell */
+ /* ffopen to move to 1st significant image when opening the file. */
+
+ skip_table = 1;
+ *status = 0;
+ }
+ else if (*status == OPEN_DISK_FILE)
+ {
+ /* this special status value is used as a flag by ffdkopn to tell */
+ /* ffopen to not interpret the input filename using CFITSIO's */
+ /* extended filename syntax, and simply open the specified disk file */
+
+ open_disk_file = 1;
+ *status = 0;
+ }
+
+ *fptr = 0; /* initialize null file pointer */
+ writecopy = 0; /* have we made a write-able copy of the input file? */
+
+ if (need_to_initialize) /* this is called only once */
+ *status = fits_init_cfitsio();
+
+ if (*status > 0)
+ return(*status);
+
+ url = (char *) name;
+ while (*url == ' ') /* ignore leading spaces in the filename */
+ url++;
+
+ if (*url == '\0')
+ {
+ ffpmsg("Name of file to open is blank. (ffopen)");
+ return(*status = FILE_NOT_OPENED);
+ }
+
+ if (open_disk_file)
+ {
+ /* treat the input URL literally as the name of the file to open */
+ /* and don't try to parse the URL using the extended filename syntax */
+
+ strcpy(infile,url);
+ strcpy(urltype, "file://");
+ outfile[0] = '\0';
+ extspec[0] = '\0';
+ binspec[0] = '\0';
+ colspec[0] = '\0';
+ rowfilter[0] = '\0';
+ }
+ else
+ {
+ /* parse the input file specification */
+ ffiurl(url, urltype, infile, outfile, extspec,
+ rowfilter, binspec, colspec, status);
+ }
+
+ if (*status > 0)
+ {
+ ffpmsg("could not parse the input filename: (ffopen)");
+ ffpmsg(url);
+ return(*status);
+ }
+
+ imagecolname[0] = '\0';
+ rowexpress[0] = '\0';
+
+ if (*extspec)
+ {
+ /* parse the extension specifier into individual parameters */
+ ffexts(extspec, &extnum,
+ extname, &extvers, &movetotype, imagecolname, rowexpress, status);
+
+ if (*status > 0)
+ return(*status);
+ }
+
+ /*-------------------------------------------------------------------*/
+ /* special cases: */
+ /*-------------------------------------------------------------------*/
+
+ histfilename[0] = '\0';
+ filtfilename[0] = '\0';
+ if (*outfile && (*binspec || *imagecolname))
+ {
+ /* if binspec or imagecolumn are specified, then the */
+ /* output file name is intended for the final image, */
+ /* and not a copy of the input file. */
+ strcpy(histfilename, outfile);
+ outfile[0] = '\0';
+ }
+ else if (*outfile && (*rowfilter || *colspec))
+ {
+ /* if rowfilter or colspece are specified, then the */
+ /* output file name is intended for the filtered file */
+ /* and not a copy of the input file. */
+ strcpy(filtfilename, outfile);
+ outfile[0] = '\0';
+ }
+
+ /*-------------------------------------------------------------------*/
+ /* check if this same file is already open, and if so, attach to it */
+ /*-------------------------------------------------------------------*/
+
+ if (fits_already_open(fptr, url, urltype, infile, extspec, rowfilter,
+ binspec, colspec, mode, &isopen, status) > 0)
+ {
+ return(*status);
+ }
+
+ if (isopen)
+ goto move2hdu;
+
+ /* get the driver number corresponding to this urltype */
+ *status = urltype2driver(urltype, &driver);
+
+ if (*status > 0)
+ {
+ ffpmsg("could not find driver for this file: (ffopen)");
+ ffpmsg(urltype);
+ ffpmsg(url);
+ return(*status);
+ }
+
+ /*-------------------------------------------------------------------
+ deal with all those messy special cases which may require that
+ a different driver be used:
+ - is disk file compressed?
+ - are ftp: or http: files compressed?
+ - has user requested that a local copy be made of
+ the ftp or http file?
+ -------------------------------------------------------------------*/
+
+ if (driverTable[driver].checkfile)
+ {
+ strcpy(origurltype,urltype); /* Save the urltype */
+
+ /* 'checkfile' may modify the urltype, infile and outfile strings */
+ *status = (*driverTable[driver].checkfile)(urltype, infile, outfile);
+
+ if (*status)
+ {
+ ffpmsg("checkfile failed for this file: (ffopen)");
+ ffpmsg(url);
+ return(*status);
+ }
+
+ if (strcmp(origurltype, urltype)) /* did driver changed on us? */
+ {
+ *status = urltype2driver(urltype, &driver);
+ if (*status > 0)
+ {
+ ffpmsg("could not change driver for this file: (ffopen)");
+ ffpmsg(url);
+ ffpmsg(urltype);
+ return(*status);
+ }
+ }
+ }
+
+ /* call appropriate driver to open the file */
+ if (driverTable[driver].open)
+ {
+ *status = (*driverTable[driver].open)(infile, mode, &handle);
+ if (*status > 0)
+ {
+ ffpmsg("failed to find or open the following file: (ffopen)");
+ ffpmsg(url);
+ return(*status);
+ }
+ }
+ else
+ {
+ ffpmsg("cannot open an existing file of this type: (ffopen)");
+ ffpmsg(url);
+ return(*status = FILE_NOT_OPENED);
+ }
+
+ /* get initial file size */
+ *status = (*driverTable[driver].size)(handle, &filesize);
+ if (*status > 0)
+ {
+ (*driverTable[driver].close)(handle); /* close the file */
+ ffpmsg("failed get the size of the following file: (ffopen)");
+ ffpmsg(url);
+ return(*status);
+ }
+
+ /* allocate fitsfile structure and initialize = 0 */
+ *fptr = (fitsfile *) calloc(1, sizeof(fitsfile));
+
+ if (!(*fptr))
+ {
+ (*driverTable[driver].close)(handle); /* close the file */
+ ffpmsg("failed to allocate structure for following file: (ffopen)");
+ ffpmsg(url);
+ return(*status = MEMORY_ALLOCATION);
+ }
+
+ /* allocate FITSfile structure and initialize = 0 */
+ (*fptr)->Fptr = (FITSfile *) calloc(1, sizeof(FITSfile));
+
+ if (!((*fptr)->Fptr))
+ {
+ (*driverTable[driver].close)(handle); /* close the file */
+ ffpmsg("failed to allocate structure for following file: (ffopen)");
+ ffpmsg(url);
+ free(*fptr);
+ *fptr = 0;
+ return(*status = MEMORY_ALLOCATION);
+ }
+
+ slen = strlen(url) + 1;
+ slen = maxvalue(slen, 32); /* reserve at least 32 chars */
+ ((*fptr)->Fptr)->filename = (char *) malloc(slen); /* mem for file name */
+
+ if ( !(((*fptr)->Fptr)->filename) )
+ {
+ (*driverTable[driver].close)(handle); /* close the file */
+ ffpmsg("failed to allocate memory for filename: (ffopen)");
+ ffpmsg(url);
+ free((*fptr)->Fptr);
+ free(*fptr);
+ *fptr = 0; /* return null file pointer */
+ return(*status = MEMORY_ALLOCATION);
+ }
+
+ /* mem for headstart array */
+ ((*fptr)->Fptr)->headstart = (OFF_T *) calloc(1001, sizeof(OFF_T));
+
+ if ( !(((*fptr)->Fptr)->headstart) )
+ {
+ (*driverTable[driver].close)(handle); /* close the file */
+ ffpmsg("failed to allocate memory for headstart array: (ffopen)");
+ ffpmsg(url);
+ free( ((*fptr)->Fptr)->filename);
+ free((*fptr)->Fptr);
+ free(*fptr);
+ *fptr = 0; /* return null file pointer */
+ return(*status = MEMORY_ALLOCATION);
+ }
+ /* store the parameters describing the file */
+ ((*fptr)->Fptr)->MAXHDU = 1000; /* initial size of headstart */
+ ((*fptr)->Fptr)->filehandle = handle; /* file handle */
+ ((*fptr)->Fptr)->driver = driver; /* driver number */
+ strcpy(((*fptr)->Fptr)->filename, url); /* full input filename */
+ ((*fptr)->Fptr)->filesize = filesize; /* physical file size */
+ ((*fptr)->Fptr)->logfilesize = filesize; /* logical file size */
+ ((*fptr)->Fptr)->writemode = mode; /* read-write mode */
+ ((*fptr)->Fptr)->datastart = DATA_UNDEFINED; /* unknown start of data */
+ ((*fptr)->Fptr)->curbuf = -1; /* undefined current IO buffer */
+ ((*fptr)->Fptr)->open_count = 1; /* structure is currently used once */
+ ((*fptr)->Fptr)->validcode = VALIDSTRUC; /* flag denoting valid structure */
+
+ ffldrc(*fptr, 0, REPORT_EOF, status); /* load first record */
+
+ fits_store_Fptr( (*fptr)->Fptr, status); /* store Fptr address */
+
+ if (ffrhdu(*fptr, &hdutyp, status) > 0) /* determine HDU structure */
+ {
+ ffpmsg(
+ "ffopen could not interpret primary array header of file: ");
+ ffpmsg(url);
+
+ if (*status == UNKNOWN_REC)
+ ffpmsg("This does not look like a FITS file.");
+
+ ffclos(*fptr, status);
+ *fptr = 0; /* return null file pointer */
+ return(*status);
+ }
+
+ /* ------------------------------------------------------------- */
+ /* At this point, the input file has been opened. If outfile was */
+ /* specified, then we have opened a copy of the file, not the */
+ /* original file so it is safe to modify it if necessary */
+ /* ------------------------------------------------------------- */
+
+ if (*outfile)
+ writecopy = 1;
+
+move2hdu:
+
+ /* ---------------------------------------------------------- */
+ /* move to desired extension, if specified as part of the URL */
+ /* ---------------------------------------------------------- */
+
+ if (*extspec)
+ {
+ if (extnum) /* extension number was specified */
+ {
+ ffmahd(*fptr, extnum + 1, &hdutyp, status);
+ }
+ else if (*extname) /* move to named extension, if specified */
+ {
+ ffmnhd(*fptr, movetotype, extname, extvers, status);
+ }
+
+ if (*status > 0) /* clean up after error */
+ {
+ ffpmsg("ffopen could not move to the specified extension:");
+ if (extnum > 0)
+ {
+ sprintf(errmsg,
+ " extension number %d doesn't exist or couldn't be opened.",extnum);
+ ffpmsg(errmsg);
+ }
+ else
+ {
+ sprintf(errmsg,
+ " extension with EXTNAME = %s,", extname);
+ ffpmsg(errmsg);
+
+ if (extvers)
+ {
+ sprintf(errmsg,
+ " and with EXTVERS = %d,", extvers);
+ ffpmsg(errmsg);
+ }
+
+ if (movetotype != ANY_HDU)
+ {
+ sprintf(errmsg,
+ " and with XTENSION = %s,", hdtype[movetotype]);
+ ffpmsg(errmsg);
+ }
+
+ ffpmsg(" doesn't exist or couldn't be opened.");
+ }
+
+ ffclos(*fptr, status);
+ *fptr = 0; /* return null file pointer */
+ return(*status);
+ }
+ }
+ else if (skip_null || skip_image || skip_table ||
+ (*imagecolname || *colspec || *rowfilter || *binspec))
+ {
+ /* ------------------------------------------------------------------
+
+ If no explicit extension specifier is given as part of the file
+ name, and, if a) skip_null is true (set if ffopen is called by
+ ffdopn) or b) skip_image or skip_table is true (set if ffopen is
+ called by fftopn or ffdopn) or c) other file filters are
+ specified, then CFITSIO will attempt to move to the first
+ 'interesting' HDU after opening an existing FITS file (or to
+ first interesting table HDU if skip_image is true);
+
+ An 'interesting' HDU is defined to be either an image with NAXIS
+ > 0 (i.e., not a null array) or a table which has an EXTNAME
+ value which does not contain any of the following strings:
+ 'GTI' - Good Time Interval extension
+ 'OBSTABLE' - used in Beppo SAX data files
+
+ The main purpose for this is to allow CFITSIO to skip over a null
+ primary and other non-interesting HDUs when opening an existing
+ file, and move directly to the first extension that contains
+ significant data.
+ ------------------------------------------------------------------ */
+
+ fits_get_hdu_num(*fptr, &hdunum);
+ if (hdunum == 1) {
+
+ fits_get_img_dim(*fptr, &naxis, status);
+
+ if (naxis == 0 || skip_image) /* skip primary array */
+ {
+ while(1)
+ {
+ /* see if the next HDU is 'interesting' */
+ if (fits_movrel_hdu(*fptr, 1, &hdutyp, status))
+ {
+ if (*status == END_OF_FILE)
+ *status = 0; /* reset expected error */
+
+ /* didn't find an interesting HDU so move back to beginning */
+ fits_movabs_hdu(*fptr, 1, &hdutyp, status);
+ break;
+ }
+
+ if (hdutyp == IMAGE_HDU && skip_image) {
+
+ continue; /* skip images */
+
+ } else if (hdutyp != IMAGE_HDU && skip_table) {
+
+ continue; /* skip tables */
+
+ } else if (hdutyp == IMAGE_HDU) {
+
+ fits_get_img_dim(*fptr, &naxis, status);
+ if (naxis > 0)
+ break; /* found a non-null image */
+
+ } else {
+
+ tstatus = 0;
+ tblname[0] = '\0';
+ fits_read_key(*fptr, TSTRING, "EXTNAME", tblname, NULL,&tstatus);
+
+ if ( (!strstr(tblname, "GTI") && !strstr(tblname, "gti")) &&
+ strncasecmp(tblname, "OBSTABLE", 8) )
+ break; /* found an interesting table */
+ }
+ } /* end while */
+ }
+ } /* end if (hdunum==1) */
+ }
+
+ if (*imagecolname)
+ {
+ /* ----------------------------------------------------------------- */
+ /* we need to open an image contained in a single table cell */
+ /* First, determine which row of the table to use. */
+ /* ----------------------------------------------------------------- */
+
+ if (isdigit((int) *rowexpress)) /* is the row specification a number? */
+ {
+ sscanf(rowexpress, "%ld", &rownum);
+ if (rownum < 1)
+ {
+ ffpmsg("illegal rownum for image cell:");
+ ffpmsg(rowexpress);
+ ffpmsg("Could not open the following image in a table cell:");
+ ffpmsg(extspec);
+ ffclos(*fptr, status);
+ *fptr = 0; /* return null file pointer */
+ return(*status = BAD_ROW_NUM);
+ }
+ }
+ else if (fits_find_first_row(*fptr, rowexpress, &rownum, status) > 0)
+ {
+ ffpmsg("Failed to find row matching this expression:");
+ ffpmsg(rowexpress);
+ ffpmsg("Could not open the following image in a table cell:");
+ ffpmsg(extspec);
+ ffclos(*fptr, status);
+ *fptr = 0; /* return null file pointer */
+ return(*status);
+ }
+
+ if (rownum == 0)
+ {
+ ffpmsg("row statisfying this expression doesn't exist::");
+ ffpmsg(rowexpress);
+ ffpmsg("Could not open the following image in a table cell:");
+ ffpmsg(extspec);
+ ffclos(*fptr, status);
+ *fptr = 0; /* return null file pointer */
+ return(*status = BAD_ROW_NUM);
+ }
+
+ /* determine the name of the new file to contain copy of the image */
+ if (*histfilename)
+ strcpy(outfile, histfilename); /* the original outfile name */
+ else
+ strcpy(outfile, "mem://_1"); /* create image file in memory */
+
+ /* Copy the image into new primary array and open it as the current */
+ /* fptr. This will close the table that contains the original image. */
+
+ if (fits_copy_image_cell(fptr, outfile, imagecolname, rownum,
+ status) > 0)
+ {
+ ffpmsg("Failed to copy table cell to new primary array:");
+ ffpmsg(extspec);
+ ffclos(*fptr, status);
+ *fptr = 0; /* return null file pointer */
+ return(*status);
+ }
+
+ writecopy = 1; /* we are now dealing with a copy of the original file */
+
+ /* add some HISTORY; fits_copy_image_cell also wrote HISTORY keywords */
+
+ if (*extname)
+ sprintf(card,"HISTORY in HDU '%.16s' of file '%.36s'",extname,infile);
+ else
+ sprintf(card,"HISTORY in HDU %d of file '%.45s'", extnum, infile);
+
+ ffprec(*fptr, card, status);
+ }
+
+ /* --------------------------------------------------------------------- */
+ /* edit columns (and/or keywords) in the table, if specified in the URL */
+ /* --------------------------------------------------------------------- */
+
+ if (*colspec)
+ {
+ /* the column specifier will modify the file, so make sure */
+ /* we are already dealing with a copy, or else make a new copy */
+
+ if (!writecopy) /* Is the current file already a copy? */
+ writecopy = fits_is_this_a_copy(urltype);
+
+ if (!writecopy)
+ {
+ if (*filtfilename && *outfile == '\0')
+ strcpy(outfile, filtfilename); /* the original outfile name */
+ else
+ strcpy(outfile, "mem://_1"); /* will create copy in memory */
+
+ writecopy = 1;
+ }
+ else
+ {
+ ((*fptr)->Fptr)->writemode = READWRITE; /* we have write access */
+ outfile[0] = '\0';
+ }
+
+ if (ffedit_columns(fptr, outfile, colspec, status) > 0)
+ {
+ ffpmsg("editing columns in input table failed (ffopen)");
+ ffpmsg(" while trying to perform the following operation:");
+ ffpmsg(colspec);
+ ffclos(*fptr, status);
+ *fptr = 0; /* return null file pointer */
+ return(*status);
+ }
+ }
+
+ /* ------------------------------------------------------------------- */
+ /* select rows from the table, if specified in the URL */
+ /* or select a subimage (if this is an image HDU and not a table) */
+ /* ------------------------------------------------------------------- */
+
+ if (*rowfilter)
+ {
+ fits_get_hdu_type(*fptr, &hdutyp, status); /* get type of HDU */
+ if (hdutyp == IMAGE_HDU)
+ {
+ /* this is an image so 'rowfilter' is an image section specification */
+
+ if (*filtfilename && *outfile == '\0')
+ strcpy(outfile, filtfilename); /* the original outfile name */
+ else if (*outfile == '\0') /* output file name not already defined? */
+ strcpy(outfile, "mem://_2"); /* will create file in memory */
+
+ /* create new file containing the image section, plus a copy of */
+ /* any other HDUs that exist in the input file. This routine */
+ /* will close the original image file and return a pointer */
+ /* to the new file. */
+
+ if (fits_select_image_section(fptr, outfile, rowfilter, status) > 0)
+ {
+ ffpmsg("on-the-fly selection of image section failed (ffopen)");
+ ffpmsg(" while trying to use the following section filter:");
+ ffpmsg(rowfilter);
+ ffclos(*fptr, status);
+ *fptr = 0; /* return null file pointer */
+ return(*status);
+ }
+ writecopy = 1;
+ }
+ else
+ {
+ /* this is a table HDU, so the rowfilter is really a row filter */
+
+ if (*binspec)
+ {
+ /* since we are going to make a histogram of the selected rows, */
+ /* it would be a waste of time and memory to make a whole copy of */
+ /* the selected rows. Instead, just construct an array of TRUE */
+ /* or FALSE values that indicate which rows are to be included */
+ /* in the histogram and pass that to the histogram generating */
+ /* routine */
+
+ fits_get_num_rows(*fptr, &nrows, status); /* get no. of rows */
+
+ rowselect = (char *) calloc(nrows, 1);
+ if (!rowselect)
+ {
+ ffpmsg(
+ "failed to allocate memory for selected columns array (ffopen)");
+ ffpmsg(" while trying to select rows with the following filter:");
+ ffpmsg(rowfilter);
+ ffclos(*fptr, status);
+ *fptr = 0; /* return null file pointer */
+ return(*status = MEMORY_ALLOCATION);
+ }
+
+ if (fits_find_rows(*fptr, rowfilter, 1L, nrows, &goodrows,
+ rowselect, status) > 0)
+ {
+ ffpmsg("selection of rows in input table failed (ffopen)");
+ ffpmsg(" while trying to select rows with the following filter:");
+ ffpmsg(rowfilter);
+ free(rowselect);
+ ffclos(*fptr, status);
+ *fptr = 0; /* return null file pointer */
+ return(*status);
+ }
+ }
+ else
+ {
+ if (!writecopy) /* Is the current file already a copy? */
+ writecopy = fits_is_this_a_copy(urltype);
+
+ if (!writecopy)
+ {
+ if (*filtfilename && *outfile == '\0')
+ strcpy(outfile, filtfilename); /* the original outfile name */
+ else if (*outfile == '\0') /* output filename not already defined? */
+ strcpy(outfile, "mem://_2"); /* will create copy in memory */
+ }
+ else
+ {
+ ((*fptr)->Fptr)->writemode = READWRITE; /* we have write access */
+ outfile[0] = '\0';
+ }
+
+ /* select rows in the table. If a copy of the input file has */
+ /* not already been made, then this routine will make a copy */
+ /* and then close the input file, so that the modifications will */
+ /* only be made on the copy, not the original */
+
+ if (ffselect_table(fptr, outfile, rowfilter, status) > 0)
+ {
+ ffpmsg("on-the-fly selection of rows in input table failed (ffopen)");
+ ffpmsg(" while trying to select rows with the following filter:");
+ ffpmsg(rowfilter);
+ ffclos(*fptr, status);
+ *fptr = 0; /* return null file pointer */
+ return(*status);
+ }
+
+ /* write history records */
+ ffphis(*fptr,
+ "CFITSIO used the following filtering expression to create this table:",
+ status);
+ ffphis(*fptr, name, status);
+
+ } /* end of no binspec case */
+ } /* end of table HDU case */
+ } /* end of rowfilter exists case */
+
+ /* ------------------------------------------------------------------- */
+ /* make an image histogram by binning columns, if specified in the URL */
+ /* ------------------------------------------------------------------- */
+
+ if (*binspec)
+ {
+ if (*histfilename)
+ strcpy(outfile, histfilename); /* the original outfile name */
+ else
+ strcpy(outfile, "mem://_3"); /* create histogram in memory */
+ /* if not already copied the file */
+
+ /* parse the binning specifier into individual parameters */
+ ffbins(binspec, &imagetype, &haxis, colname,
+ minin, maxin, binsizein,
+ minname, maxname, binname,
+ &weight, wtcol, &recip, status);
+
+ /* Create the histogram primary array and open it as the current fptr */
+ /* This will close the table that was used to create the histogram. */
+ ffhist(fptr, outfile, imagetype, haxis, colname, minin, maxin,
+ binsizein, minname, maxname, binname,
+ weight, wtcol, recip, rowselect, status);
+
+ if (rowselect)
+ free(rowselect);
+
+ if (*status > 0)
+ {
+ ffpmsg("on-the-fly histogramming of input table failed (ffopen)");
+ ffpmsg(" while trying to execute the following histogram specification:");
+ ffpmsg(binspec);
+ ffclos(*fptr, status);
+ *fptr = 0; /* return null file pointer */
+ return(*status);
+ }
+
+ /* write history records */
+ ffphis(*fptr,
+ "CFITSIO used the following expression to create this histogram:",
+ status);
+ ffphis(*fptr, name, status);
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffreopen(fitsfile *openfptr, /* I - FITS file pointer to open file */
+ fitsfile **newfptr, /* O - pointer to new re opened file */
+ int *status) /* IO - error status */
+/*
+ Reopen an existing FITS file with either readonly or read/write access.
+ The reopened file shares the same FITSfile structure but may point to a
+ different HDU within the file.
+*/
+{
+ if (*status > 0)
+ return(*status);
+
+ /* check that the open file pointer is valid */
+ if (!openfptr)
+ return(*status = NULL_INPUT_PTR);
+ else if ((openfptr->Fptr)->validcode != VALIDSTRUC) /* check magic value */
+ return(*status = BAD_FILEPTR);
+
+ /* allocate fitsfile structure and initialize = 0 */
+ *newfptr = (fitsfile *) calloc(1, sizeof(fitsfile));
+
+ (*newfptr)->Fptr = openfptr->Fptr; /* both point to the same structure */
+ (*newfptr)->HDUposition = 0; /* set initial position to primary array */
+ (((*newfptr)->Fptr)->open_count)++; /* increment the file usage counter */
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fits_store_Fptr(FITSfile *Fptr, /* O - FITS file pointer */
+ int *status) /* IO - error status */
+/*
+ store the new Fptr address for future use by fits_already_open
+*/
+{
+ int ii;
+
+ if (*status > 0)
+ return(*status);
+
+ for (ii = 0; ii < NMAXFILES; ii++) {
+ if (FptrTable[ii] == 0) {
+ FptrTable[ii] = Fptr;
+ break;
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fits_clear_Fptr(FITSfile *Fptr, /* O - FITS file pointer */
+ int *status) /* IO - error status */
+/*
+ clear the Fptr address from the Fptr Table
+*/
+{
+ int ii;
+
+ for (ii = 0; ii < NMAXFILES; ii++) {
+ if (FptrTable[ii] == Fptr) {
+ FptrTable[ii] = 0;
+ break;
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fits_already_open(fitsfile **fptr, /* I/O - FITS file pointer */
+ char *url,
+ char *urltype,
+ char *infile,
+ char *extspec,
+ char *rowfilter,
+ char *binspec,
+ char *colspec,
+ int mode, /* I - 0 = open readonly; 1 = read/write */
+ int *isopen, /* O - 1 = file is already open */
+ int *status) /* IO - error status */
+/*
+ Check if the file to be opened is already open. If so, then attach to it.
+*/
+ /*
+ this function was changed so that for files of access method FILE://
+ the file paths are compared using standard URL syntax and absolute
+ paths (as opposed to relative paths). This eliminates some instances
+ where a file is already opened but it is not realized because it
+ was opened with another file path. For instance, if the CWD is
+ /a/b/c and I open /a/b/c/foo.fits then open ./foo.fits the previous
+ version of this function would not have reconized that the two files
+ were the same. This version does recognize that the two files are
+ the same.
+ */
+{
+ FITSfile *oldFptr;
+ int ii;
+ char oldurltype[MAX_PREFIX_LEN], oldinfile[FLEN_FILENAME];
+ char oldextspec[FLEN_FILENAME], oldoutfile[FLEN_FILENAME];
+ char oldrowfilter[FLEN_FILENAME];
+ char oldbinspec[FLEN_FILENAME], oldcolspec[FLEN_FILENAME];
+ char cwd[FLEN_FILENAME];
+ char tmpStr[FLEN_FILENAME];
+ char tmpinfile[FLEN_FILENAME];
+
+ *isopen = 0;
+
+ if(strcasecmp(urltype,"FILE://") == 0)
+ {
+ fits_path2url(infile,tmpinfile,status);
+
+ if(tmpinfile[0] != '/')
+ {
+ fits_get_cwd(cwd,status);
+ strcat(cwd,"/");
+ strcat(cwd,tmpinfile);
+ fits_clean_url(cwd,tmpinfile,status);
+ }
+ }
+ else
+ strcpy(tmpinfile,infile);
+
+ for (ii = 0; ii < NMAXFILES; ii++) /* check every buffer */
+ {
+ if (FptrTable[ii] != 0)
+ {
+ oldFptr = FptrTable[ii];
+
+ ffiurl(oldFptr->filename, oldurltype,
+ oldinfile, oldoutfile, oldextspec, oldrowfilter,
+ oldbinspec, oldcolspec, status);
+
+ if (*status > 0)
+ {
+ ffpmsg("could not parse the previously opened filename: (ffopen)");
+ ffpmsg(oldFptr->filename);
+ return(*status);
+ }
+
+ if(strcasecmp(oldurltype,"FILE://") == 0)
+ {
+ fits_path2url(oldinfile,tmpStr,status);
+
+ if(tmpStr[0] != '/')
+ {
+ fits_get_cwd(cwd,status);
+ strcat(cwd,"/");
+ strcat(cwd,tmpStr);
+ fits_clean_url(cwd,tmpStr,status);
+ }
+
+ strcpy(oldinfile,tmpStr);
+ }
+
+ if (!strcmp(urltype, oldurltype) && !strcmp(tmpinfile, oldinfile) )
+ {
+ /* identical type of file and root file name */
+
+ if ( (!rowfilter[0] && !oldrowfilter[0] &&
+ !binspec[0] && !oldbinspec[0] &&
+ !colspec[0] && !oldcolspec[0])
+
+ /* no filtering or binning specs for either file, so */
+ /* this is a case where the same file is being reopened. */
+ /* It doesn't matter if the extensions are different */
+
+ || /* or */
+
+ (!strcmp(rowfilter, oldrowfilter) &&
+ !strcmp(binspec, oldbinspec) &&
+ !strcmp(colspec, oldcolspec) &&
+ !strcmp(extspec, oldextspec) ) )
+
+ /* filtering specs are given and are identical, and */
+ /* the same extension is specified */
+
+ {
+ if (mode == READWRITE && oldFptr->writemode == READONLY)
+ {
+ /*
+ cannot assume that a file previously opened with READONLY
+ can now be written to (e.g., files on CDROM, or over the
+ the network, or STDIN), so return with an error.
+ */
+
+ ffpmsg(
+ "cannot reopen file READWRITE when previously opened READONLY");
+ ffpmsg(url);
+ return(*status = FILE_NOT_OPENED);
+ }
+
+ *fptr = (fitsfile *) calloc(1, sizeof(fitsfile));
+
+ if (!(*fptr))
+ {
+ ffpmsg(
+ "failed to allocate structure for following file: (ffopen)");
+ ffpmsg(url);
+ return(*status = MEMORY_ALLOCATION);
+ }
+
+ (*fptr)->Fptr = oldFptr; /* point to the structure */
+ (*fptr)->HDUposition = 0; /* set initial position */
+ (((*fptr)->Fptr)->open_count)++; /* increment usage counter */
+
+ if (binspec[0]) /* if binning specified, don't move */
+ extspec[0] = '\0';
+
+ /* all the filtering has already been applied, so ignore */
+ rowfilter[0] = '\0';
+ binspec[0] = '\0';
+ colspec[0] = '\0';
+
+ *isopen = 1;
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fits_is_this_a_copy(char *urltype) /* I - type of file */
+/*
+ specialized routine that returns 1 if the file is known to be a temporary
+ copy of the originally opened file. Otherwise it returns 0.
+*/
+{
+ int iscopy;
+
+ if (!strncmp(urltype, "mem", 3) )
+ iscopy = 1; /* file copy is in memory */
+ else if (!strncmp(urltype, "compress", 8) )
+ iscopy = 1; /* compressed diskfile that is uncompressed in memory */
+ else if (!strncmp(urltype, "http", 4) )
+ iscopy = 1; /* copied file using http protocol */
+ else if (!strncmp(urltype, "ftp", 3) )
+ iscopy = 1; /* copied file using ftp protocol */
+ else if (!strncpy(urltype, "stdin", 5) )
+ iscopy = 1; /* piped stdin has been copied to memory */
+ else
+ iscopy = 0; /* file is not known to be a copy */
+
+ return(iscopy);
+}
+/*--------------------------------------------------------------------------*/
+int ffedit_columns(
+ fitsfile **fptr, /* IO - pointer to input table; on output it */
+ /* points to the new selected rows table */
+ char *outfile, /* I - name for output file */
+ char *expr, /* I - column edit expression */
+ int *status)
+/*
+ modify columns in a table and/or header keywords in the HDU
+*/
+{
+ fitsfile *newptr;
+ int ii, hdunum, slen, colnum, deletecol = 0, savecol = 0;
+ int numcols = 0, *colindex = 0, tstatus = 0;
+ char *cptr, *cptr2, *cptr3, clause[FLEN_FILENAME], keyname[FLEN_KEYWORD];
+ char colname[FLEN_VALUE], oldname[FLEN_VALUE], colformat[FLEN_VALUE];
+ char *file_expr = NULL;
+
+ if (*outfile)
+ {
+ /* create new empty file in to hold the selected rows */
+ if (ffinit(&newptr, outfile, status) > 0)
+ {
+ ffpmsg("failed to create file for copy (ffedit_columns)");
+ return(*status);
+ }
+
+ fits_get_hdu_num(*fptr, &hdunum); /* current HDU number in input file */
+
+ /* copy all HDUs to the output copy */
+
+ for (ii = 1; 1; ii++)
+ {
+ if (fits_movabs_hdu(*fptr, ii, NULL, status) > 0)
+ break;
+
+ fits_copy_hdu(*fptr, newptr, 0, status);
+ }
+
+ if (*status == END_OF_FILE)
+ {
+ *status = 0; /* got the expected EOF error; reset = 0 */
+ }
+ else if (*status > 0)
+ {
+ ffclos(newptr, status);
+ ffpmsg("failed to copy all HDUs from input file (ffedit_columns)");
+ return(*status);
+ }
+
+ /* close the original file and return ptr to the new image */
+ ffclos(*fptr, status);
+
+ *fptr = newptr; /* reset the pointer to the new table */
+
+ /* move back to the selected table HDU */
+ if (fits_movabs_hdu(*fptr, hdunum, NULL, status) > 0)
+ {
+ ffpmsg("failed to copy the input file (ffedit_columns)");
+ return(*status);
+ }
+ }
+
+ /* remove the "col " from the beginning of the column edit expression */
+ cptr = expr + 4;
+
+ while (*cptr == ' ')
+ cptr++; /* skip leading white space */
+
+ /* Check if need to import expression from a file */
+
+ if( *cptr=='@' ) {
+ if( ffimport_file( cptr+1, &file_expr, status ) ) return(*status);
+ cptr = file_expr;
+ while (*cptr == ' ')
+ cptr++; /* skip leading white space... again */
+ }
+
+ tstatus = 0;
+ ffgncl(*fptr, &numcols, &tstatus); /* get initial # of cols */
+
+ /* parse expression and get first clause, if more than 1 */
+
+ while ((slen = fits_get_token(&cptr, ";", clause, NULL)) > 0 )
+ {
+ if( *cptr==';' ) cptr++;
+ clause[slen] = '\0';
+
+ if (clause[0] == '!' || clause[0] == '-')
+ {
+ /* ===================================== */
+ /* Case I. delete this column or keyword */
+ /* ===================================== */
+
+ if (ffgcno(*fptr, CASEINSEN, &clause[1], &colnum, status) <= 0)
+ {
+ /* a column with this name exists, so try to delete it */
+ if (ffdcol(*fptr, colnum, status) > 0)
+ {
+ ffpmsg("failed to delete column in input file:");
+ ffpmsg(clause);
+ if( colindex ) free( colindex );
+ if( file_expr ) free( file_expr );
+ return(*status);
+ }
+ deletecol = 1; /* set flag that at least one col was deleted */
+ numcols--;
+ }
+ else
+ {
+ /* try deleting a keyword with this name */
+ *status = 0;
+ if (ffdkey(*fptr, &clause[1], status) > 0)
+ {
+ ffpmsg("column or keyword to be deleted does not exist:");
+ ffpmsg(clause);
+ if( colindex ) free( colindex );
+ if( file_expr ) free( file_expr );
+ return(*status);
+ }
+ }
+ }
+ else
+ {
+ /* ===================================================== */
+ /* Case II:
+ this is either a column name, (case 1)
+
+ or a new column name followed by double = ("==") followed
+ by the old name which is to be renamed. (case 2A)
+
+ or a column or keyword name followed by a single "=" and a
+ calculation expression (case 2B) */
+ /* ===================================================== */
+ cptr2 = clause;
+ slen = fits_get_token(&cptr2, "( =", colname, NULL);
+
+
+ if (slen == 0)
+ {
+ ffpmsg("error: column or keyword name is blank:");
+ ffpmsg(clause);
+ if( colindex ) free( colindex );
+ if( file_expr ) free( file_expr );
+ return(*status= URL_PARSE_ERROR);
+ }
+
+ /* if we encountered an opening parenthesis, then we need to */
+ /* find the closing parenthesis, and concatinate the 2 strings */
+ /* This supports expressions like:
+ [col #EXTNAME(Extension name)="GTI"]
+ */
+ if (*cptr2 == '(')
+ {
+ fits_get_token(&cptr2, ")", oldname, NULL);
+ strcat(colname, oldname);
+ strcat(colname, ")");
+ cptr2++;
+ }
+
+ while (*cptr2 == ' ')
+ cptr2++; /* skip white space */
+
+ if (*cptr2 != '=')
+ {
+ /* ------------------------------------ */
+ /* case 1 - simply the name of a column */
+ /* ------------------------------------ */
+
+ /* look for matching column */
+ ffgcno(*fptr, CASEINSEN, colname, &colnum, status);
+
+ while (*status == COL_NOT_UNIQUE)
+ {
+ /* the column name contained wild cards, and it */
+ /* matches more than one column in the table. */
+
+ /* keep this column in the output file */
+ savecol = 1;
+
+ if (!colindex)
+ colindex = calloc(999, sizeof(int));
+
+ colindex[colnum - 1] = 1; /* flag this column number */
+
+ /* look for other matching column names */
+ ffgcno(*fptr, CASEINSEN, colname, &colnum, status);
+
+ if (*status == COL_NOT_FOUND)
+ *status = 999; /* temporary status flag value */
+ }
+
+ if (*status <= 0)
+ {
+ /* keep this column in the output file */
+ savecol = 1;
+
+ if (!colindex)
+ colindex = calloc(999, sizeof(int));
+
+ colindex[colnum - 1] = 1; /* flag this column number */
+ }
+ else if (*status == 999)
+ {
+ /* this special flag value does not represent an error */
+ *status = 0;
+ }
+ else
+ {
+ ffpmsg("Syntax error in columns specifier in input URL:");
+ ffpmsg(cptr2);
+ if( colindex ) free( colindex );
+ if( file_expr ) free( file_expr );
+ return(*status = URL_PARSE_ERROR);
+ }
+ }
+ else
+ {
+ /* ----------------------------------------------- */
+ /* case 2 where the token ends with an equals sign */
+ /* ----------------------------------------------- */
+
+ cptr2++; /* skip over the first '=' */
+
+ if (*cptr2 == '=')
+ {
+ /*................................................. */
+ /* Case A: rename a column or keyword; syntax is
+ "new_name == old_name" */
+ /*................................................. */
+
+ cptr2++; /* skip the 2nd '=' */
+ while (*cptr2 == ' ')
+ cptr2++; /* skip white space */
+
+ fits_get_token(&cptr2, " ", oldname, NULL);
+
+ /* get column number of the existing column */
+ if (ffgcno(*fptr, CASEINSEN, oldname, &colnum, status) <= 0)
+ {
+ /* modify the TTYPEn keyword value with the new name */
+ ffkeyn("TTYPE", colnum, keyname, status);
+
+ if (ffmkys(*fptr, keyname, colname, NULL, status) > 0)
+ {
+ ffpmsg("failed to rename column in input file");
+ ffpmsg(" oldname =");
+ ffpmsg(oldname);
+ ffpmsg(" newname =");
+ ffpmsg(colname);
+ if( colindex ) free( colindex );
+ if( file_expr ) free( file_expr );
+ return(*status);
+ }
+ /* keep this column in the output file */
+ savecol = 1;
+ if (!colindex)
+ colindex = calloc(999, sizeof(int));
+
+ colindex[colnum - 1] = 1; /* flag this column number */
+ }
+ else
+ {
+ /* try renaming a keyword */
+ *status = 0;
+ if (ffmnam(*fptr, oldname, colname, status) > 0)
+ {
+ ffpmsg("column or keyword to be renamed does not exist:");
+ ffpmsg(clause);
+ if( colindex ) free( colindex );
+ if( file_expr ) free( file_expr );
+ return(*status);
+ }
+ }
+ }
+ else
+ {
+ /*...................................................... */
+ /* Case B: */
+ /* this must be a general column/keyword calc expression */
+ /* "name = expression" or "colname(TFORM) = expression" */
+ /*...................................................... */
+
+ /* parse the name and TFORM values, if present */
+ colformat[0] = '\0';
+ cptr3 = colname;
+
+ fits_get_token(&cptr3, "(", oldname, NULL);
+
+ if (cptr3[0] == '(' )
+ {
+ cptr3++; /* skip the '(' */
+ fits_get_token(&cptr3, ")", colformat, NULL);
+ }
+
+ /* calculate values for the column or keyword */
+ /* cptr2 = the expression to be calculated */
+ /* oldname = name of the column or keyword */
+ /* colformat = column format, or keyword comment string */
+
+ fits_calculator(*fptr, cptr2, *fptr, oldname, colformat,
+ status);
+
+ /* test if this is a column and not a keyword */
+ tstatus = 0;
+ ffgcno(*fptr, CASEINSEN, oldname, &colnum, &tstatus);
+ if (tstatus == 0)
+ {
+ /* keep this column in the output file */
+ savecol = 1;
+
+ if (!colindex)
+ colindex = calloc(999, sizeof(int));
+
+ colindex[colnum - 1] = 1;
+ if (colnum > numcols)numcols++;
+ }
+ }
+ }
+ }
+ }
+
+ if (savecol && !deletecol)
+ {
+ /* need to delete all but the specified columns */
+ for (ii = numcols; ii > 0; ii--)
+ {
+ if (!colindex[ii-1]) /* delete this column */
+ {
+ if (ffdcol(*fptr, ii, status) > 0)
+ {
+ ffpmsg("failed to delete column in input file:");
+ ffpmsg(clause);
+ if( colindex ) free( colindex );
+ if( file_expr ) free( file_expr );
+ return(*status);
+ }
+ }
+ }
+ }
+
+ if( colindex ) free( colindex );
+ if( file_expr ) free( file_expr );
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fits_copy_image_cell(
+ fitsfile **fptr, /* IO - pointer to input table; on output it */
+ /* points to the new image primary array */
+ char *outfile, /* I - name for output file */
+ char *colname, /* I - name of column containing the image */
+ long rownum, /* I - number of the row containing the image */
+ int *status)
+{
+ fitsfile *newptr;
+ unsigned char buffer[30000];
+ int ii, hdutype, colnum, typecode, bitpix, naxis, maxelem, tstatus;
+ long naxes[9], nbytes, firstbyte, twidth;
+ OFF_T repeat, startpos, elemnum, rowlen;
+ long incre, tnull, ntodo;
+ double scale, zero;
+ char tform[20];
+ char keyname[FLEN_KEYWORD], card[FLEN_CARD];
+ char axisnum[10], root[9];
+
+ if (*status > 0)
+ return(*status);
+
+ /* get column number */
+ if (ffgcno(*fptr, CASEINSEN, colname, &colnum, status) > 0)
+ {
+ ffpmsg("column containing image in table cell does not exist:");
+ ffpmsg(colname);
+ return(*status);
+ }
+
+ /*---------------------------------------------------*/
+ /* Check input and get parameters about the column: */
+ /*---------------------------------------------------*/
+ if ( ffgcpr(*fptr, colnum, rownum, 1L, 1L, 0, &scale, &zero,
+ tform, &twidth, &typecode, &maxelem, &startpos, &elemnum, &incre,
+ &repeat, &rowlen, &hdutype, &tnull, (char *) buffer, status) > 0 )
+ return(*status);
+
+ if (hdutype != BINARY_TBL)
+ {
+ ffpmsg("This extension is not a binary table.");
+ ffpmsg(" Cannot open the image in a binary table cell.");
+ return(*status = NOT_BTABLE);
+ }
+
+ if (typecode < 0)
+ {
+ /* variable length array */
+ typecode *= -1;
+
+ /* variable length arrays are 1-dimensional by default */
+ naxis = 1;
+ naxes[0] = (long) repeat;
+ }
+ else
+ {
+ /* get the dimensions of the image */
+ ffgtdm(*fptr, colnum, 9, &naxis, naxes, status);
+ }
+
+ if (*status > 0)
+ {
+ ffpmsg("Error getting the dimensions of the image");
+ return(*status);
+ }
+
+ /* determine BITPIX value for the image */
+ if (typecode == TBYTE)
+ {
+ bitpix = BYTE_IMG;
+ nbytes = (long) repeat;
+ }
+ else if (typecode == TSHORT)
+ {
+ bitpix = SHORT_IMG;
+ nbytes = (long) repeat * 2;
+ }
+ else if (typecode == TLONG)
+ {
+ bitpix = LONG_IMG;
+ nbytes = (long) repeat * 4;
+ }
+ else if (typecode == TFLOAT)
+ {
+ bitpix = FLOAT_IMG;
+ nbytes = (long) repeat * 4;
+ }
+ else if (typecode == TDOUBLE)
+ {
+ bitpix = DOUBLE_IMG;
+ nbytes = (long) repeat * 8;
+ }
+ else
+ {
+ ffpmsg("Error: the following image column has invalid datatype:");
+ ffpmsg(colname);
+ ffpmsg(tform);
+ ffpmsg("Cannot open an image in a single row of this column.");
+ return(*status = BAD_TFORM);
+ }
+
+ /* create new empty file to hold copy of the image */
+ if (ffinit(&newptr, outfile, status) > 0)
+ {
+ ffpmsg("failed to create file for copy of image in table cell:");
+ ffpmsg(outfile);
+ return(*status);
+ }
+
+ if (ffcrim(newptr, bitpix, naxis, naxes, status) > 0)
+ {
+ ffpmsg("failed to write required primary array keywords in this file:");
+ ffpmsg(outfile);
+ return(*status);
+ }
+
+ /* write the BSCAL and BZERO keywords, if needed */
+ if (scale != 1.0)
+ ffpky(newptr, TDOUBLE, "BSCALE", &scale, "Array scaling factor",
+ status);
+
+ if (zero != 0.0)
+ ffpky(newptr, TDOUBLE, "BZERO", &zero, "Array scaling zero point",
+ status);
+
+ ffkeyn("TUNIT", colnum, keyname, status);
+ tstatus = 0;
+ if (ffgcrd(*fptr, keyname, card, &tstatus) == 0)
+ {
+ strncpy(card, "BUNIT ", 8);
+ ffprec(newptr, card, status);
+ }
+
+ ffkeyn("TNULL", colnum, keyname, status);
+ tstatus = 0;
+ if (ffgcrd(*fptr, keyname, card, &tstatus) == 0)
+ {
+ strncpy(card, "BLANK ", 8);
+ ffprec(newptr, card, status);
+ }
+
+ /* convert the nominal WCS keywords, if present */
+ strcpy(axisnum,"123456789");
+ for (ii = 0; ii < naxis; ii++)
+ {
+ strcpy(root, "1CTYP");
+ root[0] = axisnum[ii];
+ ffkeyn(root, colnum, keyname, status);
+ tstatus = 0;
+ if (ffgcrd(*fptr, keyname, card, &tstatus) == 0)
+ {
+ strncpy(card, "CTYPE1 ", 8);
+ card[5] = axisnum[ii];
+ ffprec(newptr, card, status);
+ }
+
+ strcpy(root, "1CUNI");
+ root[0] = axisnum[ii];
+ ffkeyn(root, colnum, keyname, status);
+ tstatus = 0;
+ if (ffgcrd(*fptr, keyname, card, &tstatus) == 0)
+ {
+ strncpy(card, "CUNIT1 ", 8);
+ card[5] = axisnum[ii];
+ ffprec(newptr, card, status);
+ }
+
+ strcpy(root, "1CRPX");
+ root[0] = axisnum[ii];
+ ffkeyn(root, colnum, keyname, status);
+ tstatus = 0;
+ if (ffgcrd(*fptr, keyname, card, &tstatus) == 0)
+ {
+ strncpy(card, "CRPIX1 ", 8);
+ card[5] = axisnum[ii];
+ ffprec(newptr, card, status);
+ }
+
+ strcpy(root, "1CRVL");
+ root[0] = axisnum[ii];
+ ffkeyn(root, colnum, keyname, status);
+ tstatus = 0;
+ if (ffgcrd(*fptr, keyname, card, &tstatus) == 0)
+ {
+ strncpy(card, "CRVAL1 ", 8);
+ card[5] = axisnum[ii];
+ ffprec(newptr, card, status);
+ }
+
+ strcpy(root, "1CDLT");
+ root[0] = axisnum[ii];
+ ffkeyn(root, colnum, keyname, status);
+ tstatus = 0;
+ if (ffgcrd(*fptr, keyname, card, &tstatus) == 0)
+ {
+ strncpy(card, "CDELT1 ", 8);
+ card[5] = axisnum[ii];
+ ffprec(newptr, card, status);
+ }
+
+ strcpy(root, "1CROT");
+ root[0] = axisnum[ii];
+ ffkeyn(root, colnum, keyname, status);
+ tstatus = 0;
+ if (ffgcrd(*fptr, keyname, card, &tstatus) == 0)
+ {
+ strncpy(card, "CROTA1 ", 8);
+ card[5] = axisnum[ii];
+ ffprec(newptr, card, status);
+ }
+ }
+
+ /* copy all other relevant keywords */
+ fits_copy_image_keywords(*fptr, newptr, status);
+
+ /* add some HISTORY */
+ sprintf(card,"HISTORY This image was copied from row %ld of column '%s',",
+ rownum, colname);
+ ffprec(newptr, card, status);
+
+ /* finally, copy the data, one buffer size at a time */
+ ffmbyt(*fptr, startpos, TRUE, status);
+ firstbyte = 1;
+
+ /* the upper limit on the number of bytes must match the declaration */
+ /* read up to the first 30000 bytes in the normal way with ffgbyt */
+ ntodo = minvalue(30000L, nbytes);
+ ffgbyt(*fptr, ntodo, buffer, status);
+ ffptbb(newptr, 1, firstbyte, ntodo, buffer, status);
+
+ nbytes -= ntodo;
+ firstbyte += ntodo;
+
+ /* read any additional bytes with low-level ffread routine, for speed */
+ while (nbytes && (*status <= 0) )
+ {
+ ntodo = minvalue(30000L, nbytes);
+ ffread((*fptr)->Fptr, ntodo, buffer, status);
+ ffptbb(newptr, 1, firstbyte, ntodo, buffer, status);
+ nbytes -= ntodo;
+ firstbyte += ntodo;
+ }
+
+ /* close the original file and return ptr to the new image */
+ ffclos(*fptr, status);
+
+ *fptr = newptr; /* reset the pointer to the new table */
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fits_copy_image_keywords(
+ fitsfile *infptr, /* I - pointer to input table */
+ fitsfile *outfptr, /* I - pointer to input table */
+ int *status)
+/*
+ Copy relevant keywords from the table header into the newly created
+ primary array header. Convert names of keywords where appropriate.
+*/
+{
+ int nrec, nkeys, nmore;
+ char rec[FLEN_CARD], *root;
+
+ if (*status > 0)
+ return(*status);
+
+ ffghsp(infptr, &nkeys, &nmore, status); /* get number of keywords */
+ root = rec + 1;
+
+ for (nrec = 9; nrec <= nkeys; nrec++)
+ {
+ ffgrec(infptr, nrec, rec, status);
+
+ if (*rec == 'T')
+ {
+ if (!strncmp(root, "FORM", 4) || !strncmp(root, "HEAP", 4) ||
+ !strncmp(root, "TYPE", 4) || !strncmp(root, "SCAL", 4) ||
+ !strncmp(root, "ZERO", 4) || !strncmp(root, "DISP", 4) ||
+ !strncmp(root, "LMIN", 4) || !strncmp(root, "LMAX", 4) ||
+ !strncmp(root, "DMIN", 4) || !strncmp(root, "DMAX", 4) ||
+ !strncmp(root, "CTYP", 4) || !strncmp(root, "CRPX", 4) ||
+ !strncmp(root, "CRVL", 4) || !strncmp(root, "CDLT", 4) ||
+ !strncmp(root, "CROT", 4) || !strncmp(root, "CUNI", 4) ||
+ !strncmp(root, "UNIT", 4) || !strncmp(root, "NULL", 4) ||
+ !strncmp(root, "DIM" , 3) || !strncmp(root, "BCOL", 4) )
+
+ /* will have to deal with the WCS keywords separately */
+ {
+ continue; /* ignore these keywords */
+ }
+ else
+ {
+ ffprec(outfptr, rec, status); /* copy the keyword */
+ }
+ }
+ else if (isdigit((int) *rec) )
+ {
+ if ( !strncmp(root, "CTYP", 4) || !strncmp(root, "CRPX", 4) ||
+ !strncmp(root, "CRVL", 4) || !strncmp(root, "CDLT", 4) ||
+ !strncmp(root, "CROT", 4) || !strncmp(root, "CUNI", 4) )
+
+ /* will have to deal with the WCS keywords separately */
+ {
+ continue; /* ignore these keywords */
+ }
+ else
+ {
+ ffprec(outfptr, rec, status); /* copy the keyword */
+ }
+ }
+ else if (*rec == 'E' && *root == 'X')
+ {
+ if (!strncmp(root, "XTNAME", 6) || !strncmp(root, "XTVER", 5) ||
+ !strncmp(root, "XTLEVEL", 7) )
+ {
+ continue;
+ }
+ else
+ {
+ ffprec(outfptr, rec, status); /* copy the keyword */
+ }
+ }
+ else
+ {
+ ffprec(outfptr, rec, status); /* copy the keyword */
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fits_select_image_section(
+ fitsfile **fptr, /* IO - pointer to input image; on output it */
+ /* points to the new subimage */
+ char *outfile, /* I - name for output file */
+ char *expr, /* I - Image section expression */
+ int *status)
+{
+ /*
+ copies an image section from the input file to an output file
+ */
+
+ fitsfile *newptr;
+ int ii, hdunum, naxis, bitpix, tstatus, anynull, nkey, numkeys;
+ long naxes[9], smin, smax, sinc, fpixels[9], lpixels[9], incs[9];
+ long outnaxes[9], outsize, buffsize, dummy[2];
+ char *cptr, keyname[FLEN_KEYWORD], card[FLEN_CARD];
+ double *buffer = 0, crpix, cdelt;
+
+ /* create new empty file to hold the image section */
+ if (ffinit(&newptr, outfile, status) > 0)
+ {
+ ffpmsg(
+ "failed to create output file for image section:");
+ ffpmsg(outfile);
+ return(*status);
+ }
+
+ fits_get_hdu_num(*fptr, &hdunum); /* current HDU number in input file */
+
+ /* copy all preceding extensions to the output file */
+ for (ii = 1; ii < hdunum; ii++)
+ {
+ fits_movabs_hdu(*fptr, ii, NULL, status);
+ if (fits_copy_hdu(*fptr, newptr, 0, status) > 0)
+ {
+ ffclos(newptr, status);
+ return(*status);
+ }
+ }
+
+ /* move back to the original HDU position */
+ fits_movabs_hdu(*fptr, hdunum, NULL, status);
+
+ /* get the size of the input image */
+ fits_get_img_type(*fptr, &bitpix, status);
+ fits_get_img_dim(*fptr, &naxis, status);
+ if (fits_get_img_size(*fptr, naxis, naxes, status) > 0)
+ {
+ ffclos(newptr, status);
+ return(*status);
+ }
+
+ if (naxis < 1 || naxis > 9)
+ {
+ ffpmsg(
+ "Input image either had NAXIS = 0 (NULL image) or has > 9 dimensions");
+ ffclos(newptr, status);
+ return(*status = BAD_NAXIS);
+ }
+
+ /* create output image with same size and type as the input image */
+ /* Will update the size later */
+ fits_create_img(newptr, bitpix, naxis, naxes, status);
+
+ /* copy all other non-structural keywords from the input to output file */
+ fits_get_hdrspace(*fptr, &numkeys, NULL, status);
+
+ for (nkey = 4; nkey <= numkeys; nkey++) /* skip the first few keywords */
+ {
+ fits_read_record(*fptr, nkey, card, status);
+
+ if (fits_get_keyclass(card) > TYP_CMPRS_KEY)
+ {
+ /* write the record to the output file */
+ fits_write_record(newptr, card, status);
+ }
+ }
+
+ if (*status > 0)
+ {
+ ffpmsg("error copying header from input image to output image");
+ return(*status);
+ }
+
+ /* parse the section specifier to get min, max, and inc for each axis */
+ /* and the size of each output image axis */
+
+ outsize = 1;
+ cptr = expr;
+ for (ii=0; ii < naxis; ii++)
+ {
+
+ if (fits_get_section_range(&cptr, &smin, &smax, &sinc, status) > 0)
+ {
+ ffpmsg("error parsing the following image section specifier:");
+ ffpmsg(expr);
+ ffclos(newptr, status);
+ return(*status);
+ }
+
+ if (smax == 0)
+ smax = naxes[ii]; /* use whole axis by default */
+ else if (smin == 0)
+ smin = naxes[ii]; /* use inverted whole axis */
+
+ if (smin > naxes[ii] || smax > naxes[ii])
+ {
+ ffpmsg("image section exceeds dimensions of input image:");
+ ffpmsg(expr);
+ ffclos(newptr, status);
+ return(*status = BAD_NAXIS);
+ }
+
+ fpixels[ii] = smin;
+ lpixels[ii] = smax;
+ incs[ii] = sinc;
+
+ if (smin <= smax)
+ outnaxes[ii] = (smax - smin + sinc) / sinc;
+ else
+ outnaxes[ii] = (smin - smax + sinc) / sinc;
+
+ outsize = outsize * outnaxes[ii];
+
+ /* modify the NAXISn keyword */
+ fits_make_keyn("NAXIS", ii + 1, keyname, status);
+ fits_modify_key_lng(newptr, keyname, outnaxes[ii], NULL, status);
+
+ /* modify the WCS keywords if necessary */
+
+ if (fpixels[ii] != 1 || incs[ii] != 1)
+ {
+ /* read the CRPIXn keyword if it exists in the input file */
+ fits_make_keyn("CRPIX", ii + 1, keyname, status);
+ tstatus = 0;
+
+ if (fits_read_key(*fptr, TDOUBLE, keyname,
+ &crpix, NULL, &tstatus) == 0)
+ {
+ /* calculate the new CRPIXn value */
+ if (fpixels[ii] <= lpixels[ii])
+ crpix = (crpix - (fpixels[ii] - 1.0) - .5) / incs[ii] + 0.5;
+ else
+ crpix = (fpixels[ii] - (crpix - 1.0) - .5) / incs[ii] + 0.5;
+
+ /* modify the value in the output file */
+ fits_modify_key_dbl(newptr, keyname, crpix, 15, NULL, status);
+
+ if (incs[ii] != 1 || fpixels[ii] > lpixels[ii])
+ {
+ /* read the CDELTn keyword if it exists in the input file */
+ fits_make_keyn("CDELT", ii + 1, keyname, status);
+ tstatus = 0;
+
+ if (fits_read_key(*fptr, TDOUBLE, keyname,
+ &cdelt, NULL, &tstatus) == 0)
+ {
+ /* calculate the new CDELTn value */
+ if (fpixels[ii] <= lpixels[ii])
+ cdelt = cdelt * incs[ii];
+ else
+ cdelt = cdelt * (-incs[ii]);
+
+ /* modify the value in the output file */
+ fits_modify_key_dbl(newptr, keyname, cdelt, 15, NULL, status);
+ }
+
+ /* modify the CDi_j keywords if thet exist in the input file */
+
+ fits_make_keyn("CD1_", ii + 1, keyname, status);
+ tstatus = 0;
+ if (fits_read_key(*fptr, TDOUBLE, keyname,
+ &cdelt, NULL, &tstatus) == 0)
+ {
+ /* calculate the new CDi_j value */
+ if (fpixels[ii] <= lpixels[ii])
+ cdelt = cdelt * incs[ii];
+ else
+ cdelt = cdelt * (-incs[ii]);
+
+ /* modify the value in the output file */
+ fits_modify_key_dbl(newptr, keyname, cdelt, 15, NULL, status);
+ }
+
+ fits_make_keyn("CD2_", ii + 1, keyname, status);
+ tstatus = 0;
+ if (fits_read_key(*fptr, TDOUBLE, keyname,
+ &cdelt, NULL, &tstatus) == 0)
+ {
+ /* calculate the new CDi_j value */
+ if (fpixels[ii] <= lpixels[ii])
+ cdelt = cdelt * incs[ii];
+ else
+ cdelt = cdelt * (-incs[ii]);
+
+ /* modify the value in the output file */
+ fits_modify_key_dbl(newptr, keyname, cdelt, 15, NULL, status);
+ }
+ }
+ }
+ }
+ } /* end of main NAXIS loop */
+
+ if (ffrdef(newptr, status) > 0) /* force the header to be scanned */
+ {
+ ffclos(newptr, status);
+ return(*status);
+ }
+
+ /* write a dummy value to the last pixel in the output section */
+ /* This will force memory to be allocated for the FITS files if it */
+ /* is being written in memory, before we allocate some more memory */
+ /* below. Hopefully this leads to better memory management and */
+ /* reduces the probability that the memory for the FITS file will have */
+ /* to be reallocated to a new location later. */
+
+ /* turn off any scaling of the pixel values */
+ fits_set_bscale(*fptr, 1.0, 0.0, status);
+ fits_set_bscale(newptr, 1.0, 0.0, status);
+
+ dummy[0] = 0;
+ if (fits_write_img(newptr, TLONG, outsize, 1, dummy, status) > 0)
+ {
+ ffpmsg("error trying to write dummy value to the last image pixel");
+ ffclos(newptr, status);
+ return(*status);
+ }
+
+ /* allocate memory for the entire image section */
+ buffsize = (abs(bitpix) / 8) * outsize;
+
+ buffer = (double *) malloc(buffsize);
+ if (!buffer)
+ {
+ ffpmsg("error allocating memory for image section");
+ ffclos(newptr, status);
+ return(*status = MEMORY_ALLOCATION);
+ }
+
+ /* read the image section then write it to the output file */
+
+ if (bitpix == 8)
+ {
+ ffgsvb(*fptr, 1, naxis, naxes, fpixels, lpixels, incs, 0,
+ (unsigned char *) buffer, &anynull, status);
+
+ ffpprb(newptr, 1, 1, outsize, (unsigned char *) buffer, status);
+ }
+ else if (bitpix == 16)
+ {
+ ffgsvi(*fptr, 1, naxis, naxes, fpixels, lpixels, incs, 0,
+ (short *) buffer, &anynull, status);
+
+ ffppri(newptr, 1, 1, outsize, (short *) buffer, status);
+ }
+ else if (bitpix == 32)
+ {
+ ffgsvk(*fptr, 1, naxis, naxes, fpixels, lpixels, incs, 0,
+ (int *) buffer, &anynull, status);
+
+ ffpprk(newptr, 1, 1, outsize, (int *) buffer, status);
+ }
+ else if (bitpix == -32)
+ {
+ ffgsve(*fptr, 1, naxis, naxes, fpixels, lpixels, incs, FLOATNULLVALUE,
+ (float *) buffer, &anynull, status);
+
+ ffppne(newptr, 1, 1, outsize, (float *) buffer, FLOATNULLVALUE, status);
+ }
+ else if (bitpix == -64)
+ {
+ ffgsvd(*fptr, 1, naxis, naxes, fpixels, lpixels, incs, DOUBLENULLVALUE,
+ buffer, &anynull, status);
+
+ ffppnd(newptr, 1, 1, outsize, buffer, DOUBLENULLVALUE,
+ status);
+ }
+
+ free(buffer); /* finished with the memory */
+
+ if (*status > 0)
+ {
+ ffpmsg("error copying image section from input to output file");
+ ffclos(newptr, status);
+ return(*status);
+ }
+
+ /* copy any remaining HDUs to the output file */
+
+ for (ii = hdunum + 1; 1; ii++)
+ {
+ if (fits_movabs_hdu(*fptr, ii, NULL, status) > 0)
+ break;
+
+ fits_copy_hdu(*fptr, newptr, 0, status);
+ }
+
+ if (*status == END_OF_FILE)
+ *status = 0; /* got the expected EOF error; reset = 0 */
+ else if (*status > 0)
+ {
+ ffclos(newptr, status);
+ return(*status);
+ }
+
+ /* close the original file and return ptr to the new image */
+ ffclos(*fptr, status);
+
+ *fptr = newptr; /* reset the pointer to the new table */
+
+ /* move back to the image subsection */
+ if (ii - 1 != hdunum)
+ fits_movabs_hdu(*fptr, hdunum, NULL, status);
+ else
+ {
+ /* may have to reset BSCALE and BZERO pixel scaling, */
+ /* since the keywords were previously turned off */
+
+ if (ffrdef(*fptr, status) > 0)
+ {
+ ffclos(*fptr, status);
+ return(*status);
+ }
+
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fits_get_section_range(char **ptr,
+ long *secmin,
+ long *secmax,
+ long *incre,
+ int *status)
+/*
+ Parse the input image section specification string, returning
+ the min, max and increment values.
+ Typical string = "1:512:2" or "1:512"
+*/
+{
+ int slen, isanumber;
+ char token[FLEN_VALUE];
+
+ if (*status > 0)
+ return(*status);
+
+ slen = fits_get_token(ptr, " ,:", token, &isanumber); /* get 1st token */
+
+ if (*token == '*') /* wild card means to use the whole range */
+ {
+ *secmin = 1;
+ *secmax = 0;
+ }
+ else if (*token == '-' && *(token+1) == '*' ) /* invert the whole range */
+ {
+ *secmin = 0;
+ *secmax = 1;
+ }
+ else
+ {
+ if (slen == 0 || !isanumber || **ptr != ':')
+ return(*status = URL_PARSE_ERROR);
+
+ /* the token contains the min value */
+ *secmin = atol(token);
+
+ (*ptr)++; /* skip the colon between the min and max values */
+ slen = fits_get_token(ptr, " ,:", token, &isanumber); /* get token */
+
+ if (slen == 0 || !isanumber)
+ return(*status = URL_PARSE_ERROR);
+
+ /* the token contains the max value */
+ *secmax = atol(token);
+ }
+
+ if (**ptr == ':')
+ {
+ (*ptr)++; /* skip the colon between the max and incre values */
+ slen = fits_get_token(ptr, " ,", token, &isanumber); /* get token */
+
+ if (slen == 0 || !isanumber)
+ return(*status = URL_PARSE_ERROR);
+
+ *incre = atol(token);
+ }
+ else
+ *incre = 1; /* default increment if none is supplied */
+
+ if (**ptr == ',')
+ (*ptr)++;
+
+ while (**ptr == ' ') /* skip any trailing blanks */
+ (*ptr)++;
+
+ if (*secmin < 0 || *secmax < 0 || *incre < 1)
+ *status = URL_PARSE_ERROR;
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffselect_table(
+ fitsfile **fptr, /* IO - pointer to input table; on output it */
+ /* points to the new selected rows table */
+ char *outfile, /* I - name for output file */
+ char *expr, /* I - Boolean expression */
+ int *status)
+{
+ fitsfile *newptr;
+ int ii, hdunum;
+
+ if (*outfile)
+ {
+ /* create new empty file in to hold the selected rows */
+ if (ffinit(&newptr, outfile, status) > 0)
+ {
+ ffpmsg(
+ "failed to create file for selected rows from input table");
+ ffpmsg(outfile);
+ return(*status);
+ }
+
+ fits_get_hdu_num(*fptr, &hdunum); /* current HDU number in input file */
+
+ /* copy all preceding extensions to the output file */
+ for (ii = 1; ii < hdunum; ii++)
+ {
+ fits_movabs_hdu(*fptr, ii, NULL, status);
+ if (fits_copy_hdu(*fptr, newptr, 0, status) > 0)
+ {
+ ffclos(newptr, status);
+ return(*status);
+ }
+ }
+
+ /* copy all the header keywords from the input to output file */
+ fits_movabs_hdu(*fptr, hdunum, NULL, status);
+ if (fits_copy_header(*fptr, newptr, status) > 0)
+ {
+ ffclos(newptr, status);
+ return(*status);
+ }
+
+ /* set number of rows = 0 */
+ fits_modify_key_lng(newptr, "NAXIS2", 0, NULL,status);
+ (newptr->Fptr)->numrows = 0;
+ (newptr->Fptr)->origrows = 0;
+
+ if (ffrdef(newptr, status) > 0) /* force the header to be scanned */
+ {
+ ffclos(newptr, status);
+ return(*status);
+ }
+ }
+ else
+ newptr = *fptr; /* will delete rows in place in the table */
+
+ /* copy rows which satisfy the selection expression to the output table */
+ /* or delete the nonqualifying rows if *fptr = newptr. */
+ if (fits_select_rows(*fptr, newptr, expr, status) > 0)
+ {
+ if (*outfile)
+ ffclos(newptr, status);
+
+ return(*status);
+ }
+
+ if (*outfile)
+ {
+ /* copy any remaining HDUs to the output copy */
+
+ for (ii = hdunum + 1; 1; ii++)
+ {
+ if (fits_movabs_hdu(*fptr, ii, NULL, status) > 0)
+ break;
+
+ fits_copy_hdu(*fptr, newptr, 0, status);
+ }
+
+ if (*status == END_OF_FILE)
+ *status = 0; /* got the expected EOF error; reset = 0 */
+ else if (*status > 0)
+ {
+ ffclos(newptr, status);
+ return(*status);
+ }
+
+ /* close the original file and return ptr to the new image */
+ ffclos(*fptr, status);
+
+ *fptr = newptr; /* reset the pointer to the new table */
+
+ /* move back to the selected table HDU */
+ fits_movabs_hdu(*fptr, hdunum, NULL, status);
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffparsecompspec(fitsfile *fptr, /* I - FITS file pointer */
+ char *compspec, /* I - image compression specification */
+ int *status) /* IO - error status */
+/*
+ Parse the image compression specification that was give in square brackets
+ following the output FITS file name, as in these examples:
+
+ myfile.fits[compress] - default Rice compression, row by row
+ myfile.fits[compress TYPE] - the first letter of TYPE defines the
+ compression algorithm:
+ R = Rice
+ G = GZIP
+ P = PLIO
+
+ myfile.fits[compress TYPE 100,100] - the numbers give the dimensions
+ of the compression tiles. Default
+ is NAXIS1, 1, 1, ...
+
+ myfile.fits[compress; 5] The number following the semicolon
+ mufile.fits[compress TYPE; 5] gives the value of the noisebits
+ myfile.fits[compress TYPE 100,100; 5] parameter that is used when
+ quantizing floating point images.
+
+The compression parameters are saved in the fptr->Fptr structure for use
+when writing FITS images.
+
+*/
+{
+ char *ptr1;
+
+ /* initialize with default values */
+ int ii, compresstype = RICE_1, noisebits = 4;
+ long tilesize[9] = {0,1,1,1,1,1,1,1,1};
+
+ ptr1 = compspec;
+ while (*ptr1 == ' ') /* ignore leading blanks */
+ ptr1++;
+
+ if (strncmp(ptr1, "compress", 8) && strncmp(ptr1, "COMPRESS", 8) )
+ {
+ /* apparently this string does not specify compression parameters */
+ return(*status = URL_PARSE_ERROR);
+ }
+
+ ptr1 += 8;
+ while (*ptr1 == ' ') /* ignore leading blanks */
+ ptr1++;
+
+ /* ========================= */
+ /* look for compression type */
+ /* ========================= */
+
+ if (*ptr1 == 'r' || *ptr1 == 'R')
+ {
+ compresstype = RICE_1;
+ while (*ptr1 != ' ' && *ptr1 != ';' && *ptr1 != '\0')
+ ptr1++;
+ }
+ else if (*ptr1 == 'g' || *ptr1 == 'G')
+ {
+ compresstype = GZIP_1;
+ while (*ptr1 != ' ' && *ptr1 != ';' && *ptr1 != '\0')
+ ptr1++;
+
+ }
+ else if (*ptr1 == 'p' || *ptr1 == 'P')
+ {
+ compresstype = PLIO_1;
+ while (*ptr1 != ' ' && *ptr1 != ';' && *ptr1 != '\0')
+ ptr1++;
+ }
+
+ /* ======================== */
+ /* look for tile dimensions */
+ /* ======================== */
+
+ while (*ptr1 == ' ') /* ignore leading blanks */
+ ptr1++;
+
+ ii = 0;
+ while (isdigit( (int) *ptr1) && ii < 9)
+ {
+ tilesize[ii] = atol(ptr1); /* read the integer value */
+ ii++;
+
+ while (isdigit((int) *ptr1)) /* skip over the integer */
+ ptr1++;
+
+ if (*ptr1 == ',')
+ ptr1++; /* skip over the comma */
+
+ while (*ptr1 == ' ') /* ignore leading blanks */
+ ptr1++;
+ }
+
+ /* ============================= */
+ /* look for noise bits parameter */
+ /* ============================= */
+
+ if (*ptr1 == ';')
+ {
+ ptr1++;
+
+ while (*ptr1 == ' ') /* ignore leading blanks */
+ ptr1++;
+
+ if (!isdigit((int) *ptr1) )
+ return(*status = URL_PARSE_ERROR);
+
+ noisebits = atol(ptr1); /* read the integer value */
+
+ while (isdigit((int) *ptr1)) /* skip over the integer */
+ ptr1++;
+ }
+
+ while (*ptr1 == ' ') /* ignore leading blanks */
+ ptr1++;
+
+ if (*ptr1 != 0) /* remaining junk in the string?? */
+ return(*status = URL_PARSE_ERROR);
+
+ /* ================================= */
+ /* finished parsing; save the values */
+ /* ================================= */
+
+ (fptr->Fptr)->request_compress_type = compresstype;
+ for (ii = 0; ii < 9; ii++)
+ (fptr->Fptr)->request_tilesize[ii] = tilesize[ii];
+ (fptr->Fptr)->request_rice_nbits = noisebits;
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffdkinit(fitsfile **fptr, /* O - FITS file pointer */
+ const char *name, /* I - name of file to create */
+ int *status) /* IO - error status */
+/*
+ Create and initialize a new FITS file on disk. This routine differs
+ from ffinit in that the input 'name' is literally taken as the name
+ of the disk file to be created, and it does not support CFITSIO's
+ extended filename syntax.
+*/
+{
+ if (*status > 0)
+ return(*status);
+
+ *status = CREATE_DISK_FILE;
+
+ ffinit(fptr, name,status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffinit(fitsfile **fptr, /* O - FITS file pointer */
+ const char *name, /* I - name of file to create */
+ int *status) /* IO - error status */
+/*
+ Create and initialize a new FITS file.
+*/
+{
+ int driver, slen, clobber = 0;
+ char *url;
+ char urltype[MAX_PREFIX_LEN], outfile[FLEN_FILENAME];
+ char tmplfile[FLEN_FILENAME], compspec[80];
+ int handle, create_disk_file = 0;
+
+ if (*status > 0)
+ return(*status);
+
+ if (*status == CREATE_DISK_FILE)
+ {
+ create_disk_file = 1;
+ *status = 0;
+ }
+
+ *fptr = 0; /* initialize null file pointer */
+
+ if (need_to_initialize) /* this is called only once */
+ *status = fits_init_cfitsio();
+
+ if (*status > 0)
+ return(*status);
+
+ url = (char *) name;
+ while (*url == ' ') /* ignore leading spaces in the filename */
+ url++;
+
+ if (*url == '\0')
+ {
+ ffpmsg("Name of file to create is blank. (ffinit)");
+ return(*status = FILE_NOT_CREATED);
+ }
+
+ if (create_disk_file)
+ {
+ strcpy(outfile, url);
+ strcpy(urltype, "file://");
+ tmplfile[0] = '\0';
+ compspec[0] = '\0';
+ }
+ else
+ {
+
+ /* check for clobber symbol, i.e, overwrite existing file */
+ if (*url == '!')
+ {
+ clobber = TRUE;
+ url++;
+ }
+ else
+ clobber = FALSE;
+
+ /* parse the output file specification */
+ ffourl(url, urltype, outfile, tmplfile, compspec, status);
+
+ if (*status > 0)
+ {
+ ffpmsg("could not parse the output filename: (ffinit)");
+ ffpmsg(url);
+ return(*status);
+ }
+ }
+
+ /* find which driver corresponds to the urltype */
+ *status = urltype2driver(urltype, &driver);
+
+ if (*status)
+ {
+ ffpmsg("could not find driver for this file: (ffinit)");
+ ffpmsg(url);
+ return(*status);
+ }
+
+ /* delete pre-existing file, if asked to do so */
+ if (clobber)
+ {
+ if (driverTable[driver].remove)
+ (*driverTable[driver].remove)(outfile);
+ }
+
+ /* call appropriate driver to create the file */
+ if (driverTable[driver].create)
+ {
+ *status = (*driverTable[driver].create)(outfile, &handle);
+ if (*status)
+ {
+ ffpmsg("failed to create new file (already exists?):");
+ ffpmsg(url);
+ return(*status);
+ }
+ }
+ else
+ {
+ ffpmsg("cannot create a new file of this type: (ffinit)");
+ ffpmsg(url);
+ return(*status = FILE_NOT_CREATED);
+ }
+
+ /* allocate fitsfile structure and initialize = 0 */
+ *fptr = (fitsfile *) calloc(1, sizeof(fitsfile));
+
+ if (!(*fptr))
+ {
+ (*driverTable[driver].close)(handle); /* close the file */
+ ffpmsg("failed to allocate structure for following file: (ffopen)");
+ ffpmsg(url);
+ return(*status = MEMORY_ALLOCATION);
+ }
+
+ /* allocate FITSfile structure and initialize = 0 */
+ (*fptr)->Fptr = (FITSfile *) calloc(1, sizeof(FITSfile));
+
+ if (!((*fptr)->Fptr))
+ {
+ (*driverTable[driver].close)(handle); /* close the file */
+ ffpmsg("failed to allocate structure for following file: (ffopen)");
+ ffpmsg(url);
+ free(*fptr);
+ *fptr = 0;
+ return(*status = MEMORY_ALLOCATION);
+ }
+
+ slen = strlen(url) + 1;
+ slen = maxvalue(slen, 32); /* reserve at least 32 chars */
+ ((*fptr)->Fptr)->filename = (char *) malloc(slen); /* mem for file name */
+
+ if ( !(((*fptr)->Fptr)->filename) )
+ {
+ (*driverTable[driver].close)(handle); /* close the file */
+ ffpmsg("failed to allocate memory for filename: (ffinit)");
+ ffpmsg(url);
+ free((*fptr)->Fptr);
+ free(*fptr);
+ *fptr = 0; /* return null file pointer */
+ return(*status = FILE_NOT_CREATED);
+ }
+
+ /* mem for headstart array */
+ ((*fptr)->Fptr)->headstart = (OFF_T *) calloc(1001, sizeof(OFF_T));
+
+ if ( !(((*fptr)->Fptr)->headstart) )
+ {
+ (*driverTable[driver].close)(handle); /* close the file */
+ ffpmsg("failed to allocate memory for headstart array: (ffinit)");
+ ffpmsg(url);
+ free( ((*fptr)->Fptr)->filename);
+ free((*fptr)->Fptr);
+ free(*fptr);
+ *fptr = 0; /* return null file pointer */
+ return(*status = MEMORY_ALLOCATION);
+ }
+
+ /* store the parameters describing the file */
+ ((*fptr)->Fptr)->MAXHDU = 1000; /* initial size of headstart */
+ ((*fptr)->Fptr)->filehandle = handle; /* store the file pointer */
+ ((*fptr)->Fptr)->driver = driver; /* driver number */
+ strcpy(((*fptr)->Fptr)->filename, url); /* full input filename */
+ ((*fptr)->Fptr)->filesize = 0; /* physical file size */
+ ((*fptr)->Fptr)->logfilesize = 0; /* logical file size */
+ ((*fptr)->Fptr)->writemode = 1; /* read-write mode */
+ ((*fptr)->Fptr)->datastart = DATA_UNDEFINED; /* unknown start of data */
+ ((*fptr)->Fptr)->curbuf = -1; /* undefined current IO buffer */
+ ((*fptr)->Fptr)->open_count = 1; /* structure is currently used once */
+ ((*fptr)->Fptr)->validcode = VALIDSTRUC; /* flag denoting valid structure */
+
+ ffldrc(*fptr, 0, IGNORE_EOF, status); /* initialize first record */
+
+ fits_store_Fptr( (*fptr)->Fptr, status); /* store Fptr address */
+
+ /* if template file was given, use it to define structure of new file */
+
+ if (tmplfile[0])
+ ffoptplt(*fptr, tmplfile, status);
+
+ /* parse and save image compression specification, if given */
+ if (compspec[0])
+ ffparsecompspec(*fptr, compspec, status);
+
+ return(*status); /* successful return */
+}
+/*--------------------------------------------------------------------------*/
+/* ffimem == fits_create_memfile */
+
+int ffimem(fitsfile **fptr, /* O - FITS file pointer */
+ void **buffptr, /* I - address of memory pointer */
+ size_t *buffsize, /* I - size of buffer, in bytes */
+ size_t deltasize, /* I - increment for future realloc's */
+ void *(*mem_realloc)(void *p, size_t newsize), /* function */
+ int *status) /* IO - error status */
+
+/*
+ Create and initialize a new FITS file in memory
+*/
+{
+ int driver, slen;
+ char urltype[MAX_PREFIX_LEN];
+ int handle;
+
+ if (*status > 0)
+ return(*status);
+
+ *fptr = 0; /* initialize null file pointer */
+
+ if (need_to_initialize) /* this is called only once */
+ *status = fits_init_cfitsio();
+
+ if (*status > 0)
+ return(*status);
+
+ strcpy(urltype, "memkeep://"); /* URL type for pre-existing memory file */
+
+ *status = urltype2driver(urltype, &driver);
+
+ if (*status > 0)
+ {
+ ffpmsg("could not find driver for pre-existing memory file: (ffimem)");
+ return(*status);
+ }
+
+ /* call driver routine to "open" the memory file */
+ *status = mem_openmem( buffptr, buffsize, deltasize,
+ mem_realloc, &handle);
+
+ if (*status > 0)
+ {
+ ffpmsg("failed to open pre-existing memory file: (ffimem)");
+ return(*status);
+ }
+
+ /* allocate fitsfile structure and initialize = 0 */
+ *fptr = (fitsfile *) calloc(1, sizeof(fitsfile));
+
+ if (!(*fptr))
+ {
+ (*driverTable[driver].close)(handle); /* close the file */
+ ffpmsg("failed to allocate structure for memory file: (ffimem)");
+ return(*status = MEMORY_ALLOCATION);
+ }
+
+ /* allocate FITSfile structure and initialize = 0 */
+ (*fptr)->Fptr = (FITSfile *) calloc(1, sizeof(FITSfile));
+
+ if (!((*fptr)->Fptr))
+ {
+ (*driverTable[driver].close)(handle); /* close the file */
+ ffpmsg("failed to allocate structure for memory file: (ffimem)");
+ free(*fptr);
+ *fptr = 0;
+ return(*status = MEMORY_ALLOCATION);
+ }
+
+ slen = 32; /* reserve at least 32 chars */
+ ((*fptr)->Fptr)->filename = (char *) malloc(slen); /* mem for file name */
+
+ if ( !(((*fptr)->Fptr)->filename) )
+ {
+ (*driverTable[driver].close)(handle); /* close the file */
+ ffpmsg("failed to allocate memory for filename: (ffimem)");
+ free((*fptr)->Fptr);
+ free(*fptr);
+ *fptr = 0; /* return null file pointer */
+ return(*status = MEMORY_ALLOCATION);
+ }
+
+ /* mem for headstart array */
+ ((*fptr)->Fptr)->headstart = (OFF_T *) calloc(1001, sizeof(OFF_T));
+
+ if ( !(((*fptr)->Fptr)->headstart) )
+ {
+ (*driverTable[driver].close)(handle); /* close the file */
+ ffpmsg("failed to allocate memory for headstart array: (ffinit)");
+ free( ((*fptr)->Fptr)->filename);
+ free((*fptr)->Fptr);
+ free(*fptr);
+ *fptr = 0; /* return null file pointer */
+ return(*status = MEMORY_ALLOCATION);
+ }
+
+ /* store the parameters describing the file */
+ ((*fptr)->Fptr)->MAXHDU = 1000; /* initial size of headstart */
+ ((*fptr)->Fptr)->filehandle = handle; /* file handle */
+ ((*fptr)->Fptr)->driver = driver; /* driver number */
+ strcpy(((*fptr)->Fptr)->filename, "memfile"); /* dummy filename */
+ ((*fptr)->Fptr)->filesize = *buffsize; /* physical file size */
+ ((*fptr)->Fptr)->logfilesize = *buffsize; /* logical file size */
+ ((*fptr)->Fptr)->writemode = 1; /* read-write mode */
+ ((*fptr)->Fptr)->datastart = DATA_UNDEFINED; /* unknown start of data */
+ ((*fptr)->Fptr)->curbuf = -1; /* undefined current IO buffer */
+ ((*fptr)->Fptr)->open_count = 1; /* structure is currently used once */
+ ((*fptr)->Fptr)->validcode = VALIDSTRUC; /* flag denoting valid structure */
+
+ ffldrc(*fptr, 0, IGNORE_EOF, status); /* initialize first record */
+ fits_store_Fptr( (*fptr)->Fptr, status); /* store Fptr address */
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fits_init_cfitsio(void)
+/*
+ initialize anything that is required before using the CFITSIO routines
+*/
+{
+ int status;
+
+ union u_tag {
+ short ival;
+ char cval[2];
+ } u;
+
+ need_to_initialize = 0;
+
+ /* test for correct byteswapping. */
+
+ u.ival = 1;
+ if ((BYTESWAPPED && u.cval[0] != 1) ||
+ (BYTESWAPPED == FALSE && u.cval[1] != 1) )
+ {
+ printf ("\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
+ printf(" Byteswapping is not being done correctly on this system.\n");
+ printf(" Check the MACHINE and BYTESWAPPED definitions in fitsio2.h\n");
+ printf(" Please report this problem to the author at\n");
+ printf(" pence@tetra.gsfc.nasa.gov\n");
+ printf( "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
+ return(1);
+ }
+
+ /* register the standard I/O drivers that are always available */
+
+ /* 1--------------------disk file driver-----------------------*/
+ status = fits_register_driver("file://",
+ file_init,
+ file_shutdown,
+ file_setoptions,
+ file_getoptions,
+ file_getversion,
+ file_checkfile,
+ file_open,
+ file_create,
+#ifdef HAVE_FTRUNCATE
+ file_truncate,
+#else
+ NULL, /* no file truncate function */
+#endif
+ file_close,
+ file_remove,
+ file_size,
+ file_flush,
+ file_seek,
+ file_read,
+ file_write);
+
+ if (status)
+ {
+ ffpmsg("failed to register the file:// driver (init_cfitsio)");
+ return(status);
+ }
+
+ /* 2------------ output temporary memory file driver ----------------*/
+ status = fits_register_driver("mem://",
+ mem_init,
+ mem_shutdown,
+ mem_setoptions,
+ mem_getoptions,
+ mem_getversion,
+ NULL, /* checkfile not needed */
+ NULL, /* open function not allowed */
+ mem_create,
+ mem_truncate,
+ mem_close_free,
+ NULL, /* remove function not required */
+ mem_size,
+ NULL, /* flush function not required */
+ mem_seek,
+ mem_read,
+ mem_write);
+
+
+ if (status)
+ {
+ ffpmsg("failed to register the mem:// driver (init_cfitsio)");
+ return(status);
+ }
+
+ /* 3--------------input pre-existing memory file driver----------------*/
+ status = fits_register_driver("memkeep://",
+ mem_init,
+ mem_shutdown,
+ mem_setoptions,
+ mem_getoptions,
+ mem_getversion,
+ NULL, /* checkfile not needed */
+ NULL, /* file open driver function is not used */
+ NULL, /* create function not allowed */
+ mem_truncate,
+ mem_close_keep,
+ NULL, /* remove function not required */
+ mem_size,
+ NULL, /* flush function not required */
+ mem_seek,
+ mem_read,
+ mem_write);
+
+
+ if (status)
+ {
+ ffpmsg("failed to register the memkeep:// driver (init_cfitsio)");
+ return(status);
+ }
+
+ /* 4-------------------stdin stream driver----------------------*/
+ /* the stdin stream is copied to memory then opened in memory */
+
+ status = fits_register_driver("stdin://",
+ mem_init,
+ mem_shutdown,
+ mem_setoptions,
+ mem_getoptions,
+ mem_getversion,
+ stdin_checkfile,
+ stdin_open,
+ NULL, /* create function not allowed */
+ mem_truncate,
+ mem_close_free,
+ NULL, /* remove function not required */
+ mem_size,
+ NULL, /* flush function not required */
+ mem_seek,
+ mem_read,
+ mem_write);
+
+ if (status)
+ {
+ ffpmsg("failed to register the stdin:// driver (init_cfitsio)");
+ return(status);
+ }
+
+ /* 5-------------------stdin file stream driver----------------------*/
+ /* the stdin stream is copied to a disk file then the disk file is opened */
+
+ status = fits_register_driver("stdinfile://",
+ mem_init,
+ mem_shutdown,
+ mem_setoptions,
+ mem_getoptions,
+ mem_getversion,
+ NULL, /* checkfile not needed */
+ stdin_open,
+ NULL, /* create function not allowed */
+#ifdef HAVE_FTRUNCATE
+ file_truncate,
+#else
+ NULL, /* no file truncate function */
+#endif
+ file_close,
+ file_remove,
+ file_size,
+ file_flush,
+ file_seek,
+ file_read,
+ file_write);
+
+ if (status)
+ {
+ ffpmsg("failed to register the stdinfile:// driver (init_cfitsio)");
+ return(status);
+ }
+
+
+ /* 6-----------------------stdout stream driver------------------*/
+ status = fits_register_driver("stdout://",
+ mem_init,
+ mem_shutdown,
+ mem_setoptions,
+ mem_getoptions,
+ mem_getversion,
+ NULL, /* checkfile not needed */
+ NULL, /* open function not required */
+ mem_create,
+ mem_truncate,
+ stdout_close,
+ NULL, /* remove function not required */
+ mem_size,
+ NULL, /* flush function not required */
+ mem_seek,
+ mem_read,
+ mem_write);
+
+ if (status)
+ {
+ ffpmsg("failed to register the stdout:// driver (init_cfitsio)");
+ return(status);
+ }
+
+ /* 7------------------iraf disk file to memory driver -----------*/
+ status = fits_register_driver("irafmem://",
+ mem_init,
+ mem_shutdown,
+ mem_setoptions,
+ mem_getoptions,
+ mem_getversion,
+ NULL, /* checkfile not needed */
+ mem_iraf_open,
+ NULL, /* create function not required */
+ mem_truncate,
+ mem_close_free,
+ NULL, /* remove function not required */
+ mem_size,
+ NULL, /* flush function not required */
+ mem_seek,
+ mem_read,
+ mem_write);
+
+ if (status)
+ {
+ ffpmsg("failed to register the irafmem:// driver (init_cfitsio)");
+ return(status);
+ }
+
+ /* 8------------------raw binary file to memory driver -----------*/
+ status = fits_register_driver("rawfile://",
+ mem_init,
+ mem_shutdown,
+ mem_setoptions,
+ mem_getoptions,
+ mem_getversion,
+ NULL, /* checkfile not needed */
+ mem_rawfile_open,
+ NULL, /* create function not required */
+ mem_truncate,
+ mem_close_free,
+ NULL, /* remove function not required */
+ mem_size,
+ NULL, /* flush function not required */
+ mem_seek,
+ mem_read,
+ mem_write);
+
+ if (status)
+ {
+ ffpmsg("failed to register the rawfile:// driver (init_cfitsio)");
+ return(status);
+ }
+
+ /* 9------------------compressed disk file to memory driver -----------*/
+ status = fits_register_driver("compress://",
+ mem_init,
+ mem_shutdown,
+ mem_setoptions,
+ mem_getoptions,
+ mem_getversion,
+ NULL, /* checkfile not needed */
+ mem_compress_open,
+ NULL, /* create function not required */
+ mem_truncate,
+ mem_close_free,
+ NULL, /* remove function not required */
+ mem_size,
+ NULL, /* flush function not required */
+ mem_seek,
+ mem_read,
+ mem_write);
+
+ if (status)
+ {
+ ffpmsg("failed to register the compress:// driver (init_cfitsio)");
+ return(status);
+ }
+
+ /* 10------------------compressed disk file to memory driver -----------*/
+ /* Identical to compress://, except it allows READWRITE access */
+
+ status = fits_register_driver("compressmem://",
+ mem_init,
+ mem_shutdown,
+ mem_setoptions,
+ mem_getoptions,
+ mem_getversion,
+ NULL, /* checkfile not needed */
+ mem_compress_openrw,
+ NULL, /* create function not required */
+ mem_truncate,
+ mem_close_free,
+ NULL, /* remove function not required */
+ mem_size,
+ NULL, /* flush function not required */
+ mem_seek,
+ mem_read,
+ mem_write);
+
+ if (status)
+ {
+ ffpmsg("failed to register the compressmem:// driver (init_cfitsio)");
+ return(status);
+ }
+
+ /* 11------------------compressed disk file to disk file driver -------*/
+ status = fits_register_driver("compressfile://",
+ file_init,
+ file_shutdown,
+ file_setoptions,
+ file_getoptions,
+ file_getversion,
+ NULL, /* checkfile not needed */
+ file_compress_open,
+ file_create,
+#ifdef HAVE_FTRUNCATE
+ file_truncate,
+#else
+ NULL, /* no file truncate function */
+#endif
+ file_close,
+ file_remove,
+ file_size,
+ file_flush,
+ file_seek,
+ file_read,
+ file_write);
+
+ if (status)
+ {
+ ffpmsg("failed to register the compressfile:// driver (init_cfitsio)");
+ return(status);
+ }
+
+ /* 12---create file in memory, then compress it to disk file on close--*/
+ status = fits_register_driver("compressoutfile://",
+ mem_init,
+ mem_shutdown,
+ mem_setoptions,
+ mem_getoptions,
+ mem_getversion,
+ NULL, /* checkfile not needed */
+ NULL, /* open function not allowed */
+ mem_create_comp,
+ mem_truncate,
+ mem_close_comp,
+ file_remove, /* delete existing compressed disk file */
+ mem_size,
+ NULL, /* flush function not required */
+ mem_seek,
+ mem_read,
+ mem_write);
+
+
+ if (status)
+ {
+ ffpmsg(
+ "failed to register the compressoutfile:// driver (init_cfitsio)");
+ return(status);
+ }
+
+ /* Register Optional drivers */
+
+#ifdef HAVE_NET_SERVICES
+
+ /* 13--------------------root driver-----------------------*/
+
+ status = fits_register_driver("root://",
+ root_init,
+ root_shutdown,
+ root_setoptions,
+ root_getoptions,
+ root_getversion,
+ NULL, /* checkfile not needed */
+ root_open,
+ root_create,
+ NULL, /* No truncate possible */
+ root_close,
+ NULL, /* No remove possible */
+ root_size, /* no size possible */
+ root_flush,
+ root_seek, /* Though will always succeed */
+ root_read,
+ root_write);
+
+ if (status)
+ {
+ ffpmsg("failed to register the root:// driver (init_cfitsio)");
+ return(status);
+ }
+
+ /* 14--------------------http driver-----------------------*/
+ status = fits_register_driver("http://",
+ mem_init,
+ mem_shutdown,
+ mem_setoptions,
+ mem_getoptions,
+ mem_getversion,
+ http_checkfile,
+ http_open,
+ NULL, /* create function not required */
+ mem_truncate,
+ mem_close_free,
+ NULL, /* remove function not required */
+ mem_size,
+ NULL, /* flush function not required */
+ mem_seek,
+ mem_read,
+ mem_write);
+
+ if (status)
+ {
+ ffpmsg("failed to register the http:// driver (init_cfitsio)");
+ return(status);
+ }
+
+ /* 15--------------------http file driver-----------------------*/
+
+ status = fits_register_driver("httpfile://",
+ file_init,
+ file_shutdown,
+ file_setoptions,
+ file_getoptions,
+ file_getversion,
+ NULL, /* checkfile not needed */
+ http_file_open,
+ file_create,
+#ifdef HAVE_FTRUNCATE
+ file_truncate,
+#else
+ NULL, /* no file truncate function */
+#endif
+ file_close,
+ file_remove,
+ file_size,
+ file_flush,
+ file_seek,
+ file_read,
+ file_write);
+
+ if (status)
+ {
+ ffpmsg("failed to register the httpfile:// driver (init_cfitsio)");
+ return(status);
+ }
+
+ /* 16--------------------http memory driver-----------------------*/
+ /* same as http:// driver, except memory file can be opened READWRITE */
+ status = fits_register_driver("httpmem://",
+ mem_init,
+ mem_shutdown,
+ mem_setoptions,
+ mem_getoptions,
+ mem_getversion,
+ http_checkfile,
+ http_file_open, /* this will simply call http_open */
+ NULL, /* create function not required */
+ mem_truncate,
+ mem_close_free,
+ NULL, /* remove function not required */
+ mem_size,
+ NULL, /* flush function not required */
+ mem_seek,
+ mem_read,
+ mem_write);
+
+ if (status)
+ {
+ ffpmsg("failed to register the httpmem:// driver (init_cfitsio)");
+ return(status);
+ }
+
+ /* 17--------------------httpcompress file driver-----------------------*/
+
+ status = fits_register_driver("httpcompress://",
+ mem_init,
+ mem_shutdown,
+ mem_setoptions,
+ mem_getoptions,
+ mem_getversion,
+ NULL, /* checkfile not needed */
+ http_compress_open,
+ NULL, /* create function not required */
+ mem_truncate,
+ mem_close_free,
+ NULL, /* remove function not required */
+ mem_size,
+ NULL, /* flush function not required */
+ mem_seek,
+ mem_read,
+ mem_write);
+
+ if (status)
+ {
+ ffpmsg("failed to register the httpcompress:// driver (init_cfitsio)");
+ return(status);
+ }
+
+
+ /* 18--------------------ftp driver-----------------------*/
+ status = fits_register_driver("ftp://",
+ mem_init,
+ mem_shutdown,
+ mem_setoptions,
+ mem_getoptions,
+ mem_getversion,
+ ftp_checkfile,
+ ftp_open,
+ NULL, /* create function not required */
+ mem_truncate,
+ mem_close_free,
+ NULL, /* remove function not required */
+ mem_size,
+ NULL, /* flush function not required */
+ mem_seek,
+ mem_read,
+ mem_write);
+
+ if (status)
+ {
+ ffpmsg("failed to register the ftp:// driver (init_cfitsio)");
+ return(status);
+ }
+
+ /* 19--------------------ftp file driver-----------------------*/
+ status = fits_register_driver("ftpfile://",
+ file_init,
+ file_shutdown,
+ file_setoptions,
+ file_getoptions,
+ file_getversion,
+ NULL, /* checkfile not needed */
+ ftp_file_open,
+ file_create,
+#ifdef HAVE_FTRUNCATE
+ file_truncate,
+#else
+ NULL, /* no file truncate function */
+#endif
+ file_close,
+ file_remove,
+ file_size,
+ file_flush,
+ file_seek,
+ file_read,
+ file_write);
+
+ if (status)
+ {
+ ffpmsg("failed to register the ftpfile:// driver (init_cfitsio)");
+ return(status);
+ }
+
+ /* 20--------------------ftp mem driver-----------------------*/
+ /* same as ftp:// driver, except memory file can be opened READWRITE */
+ status = fits_register_driver("ftpmem://",
+ mem_init,
+ mem_shutdown,
+ mem_setoptions,
+ mem_getoptions,
+ mem_getversion,
+ ftp_checkfile,
+ ftp_file_open, /* this will simply call ftp_open */
+ NULL, /* create function not required */
+ mem_truncate,
+ mem_close_free,
+ NULL, /* remove function not required */
+ mem_size,
+ NULL, /* flush function not required */
+ mem_seek,
+ mem_read,
+ mem_write);
+
+ if (status)
+ {
+ ffpmsg("failed to register the ftpmem:// driver (init_cfitsio)");
+ return(status);
+ }
+
+ /* 21--------------------ftp compressed file driver------------------*/
+ status = fits_register_driver("ftpcompress://",
+ mem_init,
+ mem_shutdown,
+ mem_setoptions,
+ mem_getoptions,
+ mem_getversion,
+ NULL, /* checkfile not needed */
+ ftp_compress_open,
+ 0, /* create function not required */
+ mem_truncate,
+ mem_close_free,
+ 0, /* remove function not required */
+ mem_size,
+ 0, /* flush function not required */
+ mem_seek,
+ mem_read,
+ mem_write);
+
+ if (status)
+ {
+ ffpmsg("failed to register the ftpcompress:// driver (init_cfitsio)");
+ return(status);
+ }
+ /* === End of net drivers section === */
+#endif
+
+/* ==================== SHARED MEMORY DRIVER SECTION ======================= */
+
+#ifdef HAVE_SHMEM_SERVICES
+
+ /* 22--------------------shared memory driver-----------------------*/
+ status = fits_register_driver("shmem://",
+ smem_init,
+ smem_shutdown,
+ smem_setoptions,
+ smem_getoptions,
+ smem_getversion,
+ NULL, /* checkfile not needed */
+ smem_open,
+ smem_create,
+ NULL, /* truncate file not supported yet */
+ smem_close,
+ smem_remove,
+ smem_size,
+ smem_flush,
+ smem_seek,
+ smem_read,
+ smem_write );
+
+ if (status)
+ {
+ ffpmsg("failed to register the shmem:// driver (init_cfitsio)");
+ return(status);
+ }
+
+#endif
+
+/* ==================== END OF SHARED MEMORY DRIVER SECTION ================ */
+
+ return(status);
+}
+/*--------------------------------------------------------------------------*/
+int fits_register_driver(char *prefix,
+ int (*init)(void),
+ int (*shutdown)(void),
+ int (*setoptions)(int option),
+ int (*getoptions)(int *options),
+ int (*getversion)(int *version),
+ int (*checkfile) (char *urltype, char *infile, char *outfile),
+ int (*open)(char *filename, int rwmode, int *driverhandle),
+ int (*create)(char *filename, int *driverhandle),
+ int (*truncate)(int driverhandle, OFF_T filesize),
+ int (*close)(int driverhandle),
+ int (*fremove)(char *filename),
+ int (*size)(int driverhandle, OFF_T *size),
+ int (*flush)(int driverhandle),
+ int (*seek)(int driverhandle, OFF_T offset),
+ int (*read) (int driverhandle, void *buffer, long nbytes),
+ int (*write)(int driverhandle, void *buffer, long nbytes) )
+/*
+ register all the functions needed to support an I/O driver
+*/
+{
+ int status;
+
+ if (no_of_drivers + 1 > MAX_DRIVERS)
+ return(TOO_MANY_DRIVERS);
+
+ if (prefix == NULL)
+ return(BAD_URL_PREFIX);
+
+
+ if (init != NULL)
+ {
+ status = (*init)();
+ if (status)
+ return(status);
+ }
+
+ /* fill in data in table */
+ strncpy(driverTable[no_of_drivers].prefix, prefix, MAX_PREFIX_LEN);
+ driverTable[no_of_drivers].prefix[MAX_PREFIX_LEN - 1] = 0;
+ driverTable[no_of_drivers].init = init;
+ driverTable[no_of_drivers].shutdown = shutdown;
+ driverTable[no_of_drivers].setoptions = setoptions;
+ driverTable[no_of_drivers].getoptions = getoptions;
+ driverTable[no_of_drivers].getversion = getversion;
+ driverTable[no_of_drivers].checkfile = checkfile;
+ driverTable[no_of_drivers].open = open;
+ driverTable[no_of_drivers].create = create;
+ driverTable[no_of_drivers].truncate = truncate;
+ driverTable[no_of_drivers].close = close;
+ driverTable[no_of_drivers].remove = fremove;
+ driverTable[no_of_drivers].size = size;
+ driverTable[no_of_drivers].flush = flush;
+ driverTable[no_of_drivers].seek = seek;
+ driverTable[no_of_drivers].read = read;
+ driverTable[no_of_drivers].write = write;
+
+ no_of_drivers++; /* increment the number of drivers */
+ return(0);
+ }
+/*--------------------------------------------------------------------------*/
+int ffiurl(char *url, /* input filename */
+ char *urltype, /* e.g., 'file://', 'http://', 'mem://' */
+ char *infilex, /* root filename (may be complete path) */
+ char *outfile, /* optional output file name */
+ char *extspec, /* extension spec: +n or [extname, extver] */
+ char *rowfilterx, /* boolean row filter expression */
+ char *binspec, /* histogram binning specifier */
+ char *colspec, /* column or keyword modifier expression */
+ int *status)
+/*
+ parse the input URL into its basic components.
+ This routine is big and ugly and should be redesigned someday!
+*/
+{
+ int ii, jj, slen, infilelen, plus_ext = 0, collen;
+ char *ptr1, *ptr2, *ptr3, *tmptr;
+ int hasAt, hasDot, hasOper, followingOper, spaceTerm, rowFilter;
+ int colStart, binStart;
+
+
+ /* must have temporary variable for these, in case inputs are NULL */
+ char *infile;
+ char *rowfilter;
+ char *tmpstr;
+
+ if (*status > 0)
+ return(*status);
+
+ /* Initialize null strings */
+ if (infilex) *infilex = '\0';
+ if (urltype) *urltype = '\0';
+ if (outfile) *outfile = '\0';
+ if (extspec) *extspec = '\0';
+ if (binspec) *binspec = '\0';
+ if (colspec) *colspec = '\0';
+ if (rowfilterx) *rowfilterx = '\0';
+
+ slen = strlen(url);
+
+ if (slen == 0) /* blank filename ?? */
+ return(*status);
+
+ /* allocate memory for 3 strings, each as long as the input url */
+ infile = (char *) calloc(3, slen + 1);
+ if (!infile)
+ return(*status = MEMORY_ALLOCATION);
+
+ rowfilter = &infile[slen + 1];
+ tmpstr = &rowfilter[slen + 1];
+
+ ptr1 = url;
+
+ /* -------------------------------------------------------- */
+ /* get urltype (e.g., file://, ftp://, http://, etc.) */
+ /* --------------------------------------------------------- */
+
+ if (*ptr1 == '-' && ( *(ptr1 +1) == 0 || *(ptr1 +1) == ' ' ||
+ *(ptr1 +1) == '[' || *(ptr1 +1) == '(' ) )
+ {
+ /* "-" means read file from stdin. Also support "- ", */
+ /* "-[extname]" and '-(outfile.fits)" but exclude disk file */
+ /* names that begin with a minus sign, e.g., "-55d33m.fits" */
+
+ if (urltype)
+ strcat(urltype, "stdin://");
+ ptr1++;
+ }
+ else if (!strncasecmp(ptr1, "stdin", 5))
+ {
+ if (urltype)
+ strcat(urltype, "stdin://");
+ ptr1 = ptr1 + 5;
+ }
+ else
+ {
+ ptr2 = strstr(ptr1, "://");
+ ptr3 = strstr(ptr1, "(" );
+
+ if (ptr3 && (ptr3 < ptr2) )
+ {
+ /* the urltype follows a '(' character, so it must apply */
+ /* to the output file, and is not the urltype of the input file */
+ ptr2 = 0; /* so reset pointer to zero */
+ }
+
+ if (ptr2) /* copy the explicit urltype string */
+ {
+ if (urltype)
+ strncat(urltype, ptr1, ptr2 - ptr1 + 3);
+ ptr1 = ptr2 + 3;
+ }
+ else if (!strncmp(ptr1, "ftp:", 4) )
+ { /* the 2 //'s are optional */
+ if (urltype)
+ strcat(urltype, "ftp://");
+ ptr1 += 4;
+ }
+ else if (!strncmp(ptr1, "http:", 5) )
+ { /* the 2 //'s are optional */
+ if (urltype)
+ strcat(urltype, "http://");
+ ptr1 += 5;
+ }
+ else if (!strncmp(ptr1, "mem:", 4) )
+ { /* the 2 //'s are optional */
+ if (urltype)
+ strcat(urltype, "mem://");
+ ptr1 += 4;
+ }
+ else if (!strncmp(ptr1, "shmem:", 6) )
+ { /* the 2 //'s are optional */
+ if (urltype)
+ strcat(urltype, "shmem://");
+ ptr1 += 6;
+ }
+ else if (!strncmp(ptr1, "file:", 5) )
+ { /* the 2 //'s are optional */
+ if (urltype)
+ strcat(urltype, "file://");
+ ptr1 += 5;
+ }
+ else /* assume file driver */
+ {
+ if (urltype)
+ strcat(urltype, "file://");
+ }
+ }
+
+ /* ----------------------------------------------------------
+ If this is a http:// type file, then the cgi file name could
+ include the '[' character, which should not be interpreted
+ as part of CFITSIO's Extended File Name Syntax. Test for this
+ case by seeing if the last character is a ']' or ')'. If it
+ is not, then just treat the whole input string as the file name
+ and do not attempt to interprete the name using the extended
+ filename syntax.
+ ----------------------------------------------------------- */
+
+ if (urltype && !strncmp(urltype, "http://", 7) )
+ {
+ /* test for opening parenthesis or bracket in the file name */
+ if( strchr(ptr1, '(' ) || strchr(ptr1, '[' ) )
+ {
+ slen = strlen(ptr1);
+ ptr3 = ptr1 + slen - 1;
+ while (*ptr3 == ' ') /* ignore trailing blanks */
+ ptr3--;
+
+ if (*ptr3 != ']' && *ptr3 != ')' )
+ {
+ /* name doesn't end with a ']' or ')' so don't try */
+ /* to parse this unusual string (may be cgi string) */
+ if (infilex)
+ strcpy(infilex, ptr1);
+
+ free(infile);
+ return(*status);
+ }
+ }
+ }
+
+ /* ----------------------------------------------------------
+ Look for VMS style filenames like:
+ disk:[directory.subdirectory]filename.ext, or
+ [directory.subdirectory]filename.ext
+
+ Check if the first character is a '[' and urltype != stdin
+ or if there is a ':[' string in the remaining url string. If
+ so, then need to move past this bracket character before
+ search for the opening bracket of a filter specification.
+ ----------------------------------------------------------- */
+
+ tmptr = ptr1;
+ if (*ptr1 == '[')
+ {
+ if (*url != '-')
+ tmptr = ptr1 + 1; /* this bracket encloses a VMS directory name */
+ }
+ else
+ {
+ tmptr = strstr(ptr1, ":[");
+ if (tmptr) /* these 2 chars are part of the VMS disk and directory */
+ tmptr += 2;
+ else
+ tmptr = ptr1;
+ }
+
+ /* ------------------------ */
+ /* get the input file name */
+ /* ------------------------ */
+
+ ptr2 = strchr(tmptr, '('); /* search for opening parenthesis ( */
+ ptr3 = strchr(tmptr, '['); /* search for opening bracket [ */
+
+ if (ptr2 == ptr3) /* simple case: no [ or ( in the file name */
+ {
+ strcat(infile, ptr1);
+ }
+ else if (!ptr3 || /* no bracket, so () enclose output file name */
+ (ptr2 && (ptr2 < ptr3)) ) /* () enclose output name before bracket */
+ {
+ strncat(infile, ptr1, ptr2 - ptr1);
+ ptr2++;
+
+ ptr1 = strchr(ptr2, ')' ); /* search for closing ) */
+ if (!ptr1)
+ {
+ free(infile);
+ return(*status = URL_PARSE_ERROR); /* error, no closing ) */
+ }
+
+ if (outfile)
+ strncat(outfile, ptr2, ptr1 - ptr2);
+
+ /* the opening [ could have been part of output name, */
+ /* e.g., file(out[compress])[3][#row > 5] */
+ /* so search again for opening bracket following the closing ) */
+ ptr3 = strchr(ptr1, '[');
+
+ }
+ else /* bracket comes first, so there is no output name */
+ {
+ strncat(infile, ptr1, ptr3 - ptr1);
+ }
+
+ /* strip off any trailing blanks in the names */
+
+ slen = strlen(infile);
+ while ( (--slen) > 0 && infile[slen] == ' ')
+ infile[slen] = '\0';
+
+ if (outfile)
+ {
+ slen = strlen(outfile);
+ while ( (--slen) > 0 && outfile[slen] == ' ')
+ outfile[slen] = '\0';
+ }
+
+ /* --------------------------------------------- */
+ /* check if this is an IRAF file (.imh extension */
+ /* --------------------------------------------- */
+
+ if (strstr(infile, ".imh"))
+ {
+ if (urltype)
+ strcpy(urltype, "irafmem://");
+ }
+
+ /* --------------------------------------------- */
+ /* check if the 'filename+n' convention has been */
+ /* used to specifiy which HDU number to open */
+ /* --------------------------------------------- */
+
+ jj = strlen(infile);
+
+ for (ii = jj - 1; ii >= 0; ii--)
+ {
+ if (infile[ii] == '+') /* search backwards for '+' sign */
+ break;
+ }
+
+ if (ii > 0 && (jj - ii) < 7) /* limit extension numbers to 5 digits */
+ {
+ infilelen = ii;
+ ii++;
+ ptr1 = infile+ii; /* pointer to start of sequence */
+
+ for (; ii < jj; ii++)
+ {
+ if (!isdigit((int) infile[ii] ) ) /* are all the chars digits? */
+ break;
+ }
+
+ if (ii == jj)
+ {
+ /* yes, the '+n' convention was used. Copy */
+ /* the digits to the output extspec string. */
+ plus_ext = 1;
+
+ if (extspec)
+ strncpy(extspec, ptr1, jj - infilelen);
+
+ infile[infilelen] = '\0'; /* delete the extension number */
+ }
+ }
+
+ /* -------------------------------------------------------------------- */
+ /* if '*' was given for the output name expand it to the root file name */
+ /* -------------------------------------------------------------------- */
+
+ if (outfile && outfile[0] == '*')
+ {
+ /* scan input name backwards to the first '/' character */
+ for (ii = jj - 1; ii >= 0; ii--)
+ {
+ if (infile[ii] == '/' || ii == 0)
+ {
+ strcpy(outfile, &infile[ii + 1]);
+ break;
+ }
+ }
+ }
+
+ /* ------------------------------------------ */
+ /* copy strings from local copy to the output */
+ /* ------------------------------------------ */
+ if (infilex)
+ strcpy(infilex, infile);
+
+ /* ---------------------------------------------------------- */
+ /* if no '[' character in the input string, then we are done. */
+ /* ---------------------------------------------------------- */
+ if (!ptr3)
+ {
+ free(infile);
+ return(*status);
+ }
+
+ /* ------------------------------------------- */
+ /* see if [ extension specification ] is given */
+ /* ------------------------------------------- */
+
+ if (!plus_ext) /* extension no. not already specified? Then */
+ /* first brackets must enclose extension name or # */
+ /* or it encloses a image subsection specification */
+ /* or a raw binary image specifier */
+
+ /* Or, the extension specification may have been */
+ /* omitted and we have to guess what the user intended */
+ {
+ ptr1 = ptr3 + 1; /* pointer to first char after the [ */
+
+ ptr2 = strchr(ptr1, ']' ); /* search for closing ] */
+ if (!ptr2)
+ {
+ ffpmsg("input file URL is missing closing bracket ']'");
+ free(infile);
+ return(*status = URL_PARSE_ERROR); /* error, no closing ] */
+ }
+
+ /* ---------------------------------------------- */
+ /* First, test if this is a rawfile specifier */
+ /* which looks something like: '[ib512,512:2880]' */
+ /* Test if first character is b,i,j,d,r,f, or u, */
+ /* and optional second character is b or l, */
+ /* followed by one or more digits, */
+ /* finally followed by a ',', ':', or ']' */
+ /* ---------------------------------------------- */
+
+ if (*ptr1 == 'b' || *ptr1 == 'B' || *ptr1 == 'i' || *ptr1 == 'I' ||
+ *ptr1 == 'j' || *ptr1 == 'J' || *ptr1 == 'd' || *ptr1 == 'D' ||
+ *ptr1 == 'r' || *ptr1 == 'R' || *ptr1 == 'f' || *ptr1 == 'F' ||
+ *ptr1 == 'u' || *ptr1 == 'U')
+ {
+ /* next optional character may be a b or l (for Big or Little) */
+ ptr1++;
+ if (*ptr1 == 'b' || *ptr1 == 'B' || *ptr1 == 'l' || *ptr1 == 'L')
+ ptr1++;
+
+ if (isdigit((int) *ptr1)) /* must have at least 1 digit */
+ {
+ while (isdigit((int) *ptr1))
+ ptr1++; /* skip over digits */
+
+ if (*ptr1 == ',' || *ptr1 == ':' || *ptr1 == ']' )
+ {
+ /* OK, this looks like a rawfile specifier */
+
+ if (urltype)
+ {
+ if (strstr(urltype, "stdin") )
+ strcpy(urltype, "rawstdin://");
+ else
+ strcpy(urltype, "rawfile://");
+ }
+
+ /* append the raw array specifier to infilex */
+ if (infilex)
+ {
+ strcat(infilex, ptr3);
+ ptr1 = strchr(infilex, ']'); /* find the closing ] char */
+ if (ptr1)
+ *(ptr1 + 1) = '\0'; /* terminate string after the ] */
+ }
+
+ if (extspec)
+ strcpy(extspec, "0"); /* the 0 ext number is implicit */
+
+ tmptr = strchr(ptr2 + 1, '[' ); /* search for another [ char */
+
+ /* copy any remaining characters into rowfilterx */
+ if (tmptr && rowfilterx)
+ {
+ strcat(rowfilterx, tmptr + 1);
+
+ tmptr = strchr(rowfilterx, ']' ); /* search for closing ] */
+ if (tmptr)
+ *tmptr = '\0'; /* overwrite the ] with null terminator */
+ }
+
+ free(infile); /* finished parsing, so return */
+ return(*status);
+ }
+ }
+ } /* end of rawfile specifier test */
+
+ /* -------------------------------------------------------- */
+ /* Not a rawfile, so next, test if this is an image section */
+ /* i.e., an integer followed by a ':' or a '*' or '-*' */
+ /* -------------------------------------------------------- */
+
+ ptr1 = ptr3 + 1; /* reset pointer to first char after the [ */
+ tmptr = ptr1;
+
+ while (*tmptr == ' ')
+ tmptr++; /* skip leading blanks */
+
+ while (isdigit((int) *tmptr))
+ tmptr++; /* skip over leading digits */
+
+ if (*tmptr == ':' || *tmptr == '*' || *tmptr == '-')
+ {
+ /* this is an image section specifier */
+ strcat(rowfilter, ptr3);
+/*
+ don't want to assume 0 extension any more; may imply an image extension.
+ if (extspec)
+ strcpy(extspec, "0");
+*/
+ }
+ else
+ {
+ /* -----------------------------------------------------------------
+ Not an image section or rawfile spec so may be an extension spec.
+
+ Examples of valid extension specifiers:
+ [3] - 3rd extension; 0 = primary array
+ [events] - events extension
+ [events, 2] - events extension, with EXTVER = 2
+ [events,2] - spaces are optional
+ [events, 3, b] - same as above, plus XTENSION = 'BINTABLE'
+ [PICS; colName(12)] - an image in row 12 of the colName column
+ in the PICS table extension
+ [PICS; colName(exposure > 1000)] - as above, but find image in
+ first row with with exposure column value > 1000.
+ [Rate Table] - extension name can contain spaces!
+ [Rate Table;colName(exposure>1000)]
+
+ Examples of other types of specifiers (Not extension specifiers)
+
+ [bin] !!! this is ambiguous, and can't be distinguished from
+ a valid extension specifier
+ [bini X=1:512:16] (also binb, binj, binr, and bind are allowed)
+ [binr (X,Y) = 5]
+ [bin @binfilter.txt]
+
+ [col Time;rate]
+ [col PI=PHA * 1.1]
+ [col -Time; status]
+
+ [X > 5]
+ [X>5]
+ [@filter.txt]
+ [StatusCol] !!! this is ambiguous, and can't be distinguished
+ from a valid extension specifier
+ [StatusCol==0]
+ [StatusCol || x>6]
+ [gtifilter()]
+ [regfilter("region.reg)]
+
+ There will always be some ambiguity between an extension name and
+ a boolean row filtering expression, (as in a couple of the above
+ examples). If there is any doubt, the expression should be treated
+ as an extension specification; The user can always add an explicit
+ expression specifier to override this interpretation.
+
+ The following decision logic will be used:
+
+ 1) locate the first token, terminated with a space, comma,
+ semi-colon, or closing bracket.
+
+ 2) the token is not part of an extension specifier if any of
+ the following is true:
+
+ - if the token begins with '@' and contains a '.'
+ - if the token contains an operator: = > < || &&
+ - if the token begins with "gtifilter(" or "regfilter("
+ - if the token is terminated by a space and is followed by
+ additional characters (not a ']') AND any of the following:
+ - the token is 'col'
+ - the token is 3 or 4 chars long and begins with 'bin'
+ - the second token begins with an operator:
+ ! = < > | & + - * / %
+
+
+ 3) otherwise, the string is assumed to be an extension specifier
+
+ ----------------------------------------------------------------- */
+
+ tmptr = ptr1;
+ while(*tmptr == ' ')
+ tmptr++;
+
+ hasAt = 0;
+ hasDot = 0;
+ hasOper = 0;
+ followingOper = 0;
+ spaceTerm = 0;
+ rowFilter = 0;
+ colStart = 0;
+ binStart = 0;
+
+ if (*tmptr == '@') /* test for leading @ symbol */
+ hasAt = 1;
+
+ if ( !strncasecmp(tmptr, "col ", 4) )
+ colStart = 1;
+
+ if ( !strncasecmp(tmptr, "bin", 3) )
+ binStart = 1;
+
+ if ( !strncasecmp(tmptr, "gtifilter(", 10) ||
+ !strncasecmp(tmptr, "regfilter(", 10) )
+ {
+ rowFilter = 1;
+ }
+ else
+ {
+ /* parse the first token of the expression */
+ for (ii = 0; ii < ptr2 - ptr1 + 1; ii++, tmptr++)
+ {
+ if (*tmptr == '.')
+ hasDot = 1;
+ else if (*tmptr == '=' || *tmptr == '>' || *tmptr == '<' ||
+ (*tmptr == '|' && *(tmptr+1) == '|') ||
+ (*tmptr == '&' && *(tmptr+1) == '&') )
+ hasOper = 1;
+
+ else if (*tmptr == ',' || *tmptr == ';' || *tmptr == ']')
+ {
+ break;
+ }
+ else if (*tmptr == ' ') /* a space char? */
+ {
+ while(*tmptr == ' ') /* skip spaces */
+ tmptr++;
+
+ if (*tmptr == ']') /* is this the end? */
+ break;
+
+ spaceTerm = 1; /* 1st token is terminated by space */
+
+ /* test if this is a column or binning specifier */
+ if (colStart || (ii <= 4 && binStart) )
+ rowFilter = 1;
+ else
+ {
+
+ /* check if next character is an operator */
+ if (*tmptr == '=' || *tmptr == '>' || *tmptr == '<' ||
+ *tmptr == '|' || *tmptr == '&' || *tmptr == '!' ||
+ *tmptr == '+' || *tmptr == '-' || *tmptr == '*' ||
+ *tmptr == '/' || *tmptr == '%')
+ followingOper = 1;
+ }
+ break;
+ }
+ }
+ }
+
+ /* test if this is NOT an extension specifier */
+ if ( rowFilter ||
+ (hasAt && hasDot) ||
+ hasOper ||
+ (spaceTerm && followingOper) )
+ {
+ /* this is (probably) not an extension specifier */
+ /* so copy all chars to filter spec string */
+ strcat(rowfilter, ptr3);
+ }
+ else
+ {
+ /* this appears to be a legit extension specifier */
+ /* copy the extension specification */
+ if (extspec)
+ strncat(extspec, ptr1, ptr2 - ptr1);
+
+ /* copy any remaining chars to filter spec string */
+ strcat(rowfilter, ptr2 + 1);
+ }
+ }
+ } /* end of if (!plus_ext) */
+ else
+ {
+ /* ------------------------------------------------------------------ */
+ /* already have extension, so this must be a filter spec of some sort */
+ /* ------------------------------------------------------------------ */
+
+ strcat(rowfilter, ptr3);
+ }
+
+ /* strip off any trailing blanks from filter */
+ slen = strlen(rowfilter);
+ while ( (--slen) >= 0 && rowfilter[slen] == ' ')
+ rowfilter[slen] = '\0';
+
+ if (!rowfilter[0])
+ {
+ free(infile);
+ return(*status); /* nothing left to parse */
+ }
+
+ /* ------------------------------------------------ */
+ /* does the filter contain a binning specification? */
+ /* ------------------------------------------------ */
+
+ ptr1 = strstr(rowfilter, "[bin"); /* search for "[bin" */
+ if (!ptr1)
+ ptr1 = strstr(rowfilter, "[BIN"); /* search for "[BIN" */
+ if (!ptr1)
+ ptr1 = strstr(rowfilter, "[Bin"); /* search for "[Bin" */
+
+ if (ptr1)
+ {
+ ptr2 = ptr1 + 4; /* end of the '[bin' string */
+ if (*ptr2 == 'b' || *ptr2 == 'i' || *ptr2 == 'j' ||
+ *ptr2 == 'r' || *ptr2 == 'd')
+ ptr2++; /* skip the datatype code letter */
+
+
+ if ( *ptr2 != ' ' && *ptr2 != ']')
+ ptr1 = NULL; /* bin string must be followed by space or ] */
+ }
+
+ if (ptr1)
+ {
+ /* found the binning string */
+ if (binspec)
+ {
+ strcpy(binspec, ptr1 + 1);
+ ptr2 = strchr(binspec, ']');
+
+ if (ptr2) /* terminate the binning filter */
+ {
+ *ptr2 = '\0';
+
+ if ( *(--ptr2) == ' ') /* delete trailing spaces */
+ *ptr2 = '\0';
+ }
+ else
+ {
+ ffpmsg("input file URL is missing closing bracket ']'");
+ ffpmsg(rowfilter);
+ free(infile);
+ return(*status = URL_PARSE_ERROR); /* error, no closing ] */
+ }
+ }
+
+ /* delete the binning spec from the row filter string */
+ ptr2 = strchr(ptr1, ']');
+ strcpy(tmpstr, ptr2+1); /* copy any chars after the binspec */
+ strcpy(ptr1, tmpstr); /* overwrite binspec */
+ }
+
+ /* --------------------------------------------------------- */
+ /* does the filter contain a column selection specification? */
+ /* --------------------------------------------------------- */
+
+ ptr1 = strstr(rowfilter, "[col ");
+ if (!ptr1)
+ {
+ ptr1 = strstr(rowfilter, "[COL ");
+
+ if (!ptr1)
+ ptr1 = strstr(rowfilter, "[Col ");
+ }
+
+ if (ptr1)
+ { /* find the end of the column specifier */
+ ptr2 = ptr1 + 5;
+ while (*ptr2 != ']')
+ {
+ if (*ptr2 == '\0')
+ {
+ ffpmsg("input file URL is missing closing bracket ']'");
+ free(infile);
+ return(*status = URL_PARSE_ERROR); /* error, no closing ] */
+ }
+
+ if (*ptr2 == '\'') /* start of a literal string */
+ {
+ ptr2 = strchr(ptr2 + 1, '\''); /* find closing quote */
+ if (!ptr2)
+ {
+ ffpmsg
+ ("literal string in input file URL is missing closing single quote");
+ free(infile);
+ return(*status = URL_PARSE_ERROR); /* error, no closing ] */
+ }
+ }
+
+ if (*ptr2 == '[') /* set of nested square brackets */
+ {
+ ptr2 = strchr(ptr2 + 1, ']'); /* find closing bracket */
+ if (!ptr2)
+ {
+ ffpmsg
+ ("nested brackets in input file URL is missing closing bracket");
+ free(infile);
+ return(*status = URL_PARSE_ERROR); /* error, no closing ] */
+ }
+ }
+
+ ptr2++; /* continue search for the closing bracket character */
+ }
+
+ collen = ptr2 - ptr1 - 1;
+
+ if (colspec) /* copy the column specifier to output string */
+ {
+ strncpy(colspec, ptr1 + 1, collen);
+ colspec[collen] = '\0';
+
+ while (colspec[--collen] == ' ')
+ colspec[collen] = '\0'; /* strip trailing blanks */
+ }
+
+ /* delete the column selection spec from the row filter string */
+ strcpy(tmpstr, ptr2 + 1); /* copy any chars after the colspec */
+ strcpy(ptr1, tmpstr); /* overwrite binspec */
+ }
+
+ /* copy the remaining string to the rowfilter output... should only */
+ /* contain a rowfilter expression of the form "[expr]" */
+
+ if (rowfilterx && rowfilter[0]) {
+ ptr2 = rowfilter + strlen(rowfilter) - 1;
+ if( rowfilter[0]=='[' && *ptr2==']' ) {
+ *ptr2 = '\0';
+ strcpy(rowfilterx, rowfilter+1);
+ } else {
+ ffpmsg("input file URL lacks valid row filter expression");
+ *status = URL_PARSE_ERROR;
+ }
+ }
+
+ free(infile);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffexist(const char *infile, /* I - input filename or URL */
+ int *exists, /* O - 2 = a compressed version of file exists */
+ /* 1 = yes, disk file exists */
+ /* 0 = no, disk file could not be found */
+ /* -1 = infile is not a disk file (could */
+ /* be a http, ftp, smem, or stdin file) */
+ int *status) /* I/O status */
+
+/*
+ test if the input file specifier is an existing file on disk
+ If the specified file can't be found, it then searches for a
+ compressed version of the file.
+*/
+{
+ FILE *diskfile;
+ char rootname[FLEN_FILENAME];
+ char *ptr1;
+
+ if (*status > 0)
+ return(*status);
+
+ /* strip off any extname or filters from the name */
+ ffrtnm( (char *)infile, rootname, status);
+
+ ptr1 = strstr(rootname, "://");
+
+ if (ptr1 || *rootname == '-') {
+ if (!strncmp(rootname, "file", 4) ) {
+ ptr1 = ptr1 + 3; /* pointer to start of the disk file name */
+ } else {
+ *exists = -1; /* this is not a disk file */
+ return (*status);
+ }
+ } else {
+ ptr1 = rootname;
+ }
+
+ /* see if the disk file exists */
+ if (file_openfile(ptr1, 0, &diskfile)) {
+
+ /* no, couldn't open file, so see if there is a compressed version */
+ if (file_is_compressed(ptr1) ) {
+ *exists = 2; /* a compressed version of the file exists */
+ } else {
+ *exists = 0; /* neither file nor compressed version exist */
+ }
+
+ } else {
+
+ /* yes, file exists */
+ *exists = 1;
+ fclose(diskfile);
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffrtnm(char *url,
+ char *rootname,
+ int *status)
+/*
+ parse the input URL, returning the root name (filetype://basename).
+*/
+
+{
+ int ii, jj, slen, infilelen;
+ char *ptr1, *ptr2, *ptr3;
+ char urltype[MAX_PREFIX_LEN];
+ char infile[FLEN_FILENAME];
+
+ if (*status > 0)
+ return(*status);
+
+ ptr1 = url;
+ *rootname = '\0';
+ *urltype = '\0';
+ *infile = '\0';
+
+ /* get urltype (e.g., file://, ftp://, http://, etc.) */
+ if (*ptr1 == '-') /* "-" means read file from stdin */
+ {
+ strcat(urltype, "-");
+ ptr1++;
+ }
+ else if (!strncmp(ptr1, "stdin", 5) || !strncmp(ptr1, "STDIN", 5))
+ {
+ strcat(urltype, "-");
+ ptr1 = ptr1 + 5;
+ }
+ else
+ {
+ ptr2 = strstr(ptr1, "://");
+ ptr3 = strstr(ptr1, "(" );
+
+ if (ptr3 && (ptr3 < ptr2) )
+ {
+ /* the urltype follows a '(' character, so it must apply */
+ /* to the output file, and is not the urltype of the input file */
+ ptr2 = 0; /* so reset pointer to zero */
+ }
+
+
+ if (ptr2) /* copy the explicit urltype string */
+ {
+ strncat(urltype, ptr1, ptr2 - ptr1 + 3);
+ ptr1 = ptr2 + 3;
+ }
+ else if (!strncmp(ptr1, "ftp:", 4) )
+ { /* the 2 //'s are optional */
+ strcat(urltype, "ftp://");
+ ptr1 += 4;
+ }
+ else if (!strncmp(ptr1, "http:", 5) )
+ { /* the 2 //'s are optional */
+ strcat(urltype, "http://");
+ ptr1 += 5;
+ }
+ else if (!strncmp(ptr1, "mem:", 4) )
+ { /* the 2 //'s are optional */
+ strcat(urltype, "mem://");
+ ptr1 += 4;
+ }
+ else if (!strncmp(ptr1, "shmem:", 6) )
+ { /* the 2 //'s are optional */
+ strcat(urltype, "shmem://");
+ ptr1 += 6;
+ }
+ else if (!strncmp(ptr1, "file:", 5) )
+ { /* the 2 //'s are optional */
+ ptr1 += 5;
+ }
+
+ /* else assume file driver */
+ }
+
+ /* get the input file name */
+ ptr2 = strchr(ptr1, '('); /* search for opening parenthesis ( */
+ ptr3 = strchr(ptr1, '['); /* search for opening bracket [ */
+
+ if (ptr2 == ptr3) /* simple case: no [ or ( in the file name */
+ {
+ strcat(infile, ptr1);
+ }
+ else if (!ptr3) /* no bracket, so () enclose output file name */
+ {
+ strncat(infile, ptr1, ptr2 - ptr1);
+ ptr2++;
+
+ ptr1 = strchr(ptr2, ')' ); /* search for closing ) */
+ if (!ptr1)
+ return(*status = URL_PARSE_ERROR); /* error, no closing ) */
+
+ }
+ else if (ptr2 && (ptr2 < ptr3)) /* () enclose output name before bracket */
+ {
+ strncat(infile, ptr1, ptr2 - ptr1);
+ ptr2++;
+
+ ptr1 = strchr(ptr2, ')' ); /* search for closing ) */
+ if (!ptr1)
+ return(*status = URL_PARSE_ERROR); /* error, no closing ) */
+ }
+ else /* bracket comes first, so there is no output name */
+ {
+ strncat(infile, ptr1, ptr3 - ptr1);
+ }
+
+ /* strip off any trailing blanks in the names */
+ slen = strlen(infile);
+ for (ii = slen - 1; ii > 0; ii--)
+ {
+ if (infile[ii] == ' ')
+ infile[ii] = '\0';
+ else
+ break;
+ }
+
+ /* --------------------------------------------- */
+ /* check if the 'filename+n' convention has been */
+ /* used to specifiy which HDU number to open */
+ /* --------------------------------------------- */
+
+ jj = strlen(infile);
+
+ for (ii = jj - 1; ii >= 0; ii--)
+ {
+ if (infile[ii] == '+') /* search backwards for '+' sign */
+ break;
+ }
+
+ if (ii > 0 && (jj - ii) < 5) /* limit extension numbers to 4 digits */
+ {
+ infilelen = ii;
+ ii++;
+
+
+ for (; ii < jj; ii++)
+ {
+ if (!isdigit((int) infile[ii] ) ) /* are all the chars digits? */
+ break;
+ }
+
+ if (ii == jj)
+ {
+ /* yes, the '+n' convention was used. */
+
+ infile[infilelen] = '\0'; /* delete the extension number */
+ }
+ }
+
+ strcat(rootname, urltype); /* construct the root name */
+ strcat(rootname, infile);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffourl(char *url, /* I - full input URL */
+ char *urltype, /* O - url type */
+ char *outfile, /* O - base file name */
+ char *tpltfile, /* O - template file name, if any */
+ char *compspec, /* O - compression specification, if any */
+ int *status)
+/*
+ parse the output URL into its basic components.
+*/
+
+{
+ char *ptr1, *ptr2, *ptr3;
+
+ if (*status > 0)
+ return(*status);
+
+ if (urltype)
+ *urltype = '\0';
+ if (outfile)
+ *outfile = '\0';
+ if (tpltfile)
+ *tpltfile = '\0';
+ if (compspec)
+ *compspec = '\0';
+
+ ptr1 = url;
+ while (*ptr1 == ' ') /* ignore leading blanks */
+ ptr1++;
+
+ if ( ( (*ptr1 == '-') && ( *(ptr1 +1) == 0 || *(ptr1 +1) == ' ' ) )
+ || !strcmp(ptr1, "stdout")
+ || !strcmp(ptr1, "STDOUT"))
+
+ /* "-" means write to stdout; also support "- " */
+ /* but exclude disk file names that begin with a minus sign */
+ /* e.g., "-55d33m.fits" */
+ {
+ if (urltype)
+ strcpy(urltype, "stdout://");
+ }
+ else
+ {
+ /* not writing to stdout */
+ /* get urltype (e.g., file://, ftp://, http://, etc.) */
+
+ ptr2 = strstr(ptr1, "://");
+ if (ptr2) /* copy the explicit urltype string */
+ {
+ if (urltype)
+ strncat(urltype, ptr1, ptr2 - ptr1 + 3);
+
+ ptr1 = ptr2 + 3;
+ }
+ else /* assume file driver */
+ {
+ if (urltype)
+ strcat(urltype, "file://");
+ }
+
+ /* look for template file name, enclosed in parenthesis */
+ ptr2 = strchr(ptr1, '(');
+
+ /* look for image compression parameters, enclosed in sq. brackets */
+ ptr3 = strchr(ptr1, '[');
+
+ if (outfile)
+ {
+ if (ptr2) /* template file was specified */
+ strncat(outfile, ptr1, ptr2 - ptr1);
+
+ else if (ptr3) /* compression was specified */
+ strncat(outfile, ptr1, ptr3 - ptr1);
+
+ else /* no template file or compression */
+ strcpy(outfile, ptr1);
+ }
+
+
+ if (ptr2) /* template file was specified */
+ {
+ ptr2++;
+
+ ptr1 = strchr(ptr2, ')' ); /* search for closing ) */
+
+ if (!ptr1)
+ {
+ return(*status = URL_PARSE_ERROR); /* error, no closing ) */
+ }
+
+ if (tpltfile)
+ strncat(tpltfile, ptr2, ptr1 - ptr2);
+ }
+
+ if (ptr3) /* compression was specified */
+ {
+ ptr3++;
+
+ ptr1 = strchr(ptr3, ']' ); /* search for closing ] */
+
+ if (!ptr1)
+ {
+ return(*status = URL_PARSE_ERROR); /* error, no closing ] */
+ }
+
+ if (compspec)
+ strncat(compspec, ptr3, ptr1 - ptr3);
+ }
+
+ /* check if a .gz compressed output file is to be created */
+ /* by seeing if the filename ends in '.gz' */
+ if (urltype && outfile)
+ {
+ if (!strcmp(urltype, "file://") )
+ {
+ ptr1 = strstr(outfile, ".gz");
+ if (ptr1)
+ { /* make sure the ".gz" is at the end of the file name */
+ ptr1 += 3;
+ if (*ptr1 == 0 || *ptr1 == ' ' )
+ strcpy(urltype, "compressoutfile://");
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffexts(char *extspec,
+ int *extnum,
+ char *extname,
+ int *extvers,
+ int *hdutype,
+ char *imagecolname,
+ char *rowexpress,
+ int *status)
+{
+/*
+ Parse the input extension specification string, returning either the
+ extension number or the values of the EXTNAME, EXTVERS, and XTENSION
+ keywords in desired extension. Also return the name of the column containing
+ an image, and an expression to be used to determine which row to use,
+ if present.
+*/
+ char *ptr1, *ptr2;
+ int slen, nvals;
+ int notint = 1; /* initially assume specified extname is not an integer */
+ char tmpname[FLEN_VALUE], *loc;
+
+ *extnum = 0;
+ *extname = '\0';
+ *extvers = 0;
+ *hdutype = ANY_HDU;
+ *imagecolname = '\0';
+ *rowexpress = '\0';
+
+ if (*status > 0)
+ return(*status);
+
+ ptr1 = extspec; /* pointer to first char */
+
+ while (*ptr1 == ' ') /* skip over any leading blanks */
+ ptr1++;
+
+ if (isdigit((int) *ptr1)) /* is the extension specification a number? */
+ {
+ notint = 0; /* looks like extname may actually be the ext. number */
+ *extnum = strtol(ptr1, &loc, 10); /* read the string as an integer */
+
+ while (*loc == ' ') /* skip over trailing blanks */
+ loc++;
+
+ /* check for read error, or junk following the integer */
+ if ((*loc != '\0' ) || (errno == ERANGE) )
+ {
+ *extnum = 0;
+ notint = 1; /* no, extname was not a simple integer after all */
+ }
+
+ if ( *extnum < 0 || *extnum > 99999)
+ {
+ *extnum = 0; /* this is not a reasonable extension number */
+ ffpmsg("specified extension number is out of range:");
+ ffpmsg(extspec);
+ return(*status = URL_PARSE_ERROR);
+ }
+ }
+
+
+/* This logic was too simple, and failed on extnames like '1000TEMP'
+ where it would try to move to the 1000th extension
+
+ if (isdigit((int) *ptr1))
+ {
+ sscanf(ptr1, "%d", extnum);
+ if (*extnum < 0 || *extnum > 9999)
+ {
+ *extnum = 0;
+ ffpmsg("specified extension number is out of range:");
+ ffpmsg(extspec);
+ return(*status = URL_PARSE_ERROR);
+ }
+ }
+*/
+
+ if (notint)
+ {
+ /* not a number, so EXTNAME must be specified, followed by */
+ /* optional EXTVERS and XTENSION values */
+
+ /* don't use space char as end indicator, because there */
+ /* may be imbedded spaces in the EXTNAME value */
+ slen = strcspn(ptr1, ",:;"); /* length of EXTNAME */
+ strncat(extname, ptr1, slen); /* EXTNAME value */
+
+ /* now remove any trailing blanks */
+ while (slen > 0 && *(extname + slen -1) == ' ')
+ {
+ *(extname + slen -1) = '\0';
+ slen--;
+ }
+
+ ptr1 += slen;
+ slen = strspn(ptr1, " ,:"); /* skip delimiter characters */
+ ptr1 += slen;
+
+ slen = strcspn(ptr1, " ,:;"); /* length of EXTVERS */
+ if (slen)
+ {
+ nvals = sscanf(ptr1, "%d", extvers); /* EXTVERS value */
+ if (nvals != 1)
+ {
+ ffpmsg("illegal EXTVER value in input URL:");
+ ffpmsg(extspec);
+ return(*status = URL_PARSE_ERROR);
+ }
+
+ ptr1 += slen;
+ slen = strspn(ptr1, " ,:"); /* skip delimiter characters */
+ ptr1 += slen;
+
+ slen = strcspn(ptr1, ";"); /* length of HDUTYPE */
+ if (slen)
+ {
+ if (*ptr1 == 'b' || *ptr1 == 'B')
+ *hdutype = BINARY_TBL;
+ else if (*ptr1 == 't' || *ptr1 == 'T' ||
+ *ptr1 == 'a' || *ptr1 == 'A')
+ *hdutype = ASCII_TBL;
+ else if (*ptr1 == 'i' || *ptr1 == 'I')
+ *hdutype = IMAGE_HDU;
+ else
+ {
+ ffpmsg("unknown type of HDU in input URL:");
+ ffpmsg(extspec);
+ return(*status = URL_PARSE_ERROR);
+ }
+ }
+ }
+ else
+ {
+ strcpy(tmpname, extname);
+ ffupch(tmpname);
+ if (!strcmp(tmpname, "PRIMARY") || !strcmp(tmpname, "P") )
+ *extname = '\0'; /* return extnum = 0 */
+ }
+ }
+
+ ptr1 = strchr(ptr1, ';');
+ if (ptr1)
+ {
+ /* an image is to be opened; the image is contained in a single */
+ /* cell of a binary table. A column name and an expression to */
+ /* determine which row to use has been entered. */
+
+ ptr1++; /* skip over the ';' delimiter */
+ while (*ptr1 == ' ') /* skip over any leading blanks */
+ ptr1++;
+
+ ptr2 = strchr(ptr1, '(');
+ if (!ptr2)
+ {
+ ffpmsg("illegal specification of image in table cell in input URL:");
+ ffpmsg(" did not find a row expression enclosed in ( )");
+ ffpmsg(extspec);
+ return(*status = URL_PARSE_ERROR);
+ }
+
+ strncat(imagecolname, ptr1, ptr2 - ptr1); /* copy column name */
+
+ ptr2++; /* skip over the '(' delimiter */
+ while (*ptr2 == ' ') /* skip over any leading blanks */
+ ptr2++;
+
+
+ ptr1 = strchr(ptr2, ')');
+ if (!ptr2)
+ {
+ ffpmsg("illegal specification of image in table cell in input URL:");
+ ffpmsg(" missing closing ')' character in row expression");
+ ffpmsg(extspec);
+ return(*status = URL_PARSE_ERROR);
+ }
+
+ strncat(rowexpress, ptr2, ptr1 - ptr2); /* row expression */
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffextn(char *url, /* I - input filename/URL */
+ int *extension_num, /* O - returned extension number */
+ int *status)
+{
+/*
+ Parse the input url string and return the number of the extension that
+ CFITSIO would automatically move to if CFITSIO were to open this input URL.
+ The extension numbers are one's based, so 1 = the primary array, 2 = the
+ first extension, etc.
+
+ The extension number that gets returned is determined by the following
+ algorithm:
+
+ 1. If the input URL includes a binning specification (e.g.
+ 'myfile.fits[3][bin X,Y]') then the returned extension number
+ will always = 1, since CFITSIO would create a temporary primary
+ image on the fly in this case. The same is true if an image
+ within a single cell of a binary table is opened.
+
+ 2. Else if the input URL specifies an extension number (e.g.,
+ 'myfile.fits[3]' or 'myfile.fits+3') then the specified extension
+ number (+ 1) is returned.
+
+ 3. Else if the extension name is specified in brackets
+ (e.g., this 'myfile.fits[EVENTS]') then the file will be opened and searched
+ for the extension number. If the input URL is '-' (reading from the stdin
+ file stream) this is not possible and an error will be returned.
+
+ 4. Else if the URL does not specify an extension (e.g. 'myfile.fits') then
+ a special extension number = -99 will be returned to signal that no
+ extension was specified. This feature is mainly for compatibility with
+ existing FTOOLS software. CFITSIO would open the primary array by default
+ (extension_num = 1) in this case.
+
+*/
+ fitsfile *fptr;
+ char urltype[20];
+ char infile[FLEN_FILENAME];
+ char outfile[FLEN_FILENAME];
+ char extspec[FLEN_FILENAME];
+ char extname[FLEN_FILENAME];
+ char rowfilter[FLEN_FILENAME];
+ char binspec[FLEN_FILENAME];
+ char colspec[FLEN_FILENAME];
+ char imagecolname[FLEN_VALUE], rowexpress[FLEN_FILENAME];
+ char *cptr;
+ int extnum, extvers, hdutype, tstatus = 0;
+
+ if (*status > 0)
+ return(*status);
+
+ /* parse the input URL into its basic components */
+ ffiurl(url, urltype, infile, outfile,
+ extspec, rowfilter,binspec, colspec, status);
+
+ if (*status > 0)
+ return(*status);
+
+ if (*binspec) /* is there a binning specification? */
+ {
+ *extension_num = 1; /* a temporary primary array image is created */
+ return(*status);
+ }
+
+ if (*extspec) /* is an extension specified? */
+ {
+ ffexts(extspec, &extnum,
+ extname, &extvers, &hdutype, imagecolname, rowexpress, status);
+
+ if (*status > 0)
+ return(*status);
+
+ if (*imagecolname) /* is an image within a table cell being opened? */
+ {
+ *extension_num = 1; /* a temporary primary array image is created */
+ return(*status);
+ }
+
+ if (*extname)
+ {
+ /* have to open the file to search for the extension name (curses!) */
+
+ if (!strcmp(urltype, "stdin://"))
+ /* opening stdin would destroying it! */
+ return(*status = URL_PARSE_ERROR);
+
+ /* First, strip off any filtering specification */
+ strcpy(infile, url);
+ cptr = strchr(infile, ']'); /* locate the closing bracket */
+ if (!cptr)
+ {
+ return(*status = URL_PARSE_ERROR);
+ }
+ else
+ {
+ cptr++;
+ *cptr = '\0'; /* terminate URl after the extension spec */
+ }
+
+ if (ffopen(&fptr, infile, READONLY, status) > 0) /* open the file */
+ {
+ ffclos(fptr, &tstatus);
+ return(*status);
+ }
+
+ ffghdn(fptr, &extnum); /* where am I in the file? */
+ *extension_num = extnum;
+ ffclos(fptr, status);
+
+ return(*status);
+ }
+ else
+ {
+ *extension_num = extnum + 1; /* return the specified number (+ 1) */
+ return(*status);
+ }
+ }
+ else
+ {
+ *extension_num = -99; /* no specific extension was specified */
+ /* defaults to primary array */
+ return(*status);
+ }
+}
+/*--------------------------------------------------------------------------*/
+
+int ffurlt(fitsfile *fptr, char *urlType, int *status)
+/*
+ return the prefix string associated with the driver in use by the
+ fitsfile pointer fptr
+*/
+
+{
+ strcpy(urlType, driverTable[fptr->Fptr->driver].prefix);
+ return(*status);
+}
+
+/*--------------------------------------------------------------------------*/
+int ffimport_file( char *filename, /* Text file to read */
+ char **contents, /* Pointer to pointer to hold file */
+ int *status ) /* CFITSIO error code */
+/*
+ Read and concatenate all the lines from the given text file. User
+ must free the pointer returned in contents. Pointer is guaranteed
+ to hold 2 characters more than the length of the text... allows the
+ calling routine to append (or prepend) a newline (or quotes?) without
+ reallocating memory.
+*/
+{
+ int allocLen, totalLen, llen, eoline;
+ char *lines,line[256];
+ FILE *aFile;
+
+ if( *status > 0 ) return( *status );
+
+ totalLen = 0;
+ allocLen = 1024;
+ lines = (char *)malloc( allocLen * sizeof(char) );
+ if( !lines ) {
+ ffpmsg("Couldn't allocate memory to hold ASCII file contents.");
+ return(*status = MEMORY_ALLOCATION );
+ }
+ lines[0] = '\0';
+
+ if( (aFile = fopen( filename, "r" ))==NULL ) {
+ sprintf(line,"Could not open ASCII file %s.",filename);
+ ffpmsg(line);
+ free( lines );
+ return(*status = FILE_NOT_OPENED);
+ }
+
+ while( fgets(line,256,aFile)!=NULL ) {
+ llen = strlen(line);
+ if ((llen > 1) && (line[0] == '/' && line[1] == '/'))
+ continue; /* skip comment lines begging with // */
+
+ eoline = 0;
+
+ /* replace CR and newline chars at end of line with nulls */
+ if ((llen > 0) && (line[llen-1]=='\n' || line[llen-1] == '\r')) {
+ line[--llen] = '\0';
+ eoline = 1; /* found an end of line character */
+
+ if ((llen > 0) && (line[llen-1]=='\n' || line[llen-1] == '\r')) {
+ line[--llen] = '\0';
+ }
+ }
+
+ if( totalLen + llen + 3 >= allocLen ) {
+ allocLen += 256;
+ lines = (char *)realloc(lines, allocLen * sizeof(char) );
+ if( ! lines ) {
+ ffpmsg("Couldn't allocate memory to hold ASCII file contents.");
+ *status = MEMORY_ALLOCATION;
+ break;
+ }
+ }
+ strcpy( lines+totalLen, line );
+ totalLen += llen;
+
+ if (eoline) {
+ strcpy( lines+totalLen, " "); /* add a space between lines */
+ totalLen += 1;
+ }
+ }
+ fclose(aFile);
+
+ *contents = lines;
+ return( *status );
+}
+
+/*--------------------------------------------------------------------------*/
+int fits_get_token(char **ptr,
+ char *delimiter,
+ char *token,
+ int *isanumber) /* O - is this token a number? */
+/*
+ parse off the next token, delimited by a character in 'delimiter',
+ from the input ptr string; increment *ptr to the end of the token.
+ Returns the length of the token, not including the delimiter char;
+*/
+{
+ int slen, ii;
+
+ *token = '\0';
+
+ while (**ptr == ' ') /* skip over leading blanks */
+ (*ptr)++;
+
+ slen = strcspn(*ptr, delimiter); /* length of next token */
+ if (slen)
+ {
+ strncat(token, *ptr, slen); /* copy token */
+
+ (*ptr) += slen; /* skip over the token */
+
+ if (isanumber)
+ {
+ *isanumber = 1;
+
+ for (ii = 0; ii < slen; ii++)
+ {
+ if ( !isdigit((int) token[ii]) && token[ii] != '.' &&
+ token[ii] != '-' && token[ii] != '+' &&
+ token[ii] != 'E' && token[ii] != 'e')
+ {
+ *isanumber = 0;
+ break;
+ }
+ }
+ }
+ }
+
+ return(slen);
+}
+/*---------------------------------------------------------------------------*/
+char *fits_split_names(
+ char *list) /* I - input list of names */
+{
+/*
+ A sequence of calls to fits_split_names will split the input string
+ into name tokens. The string typically contains a list of file or
+ column names. The names must be delimited by a comma and/or spaces.
+ This routine ignores spaces and commas that occur within parentheses,
+ brackets, or curly brackets. It also strips any leading and trailing
+ blanks from the returned name.
+
+ This routine is similar to the ANSI C 'strtok' function:
+
+ The first call to fits_split_names has a non-null input string.
+ It finds the first name in the string and terminates it by
+ overwriting the next character of the string with a '\0' and returns
+ a pointer to the name. Each subsequent call, indicated by a NULL
+ value of the input string, returns the next name, searching from
+ just past the end of the previous name. It returns NULL when no
+ further names are found.
+
+ The following line illustrates how a string would be split into 3 names:
+ myfile[1][bin (x,y)=4], file2.fits file3.fits
+ ^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^ ^^^^^^^^^^
+ 1st name 2nd name 3rd name
+
+*/
+ int depth = 0;
+ char *start;
+ static char *ptr;
+
+ if (list) /* reset ptr if a string is given */
+ ptr = list;
+
+ while (*ptr == ' ')ptr++; /* skip leading white space */
+
+ if (*ptr == '\0')return(0); /* no remaining file names */
+
+ start = ptr;
+
+ while (*ptr != '\0') {
+ if ((*ptr == '[') || (*ptr == '(') || (*ptr == '{')) depth ++;
+ else if ((*ptr == '}') || (*ptr == ')') || (*ptr == ']')) depth --;
+ else if ((depth == 0) && (*ptr == ',' || *ptr == ' ')) {
+ *ptr = '\0'; /* terminate the filename here */
+ ptr++; /* save pointer to start of next filename */
+ break;
+ }
+ ptr++;
+ }
+
+ return(start);
+}
+/*--------------------------------------------------------------------------*/
+int urltype2driver(char *urltype, int *driver)
+/*
+ compare input URL with list of known drivers, returning the
+ matching driver numberL.
+*/
+
+{
+ int ii;
+
+ /* find matching driver; search most recent drivers first */
+
+ for (ii=no_of_drivers - 1; ii >= 0; ii--)
+ {
+ if (0 == strcmp(driverTable[ii].prefix, urltype))
+ {
+ *driver = ii;
+ return(0);
+ }
+ }
+
+ return(NO_MATCHING_DRIVER);
+}
+/*--------------------------------------------------------------------------*/
+int ffclos(fitsfile *fptr, /* I - FITS file pointer */
+ int *status) /* IO - error status */
+/*
+ close the FITS file by completing the current HDU, flushing it to disk,
+ then calling the system dependent routine to physically close the FITS file
+*/
+{
+ int tstatus = NO_CLOSE_ERROR, zerostatus = 0;
+
+ if (!fptr)
+ return(*status = NULL_INPUT_PTR);
+ else if ((fptr->Fptr)->validcode != VALIDSTRUC) /* check for magic value */
+ return(*status = BAD_FILEPTR);
+
+ /* close and flush the current HDU */
+ if (*status > 0)
+ ffchdu(fptr, &tstatus); /* turn off the error message from ffchdu */
+ else
+ ffchdu(fptr, status);
+
+ ((fptr->Fptr)->open_count)--; /* decrement usage counter */
+
+ if ((fptr->Fptr)->open_count == 0) /* if no other files use structure */
+ {
+ ffflsh(fptr, TRUE, status); /* flush and disassociate IO buffers */
+
+ /* call driver function to actually close the file */
+ if (
+ (*driverTable[(fptr->Fptr)->driver].close)((fptr->Fptr)->filehandle) )
+ {
+ if (*status <= 0)
+ {
+ *status = FILE_NOT_CLOSED; /* report if no previous error */
+
+ ffpmsg("failed to close the following file: (ffclos)");
+ ffpmsg((fptr->Fptr)->filename);
+ }
+ }
+
+ fits_clear_Fptr( fptr->Fptr, status); /* clear Fptr address */
+ free((fptr->Fptr)->headstart); /* free memory for headstart array */
+ free((fptr->Fptr)->filename); /* free memory for the filename */
+ (fptr->Fptr)->filename = 0;
+ (fptr->Fptr)->validcode = 0; /* magic value to indicate invalid fptr */
+ free(fptr->Fptr); /* free memory for the FITS file structure */
+ free(fptr); /* free memory for the FITS file structure */
+ }
+ else
+ {
+ /*
+ to minimize the fallout from any previous error (e.g., trying to
+ open a non-existent extension in a already opened file),
+ always call ffflsh with status = 0.
+ */
+ /* just flush the buffers, don't disassociate them */
+ if (*status > 0)
+ ffflsh(fptr, FALSE, &zerostatus);
+ else
+ ffflsh(fptr, FALSE, status);
+
+ free(fptr); /* free memory for the FITS file structure */
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffdelt(fitsfile *fptr, /* I - FITS file pointer */
+ int *status) /* IO - error status */
+/*
+ close and DELETE the FITS file.
+*/
+{
+ char *basename;
+ int slen, tstatus = 0;
+
+ if (!fptr)
+ return(*status = NULL_INPUT_PTR);
+ else if ((fptr->Fptr)->validcode != VALIDSTRUC) /* check for magic value */
+ return(*status = BAD_FILEPTR);
+
+ ffchdu(fptr, status); /* close the current HDU, ignore any errors */
+ ffflsh(fptr, TRUE, status); /* flush and disassociate IO buffers */
+
+ /* call driver function to actually close the file */
+ if ( (*driverTable[(fptr->Fptr)->driver].close)((fptr->Fptr)->filehandle) )
+ {
+ if (*status <= 0)
+ {
+ *status = FILE_NOT_CLOSED; /* report error if no previous error */
+
+ ffpmsg("failed to close the following file: (ffdelt)");
+ ffpmsg((fptr->Fptr)->filename);
+ }
+ }
+
+ /* call driver function to actually delete the file */
+ if ( (driverTable[(fptr->Fptr)->driver].remove) )
+ {
+ /* parse the input URL to get the base filename */
+ slen = strlen((fptr->Fptr)->filename);
+ basename = (char *) malloc(slen +1);
+ if (!basename)
+ return(*status = MEMORY_ALLOCATION);
+
+ ffiurl((fptr->Fptr)->filename, NULL, basename, NULL, NULL, NULL, NULL,
+ NULL, &tstatus);
+
+ if ((*driverTable[(fptr->Fptr)->driver].remove)(basename))
+ {
+ ffpmsg("failed to delete the following file: (ffdelt)");
+ ffpmsg((fptr->Fptr)->filename);
+ if (!(*status))
+ *status = FILE_NOT_CLOSED;
+ }
+ free(basename);
+ }
+
+ fits_clear_Fptr( fptr->Fptr, status); /* clear Fptr address */
+ free((fptr->Fptr)->headstart); /* free memory for headstart array */
+ free((fptr->Fptr)->filename); /* free memory for the filename */
+ (fptr->Fptr)->filename = 0;
+ (fptr->Fptr)->validcode = 0; /* magic value to indicate invalid fptr */
+ free(fptr->Fptr); /* free memory for the FITS file structure */
+ free(fptr); /* free memory for the FITS file structure */
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fftrun( fitsfile *fptr, /* I - FITS file pointer */
+ OFF_T filesize, /* I - size to truncate the file */
+ int *status) /* O - error status */
+/*
+ low level routine to truncate a file to a new smaller size.
+*/
+{
+ if (driverTable[(fptr->Fptr)->driver].truncate)
+ {
+ ffflsh(fptr, FALSE, status); /* flush all the buffers first */
+ (fptr->Fptr)->filesize = filesize;
+ (fptr->Fptr)->logfilesize = filesize;
+ (fptr->Fptr)->bytepos = filesize;
+ ffbfeof(fptr, status); /* eliminate any buffers beyond current EOF */
+ return (*status =
+ (*driverTable[(fptr->Fptr)->driver].truncate)((fptr->Fptr)->filehandle,
+ filesize) );
+ }
+ else
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffflushx( FITSfile *fptr) /* I - FITS file pointer */
+/*
+ low level routine to flush internal file buffers to the file.
+*/
+{
+ if (driverTable[fptr->driver].flush)
+ return ( (*driverTable[fptr->driver].flush)(fptr->filehandle) );
+ else
+ return(0); /* no flush function defined for this driver */
+}
+/*--------------------------------------------------------------------------*/
+int ffseek( FITSfile *fptr, /* I - FITS file pointer */
+ OFF_T position) /* I - byte position to seek to */
+/*
+ low level routine to seek to a position in a file.
+*/
+{
+ return( (*driverTable[fptr->driver].seek)(fptr->filehandle, position) );
+}
+/*--------------------------------------------------------------------------*/
+int ffwrite( FITSfile *fptr, /* I - FITS file pointer */
+ long nbytes, /* I - number of bytes to write */
+ void *buffer, /* I - buffer to write */
+ int *status) /* O - error status */
+/*
+ low level routine to write bytes to a file.
+*/
+{
+ if ( (*driverTable[fptr->driver].write)(fptr->filehandle, buffer, nbytes) )
+ *status = WRITE_ERROR;
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffread( FITSfile *fptr, /* I - FITS file pointer */
+ long nbytes, /* I - number of bytes to read */
+ void *buffer, /* O - buffer to read into */
+ int *status) /* O - error status */
+/*
+ low level routine to read bytes from a file.
+*/
+{
+ int readstatus;
+
+ readstatus = (*driverTable[fptr->driver].read)(fptr->filehandle,
+ buffer, nbytes);
+
+ if (readstatus == END_OF_FILE)
+ *status = END_OF_FILE;
+ else if (readstatus > 0)
+ *status = READ_ERROR;
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fftplt(fitsfile **fptr, /* O - FITS file pointer */
+ const char *filename, /* I - name of file to create */
+ const char *tempname, /* I - name of template file */
+ int *status) /* IO - error status */
+/*
+ Create and initialize a new FITS file based on a template file.
+ Uses C fopen and fgets functions.
+*/
+{
+ if (*status > 0)
+ return(*status);
+
+ if ( ffinit(fptr, filename, status) ) /* create empty file */
+ return(*status);
+
+ ffoptplt(*fptr, tempname, status); /* open and use template */
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffoptplt(fitsfile *fptr, /* O - FITS file pointer */
+ const char *tempname, /* I - name of template file */
+ int *status) /* IO - error status */
+/*
+ open template file and use it to create new file
+*/
+{
+ fitsfile *tptr;
+ int tstatus = 0, nkeys, nadd, ii;
+ char card[FLEN_CARD];
+
+ if (*status > 0)
+ return(*status);
+
+ if (tempname == NULL || *tempname == '\0') /* no template file? */
+ return(*status);
+
+ /* try opening template */
+ ffopen(&tptr, (char *) tempname, READONLY, &tstatus);
+
+ if (tstatus) /* not a FITS file, so treat it as an ASCII template */
+ {
+ ffxmsg(2, card); /* clear the error message */
+ fits_execute_template(fptr, (char *) tempname, status);
+
+ ffmahd(fptr, 1, 0, status); /* move back to the primary array */
+ return(*status);
+ }
+ else /* template is a valid FITS file */
+ {
+ ffmahd(tptr, 1, NULL, status); /* make sure we are at the beginning */
+ while (*status <= 0)
+ {
+ ffghsp(tptr, &nkeys, &nadd, status); /* get no. of keywords */
+
+ for (ii = 1; ii <= nkeys; ii++) /* copy keywords */
+ {
+ ffgrec(tptr, ii, card, status);
+ ffprec(fptr, card, status);
+ }
+
+ ffmrhd(tptr, 1, 0, status); /* move to next HDU until error */
+ ffcrhd(fptr, status); /* create empty new HDU in output file */
+ }
+
+ if (*status == END_OF_FILE)
+ {
+ *status = 0; /* expected error condition */
+ }
+ ffclos(tptr, status); /* close the template file */
+ }
+
+ ffmahd(fptr, 1, 0, status); /* move to the primary array */
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+void ffrprt( FILE *stream, int status)
+/*
+ Print out report of cfitsio error status and messages on the error stack.
+ Uses C FILE stream.
+*/
+{
+ char status_str[FLEN_STATUS], errmsg[FLEN_ERRMSG];
+
+ if (status)
+ {
+
+ fits_get_errstatus(status, status_str); /* get the error description */
+ fprintf(stream, "\nFITSIO status = %d: %s\n", status, status_str);
+
+ while ( fits_read_errmsg(errmsg) ) /* get error stack messages */
+ fprintf(stream, "%s\n", errmsg);
+ }
+ return;
+}
diff --git a/pkg/tbtables/cfitsio/cfitsio.doc b/pkg/tbtables/cfitsio/cfitsio.doc
new file mode 100644
index 00000000..6ef31dfb
--- /dev/null
+++ b/pkg/tbtables/cfitsio/cfitsio.doc
@@ -0,0 +1,8406 @@
+ CFITSIO - An Interface to FITS Format Files for C Programmers
+
+ William D Pence, HEASARC, NASA/GSFC
+ Version 2.4
+
+
+[Note: This file contains various formatting command symbols ('*', '-')
+in the first column which are used when generating the LATeX version of
+this document.]
+
+*I. Introduction
+
+**A. A Brief Overview
+
+CFITSIO is a machine-independent library of routines for reading and
+writing data files in the FITS (Flexible Image Transport System) data
+format. It can also read IRAF format image files and raw binary data
+arrays by converting them on the fly into a virtual FITS format file.
+This library is written in ANSI C and provides a powerful yet simple
+interface for accessing FITS files which will run on most commonly used
+computers and workstations. CFITSIO supports all the features
+described in the official NOST definition of the FITS format and can
+read and write all the currently defined types of extensions, including
+ASCII tables (TABLE), Binary tables (BINTABLE) and IMAGE extensions.
+The CFITSIO routines insulate the programmer from having to deal with
+the complicated formatting details in the FITS file, however, it is
+assumed that users have a general knowledge about the structure and
+usage of FITS files.
+
+CFITSIO also contains a set of Fortran callable wrapper routines which
+allow Fortran programs to call the CFITSIO routines. See the companion
+``FITSIO User's Guide'' for the definition of the Fortran subroutine
+calling sequences. These wrappers replace the older Fortran FITSIO
+library which is no longer supported.
+
+The CFITSIO package was initially developed by the HEASARC (High Energy
+Astrophysics Science Archive Research Center) at the NASA Goddard Space
+Flight Center to convert various existing and newly acquired
+astronomical data sets into FITS format and to further analyze data
+already in FITS format. New features continue to be added to CFITSIO
+in large part due to contributions of ideas or actual code from
+users of the package. The Integral Science Data Center in Switzerland,
+and the XMM/ESTEC project in The Netherlands made especially significant
+contributions that resulted in many of the new features that appeared
+in v2.0 of CFITSIO.
+
+**B. Sources of FITS Software and Information
+
+The latest version of the CFITSIO source code,
+documentation, and example programs are available on the World-Wide
+Web or via anonymous ftp from:
+-
+ http://heasarc.gsfc.nasa.gov/fitsio
+ ftp://legacy.gsfc.nasa.gov/software/fitsio/c
+-
+
+Any questions, bug reports, or suggested enhancements related to the CFITSIO
+package should be sent to the primary author:
+-
+ Dr. William Pence Telephone: (301) 286-4599
+ HEASARC, Code 662 E-mail: pence@tetra.gsfc.nasa.gov
+ NASA/Goddard Space Flight Center
+ Greenbelt, MD 20771, USA
+-
+This User's Guide assumes that readers already have a general
+understanding of the definition and structure of FITS format files.
+Further information about FITS formats is available from the FITS Support
+Office at {\tt http://fits.gsfc.nasa.gov}. In particular, the
+'NOST FITS Standard' gives the authoritative definition of the FITS data
+format, and the `FITS User's Guide' provides additional historical background
+and practical advice on using FITS files.
+
+The HEASARC also provides a very sophisticated FITS file analysis
+program called `Fv' which can be used to display and edit the contents
+of any FITS file as well as construct new FITS files from scratch. The
+display functions in Fv allow users to interactively adjust the
+brightness and contrast of images, pan, zoom, and blink images, and
+measure the positions and brightnesses of objects within images. FITS
+tables can be displayed like a spread sheet, and then modified using
+powerful calculator and sorting functions. Fv is freely available for
+most Unix platforms, Mac PCs, and Windows PCs.
+CFITSIO users may also be interested in the FTOOLS package of programs
+that can be used to manipulate and analyze FITS format files.
+Fv and FTOOLS are available from their respective Web sites at:
+-
+ http://fv.gsfc.nasa.gov
+ http://heasarc.gsfc.nasa.gov/ftools
+-
+
+**C. Acknowledgements
+
+The development of the powerful features in CFITSIO was made
+possible through collaborations with many people or organizations from
+around the world. The following in particular have made especially
+significant contributions:
+
+Programmers from the Integral Science Data Center, Switzerland (namely,
+Jurek Borkowski, Bruce O'Neel, and Don Jennings), designed the concept
+for the plug-in I/O drivers that was introduced with CFITSIO 2.0. The
+use of `drivers' greatly simplified the low-level I/O, which in turn
+made other new features in CFITSIO (e.g., support for compressed FITS
+files and support for IRAF format image files) much easier to
+implement. Jurek Borkowski wrote the Shared Memory driver, and Bruce
+O'Neel wrote the drivers for accessing FITS files over the network
+using the FTP, HTTP, and ROOT protocols.
+
+The ISDC also provided the template parsing routines (written by Jurek
+Borkowski) and the hierarchical grouping routines (written by Don
+Jennings). The ISDC DAL (Data Access Layer) routines are layered on
+top of CFITSIO and make extensive use of these features.
+
+Uwe Lammers (XMM/ESA/ESTEC, The Netherlands) designed the
+high-performance lexical parsing algorithm that is used to do
+on-the-fly filtering of FITS tables. This algorithm essentially
+pre-compiles the user-supplied selection expression into a form that
+can be rapidly evaluated for each row. Peter Wilson (RSTX, NASA/GSFC)
+then wrote the parsing routines used by CFITSIO based on Lammers'
+design, combined with other techniques such as the CFITSIO iterator
+routine to further enhance the data processing throughput. This effort
+also benefited from a much earlier lexical parsing routine that was
+developed by Kent Blackburn (NASA/GSFC). More recently, Craig Markwardt
+(NASA/GSFC) implemented additional functions (median, average, stddev)
+and other enhancements to the lexical parser.
+
+The CFITSIO iterator function is loosely based on similar ideas
+developed for the XMM Data Access Layer.
+
+Peter Wilson (RSTX, NASA/GSFC) wrote the complete set of
+Fortran-callable wrappers for all the CFITSIO routines, which in turn
+rely on the CFORTRAN macro developed by Burkhard Burow.
+
+The syntax used by CFITSIO for filtering or binning input FITS files is
+based on ideas developed for the AXAF Science Center Data Model by
+Jonathan McDowell, Antonella Fruscione, Aneta Siemiginowska and Bill
+Joye. See http://heasarc.gsfc.nasa.gov/docs/journal/axaf7.html for
+further description of the AXAF Data Model.
+
+The file decompression code were taken directly from the gzip (GNU zip)
+program developed by Jean-loup Gailly and others.
+
+The new compressed image data format (where the image is tiled and
+the compressed byte stream from each tile is stored in a binary table)
+was implemented in collaboration with Richard White (STScI), Perry
+Greenfield (STScI) and Doug Tody (NOAO).
+
+Doug Mink (SAO) provided the routines for converting IRAF format
+images into FITS format.
+
+In addition, many other people have made valuable contributions to the
+development of CFITSIO. These include (with apologies to others that may
+have inadvertently been omitted):
+
+Steve Allen, Carl Akerlof, Keith Arnaud, Morten Krabbe Barfoed, Kent
+Blackburn, G Bodammer, Romke Bontekoe, Lucio Chiappetti, Keith Costorf,
+Robin Corbet, John Davis, Richard Fink, Ning Gan, Emily Greene, Gretchen
+Green, Joe Harrington, Cheng Ho, Phil Hodge, Jim Ingham, Yoshitaka
+Ishisaki, Diab Jerius, Mark Levine, Todd Karakaskian, Edward King,
+Scott Koch, Claire Larkin, Rob Managan, Eric Mandel, Richard Mathar,
+John Mattox, Carsten Meyer, Emi Miyata, Stefan Mochnacki, Mike Noble,
+Oliver Oberdorf, Clive Page, Arvind Parmar, Jeff Pedelty, Tim Pearson,
+Philippe Prugniel, Maren Purves, Scott Randall, Chris Rogers, Arnold Rots,
+Barry Schlesinger, Robin Stebbins, Andrew Szymkowiak, Allyn Tennant,
+Peter Teuben, James Theiler, Doug Tody, Shiro Ueno, Steve Walton, Archie
+Warnock, Alan Watson, Dan Whipple, Wim Wimmers, Peter Young, Jianjun Xu,
+and Nelson Zarate.
+
+**D. Legal Stuff
+
+Copyright (Unpublished--all rights reserved under the copyright laws of
+the United States), U.S. Government as represented by the Administrator
+of the National Aeronautics and Space Administration. No copyright is
+claimed in the United States under Title 17, U.S. Code.
+
+Permission to freely use, copy, modify, and distribute this software
+and its documentation without fee is hereby granted, provided that this
+copyright notice and disclaimer of warranty appears in all copies.
+(However, see the restriction on the use of the gzip compression code,
+below).
+
+DISCLAIMER:
+
+THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND,
+EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO,
+ANY WARRANTY THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY
+IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE, AND FREEDOM FROM INFRINGEMENT, AND ANY WARRANTY THAT THE
+DOCUMENTATION WILL CONFORM TO THE SOFTWARE, OR ANY WARRANTY THAT THE
+SOFTWARE WILL BE ERROR FREE. IN NO EVENT SHALL NASA BE LIABLE FOR ANY
+DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, INDIRECT, SPECIAL OR
+CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, OR IN ANY WAY
+CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY,
+CONTRACT, TORT , OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY
+PERSONS OR PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED
+FROM, OR AROSE OUT OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR
+SERVICES PROVIDED HEREUNDER."
+
+The file compress.c contains (slightly modified) source code that
+originally came from gzip-1.2.4, copyright (C) 1992-1993 by Jean-loup
+Gailly. This gzip code is distributed under the GNU General Public
+License and thus requires that any software that uses the CFITSIO
+library (which in turn uses the gzip code) must conform to the
+provisions in the GNU General Public License. A copy of the GNU
+license is included at the beginning of compress.c file.
+
+An alternate version of the compress.c file (called
+compress\_alternate.c) is provided for users who want to use the CFITSIO
+library but are unwilling or unable to publicly release their software
+under the terms of the GNU General Public License. This alternate
+version contains non-functional stubs for the file compression and
+uncompression routines used by CFITSIO. Replace the file `compress.c'
+with `compress\_alternate.c' before compiling the CFITSIO library. This
+will produce a version of CFITSIO which does not support reading or
+writing compressed FITS files but is otherwise identical to the
+standard version.
+
+*II. Creating the CFITSIO Library
+
+**A. Building the Library
+
+The CFITSIO code is contained in about 40 C source files (*.c) and header
+files (*.h). On VAX/VMS systems 2 assembly-code files (vmsieeed.mar and
+vmsieeer.mar) are also needed.
+
+CFITSIO has currently been tested on the following platforms:
+-
+ OPERATING SYSTEM COMPILER
+ Sun OS gcc and cc (3.0.1)
+ Sun Solaris gcc and cc
+ Silicon Graphics IRIX gcc and cc
+ Silicon Graphics IRIX64 MIPS
+ Dec Alpha OSF/1 gcc and cc
+ DECstation Ultrix gcc
+ Dec Alpha OpenVMS cc
+ DEC VAX/VMS gcc and cc
+ HP-UX gcc
+ IBM AIX gcc
+ Linux gcc
+ MkLinux DR3
+ Windows 95/98/NT Borland C++ V4.5
+ Windows 95/98/NT/ME/XP Microsoft/Compaq Visual C++ v5.0, v6.0
+ Windows 95/98/NT Cygwin gcc
+ MacOS 7.1 or greater Metrowerks 10.+
+ MacOS-X 10.1 or greater cc (gcc)
+-
+CFITSIO will probably run on most other Unix platforms. Cray
+supercomputers are currently not supported.
+
+***1. Unix Systems
+
+The CFITSIO library is built on Unix systems by typing:
+-
+ > ./configure [--prefix=/target/installation/path]
+ > make (or 'make shared')
+ > make install (this step is optional)
+-
+at the operating system prompt. The configure command customizes the
+Makefile for the particular system, then the `make' command compiles the
+source files and builds the library. Type `./configure' and not simply
+`configure' to ensure that the configure script in the current directory
+is run and not some other system-wide configure script. The optional
+'prefix' argument to configure gives the path to the directory where
+the CFITSIO library and include files should be installed via the later
+'make install' command. For example,
+-
+ > ./configure --prefix=/usr1/local
+-
+will cause the 'make install' command to copy the CFITSIO libcfitsio file
+to /usr1/local/lib and the necessary include files to /usr1/local/include
+(assuming of course that the process has permission to write to these
+directories).
+
+The 'make shared' option builds a shared or dynamic version of the
+CFITSIO library. When using the shared library the executable code is
+not copied into your program at link time and instead the program
+locates the necessary library code at run time, normally through
+LD\_LIBRARY\_PATH or some other method. The advantages of using a shared
+library are:
+-
+ 1. Less disk space if you build more than 1 program
+ 2. Less memory if more than one copy of a program using the shared
+ library is running at the same time since the system is smart
+ enough to share copies of the shared library at run time.
+ 3. Possibly easier maintenance since a new version of the shared
+ library can be installed without relinking all the software
+ that uses it (as long as the subroutine names and calling
+ sequences remain unchanged).
+ 4. No run-time penalty.
+-
+The disadvantages are:
+-
+ 1. More hassle at runtime. You have to either build the programs
+ specially or have LD_LIBRARY_PATH set right.
+ 2. There may be a slight start up penalty, depending on where you are
+ reading the shared library and the program from and if your CPU is
+ either really slow or really heavily loaded.
+-
+
+On Mac OS X platforms the 'make shared' command works like on other
+UNIX platforms, but a .dylib file will be created instead of .so. If
+installed in a nonstandard location, add its location to the
+DYLD\_LIBRARY\_PATH environment variable so that the library can be found
+at run time.
+
+On HP/UX systems, the environment variable CFLAGS should be set
+to -Ae before running configure to enable "extended ANSI" features.
+
+By default, a set of Fortran-callable wrapper routines are
+also built and included in the CFITSIO library. If these wrapper
+routines are not needed (i.e., the CFITSIO library will not
+be linked to any Fortran applications which call FITSIO subroutines)
+then they may be omitted from the build by typing 'make all-nofitsio'
+instead of simply typing 'make'. This will reduce the size
+of the CFITSIO library slightly.
+
+Most 32-bit operating systems have only supported disk files up to 2.1GB
+(2**31 bytes) in size. Starting with version 2.1 of CFITSIO, FITS files
+larger than this limit (up to 6 terabytes) can be read and written on
+platforms that support large files (e.g., at least some LINUX platforms
+and Solaris). To enable this
+feature, CFITSIO must be compiled with the '-D\_LARGEFILE\_SOURCE' and
+`-D\_FILE\_OFFSET\_BITS=64'
+compiler flags. Some platforms may also require the `-D\_LARGE\_FILES'
+compiler flag. It appears that in most cases it is not necessary to
+also include these compiler flags when compiling programs that link to
+the CFITSIO library. See the `CFITSIO Size Limitations'
+section in Chapter 4 for further details.
+
+It may not be possible to staticly link programs that use CFITSIO on
+some platforms (namely, on Solaris 2.6) due to the network drivers
+(which provide FTP and HTTP access to FITS files). It is possible to
+make both a dynamic and a static version of the CFITSIO library, but
+network file access will not be possible using the static version.
+
+***2. VMS
+
+On VAX/VMS and ALPHA/VMS systems the make\_gfloat.com command file may
+be executed to build the cfitsio.olb object library using the default
+G-floating point option for double variables. The make\_dfloat.com and
+make\_ieee.com files may be used instead to build the library with the
+other floating point options. Note that the getcwd function that is
+used in the group.c module may require that programs using CFITSIO be
+linked with the ALPHA\$LIBRARY:VAXCRTL.OLB library. See the example
+link line in the next section of this document.
+
+***3. Windows PCs
+
+A precompiled DLL version of CFITSIO is available for IBM-PC users of
+the Borland or Microsoft Visual C++ compilers in the files
+cfitsiodll\_2xxx\_borland.zip and cfitsiodll\_2xxx\_vcc.zip, where
+'2xxx' represents the current release number. These zip archives also
+contains other files and instructions on how to use the CFITSIO DLL
+library.
+
+The CFITSIO library may also be built from the source code using the
+makefile.bc or makefile.vcc files. Finally, the makepc.bat file gives
+an example of building CFITSIO with the Borland C++ v4.5 compiler
+using older DOS commands.
+
+***4. Macintosh PCs
+
+When building on Mac OS-X, users should follow the Unix instructions,
+above.
+
+The classic MacOS version (OS 9 or earlier) of the CFITSIO library can
+be built by (1) un binhex and unstuff cfitsio\_mac.sit.hqx, (2) put
+CFitsioPPC.mcp in the cfitsio directory, and (3) load CFitsioPPC.mcp
+into CodeWarrior Pro 5 and make. This builds the CFITSIO library for
+PPC. There are also targets for both the test program and the speed
+test program.
+
+To use the MacOS port you can add Cfitsio PPC.lib to your CodeWarrior
+Pro 5 project. Note that this only has been tested for the PPC and
+probably won't work on 68k Macs.
+
+
+**B. Testing the Library
+
+The CFITSIO library should be tested by building and running
+the testprog.c program that is included with the release.
+On Unix systems, type:
+-
+ % make testprog
+ % testprog > testprog.lis
+ % diff testprog.lis testprog.out
+ % cmp testprog.fit testprog.std
+-
+ On VMS systems,
+(assuming cc is the name of the C compiler command), type:
+-
+ $ cc testprog.c
+ $ link testprog, cfitsio/lib, alpha$library:vaxcrtl/lib
+ $ run testprog
+-
+The test program should produce a FITS file called `testprog.fit'
+that is identical to the `testprog.std' FITS file included with this
+release. The diagnostic messages (which were piped to the file
+testprog.lis in the Unix example) should be identical to the listing
+contained in the file testprog.out. The 'diff' and 'cmp' commands
+shown above should not report any differences in the files. (There
+may be some minor format differences, such as the presence or
+absence of leading zeros, or 3 digit exponents in numbers,
+which can be ignored).
+
+The Fortran wrappers in CFITSIO may be tested with the testf77
+program on Unix systems with:
+-
+ % f77 -o testf77 testf77.f -L. -lcfitsio -lnsl -lsocket
+ or
+ % f77 -f -o testf77 testf77.f -L. -lcfitsio (under SUN O/S)
+ or
+ % f77 -o testf77 testf77.f -Wl,-L. -lcfitsio -lm -lnsl -lsocket (HP/UX)
+
+ % testf77 > testf77.lis
+ % diff testf77.lis testf77.out
+ % cmp testf77.fit testf77.std
+-
+On machines running SUN O/S, Fortran programs must be compiled with the
+'-f' option to force double precision variables to be aligned on 8-byte
+boundarys to make the fortran-declared variables compatible with C. A
+similar compiler option may be required on other platforms. Failing to
+use this option may cause the program to crash on FITSIO routines that
+read or write double precision variables.
+
+Also note that on some systems, the output listing of the testf77
+program may differ slightly from the testf77.std template, if leading
+zeros are not printed by default before the decimal point when using F
+format.
+
+A few other utility programs are included with CFITSIO; the first four
+of this programs can be compiled an linked by typing `make
+program\_name' where `program\_name' is the actual name of the program:
+-
+ speed - measures the maximum throughput (in MB per second)
+ for writing and reading FITS files with CFITSIO.
+
+ listhead - lists all the header keywords in any FITS file
+
+ fitscopy - copies any FITS file (especially useful in conjunction
+ with the CFITSIO's extended input filename syntax).
+
+ cookbook - a sample program that performs common read and
+ write operations on a FITS file.
+
+ iter_a, iter_b, iter_c - examples of the CFITSIO iterator routine
+-
+
+**C. Linking Programs with CFITSIO
+
+When linking applications software with the CFITSIO library, several
+system libraries usually need to be specified on the link command
+line. On Unix systems, the most reliable way to determine what
+libraries are required is to type 'make testprog' and see what
+libraries the configure script has added. The typical libraries that
+need to be added are -lm (the math library) and -lnsl and -lsocket
+(needed only for FTP and HTTP file access). These latter 2 libraries
+are not needed on VMS and Windows platforms, because FTP file access is
+not currently supported on those platforms.
+
+Note that when upgrading to a newer version of CFITSIO it is usually
+necessary to recompile, as well as relink, the programs that use CFITSIO,
+because the definitions in fitsio.h often change.
+
+**D. Getting Started with CFITSIO
+
+In order to effectively use the CFITSIO library it is recommended that
+new users begin by reading the ``CFITSIO Quick Start Guide''. It
+contains all the basic information needed to write programs that
+perform most types of operations on FITS files. The set of example
+FITS utility programs that are available from the CFITSIO web site are
+also very useful for learning how to use CFITSIO. To learn even more
+about the capabilities of the CFITSIO library the following steps are
+recommended:
+
+1. Read the following short `FITS Primer' chapter for an overview of
+the structure of FITS files.
+
+2. Review the Programming Guidelines in Chapter 4 to become familiar
+with the conventions used by the CFITSIO interface.
+
+3. Refer to the cookbook.c, listhead.c, and fitscopy.c programs that
+are included with this release for examples of routines that perform
+various common FITS file operations. Type 'make program\_name' to
+compile and link these programs on Unix systems.
+
+4. Write a simple program to read or write a FITS file using the Basic
+Interface routines described in Chapter 5.
+
+5. Scan through the more specialized routines that are described in
+the following chapters to become familiar with the functionality that
+they provide.
+
+**E. Example Program
+
+The following listing shows an example of how to use the CFITSIO
+routines in a C program. Refer to the cookbook.c program that is
+included with the CFITSIO distribution for other example routines.
+
+This program creates a new FITS file, containing a FITS image. An
+`EXPOSURE' keyword is written to the header, then the image data are
+written to the FITS file before closing the FITS file.
+-
+#include "fitsio.h" /* required by every program that uses CFITSIO */
+main()
+{
+ fitsfile *fptr; /* pointer to the FITS file; defined in fitsio.h */
+ int status, ii, jj;
+ long fpixel = 1, naxis = 2, nelements, exposure;
+ long naxes[2] = { 300, 200 }; /* image is 300 pixels wide by 200 rows */
+ short array[200][300];
+
+ status = 0; /* initialize status before calling fitsio routines */
+ fits_create_file(&fptr, "testfile.fits", &status); /* create new file */
+
+ /* Create the primary array image (16-bit short integer pixels */
+ fits_create_img(fptr, SHORT_IMG, naxis, naxes, &status);
+
+ /* Write a keyword; must pass the ADDRESS of the value */
+ exposure = 1500.;
+ fits_update_key(fptr, TLONG, "EXPOSURE", &exposure,
+ "Total Exposure Time", &status);
+
+ /* Initialize the values in the image with a linear ramp function */
+ for (jj = 0; jj < naxes[1]; jj++)
+ for (ii = 0; ii < naxes[0]; ii++)
+ array[jj][ii] = ii + jj;
+
+ nelements = naxes[0] * naxes[1]; /* number of pixels to write */
+
+ /* Write the array of integers to the image */
+ fits_write_img(fptr, TSHORT, fpixel, nelements, array[0], &status);
+
+ fits_close_file(fptr, &status); /* close the file */
+
+ fits_report_error(stderr, status); /* print out any error messages */
+ return( status );
+}
+-
+
+*III. A FITS Primer
+
+This section gives a brief overview of the structure of FITS files.
+Users should refer to the documentation available from the NOST, as
+described in the introduction, for more detailed information on FITS
+formats.
+
+FITS was first developed in the late 1970's as a standard data
+interchange format between various astronomical observatories. Since
+then FITS has become the standard data format supported by most
+astronomical data analysis software packages.
+
+A FITS file consists of one or more Header + Data Units (HDUs), where
+the first HDU is called the `Primary HDU', or `Primary Array'. The
+primary array contains an N-dimensional array of pixels, such as a 1-D
+spectrum, a 2-D image, or a 3-D data cube. Five different primary
+data types are supported: Unsigned 8-bit bytes, 16 and 32-bit signed
+integers, and 32 and 64-bit floating point reals. FITS also has a
+convention for storing 16 and 32-bit unsigned integers (see the later
+section entitled `Unsigned Integers' for more details). The primary HDU
+may also consist of only a header with a null array containing no
+data pixels.
+
+Any number of additional HDUs may follow the primary array; these
+additional HDUs are called FITS `extensions'. There are currently 3
+types of extensions defined by the FITS standard:
+
+\begin{itemize}
+\item
+ Image Extension - a N-dimensional array of pixels, like in a primary array
+\item
+ ASCII Table Extension - rows and columns of data in ASCII character format
+\item
+ Binary Table Extension - rows and columns of data in binary representation
+\end{itemize}
+
+In each case the HDU consists of an ASCII Header Unit followed by an optional
+Data Unit. For historical reasons, each Header or Data unit must be an
+exact multiple of 2880 8-bit bytes long. Any unused space is padded
+with fill characters (ASCII blanks or zeros).
+
+Each Header Unit consists of any number of 80-character keyword records
+or `card images' which have the
+general form:
+-
+ KEYNAME = value / comment string
+ NULLKEY = / comment: This keyword has no value
+-
+The keyword names may be up to 8 characters long and can only contain
+uppercase letters, the digits 0-9, the hyphen, and the underscore
+character. The keyword name is (usually) followed by an equals sign and
+a space character (= ) in columns 9 - 10 of the record, followed by the
+value of the keyword which may be either an integer, a floating point
+number, a character string (enclosed in single quotes), or a boolean
+value (the letter T or F). A keyword may also have a null or undefined
+value if there is no specified value string, as in the second example, above
+
+The last keyword in the header is always the `END' keyword which has no
+value or comment fields. There are many rules governing the exact
+format of a keyword record (see the NOST FITS Standard) so it is better
+to rely on standard interface software like CFITSIO to correctly
+construct or to parse the keyword records rather than try to deal
+directly with the raw FITS formats.
+
+Each Header Unit begins with a series of required keywords which depend
+on the type of HDU. These required keywords specify the size and
+format of the following Data Unit. The header may contain other
+optional keywords to describe other aspects of the data, such as the
+units or scaling values. Other COMMENT or HISTORY keywords are also
+frequently added to further document the data file.
+
+The optional Data Unit immediately follows the last 2880-byte block in
+the Header Unit. Some HDUs do not have a Data Unit and only consist of
+the Header Unit.
+
+If there is more than one HDU in the FITS file, then the Header Unit of
+the next HDU immediately follows the last 2880-byte block of the
+previous Data Unit (or Header Unit if there is no Data Unit).
+
+The main required keywords in FITS primary arrays or image extensions are:
+\begin{itemize}
+\item
+BITPIX -- defines the data type of the array: 8, 16, 32, -32, -64 for
+unsigned 8--bit byte, 16--bit signed integer, 32--bit signed integer,
+32--bit IEEE floating point, and 64--bit IEEE double precision floating
+point, respectively.
+\item
+NAXIS -- the number of dimensions in the array, usually 0, 1, 2, 3, or 4.
+\item
+NAXISn -- (n ranges from 1 to NAXIS) defines the size of each dimension.
+\end{itemize}
+
+FITS tables start with the keyword XTENSION = `TABLE' (for ASCII
+tables) or XTENSION = `BINTABLE' (for binary tables) and have the
+following main keywords:
+\begin{itemize}
+\item
+TFIELDS -- number of fields or columns in the table
+\item
+NAXIS2 -- number of rows in the table
+\item
+TTYPEn -- for each column (n ranges from 1 to TFIELDS) gives the
+name of the column
+\item
+TFORMn -- the data type of the column
+\item
+TUNITn -- the physical units of the column (optional)
+\end{itemize}
+
+Users should refer to the FITS Support Office at {\tt http://fits.gsfc.nasa.gov}
+for futher information about the FITS format and related software
+packages.
+
+
+*IV. Programming Guidelines
+
+**A. CFITSIO Definitions
+
+Any program that uses the CFITSIO interface must include the fitsio.h
+header file with the statement
+-
+ #include "fitsio.h"
+-
+This header file contains the prototypes for all the CFITSIO user
+interface routines as well as the definitions of various constants used
+in the interface. It also defines a C structure of type `fitsfile'
+that is used by CFITSIO to store the relevant parameters that define
+the format of a particular FITS file. Application programs must define
+a pointer to this structure for each FITS file that is to be opened.
+This structure is initialized (i.e., memory is allocated for the
+structure) when the FITS file is first opened or created with the
+fits\_open\_file or fits\_create\_file routines. This fitsfile pointer
+is then passed as the first argument to every other CFITSIO routine
+that operates on the FITS file. Application programs must not directly
+read or write elements in this fitsfile structure because the
+definition of the structure may change in future versions of CFITSIO.
+
+A number of symbolic constants are also defined in fitsio.h for the
+convenience of application programmers. Use of these symbolic
+constants rather than the actual numeric value will help to make the
+source code more readable and easier for others to understand.
+-
+String Lengths, for use when allocating character arrays:
+
+ #define FLEN_FILENAME 1025 /* max length of a filename */
+ #define FLEN_KEYWORD 72 /* max length of a keyword */
+ #define FLEN_CARD 81 /* max length of a FITS header card */
+ #define FLEN_VALUE 71 /* max length of a keyword value string */
+ #define FLEN_COMMENT 73 /* max length of a keyword comment string */
+ #define FLEN_ERRMSG 81 /* max length of a CFITSIO error message */
+ #define FLEN_STATUS 31 /* max length of a CFITSIO status text string */
+
+ Note that FLEN_KEYWORD is longer than the nominal 8-character keyword
+ name length because the HIERARCH convention supports longer keyword names.
+
+Access modes when opening a FITS file:
+
+ #define READONLY 0
+ #define READWRITE 1
+
+BITPIX data type code values for FITS images:
+
+ #define BYTE_IMG 8 /* 8-bit unsigned integers */
+ #define SHORT_IMG 16 /* 16-bit signed integers */
+ #define LONG_IMG 32 /* 32-bit signed integers */
+ #define FLOAT_IMG -32 /* 32-bit single precision floating point */
+ #define DOUBLE_IMG -64 /* 64-bit double precision floating point */
+
+ The following 4 data type codes are also supported by CFITSIO:
+ #define LONGLONG_IMG 64 /* 64-bit long signed integers */
+ #define SBYTE_IMG 10 /* 8-bit signed integers, equivalent to */
+ /* BITPIX = 8, BSCALE = 1, BZERO = -128 */
+ #define USHORT_IMG 20 /* 16-bit unsigned integers, equivalent to */
+ /* BITPIX = 16, BSCALE = 1, BZERO = 32768 */
+ #define ULONG_IMG 40 /* 32-bit unsigned integers, equivalent to */
+ /* BITPIX = 32, BSCALE = 1, BZERO = 2147483648 */
+
+Codes for the data type of binary table columns and/or for the
+data type of variables when reading or writing keywords or data:
+
+ DATATYPE TFORM CODE
+ #define TBIT 1 /* 'X' */
+ #define TBYTE 11 /* 8-bit unsigned byte, 'B' */
+ #define TLOGICAL 14 /* logicals (int for keywords */
+ /* and char for table cols 'L' */
+ #define TSTRING 16 /* ASCII string, 'A' */
+ #define TSHORT 21 /* signed short, 'I' */
+ #define TINT32BIT 41 /* signed 32-bit int, 'J' */
+ #define TLONG 41 /* signed long, */
+ #define TFLOAT 42 /* single precision float, 'E' */
+ #define TDOUBLE 82 /* double precision float, 'D' */
+ #define TCOMPLEX 83 /* complex (pair of floats) 'C' */
+ #define TDBLCOMPLEX 163 /* double complex (2 doubles) 'M' */
+
+ The following data type codes are also supported by CFITSIO:
+ #define TINT 31 /* int */
+ #define TSBYTE 12 /* 8-bit signed byte, 'S' */
+ #define TUINT 30 /* unsigned int 'V' */
+ #define TUSHORT 20 /* unsigned short 'U' */
+ #define TULONG 40 /* unsigned long */
+ #define TLONGLONG 81 /* 64-bit long signed integer 'K' */
+
+HDU type code values (value returned when moving to new HDU):
+
+ #define IMAGE_HDU 0 /* Primary Array or IMAGE HDU */
+ #define ASCII_TBL 1 /* ASCII table HDU */
+ #define BINARY_TBL 2 /* Binary table HDU */
+ #define ANY_HDU -1 /* matches any type of HDU */
+
+Column name and string matching case-sensitivity:
+
+ #define CASESEN 1 /* do case-sensitive string match */
+ #define CASEINSEN 0 /* do case-insensitive string match */
+
+Logical states (if TRUE and FALSE are not already defined):
+
+ #define TRUE 1
+ #define FALSE 0
+
+Values to represent undefined floating point numbers:
+
+ #define FLOATNULLVALUE -9.11912E-36F
+ #define DOUBLENULLVALUE -9.1191291391491E-36
+
+Image compression algorithm definitions
+
+ #define RICE_1 11
+ #define GZIP_1 21
+ #define PLIO_1 31
+-
+
+**B. Current Header Data Unit (CHDU)
+
+The concept of the Current Header and Data Unit, or CHDU, is
+fundamental to the use of the CFITSIO library. A simple FITS image may
+only contain a single Header and Data unit (HDU), but in general FITS
+files can contain multiple Header Data Units (also known as
+`extensions'), concatenated one after the other in the file. The user
+can specify which HDU should be initially opened at run time by giving
+the HDU name or number after the root file name. For example,
+'myfile.fits[4]' opens the 5th HDU in the file (note that the numbering
+starts with 0), and 'myfile.fits[EVENTS] opens the HDU with the name
+'EVENTS' (as defined by the EXTNAME or HDUNAME keywords). If no HDU is
+specified then CFITSIO opens the first HDU (the primary array) by
+default. The CFITSIO routines which read and write data only operate
+within the opened HDU, Other CFITSIO routines are provided to move to
+and open any other existing HDU within the FITS file or to append or
+insert new HDUs in the FITS file.
+
+**C. Function Names and Variable Datatypes
+
+Most of the CFITSIO routines have both a short name as well as a
+longer descriptive name. The short name is only 5 or 6 characters long
+and is similar to the subroutine name in the Fortran-77 version of
+FITSIO. The longer name is more descriptive and it is recommended that
+it be used instead of the short name to more clearly document the
+source code.
+
+Many of the CFITSIO routines come in families which differ only in the
+data type of the associated parameter(s). The data type of these
+routines is indicated by the suffix of the routine name. The short
+routine names have a 1 or 2 character suffix (e.g., 'j' in 'ffpkyj')
+while the long routine names have a 4 character or longer suffix
+as shown in the following table:
+-
+ Long Short Data
+ Names Names Type
+ ----- ----- ----
+ _bit x bit
+ _byt b unsigned byte
+ _sbyt sb signed byte
+ _sht i short integer
+ _lng j long integer
+ _lnglng jj 8-byte LONGLONG integer (see note below)
+ _usht ui unsigned short integer
+ _ulng uj unsigned long integer
+ _uint uk unsigned int integer
+ _int k int integer
+ _flt e real exponential floating point (float)
+ _fixflt f real fixed-decimal format floating point (float)
+ _dbl d double precision real floating-point (double)
+ _fixdbl g double precision fixed-format floating point (double)
+ _cmp c complex reals (pairs of float values)
+ _fixcmp fc complex reals, fixed-format floating point
+ _dblcmp m double precision complex (pairs of double values)
+ _fixdblcmp fm double precision complex, fixed-format floating point
+ _log l logical (int)
+ _str s character string
+-
+
+The logical data type corresponds to `int' for logical keyword values,
+and `byte' for logical binary table columns. In other words, the value
+when writing a logical keyword must be stored in an `int' variable, and
+must be stored in a `char' array when reading or writing to `L' columns
+in a binary table. Inplicit data type conversion is not supported for
+logical table columns, but is for keywords, so a logical keyword may be
+read and cast to any numerical data type; a returned value = 0
+indicates false, and any other value = true.
+
+The `int' data type may be 2 bytes long on some IBM PC compatible
+systems and is usually 4 bytes long on most other systems. Some 64-bit
+machines, however, like the Dec Alpha/OSF, define the `short', `int',
+and `long' integer data types to be 2, 4, and 8 bytes long,
+respectively. The FITS standard only supports 2 and 4 byte integer
+data types, so CFITSIO internally converts between 4 and 8 bytes when
+reading or writing `long' integers on Alpha/OSF systems.
+
+The 8-byte 'LONGLONG' integer data type is supported on most platforms.
+CFITSIO defines the LONGLONG data type to be equivalent to 'long long'
+on most Unix platforms and on Mac OS-X. Since most Windows compilers don't
+support the 'long long' data type, LONGLONG is defined instead to be
+equivalent to '\_\_int64'. If the compiler does not support a 8-byte
+integer data type then LONGLONG is defined to be equivalent to 'long'.
+Note that the C format specifier to print out these long integer values
+is "\%lld" on most unix machines, except on OSF platforms where "\%ld"
+must be used. On Windows platform that have the \_\_int64 data type,
+the format specifier is "\%INT64d".
+
+When dealing with the FITS byte data type it is important to remember
+that the raw values (before any scaling by the BSCALE and BZERO, or
+TSCALn and TZEROn keyword values) in byte arrays (BITPIX = 8) or byte
+columns (TFORMn = 'B') are interpreted as unsigned bytes with values
+ranging from 0 to 255. Some C compilers define a 'char' variable as
+signed, so it is important to explicitly declare a numeric char
+variable as 'unsigned char' to avoid any ambiguity
+
+One feature of the CFITSIO routines is that they can operate on a `X'
+(bit) column in a binary table as though it were a `B' (byte) column.
+For example a `11X' data type column can be interpreted the same as a
+`2B' column (i.e., 2 unsigned 8-bit bytes). In some instances, it can
+be more efficient to read and write whole bytes at a time, rather than
+reading or writing each individual bit.
+
+The complex and double precision complex data types are not directly
+supported in ANSI C so these data types should be interpreted as pairs
+of float or double values, respectively, where the first value in each
+pair is the real part, and the second is the imaginary part.
+
+**D. Support for Unsigned Integers and Signed Bytes
+
+Although FITS does not directly support unsigned integers as one of its
+fundamental data types, FITS can still be used to efficiently store
+unsigned integer data values in images and binary tables. The
+convention used in FITS files is to store the unsigned integers as
+signed integers with an associated offset (specified by the BZERO or
+TZEROn keyword). For example, to store unsigned 16-bit integer values
+in a FITS image the image would be defined as a signed 16-bit integer
+(with BITPIX keyword = SHORT\_IMG = 16) with the keywords BSCALE = 1.0
+and BZERO = 32768. Thus the unsigned values of 0, 32768, and 65535,
+for example, are physically stored in the FITS image as -32768, 0, and
+32767, respectively; CFITSIO automatically adds the BZERO offset to
+these values when they are read. Similarly, in the case of unsigned
+32-bit integers the BITPIX keyword would be equal to LONG\_IMG = 32 and
+BZERO would be equal to 2147483648 (i.e. 2 raised to the 31st power).
+
+The CFITSIO interface routines will efficiently and transparently apply
+the appropriate offset in these cases so in general application
+programs do not need to be concerned with how the unsigned values are
+actually stored in the FITS file. As a convenience for users, CFITSIO
+has several predefined constants for the value of BITPIX (USHORT\_IMG,
+ULONG\_IMG) and for the TFORMn value in the case of binary tables (`U'
+and `V') which programmers can use when creating FITS files containing
+unsigned integer values. The following code fragment illustrates how
+to write a FITS 1-D primary array of unsigned 16-bit integers:
+-
+ unsigned short uarray[100];
+ int naxis, status;
+ long naxes[10], group, firstelem, nelements;
+ ...
+ status = 0;
+ naxis = 1;
+ naxes[0] = 100;
+ fits_create_img(fptr, USHORT_IMG, naxis, naxes, &status);
+
+ firstelem = 1;
+ nelements = 100;
+ fits_write_img(fptr, TUSHORT, firstelem, nelements,
+ uarray, &status);
+ ...
+-
+In the above example, the 2nd parameter in fits\_create\_img tells
+CFITSIO to write the header keywords appropriate for an array of 16-bit
+unsigned integers (i.e., BITPIX = 16 and BZERO = 32768). Then the
+fits\_write\_img routine writes the array of unsigned short integers
+(uarray) into the primary array of the FITS file. Similarly, a 32-bit
+unsigned integer image may be created by setting the second parameter
+in fits\_create\_img equal to `ULONG\_IMG' and by calling the
+fits\_write\_img routine with the second parameter = TULONG to write
+the array of unsigned long image pixel values.
+
+An analogous set of routines are available for reading or writing unsigned
+integer values and signed byte values in a FITS binary table extension.
+When specifying the TFORMn keyword value which defines the format of a
+column, CFITSIO recognized 3 additional data type codes besides those
+already defined in the FITS standard: `U' meaning a 16-bit unsigned
+integer column, `V' for a 32-bit unsigned integer column, and 'S'
+for a signed byte column. These non-standard data type codes are not
+actually written into the FITS file but instead are just used internally
+within CFITSIO. The following code fragment illustrates how to use
+these features:
+-
+ unsigned short uarray[100];
+ unsigned int varray[100];
+
+ int colnum, tfields, status;
+ long nrows, firstrow, firstelem, nelements, pcount;
+
+ char extname[] = "Test_table"; /* extension name */
+
+ /* define the name, data type, and physical units for the 2 columns */
+ char *ttype[] = { "Col_1", "Col_2", "Col_3" };
+ char *tform[] = { "1U", "1V", "1S"}; /* special CFITSIO codes */
+ char *tunit[] = { " ", " ", " " };
+ ...
+
+ /* write the header keywords */
+ status = 0;
+ nrows = 1;
+ tfields = 3
+ pcount = 0;
+ fits_create_tbl(fptr, BINARY_TBL, nrows, tfields, ttype, tform,
+ tunit, extname, &status);
+
+ /* write the unsigned shorts to the 1st column */
+ colnum = 1;
+ firstrow = 1;
+ firstelem = 1;
+ nelements = 100;
+ fits_write_col(fptr, TUSHORT, colnum, firstrow, firstelem,
+ nelements, uarray, &status);
+
+ /* now write the unsigned longs to the 2nd column */
+ colnum = 2;
+ fits_write_col(fptr, TUINT, colnum, firstrow, firstelem,
+ nelements, varray, &status);
+ ...
+-
+Note that the non-standard TFORM values for the 3 columns, `U' and `V',
+tell CFITSIO to write the keywords appropriate for unsigned 16-bit and
+unsigned 32-bit integers, respectively (i.e., TFORMn = '1I' and TZEROn
+= 32678 for unsigned 16-bit integers, and TFORMn = '1J' and TZEROn =
+2147483648 for unsigned 32-bit integers). The 'S' TFORMn value tells
+CFITSIO to write the keywords appropriate for a signed 8-bit byte column
+with TFORMn = '1B' and TZEROn = -128. The calls to fits\_write\_col
+then write the arrays of unsigned integer values to the columns.
+
+**E. Dealing with Character Strings
+
+The character string values in a FITS header or in an ASCII column in a
+FITS table extension are generally padded out with non-significant
+space characters (ASCII 32) to fill up the header record or the column
+width. When reading a FITS string value, the CFITSIO routines will
+strip off these non-significant trailing spaces and will return a
+null-terminated string value containing only the significant
+characters. Leading spaces in a FITS string are considered
+significant. If the string contains all blanks, then CFITSIO will
+return a single blank character, i.e, the first blank is considered to
+be significant, since it distinguishes the string from a null or
+undefined string, but the remaining trailing spaces are not
+significant.
+
+Similarly, when writing string values to a FITS file the
+CFITSIO routines expect to get a null-terminated string as input;
+CFITSIO will pad the string with blanks if necessary when writing it
+to the FITS file.
+
+When calling CFITSIO routines that return a character string it is
+vital that the size of the char array be large enough to hold the
+entire string of characters, otherwise CFITSIO will overwrite whatever
+memory locations follow the char array, possibly causing the program to
+execute incorrectly. This type of error can be difficult to debug, so
+programmers should always ensure that the char arrays are allocated
+enough space to hold the longest possible string, {\bf including} the
+terminating NULL character. The fitsio.h file contains the following
+defined constants which programmers are strongly encouraged to use
+whenever they are allocating space for char arrays:
+-
+#define FLEN_FILENAME 1025 /* max length of a filename */
+#define FLEN_KEYWORD 72 /* max length of a keyword */
+#define FLEN_CARD 81 /* length of a FITS header card */
+#define FLEN_VALUE 71 /* max length of a keyword value string */
+#define FLEN_COMMENT 73 /* max length of a keyword comment string */
+#define FLEN_ERRMSG 81 /* max length of a CFITSIO error message */
+#define FLEN_STATUS 31 /* max length of a CFITSIO status text string */
+-
+For example, when declaring a char array to hold the value string
+of FITS keyword, use the following statement:
+-
+ char value[FLEN_VALUE];
+-
+Note that FLEN\_KEYWORD is longer than needed for the nominal 8-character
+keyword name because the HIERARCH convention supports longer keyword names.
+
+**F. Implicit Data Type Conversion
+
+The CFITSIO routines that read and write numerical data can perform
+implicit data type conversion. This means that the data type of the
+variable or array in the program does not need to be the same as the
+data type of the value in the FITS file. Data type conversion is
+supported for numerical and string data types (if the string contains a
+valid number enclosed in quotes) when reading a FITS header keyword
+value and for numeric values when reading or writing values in the
+primary array or a table column. CFITSIO returns status =
+NUM\_OVERFLOW if the converted data value exceeds the range of the
+output data type. Implicit data type conversion is not supported
+within binary tables for string, logical, complex, or double complex
+data types.
+
+In addition, any table column may be read as if it contained string values.
+In the case of numeric columns the returned string will be formatted
+using the TDISPn display format if it exists.
+
+**G. Data Scaling
+
+When reading numerical data values in the primary array or a
+table column, the values will be scaled automatically by the BSCALE and
+BZERO (or TSCALn and TZEROn) header values if they are
+present in the header. The scaled data that is returned to the reading
+program will have
+-
+ output value = (FITS value) * BSCALE + BZERO
+-
+(a corresponding formula using TSCALn and TZEROn is used when reading
+from table columns). In the case of integer output values the floating
+point scaled value is truncated to an integer (not rounded to the
+nearest integer). The fits\_set\_bscale and fits\_set\_tscale routines
+(described in the `Advanced' chapter) may be used to override the
+scaling parameters defined in the header (e.g., to turn off the scaling
+so that the program can read the raw unscaled values from the FITS
+file).
+
+When writing numerical data to the primary array or to a table column
+the data values will generally be automatically inversely scaled by the
+value of the BSCALE and BZERO (or TSCALn and TZEROn) keyword values if
+they they exist in the header. These keywords must have been written
+to the header before any data is written for them to have any immediate
+effect. One may also use the fits\_set\_bscale and fits\_set\_tscale
+routines to define or override the scaling keywords in the header
+(e.g., to turn off the scaling so that the program can write the raw
+unscaled values into the FITS file). If scaling is performed, the
+inverse scaled output value that is written into the FITS file will
+have
+-
+ FITS value = ((input value) - BZERO) / BSCALE
+-
+(a corresponding formula using TSCALn and TZEROn is used when
+writing to table columns). Rounding to the nearest integer, rather
+than truncation, is performed when writing integer data types to the
+FITS file.
+
+**H. Support for IEEE Special Values
+
+The ANSI/IEEE-754 floating-point number standard defines certain
+special values that are used to represent such quantities as
+Not-a-Number (NaN), denormalized, underflow, overflow, and infinity.
+(See the Appendix in the NOST FITS standard or the NOST FITS User's
+Guide for a list of these values). The CFITSIO routines that read
+floating point data in FITS files recognize these IEEE special values
+and by default interpret the overflow and infinity values as being
+equivalent to a NaN, and convert the underflow and denormalized values
+into zeros. In some cases programmers may want access to the raw IEEE
+values, without any modification by CFITSIO. This can be done by
+calling the fits\_read\_img or fits\_read\_col routines while
+specifying 0.0 as the value of the NULLVAL parameter. This will force
+CFITSIO to simply pass the IEEE values through to the application
+program without any modification. This is not fully supported on
+VAX/VMS machines, however, where there is no easy way to bypass the
+default interpretation of the IEEE special values.
+
+**I. Error Status Values and the Error Message Stack
+
+Nearly all the CFITSIO routines return an error status value
+in 2 ways: as the value of the last parameter in the function call,
+and as the returned value of the function itself. This provides
+some flexibility in the way programmers can test if an error
+occurred, as illustrated in the following 2 code fragments:
+-
+ if ( fits_write_record(fptr, card, &status) )
+ printf(" Error occurred while writing keyword.");
+
+or,
+
+ fits_write_record(fptr, card, &status);
+ if ( status )
+ printf(" Error occurred while writing keyword.");
+-
+A listing of all the CFITSIO status code values is given at the end of
+this document. Programmers are encouraged to use the symbolic
+mnemonics (defined in fitsio.h) rather than the actual integer status
+values to improve the readability of their code.
+
+The CFITSIO library uses an `inherited status' convention for the
+status parameter which means that if a routine is called with a
+positive input value of the status parameter as input, then the routine
+will exit immediately without changing the value of the status
+parameter. Thus, if one passes the status value returned from each
+CFITSIO routine as input to the next CFITSIO routine, then whenever an
+error is detected all further CFITSIO processing will cease. This
+convention can simplify the error checking in application programs
+because it is not necessary to check the value of the status parameter
+after every single CFITSIO routine call. If a program contains a
+sequence of several CFITSIO calls, one can just check the status value
+after the last call. Since the returned status values are generally
+distinctive, it should be possible to determine which routine
+originally returned the error status.
+
+CFITSIO also maintains an internal stack of error messages
+(80-character maximum length) which in many cases provide a more
+detailed explanation of the cause of the error than is provided by the
+error status number alone. It is recommended that the error message
+stack be printed out whenever a program detects a CFITSIO error. The
+function fits\_report\_error will print out the entire error message
+stack, or alternatively one may call fits\_read\_errmsg to get the
+error messages one at a time.
+
+**J. Variable-Length Arrays in Binary Tables
+
+CFITSIO provides easy-to-use support for reading and writing data in
+variable length fields of a binary table. The variable length columns
+have TFORMn keyword values of the form `1Pt(len)' where `t' is the
+data type code (e.g., I, J, E, D, etc.) and `len' is an integer
+specifying the maximum length of the vector in the table. If the value
+of `len' is not specified when the table is created (e.g., if the TFORM
+keyword value is simply specified as '1PE' instead of '1PE(400) ), then
+CFITSIO will automatically scan the table when it is closed to
+determine the maximum length of the vector and will append this value
+to the TFORMn value.
+
+The same routines that read and write data in an ordinary fixed length
+binary table extension are also used for variable length fields,
+however, the routine parameters take on a slightly different
+interpretation as described below.
+
+All the data in a variable length field is written into an area called
+the `heap' which follows the main fixed-length FITS binary table. The
+size of the heap, in bytes, is specified by the PCOUNT keyword in the
+FITS header. When creating a new binary table, the initial value of
+PCOUNT should usually be set to zero. CFITSIO will recompute the size
+of the heap as the data is written and will automatically update the
+PCOUNT keyword value when the table is closed. When writing variable
+length data to a table, CFITSIO will automatically extend the size
+of the heap area if necessary, so that any following HDUs do not
+get overwritten.
+
+By default the heap data area starts immediately after the last row of
+the fixed-length table. This default starting location may be
+overridden by the THEAP keyword, but this is not recommended.
+If additional rows of data are added to the table, CFITSIO will
+automatically shift the the heap down to make room for the new
+rows, but it is obviously be more efficient to initially
+create the table with the necessary number of blank rows, so that
+the heap does not needed to be constantly moved.
+
+When writing to a variable length field the entire array of values for
+a given row of the table must be written with a single call to
+fits\_write\_col. The total length of the array is given by nelements
++ firstelem - 1. Additional elements cannot be appended to an existing
+vector at a later time since any attempt to do so will simply overwrite
+all the previously written data. Note also that the new data will be
+written to a new area of the heap and the heap space used by the
+previous write cannot be reclaimed. For this reason each row of a
+variable length field should only be written once. An exception to
+this general rule occurs when setting elements of an array as
+undefined. One must first write a dummy value into the array with
+fits\_write\_col, and then call fits\_write\_col\_nul to flag the
+desired elements as undefined. (Do not use the fits\_write\_colnull
+routines with variable length fields). Note that the rows of a table,
+whether fixed or variable length, do not have to be written
+consecutively and may be written in any order.
+
+When writing to a variable length ASCII character field (e.g., TFORM =
+'1PA') only a single character string can be written. The `firstelem'
+and `nelements' parameter values in the fits\_write\_col routine are
+ignored and the number of characters to write is simply determined by
+the length of the input null-terminated character string.
+
+The fits\_write\_descript routine is useful in situations where
+multiple rows of a variable length column have the identical array of
+values. One can simply write the array once for the first row, and
+then use fits\_write\_descript to write the same descriptor values into
+the other rows; all the rows will then point to the same storage
+location thus saving disk space.
+
+When reading from a variable length array field one can only read as
+many elements as actually exist in that row of the table; reading does
+not automatically continue with the next row of the table as occurs
+when reading an ordinary fixed length table field. Attempts to read
+more than this will cause an error status to be returned. One can
+determine the number of elements in each row of a variable column with
+the fits\_read\_descript routine.
+
+**K. Multiple Access to the Same FITS File
+
+CFITSIO supports simultaneous read and write access to multiple HDUs in
+the same FITS file. Thus, one can open the same FITS file twice within
+a single program and move to 2 different HDUs in the file, and then
+read and write data or keywords to the 2 extensions just as if one were
+accessing 2 completely separate FITS files. Since in general it is
+not possible to physically open the same file twice and then expect to
+be able to simultaneously (or in alternating succession) write to 2
+different locations in the file, CFITSIO recognizes when the file to be
+opened (in the call to fits\_open\_file) has already been opened and
+instead of actually opening the file again, just logically links the
+new file to the old file. (This only applies if the file is opened
+more than once within the same program, and does not prevent the same
+file from being simultaneously opened by more than one program). Then
+before CFITSIO reads or writes to either (logical) file, it makes sure
+that any modifications made to the other file have been completely
+flushed from the internal buffers to the file. Thus, in principle, one
+could open a file twice, in one case pointing to the first extension
+and in the other pointing to the 2nd extension and then write data to
+both extensions, in any order, without danger of corrupting the file,
+There may be some efficiency penalties in doing this however, since
+CFITSIO has to flush all the internal buffers related to one file
+before switching to the other, so it would still be prudent to
+minimize the number of times one switches back and forth between doing
+I/O to different HDUs in the same file.
+
+**L. When the Final Size of the FITS HDU is Unknown
+
+It is not required to know the total size of a FITS data array or table
+before beginning to write the data to the FITS file. In the case of
+the primary array or an image extension, one should initially create
+the array with the size of the highest dimension (largest NAXISn
+keyword) set to a dummy value, such as 1. Then after all the data have
+been written and the true dimensions are known, then the NAXISn value
+should be updated using the fits\_update\_key routine before moving to
+another extension or closing the FITS file.
+
+When writing to FITS tables, CFITSIO automatically keeps track of the
+highest row number that is written to, and will increase the size of
+the table if necessary. CFITSIO will also automatically insert space
+in the FITS file if necessary, to ensure that the data 'heap', if it
+exists, and/or any additional HDUs that follow the table do not get
+overwritten as new rows are written to the table.
+
+As a general rule it is best to specify the initial number of rows = 0
+when the table is created, then let CFITSIO keep track of the number of
+rows that are actually written. The application program should not
+manually update the number of rows in the table (as given by the NAXIS2
+keyword) since CFITSIO does this automatically. If a table is
+initially created with more than zero rows, then this will usually be
+considered as the minimum size of the table, even if fewer rows are
+actually written to the table. Thus, if a table is initially created
+with NAXIS2 = 20, and CFITSIO only writes 10 rows of data before
+closing the table, then NAXIS2 will remain equal to 20. If however, 30
+rows of data are written to this table, then NAXIS2 will be increased
+from 20 to 30. The one exception to this automatic updating of the
+NAXIS2 keyword is if the application program directly modifies the
+value of NAXIS2 (up or down) itself just before closing the table. In this
+case, CFITSIO does not update NAXIS2 again, since it assumes that the
+application program must have had a good reason for changing the value
+directly. This is not recommended, however, and is only provided for
+backward compatibility with software that initially creates a table
+with a large number of rows, than decreases the NAXIS2 value to the
+actual smaller value just before closing the table.
+
+**M. CFITSIO Size Limitations
+
+CFITSIO places very few restrictions on the size of FITS files that it
+reads or writes. There are a few limits, however, that may affect
+some extreme cases:
+
+1. The maximum number of FITS files that may be simultaneously opened
+by CFITSIO is set by NMAXFILES as defined in fitsio2.h. It is currently
+set = 300 by default. CFITSIO will allocate about 80 * NMAXFILES bytes
+of memory for internal use. Note that the underlying C compiler or
+operating system, may have a smaller limit on the number of opened files.
+The C symbolic constant FOPEN\_MAX is intended to define the maximum
+number of files that may open at once (including any other text or
+binary files that may be open, not just FITS files). On some systems it
+has been found that gcc supports a maximum of 255 opened files.
+
+Note that opening and operating on many FITS files simultaneously in
+parallel may be less efficient than operating on smaller groups of files
+in series. CFITSIO only has NIOBUF number of internal buffers (set = 40
+by default) that are used for temporary storage of the most recent data
+records that have been read or written in the FITS files. If the number
+of opened files is greater than NIOBUF, then CFITSIO may waste more time
+flushing and re-reading or re-writing the same records in the FITS files.
+
+2. By default, CFITSIO can handle FITS files up to 2.1 GB in size (2**31
+bytes). This file size limit is often imposed by 32-bit operating
+systems. More recently, as 64-bit operating systems become more common, an
+industry-wide standard (at least on Unix systems) has been developed to
+support larger sized files (see http://ftp.sas.com/standards/large.file/).
+Starting with version 2.1 of CFITSIO, larger FITS files up to 6 terabytes
+in size may be read and written on supported platforms. In order
+to support these larger files, CFITSIO must be compiled with the
+'-D\_LARGEFILE\_SOURCE' and `-D\_FILE\_OFFSET\_BITS=64' compiler flags.
+Some platforms may also require the `-D\_LARGE\_FILES' compiler flag.
+ This causes the compiler to allocate 8-bytes instead of
+4-bytes for the `off\_t' data type that is used to store file offset
+positions. It appears that in most cases it is not necessary to
+also include these compiler flags when compiling programs that link to
+the CFITSIO library.
+
+If CFITSIO is compiled with the -D\_LARGEFILE\_SOURCE
+and -D\_FILE\_OFFSET\_BITS=64 flags on a
+platform that supports large files, then it can read and write FITS
+files that contain up to 2**31 2880-byte FITS records, or approximately
+6 terabytes in size. It is still required that the value of the NAXISn
+and PCOUNT keywords in each extension be within the range of a signed
+4-byte integer (max value = 2,147,483,648). Thus, each dimension of an
+image (given by the NAXISn keywords), the total width of a table
+(NAXIS1 keyword), the number of rows in a table (NAXIS2 keyword), and
+the total size of the variable-length array heap in binary tables
+(PCOUNT keyword) must be less than this limit.
+
+Currently, support for large files within CFITSIO has been tested
+on the Linux, Solaris, and IBM AIX operating systems.
+
+*V. Basic CFITSIO Interface Routines
+
+This chapter describes the basic routines in the CFITSIO user interface
+that provide all the functions normally needed to read and write most
+FITS files. It is recommended that these routines be used for most
+applications and that the more advanced routines described in the
+next chapter only be used in special circumstances when necessary.
+
+The following conventions are used in this chapter in the description
+of each function:
+
+1. Most functions have 2 names: a long descriptive name and a short
+concise name. Both names are listed on the first line of the following
+descriptions, separated by a slash (/) character. Programmers may use
+either name in their programs but the long names are recommended to
+help document the code and make it easier to read.
+
+2. A right arrow symbol ($>$) is used in the function descriptions to
+separate the input parameters from the output parameters in the
+definition of each routine. This symbol is not actually part of the C
+calling sequence.
+
+3. The function parameters are defined in more detail in the
+alphabetical listing in Appendix B.
+
+4. The first argument in almost all the functions is a pointer to a
+structure of type `fitsfile'. Memory for this structure is allocated
+by CFITSIO when the FITS file is first opened or created and is freed
+when the FITS file is closed.
+
+5. The last argument in almost all the functions is the error status
+parameter. It must be equal to 0 on input, otherwise the function will
+immediately exit without doing anything. A non-zero output value
+indicates that an error occurred in the function. In most cases the
+status value is also returned as the value of the function itself.
+
+**A. CFITSIO Error Status Routines
+
+>1 Return a descriptive text string (30 char max.) corresponding to
+> a CFITSIO error status code.\label{ffgerr}
+-
+ void fits_get_errstatus / ffgerr (int status, > char *err_text)
+-
+>2 Return the top (oldest) 80-character error message from the
+ internal CFITSIO stack of error messages and shift any remaining
+ messages on the stack up one level. Call this routine
+ repeatedly to get each message in sequence. The function returns
+ a value = 0 and a null error message when the error stack is empty.
+>\label{ffgmsg}
+-
+ int fits_read_errmsg / ffgmsg (char *err_msg)
+-
+>3 Print out the error message corresponding to the input status
+ value and all the error messages on the CFITSIO stack to the specified
+ file stream (normally to stdout or stderr). If the input
+ status value = 0 then this routine does nothing.
+>\label{ffrprt}
+-
+ void fits_report_error / ffrprt (FILE *stream, > status)
+-
+>4 The fits\_write\_errmark routine puts an invisible marker on the
+ CFITSIO error stack. The fits\_clear\_errmark routine can then be
+ used to delete any more recent error messages on the stack, back to
+ the position of the marker. This preserves any older error messages
+ on the stack. The fits\_clear\_errmsg routine simply clears all the
+ messages (and marks) from the stack. These routines are called
+ without any arguments.
+>\label{ffpmrk} \label{ffcmsg}
+-
+ void fits_write_errmark / ffpmrk (void)
+ void fits_clear_errmark / ffcmrk (void)
+ void fits_clear_errmsg / ffcmsg (void)
+-
+
+**B. FITS File Access Routines
+
+>1 Open an existing data file. \label{ffopen}
+
+-
+int fits_open_file / ffopen
+ (fitsfile **fptr, char *filename, int iomode, > int *status)
+
+int fits_open_diskfile / ffdkopen
+ (fitsfile **fptr, char *filename, int iomode, > int *status)
+
+int fits_open_data / ffdopn
+ (fitsfile **fptr, char *filename, int iomode, > int *status)
+
+int fits_open_table / fftopn
+ (fitsfile **fptr, char *filename, int iomode, > int *status)
+
+int fits_open_image / ffiopn
+ (fitsfile **fptr, char *filename, int iomode, > int *status)
+-
+
+The iomode parameter determines the read/write access allowed in the
+file and can have values of READONLY (0) or READWRITE (1). The filename
+parameter gives the name of the file to be opened, followed by an
+optional argument giving the name or index number of the extension
+within the FITS file that should be moved to and opened (e.g.,
+\verb-myfile.fits+3- or \verb-myfile.fits[3]- moves to the 3rd extension within
+the file, and \verb-myfile.fits[events]- moves to the extension with the
+keyword EXTNAME = 'EVENTS').
+
+The fits\_open\_diskfile routine is similar to the fits\_open\_file routine
+except that it does not support the extended filename syntax in the input
+file name. This routine simply tries to open the specified input file
+on magnetic disk. This routine is mainly for use in cases where the
+filename (or directory path) contains square or curly bracket characters
+that would confuse the extended filename parser.
+
+The fits\_open\_data routine is similar to the fits\_open\_file routine
+except that it will move to the first HDU containing significant data,
+if a HDU name or number to open was not explicitly specified as
+part of the filename. In this case, it will look for the first
+IMAGE HDU with NAXIS > 0, or the first table that does not contain the
+strings `GTI' (Good Time Interval extension) or `OBSTABLE' in the
+EXTNAME keyword value.
+
+The fits\_open\_table and fits\_open\_image routines are similar to
+fits\_open\_data except they will move to the first significant table
+HDU or image HDU in the file, respectively, if a HDU name or
+number is not specified as part of the filename.
+
+IRAF images (.imh format files) and raw binary data arrays may also be
+opened with READONLY access. CFITSIO will automatically test if the
+input file is an IRAF image, and if, so will convert it on the fly into
+a virtual FITS image before it is opened by the application program.
+If the input file is a raw binary data array of numbers, then the data type
+and dimensions of the array must be specified in square brackets
+following the name of the file (e.g. 'rawfile.dat[i512,512]' opens a
+512 x 512 short integer image). See the `Extended File Name Syntax'
+chapter for more details on how to specify the raw file name. The raw
+file is converted on the fly into a virtual FITS image in memory that
+is then opened by the application program with READONLY access.
+
+Programs can read the input file from the 'stdin' file stream if a dash
+character ('-') is given as the filename. Files can also be opened over
+the network using FTP or HTTP protocols by supplying the appropriate URL
+as the filename.
+
+The input file can be modified in various ways to create a virtual file
+(usually stored in memory) that is then opened by the application
+program by supplying a filtering or binning specifier in square brackets
+following the filename. Some of the more common filtering methods are
+illustrated in the following paragraphs, but users should refer to the
+'Extended File Name Syntax' chapter for a complete description of
+the full file filtering syntax.
+
+When opening an image, a rectangular subset of the physical image may be
+opened by listing the first and last pixel in each dimension (and
+optional pixel skipping factor):
+-
+myimage.fits[101:200,301:400]
+-
+will create and open a 100x100 pixel virtual image of that section of
+the physical image, and \verb+myimage.fits[*,-*]+ opens a virtual image
+that is the same size as the physical image but has been flipped in
+the vertical direction.
+
+When opening a table, the filtering syntax can be used to add or delete
+columns or keywords in the virtual table:
+\verb-myfile.fits[events][col !time; PI = PHA*1.2]- opens a virtual table in which the TIME column
+has been deleted and a new PI column has been added with a value 1.2
+times that of the PHA column. Similarly, one can filter a table to keep
+only those rows that satisfy a selection criterion:
+\verb-myfile.fits[events][pha > 50]- creates and opens a virtual table
+containing only those rows with a PHA value greater than 50. A large
+number of boolean and mathematical operators can be used in the
+selection expression. One can also filter table rows using 'Good Time
+Interval' extensions, and spatial region filters as in
+\verb-myfile.fits[events][gtifilter()]- and
+\verb-myfile.fits[events][regfilter( "stars.rng")]-.
+
+Finally, table columns may be binned or histogrammed to generate a
+virtual image. For example, \verb-myfile.fits[events][bin (X,Y)=4]- will
+result in a 2-dimensional image calculated by binning the X and Y
+columns in the event table with a bin size of 4 in each dimension. The
+TLMINn and TLMAXn keywords will be used by default to determine the
+range of the image.
+
+A single program can open the same FITS file more than once and then
+treat the resulting fitsfile pointers as though they were completely
+independent FITS files. Using this facility, a program can open a FITS
+file twice, move to 2 different extensions within the file, and then
+> read and write data in those extensions in any order.
+
+>2 Create and open a new empty output FITS file. \label{ffinit}
+
+-
+int fits_create_file / ffinit
+ (fitsfile **fptr, char *filename, > int *status)
+
+int fits_create_diskfile / ffdkinit
+ (fitsfile **fptr, char *filename, > int *status)
+-
+
+An error will be returned if the specified file already exists, unless
+the filename is prefixed with an exclamation point (!). In that case
+CFITSIO will overwrite (delete) any existing file with the same name.
+Note that the exclamation point is a special UNIX character so if
+it is used on the command line it must be preceded by a backslash to
+force the UNIX shell to accept the character as part of the filename.
+
+The output file will be written to the 'stdout' file stream if a dash
+character ('-') or the string 'stdout' is given as the filename. Similarly,
+'-.gz' or 'stdout.gz' will cause the file to be gzip compressed before
+it is written out to the stdout stream.
+
+Optionally, the name of a template file that is used to define the
+structure of the new file may be specified in parentheses following the
+output file name. The template file may be another FITS file, in which
+case the new file, at the time it is opened, will be an exact copy of
+the template file except that the data structures (images and tables)
+will be filled with zeros. Alternatively, the template file may be an
+ASCII format text file containing directives that define the keywords to be
+created in each HDU of the file. See the 'Extended File Name Syntax'
+ section for a complete description of the template file syntax.
+
+The fits\_create\_diskfile routine is similar to the fits\_create\_file routine
+except that it does not support the extended filename syntax in the input
+file name. This routine simply tries to create the specified file
+on magnetic disk. This routine is mainly for use in cases where the
+filename (or directory path) contains square or curly bracket characters
+> that would confuse the extended filename parser.
+
+
+>3 Close a previously opened FITS file. The first routine simply
+closes the file, whereas the second one also DELETES THE FILE, which
+can be useful in cases where a FITS file has been partially created,
+but then an error occurs which prevents it from being completed.
+> \label{ffclos} \label{ffdelt}
+-
+ int fits_close_file / ffclos (fitsfile *fptr, > int *status)
+
+ int fits_delete_file / ffdelt (fitsfile *fptr, > int *status)
+-
+>4 Return the name, I/O mode (READONLY or READWRITE), and/or the file
+type (e.g. 'file://', 'ftp://') of the opened FITS file. \label{ffflnm}
+> \label{ffflmd} \label{ffurlt}
+-
+ int fits_file_name / ffflnm (fitsfile *fptr, > char *filename, int *status)
+
+ int fits_file_mode / ffflmd (fitsfile *fptr, > int *iomode, int *status)
+
+ int fits_url_type / ffurlt (fitsfile *fptr, > char *urltype, int *status)
+-
+**C. HDU Access Routines
+
+The following functions perform operations on Header-Data Units (HDUs)
+as a whole.
+
+>1 Move to a different HDU in the file. The first routine moves to a
+ specified absolute HDU number (starting with 1 for the primary
+ array) in the FITS file, and the second routine moves a relative
+ number HDUs forward or backward from the current HDU. A null
+ pointer may be given for the hdutype parameter if it's value is not
+ needed. The third routine moves to the (first) HDU which has the
+ specified extension type and EXTNAME and EXTVER keyword values (or
+ HDUNAME and HDUVER keywords). The hdutype parameter may have a
+ value of IMAGE\_HDU, ASCII\_TBL, BINARY\_TBL, or ANY\_HDU where
+ ANY\_HDU means that only the extname and extver values will be used
+ to locate the correct extension. If the input value of extver is 0
+ then the EXTVER keyword is ignored and the first HDU with a
+ matching EXTNAME (or HDUNAME) keyword will be found. If no
+ matching HDU is found in the file then the current HDU will remain
+ unchanged and a status = BAD\_HDU\_NUM will be returned.
+> \label{ffmahd} \label{ffmrhd} \label{ffmnhd}
+-
+ int fits_movabs_hdu / ffmahd
+ (fitsfile *fptr, int hdunum, > int *hdutype, int *status)
+
+ int fits_movrel_hdu / ffmrhd
+ (fitsfile *fptr, int nmove, > int *hdutype, int *status)
+
+ int fits_movnam_hdu / ffmnhd
+ (fitsfile *fptr, int hdutype, char *extname, int extver, > int *status)
+-
+>2 Return the total number of HDUs in the FITS file.
+> The current HDU remains unchanged. \label{ffthdu}
+-
+ int fits_get_num_hdus / ffthdu
+ (fitsfile *fptr, > int *hdunum, int *status)
+-
+>3 Return the number of the current HDU (CHDU) in the FITS file (where
+ the primary array = 1). This function returns the HDU number
+> rather than a status value. \label{ffghdn}
+-
+ int fits_get_hdu_num / ffghdn
+ (fitsfile *fptr, > int *hdunum)
+-
+>4 Return the type of the current HDU in the FITS file. The possible
+> values for hdutype are: IMAGE\_HDU, ASCII\_TBL, or BINARY\_TBL. \label{ffghdt}
+-
+ int fits_get_hdu_type / ffghdt
+ (fitsfile *fptr, > int *hdutype, int *status)
+-
+>5 Copy all or part of the HDUs in the FITS file associated with infptr
+ and append them to the end of the FITS file associated with
+ outfptr. If 'previous' is true (not 0), then any HDUs preceding
+ the current HDU in the input file will be copied to the output
+ file. Similarly, 'current' and 'following' determine whether the
+ current HDU, and/or any following HDUs in the input file will be
+ copied to the output file. Thus, if all 3 parameters are true, then the
+ entire input file will be copied. On exit, the current HDU in
+ the input file will be unchanged, and the last HDU in the output
+> file will be the current HDU. \label{ffcpfl}
+-
+ int fits_copy_file / ffcpfl
+ (fitsfile *infptr, fitsfile *outfptr, int previous, int current,
+ int following, > int *status)
+-
+>6 Copy the current HDU from the FITS file associated with infptr and append it
+ to the end of the FITS file associated with outfptr. Space may be
+> reserved for MOREKEYS additional keywords in the output header. \label{ffcopy}
+-
+ int fits_copy_hdu / ffcopy
+ (fitsfile *infptr, fitsfile *outfptr, int morekeys, > int *status)
+-
+>7 Copy the header (and not the data) from the CHDU associated with infptr
+ to the CHDU associated with outfptr. If the current output HDU
+ is not completely empty, then the CHDU will be closed and a new
+ HDU will be appended to the output file. An empty output data unit
+> will be created with all values initially = 0). \label{ffcphd}
+-
+ int fits_copy_header / ffcphd
+ (fitsfile *infptr, fitsfile *outfptr, > int *status)
+-
+>8 Delete the CHDU in the FITS file. Any following HDUs will be shifted
+ forward in the file, to fill in the gap created by the deleted
+ HDU. In the case of deleting the primary array (the first HDU in
+ the file) then the current primary array will be replace by a null
+ primary array containing the minimum set of required keywords and
+ no data. If there are more extensions in the file following the
+ one that is deleted, then the the CHDU will be redefined to point
+ to the following extension. If there are no following extensions
+ then the CHDU will be redefined to point to the previous HDU. The
+ output hdutype parameter returns the type of the new CHDU. A null
+ pointer may be given for
+> hdutype if the returned value is not needed. \label{ffdhdu}
+-
+ int fits_delete_hdu / ffdhdu
+ (fitsfile *fptr, > int *hdutype, int *status)
+-
+**D. Header Keyword Read/Write Routines
+
+These routines read or write keywords in the Current Header Unit
+(CHU). Wild card characters (*, ?, or \#) may be used when specifying
+the name of the keyword to be read: a '?' will match any single
+character at that position in the keyword name and a '*' will match any
+length (including zero) string of characters. The '\#' character will
+match any consecutive string of decimal digits (0 - 9). When a wild
+card is used the routine will only search for a match from the current
+header position to the end of the header and will not resume the search
+from the top of the header back to the original header position as is
+done when no wildcards are included in the keyword name. The
+fits\_read\_record routine may be used to set the starting position
+when doing wild card searchs. A status value of KEY\_NO\_EXIST is
+returned if the specified keyword to be read is not found in the
+header.
+
+***1. Keyword Reading Routines
+
+>1 Return the number of existing keywords (not counting the
+ END keyword) and the amount of space currently available for more
+ keywords. It returns morekeys = -1 if the header has not yet been
+ closed. Note that CFITSIO will dynamically add space if required
+ when writing new keywords to a header so in practice there is no
+ limit to the number of keywords that can be added to a header. A
+ null pointer may be entered for the morekeys parameter if it's
+> value is not needed. \label{ffghsp}
+-
+ int fits_get_hdrspace / ffghsp
+ (fitsfile *fptr, > int *keysexist, int *morekeys, int *status)
+-
+>2 Return the specified keyword. In the first routine,
+ the datatype parameter specifies the desired returned data type of the
+ keyword value and can have one of the following symbolic constant
+ values: TSTRING, TLOGICAL (== int), TBYTE, TSHORT, TUSHORT, TINT,
+ TUINT, TLONG, TULONG, TFLOAT, TDOUBLE, TCOMPLEX, and TDBLCOMPLEX.
+ Within the context of this routine, TSTRING corresponds to a
+ 'char*' data type, i.e., a pointer to a character array. Data type
+ conversion will be performed for numeric values if the keyword
+ value does not have the same data type. If the value of the keyword
+ is undefined (i.e., the value field is blank) then an error status
+ = VALUE\_UNDEFINED will be returned.
+
+ The second routine returns the keyword value as a character string
+ (a literal copy of what is in the value field) regardless of the
+ intrinsic data type of the keyword. The third routine returns
+ the entire 80-character header record of the keyword.
+
+ If a NULL comment pointer is supplied then the comment string
+> will not be returned. \label{ffgky} \label{ffgkey} \label{ffgcrd}
+-
+ int fits_read_key / ffgky
+ (fitsfile *fptr, int datatype, char *keyname, > DTYPE *value,
+ char *comment, int *status)
+
+ int fits_read_keyword / ffgkey
+ (fitsfile *fptr, char *keyname, > char *value, char *comment,
+ int *status)
+
+ int fits_read_card / ffgcrd
+ (fitsfile *fptr, char *keyname, > char *card, int *status)
+-
+>3 Return the nth header record in the CHU. The first keyword
+ in the header is at keynum = 1; if keynum = 0 then these routines
+ simply reset the internal CFITSIO pointer to the beginning of the header
+ so that subsequent keyword operations will start at the top of the
+ header (e.g., prior to searching for keywords using wild cards in
+ the keyword name). The first routine returns the entire
+ 80-character header record, while the second routine parses the
+ record and returns the name, value, and comment fields as separate
+ character strings. If a NULL comment pointer is given on input,
+ then the comment string will not be
+> returned. \label{ffgrec} \label{ffgkyn}
+-
+ int fits_read_record / ffgrec
+ (fitsfile *fptr, int keynum, > char *card, int *status)
+
+ int fits_read_keyn / ffgkyn
+ (fitsfile *fptr, int keynum, > char *keyname, char *value,
+ char *comment, int *status)
+-
+>4 Return the next keyword whose name matches one of the strings in
+ 'inclist' but does not match any of the strings in 'exclist'.
+ The strings in inclist and exclist may contain wild card characters
+ (*, ?, and \#) as described at the beginning of this section.
+ This routine searches from the current header position to the
+ end of the header, only, and does not continue the search from
+ the top of the header back to the original position. The current
+ header position may be reset with the ffgrec routine. Note
+ that nexc may be set = 0 if there are no keywords to be excluded.
+ This routine returns status = KEY\_NO\_EXIST if a matching
+> keyword is not found. \label{ffgnxk}
+-
+ int fits_find_nextkey / ffgnxk
+ (fitsfile *fptr, char **inclist, int ninc, char **exclist,
+ int nexc, > char *card, int *status)
+-
+>5 Return the physical units string from an existing keyword. This
+ routine uses a local convention, shown in the following example,
+ in which the keyword units are enclosed in square brackets in the
+ beginning of the keyword comment field. A null string is returned
+> if no units are defined for the keyword. \label{ffgunt}
+-
+ VELOCITY= 12.3 / [km/s] orbital speed
+
+ int fits_read_key_unit / ffgunt
+ (fitsfile *fptr, char *keyname, > char *unit, int *status)
+-
+>6 Concatenate the header keywords in the CHDU into a single long
+ string of characters. This provides a convenient way of passing
+ all or part of the header information in a FITS HDU to other subroutines.
+ Each 80-character fixed-length keyword record is appended to the
+ output character string, in order, with no intervening separator or
+ terminating characters. The last header record is terminated with
+ a NULL character. This routine allocates memory for the returned
+ character array, so the calling program must free the memory when
+ finished.
+
+ Selected keywords may be excluded from the returned character string.
+ If the second parameter (nocomments) is TRUE (nonzero) then any
+ COMMENT, HISTORY, or blank keywords in the header will not be copied
+ to the output string.
+
+ The 'exclist' parameter may be used to supply a list of keywords
+ that are to be excluded from the output character string. Wild card
+ characters (*, ?, and \#) may be used in the excluded keyword names.
+ If no additional keywords are to be excluded, then set nexc = 0 and
+> specify NULL for the the **header parameter. \label{ffhdr2str}
+-
+ int fits_hdr2str
+ (fitsfile *fptr, int nocomments, char **exclist, int nexc,
+ > char **header, int *nkeys, int *status)
+-
+
+***2. Keyword Writing Routines
+
+>1 Write a keyword of the appropriate data type into the
+ CHU. The first routine simply appends a new keyword whereas the
+ second routine will update the value and comment fields of the
+ keyword if it already exists, otherwise it appends a new
+ keyword. Note that the address to the value, and not the value
+ itself, must be entered. The datatype parameter specifies the
+ data type of the keyword value with one of the following values:
+ TSTRING, TLOGICAL (== int), TBYTE, TSHORT, TUSHORT, TINT, TUINT,
+ TLONG, TULONG, TFLOAT, TDOUBLE. Within the context of this
+ routine, TSTRING corresponds to a 'char*' data type, i.e., a pointer
+ to a character array. A null pointer may be entered for the
+ comment parameter in which case the keyword comment
+> field will be unmodified or left blank. \label{ffpky} \label{ffuky}
+-
+ int fits_write_key / ffpky
+ (fitsfile *fptr, int datatype, char *keyname, DTYPE *value,
+ char *comment, > int *status)
+
+ int fits_update_key / ffuky
+ (fitsfile *fptr, int datatype, char *keyname, DTYPE *value,
+ char *comment, > int *status)
+-
+>2 Write a keyword with a null or undefined value (i.e., the
+ value field in the keyword is left blank). The first routine
+ simply appends a new keyword whereas the second routine will update
+ the value and comment fields of the keyword if it already exists,
+ otherwise it appends a new keyword. A null pointer may be
+ entered for the comment parameter in which case the keyword
+ comment
+> field will be unmodified or left blank. \label{ffpkyu} \label{ffukyu}
+-
+ int fits_write_key_null / ffpkyu
+ (fitsfile *fptr, char *keyname, char *comment, > int *status)
+
+ int fits_update_key_null / ffukyu
+ (fitsfile *fptr, char *keyname, char *comment, > int *status)
+-
+>3 Write (append) a COMMENT or HISTORY keyword to the CHU. The comment or
+ history string will be continued over multiple keywords if it is longer
+> than 70 characters. \label{ffpcom} \label{ffphis}
+-
+ int fits_write_comment / ffpcom
+ (fitsfile *fptr, char *comment, > int *status)
+
+ int fits_write_history / ffphis
+ (fitsfile *fptr, char *history, > int *status)
+-
+>4 Write the DATE keyword to the CHU. The keyword value will contain
+ the current system date as a character string in 'yyyy-mm-ddThh:mm:ss'
+ format. If a DATE keyword already exists in the header, then this
+ routine will simply update the keyword value with the current date.
+> \label{ffpdat}
+-
+ int fits_write_date / ffpdat
+ (fitsfile *fptr, > int *status)
+-
+>5 Write a user specified keyword record into the CHU. This is
+ a low--level routine which can be used to write any arbitrary
+ record into the header. The record must conform to the all
+> the FITS format requirements. \label{ffprec}
+-
+ int fits_write_record / ffprec
+ (fitsfile *fptr, char *card, > int *status)
+-
+>6 Update an 80-character record in the CHU. If a keyword with the input
+ name already exists, then it is overwritten by the value of card. This
+ could modify the keyword name as well as the value and comment fields.
+ If the keyword doesn't already exist then a new keyword card is appended
+> to the header. \label{ffucrd}
+-
+ int fits_update_card / ffucrd
+ (fitsfile *fptr, char *keyname, char *card, > int *status)
+-
+
+>>7 Modify (overwrite) the comment field of an existing keyword. \label{ffmcom}
+-
+ int fits_modify_comment / ffmcom
+ (fitsfile *fptr, char *keyname, char *comment, > int *status)
+-
+
+>8 Write the physical units string into an existing keyword. This
+ routine uses a local convention, shown in the following example,
+ in which the keyword units are enclosed in square brackets in the
+> beginning of the keyword comment field. \label{ffpunt}
+-
+ VELOCITY= 12.3 / [km/s] orbital speed
+
+ int fits_write_key_unit / ffpunt
+ (fitsfile *fptr, char *keyname, char *unit, > int *status)
+-
+>9 Rename an existing keyword, preserving the current value
+> and comment fields. \label{ffmnam}
+-
+ int fits_modify_name / ffmnam
+ (fitsfile *fptr, char *oldname, char *newname, > int *status)
+-
+>10 Delete a keyword record. The space occupied by
+ the keyword is reclaimed by moving all the following header records up
+ one row in the header. The first routine deletes a keyword at a
+ specified position in the header (the first keyword is at position 1),
+ whereas the second routine deletes a specifically named keyword.
+ Wild card characters may be used when specifying the name of the keyword
+> to be deleted. \label{ffdrec} \label{ffdkey}
+-
+ int fits_delete_record / ffdrec
+ (fitsfile *fptr, int keynum, > int *status)
+
+ int fits_delete_key / ffdkey
+ (fitsfile *fptr, char *keyname, > int *status)
+-
+**E. Primary Array or IMAGE Extension I/O Routines
+
+These routines read or write data values in the primary data array (i.e.,
+the first HDU in a FITS file) or an IMAGE extension. There are also
+routines to get information about the data type and size of the image.
+Users should also read the following chapter on the CFITSIO iterator
+function which provides a more `object oriented' method of reading and
+writing images. The iterator function is a little more complicated to
+use, but the advantages are that it usually takes less code to perform
+the same operation, and the resulting program oftens runs faster because
+the FITS files are read and written using the most efficient block size.
+
+C programmers should note that the ordering of arrays in FITS files, and
+hence in all the CFITSIO calls, is more similar to the dimensionality
+of arrays in Fortran rather than C. For instance if a FITS image has
+NAXIS1 = 100 and NAXIS2 = 50, then a 2-D array just large enough to hold
+the image should be declared as array[50][100] and not as array[100][50].
+
+The `datatype' parameter specifies the data type of the `nulval' and
+`array' pointers and can have one of the following values: TBYTE,
+TSBYTE, TSHORT, TUSHORT, TINT, TUINT, TLONG, TLONGLONG, TULONG, TFLOAT,
+TDOUBLE. Automatic data type conversion is performed if the data type
+of the FITS array (as defined by the BITPIX keyword) differs from that
+specified by 'datatype'. The data values are also automatically scaled
+by the BSCALE and BZERO keyword values as they are being read or written
+in the FITS array.
+
+>1 Get the data type or equivalent data type of the image. The
+ first routine returns the physical data type of the FITS image, as
+ given by the BITPIX keyword, with allowed values of BYTE\_IMG (8),
+ SHORT\_IMG (16), LONG\_IMG (32), FLOAT\_IMG (-32), and DOUBLE\_IMG
+ (-64). The second routine is similar, except that if the image pixel
+ values are scaled, with non-default values for the BZERO and BSCALE
+ keywords, then the routine will return the 'equivalent' data type
+ that is needed to store the scaled values. For example, if BITPIX
+ = 16 and BSCALE = 0.1 then the equivalent data type is FLOAT\_IMG.
+ Similarly if BITPIX = 16, BSCALE = 1, and BZERO = 32768, then the
+ the pixel values span the range of an unsigned short integer and
+> the returned data type will be USHORT\_IMG. \label{ffgidt}
+-
+ int fits_get_img_type / ffgidt
+ (fitsfile *fptr, > int *bitpix, int *status)
+
+ int fits_get_img_equivtype / ffgiet
+ (fitsfile *fptr, > int *bitpix, int *status)
+-
+>2 Get the number of dimensions, and/or the size of
+ each dimension in the image . The number of axes in the image is
+ given by naxis, and the size of each dimension is given by the
+ naxes array (a maximum of maxdim dimensions will be returned).
+> \label{ffgidm} \label{ffgisz} \label{ffgipr}
+-
+ int fits_get_img_dim / ffgidm
+ (fitsfile *fptr, > int *naxis, int *status)
+
+ int fits_get_img_size / ffgisz
+ (fitsfile *fptr, int maxdim, > long *naxes, int *status)
+
+ int fits_get_img_param / ffgipr
+ (fitsfile *fptr, int maxdim, > int *bitpix, int *naxis, long *naxes,
+ int *status)
+-
+>3 Create a new primary array or IMAGE extension with a specified
+ data type and size. If the FITS file is currently empty then a
+ primary array is created, otherwise a new IMAGE extension is
+> appended to the file. \label{ffcrim}
+-
+ int fits_create_img / ffcrim
+ ( fitsfile *fptr, int bitpix, int naxis, long *naxes, > int *status)
+-
+>4 Write a rectangular subimage (or the whole image) to the FITS data
+ array. The fpixel and lpixel arrays give the coordinates of the
+ first (lower left corner) and last (upper right corner) pixels in
+> FITS image to be written to. \label{ffpss}
+-
+ int fits_write_subset / ffpss
+ (fitsfile *fptr, int datatype, long *fpixel, long *lpixel,
+ DTYPE *array, > int *status)
+-
+>5 Write pixels into the FITS data array. 'fpixel' is an array of
+ length NAXIS which gives the coordinate of the starting pixel to be
+ written to, such that fpixel[0] is in the range 1 to NAXIS1,
+ fpixel[1] is in the range 1 to NAXIS2, etc. The first routine
+ simply writes the array of pixels to the FITS file (doing data type
+ conversion if necessary) whereas the second routine will substitute
+ the appropriate FITS null value for any elements which are equal to
+ the input value of nulval (note that this parameter gives the
+ address of the null value, not the null value itself). For integer
+ FITS arrays, the FITS null value is defined by the BLANK keyword (an
+ error is returned if the BLANK keyword doesn't exist). For floating
+ point FITS arrays the special IEEE NaN (Not-a-Number) value will be
+ written into the FITS file. If a null pointer is entered for
+ nulval, then the null value is ignored and this routine behaves
+> the same as fits\_write\_pix. \label{ffppx} \label{ffppxn}
+-
+ int fits_write_pix / ffppx
+ (fitsfile *fptr, int datatype, long *fpixel, long nelements,
+ DTYPE *array, int *status);
+
+ int fits_write_pixnull / ffppxn
+ (fitsfile *fptr, int datatype, long *fpixel, long nelements,
+ DTYPE *array, DTYPE *nulval, > int *status);
+-
+>6 Set FITS data array elements equal to the appropriate null pixel
+ value. For integer FITS arrays, the FITS null value is defined by
+ the BLANK keyword (an error is returned if the BLANK keyword
+ doesn't exist). For floating point FITS arrays the special IEEE NaN
+ (Not-a-Number) value will be written into the FITS file. Note that
+ 'firstelem' is a scalar giving the offset to the first pixel to be
+> written in the equivalent 1-dimensional array of image pixels. \label{ffpprn}
+-
+ int fits_write_null_img / ffpprn
+ (fitsfile *fptr, long firstelem, long nelements, > int *status)
+-
+>7 Read a rectangular subimage (or the whole image) from the FITS
+ data array. The fpixel and lpixel arrays give the coordinates of
+ the first (lower left corner) and last (upper right corner) pixels
+ to be read from the FITS image. Undefined FITS array elements will
+ be returned with a value = *nullval, (note that this parameter
+ gives the address of the null value, not the null value itself)
+ unless nulval = 0 or *nulval = 0, in which case no checks for
+> undefined pixels will be performed. \label{ffgsv}
+-
+ int fits_read_subset / ffgsv
+ (fitsfile *fptr, int datatype, long *fpixel, long *lpixel, long *inc,
+ DTYPE *nulval, > DTYPE *array, int *anynul, int *status)
+-
+>8 Read pixels from the FITS data array. 'fpixel' is the starting
+ pixel location and is an array of length NAXIS such that fpixel[0]
+ is in the range 1 to NAXIS1, fpixel[1] is in the range 1 to NAXIS2,
+ etc. The nelements parameter specifies the number of pixels to
+ read. If fpixel is set to the first pixel, and nelements is set
+ equal to the NAXIS1 value, then this routine would read the first
+ row of the image. Alternatively, if nelements is set equal to
+ NAXIS1 * NAXIS2 then it would read an entire 2D image, or the first
+ plane of a 3-D datacube.
+
+ The first routine will return any undefined pixels in the FITS array
+ equal to the value of *nullval (note that this parameter gives the
+ address of the null value, not the null value itself) unless nulval
+ = 0 or *nulval = 0, in which case no checks for undefined pixels
+ will be performed. The second routine is similar except that any
+ undefined pixels will have the corresponding nullarray element set
+> equal to TRUE (= 1). \label{ffgpxv} \label{ffgpxf}
+-
+ int fits_read_pix / ffgpxv
+ (fitsfile *fptr, int datatype, long *fpixel, long nelements,
+ DTYPE *nulval, > DTYPE *array, int *anynul, int *status)
+
+ int fits_read_pixnull / ffgpxf
+ (fitsfile *fptr, int datatype, long *fpixel, long nelements,
+ > DTYPE *array, char *nullarray, int *anynul, int *status)
+-
+**F. Image Compression
+
+CFITSIO now transparently supports 2 types of image compression:
+
+1) The entire FITS file may be externally compressed with the gzip or
+Unix compress algorithm, producing a *.gz or *.Z file, respectively.
+When reading compressed files of this type, CFITSIO first uncompresses
+the entire file into memory before performing the requested read
+operations. Output files can be directly written in the gzip
+compressed format if the user-specified filename ends with `.gz'. In
+this case, CFITSIO initially writes the uncompressed file in memory and
+then compresses it and writes it to disk when the FITS file is closed,
+thus saving user disk space. Read and write access to these compressed
+FITS files is generally quite fast; the main limitation is that there
+must be enough available memory (or swap space) to hold the entire
+uncompressed FITS file.
+
+2) CFITSIO also supports a newer image compression format in which the
+image is divided into a grid of rectangular tiles, and each tile of
+pixels is individually compressed. The compressed tiles are stored in
+rows of a variable length array column in a FITS binary table, but
+CFITSIO recognizes that the binary table extension contains an image
+and treats it as if it were an IMAGE extension. This tile-compressed
+format is especially well suited for compressing very large images
+because a) the FITS header keywords remain uncompressed for rapid read
+access, and because b) it is possible to extract and uncompress
+sections of the image without having to uncompress the entire image.
+This format is also much more effective in compressing floating point
+images (using a lossy compression algorithm) than simply compressing
+the image using gzip or compress.
+
+A detailed description of this format is available at:
+-
+http://heasarc.gsfc.nasa.gov/docs/software/fitsio/
+ compression/compress_image.html
+-
+
+The N-dimensional FITS image can be divided into any
+desired rectangular grid of compression tiles. By default the tiles
+are chosen to correspond to the rows of the image, each containing
+NAXIS1 pixels. For example, a 800 x 800 x 4 pixel data cube would be
+divided in to 3200 tiles containing 800 pixels each by default.
+Alternatively, this data cube could be divided into 256 tiles that are each
+100 X 100 X 1 pixels in size, or 4 tiles containing 800 x 800 X 1
+pixels, or a single tile containing the entire data cube. Note that
+the image dimensions are not required to be an integer multiple of the
+tile dimensions, so, for example, this data cube could also be divided
+into 250 X 200 pixel tiles, in which case the last tile in each row
+would only contain 50 X 200 pixels.
+
+Currently, 3 image compression algorithms are supported: Rice, GZIP,
+and PLIO. Rice and GZIP are general purpose algorithms that can be
+used to compress almost any image. The PLIO algorithm, on the other
+hand, is more specialized and was developed for use in IRAF to store
+pixel data quality masks. It is designed to only work on images
+containing positive integers with values up to about 2**24. Other
+image compression algorithms may be supported in the future.
+
+The 3 supported image compression algorithms are all 'loss-less' when
+applied to integer FITS images; the pixel values are preserved exactly
+with no loss of information during the compression and uncompression
+process. Floating point FITS images (which have BITPIX = -32 or -64)
+are first quantized into scaled integer pixel values before being
+compressed. This technique produces much higher compression factors
+than simply using GZIP to compress the image, but it also means that
+the original floating value pixel values may not be precisely returned
+when the image is uncompressed. When done properly, this only discards
+the 'noise' from the floating point values without losing any
+significant information. The amount of noise that is discarded can be
+controlled by the 'noise\_bits' compression parameter.
+
+No special action is required to read tile-compressed images because
+all the CFITSIO routines that read normal uncompressed FITS images can
+also read images in the tile-compressed format; CFITSIO essentially
+treats the binary table that contains the compressed tiles as if
+it were an IMAGE extension.
+
+When creating (writing) a new image with CFITSIO, a normal uncompressed
+FITS primary array or IMAGE extension will be written unless the
+tile-compressed format has been specified in 1 of 2 possible ways:
+
+1) At run time, when specifying the name of the output FITS file to be
+created at run time, the user can indicate that images should be
+written in tile-compressed format by enclosing the compression
+parameters in square brackets following the root disk file name. The
+`imcopy' example program that included with the CFITSIO distribution
+can be used for this purpose to compress or uncompress images. Here
+are some examples of the extended file name syntax for specifying
+tile-compressed output images:
+-
+ myfile.fit[compress] - use the default compression algorithm (Rice)
+ and the default tile size (row by row)
+
+ myfile.fit[compress GZIP] - use the specified compression algorithm;
+ myfile.fit[compress Rice] only the first letter of the algorithm
+ myfile.fit[compress PLIO] name is required.
+
+ myfile.fit[compress R 100,100] - use Rice compression and
+ 100 x 100 pixel tile size
+
+ myfile.fit[compress R 100,100;2] - as above, and also use noisebits = 2
+-
+
+2) Before calling the CFITSIO routine to write the image header
+keywords (e.g., fits\_create\_image) the programmer can call the
+routines described below to specify the compression algorithm and the
+tiling pattern that is to be used. There are 3 routines for specifying
+the various compression parameters and 3 corresponding routines to
+return the current values of the parameters:
+\label{ffsetcomp} \label{ffgetcomp}
+-
+ int fits_set_compression_type(fitsfile *fptr, int comptype, int *status)
+ int fits_set_tile_dim(fitsfile *fptr, int ndim, long *tilesize, int *status)
+ int fits_set_noise_bits(fitsfile *fptr, int noisebits, int *status)
+
+ int fits_get_compression_type(fitsfile *fptr, int *comptype, int *status)
+ int fits_get_tile_dim(fitsfile *fptr, int ndim, long *tilesize, int *status)
+ int fits_get_noise_bits(fitsfile *fptr, int *noisebits, int *status)
+-
+3 symbolic constants are defined for use as the value of the
+`comptype' parameter: GZIP\_1, RICE\_1, or PLIO\_1. Entering NULL for
+comptype will turn off the tile-compression and cause normal FITS
+images to be written.
+
+The 'noisebits' parameter is only used when compressing floating point
+images. The default value is 4. Decreasing the value of noisebits
+will improve the overall compression efficiency at the expense of
+losing more information.
+
+A small example program called 'imcopy' is included with CFITSIO that
+can be used to compress (or uncompress) any FITS image. This
+program can be used to experiment with the various compression options
+on existing FITS images as shown in these examples:
+-
+1) imcopy infile.fit 'outfile.fit[compress]'
+
+ This will use the default compression algorithm (Rice) and the
+ default tile size (row by row)
+
+2) imcopy infile.fit 'outfile.fit[compress GZIP]'
+
+ This will use the GZIP compression algorithm and the default
+ tile size (row by row). The allowed compression algorithms are
+ Rice, GZIP, and PLIO. Only the first letter of the algorithm
+ name needs to be specified.
+
+3) imcopy infile.fit 'outfile.fit[compress G 100,100]'
+
+ This will use the GZIP compression algorithm and 100 X 100 pixel
+ tiles.
+
+4) imcopy infile.fit 'outfile.fit[compress R 100,100; 4]'
+
+ This will use the Rice compression algorithm, 100 X 100 pixel
+ tiles, and noise_bits = 4 (assuming the input image has a
+ floating point data type). Decreasing the value of noisebits
+ will improve the overall compression efficiency at the expense
+ of losing more information.
+
+5) imcopy infile.fit outfile.fit
+
+ If the input file is in tile-compressed format, then it will be
+ uncompressed to the output file. Otherwise, it simply copies
+ the input image to the output image.
+
+6) imcopy 'infile.fit[1001:1500,2001:2500]' outfile.fit
+
+ This extracts a 500 X 500 pixel section of the much larger
+ input image (which may be in tile-compressed format). The
+ output is a normal uncompressed FITS image.
+
+7) imcopy 'infile.fit[1001:1500,2001:2500]' outfile.fit.gz
+
+ Same as above, except the output file is externally compressed
+ using the gzip algorithm.
+
+-
+**G. ASCII and Binary Table Routines
+
+These routines perform read and write operations on columns of data in
+FITS ASCII or Binary tables. Note that in the following discussions,
+the first row and column in a table is at position 1 not 0.
+
+Users should also read the following chapter on the CFITSIO iterator
+function which provides a more `object oriented' method of reading and
+writing table columns. The iterator function is a little more
+complicated to use, but the advantages are that it usually takes less
+code to perform the same operation, and the resulting program oftens
+runs faster because the FITS files are read and written using the most
+efficient block size.
+
+***1. Create New Table
+
+>1 Create a new ASCII or bintable table extension. If
+ the FITS file is currently empty then a dummy primary array will be
+ created before appending the table extension to it. The tbltype
+ parameter defines the type of table and can have values of
+ ASCII\_TBL or BINARY\_TBL. The naxis2 parameter gives the initial
+ number of rows to be created in the table, and should normally be
+ set = 0. CFITSIO will automatically increase the size of the table
+ as additional rows are written. A non-zero number of rows may be
+ specified to reserve space for that many rows, even if a fewer
+ number of rows will be written. The tunit and extname parameters
+ are optional and a null pointer may be given if they are not
+ defined. The FITS Standard recommends that only letters, digits,
+ and the underscore character be used in column names (the ttype
+ parameter) with no embedded spaces. Trailing blank characters are
+ not significant. It is recommended that all the column names in a
+ given table be unique within the first 8 characters, and strongly
+ recommended that the names be
+> unique within the first 16 characters. \label{ffcrtb}
+-
+ int fits_create_tbl / ffcrtb
+ (fitsfile *fptr, int tbltype, long naxis2, int tfields, char *ttype[],
+ char *tform[], char *tunit[], char *extname, int *status)
+-
+***2. Column Information Routines
+
+>1 Get the number of rows or columns in the current FITS table.
+ The number of rows is given by the NAXIS2 keyword and the
+ number of columns is given by the TFIELDS keyword in the header
+> of the table. \label{ffgnrw}
+-
+ int fits_get_num_rows / ffgnrw
+ (fitsfile *fptr, > long *nrows, int *status);
+
+ int fits_get_num_cols / ffgncl
+ (fitsfile *fptr, > int *ncols, int *status);
+-
+
+>2 Get the table column number (and name) of the column whose name
+matches an input template name. If casesen = CASESEN then the column
+name match will be case-sensitive, whereas if casesen = CASEINSEN then
+the case will be ignored. As a general rule, the column names should
+be treated as case INsensitive.
+
+The input column name template may be either the exact name of the
+column to be searched for, or it may contain wild card characters (*,
+?, or \#), or it may contain the integer number of the desired column
+(with the first column = 1). The `*' wild card character matches any
+sequence of characters (including zero characters) and the `?'
+character matches any single character. The \# wildcard will match any
+consecutive string of decimal digits (0-9). If more than one column
+name in the table matches the template string, then the first match is
+returned and the status value will be set to COL\_NOT\_UNIQUE as a
+warning that a unique match was not found. To find the other cases
+that match the template, call the routine again leaving the input
+status value equal to COL\_NOT\_UNIQUE and the next matching name will
+then be returned. Repeat this process until a status =
+COL\_NOT\_FOUND is returned.
+
+The FITS Standard recommends that only letters, digits, and the
+underscore character be used in column names (with no embedded
+spaces). Trailing blank characters are not significant. It is
+recommended that all the column names in a given table be unique within
+the first 8 characters, and strongly recommended that the names be
+> unique within the first 16 characters. \label{ffgcno} \label{ffgcnn}
+-
+ int fits_get_colnum / ffgcno
+ (fitsfile *fptr, int casesen, char *templt, > int *colnum,
+ int *status)
+
+ int fits_get_colname / ffgcnn
+ (fitsfile *fptr, int casesen, char *templt, > char *colname,
+ int *colnum, int *status)
+-
+>3 Return the data type, vector repeat value, and the width in bytes
+ of a column in an ASCII or binary table. Allowed values for the
+ data type in ASCII tables are: TSTRING, TSHORT, TLONG, TFLOAT, and
+ TDOUBLE. Binary tables also support these types: TLOGICAL, TBIT,
+ TBYTE, TCOMPLEX and TDBLCOMPLEX. The negative of the data type code
+ value is returned if it is a variable length array column. Note
+ that in the case of a 'J' 32-bit integer binary table column, this
+ routine will return data type = TINT32BIT (which in fact is
+ equivalent to TLONG). With most current C compilers, a value in a
+ 'J' column has the same size as an 'int' variable, and may not be
+ equivalent to a 'long' variable, which is 64-bits long on an
+ increasing number of compilers.
+
+ The 'repeat' parameter returns the vector repeat count on the binary
+ table TFORMn keyword value. (ASCII table columns always have repeat
+ = 1). The 'width' parameter returns the width in bytes of a single
+ column element (e.g., a '10D' binary table column will have width =
+ 8, an ASCII table 'F12.2' column will have width = 12, and a binary
+ table'60A' character string column will have width = 60); Note that
+ this routine supports the local convention for specifying arrays of
+ fixed length strings within a binary table character column using
+ the syntax TFORM = 'rAw' where 'r' is the total number of characters
+ (= the width of the column) and 'w' is the width of a unit string
+ within the column. Thus if the column has TFORM = '60A12' then this
+ means that each row of the table contains 5 12-character substrings
+ within the 60-character field, and thus in this case this routine will
+ return typecode = TSTRING, repeat = 60, and width = 12. The number
+ of substings in any binary table character string field can be
+ calculated by (repeat/width). A null pointer may be given for any of
+ the output parameters that are not needed.
+
+ The second routine, fit\_get\_eqcoltype is similar except that in
+ the case of scaled integer columns it returns the 'equivalent' data
+ type that is needed to store the scaled values, and not necessarily
+ the physical data type of the unscaled values as stored in the FITS
+ table. For example if a '1I' column in a binary table has TSCALn =
+ 1 and TZEROn = 32768, then this column effectively contains unsigned
+ short integer values, and thus the returned value of typecode will
+ be TUSHORT, not TSHORT. Similarly, if a column has TTYPEn = '1I'
+ and TSCALn = 0.12, then the returned typecode
+> will be TFLOAT. \label{ffgtcl}
+-
+ int fits_get_coltype / ffgtcl
+ (fitsfile *fptr, int colnum, > int *typecode, long *repeat,
+ long *width, int *status)
+
+ int fits_get_eqcoltype / ffeqty
+ (fitsfile *fptr, int colnum, > int *typecode, long *repeat,
+ long *width, int *status)
+-
+>4 Return the display width of a column. This is the length
+ of the string that will be returned by the fits\_read\_col routine
+ when reading the column as a formatted string. The display width is
+ determined by the TDISPn keyword, if present, otherwise by the data
+> type of the column. \label{ffgcdw}
+-
+ int fits_get_col_display_width / ffgcdw
+ (fitsfile *fptr, int colnum, > int *dispwidth, int *status)
+-
+
+>5 Return the number of and size of the dimensions of a table column in
+ a binary table. Normally this information is given by the TDIMn keyword,
+ but if this keyword is not present then this routine returns naxis = 1
+> and naxes[0] equal to the repeat count in the TFORM keyword. \label{ffgtdm}
+-
+ int fits_read_tdim / ffgtdm
+ (fitsfile *fptr, int colnum, int maxdim, > int *naxis,
+ long *naxes, int *status)
+-
+>6 Decode the input TDIMn keyword string (e.g. '(100,200)') and return the
+ number of and size of the dimensions of a binary table column. If the input
+ tdimstr character string is null, then this routine returns naxis = 1
+ and naxes[0] equal to the repeat count in the TFORM keyword. This routine
+> is called by fits\_read\_tdim. \label{ffdtdm}
+-
+ int fits_decode_tdim / ffdtdm
+ (fitsfile *fptr, char *tdimstr, int colnum, int maxdim, > int *naxis,
+ long *naxes, int *status)
+-
+>7 Write a TDIMn keyword whose value has the form '(l,m,n...)'
+ where l, m, n... are the dimensions of a multidimension array
+> column in a binary table. \label{ffptdm}
+-
+ int fits_write_tdim / ffptdm
+ (fitsfile *fptr, int colnum, int naxis, long *naxes, > int *status)
+-
+
+***3. Routines to Edit Rows or Columns
+
+>1 Insert or delete rows in an ASCII or binary table. When inserting rows
+ all the rows following row FROW are shifted down by NROWS rows; if
+ FROW = 0 then the blank rows are inserted at the beginning of the
+ table. The first delete routine deletes NROWS consecutive rows
+ starting with row FIRSTROW. The second delete routine takes an
+ input string that lists the rows or row ranges (e.g.,
+ '5-10,12,20-30'), whereas the third delete routine takes an input
+ integer array that specifies each individual row to be deleted. In
+ both latter cases, the input list of rows to delete must be sorted
+ in ascending order. These routines update the NAXIS2 keyword to
+ reflect the new number of rows in the
+> table. \label{ffirow} \label{ffdrow} \label{ffdrws} \label{ffdrrg}
+-
+ int fits_insert_rows / ffirow
+ (fitsfile *fptr, long firstrow, long nrows, > int *status)
+
+ int fits_delete_rows / ffdrow
+ (fitsfile *fptr, long firstrow, long nrows, > int *status)
+
+ int fits_delete_rowrange / ffdrrg
+ (fitsfile *fptr, char *rangelist, > int *status)
+
+ int fits_delete_rowlist / ffdrws
+ (fitsfile *fptr, long *rowlist, long nrows, > int *status)
+-
+>2 Insert or delete column(s) in an ASCII or binary
+ table. When inserting, COLNUM specifies the column number that the
+ (first) new column should occupy in the table. NCOLS specifies how
+ many columns are to be inserted. Any existing columns from this
+ position and higher are shifted over to allow room for the new
+ column(s). The index number on all the following keywords will be
+ incremented or decremented if necessary to reflect the new position
+ of the column(s) in the table: TBCOLn, TFORMn, TTYPEn, TUNITn,
+ TNULLn, TSCALn, TZEROn, TDISPn, TDIMn, TLMINn, TLMAXn, TDMINn,
+ TDMAXn, TCTYPn, TCRPXn, TCRVLn, TCDLTn, TCROTn,
+> and TCUNIn. \label{fficol} \label{fficls} \label{ffdcol}
+-
+ int fits_insert_col / fficol
+ (fitsfile *fptr, int colnum, char *ttype, char *tform,
+ > int *status)
+
+ int fits_insert_cols / fficls
+ (fitsfile *fptr, int colnum, int ncols, char **ttype,
+ char **tform, > int *status)
+
+ int fits_delete_col / ffdcol(fitsfile *fptr, int colnum, > int *status)
+-
+>3 Copy a column from one HDU to another (or to the same HDU). If
+ create\_col = TRUE, then a new column will be inserted in the output
+ table, at position `outcolumn', otherwise the existing output column will
+ be overwritten (in which case it must have a compatible data type).
+ If outcolnum is greater than the number of column in the table, then
+ the new column will be appended to the end of the table.
+ Note that the first column in a table is at colnum = 1.
+ The standard indexed keywords that related to the column (e.g., TDISPn,
+> TUNITn, TCRPXn, TCDLTn, etc.) will also be copied. \label{ffcpcl}
+-
+ int fits_copy_col / ffcpcl
+ (fitsfile *infptr, fitsfile *outfptr, int incolnum, int outcolnum,
+ int create_col, > int *status);
+-
+>4 Modify the vector length of a binary table column (e.g.,
+ change a column from TFORMn = '1E' to '20E'). The vector
+> length may be increased or decreased from the current value. \label{ffmvec}
+-
+ int fits_modify_vector_len / ffmvec
+ (fitsfile *fptr, int colnum, long newveclen, > int *status)
+-
+***4. Read and Write Column Data Routines
+
+The following routines write or read data values in the current ASCII
+or binary table extension. If a write operation extends beyond the
+current size of the table, then the number of rows in the table will
+automatically be increased and the NAXIS2 keyword value will be
+updated. Attempts to read beyond the end of the table will result in
+an error.
+
+Automatic data type conversion is performed for numerical data types
+(only) if the data type of the column (defined by the TFORMn keyword)
+differs from the data type of the calling routine. ASCII and binary
+tables support the following data type values: TSTRING, TBYTE, TSBYTE, TSHORT,
+TUSHORT, TINT, TUINT, TLONG, TLONGLONG, TULONG, TFLOAT, or TDOUBLE.
+Binary tables also support TLOGICAL (internally mapped to the `char'
+data type), TCOMPLEX, and TDBLCOMPLEX.
+
+Note that within the context of these routines, the TSTRING data type
+corresponds to a C 'char**' data type, i.e., a pointer to an array of
+pointers to an array of characters. This is different from the keyword
+reading and writing routines where TSTRING corresponds to a C 'char*'
+data type, i.e., a single pointer to an array of characters. When
+reading strings from a table, the char arrays obviously must have been
+allocated long enough to hold the whole FITS table string.
+
+Numerical data values are automatically scaled by the TSCALn and TZEROn
+keyword values (if they exist).
+
+In the case of binary tables with vector elements, the 'felem'
+parameter defines the starting element (beginning with 1, not 0) within
+the cell (a cell is defined as the intersection of a row and a column
+and may contain a single value or a vector of values). The felem
+parameter is ignored when dealing with ASCII tables. Similarly, in the
+case of binary tables the 'nelements' parameter specifies the total
+number of vector values to be read or written (continuing on subsequent
+rows if required) and not the number of table cells.
+
+>>1 Write elements into an ASCII or binary table column.
+ The first routine simply writes the array of values to the FITS file
+ (doing data type conversion if necessary) whereas the second routine
+ will substitute the appropriate FITS null value for all elements
+ which are equal to the input value of nulval (note that this
+ parameter gives the address of nulval, not the null value
+ itself). For integer columns the FITS null value is defined by the
+ TNULLn keyword (an error is returned if the keyword doesn't exist).
+ For floating point columns the special IEEE NaN (Not-a-Number)
+ value will be written into the FITS file. If a null pointer is
+ entered for nulval, then the null value is ignored and this routine
+ behaves the same as the first routine. The second routine must not
+ be used to write to variable length array columns. The third routine
+ simply writes undefined pixel values to the column.
+ \label{ffpcl} \label{ffpcn} \label{ffpclu}
+-
+ int fits_write_col / ffpcl
+ (fitsfile *fptr, int datatype, int colnum, long firstrow,
+ long firstelem, long nelements, DTYPE *array, > int *status)
+
+ int fits_write_colnull / ffpcn
+ (fitsfile *fptr, int datatype, int colnum, long firstrow,
+ long firstelem, long nelements, DTYPE *array, DTYPE *nulval,
+ > int *status)
+
+ int fits_write_col_null / ffpclu
+ (fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelements, > int *status)
+-
+>2 Read elements from an ASCII or binary table column. The data type
+ parameter specifies the data type of the `nulval' and `array' pointers;
+ Undefined array elements will be returned with a value = *nullval,
+ (note that this parameter gives the address of the null value, not the
+ null value itself) unless nulval = 0 or *nulval = 0, in which case
+ no checking for undefined pixels will be performed. The second
+ routine is similar except that any undefined pixels will have the
+ corresponding nullarray element set equal to TRUE (= 1).
+
+ Any column, regardless of it's intrinsic data type, may be read as a
+ string. It should be noted however that reading a numeric column
+ as a string is 10 - 100 times slower than reading the same column
+ as a number due to the large overhead in constructing the formatted
+ strings. The display format of the returned strings will be
+ determined by the TDISPn keyword, if it exists, otherwise by the
+ data type of the column. The length of the returned strings (not
+ including the null terminating character) can be determined with
+ the fits\_get\_col\_display\_width routine. The following TDISPn
+ display formats are currently supported:
+-
+ Iw.m Integer
+ Ow.m Octal integer
+ Zw.m Hexadecimal integer
+ Fw.d Fixed floating point
+ Ew.d Exponential floating point
+ Dw.d Exponential floating point
+ Gw.d General; uses Fw.d if significance not lost, else Ew.d
+-
+ where w is the width in characters of the displayed values, m is the minimum
+ number of digits displayed, and d is the number of digits to the right of the
+ decimal. The .m field is optional.
+> \label{ffgcv} \label{ffgcf}
+-
+ int fits_read_col / ffgcv
+ (fitsfile *fptr, int datatype, int colnum, long firstrow, long firstelem,
+ long nelements, DTYPE *nulval, DTYPE *array, int *anynul, int *status)
+
+ int fits_read_colnull / ffgcf
+ (fitsfile *fptr, int datatype, int colnum, long firstrow, long firstelem,
+ long nelements, DTYPE *array, char *nullarray, int *anynul, int *status)
+-
+
+***5. Row Selection and Calculator Routines
+
+These routines all parse and evaluate an input string containing a user
+defined arithmetic expression. The first 3 routines select rows in a
+FITS table, based on whether the expression evaluates to true (not
+equal to zero) or false (zero). The other routines evaluate the
+expression and calculate a value for each row of the table. The
+allowed expression syntax is described in the row filter section in the
+`Extended File Name Syntax' chapter of this document. The expression
+may also be written to a text file, and the name of the file, prepended
+with a '@' character may be supplied for the 'expr' parameter (e.g.
+'@filename.txt'). The expression in the file can be arbitrarily
+complex and extend over multiple lines of the file. Lines that begin
+with 2 slash characters ('//') will be ignored and may be used to add
+comments to the file.
+
+>1 Evaluate a boolean expression over the indicated rows, returning an
+> array of flags indicating which rows evaluated to TRUE/FALSE \label{fffrow}
+-
+ int fits_find_rows / fffrow
+ (fitsfile *fptr, char *expr, long firstrow, long nrows,
+ > long *n_good_rows, char *row_status, int *status)
+-
+>>2 Find the first row which satisfies the input boolean expression \label{ffffrw}
+-
+ int fits_find_first_row / ffffrw
+ (fitsfile *fptr, char *expr, > long *rownum, int *status)
+-
+>3 Evaluate an expression on all rows of a table. If the input and output
+files are not the same, copy the TRUE rows to the output file. If the
+>files are the same, delete the FALSE rows (preserve the TRUE rows). \label{ffsrow}
+-
+ int fits_select_rows / ffsrow
+ (fitsfile *infptr, fitsfile *outfptr, char *expr, > int *status )
+-
+>4 Calculate an expression for the indicated rows of a table, returning
+the results, cast as datatype (TSHORT, TDOUBLE, etc), in array. If
+nulval==NULL, UNDEFs will be zeroed out. For vector results, the number
+of elements returned may be less than nelements if nelements is not an
+even multiple of the result dimension. Call fits\_test\_expr to obtain
+>the dimensions of the results. \label{ffcrow}
+-
+ int fits_calc_rows / ffcrow
+ (fitsfile *fptr, int datatype, char *expr, long firstrow,
+ long nelements, void *nulval, > void *array, int *anynul, int *status)
+-
+>5 Evaluate an expression and write the result either to a column (if
+the expression is a function of other columns in the table) or to a
+keyword (if the expression evaluates to a constant and is not a
+function of other columns in the table). In the former case, the
+parName parameter is the name of the column (which may or may not already
+exist) into which to write the results, and parInfo contains an
+optional TFORM keyword value if a new column is being created. If a
+TFORM value is not specified then a default format will be used,
+depending on the expression. If the expression evaluates to a constant,
+then the result will be written to the keyword name given by the
+parName parameter, and the parInfo parameter may be used to supply an
+optional comment for the keyword. If the keyword does not already
+exist, then the name of the keyword must be preceded with a '\#' character,
+otherwise the result will be written to a column with that name.
+> \label{ffcalc}
+-
+ int fits_calculator / ffcalc
+ (fitsfile *infptr, char *expr, fitsfile *outfptr, char *parName,
+ char *parInfo, > int *status)
+-
+>6 This calculator routine is similar to the previous routine, except
+that the expression is only evaluated over the specified
+row ranges. nranges specifies the number of row ranges, and firstrow
+and lastrow give the starting and ending row number of each range.
+> \label{ffcalcrng}
+-
+ int fits_calculator_rng / ffcalc_rng
+ (fitsfile *infptr, char *expr, fitsfile *outfptr, char *parName,
+ char *parInfo, int nranges, long *firstrow, long *lastrow
+ > int *status)
+-
+
+>>7 Evaluate the given expression and return information on the result. \label{fftexp}
+-
+ int fits_test_expr / fftexp
+ (fitsfile *fptr, char *expr, > int *datatype, long *nelem, int *naxis,
+ long *naxes, int *status)
+-
+
+
+**H. Utility Routines
+
+***1. File Checksum Routines
+
+The following routines either compute or validate the checksums for the
+CHDU. The DATASUM keyword is used to store the numerical value of the
+32-bit, 1's complement checksum for the data unit alone. If there is
+no data unit then the value is set to zero. The numerical value is
+stored as an ASCII string of digits, enclosed in quotes, because the
+value may be too large to represent as a 32-bit signed integer. The
+CHECKSUM keyword is used to store the ASCII encoded COMPLEMENT of the
+checksum for the entire HDU. Storing the complement, rather than the
+actual checksum, forces the checksum for the whole HDU to equal zero.
+If the file has been modified since the checksums were computed, then
+the HDU checksum will usually not equal zero. These checksum keyword
+conventions are based on a paper by Rob Seaman published in the
+proceedings of the ADASS IV conference in Baltimore in November 1994
+and a later revision in June 1995. See Appendix B for the definition
+of the parameters used in these routines.
+
+>1 Compute and write the DATASUM and CHECKSUM keyword values for the CHDU
+ into the current header. If the keywords already exist, their values
+ will be updated only if necessary (i.e., if the file
+ has been modified since the original keyword
+> values were computed). \label{ffpcks}
+-
+ int fits_write_chksum / ffpcks
+ (fitsfile *fptr, > int *status)
+-
+>2 Update the CHECKSUM keyword value in the CHDU, assuming that the
+ DATASUM keyword exists and already has the correct value. This routine
+ calculates the new checksum for the current header unit, adds it to the
+ data unit checksum, encodes the value into an ASCII string, and writes
+> the string to the CHECKSUM keyword. \label{ffupck}
+-
+ int fits_update_chksum / ffupck
+ (fitsfile *fptr, > int *status)
+-
+>3 Verify the CHDU by computing the checksums and comparing
+ them with the keywords. The data unit is verified correctly
+ if the computed checksum equals the value of the DATASUM
+ keyword. The checksum for the entire HDU (header plus data unit) is
+ correct if it equals zero. The output DATAOK and HDUOK parameters
+ in this routine are integers which will have a value = 1
+ if the data or HDU is verified correctly, a value = 0
+ if the DATASUM or CHECKSUM keyword is not present, or value = -1
+> if the computed checksum is not correct. \label{ffvcks}
+-
+ int fits_verify_chksum / ffvcks
+ (fitsfile *fptr, > int *dataok, int *hduok, int *status)
+-
+>4 Compute and return the checksum values for the CHDU
+ without creating or modifying the
+ CHECKSUM and DATASUM keywords. This routine is used internally by
+> ffvcks, but may be useful in other situations as well. \label{ffgcks}
+-
+ int fits_get_chksum/ /ffgcks
+ (fitsfile *fptr, > unsigned long *datasum, unsigned long *hdusum,
+ int *status)
+-
+>5 Encode a checksum value
+ into a 16-character string. If complm is non-zero (true) then the 32-bit
+> sum value will be complemented before encoding. \label{ffesum}
+-
+ int fits_encode_chksum / ffesum
+ (unsigned long sum, int complm, > char *ascii);
+-
+>6 Decode a 16-character checksum string into a unsigned long value.
+ If is non-zero (true). then the 32-bit sum value will be complemented
+ after decoding. The checksum value is also returned as the
+> value of the function. \label{ffdsum}
+-
+ unsigned long fits_decode_chksum / ffdsum
+ (char *ascii, int complm, > unsigned long *sum);
+-
+
+***2. Date and Time Utility Routines
+
+The following routines help to construct or parse the FITS date/time
+strings. Starting in the year 2000, the FITS DATE keyword values (and
+the values of other `DATE-' keywords) must have the form 'YYYY-MM-DD'
+(date only) or 'YYYY-MM-DDThh:mm:ss.ddd...' (date and time) where the
+number of decimal places in the seconds value is optional. These times
+are in UTC. The older 'dd/mm/yy' date format may not be used for dates
+after 01 January 2000. See Appendix B for the definition of the
+parameters used in these routines.
+
+>1 Get the current system date. C already provides standard
+ library routines for getting the current date and time,
+ but this routine is provided for compatibility with
+ the Fortran FITSIO library. The returned year has 4 digits
+> (1999, 2000, etc.) \label{ffgsdt}
+-
+ int fits_get_system_date/ffgsdt
+ ( > int *day, int *month, int *year, int *status )
+-
+
+>2 Get the current system date and time string ('YYYY-MM-DDThh:mm:ss').
+The time will be in UTC/GMT if available, as indicated by a returned timeref
+value = 0. If the returned value of timeref = 1 then this indicates that
+it was not possible to convert the local time to UTC, and thus the local
+>time was returned.
+-
+ int fits_get_system_time/ffgstm
+ (> char *datestr, int *timeref, int *status)
+-
+
+>3 Construct a date string from the input date values. If the year
+is between 1900 and 1998, inclusive, then the returned date string will
+have the old FITS format ('dd/mm/yy'), otherwise the date string will
+have the new FITS format ('YYYY-MM-DD'). Use fits\_time2str instead
+> to always return a date string using the new FITS format. \label{ffdt2s}
+-
+ int fits_date2str/ffdt2s
+ (int year, int month, int day, > char *datestr, int *status)
+-
+
+>4 Construct a new-format date + time string ('YYYY-MM-DDThh:mm:ss.ddd...').
+ If the year, month, and day values all = 0 then only the time is encoded
+ with format 'hh:mm:ss.ddd...'. The decimals parameter specifies how many
+ decimal places of fractional seconds to include in the string. If `decimals'
+> is negative, then only the date will be return ('YYYY-MM-DD').
+-
+ int fits_time2str/fftm2s
+ (int year, int month, int day, int hour, int minute, double second,
+ int decimals, > char *datestr, int *status)
+-
+
+>5 Return the date as read from the input string, where the string may be
+in either the old ('dd/mm/yy') or new ('YYYY-MM-DDThh:mm:ss' or
+'YYYY-MM-DD') FITS format. Null pointers may be supplied for any
+> unwanted output date parameters.
+-
+ int fits_str2date/ffs2dt
+ (char *datestr, > int *year, int *month, int *day, int *status)
+-
+
+>6 Return the date and time as read from the input string, where the
+string may be in either the old or new FITS format. The returned hours,
+minutes, and seconds values will be set to zero if the input string
+does not include the time ('dd/mm/yy' or 'YYYY-MM-DD') . Similarly,
+the returned year, month, and date values will be set to zero if the
+date is not included in the input string ('hh:mm:ss.ddd...'). Null
+pointers may be supplied for any unwanted output date and time
+>parameters.
+-
+ int fits_str2time/ffs2tm
+ (char *datestr, > int *year, int *month, int *day, int *hour,
+ int *minute, double *second, int *status)
+-
+
+***3. General Utility Routines
+
+The following utility routines may be useful for certain applications.
+
+>1 Return the revision number of the CFITSIO library.
+ The revision number will be incremented with each new
+> release of CFITSIO. \label{ffvers}
+-
+ float fits_get_version / ffvers ( > float *version)
+-
+>2 Write an 80-character message to the CFITSIO error stack. Application
+ programs should not normally write to the stack, but there may be
+> some situations where this is desirable. \label{ffpmsg}
+-
+ void fits_write_errmsg / ffpmsg (char *err_msg)
+-
+>>3 Convert a character string to uppercase (operates in place). \label{ffupch}
+-
+ void fits_uppercase / ffupch (char *string)
+-
+>4 Compare the input template string against the reference string
+ to see if they match. The template string may contain wildcard
+ characters: '*' will match any sequence of characters (including
+ zero characters) and '\%' will match any single character in the
+ reference string. If casesen = CASESEN = TRUE then the match will be
+ case sensitive, otherwise the case of the letters will be ignored
+ if casesen = CASEINSEN = FALSE. The returned MATCH parameter will be
+ TRUE if the 2 strings match, and EXACT will be TRUE if the match is
+ exact (i.e., if no wildcard characters were used in the match).
+> Both strings must be 68 characters or less in length. \label{ffcmps}
+-
+ void fits_compare_str / ffcmps
+ (char *templt, char *string, int casesen, > int *match, int *exact)
+-
+>5 Split a string containing a list of names (typically file names or column
+ names) into individual name tokens by a sequence of calls to
+ fits\_split\_names. The names in the list must be delimited by a comma
+ and/or spaces. This routine ignores spaces and commas that occur
+ within parentheses, brackets, or curly brackets. It also strips any
+ leading and trailing blanks from the returned name.
+
+ This routine is similar to the ANSI C 'strtok' function:
+
+ The first call to fits\_split\_names has a non-null input string.
+ It finds the first name in the string and terminates it by overwriting
+ the next character of the string with a null terminator and returns a
+ pointer to the name. Each subsequent call, indicated by a NULL value
+ of the input string, returns the next name, searching from just past
+ the end of the previous name. It returns NULL when no further names
+> are found. \label{splitnames}
+-
+ char *fits_split_names(char *namelist)
+-
+ The following example shows how a string would be split into 3 names:
+-
+ myfile[1][bin (x,y)=4], file2.fits file3.fits
+ ^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^ ^^^^^^^^^^
+ 1st name 2nd name 3rd name
+-
+>6 Test that the keyword name contains only legal characters (A-Z,0-9,
+ hyphen, and underscore) or that the keyword record contains only legal
+> printable ASCII characters \label{fftkey} \label{fftrec}
+-
+ int fits_test_keyword / fftkey (char *keyname, > int *status)
+
+ int fits_test_record / fftrec (char *card, > int *status)
+-
+>7 Test whether the current header contains any NULL (ASCII 0) characters.
+ These characters are illegal in the header, but they will go undetected
+ by most of the CFITSIO keyword header routines, because the null is
+ interpreted as the normal end-of-string terminator. This routine returns
+ the position of the first null character in the header, or zero if there
+ are no nulls. For example a returned value of 110 would indicate that
+ the first NULL is located in the 30th character of the second keyword
+ in the header (recall that each header record is 80 characters long).
+ Note that this is one of the few CFITSIO routines in which the returned
+ value is not necessarily equal to the status value).
+> \label{ffnchk}
+-
+ int fits_null_check / ffnchk (char *card, > int *status)
+-
+>8 Parse a header keyword record and return the name of the keyword,
+ and the length of the name.
+ The keyword name normally occupies the first 8 characters of the
+ record, except under the HIERARCH convention where the name can
+> be up to 70 characters in length. \label{ffgknm}
+-
+ int fits_get_keyname / ffgknm
+ (char *card, > char *keyname, int *keylength, int *status)
+-
+>9 Parse a header keyword record, returning the value (as
+ a literal character string) and comment strings. If the keyword has no
+ value (columns 9-10 not equal to '= '), then a null value string is
+ returned and the comment string is set equal to column 9 - 80 of the
+> input string. \label{ffpsvc}
+-
+ int fits_parse_value / ffpsvc
+ (char *card, > char *value, char *comment, int *status)
+-
+>10 Construct an array indexed keyword name (ROOT + nnn).
+ This routine appends the sequence number to the root string to create
+> a keyword name (e.g., 'NAXIS' + 2 = 'NAXIS2') \label{ffkeyn}
+-
+ int fits_make_keyn / ffkeyn
+ (char *keyroot, int value, > char *keyname, int *status)
+-
+>11 Construct a sequence keyword name (n + ROOT).
+ This routine concatenates the sequence number to the front of the
+> root string to create a keyword name (e.g., 1 + 'CTYP' = '1CTYP') \label{ffnkey}
+-
+ int fits_make_nkey / ffnkey
+ (int value, char *keyroot, > char *keyname, int *status)
+-
+>12 Determine the data type of a keyword value string. This routine
+ parses the keyword value string to determine its data type.
+ Returns 'C', 'L', 'I', 'F' or 'X', for character string, logical,
+> integer, floating point, or complex, respectively. \label{ffdtyp}
+-
+ int fits_get_keytype / ffdtyp
+ (char *value, > char *dtype, int *status)
+-
+>13 Return the class of an input header record. The record is classified
+ into one of the following categories (the class values are
+ defined in fitsio.h). Note that this is one of the few CFITSIO
+> routines that does not return a status value. \label{ffgkcl}
+-
+ Class Value Keywords
+ TYP_STRUC_KEY 10 SIMPLE, BITPIX, NAXIS, NAXISn, EXTEND, BLOCKED,
+ GROUPS, PCOUNT, GCOUNT, END
+ XTENSION, TFIELDS, TTYPEn, TBCOLn, TFORMn, THEAP,
+ and the first 4 COMMENT keywords in the primary array
+ that define the FITS format.
+ TYP_CMPRS_KEY 20 The experimental keywords used in the compressed
+ image format ZIMAGE, ZCMPTYPE, ZNAMEn, ZVALn,
+ ZTILEn, ZBITPIX, ZNAXISn, ZSCALE, ZZERO, ZBLANK
+ TYP_SCAL_KEY 30 BSCALE, BZERO, TSCALn, TZEROn
+ TYP_NULL_KEY 40 BLANK, TNULLn
+ TYP_DIM_KEY 50 TDIMn
+ TYP_RANG_KEY 60 TLMINn, TLMAXn, TDMINn, TDMAXn, DATAMIN, DATAMAX
+ TYP_UNIT_KEY 70 BUNIT, TUNITn
+ TYP_DISP_KEY 80 TDISPn
+ TYP_HDUID_KEY 90 EXTNAME, EXTVER, EXTLEVEL, HDUNAME, HDUVER, HDULEVEL
+ TYP_CKSUM_KEY 100 CHECKSUM, DATASUM
+ TYP_WCS_KEY 110 CTYPEn, CUNITn, CRVALn, CRPIXn, CROTAn, CDELTn
+ CDj_is, PVj_ms, LONPOLEs, LATPOLEs
+ TCTYPn, TCTYns, TCUNIn, TCUNns, TCRVLn, TCRVns, TCRPXn,
+ TCRPks, TCDn_k, TCn_ks, TPVn_m, TPn_ms, TCDLTn, TCROTn
+ jCTYPn, jCTYns, jCUNIn, jCUNns, jCRVLn, jCRVns, iCRPXn,
+ iCRPns, jiCDn, jiCDns, jPVn_m, jPn_ms, jCDLTn, jCROTn
+ (i,j,m,n are integers, s is any letter)
+ TYP_REFSYS_KEY 120 EQUINOXs, EPOCH, MJD-OBSs, RADECSYS, RADESYSs
+ TYP_COMM_KEY 130 COMMENT, HISTORY, (blank keyword)
+ TYP_CONT_KEY 140 CONTINUE
+ TYP_USER_KEY 150 all other keywords
+
+ int fits_get_keyclass / ffgkcl (char *card)
+-
+>14 Parse the 'TFORM' binary table column format string.
+ This routine parses the input TFORM character string and returns the
+ integer data type code, the repeat count of the field, and, in the case
+ of character string fields, the length of the unit string. See Appendix
+ B for the allowed values for the returned typecode parameter. A
+> null pointer may be given for any output parameters that are not needed. \label{ffbnfm}
+-
+ int fits_binary_tform / ffbnfm
+ (char *tform, > int *typecode, long *repeat, long *width,
+ int *status)
+-
+>15 Parse the 'TFORM' keyword value that defines the column format in
+ an ASCII table. This routine parses the input TFORM character
+ string and returns the data type code, the width of the column,
+ and (if it is a floating point column) the number of decimal places
+ to the right of the decimal point. The returned data type codes are
+ the same as for the binary table, with the following
+ additional rules: integer columns that are between 1 and 4 characters
+ wide are defined to be short integers (code = TSHORT). Wider integer
+ columns are defined to be regular integers (code = TLONG). Similarly,
+ Fixed decimal point columns (with TFORM = 'Fw.d') are defined to
+ be single precision reals (code = TFLOAT) if w is between 1 and 7 characters
+ wide, inclusive. Wider 'F' columns will return a double precision
+ data code (= TDOUBLE). 'Ew.d' format columns will have datacode = TFLOAT,
+ and 'Dw.d' format columns will have datacode = TDOUBLE. A null
+> pointer may be given for any output parameters that are not needed. \label{ffasfm}
+-
+ int fits_ascii_tform / ffasfm
+ (char *tform, > int *typecode, long *width, int *decimals,
+ int *status)
+-
+>16 Calculate the starting column positions and total ASCII table width
+ based on the input array of ASCII table TFORM values. The SPACE input
+ parameter defines how many blank spaces to leave between each column
+ (it is recommended to have one space between columns for better human
+> readability). \label{ffgabc}
+-
+ int fits_get_tbcol / ffgabc
+ (int tfields, char **tform, int space, > long *rowlen,
+ long *tbcol, int *status)
+-
+>17 Parse a template header record and return a formatted 80-character string
+ suitable for appending to (or deleting from) a FITS header file.
+ This routine is useful for parsing lines from an ASCII template file
+ and reformatting them into legal FITS header records. The formatted
+ string may then be passed to the fits\_write\_record, ffmcrd, or
+ fits\_delete\_key routines
+> to append or modify a FITS header record. \label{ffgthd}
+-
+ int fits_parse_template / ffgthd
+ (char *templt, > char *card, int *keytype, int *status)
+-
+ The input templt character string generally should contain 3 tokens:
+ (1) the KEYNAME, (2) the VALUE, and (3) the COMMENT string. The
+ TEMPLATE string must adhere to the following format:
+
+>- The KEYNAME token must begin in columns 1-8 and be a maximum of 8
+ characters long. A legal FITS keyword name may only
+ contain the characters A-Z, 0-9, and '-' (minus sign) and
+ underscore. This routine will automatically convert any lowercase
+ characters to uppercase in the output string. If the first 8 characters
+ of the template line are
+ blank then the remainder of the line is considered to be a FITS comment
+> (with a blank keyword name).
+
+>- The VALUE token must be separated from the KEYNAME token by one or more
+ spaces and/or an '=' character. The data type of the VALUE token
+ (numeric, logical, or character string) is automatically determined
+ and the output CARD string is formatted accordingly. The value
+ token may be forced to be interpreted as a string (e.g. if it is a
+> string of numeric digits) by enclosing it in single quotes.
+
+>- The COMMENT token is optional, but if present must be separated from
+> the VALUE token by at least one blank space and a '/' character.
+
+>- One exception to the above rules is that if the first non-blank
+ character in the first 8 characters of the template string is a
+ minus sign ('-') followed
+ by a single token, or a single token followed by an equal sign,
+ then it is interpreted as the name of a keyword which is to be
+> deleted from the FITS header.
+
+>- The second exception is that if the template string starts with
+ a minus sign and is followed by 2 tokens (without an equals sign between
+ them) then the second token
+ is interpreted as the new name for the keyword specified by
+ first token. In this case the old keyword name (first token)
+ is returned in characters 1-8 of the returned CARD string, and
+ the new keyword name (the second token) is returned in characters
+ 41-48 of the returned CARD string. These old and new names
+ may then be passed to the ffmnam routine which will change
+> the keyword name.
+
+ The keytype output parameter indicates how the returned CARD string
+ should be interpreted:
+-
+ keytype interpretation
+ ------- -------------------------------------------------
+ -2 Rename the keyword with name = the first 8 characters of CARD
+ to the new name given in characters 41 - 48 of CARD.
+
+ -1 delete the keyword with this name from the FITS header.
+
+ 0 append the CARD string to the FITS header if the
+ keyword does not already exist, otherwise update
+ the keyword value and/or comment field if is already exists.
+
+ 1 This is a HISTORY or COMMENT keyword; append it to the header
+
+ 2 END record; do not explicitly write it to the FITS file.
+-
+ EXAMPLES: The following lines illustrate valid input template strings:
+-
+ INTVAL 7 / This is an integer keyword
+ RVAL 34.6 / This is a floating point keyword
+ EVAL=-12.45E-03 / This is a floating point keyword in exponential notation
+ lval F / This is a boolean keyword
+ This is a comment keyword with a blank keyword name
+ SVAL1 = 'Hello world' / this is a string keyword
+ SVAL2 '123.5' this is also a string keyword
+ sval3 123+ / this is also a string keyword with the value '123+ '
+ # the following template line deletes the DATE keyword
+ - DATE
+ # the following template line modifies the NAME keyword to OBJECT
+ - NAME OBJECT
+-
+>18 Parse the input string containing a list of rows or row ranges, and
+ return integer arrays containing the first and last row in each
+ range. For example, if rowlist = "3-5, 6, 8-9" then it will
+ return numranges = 3, rangemin = 3, 6, 8 and rangemax = 5, 6, 9.
+ At most, 'maxranges' number of ranges will be returned. 'maxrows'
+ is the maximum number of rows in the table; any rows or ranges
+ larger than this will be ignored. The rows must be specified in
+ increasing order, and the ranges must not overlap. A minus sign
+ may be use to specify all the rows to the upper or lower bound, so
+ "50-" means all the rows from 50 to the end of the table, and "-"
+ means all the rows in the table, from 1 - maxrows.
+> \label{ffrwrg}
+-
+ int fits_parse_range / ffrwrg(char *rowlist, long maxrows, int maxranges, >
+ int *numranges, long *rangemin, long *rangemax, int *status)
+-
+>19 Check that the Header fill bytes (if any) are all blank. These are the bytes
+ that may follow END keyword and before the beginning of data unit,
+ or the end of the HDU if there is no data unit.
+> \label{ffchfl}
+-
+ int ffchfl(fitsfile *fptr, > int *status)
+-
+>20 Check that the Data fill bytes (if any) are all zero (for IMAGE or
+ BINARY Table HDU) or all blanks (for ASCII table HDU). These file
+ bytes may be located after the last valid data byte in the HDU and
+ before the physical end of the HDU.
+> \label{ffcdfl}
+-
+ int ffcdfl(fitsfile *fptr, > int *status)
+-
+
+*VII. The CFITSIO Iterator Function
+
+The fits\_iterate\_data function in CFITSIO provides a unique method of
+executing an arbitrary user-supplied `work' function that operates on
+rows of data in FITS tables or on pixels in FITS images. Rather than
+explicitly reading and writing the FITS images or columns of data, one
+instead calls the CFITSIO iterator routine, passing to it the name of
+the user's work function that is to be executed along with a list of
+all the table columns or image arrays that are to be passed to the work
+function. The CFITSIO iterator function then does all the work of
+allocating memory for the arrays, reading the input data from the FITS
+file, passing them to the work function, and then writing any output
+data back to the FITS file after the work function exits. Because
+it is often more efficient to process only a subset of the total table
+rows at one time, the iterator function can determine the optimum
+amount of data to pass in each iteration and repeatly call the work
+function until the entire table been processed.
+
+For many applications this single CFITSIO iterator function can
+effectively replace all the other CFITSIO routines for reading or
+writing data in FITS images or tables. Using the iterator has several
+important advantages over the traditional method of reading and writing
+FITS data files:
+
+\begin{itemize}
+\item
+It cleanly separates the data I/O from the routine that operates on
+the data. This leads to a more modular and `object oriented'
+programming style.
+
+\item
+It simplifies the application program by eliminating the need to allocate
+memory for the data arrays and eliminates most of the calls to the CFITSIO
+routines that explicitly read and write the data.
+
+\item
+It ensures that the data are processed as efficiently as possible.
+This is especially important when processing tabular data since
+the iterator function will calculate the most efficient number
+of rows in the table to be passed at one time to the user's work
+function on each iteration.
+
+\item
+Makes it possible for larger projects to develop a library of work
+functions that all have a uniform calling sequence and are all
+independent of the details of the FITS file format.
+
+\end{itemize}
+
+There are basically 2 steps in using the CFITSIO iterator function.
+The first step is to design the work function itself which must have a
+prescribed set of input parameters. One of these parameters is a
+structure containing pointers to the arrays of data; the work function
+can perform any desired operations on these arrays and does not need to
+worry about how the input data were read from the file or how the
+output data get written back to the file.
+
+The second step is to design the driver routine that opens all the
+necessary FITS files and initializes the input parameters to the
+iterator function. The driver program calls the CFITSIO iterator
+function which then reads the data and passes it to the user's work
+function.
+
+The following 2 sections describe these steps in more detail. There
+are also several example programs included with the CFITSIO
+distribution which illustrate how to use the iterator function.
+
+**A The Iterator Work Function
+
+The user-supplied iterator work function must have the following set of
+input parameters (the function can be given any desired name):
+
+-
+ int user_fn( long totaln, long offset, long firstn, long nvalues,
+ int narrays, iteratorCol *data, void *userPointer )
+-
+
+\begin{itemize}
+
+\item
+ totaln -- the total number of table rows or image pixels
+ that will be passed to the work function
+ during 1 or more iterations.
+
+\item
+ offset -- the offset applied to the first table row or image
+ pixel to be passed to the work function. In other
+ words, this is the number of rows or pixels that
+ are skipped over before starting the iterations. If
+ offset = 0, then all the table rows or image pixels
+ will be passed to the work function.
+
+\item
+ firstn -- the number of the first table row or image pixel
+ (starting with 1) that is being passed in this
+ particular call to the work function.
+
+\item
+ nvalues -- the number of table rows or image pixels that are
+ being passed in this particular call to the work
+ function. nvalues will always be less than or
+ equal to totaln and will have the same value on
+ each iteration, except possibly on the last
+ call which may have a smaller value.
+
+\item
+ narrays -- the number of arrays of data that are being passed
+ to the work function. There is one array for each
+ image or table column.
+
+\item
+ *data -- array of structures, one for each
+ column or image. Each structure contains a pointer
+ to the array of data as well as other descriptive
+ parameters about that array.
+
+\item
+ *userPointer -- a user supplied pointer that can be used
+ to pass ancillary information from the driver function
+ to the work function.
+ This pointer is passed to the CFITSIO iterator function
+ which then passes it on to the
+ work function without any modification.
+ It may point to a single number, to an array of values,
+ to a structure containing an arbitrary set of parameters
+ of different types,
+ or it may be a null pointer if it is not needed.
+ The work function must cast this pointer to the
+ appropriate data type before using it it.
+\end{itemize}
+
+The totaln, offset, narrays, data, and userPointer parameters are
+guaranteed to have the same value on each iteration. Only firstn,
+nvalues, and the arrays of data pointed to by the data structures may
+change on each iterative call to the work function.
+
+Note that the iterator treats an image as a long 1-D array of pixels
+regardless of it's intrinsic dimensionality. The total number of
+pixels is just the product of the size of each dimension, and the order
+of the pixels is the same as the order that they are stored in the FITS
+file. If the work function needs to know the number and size of the
+image dimensions then these parameters can be passed via the
+userPointer structure.
+
+The iteratorCol structure is currently defined as follows:
+-
+typedef struct /* structure for the iterator function column information */
+{
+ /* structure elements required as input to fits_iterate_data: */
+
+ fitsfile *fptr; /* pointer to the HDU containing the column or image */
+ int colnum; /* column number in the table; ignored for images */
+ char colname[70]; /* name (TTYPEn) of the column; null for images */
+ int datatype; /* output data type (converted if necessary) */
+ int iotype; /* type: InputCol, InputOutputCol, or OutputCol */
+
+ /* output structure elements that may be useful for the work function: */
+
+ void *array; /* pointer to the array (and the null value) */
+ long repeat; /* binary table vector repeat value; set */
+ /* equal to 1 for images */
+ long tlmin; /* legal minimum data value, if any */
+ long tlmax; /* legal maximum data value, if any */
+ char unit[70]; /* physical unit string (BUNIT or TUNITn) */
+ char tdisp[70]; /* suggested display format; null if none */
+
+} iteratorCol;
+-
+
+Instead of directly reading or writing the elements in this structure,
+it is recommended that programmers use the access functions that are
+provided for this purpose.
+
+The first five elements in this structure must be initially defined by
+the driver routine before calling the iterator routine. The CFITSIO
+iterator routine uses this information to determine what column or
+array to pass to the work function, and whether the array is to be
+input to the work function, output from the work function, or both.
+The CFITSIO iterator function fills in the values of the remaining
+structure elements before passing it to the work function.
+
+The array structure element is a pointer to the actual data array and
+it must be cast to the correct data type before it is used. The
+`repeat' structure element give the number of data values in each row
+of the table, so that the total number of data values in the array is
+given by repeat * nvalues. In the case of image arrays and ASCII
+tables, repeat will always be equal to 1. When the data type is a
+character string, the array pointer is actually a pointer to an array
+of string pointers (i.e., char **array). The other output structure
+elements are provided for convenience in case that information is
+needed within the work function. Any other information may be passed
+from the driver routine to the work function via the userPointer
+parameter.
+
+Upon completion, the work routine must return an integer status value,
+with 0 indicating success and any other value indicating an error which
+will cause the iterator function to immediately exit at that point. Return status
+values in the range 1 -- 1000 should be avoided since these are
+reserved for use by CFITSIO. A return status value of -1 may be used to
+force the CFITSIO iterator function to stop at that point and return
+control to the driver routine after writing any output arrays to the
+FITS file. CFITSIO does not considered this to be an error condition,
+so any further processing by the application program will continue normally.
+
+**B The Iterator Driver Function
+
+The iterator driver function must open the necessary FITS files and
+position them to the correct HDU. It must also initialize the following
+parameters in the iteratorCol structure (defined above) for each
+column or image before calling the CFITSIO iterator function.
+Several `constructor' routines are provided in CFITSIO for this
+purpose.
+
+\begin{itemize}
+\item
+ *fptr -- The fitsfile pointer to the table or image.
+\item
+colnum -- the number of the column in the table. This value is ignored
+ in the case of images. If colnum equals 0, then the column name
+ will be used to identify the column to be passed to the
+ work function.
+
+\item
+colname -- the name (TTYPEn keyword) of the column. This is
+ only required if colnum = 0 and is ignored for images.
+\item
+datatype -- The desired data type of the array to be passed to the
+ work function. For numerical data the data type does
+ not need to be the same as the actual data type in the
+ FITS file, in which case CFITSIO will do the conversion.
+ Allowed values are: TSTRING, TLOGICAL, TBYTE, TSBYTE, TSHORT, TUSHORT,
+ TINT, TLONG, TULONG, TFLOAT, TDOUBLE. If the input
+ value of data type equals 0, then the existing
+ data type of the column or image will be used without
+ any conversion.
+
+\item
+iotype -- defines whether the data array is to be input to the
+ work function (i.e, read from the FITS file), or output
+ from the work function (i.e., written to the FITS file) or
+ both. Allowed values are InputCol, OutputCol, or InputOutputCol.
+ Variable-length array columns are supported as InputCol or
+ InputOutputCol types, but may not be used for an OutputCol type.
+\end{itemize}
+
+After the driver routine has initialized all these parameters, it
+can then call the CFITSIO iterator function:
+
+-
+ int fits_iterate_data(int narrays, iteratorCol *data, long offset,
+ long nPerLoop, int (*workFn)( ), void *userPointer, int *status);
+-
+
+\begin{itemize}
+\item
+
+ narrays -- the number of columns or images that are to be passed
+ to the work function.
+\item
+ *data -- pointer to array of structures containing information
+ about each column or image.
+
+\item
+ offset -- if positive, this number of rows at the
+ beginning of the table (or pixels in the image)
+ will be skipped and will not be passed to the work
+ function.
+
+\item
+ nPerLoop - specifies the number of table rows (or number of
+ image pixels) that are to be passed to the work
+ function on each iteration. If nPerLoop = 0
+ then CFITSIO will calculate the optimum number
+ for greatest efficiency.
+ If nPerLoop is negative, then all the rows
+ or pixels will be passed at one time, and the work
+ function will only be called once. If any variable
+ length arrays are being processed, then the nPerLoop
+ value is ignored, and the iterator will always process
+ one row of the table at a time.
+
+\item
+ *workFn - the name (actually the address) of the work function
+ that is to be called by fits\_iterate\_data.
+
+\item
+ *userPointer - this is a user supplied pointer that can be used
+ to pass ancillary information from the driver routine
+ to the work function. It may point to a single number,
+ an array, or to a structure containing an arbitrary set
+ of parameters.
+
+\item
+ *status - The CFITSIO error status. Should = 0 on input;
+ a non-zero output value indicates an error.
+\end{itemize}
+
+When fits\_iterate\_data is called it first allocates memory to hold
+all the requested columns of data or image pixel arrays. It then reads
+the input data from the FITS tables or images into the arrays then
+passes the structure with pointers to these data arrays to the work
+function. After the work function returns, the iterator function
+writes any output columns of data or images back to the FITS files. It
+then repeats this process for any remaining sets of rows or image
+pixels until it has processed the entire table or image or until the
+work function returns a non-zero status value. The iterator then frees
+the memory that it initially allocated and returns control to the
+driver routine that called it.
+
+**C. Guidelines for Using the Iterator Function
+
+The totaln, offset, firstn, and nvalues parameters that are passed to
+the work function are useful for determining how much of the data has
+been processed and how much remains left to do. On the very first call
+to the work function firstn will be equal to offset + 1; the work
+function may need to perform various initialization tasks before
+starting to process the data. Similarly, firstn + nvalues - 1 will be
+equal to totaln on the last iteration, at which point the work function
+may need to perform some clean up operations before exiting for the
+last time. The work function can also force an early termination of
+the iterations by returning a status value = -1.
+
+The narrays and iteratorCol.datatype arguments allow the work function
+to double check that the number of input arrays and their data types
+have the expected values. The iteratorCol.fptr and iteratorCol.colnum
+structure elements can be used if the work function needs to read or
+write the values of other keywords in the FITS file associated with
+the array. This should generally only be done during the
+initialization step or during the clean up step after the last set of
+data has been processed. Extra FITS file I/O during the main
+processing loop of the work function can seriously degrade the speed of
+the program.
+
+If variable-length array columns are being processed, then the iterator
+will operate on one row of the table at a time. In this case the
+the repeat element in the interatorCol structure will be set equal to
+the number of elements in the current row that is being processed.
+
+One important feature of the iterator is that the first element in each
+array that is passed to the work function gives the value that is used
+to represent null or undefined values in the array. The real data then
+begins with the second element of the array (i.e., array[1], not
+array[0]). If the first array element is equal to zero, then this
+indicates that all the array elements have defined values and there are
+no undefined values. If array[0] is not equal to zero, then this
+indicates that some of the data values are undefined and this value
+(array[0]) is used to represent them. In the case of output arrays
+(i.e., those arrays that will be written back to the FITS file by the
+iterator function after the work function exits) the work function must
+set the first array element to the desired null value if necessary,
+otherwise the first element should be set to zero to indicate that
+there are no null values in the output array. CFITSIO defines 2
+values, FLOATNULLVALUE and DOUBLENULLVALUE, that can be used as default
+null values for float and double data types, respectively. In the case
+of character string data types, a null string is always used to
+represent undefined strings.
+
+In some applications it may be necessary to recursively call the iterator
+function. An example of this is given by one of the example programs
+that is distributed with CFITSIO: it first calls a work function that
+writes out a 2D histogram image. That work function in turn calls
+another work function that reads the `X' and `Y' columns in a table to
+calculate the value of each 2D histogram image pixel. Graphically, the
+program structure can be described as:
+-
+ driver --> iterator --> work1_fn --> iterator --> work2_fn
+-
+
+Finally, it should be noted that the table columns or image arrays that
+are passed to the work function do not all have to come from the same
+FITS file and instead may come from any combination of sources as long
+as they have the same length. The length of the first table column or
+image array is used by the iterator if they do not all have the same
+length.
+
+**D. Complete List of Iterator Routines
+
+All of the iterator routines are listed below. Most of these routines
+do not have a corresponding short function name.
+
+>1 Iterator `constructor' functions that set
+ the value of elements in the iteratorCol structure
+ that define the columns or arrays. These set the fitsfile
+ pointer, column name, column number, datatype, and iotype,
+ respectively. The last 2 routines allow all the parameters
+ to be set with one function call (one supplies the column
+> name, the other the column number). \label{ffiterset}
+
+-
+ int fits_iter_set_file(iteratorCol *col, fitsfile *fptr);
+
+ int fits_iter_set_colname(iteratorCol *col, char *colname);
+
+ int fits_iter_set_colnum(iteratorCol *col, int colnum);
+
+ int fits_iter_set_datatype(iteratorCol *col, int datatype);
+
+ int fits_iter_set_iotype(iteratorCol *col, int iotype);
+
+ int fits_iter_set_by_name(iteratorCol *col, fitsfile *fptr,
+ char *colname, int datatype, int iotype);
+
+ int fits_iter_set_by_num(iteratorCol *col, fitsfile *fptr,
+ int colnum, int datatype, int iotype);
+-
+>2 Iterator `accessor' functions that return the value of the
+ element in the iteratorCol structure
+> that describes a particular data column or array \label{ffiterget}
+-
+ fitsfile * fits_iter_get_file(iteratorCol *col);
+
+ char * fits_iter_get_colname(iteratorCol *col);
+
+ int fits_iter_get_colnum(iteratorCol *col);
+
+ int fits_iter_get_datatype(iteratorCol *col);
+
+ int fits_iter_get_iotype(iteratorCol *col);
+
+ void * fits_iter_get_array(iteratorCol *col);
+
+ long fits_iter_get_tlmin(iteratorCol *col);
+
+ long fits_iter_get_tlmax(iteratorCol *col);
+
+ long fits_iter_get_repeat(iteratorCol *col);
+
+ char * fits_iter_get_tunit(iteratorCol *col);
+
+ char * fits_iter_get_tdisp(iteratorCol *col);
+-
+>>3 The CFITSIO iterator function \label{ffiter}
+-
+ int fits_iterate_data(int narrays, iteratorCol *data, long offset,
+ long nPerLoop,
+ int (*workFn)( long totaln, long offset, long firstn,
+ long nvalues, int narrays, iteratorCol *data,
+ void *userPointer),
+ void *userPointer,
+ int *status);
+-
+
+*IX. Celestial Coordinate System Routines
+
+The FITS community has adopted a set of keyword conventions that define
+the transformations needed to convert between pixel locations in an
+image and the corresponding celestial coordinates on the sky, or more
+generally, that define world coordinates that are to be associated with
+any pixel location in an n-dimensional FITS array. CFITSIO is distributed
+with a couple of self-contained World Coordinate System (WCS) routines,
+however, these routines DO NOT support all the latest WCS conventions,
+so it is STRONGLY RECOMMENDED that software developers use a more robust
+external WCS library. Several recommended libraries are:
+
+-
+ WCSLIB - supported by Mark Calabretta
+ WCSTools - supported by Doug Mink
+ AST library - developed by the U.K. Starlink project
+-
+
+More information about the WCS keyword conventions and links to all of
+these WCS libraries can be found on the FITS Support Office web site at
+http://fits.gsfc.nasa.gov under the WCS link.
+
+The functions provided in these external WCS libraries will need
+access to the WCS information contained in the FITS file headers.
+One convenient way to pass this information to the extermal library is
+to use the fits\_hdr2str routine in CFITSIO (defined below) to copy the
+header keywords into one long string, and then pass this string to an
+interface routine in the external library that will extract
+the necessary WCS information (e.g., see the astFitsChan and astPutCards
+routines in the Starlink AST library).
+
+>1 Concatenate the header keywords in the CHDU into a single long
+ string of characters. Each 80-character fixed-length keyword
+ record is appended to the output character string, in order, with
+ no intervening separator or terminating characters. The last header
+ record is terminated with a NULL character. This routine allocates
+ memory for the returned character array, so the calling program must
+ free the memory when finished.
+
+ Selected keywords may be excluded from the returned character string.
+ If the second parameter (nocomments) is TRUE (nonzero) then any
+ COMMENT, HISTORY, or blank keywords in the header will not be copied
+ to the output string.
+
+ The 'exclist' parameter may be used to supply a list of keywords
+ that are to be excluded from the output character string. Wild card
+ characters (*, ?, and \#) may be used in the excluded keyword names.
+ If no additional keywords are to be excluded, then set nexc = 0 and
+> specify NULL for the the **header parameter. \label{hdr2str}
+-
+ int fits_hdr2str
+ (fitsfile *fptr, int nocomments, char **exclist, int nexc,
+ > char **header, int *nkeys, int *status)
+-
+
+**A. Self-contained WCS Routines
+
+The following routines DO NOT support the more recent WCS conventions
+that have been approved as part of the FITS standard. Consequently,
+the following routines ARE NOW DEPRECATED. It is STRONGLY RECOMMENDED
+that software developers not use these routines, and instead use an
+external WCS library, as described in the previous section.
+
+These routines are included mainly for backward compatibility with
+existing software. They support the following standard map
+projections: -SIN, -TAN, -ARC, -NCP, -GLS, -MER, and -AIT (these are the
+legal values for the coordtype parameter). These routines are based
+on similar functions in Classic AIPS. All the angular quantities are
+given in units of degrees.
+
+>1 Get the values of the basic set of standard FITS celestial coordinate
+ system keywords from the header of a FITS image (i.e., the primary
+ array or an IMAGE extension). These values may then be passed to
+ the fits\_pix\_to\_world and fits\_world\_to\_pix routines that
+ perform the coordinate transformations. If any or all of the WCS
+ keywords are not present, then default values will be returned. If
+ the first coordinate axis is the declination-like coordinate, then
+ this routine will swap them so that the longitudinal-like coordinate
+ is returned as the first axis.
+
+ If the file uses the newer 'CDj\_i' WCS transformation matrix
+ keywords instead of old style 'CDELTn' and 'CROTA2' keywords, then
+ this routine will calculate and return the values of the equivalent
+ old-style keywords. Note that the conversion from the new-style
+ keywords to the old-style values is sometimes only an
+ approximation, so if the approximation is larger than an internally
+ defined threshold level, then CFITSIO will still return the
+ approximate WCS keyword values, but will also return with status =
+ APPROX\_WCS\_KEY, to warn the calling program that approximations
+ have been made. It is then up to the calling program to decide
+ whether the approximations are sufficiently accurate for the
+ particular application, or whether more precise WCS transformations
+> must be performed using new-style WCS keywords directly. \label{ffgics}
+-
+ int fits_read_img_coord / ffgics
+ (fitsfile *fptr, > double *xrefval, double *yrefval,
+ double *xrefpix, double *yrefpix, double *xinc, double *yinc,
+ double *rot, char *coordtype, int *status)
+-
+>2 Get the values of the standard FITS celestial coordinate system
+ keywords from the header of a FITS table where the X and Y (or RA
+ and DEC) coordinates are stored in 2 separate columns of the table
+ (as in the Event List table format that is often used by high energy
+ astrophysics missions). These values may then be passed to the
+ fits\_pix\_to\_world and fits\_world\_to\_pix routines that perform
+> the coordinate transformations. \label{ffgtcs}
+-
+ int fits_read_tbl_coord / ffgtcs
+ (fitsfile *fptr, int xcol, int ycol, > double *xrefval,
+ double *yrefval, double *xrefpix, double *yrefpix, double *xinc,
+ double *yinc, double *rot, char *coordtype, int *status)
+-
+>3 Calculate the celestial coordinate corresponding to the input
+> X and Y pixel location in the image. \label{ffwldp}
+-
+ int fits_pix_to_world / ffwldp
+ (double xpix, double ypix, double xrefval, double yrefval,
+ double xrefpix, double yrefpix, double xinc, double yinc,
+ double rot, char *coordtype, > double *xpos, double *ypos,
+ int *status)
+-
+>4 Calculate the X and Y pixel location corresponding to the input
+> celestial coordinate in the image. \label{ffxypx}
+-
+ int fits_world_to_pix / ffxypx
+ (double xpos, double ypos, double xrefval, double yrefval,
+ double xrefpix, double yrefpix, double xinc, double yinc,
+ double rot, char *coordtype, > double *xpix, double *ypix,
+ int *status)
+-
+
+
+*VIII Hierarchical Grouping Routines
+
+These functions allow for the creation and manipulation of FITS HDU
+Groups, as defined in "A Hierarchical Grouping Convention for FITS" by
+Jennings, Pence, Folk and Schlesinger ( http:
+//adfwww.gsfc.nasa.gov/other/convert/group.html ). A group is a
+collection of HDUs whose association is defined by a {\it grouping
+table}. HDUs which are part of a group are referred to as {\it member
+HDUs} or simply as {\it members}. Grouping table member HDUs may
+themselves be grouping tables, thus allowing for the construction of
+open-ended hierarchies of HDUs.
+
+Grouping tables contain one row for each member HDU. The grouping table
+columns provide identification information that allows applications to
+reference or "point to" the member HDUs. Member HDUs are expected, but
+not required, to contain a set of GRPIDn/GRPLCn keywords in their
+headers for each grouping table that they are referenced by. In this
+sense, the GRPIDn/GRPLCn keywords "link" the member HDU back to its
+Grouping table. Note that a member HDU need not reside in the same FITS
+file as its grouping table, and that a given HDU may be referenced by
+up to 999 grouping tables simultaneously.
+
+Grouping tables are implemented as FITS binary tables with up to six
+pre-defined column TTYPEn values: 'MEMBER\_XTENSION', 'MEMBER\_NAME',
+'MEMBER\_VERSION', 'MEMBER\_POSITION', 'MEMBER\_URI\_TYPE' and 'MEMBER\_LOCATION'.
+The first three columns allow member HDUs to be identified by reference to
+their XTENSION, EXTNAME and EXTVER keyword values. The fourth column allows
+member HDUs to be identified by HDU position within their FITS file.
+The last two columns identify the FITS file in which the member HDU resides,
+if different from the grouping table FITS file.
+
+Additional user defined "auxiliary" columns may also be included with any
+grouping table. When a grouping table is copied or modified the presence of
+auxiliary columns is always taken into account by the grouping support
+functions; however, the grouping support functions cannot directly
+make use of this data.
+
+If a grouping table column is defined but the corresponding member HDU
+information is unavailable then a null value of the appropriate data type
+is inserted in the column field. Integer columns (MEMBER\_POSITION,
+MEMBER\_VERSION) are defined with a TNULLn value of zero (0). Character field
+columns (MEMBER\_XTENSION, MEMBER\_NAME, MEMBER\_URI\_TYPE, MEMBER\_LOCATION)
+utilize an ASCII null character to denote a null field value.
+
+The grouping support functions belong to two basic categories: those that
+work with grouping table HDUs (ffgt**) and those that work with member HDUs
+(ffgm**). Two functions, fits\_copy\_group() and fits\_remove\_group(), have the
+option to recursively copy/delete entire groups. Care should be taken when
+employing these functions in recursive mode as poorly defined groups could
+cause unpredictable results. The problem of a grouping table directly or
+indirectly referencing itself (thus creating an infinite loop) is protected
+against; in fact, neither function will attempt to copy or delete an HDU
+twice.
+
+**A. Grouping Table Routines
+
+>1 Create (append) a grouping table at the end of the current FITS file
+ pointed to by fptr. The grpname parameter provides the grouping table
+ name (GRPNAME keyword value) and may be set to NULL if no group name
+ is to be specified. The grouptype parameter specifies the desired
+ structure of the grouping table and may take on the values:
+ GT\_ID\_ALL\_URI (all columns created), GT\_ID\_REF (ID by reference columns),
+ GT\_ID\_POS (ID by position columns), GT\_ID\_ALL (ID by reference and
+ position columns), GT\_ID\_REF\_URI (ID by reference and FITS file URI
+> columns), and GT\_ID\_POS\_URI (ID by position and FITS file URI columns). \label{ffgtcr}
+-
+ int fits_create_group / ffgtcr
+ (fitsfile *fptr, char *grpname, int grouptype, > int *status)
+-
+>2 Create (insert) a grouping table just after the CHDU of the current FITS
+ file pointed to by fptr. All HDUs below the the insertion point will be
+ shifted downwards to make room for the new HDU. The grpname parameter
+ provides the grouping table name (GRPNAME keyword value) and may be set to
+ NULL if no group name is to be specified. The grouptype parameter specifies
+ the desired structure of the grouping table and may take on the values:
+ GT\_ID\_ALL\_URI (all columns created), GT\_ID\_REF (ID by reference columns),
+ GT\_ID\_POS (ID by position columns), GT\_ID\_ALL (ID by reference and
+ position columns), GT\_ID\_REF\_URI (ID by reference and FITS file URI
+> columns), and GT\_ID\_POS\_URI (ID by position and FITS file URI columns) \label{ffgtis}.
+-
+ int fits_insert_group / ffgtis
+ (fitsfile *fptr, char *grpname, int grouptype, > int *status)
+-
+>3 Change the structure of an existing grouping table pointed to by
+ gfptr. The grouptype parameter (see fits\_create\_group() for valid
+ parameter values) specifies the new structure of the grouping table. This
+ function only adds or removes grouping table columns, it does not add
+ or delete group members (i.e., table rows). If the grouping table already
+ has the desired structure then no operations are performed and function
+ simply returns with a (0) success status code. If the requested structure
+ change creates new grouping table columns, then the column values for all
+ existing members will be filled with the null values appropriate to the
+> column type. \label{ffgtch}
+-
+ int fits_change_group / ffgtch
+ (fitsfile *gfptr, int grouptype, > int *status)
+-
+>4 Remove the group defined by the grouping table pointed to by gfptr, and
+ optionally all the group member HDUs. The rmopt parameter specifies the
+ action to be taken for
+ all members of the group defined by the grouping table. Valid values are:
+ OPT\_RM\_GPT (delete only the grouping table) and OPT\_RM\_ALL (recursively
+ delete all HDUs that belong to the group). Any groups containing the
+ grouping table gfptr as a member are updated, and if rmopt == OPT\_RM\_GPT
+ all members have their GRPIDn and GRPLCn keywords updated accordingly.
+ If rmopt == OPT\_RM\_ALL, then other groups that contain the deleted members
+> of gfptr are updated to reflect the deletion accordingly. \label{ffgtrm}
+-
+ int fits_remove_group / ffgtrm
+ (fitsfile *gfptr, int rmopt, > int *status)
+-
+>5 Copy (append) the group defined by the grouping table pointed to by infptr,
+ and optionally all group member HDUs, to the FITS file pointed to by
+ outfptr. The cpopt parameter specifies the action to be taken for all
+ members of the group infptr. Valid values are: OPT\_GCP\_GPT (copy only
+ the grouping table) and OPT\_GCP\_ALL (recursively copy ALL the HDUs that
+ belong to the group defined by infptr). If the cpopt == OPT\_GCP\_GPT then
+ the members of infptr have their GRPIDn and GRPLCn keywords updated to
+ reflect the existence of the new grouping table outfptr, since they now
+ belong to the new group. If cpopt == OPT\_GCP\_ALL then the new
+ grouping table outfptr only contains pointers to the copied member HDUs
+ and not the original member HDUs of infptr. Note that, when
+ cpopt == OPT\_GCP\_ALL, all members of the group defined by infptr will be
+ copied to a single FITS file pointed to by outfptr regardless of their
+> file distribution in the original group. \label{ffgtcp}
+-
+ int fits_copy_group / ffgtcp
+ (fitsfile *infptr, fitsfile *outfptr, int cpopt, > int *status)
+-
+>6 Merge the two groups defined by the grouping table HDUs infptr and outfptr
+ by combining their members into a single grouping table. All member HDUs
+ (rows) are copied from infptr to outfptr. If mgopt == OPT\_MRG\_COPY then
+ infptr continues to exist unaltered after the merge. If the mgopt ==
+ OPT\_MRG\_MOV then infptr is deleted after the merge. In both cases,
+> the GRPIDn and GRPLCn keywords of the member HDUs are updated accordingly. \label{ffgtmg}
+-
+ int fits_merge_groups / ffgtmg
+ (fitsfile *infptr, fitsfile *outfptr, int mgopt, > int *status)
+-
+>7 "Compact" the group defined by grouping table pointed to by gfptr. The
+ compaction is achieved by merging (via fits\_merge\_groups()) all direct
+ member HDUs of gfptr that are themselves grouping tables. The cmopt
+ parameter defines whether the merged grouping table HDUs remain after
+ merging (cmopt == OPT\_CMT\_MBR) or if they are deleted after merging
+ (cmopt == OPT\_CMT\_MBR\_DEL). If the grouping table contains no direct
+ member HDUs that are themselves grouping tables then this function
+ does nothing. Note that this function is not recursive, i.e., only the
+> direct member HDUs of gfptr are considered for merging. \label{ffgtcm}
+-
+ int fits_compact_group / ffgtcm
+ (fitsfile *gfptr, int cmopt, > int *status)
+-
+>8 Verify the integrity of the grouping table pointed to by gfptr to make
+ sure that all group members are accessible and that all links to other
+ grouping tables are valid. The firstfailed parameter returns the member
+ ID (row number) of the first member HDU to fail verification (if positive
+ value) or the first group link to fail (if negative value). If gfptr is
+> successfully verified then firstfailed contains a return value of 0. \label{ffgtvf}
+-
+ int fits_verify_group / ffgtvf
+ (fitsfile *gfptr, > long *firstfailed, int *status)
+-
+>9 Open a grouping table that contains the member HDU pointed to by mfptr.
+ The grouping table to open is defined by the grpid parameter, which
+ contains the keyword index value of the GRPIDn/GRPLCn keyword(s) that
+ link the member HDU mfptr to the grouping table. If the grouping table
+ resides in a file other than the member HDUs file then an attempt is
+ first made to open the file readwrite, and failing that readonly. A
+ pointer to the opened grouping table HDU is returned in gfptr.
+
+ Note that it is possible, although unlikely and undesirable, for the
+ GRPIDn/GRPLCn keywords in a member HDU header to be non-continuous, e.g.,
+ GRPID1, GRPID2, GRPID5, GRPID6. In such cases, the grpid index value
+ specified in the function call shall identify the (grpid)th GRPID value.
+ In the above example, if grpid == 3, then the group specified by GRPID5
+> would be opened. \label{ffgtop}
+-
+ int fits_open_group / ffgtop
+ (fitsfile *mfptr, int group, > fitsfile **gfptr, int *status)
+-
+>10 Add a member HDU to an existing grouping table pointed to by gfptr.
+ The member HDU may either be pointed to mfptr (which must be positioned
+ to the member HDU) or, if mfptr == NULL, identified by the hdupos parameter
+ (the HDU position number, Primary array == 1) if both the grouping table
+ and the member HDU reside in the same FITS file. The new member HDU shall
+ have the appropriate GRPIDn and GRPLCn keywords created in its header.
+ Note that if the member HDU is already a member of the group then it will
+> not be added a second time. \label{ffgtam}
+-
+ int fits_add_group_member / ffgtam
+ (fitsfile *gfptr, fitsfile *mfptr, int hdupos, > int *status)
+-
+
+**B. Group Member Routines
+
+>1 Return the number of member HDUs in a grouping table gfptr. The number
+ member HDUs is just the NAXIS2 value (number of rows) of the grouping
+> table. \label{ffgtnm}
+-
+ int fits_get_num_members / ffgtnm
+ (fitsfile *gfptr, > long *nmembers, int *status)
+-
+>2 Return the number of groups to which the HDU pointed to by mfptr is
+ linked, as defined by the number of GRPIDn/GRPLCn keyword records that
+ appear in its header. Note that each time this function is called, the
+ indices of the GRPIDn/GRPLCn keywords are checked to make sure they
+ are continuous (ie no gaps) and are re-enumerated to eliminate gaps if
+> found. \label{ffgmng}
+-
+ int fits_get_num_groups / ffgmng
+ (fitsfile *mfptr, > long *nmembers, int *status)
+-
+>3 Open a member of the grouping table pointed to by gfptr. The member to
+ open is identified by its row number within the grouping table as given
+ by the parameter 'member' (first member == 1) . A fitsfile pointer to
+ the opened member HDU is returned as mfptr. Note that if the member HDU
+ resides in a FITS file different from the grouping table HDU then the
+> member file is first opened readwrite and, failing this, opened readonly. \label{ffgmop}
+-
+ int fits_open_member / ffgmop
+ (fitsfile *gfptr, long member, > fitsfile **mfptr, int *status)
+-
+>4 Copy (append) a member HDU of the grouping table pointed to by gfptr.
+ The member HDU is identified by its row number within the grouping table
+ as given by the parameter 'member' (first member == 1). The copy of the
+ group member HDU will be appended to the FITS file pointed to by mfptr,
+ and upon return mfptr shall point to the copied member HDU. The cpopt
+ parameter may take on the following values: OPT\_MCP\_ADD which adds a new
+ entry in gfptr for the copied member HDU, OPT\_MCP\_NADD which does not add
+ an entry in gfptr for the copied member, and OPT\_MCP\_REPL which replaces
+> the original member entry with the copied member entry. \label{ffgmcp}
+-
+ int fits_copy_member / ffgmcp
+ (fitsfile *gfptr, fitsfile *mfptr, long member, int cpopt, > int *status)
+-
+>5 Transfer a group member HDU from the grouping table pointed to by
+ infptr to the grouping table pointed to by outfptr. The member HDU to
+ transfer is identified by its row number within infptr as specified by
+ the parameter 'member' (first member == 1). If tfopt == OPT\_MCP\_ADD then
+ the member HDU is made
+ a member of outfptr and remains a member of infptr. If tfopt == OPT\_MCP\_MOV
+> then the member HDU is deleted from infptr after the transfer to outfptr. \label{ffgmtf}
+-
+ int fits_transfer_member / ffgmtf
+ (fitsfile *infptr, fitsfile *outfptr, long member, int tfopt,
+ > int *status)
+-
+>6 Remove a member HDU from the grouping table pointed to by gfptr. The
+ member HDU to be deleted is identified by its row number in the grouping
+ table as specified by the parameter 'member' (first member == 1). The rmopt
+ parameter may take on the following values: OPT\_RM\_ENTRY which
+ removes the member HDU entry from the grouping table and updates the
+ member's GRPIDn/GRPLCn keywords, and OPT\_RM\_MBR which removes the member
+> HDU entry from the grouping table and deletes the member HDU itself. \label{ffgmrm}
+-
+ int fits_remove_member / ffgmrm
+ (fitsfile *fptr, long member, int rmopt, > int *status)
+-
+
+*IX Specialized CFITSIO Interface Routines
+
+The basic interface routines described previously are recommended
+for most uses, but the routines described in this chapter
+are also available if necessary. Some of these routines perform more
+specialized function that cannot easily be done with the basic
+interface routines while others duplicate the functionality of the
+basic routines but have a slightly different calling sequence.
+See Appendix B for the definition of each function parameter.
+
+**A. FITS File Access Routines
+
+>1 Open an existing FITS file residing in core computer memory. This
+routine is analogous to fits\_open\_file. The 'filename' is
+currently ignored by this routine and may be any arbitrary string. In
+general, the application must have preallocated an initial block of
+memory to hold the FITS file prior to calling this routine: 'memptr'
+points to the starting address and 'memsize' gives the initial size of
+the block of memory. 'mem\_realloc' is a pointer to an optional
+function that CFITSIO can call to allocate additional memory, if needed
+(only if mode = READWRITE), and is modeled after the standard C
+'realloc' function; a null pointer may be given if the initial
+allocation of memory is all that will be required (e.g., if the file is
+opened with mode = READONLY). The 'deltasize' parameter may be used to
+suggest a minimum amount of additional memory that should be allocated
+during each call to the memory reallocation function. By default,
+CFITSIO will reallocate enough additional space to hold the entire
+currently defined FITS file (as given by the NAXISn keywords) or 1 FITS
+block (= 2880 bytes), which ever is larger. Values of deltasize less
+than 2880 will be ignored. Since the memory reallocation operation can
+be computationally expensive, allocating a larger initial block of
+memory, and/or specifying a larger deltasize value may help to reduce
+the number of reallocation calls and make the application program run
+> faster. \label{ffomem}
+-
+ int fits_open_memfile / ffomem
+ (fitsfile **fptr, const char *filename, int mode, void **memptr,
+ size_t *memsize, size_t deltasize,
+ void *(*mem_realloc)(void *p, size_t newsize), int *status)
+-
+>2 Create a new FITS file residing in core computer memory. This
+routine is analogous to fits\_create\_file. In general, the
+application must have preallocated an initial block of memory to hold
+the FITS file prior to calling this routine: 'memptr' points to the
+starting address and 'memsize' gives the initial size of the block of
+memory. 'mem\_realloc' is a pointer to an optional function that
+CFITSIO can call to allocate additional memory, if needed, and is
+modeled after the standard C 'realloc' function; a null pointer may be
+given if the initial allocation of memory is all that will be
+required. The 'deltasize' parameter may be used to suggest a minimum
+amount of additional memory that should be allocated during each call
+to the memory reallocation function. By default, CFITSIO will
+reallocate enough additional space to hold 1 FITS block (= 2880 bytes)
+and values of deltasize less than 2880 will be ignored. Since the
+memory reallocation operation can be computationally expensive,
+allocating a larger initial block of memory, and/or specifying a larger
+deltasize value may help to reduce the number of reallocation calls
+and make the application program run
+> faster. \label{ffimem}
+-
+ int fits_create_memfile / ffimem
+ (fitsfile **fptr, void **memptr,
+ size_t *memsize, size_t deltasize,
+ void *(*mem_realloc)(void *p, size_t newsize), int *status)
+-
+>3 Reopen a FITS file that was previously opened with
+ fits\_open\_file or fits\_create\_file. The new fitsfile
+ pointer may then be treated as a separate file, and one may
+ simultaneously read or write to 2 (or more) different extensions in
+ the same file. The fits\_open\_file routine (above) automatically
+ detects cases where a previously opened file is being opened again,
+ and then internally call fits\_reopen\_file, so programs should rarely
+ need to explicitly call this routine.
+>\label{ffreopen}
+-
+ int fits_reopen_file / ffreopen
+ (fitsfile *openfptr, fitsfile **newfptr, > int *status)
+-
+
+>4 Create a new FITS file, using a template file to define its
+ initial size and structure. The template may be another FITS HDU
+ or an ASCII template file. If the input template file name pointer
+ is null, then this routine behaves the same as fits\_create\_file.
+ The currently supported format of the ASCII template file is described
+ under the fits\_parse\_template routine (in the general Utilities
+ section)
+>\label{fftplt}
+-
+ int fits_create_template / fftplt
+ (fitsfile **fptr, char *filename, char *tpltfile > int *status)
+-
+
+>5 Parse the input filename or URL into its component parts: the file
+type (file://, ftp://, http://, etc), the base input file name, the
+name of the output file that the input file is to be copied to prior
+to opening, the HDU or extension specification, the filtering
+specifier, the binning specifier, and the column specifier. Null
+strings will be returned for any components that are not present
+> in the input file name. \label{ffiurl}
+-
+ int fits_parse_input_url / ffiurl
+ (char *filename, > char *filetype, char *infile, char *outfile, char
+ *extspec, char *filter, char *binspec, char *colspec, int *status)
+-
+>6 Parse the input filename and return the HDU number that would be
+moved to if the file were opened with fits\_open\_file. The returned
+HDU number begins with 1 for the primary array, so for example, if the
+input filename = `myfile.fits[2]' then hdunum = 3 will be returned.
+CFITSIO does not open the file to check if the extension actually
+exists if an extension number is specified. If an extension name is
+included in the file name specification (e.g. `myfile.fits[EVENTS]'
+then this routine will have to open the FITS file and look for the
+position of the named extension, then close file again. This is not
+possible if the file is being read from the stdin stream, and an error
+will be returned in this case. If the filename does not specify an
+explicit extension (e.g. 'myfile.fits') then hdunum = -99 will be
+returned, which is functionally equivalent to hdunum = 1. This routine
+is mainly used for backward compatibility in the ftools software
+package and is not recommended for general use. It is generally better
+and more efficient to first open the FITS file with fits\_open\_file,
+then use fits\_get\_hdu\_num to determine which HDU in the file has
+been opened, rather than calling fits\_parse\_input\_url followed by a
+call to fits\_open\_file.
+> \label{ffextn}
+-
+ int fits_parse_extnum / ffextn
+ (char *filename, > int *hdunum, int *status)
+-
+>7 Parse the input file name and return the root file name. The root
+name includes the file type if specified, (e.g. 'ftp://' or 'http://')
+and the full path name, to the extent that it is specified in the input
+filename. It does not include the HDU name or number, or any filtering
+specifications.
+> \label{ffrtnm}
+-
+ int fits_parse_rootname / ffrtnm
+ (char *filename, > char *rootname, int *status);
+-
+>8 Test if the input file or a compressed version of the file (with
+a .gz, .Z, .z, or .zip extension) exists on disk. The returned value of
+the 'exists' parameter will have 1 of the 4 following values:
+-
+ 2: the file does not exist, but a compressed version does exist
+ 1: the disk file does exist
+ 0: neither the file nor a compressed version of the file exist
+ -1: the input file name is not a disk file (could be a ftp, http,
+ smem, or mem file, or a file piped in on the STDIN stream)
+-
+
+> \label{ffexist}
+-
+ int fits_file_exists / ffexist
+ (char *filename, > int *exists, int *status);
+-
+>9 Flush any internal buffers of data to the output FITS file. These
+ routines rarely need to be called, but can be useful in cases where
+ other processes need to access the same FITS file in real time,
+ either on disk or in memory. These routines also help to ensure
+ that if the application program subsequently aborts then the FITS
+ file will have been closed properly. The first routine,
+ fits\_flush\_file is more rigorous and completely closes, then
+ reopens, the current HDU, before flushing the internal buffers, thus
+ ensuring that the output FITS file is identical to what would be
+ produced if the FITS was closed at that point (i.e., with a call to
+ fits\_close\_file). The second routine, fits\_flush\_buffer simply
+ flushes the internal CFITSIO buffers of data to the output FITS
+ file, without updating and closing the current HDU. This is much
+ faster, but there may be circumstances where the flushed file does
+ not completely reflect the final state of the file as it will exist
+ when the file is actually closed.
+
+ A typical use of these routines would be to flush the state of a
+ FITS table to disk after each row of the table is written. It is
+ recommend that fits\_flush\_file be called after the first row is
+ written, then fits\_flush\_buffer may be called after each
+ subsequent row is written. Note that this latter routine will not
+ automatically update the NAXIS2 keyword which records the number of
+ rows of data in the table, so this keyword must be explicitly
+ updated by the application program after each row is written.
+> \label{ffflus}
+-
+ int fits_flush_file / ffflus
+ (fitsfile *fptr, > int *status)
+
+ int fits_flush_buffer / ffflsh
+ (fitsfile *fptr, 0, > int *status)
+
+ (Note: The second argument must be 0).
+-
+
+**B. HDU Access Routines
+
+>1 Get the byte offsets in the FITS file to the start of the header
+ and the start and end of the data in the CHDU. The difference
+ between headstart and dataend equals the size of the CHDU. If the
+ CHDU is the last HDU in the file, then dataend is also equal to the
+ size of the entire FITS file. Null pointers may be input for any
+ of the address parameters if their values are not needed. The
+ fits\_get\_hduaddr routine is obsolete and should no longer be
+ used. The newer fits\_get\_hduoff routine uses the 'off\_t'
+ data type which can support offsets in large files greater than
+> 2.1GB in size. \label{ffghad}
+-
+ int fits_get_hduoff / ffghof
+ (fitsfile *fptr, > off_t *headstart, off_t *datastart, off_t *dataend,
+ int *status)
+
+ int fits_get_hduaddr / ffghad (OBSOLETE routine)
+ (fitsfile *fptr, > long *headstart, long *datastart, long *dataend,
+ int *status)
+-
+>2 Create (append) a new empty HDU at the end of the FITS file.
+ This is now the CHDU but it is completely empty and has
+ no header keywords. It is recommended that fits\_create\_img or
+> fits\_create\_tbl be used instead of this routine. \label{ffcrhd}
+-
+ int fits_create_hdu / ffcrhd
+ (fitsfile *fptr, > int *status)
+-
+>3 Insert a new IMAGE extension immediately following the CHDU, or
+ insert a new Primary Array at the beginning of the file. Any
+ following extensions in the file will be shifted down to make room
+ for the new extension. If the CHDU is the last HDU in the file
+ then the new image extension will simply be appended to the end of
+ the file. One can force a new primary array to be inserted at the
+ beginning of the FITS file by setting status = PREPEND\_PRIMARY prior
+ to calling the routine. In this case the old primary array will be
+ converted to an IMAGE extension. The new extension (or primary
+ array) will become the CHDU. Refer to Chapter 9 for a list of
+> pre-defined bitpix values. \label{ffiimg}
+-
+ int fits_insert_img / ffiimg
+ (fitsfile *fptr, int bitpix, int naxis, long *naxes, > int *status)
+-
+>4 Insert a new ASCII or binary table extension immediately following the CHDU.
+ Any following extensions will be shifted down to make room for the
+ new extension. If there are no other following extensions then the
+ new table extension will simply be appended to the end of the
+ file. If the FITS file is currently empty then this routine will
+ create a dummy primary array before appending the table to it. The
+ new extension will become the CHDU. The tunit and extname
+ parameters are optional and a null pointer may be given if they are
+ not defined. When inserting an ASCII table with
+ fits\_insert\_atbl, a null pointer may given for the *tbcol
+ parameter in which case each column of the table will be separated
+ by a single space character. Similarly, if the input value of
+ rowlen is 0, then CFITSIO will calculate the default rowlength
+ based on the tbcol and ttype values. When inserting a binary table
+ with fits\_insert\_btbl, if there are following extensions in the
+ file and if the table contains variable length array columns then
+ pcount must specify the expected final size of the data heap,
+> otherwise pcount must = 0. \label{ffitab} \label{ffibin}
+-
+ int fits_insert_atbl / ffitab
+ (fitsfile *fptr, long rowlen, long nrows, int tfields, char *ttype[],
+ long *tbcol, char *tform[], char *tunit[], char *extname, > int *status)
+
+ int fits_insert_btbl / ffibin
+ (fitsfile *fptr, long nrows, int tfields, char **ttype,
+ char **tform, char **tunit, char *extname, long pcount, > int *status)
+-
+>5 Modify the size, dimensions, and/or data type of the current
+ primary array or image extension. If the new image, as specified
+ by the input arguments, is larger than the current existing image
+ in the FITS file then zero fill data will be inserted at the end
+ of the current image and any following extensions will be moved
+ further back in the file. Similarly, if the new image is
+ smaller than the current image then any following extensions
+ will be shifted up towards the beginning of the FITS file
+ and the image data will be truncated to the new size.
+ This routine rewrites the BITPIX, NAXIS, and NAXISn keywords
+> with the appropriate values for the new image. \label{ffrsim}
+-
+ int fits_resize_img / ffrsim
+ (fitsfile *fptr, int bitpix, int naxis, long *naxes, > int *status)
+-
+>6 Copy the data (and not the header) from the CHDU associated with infptr
+ to the CHDU associated with outfptr. This will overwrite any data
+ previously in the output CHDU. This low level routine is used by
+ fits\_copy\_hdu, but it may also be useful in certain application programs
+ that want to copy the data from one FITS file to another but also
+ want to modify the header keywords. The required FITS header keywords
+ which define the structure of the HDU must be written to the
+> output CHDU before calling this routine. \label{ffcpdt}
+-
+ int fits_copy_data / ffcpdt
+ (fitsfile *infptr, fitsfile *outfptr, > int *status)
+-
+>7 This routine forces CFITSIO to rescan the current header keywords that
+ define the structure of the HDU (such as the NAXIS and BITPIX
+ keywords) so that it reinitializes the internal buffers that
+ describe the HDU structure. This routine is useful for
+ reinitializing the structure of an HDU if any of the required
+ keywords (e.g., NAXISn) have been modified. In practice it should
+ rarely be necessary to call this routine because CFITSIO
+> internally calls it in most situations. \label{ffrdef}
+-
+ int fits_set_hdustruc / ffrdef
+ (fitsfile *fptr, > int *status) (DEPRECATED)
+-
+**C. Specialized Header Keyword Routines
+
+***1. Header Information Routines
+
+>1 Reserve space in the CHU for MOREKEYS more header keywords.
+ This routine may be called to allocate space for additional keywords
+ at the time the header is created (prior to writing any data).
+ CFITSIO can dynamically add more space to the header when needed,
+ however it is more efficient to preallocate the required space
+> if the size is known in advance. \label{ffhdef}
+-
+ int fits_set_hdrsize / ffhdef
+ (fitsfile *fptr, int morekeys, > int *status)
+-
+>2 Return the number of keywords in the header (not counting the END
+ keyword) and the current position
+ in the header. The position is the number of the keyword record that
+ will be read next (or one greater than the position of the last keyword
+ that was read). A value of 1 is returned if the pointer is
+> positioned at the beginning of the header. \label{ffghps}
+-
+ int fits_get_hdrpos / ffghps
+ (fitsfile *fptr, > int *keysexist, int *keynum, int *status)
+-
+
+***2. Read and Write the Required Keywords
+
+>1 Write the primary header or IMAGE extension keywords into the CHU.
+ The simpler fits\_write\_imghdr routine is equivalent to calling
+ fits\_write\_grphdr with the default values of simple = TRUE, pcount
+ = 0, gcount = 1, and extend = TRUE. The PCOUNT, GCOUNT and EXTEND
+ keywords are not required in the primary header and are only written
+ if pcount is not equal to zero, gcount is not equal to zero or one,
+ and if extend is TRUE, respectively. When writing to an IMAGE
+ extension, the SIMPLE and EXTEND parameters are ignored. It is
+ recommended that fits\_create\_image or fits\_create\_tbl be used
+ instead of these routines to write the
+> required header keywords. \label{ffphpr} \label{ffphps}
+-
+ int fits_write_imghdr / ffphps
+ (fitsfile *fptr, int bitpix, int naxis, long *naxes, > int *status)
+
+ int fits_write_grphdr / ffphpr
+ (fitsfile *fptr, int simple, int bitpix, int naxis, long *naxes,
+ long pcount, long gcount, int extend, > int *status)
+-
+>2 Write the ASCII table header keywords into the CHU. The optional
+ TUNITn and EXTNAME keywords are written only if the input pointers
+ are not null. A null pointer may given for the
+ *tbcol parameter in which case a single space will be inserted
+ between each column of the table. Similarly, if rowlen is
+ given = 0, then CFITSIO will calculate the default rowlength based on
+> the tbcol and ttype values. \label{ffphtb}
+-
+ int fits_write_atblhdr / ffphtb
+ (fitsfile *fptr, long rowlen, long nrows, int tfields, char **ttype,
+ long *tbcol, char **tform, char **tunit, char *extname, > int *status)
+-
+>3 Write the binary table header keywords into the CHU. The optional
+ TUNITn and EXTNAME keywords are written only if the input pointers
+ are not null. The pcount parameter, which specifies the
+ size of the variable length array heap, should initially = 0;
+ CFITSIO will automatically update the PCOUNT keyword value if any
+ variable length array data is written to the heap. The TFORM keyword
+ value for variable length vector columns should have the form 'Pt(len)'
+ or '1Pt(len)' where `t' is the data type code letter (A,I,J,E,D, etc.)
+ and `len' is an integer specifying the maximum length of the vectors
+ in that column (len must be greater than or equal to the longest
+ vector in the column). If `len' is not specified when the table is
+ created (e.g., the input TFORMn value is just '1Pt') then CFITSIO will
+ scan the column when the table is first closed and will append the
+ maximum length to the TFORM keyword value. Note that if the table
+ is subsequently modified to increase the maximum length of the vectors
+ then the modifying program is responsible for also updating the TFORM
+> keyword value. \label{ffphbn}
+-
+ int fits_write_btblhdr / ffphbn
+ (fitsfile *fptr, long nrows, int tfields, char **ttype,
+ char **tform, char **tunit, char *extname, long pcount, > int *status)
+-
+>4 Read the required keywords from the CHDU (image or table). When
+ reading from an IMAGE extension the SIMPLE and EXTEND parameters are
+ ignored. A null pointer may be supplied for any of the returned
+> parameters that are not needed. \label{ffghpr} \label{ffghtb} \label{ffghbn}
+-
+ int fits_read_imghdr / ffghpr
+ (fitsfile *fptr, int maxdim, > int *simple, int *bitpix, int *naxis,
+ long *naxes, long *pcount, long *gcount, int *extend, int *status)
+
+ int fits_read_atblhdr / ffghtb
+ (fitsfile *fptr,int maxdim, > long *rowlen, long *nrows,
+ int *tfields, char **ttype, long *tbcol, char **tform, char **tunit,
+ char *extname, int *status)
+
+ int fits_read_btblhdr / ffghbn
+ (fitsfile *fptr, int maxdim, > long *nrows, int *tfields,
+ char **ttype, char **tform, char **tunit, char *extname,
+ long *pcount, int *status)
+-
+***3. Write Keyword Routines
+
+These routines simply append a new keyword to the header and do not
+check to see if a keyword with the same name already exists. In
+general it is preferable to use the fits\_update\_key routine to ensure
+that the same keyword is not written more than once to the header. See
+Appendix B for the definition of the parameters used in these
+routines.
+
+
+>1 Write (append) a new keyword of the appropriate data type into the CHU.
+ A null pointer may be entered for the comment parameter, which
+ will cause the comment field of the keyword to be left blank. The
+ flt, dbl, cmp, and dblcmp versions of this routine have the added
+ feature that if the 'decimals' parameter is negative, then the 'G'
+ display format rather then the 'E' format will be used when
+ constructing the keyword value, taking the absolute value of
+ 'decimals' for the precision. This will suppress trailing zeros,
+ and will use a fixed format rather than an exponential format,
+> depending on the magnitude of the value. \label{ffpkyx}
+-
+ int fits_write_key_str / ffpkys
+ (fitsfile *fptr, char *keyname, char *value, char *comment,
+ > int *status)
+
+ int fits_write_key_[log, lng] / ffpky[lj]
+ (fitsfile *fptr, char *keyname, DTYPE numval, char *comment,
+ > int *status)
+
+ int fits_write_key_[flt, dbl, fixflg, fixdbl] / ffpky[edfg]
+ (fitsfile *fptr, char *keyname, DTYPE numval, int decimals,
+ char *comment, > int *status)
+
+ int fits_write_key_[cmp, dblcmp, fixcmp, fixdblcmp] / ffpk[yc,ym,fc,fm]
+ (fitsfile *fptr, char *keyname, DTYPE *numval, int decimals,
+ char *comment, > int *status)
+-
+>2 Write (append) a string valued keyword into the CHU which may be longer
+ than 68 characters in length. This uses the Long String Keyword
+ convention that is described in the`Local FITS Conventions' section
+ in Chapter 4. Since this uses a non-standard FITS convention to
+ encode the long keyword string, programs which use this routine
+ should also call the fits\_write\_key\_longwarn routine to add some
+ COMMENT keywords to warn users of the FITS file that this
+ convention is being used. The fits\_write\_key\_longwarn routine
+ also writes a keyword called LONGSTRN to record the version of the
+ longstring convention that has been used, in case a new convention
+ is adopted at some point in the future. If the LONGSTRN keyword
+ is already present in the header, then fits\_write\_key\_longwarn
+ will
+> simply return without doing anything. \label{ffpkls} \label{ffplsw}
+-
+ int fits_write_key_longstr / ffpkls
+ (fitsfile *fptr, char *keyname, char *longstr, char *comment,
+ > int *status)
+
+ int fits_write_key_longwarn / ffplsw
+ (fitsfile *fptr, > int *status)
+-
+>3 Write (append) a numbered sequence of keywords into the CHU. The
+ starting index number (nstart) must be greater than 0. One may
+ append the same comment to every keyword (and eliminate the need
+ to have an array of identical comment strings, one for each keyword) by
+ including the ampersand character as the last non-blank character in the
+ (first) COMMENTS string parameter. This same string
+ will then be used for the comment field in all the keywords.
+ One may also enter a null pointer for the comment parameter to
+> leave the comment field of the keyword blank. \label{ffpknx}
+-
+ int fits_write_keys_str / ffpkns
+ (fitsfile *fptr, char *keyroot, int nstart, int nkeys,
+ char **value, char **comment, > int *status)
+
+ int fits_write_keys_[log, lng] / ffpkn[lj]
+ (fitsfile *fptr, char *keyroot, int nstart, int nkeys,
+ DTYPE *numval, char **comment, int *status)
+
+ int fits_write_keys_[flt, dbl, fixflg, fixdbl] / ffpkne[edfg]
+ (fitsfile *fptr, char *keyroot, int nstart, int nkey,
+ DTYPE *numval, int decimals, char **comment, > int *status)
+-
+>4 Copy an indexed keyword from one HDU to another, modifying
+ the index number of the keyword name in the process. For example,
+ this routine could read the TLMIN3 keyword from the input HDU
+ (by giving keyroot = `TLMIN' and innum = 3) and write it to the
+ output HDU with the keyword name TLMIN4 (by setting outnum = 4).
+ If the input keyword does not exist, then this routine simply
+> returns without indicating an error. \label{ffcpky}
+-
+ int fits_copy_key / ffcpky
+ (fitsfile *infptr, fitsfile *outfptr, int innum, int outnum,
+ char *keyroot, > int *status)
+-
+>5 Write (append) a `triple precision' keyword into the CHU in F28.16 format.
+ The floating point keyword value is constructed by concatenating the
+ input integer value with the input double precision fraction value
+ (which must have a value between 0.0 and 1.0). The ffgkyt routine should
+ be used to read this keyword value, because the other keyword reading
+> routines will not preserve the full precision of the value. \label{ffpkyt}
+-
+ int fits_write_key_triple / ffpkyt
+ (fitsfile *fptr, char *keyname, long intval, double frac,
+ char *comment, > int *status)
+-
+>6 Write keywords to the CHDU that are defined in an ASCII template file.
+ The format of the template file is described under the fits\_parse\_template
+> routine. \label{ffpktp}
+-
+ int fits_write_key_template / ffpktp
+ (fitsfile *fptr, const char *filename, > int *status)
+-
+***4. Insert Keyword Routines
+
+These insert routines are somewhat less efficient than the `update' or
+`write' keyword routines because the following keywords in the header
+must be shifted down to make room for the inserted keyword. See
+Appendix B for the definition of the parameters used in these
+routines.
+
+>1 Insert a new keyword record into the CHU at the specified position
+ (i.e., immediately preceding the (keynum)th keyword in the header.)
+> \label{ffirec}
+-
+ int fits_insert_record / ffirec
+ (fitsfile *fptr, int keynum, char *card, > int *status)
+-
+>2 Insert a new keyword into the CHU. The new keyword is inserted
+ immediately following the last keyword that has been read from the
+ header. The `longstr' version has the same functionality as the
+ `str' version except that it also supports the local long string
+ keyword convention for strings longer than 68 characters. A null
+ pointer may be entered for the comment parameter which will cause
+ the comment field to be left blank. The flt, dbl, cmp, and dblcmp
+ versions of this routine have the added
+ feature that if the 'decimals' parameter is negative, then the 'G'
+ display format rather then the 'E' format will be used when
+ constructing the keyword value, taking the absolute value of
+ 'decimals' for the precision. This will suppress trailing zeros,
+ and will use a fixed format rather than an exponential format,
+> depending on the magnitude of the value. \label{ffikyx}
+-
+ int fits_insert_card / ffikey
+ (fitsfile *fptr, char *card, > &status)
+
+ int fits_insert_key_[str, longstr] / ffi[kys, kls]
+ (fitsfile *fptr, char *keyname, char *value, char *comment,
+ > int *status)
+
+ int fits_insert_key_[log, lng] / ffiky[lj]
+ (fitsfile *fptr, char *keyname, DTYPE numval, char *comment,
+ > int *status)
+
+ int fits_insert_key_[flt, fixflt, dbl, fixdbl] / ffiky[edfg]
+ (fitsfile *fptr, char *keyname, DTYPE numval, int decimals,
+ char *comment, > int *status)
+
+ int fits_insert_key_[cmp, dblcmp, fixcmp, fixdblcmp] / ffik[yc,ym,fc,fm]
+ (fitsfile *fptr, char *keyname, DTYPE *numval, int decimals,
+ char *comment, > int *status)
+-
+>3 Insert a new keyword with an undefined, or null, value into the CHU.
+> The value string of the keyword is left blank in this case. \label{ffikyu}
+-
+ int fits_insert_key_null / ffikyu
+ (fitsfile *fptr, char *keyname, char *comment, > int *status)
+-
+
+***5. Read Keyword Routines
+
+Wild card characters may be used when specifying the name of the
+keyword to be read.
+
+>1 Read a keyword value (with the appropriate data type) and comment from
+ the CHU. If a NULL comment pointer is given on input, then the comment
+ string will not be returned. If the value of the keyword is not defined
+ (i.e., the value field is blank) then an error status = VALUE\_UNDEFINED
+ will be returned and the input value will not be changed (except that
+ ffgkys will reset the value to a null string).
+> \label{ffgkyx} \label{ffgkls}
+-
+ int fits_read_key_str / ffgkys
+ (fitsfile *fptr, char *keyname, > char *value, char *comment,
+ int *status);
+
+ NOTE: after calling the following routine, programs must explicitly free
+ the memory allocated for 'longstr' after it is no longer needed.
+
+ int fits_read_key_longstr / ffgkls
+ (fitsfile *fptr, char *keyname, > char **longstr, char *comment,
+ int *status)
+
+ int fits_read_key_[log, lng, flt, dbl, cmp, dblcmp] / ffgky[ljedcm]
+ (fitsfile *fptr, char *keyname, > DTYPE *numval, char *comment,
+ int *status)
+
+-
+>2 Read a sequence of indexed keyword values (e.g., NAXIS1, NAXIS2, ...).
+ The input starting index number (nstart) must be greater than 0.
+ If the value of any of the keywords is not defined (i.e., the value
+ field is blank) then an error status = VALUE\_UNDEFINED will be
+ returned and the input value for the undefined keyword(s) will not
+ be changed. These routines do not support wild card characters in
+ the root name. If there are no indexed keywords in the header with
+ the input root name then these routines do not return a non-zero
+> status value and instead simply return nfound = 0. \label{ffgknx}
+-
+ int fits_read_keys_str / ffgkns
+ (fitsfile *fptr, char *keyname, int nstart, int nkeys,
+ > char **value, int *nfound, int *status)
+
+ int fits_read_keys_[log, lng, flt, dbl] / ffgkn[ljed]
+ (fitsfile *fptr, char *keyname, int nstart, int nkeys,
+ > DTYPE *numval, int *nfound, int *status)
+-
+>3 Read the value of a floating point keyword, returning the integer and
+ fractional parts of the value in separate routine arguments.
+ This routine may be used to read any keyword but is especially
+ useful for reading the 'triple precision' keywords written by ffpkyt.
+> \label{ffgkyt}
+-
+ int fits_read_key_triple / ffgkyt
+ (fitsfile *fptr, char *keyname, > long *intval, double *frac,
+ char *comment, int *status)
+-
+***6. Modify Keyword Routines
+
+These routines modify the value of an existing keyword. An error is
+returned if the keyword does not exist. Wild card characters may be
+used when specifying the name of the keyword to be modified. See
+Appendix B for the definition of the parameters used in these
+routines.
+
+>>1 Modify (overwrite) the nth 80-character header record in the CHU. \label{ffmrec}
+-
+ int fits_modify_record / ffmrec
+ (fitsfile *fptr, int keynum, char *card, > int *status)
+-
+>2 Modify (overwrite) the 80-character header record for the named keyword
+ in the CHU. This can be used to overwrite the name of the keyword as
+> well as its value and comment fields. \label{ffmcrd}
+-
+ int fits_modify_card / ffmcrd
+ (fitsfile *fptr, char *keyname, char *card, > int *status)
+-
+>5 Modify the value and comment fields of an existing keyword in the CHU.
+ The `longstr' version has the same functionality as the `str'
+ version except that it also supports the local long string keyword
+ convention for strings longer than 68 characters. Optionally, one
+ may modify only the value field and leave the comment field
+ unchanged by setting the input COMMENT parameter equal to the
+ ampersand character (\&) or by entering a null pointer for the
+ comment parameter. The flt, dbl, cmp, and dblcmp versions of this
+ routine have the added feature that if the 'decimals' parameter is
+ negative, then the 'G' display format rather then the 'E' format
+ will be used when constructing the keyword value, taking the
+ absolute value of 'decimals' for the precision. This will suppress
+ trailing zeros, and will use a fixed format rather than an
+ exponential format,
+> depending on the magnitude of the value. \label{ffmkyx}
+-
+ int fits_modify_key_[str, longstr] / ffm[kys, kls]
+ (fitsfile *fptr, char *keyname, char *value, char *comment,
+ > int *status);
+
+ int fits_modify_key_[log, lng] / ffmky[lj]
+ (fitsfile *fptr, char *keyname, DTYPE numval, char *comment,
+ > int *status)
+
+ int fits_modify_key_[flt, dbl, fixflt, fixdbl] / ffmky[edfg]
+ (fitsfile *fptr, char *keyname, DTYPE numval, int decimals,
+ char *comment, > int *status)
+
+ int fits_modify_key_[cmp, dblcmp, fixcmp, fixdblcmp] / ffmk[yc,ym,fc,fm]
+ (fitsfile *fptr, char *keyname, DTYPE *numval, int decimals,
+ char *comment, > int *status)
+-
+>6 Modify the value of an existing keyword to be undefined, or null.
+ The value string of the keyword is set to blank.
+ Optionally, one may leave the comment field unchanged by setting the
+ input COMMENT parameter equal to
+> the ampersand character (\&) or by entering a null pointer. \label{ffmkyu}
+-
+ int fits_modify_key_null / ffmkyu
+ (fitsfile *fptr, char *keyname, char *comment, > int *status)
+-
+***7. Update Keyword Routines
+
+>1 These update routines modify the value, and optionally the comment field,
+ of the keyword if it already exists, otherwise the new keyword is
+ appended to the header. A separate routine is provided for each
+ keyword data type. The `longstr' version has the same functionality
+ as the `str' version except that it also supports the local long
+ string keyword convention for strings longer than 68 characters. A
+ null pointer may be entered for the comment parameter which will
+ leave the comment field unchanged or blank. The flt, dbl, cmp, and
+ dblcmp versions of this routine have the added feature that if the
+ 'decimals' parameter is negative, then the 'G' display format
+ rather then the 'E' format will be used when constructing the
+ keyword value, taking the absolute value of 'decimals' for the
+ precision. This will suppress trailing zeros, and will use a fixed
+ format rather than an exponential format,
+> depending on the magnitude of the value. \label{ffukyx}
+-
+ int fits_update_key_[str, longstr] / ffu[kys, kls]
+ (fitsfile *fptr, char *keyname, char *value, char *comment,
+ > int *status)
+
+ int fits_update_key_[log, lng] / ffuky[lj]
+ (fitsfile *fptr, char *keyname, DTYPE numval, char *comment,
+ > int *status)
+
+ int fits_update_key_[flt, dbl, fixflt, fixdbl] / ffuky[edfg]
+ (fitsfile *fptr, char *keyname, DTYPE numval, int decimals,
+ char *comment, > int *status)
+
+ int fits_update_key_[cmp, dblcmp, fixcmp, fixdblcmp] / ffuk[yc,ym,fc,fm]
+ (fitsfile *fptr, char *keyname, DTYPE *numval, int decimals,
+ char *comment, > int *status)
+-
+
+**D. Define Data Scaling and Undefined Pixel Parameters
+
+These routines set or modify the internal parameters used by CFITSIO
+to either scale the data or to represent undefined pixels. Generally
+CFITSIO will scale the data according to the values of the BSCALE and
+BZERO (or TSCALn and TZEROn) keywords, however these routines may be
+used to override the keyword values. This may be useful when one wants
+to read or write the raw unscaled values in the FITS file. Similarly,
+CFITSIO generally uses the value of the BLANK or TNULLn keyword to
+signify an undefined pixel, but these routines may be used to override
+this value. These routines do not create or modify the corresponding
+header keyword values. See Appendix B for the definition of the
+parameters used in these routines.
+
+>1 Reset the scaling factors in the primary array or image extension; does
+ not change the BSCALE and BZERO keyword values and only affects the
+ automatic scaling performed when the data elements are written/read
+ to/from the FITS file. When reading from a FITS file the returned
+ data value = (the value given in the FITS array) * BSCALE + BZERO.
+ The inverse formula is used when writing data values to the FITS
+> file. \label{ffpscl}
+-
+ int fits_set_bscale / ffpscl
+ (fitsfile *fptr, double scale, double zero, > int *status)
+-
+>2 Reset the scaling parameters for a table column; does not change
+ the TSCALn or TZEROn keyword values and only affects the automatic
+ scaling performed when the data elements are written/read to/from
+ the FITS file. When reading from a FITS file the returned data
+ value = (the value given in the FITS array) * TSCAL + TZERO. The
+ inverse formula is used when writing data values to the FITS file.
+> \label{fftscl}
+-
+ int fits_set_tscale / fftscl
+ (fitsfile *fptr, int colnum, double scale, double zero,
+ > int *status)
+-
+>3 Define the integer value to be used to signify undefined pixels in the
+ primary array or image extension. This is only used if BITPIX = 8, 16,
+ or 32. This does not create or change the value of the BLANK keyword in
+> the header. \label{ffpnul}
+-
+ int fits_set_imgnull / ffpnul
+ (fitsfile *fptr, long nulval, > int *status)
+-
+>4 Define the string to be used to signify undefined pixels in
+ a column in an ASCII table. This does not create or change the value
+> of the TNULLn keyword. \label{ffsnul}
+-
+ int fits_set_atblnull / ffsnul
+ (fitsfile *fptr, int colnum, char *nulstr, > int *status)
+-
+>5 Define the value to be used to signify undefined pixels in
+ an integer column in a binary table (where TFORMn = 'B', 'I', or 'J').
+ This does not create or change the value of the TNULLn keyword.
+> \label{fftnul}
+-
+ int fits_set_btblnull / fftnul
+ (fitsfile *fptr, int colnum, long nulval, > int *status)
+-
+
+**E. Specialized FITS Primary Array or IMAGE Extension I/O Routines
+
+These routines read or write data values in the primary data array
+(i.e., the first HDU in the FITS file) or an IMAGE extension.
+Automatic data type conversion is performed for if the data type of the
+FITS array (as defined by the BITPIX keyword) differs from the data
+type of the array in the calling routine. The data values are
+automatically scaled by the BSCALE and BZERO header values as they are
+being written or read from the FITS array. Unlike the basic routines
+described in the previous chapter, most of these routines specifically
+support the FITS random groups format. See Appendix B for the
+definition of the parameters used in these routines.
+
+The more primitive reading and writing routines (i. e., ffppr\_,
+ffppn\_, ffppn, ffgpv\_, or ffgpf\_) simply treat the primary array as
+a long 1-dimensional array of pixels, ignoring the intrinsic
+dimensionality of the array. When dealing with a 2D image, for
+example, the application program must calculate the pixel offset in the
+1-D array that corresponds to any particular X, Y coordinate in the
+image. C programmers should note that the ordering of arrays in FITS
+files, and hence in all the CFITSIO calls, is more similar to the
+dimensionality of arrays in Fortran rather than C. For instance if a
+FITS image has NAXIS1 = 100 and NAXIS2 = 50, then a 2-D array just
+large enough to hold the image should be declared as array[50][100] and
+not as array[100][50].
+
+For convenience, higher-level routines are also provided to specificly
+deal with 2D images (ffp2d\_ and ffg2d\_) and 3D data cubes (ffp3d\_
+and ffg3d\_). The dimensionality of the FITS image is passed by the
+naxis1, naxis2, and naxis3 parameters and the declared dimensions of
+the program array are passed in the dim1 and dim2 parameters. Note
+that the dimensions of the program array may be larger than the
+dimensions of the FITS array. For example if a FITS image with NAXIS1
+= NAXIS2 = 400 is read into a program array which is dimensioned as 512
+x 512 pixels, then the image will just fill the lower left corner of
+the array with pixels in the range 1 - 400 in the X an Y directions.
+This has the effect of taking a contiguous set of pixel value in the
+FITS array and writing them to a non-contiguous array in program memory
+(i.e., there are now some blank pixels around the edge of the image in
+the program array).
+
+The most general set of routines (ffpss\_, ffgsv\_, and ffgsf\_) may be
+used to transfer a rectangular subset of the pixels in a FITS
+N-dimensional image to or from an array which has been declared in the
+calling program. The fpixel and lpixel parameters are integer arrays
+which specify the starting and ending pixel coordinate in each dimension
+(starting with 1, not 0) of the FITS image that is to be read or
+written. It is important to note that these are the starting and
+ending pixels in the FITS image, not in the declared array in the
+program. The array parameter in these routines is treated simply as a
+large one-dimensional array of the appropriate data type containing the
+pixel values; The pixel values in the FITS array are read/written
+from/to this program array in strict sequence without any gaps; it is
+up to the calling routine to correctly interpret the dimensionality of
+this array. The two FITS reading routines (ffgsv\_ and ffgsf\_ ) also
+have an `inc' parameter which defines the data sampling interval in
+each dimension of the FITS array. For example, if inc[0]=2 and
+inc[1]=3 when reading a 2-dimensional FITS image, then only every other
+pixel in the first dimension and every 3rd pixel in the second
+dimension will be returned to the 'array' parameter.
+
+Two types of routines are provided to read the data array which differ in
+the way undefined pixels are handled. The first type of routines (e.g.,
+ffgpv\_) simply return an array of data elements in which undefined
+pixels are set equal to a value specified by the user in the `nulval'
+parameter. An additional feature of these routines is that if the user
+sets nulval = 0, then no checks for undefined pixels will be performed,
+thus reducing the amount of CPU processing. The second type of routines
+(e.g., ffgpf\_) returns the data element array and, in addition, a char
+array that indicates whether the value of the corresponding data pixel
+is undefined (= 1) or defined (= 0). The latter type of routines may
+be more convenient to use in some circumstances, however, it requires
+an additional array of logical values which can be unwieldy when working
+with large data arrays.
+
+>1 Write elements into the FITS data array.
+> \label{ffppr} \label{ffpprx} \label{ffppn} \label{ffppnx}
+-
+ int fits_write_img / ffppr
+ (fitsfile *fptr, int datatype, long firstelem, long nelements,
+ DTYPE *array, int *status);
+
+ int fits_write_img_[byt, sht, usht, int, uint, lng, ulng, lnglng, flt, dbl] /
+ ffppr[b,i,ui,k,uk,j,uj,jj,e,d]
+ (fitsfile *fptr, long group, long firstelem, long nelements,
+ DTYPE *array, > int *status);
+
+ int fits_write_imgnull / ffppn
+ (fitsfile *fptr, int datatype, long firstelem, long nelements,
+ DTYPE *array, DTYPE *nulval, > int *status);
+
+ int fits_write_imgnull_[byt, sht, usht, int, uint, lng, ulng, lnglng, flt, dbl] /
+ ffppn[b,i,ui,k,uk,j,uj,jj,e,d]
+ (fitsfile *fptr, long group, long firstelem,
+ long nelements, DTYPE *array, DTYPE nulval, > int *status);
+-
+>>2 Set data array elements as undefined. \label{ffppru}
+-
+ int fits_write_img_null / ffppru
+ (fitsfile *fptr, long group, long firstelem, long nelements,
+ > int *status)
+-
+>3 Write values into group parameters. This routine only applies
+ to the `Random Grouped' FITS format which has been used for
+ applications in radio interferometry, but is officially deprecated
+> for future use. \label{ffpgpx}
+-
+ int fits_write_grppar_[byt, sht, usht, int, uint, lng, ulng, lnglng, flt, dbl] /
+ ffpgp[b,i,ui,k,uk,j,uj,jj,e,d]
+ (fitsfile *fptr, long group, long firstelem, long nelements,
+ > DTYPE *array, int *status)
+-
+>>4 Write a 2-D or 3-D image into the data array. \label{ffp2dx} \label{ffp3dx}
+-
+ int fits_write_2d_[byt, sht, usht, int, uint, lng, ulng, lnglng, flt, dbl] /
+ ffp2d[b,i,ui,k,uk,j,uj,jj,e,d]
+ (fitsfile *fptr, long group, long dim1, long naxis1,
+ long naxis2, DTYPE *array, > int *status)
+
+ int fits_write_3d_[byt, sht, usht, int, uint, lng, ulng, lnglng, flt, dbl] /
+ ffp3d[b,i,ui,k,uk,j,uj,jj,e,d]
+ (fitsfile *fptr, long group, long dim1, long dim2,
+ long naxis1, long naxis2, long naxis3, DTYPE *array, > int *status)
+-
+>>5 Write an arbitrary data subsection into the data array. \label{ffpssx}
+-
+ int fits_write_subset_[byt, sht, usht, int, uint, lng, ulng, lnglng, flt, dbl] /
+ ffpss[b,i,ui,k,uk,j,uj,jj,e,d]
+ (fitsfile *fptr, long group, long naxis, long *naxes,
+ long *fpixel, long *lpixel, DTYPE *array, > int *status)
+-
+>6 Read elements from the FITS data array.
+> \label{ffgpv} \label{ffgpvx} \label{ffgpf} \label{ffgpfx}
+-
+ int fits_read_img / ffgpv
+ (fitsfile *fptr, int datatype, long firstelem, long nelements,
+ DTYPE *nulval, > DTYPE *array, int *anynul, int *status)
+
+ int fits_read_img_[byt, sht, usht, int, uint, lng, ulng, lnglng, flt, dbl] /
+ ffgpv[b,i,ui,k,uk,j,uj,jj,e,d]
+ (fitsfile *fptr, long group, long firstelem, long nelements,
+ DTYPE nulval, > DTYPE *array, int *anynul, int *status)
+
+ int fits_read_imgnull / ffgpf
+ (fitsfile *fptr, int datatype, long firstelem, long nelements,
+ > DTYPE *array, char *nullarray, int *anynul, int *status)
+
+ int fits_read_imgnull_[byt, sht, usht, int, uint, lng, ulng, flt, dbl] /
+ ffgpf[b,i,ui,k,uk,j,uj,jj,e,d]
+ (fitsfile *fptr, long group, long firstelem, long nelements,
+ > DTYPE *array, char *nullarray, int *anynul, int *status)
+-
+>7 Read values from group parameters. This routine only applies
+ to the `Random Grouped' FITS format which has been used for
+ applications in radio interferometry, but is officially deprecated
+> for future use. \label{ffggpx}
+-
+ int fits_read_grppar_[byt, sht, usht, int, uint, lng, ulng, lnglng, flt, dbl] /
+ ffggp[b,i,ui,k,uk,j,uj,jj,e,d]
+ (fitsfile *fptr, long group, long firstelem, long nelements,
+ > DTYPE *array, int *status)
+-
+>8 Read 2-D or 3-D image from the data array. Undefined
+ pixels in the array will be set equal to the value of 'nulval',
+ unless nulval=0 in which case no testing for undefined pixels will
+> be performed. \label{ffg2dx} \label{ffg3dx}
+-
+ int fits_read_2d_[byt, sht, usht, int, uint, lng, ulng, lnglng, flt, dbl] /
+ ffg2d[b,i,ui,k,uk,j,uj,jj,e,d]
+ (fitsfile *fptr, long group, DTYPE nulval, long dim1, long naxis1,
+ long naxis2, > DTYPE *array, int *anynul, int *status)
+
+ int fits_read_3d_[byt, sht, usht, int, uint, lng, ulng, lnglng, flt, dbl] /
+ ffg3d[b,i,ui,k,uk,j,uj,jj,e,d]
+ (fitsfile *fptr, long group, DTYPE nulval, long dim1,
+ long dim2, long naxis1, long naxis2, long naxis3,
+ > DTYPE *array, int *anynul, int *status)
+-
+>9 Read an arbitrary data subsection from the data array.
+> \label{ffgsvx} \label{ffgsfx}
+-
+ int fits_read_subset_[byt, sht, usht, int, uint, lng, ulng, lnglng, flt, dbl] /
+ ffgsv[b,i,ui,k,uk,j,uj,jj,e,d]
+ (fitsfile *fptr, int group, int naxis, long *naxes,
+ long *fpixel, long *lpixel, long *inc, DTYPE nulval,
+ > DTYPE *array, int *anynul, int *status)
+
+ int fits_read_subsetnull_[byt, sht, usht, int, uint, lng, ulng, lnglng, flt, dbl] /
+ ffgsf[b,i,ui,k,uk,j,uj,jj,e,d]
+ (fitsfile *fptr, int group, int naxis, long *naxes,
+ long *fpixel, long *lpixel, long *inc, > DTYPE *array,
+ char *nullarray, int *anynul, int *status)
+-
+
+**F. Specialized FITS ASCII and Binary Table Routines
+
+***1. General Column Routines
+
+>1 Get information about an existing ASCII or binary table column. A null
+ pointer may be given for any of the output parameters that are not
+ needed. DATATYPE is a character string which returns the data type
+ of the column as defined by the TFORMn keyword (e.g., 'I', 'J','E',
+ 'D', etc.). In the case of an ASCII character column, typecode
+ will have a value of the form 'An' where 'n' is an integer
+ expressing the width of the field in characters. For example, if
+ TFORM = '160A8' then ffgbcl will return typechar='A8' and
+ repeat=20. All the returned parameters are scalar quantities.
+> \label{ffgacl} \label{ffgbcl}
+-
+ int fits_get_acolparms / ffgacl
+ (fitsfile *fptr, int colnum, > char *ttype, long *tbcol,
+ char *tunit, char *tform, double *scale, double *zero,
+ char *nulstr, char *tdisp, int *status)
+
+ int fits_get_bcolparms / ffgbcl
+ (fitsfile *fptr, int colnum, > char *ttype, char *tunit,
+ char *typechar, long *repeat, double *scale, double *zero,
+ long *nulval, char *tdisp, int *status)
+-
+>2 Return optimal number of rows to read or write at one time for
+ maximum I/O efficiency. Refer to the
+ ``Optimizing Code'' section in Chapter 5 for more discussion on how
+> to use this routine. \label{ffgrsz}
+-
+ int fits_get_rowsize / ffgrsz
+ (fitsfile *fptr, long *nrows, *status)
+-
+>3 Define the zero indexed byte offset of the 'heap' measured from
+ the start of the binary table data. By default the heap is assumed
+ to start immediately following the regular table data, i.e., at
+ location NAXIS1 x NAXIS2. This routine is only relevant for
+ binary tables which contain variable length array columns (with
+ TFORMn = 'Pt'). This routine also automatically writes
+ the value of theap to a keyword in the extension header. This
+ routine must be called after the required keywords have been
+ written (with ffphbn)
+> but before any data is written to the table. \label{ffpthp}
+-
+ int fits_write_theap / ffpthp
+ (fitsfile *fptr, long theap, > int *status)
+-
+>4 Test the contents of the binary table variable array heap, returning
+ the size of the heap, the number of unused bytes that are not currently
+ pointed to by any of the descriptors, and the number of bytes which are
+ pointed to by multiple descriptors. It also returns valid = FALSE if
+ any of the descriptors point to invalid addresses out of range of the
+> heap. \label{fftheap}
+-
+ int fits_test_heap / fftheap
+ (fitsfile *fptr, > long *heapsize, long *unused, long *overlap,
+ int *validheap, int *status)
+-
+>5 Re-pack the vectors in the binary table variable array heap to recover
+ any unused space. Normally, when a vector in a variable length
+ array column is rewritten the previously written array remains in
+ the heap as wasted unused space. This routine will repack the
+ arrays that are still in use, thus eliminating any bytes in the
+ heap that are no longer in use. Note that if several vectors point
+ to the same bytes in the heap, then this routine will make
+ duplicate copies of the bytes for each vector, which will actually
+> expand the size of the heap. \label{ffcmph}
+-
+ int fits_compress_heap / ffcmph
+ (fitsfile *fptr, > int *status)
+-
+
+***2. Low-Level Table Access Routines
+
+The following 2 routines provide low-level access to the data in ASCII
+or binary tables and are mainly useful as an efficient way to copy all
+or part of a table from one location to another. These routines simply
+read or write the specified number of consecutive bytes in an ASCII or
+binary table, without regard for column boundaries or the row length in
+the table. These routines do not perform any machine dependent data
+conversion or byte swapping. See Appendix B for the definition of the
+parameters used in these routines.
+
+>1 Read or write a consecutive array of bytes from an ASCII or binary
+> table \label{ffgtbb} \label{ffptbb}
+-
+ int fits_read_tblbytes / ffgtbb
+ (fitsfile *fptr, long firstrow, long firstchar, long nchars,
+ > unsigned char *values, int *status)
+
+ int fits_write_tblbytes / ffptbb
+ (fitsfile *fptr, long firstrow, long firstchar, long nchars,
+ unsigned char *values, > int *status)
+-
+
+***3. Write Column Data Routines
+
+>1 Write elements into an ASCII or binary table column (in the CDU).
+ The data type of the array is implied by the suffix of the
+> routine name. \label{ffpcls}
+-
+ int fits_write_col_str / ffpcls
+ (fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelements, char **array, > int *status)
+
+ int fits_write_col_[log,byt,sht,usht,int,uint,lng,ulng,lnglng,flt,dbl,cmp,dblcmp] /
+ ffpcl[l,b,i,ui,k,uk,j,uj,jj,e,d,c,m]
+ (fitsfile *fptr, int colnum, long firstrow,
+ long firstelem, long nelements, DTYPE *array, > int *status)
+-
+>2 Write elements into an ASCII or binary table column
+ substituting the appropriate FITS null value for any elements that
+ are equal to the nulval parameter. This routines must not be used to
+> write to variable length array columns. \label{ffpcnx}
+-
+ int fits_write_colnull_[log, byt, sht, usht, int, uint, lng, ulng, lnglng, flt, dbl] /
+ ffpcn[l,b,i,ui,k,uk,j,uj,jj,e,d]
+ (fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelements, DTYPE *array, DTYPE nulval, > int *status)
+-
+>3 Write string elements into a binary table column (in the CDU)
+ substituting the FITS null value for any elements that
+ are equal to the nulstr string. This routine must NOT be
+> used to write to variable length array columns. \label{ffpcns}
+-
+ int fits_write_colnull_str / ffpcns
+ (fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelements, char **array, char *nulstr, > int *status)
+-
+>4 Write bit values into a binary byte ('B') or bit ('X') table column (in
+ the CDU). Larray is an array of characters corresponding to the
+ sequence of bits to be written. If an element of larray is true
+ (not equal to zero) then the corresponding bit in the FITS table is
+ set to 1, otherwise the bit is set to 0. The 'X' column in a FITS
+ table is always padded out to a multiple of 8 bits where the bit
+ array starts with the most significant bit of the byte and works
+ down towards the 1's bit. For example, a '4X' array, with the
+ first bit = 1 and the remaining 3 bits = 0 is equivalent to the 8-bit
+ unsigned byte decimal value of 128 ('1000 0000B'). In the case of
+ 'X' columns, CFITSIO can write to all 8 bits of each byte whether
+ they are formally valid or not. Thus if the column is defined as
+ '4X', and one calls ffpclx with firstbit=1 and nbits=8, then all
+ 8 bits will be written into the first byte (as opposed to writing
+ the first 4 bits into the first row and then the next 4 bits into
+ the next row), even though the last 4 bits of each byte are formally
+ not defined and should all be set = 0. It should also be noted that
+ it is more efficient to write 'X' columns an entire byte at a time,
+ instead of bit by bit. Any of the CFITSIO routines that write to
+ columns (e.g. fits\_write\_col\_byt) may be used for this purpose.
+ These routines will interpret 'X' columns as though they were 'B'
+ columns (e.g., '1X' through '8X' is equivalent
+> to '1B', and '9X' through '16X' is equivalent to '2B'). \label{ffpclx}
+-
+ int fits_write_col_bit / ffpclx
+ (fitsfile *fptr, int colnum, long firstrow, long firstbit,
+ long nbits, char *larray, > int *status)
+-
+>5 Write the descriptor for a variable length column in a binary table.
+ This routine can be used in conjunction with ffgdes to enable
+ 2 or more arrays to point to the same storage location to save
+> storage space if the arrays are identical. \label{ffpdes}
+-
+ int fits_write_descript / ffpdes
+ (fitsfile *fptr, int colnum, long rownum, long repeat,
+ long offset, > int *status)
+-
+***4. Read Column Data Routines
+
+Two types of routines are provided to get the column data which differ
+in the way undefined pixels are handled. The first set of routines
+(ffgcv) simply return an array of data elements in which undefined
+pixels are set equal to a value specified by the user in the 'nullval'
+parameter. If nullval = 0, then no checks for undefined pixels will be
+performed, thus increasing the speed of the program. The second set of
+routines (ffgcf) returns the data element array and in addition a
+logical array of flags which defines whether the corresponding data
+pixel is undefined. See Appendix B for the definition of the
+parameters used in these routines.
+
+ Any column, regardless of it's intrinsic data type, may be read as a
+ string. It should be noted however that reading a numeric column as
+ a string is 10 - 100 times slower than reading the same column as a number
+ due to the large overhead in constructing the formatted strings.
+ The display format of the returned strings will be
+ determined by the TDISPn keyword, if it exists, otherwise by the
+ data type of the column. The length of the returned strings (not
+ including the null terminating character) can be determined with
+ the fits\_get\_col\_display\_width routine. The following TDISPn
+ display formats are currently supported:
+-
+ Iw.m Integer
+ Ow.m Octal integer
+ Zw.m Hexadecimal integer
+ Fw.d Fixed floating point
+ Ew.d Exponential floating point
+ Dw.d Exponential floating point
+ Gw.d General; uses Fw.d if significance not lost, else Ew.d
+-
+ where w is the width in characters of the displayed values, m is
+ the minimum number of digits displayed, and d is the number of
+ digits to the right of the decimal. The .m field is optional.
+
+>1 Read elements from an ASCII or binary table column (in the CDU). These
+ routines return the values of the table column array elements. Undefined
+ array elements will be returned with a value = nulval, unless nulval = 0
+ (or = ' ' for ffgcvs) in which case no checking for undefined values will
+ be performed. The ANYF parameter is set to true if any of the returned
+> elements are undefined. \label{ffgcvx}
+-
+ int fits_read_col_str / ffgcvs
+ (fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelements, char *nulstr, > char **array, int *anynul,
+ int *status)
+
+ int fits_read_col_[log,byt,sht,usht,int,uint,lng,ulng, lnglng, flt, dbl, cmp, dblcmp] /
+ ffgcv[l,b,i,ui,k,uk,j,uj,jj,e,d,c,m]
+ (fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelements, DTYPE nulval, > DTYPE *array, int *anynul,
+ int *status)
+-
+>2 Read elements and null flags from an ASCII or binary table column (in the
+ CHDU). These routines return the values of the table column array elements.
+ Any undefined array elements will have the corresponding nullarray element
+ set equal to TRUE. The anynul parameter is set to true if any of the
+> returned elements are undefined. \label{ffgcfx}
+-
+ int fits_read_colnull_str / ffgcfs
+ (fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelements, > char **array, char *nullarray, int *anynul,
+ int *status)
+
+ int fits_read_colnull_[log,byt,sht,usht,int,uint,lng,ulng,lnglng,flt,dbl,cmp,dblcmp] /
+ ffgcf[l,b,i,ui,k,uk,j,uj,jj,e,d,c,m]
+ (fitsfile *fptr, int colnum, long firstrow,
+ long firstelem, long nelements, > DTYPE *array,
+ char *nullarray, int *anynul, int *status)
+-
+>3 Read an arbitrary data subsection from an N-dimensional array
+ in a binary table vector column. Undefined pixels
+ in the array will be set equal to the value of 'nulval',
+ unless nulval=0 in which case no testing for undefined pixels will
+ be performed. The first and last rows in the table to be read
+ are specified by fpixel(naxis+1) and lpixel(naxis+1), and hence
+ are treated as the next higher dimension of the FITS N-dimensional
+ array. The INC parameter specifies the sampling interval in
+> each dimension between the data elements that will be returned. \label{ffgsvx2}
+-
+ int fits_read_subset_[byt, sht, usht, int, uint, lng, ulng, lnglng, flt, dbl] /
+ ffgsv[b,i,ui,k,uk,j,uj,jj,e,d]
+ (fitsfile *fptr, int colnum, int naxis, long *naxes, long *fpixel,
+ long *lpixel, long *inc, DTYPE nulval, > DTYPE *array, int *anynul,
+ int *status)
+-
+>4 Read an arbitrary data subsection from an N-dimensional array
+ in a binary table vector column. Any Undefined
+ pixels in the array will have the corresponding 'nullarray'
+ element set equal to TRUE. The first and last rows in the table
+ to be read are specified by fpixel(naxis+1) and lpixel(naxis+1),
+ and hence are treated as the next higher dimension of the FITS
+ N-dimensional array. The INC parameter specifies the sampling
+ interval in each dimension between the data elements that will be
+> returned. \label{ffgsfx2}
+-
+ int fits_read_subsetnull_[byt, sht, usht, int, uint, lng, ulng, lnglng, flt, dbl] /
+ ffgsf[b,i,ui,k,uk,j,uj,jj,e,d]
+ (fitsfile *fptr, int colnum, int naxis, long *naxes,
+ long *fpixel, long *lpixel, long *inc, > DTYPE *array,
+ char *nullarray, int *anynul, int *status)
+-
+>5 Read bit values from a byte ('B') or bit (`X`) table column (in the
+ CDU). Larray is an array of logical values corresponding to the
+ sequence of bits to be read. If larray is true then the
+ corresponding bit was set to 1, otherwise the bit was set to 0.
+ The 'X' column in a FITS table is always padded out to a multiple
+ of 8 bits where the bit array starts with the most significant bit
+ of the byte and works down towards the 1's bit. For example, a
+ '4X' array, with the first bit = 1 and the remaining 3 bits = 0 is
+ equivalent to the 8-bit unsigned byte value of 128.
+ Note that in the case of 'X' columns, CFITSIO can read all 8 bits
+ of each byte whether they are formally valid or not. Thus if the
+ column is defined as '4X', and one calls ffgcx with firstbit=1 and
+ nbits=8, then all 8 bits will be read from the first byte (as
+ opposed to reading the first 4 bits from the first row and then the
+ first 4 bits from the next row), even though the last 4 bits of
+ each byte are formally not defined. It should also be noted that
+ it is more efficient to read 'X' columns an entire byte at a time,
+ instead of bit by bit. Any of the CFITSIO routines that read
+ columns (e.g. fits\_read\_col\_byt) may be used for this
+ purpose. These routines will interpret 'X' columns as though they
+ were 'B' columns (e.g., '8X' is equivalent to '1B', and '16X' is
+> equivalent to '2B'). \label{ffgcx}
+-
+ int fits_read_col_bit / ffgcx
+ (fitsfile *fptr, int colnum, long firstrow, long firstbit,
+ long nbits, > char *larray, int *status)
+-
+>6 Read any consecutive set of bits from an 'X' or 'B' column and
+ interpret them as an unsigned n-bit integer. nbits must be less
+ than 16 or 32 in ffgcxui and ffgcxuk, respectively. If nrows
+ is greater than 1, then the same set of bits will be read from
+ each row, starting with firstrow. The bits are numbered with
+ 1 = the most significant bit of the first element of the column.
+> \label{ffgcxui}
+-
+ int fits_read_col_bit_[usht, uint] / ffgcx[ui,uk]
+ (fitsfile *fptr, int colnum, long firstrow, long, nrows,
+ long firstbit, long nbits, > DTYPE *array, int *status)
+-
+>7 Return the descriptor for a variable length column in a binary table.
+ The descriptor consists of 2 integer parameters: the number of elements
+ in the array and the starting offset relative to the start of the heap.
+ The first routine returns a single descriptor whereas the second routine
+ returns the descriptors for a range of rows in the table.
+> \label{ffgdes}
+-
+ int fits_read_descript / ffgdes
+ (fitsfile *fptr, int colnum, long rownum, > long *repeat,
+ long *offset, int *status)
+
+ int fits_read_descripts / ffgdess
+ (fitsfile *fptr, int colnum, long firstrow, long nrows > long *repeat,
+ long *offset, int *status)
+-
+
+*X. Extended File Name Syntax
+
+**A. Overview
+
+CFITSIO supports an extended syntax when specifying the name of the
+data file to be opened or created that includes the following
+features:
+
+\begin{itemize}
+\item
+CFITSIO can read IRAF format images which have header file names that
+end with the '.imh' extension, as well as reading and writing FITS
+files, This feature is implemented in CFITSIO by first converting the
+IRAF image into a temporary FITS format file in memory, then opening
+the FITS file. Any of the usual CFITSIO routines then may be used to
+read the image header or data. Similarly, raw binary data arrays can
+be read by converting them on the fly into virtual FITS images.
+
+\item
+FITS files on the internet can be read (and sometimes written) using the FTP,
+HTTP, or ROOT protocols.
+
+\item
+FITS files can be piped between tasks on the stdin and stdout streams.
+
+\item
+FITS files can be read and written in shared memory. This can
+potentially achieve better data I/O performance compared to reading and
+writing the same FITS files on magnetic disk.
+
+\item
+Compressed FITS files in gzip or Unix COMPRESS format can be directly read.
+
+\item
+Output FITS files can be written directly in compressed gzip format,
+thus saving disk space.
+
+\item
+FITS table columns can be created, modified, or deleted 'on-the-fly' as
+the table is opened by CFITSIO. This creates a virtual FITS file containing
+the modifications that is then opened by the application program.
+
+\item
+Table rows may be selected, or filtered out, on the fly when the table
+is opened by CFITSIO, based on an user-specified expression.
+Only rows for which the expression evaluates to 'TRUE' are retained
+in the copy of the table that is opened by the application program.
+
+\item
+Histogram images may be created on the fly by binning the values in
+table columns, resulting in a virtual N-dimensional FITS image. The
+application program then only sees the FITS image (in the primary
+array) instead of the original FITS table.
+\end{itemize}
+
+The latter 3 table filtering features in particular add very powerful
+data processing capabilities directly into CFITSIO, and hence into
+every task that uses CFITSIO to read or write FITS files. For example,
+these features transform a very simple program that just copies an
+input FITS file to a new output file (like the `fitscopy' program that
+is distributed with CFITSIO) into a multipurpose FITS file processing
+tool. By appending fairly simple qualifiers onto the name of the input
+FITS file, the user can perform quite complex table editing operations
+(e.g., create new columns, or filter out rows in a table) or create
+FITS images by binning or histogramming the values in table columns.
+In addition, these functions have been coded using new state-of-the art
+algorithms that are, in some cases, 10 - 100 times faster than previous
+widely used implementations.
+
+Before describing the complete syntax for the extended FITS file names
+in the next section, here are a few examples of FITS file names that
+give a quick overview of the allowed syntax:
+
+\begin{itemize}
+\item
+{\tt myfile.fits}: the simplest case of a FITS file on disk in the current
+directory.
+
+\item
+{\tt myfile.imh}: opens an IRAF format image file and converts it on the
+fly into a temporary FITS format image in memory which can then be read with
+any other CFITSIO routine.
+
+\item
+{\tt rawfile.dat[i512,512]}: opens a raw binary data array (a 512 x 512
+short integer array in this case) and converts it on the fly into a
+temporary FITS format image in memory which can then be read with any
+other CFITSIO routine.
+
+\item
+{\tt myfile.fits.gz}: if this is the name of a new output file, the '.gz'
+suffix will cause it to be compressed in gzip format when it is written to
+disk.
+
+\item
+{\tt myfile.fits.gz[events, 2]}: opens and uncompresses the gzipped file
+myfile.fits then moves to the extension with the keywords EXTNAME
+= 'EVENTS' and EXTVER = 2.
+
+\item
+{\tt -}: a dash (minus sign) signifies that the input file is to be read
+from the stdin file stream, or that the output file is to be written to
+the stdout stream.
+
+\item
+{\tt ftp://legacy.gsfc.nasa.gov/test/vela.fits}: FITS files in any ftp
+archive site on the internet may be directly opened with read-only
+access.
+
+\item
+{\tt http://legacy.gsfc.nasa.gov/software/test.fits}: any valid URL to a
+FITS file on the Web may be opened with read-only access.
+
+\item
+{\tt root://legacy.gsfc.nasa.gov/test/vela.fits}: similar to ftp access
+except that it provides write as well as read access to the files
+across the network. This uses the root protocol developed at CERN.
+
+\item
+{\tt shmem://h2[events]}: opens the FITS file in a shared memory segment and
+moves to the EVENTS extension.
+
+\item
+{\tt mem://}: creates a scratch output file in core computer memory. The
+resulting 'file' will disappear when the program exits, so this
+is mainly useful for testing purposes when one does not want a
+permanent copy of the output file.
+
+\item
+{\tt myfile.fits[3; Images(10)]}: opens a copy of the image contained in the
+10th row of the 'Images' column in the binary table in the 3th extension
+of the FITS file. The virtual file that is opened by the application just
+contains this single image in the primary array.
+
+\item
+{\tt myfile.fits[1:512:2, 1:512:2]}: opens a section of the input image
+ranging from the 1st to the 512th pixel in X and Y, and selects every
+second pixel in both dimensions, resulting in a 256 x 256 pixel input image
+in this case.
+
+\item
+{\tt myfile.fits[EVENTS][col Rad = sqrt(X**2 + Y**2)]}: creates and opens
+a virtual file on the fly that is identical to
+myfile.fits except that it will contain a new column in the EVENTS
+extension called 'Rad' whose value is computed using the indicated
+expression which is a function of the values in the X and Y columns.
+
+\item
+{\tt myfile.fits[EVENTS][PHA > 5]}: creates and opens a virtual FITS
+files that is identical to 'myfile.fits' except that the EVENTS table
+will only contain the rows that have values of the PHA column greater
+than 5. In general, any arbitrary boolean expression using a C or
+Fortran-like syntax, which may combine AND and OR operators,
+may be used to select rows from a table.
+
+\item
+{\tt myfile.fits[EVENTS][bin (X,Y)=1,2048,4]}: creates a temporary FITS
+primary array image which is computed on the fly by binning (i.e,
+computing the 2-dimensional histogram) of the values in the X and Y
+columns of the EVENTS extension. In this case the X and Y coordinates
+range from 1 to 2048 and the image pixel size is 4 units in both
+dimensions, so the resulting image is 512 x 512 pixels in size.
+
+\item
+The final example combines many of these feature into one complex
+expression (it is broken into several lines for clarity):
+-
+ ftp://legacy.gsfc.nasa.gov/data/sample.fits.gz[EVENTS]
+ [col phacorr = pha * 1.1 - 0.3][phacorr >= 5.0 && phacorr <= 14.0]
+ [bin (X,Y)=32]
+-
+In this case, CFITSIO (1) copies and uncompresses the FITS file from
+the ftp site on the legacy machine, (2) moves to the 'EVENTS'
+extension, (3) calculates a new column called 'phacorr', (4) selects
+the rows in the table that have phacorr in the range 5 to 14, and
+finally (5) bins the remaining rows on the X and Y column coordinates,
+using a pixel size = 32 to create a 2D image. All this processing is
+completely transparent to the application program, which simply sees
+the final 2-D image in the primary array of the opened file.
+\end{itemize}
+
+The full extended CFITSIO FITS file name can contain several different
+components depending on the context. These components are described in
+the following sections:
+-
+When creating a new file:
+ filetype://BaseFilename(templateName)[compress]
+
+When opening an existing primary array or image HDU:
+ filetype://BaseFilename(outName)[HDUlocation][ImageSection]
+
+When opening an existing table HDU:
+ filetype://BaseFilename(outName)[HDUlocation][colFilter][rowFilter][binSpec]
+-
+The filetype, BaseFilename, outName, HDUlocation, and ImageSection
+components, if present, must be given in that order, but the colFilter,
+rowFilter, and binSpec specifiers may follow in any order. Regardless
+of the order, however, the colFilter specifier, if present, will be
+processed first by CFITSIO, followed by the rowFilter specifier, and
+finally by the binSpec specifier.
+
+**A. Filetype
+
+The type of file determines the medium on which the file is located
+(e.g., disk or network) and, hence, which internal device driver is used by
+CFITSIO to read and/or write the file. Currently supported types are
+-
+ file:// - file on local magnetic disk (default)
+ ftp:// - a readonly file accessed with the anonymous FTP protocol.
+ It also supports ftp://username:password@hostname/...
+ for accessing password-protected ftp sites.
+ http:// - a readonly file accessed with the HTTP protocol. It
+ does not support username:password like the ftp driver.
+ Proxy HTTP survers are supported using the http_proxy
+ environment variable.
+ root:// - uses the CERN root protocol for writing as well as
+ reading files over the network.
+ shmem:// - opens or creates a file which persists in the computer's
+ shared memory.
+ mem:// - opens a temporary file in core memory. The file
+ disappears when the program exits so this is mainly
+ useful for test purposes when a permanent output file
+ is not desired.
+-
+If the filetype is not specified, then type file:// is assumed.
+The double slashes '//' are optional and may be omitted in most cases.
+
+***1. Notes about HTTP proxy servers
+
+A proxy HTTP server may be used by defining the address (URL) and port
+number of the proxy server with the http\_proxy environment variable.
+For example
+-
+ setenv http_proxy http://heasarc.gsfc.nasa.gov:3128
+-
+will cause CFITSIO to use port 3128 on the heasarc proxy server whenever
+reading a FITS file with HTTP.
+
+***2. Notes about the root filetype
+
+The original rootd server can be obtained from:
+\verb-ftp://root.cern.ch/root/rootd.tar.gz-
+but, for it to work correctly with CFITSIO one has to use a modified
+version which supports a command to return the length of the file.
+This modified version is available in rootd subdirectory
+in the CFITSIO ftp area at
+-
+ ftp://legacy.gsfc.nasa.gov/software/fitsio/c/root/rootd.tar.gz.
+-
+
+This small server is started either by inetd when a client requests a
+connection to a rootd server or by hand (i.e. from the command line).
+The rootd server works with the ROOT TNetFile class. It allows remote
+access to ROOT database files in either read or write mode. By default
+TNetFile assumes port 432 (which requires rootd to be started as root).
+To run rootd via inetd add the following line to /etc/services:
+-
+ rootd 432/tcp
+-
+and to /etc/inetd.conf, add the following line:
+-
+ rootd stream tcp nowait root /user/rdm/root/bin/rootd rootd -i
+-
+Force inetd to reread its conf file with \verb+kill -HUP <pid inetd>+.
+You can also start rootd by hand running directly under your private
+account (no root system privileges needed). For example to start
+rootd listening on port 5151 just type: \verb+rootd -p 5151+
+Notice that no \& is needed. Rootd will go into background by itself.
+-
+ Rootd arguments:
+ -i says we were started by inetd
+ -p port# specifies a different port to listen on
+ -d level level of debug info written to syslog
+ 0 = no debug (default)
+ 1 = minimum
+ 2 = medium
+ 3 = maximum
+-
+Rootd can also be configured for anonymous usage (like anonymous ftp).
+To setup rootd to accept anonymous logins do the following (while being
+logged in as root):
+-
+ - Add the following line to /etc/passwd:
+
+ rootd:*:71:72:Anonymous rootd:/var/spool/rootd:/bin/false
+
+ where you may modify the uid, gid (71, 72) and the home directory
+ to suite your system.
+
+ - Add the following line to /etc/group:
+
+ rootd:*:72:rootd
+
+ where the gid must match the gid in /etc/passwd.
+
+ - Create the directories:
+
+ mkdir /var/spool/rootd
+ mkdir /var/spool/rootd/tmp
+ chmod 777 /var/spool/rootd/tmp
+
+ Where /var/spool/rootd must match the rootd home directory as
+ specified in the rootd /etc/passwd entry.
+
+ - To make writeable directories for anonymous do, for example:
+
+ mkdir /var/spool/rootd/pub
+ chown rootd:rootd /var/spool/rootd/pub
+-
+That's all. Several additional remarks: you can login to an anonymous
+server either with the names "anonymous" or "rootd". The password should
+be of type user@host.do.main. Only the @ is enforced for the time
+being. In anonymous mode the top of the file tree is set to the rootd
+home directory, therefore only files below the home directory can be
+accessed. Anonymous mode only works when the server is started via
+inetd.
+
+***3. Notes about the shmem filetype:
+
+Shared memory files are currently supported on most Unix platforms,
+where the shared memory segments are managed by the operating system
+kernel and `live' independently of processes. They are not deleted (by
+default) when the process which created them terminates, although they
+will disappear if the system is rebooted. Applications can create
+shared memory files in CFITSIO by calling:
+-
+ fit_create_file(&fitsfileptr, "shmem://h2", &status);
+-
+where the root `file' names are currently restricted to be 'h0', 'h1',
+'h2', 'h3', etc., up to a maximum number defined by the the value of
+SHARED\_MAXSEG (equal to 16 by default). This is a prototype
+implementation of the shared memory interface and a more robust
+interface, which will have fewer restrictions on the number of files
+and on their names, may be developed in the future.
+
+When opening an already existing FITS file in shared memory one calls
+the usual CFITSIO routine:
+-
+ fits_open_file(&fitsfileptr, "shmem://h7", mode, &status)
+-
+The file mode can be READWRITE or READONLY just as with disk files.
+More than one process can operate on READONLY mode files at the same
+time. CFITSIO supports proper file locking (both in READONLY and
+READWRITE modes), so calls to fits\_open\_file may be locked out until
+another other process closes the file.
+
+When an application is finished accessing a FITS file in a shared
+memory segment, it may close it (and the file will remain in the
+system) with fits\_close\_file, or delete it with fits\_delete\_file.
+Physical deletion is postponed until the last process calls
+ffclos/ffdelt. fits\_delete\_file tries to obtain a READWRITE lock on
+the file to be deleted, thus it can be blocked if the object was not
+opened in READWRITE mode.
+
+A shared memory management utility program called `smem', is included
+with the CFITSIO distribution. It can be built by typing `make smem';
+then type `smem -h' to get a list of valid options. Executing smem
+without any options causes it to list all the shared memory segments
+currently residing in the system and managed by the shared memory
+driver. To get a list of all the shared memory objects, run the system
+utility program `ipcs [-a]'.
+
+**B. Base Filename
+
+The base filename is the name of the file optionally including the
+director/subdirectory path, and in the case of `ftp', `http', and `root'
+filetypes, the machine identifier. Examples:
+-
+ myfile.fits
+ !data.fits
+ /data/myfile.fits
+ fits.gsfc.nasa.gov/ftp/sampledata/myfile.fits.gz
+-
+
+When creating a new output file on magnetic disk (of type file://) if
+the base filename begins with an exclamation point (!) then any
+existing file with that same basename will be deleted prior to creating
+the new FITS file. Otherwise if the file to be created already exists,
+then CFITSIO will return an error and will not overwrite the existing
+file. Note that the exclamation point, '!', is a special UNIX
+character, so if it is used on the command line rather than entered at
+a task prompt, it must be preceded by a backslash to force the UNIX
+shell to pass it verbatim to the application program.
+
+If the output disk file name ends with the suffix '.gz', then CFITSIO
+will compress the file using the gzip compression algorithm before
+writing it to disk. This can reduce the amount of disk space used by
+the file. Note that this feature requires that the uncompressed file
+be constructed in memory before it is compressed and written to disk,
+so it can fail if there is insufficient available memory.
+
+An input FITS file may be compressed with the gzip or Unix compress
+algorithms, in which case CFITSIO will uncompress the file on the fly
+into a temporary file (in memory or on disk). Compressed files may
+only be opened with read-only permission. When specifying the name of
+a compressed FITS file it is not necessary to append the file suffix
+(e.g., `.gz' or `.Z'). If CFITSIO cannot find the input file name
+without the suffix, then it will automatically search for a compressed
+file with the same root name. In the case of reading ftp and http type
+files, CFITSIO generally looks for a compressed version of the file
+first, before trying to open the uncompressed file. By default,
+CFITSIO copies (and uncompressed if necessary) the ftp or http FITS
+file into memory on the local machine before opening it. This will
+fail if the local machine does not have enough memory to hold the whole
+FITS file, so in this case, the output filename specifier (see the next
+section) can be used to further control how CFITSIO reads ftp and http
+files.
+
+If the input file is an IRAF image file (*.imh file) then CFITSIO will
+automatically convert it on the fly into a virtual FITS image before it
+is opened by the application program. IRAF images can only be opened
+with READONLY file access.
+
+Similarly, if the input file is a raw binary data array, then CFITSIO
+will convert it on the fly into a virtual FITS image with the basic set
+of required header keywords before it is opened by the application
+program (with READONLY access). In this case the data type and
+dimensions of the image must be specified in square brackets following
+the filename (e.g. rawfile.dat[ib512,512]). The first character (case
+insensitive) defines the data type of the array:
+-
+ b 8-bit unsigned byte
+ i 16-bit signed integer
+ u 16-bit unsigned integer
+ j 32-bit signed integer
+ r or f 32-bit floating point
+ d 64-bit floating point
+-
+An optional second character specifies the byte order of the array
+values: b or B indicates big endian (as in FITS files and the native
+format of SUN UNIX workstations and Mac PCs) and l or L indicates
+little endian (native format of DEC OSF workstations and IBM PCs). If
+this character is omitted then the array is assumed to have the native
+byte order of the local machine. These data type characters are then
+followed by a series of one or more integer values separated by commas
+which define the size of each dimension of the raw array. Arrays with
+up to 5 dimensions are currently supported. Finally, a byte offset to
+the position of the first pixel in the data file may be specified by
+separating it with a ':' from the last dimension value. If omitted, it
+is assumed that the offset = 0. This parameter may be used to skip
+over any header information in the file that precedes the binary data.
+Further examples:
+-
+ raw.dat[b10000] 1-dimensional 10000 pixel byte array
+ raw.dat[rb400,400,12] 3-dimensional floating point big-endian array
+ img.fits[ib512,512:2880] reads the 512 x 512 short integer array in
+ a FITS file, skipping over the 2880 byte header
+-
+
+One special case of input file is where the filename = `-' (a dash or
+minus sign) or 'stdin' or 'stdout', which signifies that the input file
+is to be read from the stdin stream, or written to the stdout stream if
+a new output file is being created. In the case of reading from stdin,
+CFITSIO first copies the whole stream into a temporary FITS file (in
+memory or on disk), and subsequent reading of the FITS file occurs in
+this copy. When writing to stdout, CFITSIO first constructs the whole
+file in memory (since random access is required), then flushes it out
+to the stdout stream when the file is closed. In addition, if the
+output filename = '-.gz' or 'stdout.gz' then it will be gzip compressed
+before being written to stdout.
+
+This ability to read and write on the stdin and stdout steams allows
+FITS files to be piped between tasks in memory rather than having to
+create temporary intermediate FITS files on disk. For example if task1
+creates an output FITS file, and task2 reads an input FITS file, the
+FITS file may be piped between the 2 tasks by specifying
+-
+ task1 - | task2 -
+-
+where the vertical bar is the Unix piping symbol. This assumes that the 2
+tasks read the name of the FITS file off of the command line.
+
+**C. Output File Name when Opening an Existing File
+
+An optional output filename may be specified in parentheses immediately
+following the base file name to be opened. This is mainly useful in
+those cases where CFITSIO creates a temporary copy of the input FITS
+file before it is opened and passed to the application program. This
+happens by default when opening a network FTP or HTTP-type file, when
+reading a compressed FITS file on a local disk, when reading from the
+stdin stream, or when a column filter, row filter, or binning specifier
+is included as part of the input file specification. By default this
+temporary file is created in memory. If there is not enough memory to
+create the file copy, then CFITSIO will exit with an error. In these
+cases one can force a permanent file to be created on disk, instead of
+a temporary file in memory, by supplying the name in parentheses
+immediately following the base file name. The output filename can
+include the '!' clobber flag.
+
+Thus, if the input filename to CFITSIO is:
+\verb+file1.fits.gz(file2.fits)+
+then CFITSIO will uncompress `file1.fits.gz' into the local disk file
+`file2.fits' before opening it. CFITSIO does not automatically delete
+the output file, so it will still exist after the application program
+exits.
+
+The output filename "mem://" is also allowed, which will write the
+output file into memory, and also allow write access to the file. This
+'file' will disappear when it is closed, but this may be useful for
+some applications which only need to modify a temporary copy of the file.
+
+In some cases, several different temporary FITS files will be created
+in sequence, for instance, if one opens a remote file using FTP, then
+filters rows in a binary table extension, then create an image by
+binning a pair of columns. In this case, the remote file will be
+copied to a temporary local file, then a second temporary file will be
+created containing the filtered rows of the table, and finally a third
+temporary file containing the binned image will be created. In cases
+like this where multiple files are created, the outfile specifier will
+be interpreted the name of the final file as described below, in descending
+priority:
+
+\begin{itemize}
+\item
+as the name of the final image file if an image within a single binary
+table cell is opened or if an image is created by binning a table column.
+\item
+as the name of the file containing the filtered table if a column filter
+and/or a row filter are specified.
+\item
+as the name of the local copy of the remote FTP or HTTP file.
+\item
+as the name of the uncompressed version of the FITS file, if a
+compressed FITS file on local disk has been opened.
+\item
+otherwise, the output filename is ignored.
+\end{itemize}
+
+The output file specifier is useful when reading FTP or HTTP-type
+FITS files since it can be used to create a local disk copy of the file
+that can be reused in the future. If the output file name = `*' then a
+local file with the same name as the network file will be created.
+Note that CFITSIO will behave differently depending on whether the
+remote file is compressed or not as shown by the following examples:
+\begin{itemize}
+\item
+\verb+ftp://remote.machine/tmp/myfile.fits.gz(*)+ - the remote compressed
+file is copied to the local compressed file `myfile.fits.gz', which
+is then uncompressed in local memory before being opened and passed
+to the application program.
+
+\item
+\verb+ftp://remote.machine/tmp/myfile.fits.gz(myfile.fits)+ - the
+remote compressed file is copied and uncompressed into the local file
+`myfile.fits'. This example requires less local memory than the
+previous example since the file is uncompressed on disk instead of in
+memory.
+
+\item
+\verb+ftp://remote.machine/tmp/myfile.fits(myfile.fits.gz)+ - this will
+usually produce an error since CFITSIO itself cannot compress files.
+\end{itemize}
+
+The exact behavior of CFITSIO in the latter case depends on the type of
+ftp server running on the remote machine and how it is configured. In
+some cases, if the file `myfile.fits.gz' exists on the remote machine,
+then the server will copy it to the local machine. In other cases the
+ftp server will automatically create and transmit a compressed version
+of the file if only the uncompressed version exists. This can get
+rather confusing, so users should use a certain amount of caution when
+using the output file specifier with FTP or HTTP file types, to make
+sure they get the behavior that they expect.
+
+**D. Template File Name when Creating a New File
+
+When a new FITS file is created with a call to fits\_create\_file, the
+name of a template file may be supplied in parentheses immediately
+following the name of the new file to be created. This template is
+used to define the structure of one or more HDUs in the new file. The
+template file may be another FITS file, in which case the newly created
+file will have exactly the same keywords in each HDU as in the template
+FITS file, but all the data units will be filled with zeros. The
+template file may also be an ASCII text file, where each line (in
+general) describes one FITS keyword record. The format of the ASCII
+template file is described in the following Template Files chapter.
+
+**E. Image Tile-Compression Specification
+
+When specifying the name of the output FITS file to be created, the
+user can indicate that images should be written in tile-compressed
+format (see section 5.5, ``Primary Array or IMAGE Extension I/O
+Routines'') by enclosing the compression parameters in square brackets
+following the root disk file name. Here are some examples of the
+syntax for specifying tile-compressed output images:
+-
+ myfile.fit[compress] - use Rice algorithm and default tile size
+
+ myfile.fit[compress GZIP] - use the specified compression algorithm;
+ myfile.fit[compress Rice] only the first letter of the algorithm
+ myfile.fit[compress PLIO] name is required.
+
+ myfile.fit[compress Rice 100,100] - use 100 x 100 pixel tile size
+ myfile.fit[compress Rice 100,100;2] - as above, and use noisebits = 2
+-
+
+**F. HDU Location Specification
+
+The optional HDU location specifier defines which HDU (Header-Data
+Unit, also known as an `extension') within the FITS file to initially
+open. It must immediately follow the base file name (or the output
+file name if present). If it is not specified then the first HDU (the
+primary array) is opened. The HDU location specifier is required if
+the colFilter, rowFilter, or binSpec specifiers are present, because
+the primary array is not a valid HDU for these operations. The HDU may
+be specified either by absolute position number, starting with 0 for
+the primary array, or by reference to the HDU name, and optionally, the
+version number and the HDU type of the desired extension. The location
+of an image within a single cell of a binary table may also be
+specified, as described below.
+
+The absolute position of the extension is specified either by enclosed
+the number in square brackets (e.g., `[1]' = the first extension
+following the primary array) or by preceded the number with a plus sign
+(`+1'). To specify the HDU by name, give the name of the desired HDU
+(the value of the EXTNAME or HDUNAME keyword) and optionally the
+extension version number (value of the EXTVER keyword) and the
+extension type (value of the XTENSION keyword: IMAGE, ASCII or TABLE,
+or BINTABLE), separated by commas and all enclosed in square brackets.
+If the value of EXTVER and XTENSION are not specified, then the first
+extension with the correct value of EXTNAME is opened. The extension
+name and type are not case sensitive, and the extension type may be
+abbreviated to a single letter (e.g., I = IMAGE extension or primary
+array, A or T = ASCII table extension, and B = binary table BINTABLE
+extension). If the HDU location specifier is equal to `[PRIMARY]' or
+`[P]', then the primary array (the first HDU) will be opened.
+
+FITS images are most commonly stored in the primary array or an image
+extension, but images can also be stored as a vector in a single cell
+of a binary table (i.e. each row of the vector column contains a
+different image). Such an image can be opened with CFITSIO by
+specifying the desired column name and the row number after the binary
+table HDU specifier as shown in the following examples. The column name
+is separated from the HDU specifier by a semicolon and the row number
+is enclosed in parentheses. In this case CFITSIO copies the image from
+the table cell into a temporary primary array before it is opened. The
+application program then just sees the image in the primary array,
+without any extensions. The particular row to be opened may be
+specified either by giving an absolute integer row number (starting
+with 1 for the first row), or by specifying a boolean expression that
+evaluates to TRUE for the desired row. The first row that satisfies
+the expression will be used. The row selection expression has the same
+syntax as described in the Row Filter Specifier section, below.
+
+ Examples:
+-
+ myfile.fits[3] - open the 3rd HDU following the primary array
+ myfile.fits+3 - same as above, but using the FTOOLS-style notation
+ myfile.fits[EVENTS] - open the extension that has EXTNAME = 'EVENTS'
+ myfile.fits[EVENTS, 2] - same as above, but also requires EXTVER = 2
+ myfile.fits[events,2,b] - same, but also requires XTENSION = 'BINTABLE'
+ myfile.fits[3; images(17)] - opens the image in row 17 of the 'images'
+ column in the 3rd extension of the file.
+ myfile.fits[3; images(exposure > 100)] - as above, but opens the image
+ in the first row that has an 'exposure' column value
+ greater than 100.
+-
+
+**G. Image Section
+
+A virtual file containing a rectangular subsection of an image can be
+extracted and opened by specifying the range of pixels (start:end)
+along each axis to be extracted from the original image. One can also
+specify an optional pixel increment (start:end:step) for each axis of
+the input image. A pixel step = 1 will be assumed if it is not
+specified. If the start pixel is larger then the end pixel, then the
+image will be flipped (producing a mirror image) along that dimension.
+An asterisk, '*', may be used to specify the entire range of an axis,
+and '-*' will flip the entire axis. The input image can be in the
+primary array, in an image extension, or contained in a vector cell of
+a binary table. In the later 2 cases the extension name or number must
+be specified before the image section specifier.
+
+ Examples:
+-
+ myfile.fits[1:512:2, 2:512:2] - open a 256x256 pixel image
+ consisting of the odd numbered columns (1st axis) and
+ the even numbered rows (2nd axis) of the image in the
+ primary array of the file.
+
+ myfile.fits[*, 512:256] - open an image consisting of all the columns
+ in the input image, but only rows 256 through 512.
+ The image will be flipped along the 2nd axis since
+ the starting pixel is greater than the ending pixel.
+
+ myfile.fits[*:2, 512:256:2] - same as above but keeping only
+ every other row and column in the input image.
+
+ myfile.fits[-*, *] - copy the entire image, flipping it along
+ the first axis.
+
+ myfile.fits[3][1:256,1:256] - opens a subsection of the image that
+ is in the 3rd extension of the file.
+
+ myfile.fits[4; images(12)][1:10,1:10] - open an image consisting
+ of the first 10 pixels in both dimensions. The original
+ image resides in the 12th row of the 'images' vector
+ column in the table in the 4th extension of the file.
+-
+
+When CFITSIO opens an image section it first creates a temporary file
+containing the image section plus a copy of any other HDUs in the
+file. This temporary file is then opened by the application program,
+so it is not possible to write to or modify the input file when
+specifying an image section. Note that CFITSIO automatically updates
+the world coordinate system keywords in the header of the image
+section, if they exist, so that the coordinate associated with each
+pixel in the image section will be computed correctly.
+
+**H. Column and Keyword Filtering Specification
+
+The optional column/keyword filtering specifier is used to modify the
+column structure and/or the header keywords in the HDU that was
+selected with the previous HDU location specifier. This filtering
+specifier must be enclosed in square brackets and can be distinguished
+from a general row filter specifier (described below) by the fact that
+it begins with the string 'col ' and is not immediately followed by an
+equals sign. The original file is not changed by this filtering
+operation, and instead the modifications are made on a copy of the
+input FITS file (usually in memory), which also contains a copy of all
+the other HDUs in the file. This temporary file is passed to the
+application program and will persist only until the file is closed or
+until the program exits, unless the outfile specifier (see above) is
+also supplied.
+
+The column/keyword filter can be used to perform the following
+operations. More than one operation may be specified by separating
+them with semi-colons.
+
+\begin{itemize}
+
+\item
+Copy only a specified list of columns columns to the filtered input file.
+The list of column name should be separated by semi-colons. Wild card
+characters may be used in the column names to match multiple columns.
+If the expression contains both a list of columns to be included and
+columns to be deleted, then all the columns in the original table
+except the explicitly deleted columns will appear in the filtered
+table (i.e., there is no need to explicitly list the columns to
+be included if any columns are being deleted).
+
+\item
+Delete a column or keyword by listing the name preceded by a minus sign
+or an exclamation mark (!), e.g., '-TIME' will delete the TIME column
+if it exists, otherwise the TIME keyword. An error is returned if
+neither a column nor keyword with this name exists. Note that the
+exclamation point, '!', is a special UNIX character, so if it is used
+on the command line rather than entered at a task prompt, it must be
+preceded by a backslash to force the UNIX shell to ignore it.
+
+\item
+Rename an existing column or keyword with the syntax 'NewName ==
+OldName'. An error is returned if neither a column nor keyword with
+this name exists.
+
+\item
+Append a new column or keyword to the table. To create a column,
+give the new name, optionally followed by the data type in parentheses,
+followed by a single equals sign and an expression to be used to
+compute the value (e.g., 'newcol(1J) = 0' will create a new 32-bit
+integer column called 'newcol' filled with zeros). The data type is
+specified using the same syntax that is allowed for the value of the
+FITS TFORMn keyword (e.g., 'I', 'J', 'E', 'D', etc. for binary tables,
+and 'I8', F12.3', 'E20.12', etc. for ASCII tables). If the data type is
+not specified then an appropriate data type will be chosen depending on
+the form of the expression (may be a character string, logical, bit, long
+integer, or double column). An appropriate vector count (in the case
+of binary tables) will also be added if not explicitly specified.
+
+When creating a new keyword, the keyword name must be preceded by a
+pound sign '\#', and the expression must evaluate to a scalar
+(i.e., cannot have a column name in the expression). The comment
+string for the keyword may be specified in parentheses immediately
+following the keyword name (instead of supplying a data type as in
+the case of creating a new column).
+
+\item
+Recompute (overwrite) the values in an existing column or keyword by
+giving the name followed by an equals sign and an arithmetic
+expression.
+\end{itemize}
+
+The expression that is used when appending or recomputing columns or
+keywords can be arbitrarily complex and may be a function of other
+header keyword values and other columns (in the same row). The full
+syntax and available functions for the expression are described below
+in the row filter specification section.
+
+
+For complex or commonly used operations, one can also place the
+operations into an external text file and import it into the column
+filter using the syntax '[col @filename.txt]'. The operations can
+extend over multiple lines of the file, but multiple operations must
+still be separated by semicolons. Any lines in the external text file
+that begin with 2 slash characters ('//') will be ignored and may be
+used to add comments into the file.
+
+Examples:
+-
+ [col Time;rate] - only the Time and rate columns will
+ appear in the filtered input file.
+
+ [col Time;*raw] - include the Time column and any other
+ columns whose name ends with 'raw'.
+
+ [col -TIME; Good == STATUS] - deletes the TIME column and
+ renames the status column to 'Good'
+
+ [col PI=PHA * 1.1 + 0.2] - creates new PI column from PHA values
+
+ [col rate = rate/exposure] - recomputes the rate column by dividing
+ it by the EXPOSURE keyword value.
+-
+
+**I. Row Filtering Specification
+
+ When entering the name of a FITS table that is to be opened by a
+ program, an optional row filter may be specified to select a subset
+ of the rows in the table. A temporary new FITS file is created on
+ the fly which contains only those rows for which the row filter
+ expression evaluates to true. (The primary array and any other
+ extensions in the input file are also copied to the temporary
+ file). The original FITS file is closed and the new virtual file
+ is opened by the application program. The row filter expression is
+ enclosed in square brackets following the file name and extension
+ name (e.g., 'file.fits[events][GRADE==50]' selects only those rows
+ where the GRADE column value equals 50). When dealing with tables
+ where each row has an associated time and/or 2D spatial position,
+ the row filter expression can also be used to select rows based on
+ the times in a Good Time Intervals (GTI) extension, or on spatial
+ position as given in a SAO-style region file.
+
+***1. General Syntax
+
+ The row filtering expression can be an arbitrarily complex series
+ of operations performed on constants, keyword values, and column
+ data taken from the specified FITS TABLE extension. The expression
+ must evaluate to a boolean value for each row of the table, where
+ a value of FALSE means that the row will be excluded.
+
+ For complex or commonly used filters, one can place the expression
+ into a text file and import it into the row filter using the syntax
+ '[@filename.txt]'. The expression can be arbitrarily complex and
+ extend over multiple lines of the file. Any lines in the external
+ text file that begin with 2 slash characters ('//') will be ignored
+ and may be used to add comments into the file.
+
+ Keyword and column data are referenced by name. Any string of
+ characters not surrounded by quotes (ie, a constant string) or
+ followed by an open parentheses (ie, a function name) will be
+ initially interpreted as a column name and its contents for the
+ current row inserted into the expression. If no such column exists,
+ a keyword of that name will be searched for and its value used, if
+ found. To force the name to be interpreted as a keyword (in case
+ there is both a column and keyword with the same name), precede the
+ keyword name with a single pound sign, '\#', as in '\#NAXIS2'. Due to
+ the generalities of FITS column and keyword names, if the column or
+ keyword name contains a space or a character which might appear as
+ an arithmetic term then inclose the name in '\$' characters as in
+ \$MAX PHA\$ or \#\$MAX-PHA\$. Names are case insensitive.
+
+ To access a table entry in a row other than the current one, follow
+ the column's name with a row offset within curly braces. For
+ example, 'PHA\{-3\}' will evaluate to the value of column PHA, 3 rows
+ above the row currently being processed. One cannot specify an
+ absolute row number, only a relative offset. Rows that fall outside
+ the table will be treated as undefined, or NULLs.
+
+ Boolean operators can be used in the expression in either their
+ Fortran or C forms. The following boolean operators are available:
+-
+ "equal" .eq. .EQ. == "not equal" .ne. .NE. !=
+ "less than" .lt. .LT. < "less than/equal" .le. .LE. <= =<
+ "greater than" .gt. .GT. > "greater than/equal" .ge. .GE. >= =>
+ "or" .or. .OR. || "and" .and. .AND. &&
+ "negation" .not. .NOT. ! "approx. equal(1e-7)" ~
+-
+
+Note that the exclamation
+point, '!', is a special UNIX character, so if it is used on the
+command line rather than entered at a task prompt, it must be preceded
+by a backslash to force the UNIX shell to ignore it.
+
+ The expression may also include arithmetic operators and functions.
+ Trigonometric functions use radians, not degrees. The following
+ arithmetic operators and functions can be used in the expression
+ (function names are case insensitive). A null value will be returned
+ in case of illegal operations such as divide by zero, sqrt(negative)
+ log(negative), log10(negative), arccos(.gt. 1), arcsin(.gt. 1).
+
+-
+ "addition" + "subtraction" -
+ "multiplication" * "division" /
+ "negation" - "exponentiation" ** ^
+ "absolute value" abs(x) "cosine" cos(x)
+ "sine" sin(x) "tangent" tan(x)
+ "arc cosine" arccos(x) "arc sine" arcsin(x)
+ "arc tangent" arctan(x) "arc tangent" arctan2(x,y)
+ "hyperbolic cos" cosh(x) "hyperbolic sin" sinh(x)
+ "hyperbolic tan" tanh(x) "round to nearest int" round(x)
+ "round down to int" floor(x) "round up to int" ceil(x)
+ "exponential" exp(x) "square root" sqrt(x)
+ "natural log" log(x) "common log" log10(x)
+ "modulus" i % j "random # [0.0,1.0)" random()
+ "minimum" min(x,y) "maximum" max(x,y)
+ "cumulative sum" accum(x) "sequential difference" seqdiff(x)
+ "if-then-else" b?x:y
+-
+
+ An alternate syntax for the min and max functions has only a single
+ argument which should be a vector value (see below). The result
+ will be the minimum/maximum element contained within the vector.
+
+ The accum(x) function forms the cumulative sum of x, element by element.
+ Vector columns are supported simply by performing the summation process
+ through all the values. Null values are treated as 0. The seqdiff(x)
+ function forms the sequential difference of x, element by element.
+ The first value of seqdiff is the first value of x. A single null
+ value in x causes a pair of nulls in the output. The seqdiff and
+ accum functions are functional inverses, i.e., seqdiff(accum(x)) == x
+ as long as no null values are present.
+
+ The following type casting operators are available, where the
+ inclosing parentheses are required and taken from the C language
+ usage. Also, the integer to real casts values to double precision:
+-
+ "real to integer" (int) x (INT) x
+ "integer to real" (float) i (FLOAT) i
+-
+
+ In addition, several constants are built in for use in numerical
+ expressions:
+
+-
+ #pi 3.1415... #e 2.7182...
+ #deg #pi/180 #row current row number
+ #null undefined value #snull undefined string
+-
+
+ A string constant must be enclosed in quotes as in 'Crab'. The
+ "null" constants are useful for conditionally setting table values
+ to a NULL, or undefined, value (eg., "col1==-99 ? \#NULL : col1").
+
+ There is also a function for testing if two values are close to
+ each other, i.e., if they are "near" each other to within a user
+ specified tolerance. The arguments, value\_1 and value\_2 can be
+ integer or real and represent the two values who's proximity is
+ being tested to be within the specified tolerance, also an integer
+ or real:
+-
+ near(value_1, value_2, tolerance)
+-
+ When a NULL, or undefined, value is encountered in the FITS table,
+ the expression will evaluate to NULL unless the undefined value is
+ not actually required for evaluation, e.g. "TRUE .or. NULL"
+ evaluates to TRUE. The following two functions allow some NULL
+ detection and handling:
+-
+ "a null value?" ISNULL(x)
+ "define a value for null" DEFNULL(x,y)
+-
+ The former
+ returns a boolean value of TRUE if the argument x is NULL. The
+ later "defines" a value to be substituted for NULL values; it
+ returns the value of x if x is not NULL, otherwise it returns the
+ value of y.
+
+
+
+***2. Bit Masks
+
+ Bit masks can be used to select out rows from bit columns (TFORMn =
+ \#X) in FITS files. To represent the mask, binary, octal, and hex
+ formats are allowed:
+
+-
+ binary: b0110xx1010000101xxxx0001
+ octal: o720x1 -> (b111010000xxx001)
+ hex: h0FxD -> (b00001111xxxx1101)
+-
+
+ In all the representations, an x or X is allowed in the mask as a
+ wild card. Note that the x represents a different number of wild
+ card bits in each representation. All representations are case
+ insensitive.
+
+ To construct the boolean expression using the mask as the boolean
+ equal operator described above on a bit table column. For example,
+ if you had a 7 bit column named flags in a FITS table and wanted
+ all rows having the bit pattern 0010011, the selection expression
+ would be:
+
+-
+ flags == b0010011
+ or
+ flags .eq. b10011
+-
+
+ It is also possible to test if a range of bits is less than, less
+ than equal, greater than and greater than equal to a particular
+ boolean value:
+
+-
+ flags <= bxxx010xx
+ flags .gt. bxxx100xx
+ flags .le. b1xxxxxxx
+-
+
+ Notice the use of the x bit value to limit the range of bits being
+ compared.
+
+ It is not necessary to specify the leading (most significant) zero
+ (0) bits in the mask, as shown in the second expression above.
+
+ Bit wise AND, OR and NOT operations are also possible on two or
+ more bit fields using the '\&'(AND), '$|$'(OR), and the '!'(NOT)
+ operators. All of these operators result in a bit field which can
+ then be used with the equal operator. For example:
+
+-
+ (!flags) == b1101100
+ (flags & b1000001) == bx000001
+-
+
+ Bit fields can be appended as well using the '+' operator. Strings
+ can be concatenated this way, too.
+
+***3. Vector Columns
+
+ Vector columns can also be used in building the expression. No
+ special syntax is required if one wants to operate on all elements
+ of the vector. Simply use the column name as for a scalar column.
+ Vector columns can be freely intermixed with scalar columns or
+ constants in virtually all expressions. The result will be of the
+ same dimension as the vector. Two vectors in an expression, though,
+ need to have the same number of elements and have the same
+ dimensions. The only places a vector column cannot be used (for
+ now, anyway) are the SAO region functions and the NEAR boolean
+ function.
+
+ Arithmetic and logical operations are all performed on an element by
+ element basis. Comparing two vector columns, eg "COL1 == COL2",
+ thus results in another vector of boolean values indicating which
+ elements of the two vectors are equal.
+
+ Eight functions are available that operate on a vector and return a
+ scalar result:
+-
+ "minimum" MIN(V) "maximum" MAX(V)
+ "average" AVERAGE(V) "median" MEDIAN(V)
+ "sumation" SUM(V) "standard deviation" STDDEV(V)
+ "# of values" NELEM(V) "# of non-null values" NVALID(V)
+-
+ where V represents the name of a vector column or a manually
+ constructed vector using curly brackets as described below. The
+ first 6 of these functions ignore any null values in the vector when
+ computing the result.
+
+ The SUM function literally sums all the elements in x, returning a
+ scalar value. If V is a boolean vector, SUM returns the number
+ of TRUE elements. The NELEM function returns the number of elements
+ in vector V whereas NVALID return the number of non-null elements in
+ the vector. (NELEM also operates on bit and string columns,
+ returning their column widths.) As an example, to test whether all
+ elements of two vectors satisfy a given logical comparison, one can
+ use the expression
+-
+ SUM( COL1 > COL2 ) == NELEM( COL1 )
+-
+
+ which will return TRUE if all elements of COL1 are greater than
+ their corresponding elements in COL2.
+
+ To specify a single element of a vector, give the column name
+ followed by a comma-separated list of coordinates enclosed in
+ square brackets. For example, if a vector column named PHAS exists
+ in the table as a one dimensional, 256 component list of numbers
+ from which you wanted to select the 57th component for use in the
+ expression, then PHAS[57] would do the trick. Higher dimensional
+ arrays of data may appear in a column. But in order to interpret
+ them, the TDIMn keyword must appear in the header. Assuming that a
+ (4,4,4,4) array is packed into each row of a column named ARRAY4D,
+ the (1,2,3,4) component element of each row is accessed by
+ ARRAY4D[1,2,3,4]. Arrays up to dimension 5 are currently
+ supported. Each vector index can itself be an expression, although
+ it must evaluate to an integer value within the bounds of the
+ vector. Vector columns which contain spaces or arithmetic operators
+ must have their names enclosed in "\$" characters as with
+ \$ARRAY-4D\$[1,2,3,4].
+
+ A more C-like syntax for specifying vector indices is also
+ available. The element used in the preceding example alternatively
+ could be specified with the syntax ARRAY4D[4][3][2][1]. Note the
+ reverse order of indices (as in C), as well as the fact that the
+ values are still ones-based (as in Fortran -- adopted to avoid
+ ambiguity for 1D vectors). With this syntax, one does not need to
+ specify all of the indices. To extract a 3D slice of this 4D
+ array, use ARRAY4D[4].
+
+ Variable-length vector columns are not supported.
+
+ Vectors can be manually constructed within the expression using a
+ comma-separated list of elements surrounded by curly braces ('\{\}').
+ For example, '\{1,3,6,1\}' is a 4-element vector containing the values
+ 1, 3, 6, and 1. The vector can contain only boolean, integer, and
+ real values (or expressions). The elements will be promoted to the
+ highest data type present. Any elements which are themselves
+ vectors, will be expanded out with each of its elements becoming an
+ element in the constructed vector.
+
+***4. Good Time Interval Filtering
+
+ A common filtering method involves selecting rows which have a time
+ value which lies within what is called a Good Time Interval or GTI.
+ The time intervals are defined in a separate FITS table extension
+ which contains 2 columns giving the start and stop time of each
+ good interval. The filtering operation accepts only those rows of
+ the input table which have an associated time which falls within
+ one of the time intervals defined in the GTI extension. A high
+ level function, gtifilter(a,b,c,d), is available which evaluates
+ each row of the input table and returns TRUE or FALSE depending
+ whether the row is inside or outside the good time interval. The
+ syntax is
+-
+ gtifilter( [ "gtifile" [, expr [, "STARTCOL", "STOPCOL" ] ] ] )
+ or
+ gtifilter( [ 'gtifile' [, expr [, 'STARTCOL', 'STOPCOL' ] ] ] )
+-
+ where each "[]" demarks optional parameters. Note that the quotes
+ around the gtifile and START/STOP column are required. Either single
+ or double quotes may be used. In cases where this expression is
+ entered on the Unix command line, enclose the entire expression in
+ double quotes, and then use single quotes within the expression to
+ enclose the 'gtifile' and other terms. It is also usually possible
+ to do the reverse, and enclose the whole expression in single quotes
+ and then use double quotes within the expression. The gtifile,
+ if specified, can be blank ("") which will mean to use the first
+ extension with the name "*GTI*" in the current file, a plain
+ extension specifier (eg, "+2", "[2]", or "[STDGTI]") which will be
+ used to select an extension in the current file, or a regular
+ filename with or without an extension specifier which in the latter
+ case will mean to use the first extension with an extension name
+ "*GTI*". Expr can be any arithmetic expression, including simply
+ the time column name. A vector time expression will produce a
+ vector boolean result. STARTCOL and STOPCOL are the names of the
+ START/STOP columns in the GTI extension. If one of them is
+ specified, they both must be.
+
+ In its simplest form, no parameters need to be provided -- default
+ values will be used. The expression "gtifilter()" is equivalent to
+-
+ gtifilter( "", TIME, "*START*", "*STOP*" )
+-
+ This will search the current file for a GTI extension, filter the
+ TIME column in the current table, using START/STOP times taken from
+ columns in the GTI extension with names containing the strings
+ "START" and "STOP". The wildcards ('*') allow slight variations in
+ naming conventions such as "TSTART" or "STARTTIME". The same
+ default values apply for unspecified parameters when the first one
+ or two parameters are specified. The function automatically
+ searches for TIMEZERO/I/F keywords in the current and GTI
+ extensions, applying a relative time offset, if necessary.
+
+***5. Spatial Region Filtering
+
+ Another common filtering method selects rows based on whether the
+ spatial position associated with each row is located within a given
+ 2-dimensional region. The syntax for this high-level filter is
+-
+ regfilter( "regfilename" [ , Xexpr, Yexpr [ , "wcs cols" ] ] )
+-
+ where each "[]" demarks optional parameters. The region file name
+ is required and must be enclosed in quotes. The remaining
+ parameters are optional. The region file is an ASCII text file
+ which contains a list of one or more geometric shapes (circle,
+ ellipse, box, etc.) which defines a region on the celestial sphere
+ or an area within a particular 2D image. The region file is
+ typically generated using an image display program such as fv/POW
+ (distribute by the HEASARC), or ds9 (distributed by the Smithsonian
+ Astrophysical Observatory). Users should refer to the documentation
+ provided with these programs for more details on the syntax used in
+ the region files.
+
+ In its simpliest form, (e.g., regfilter("region.reg") ) the
+ coordinates in the default 'X' and 'Y' columns will be used to
+ determine if each row is inside or outside the area specified in
+ the region file. Alternate position column names, or expressions,
+ may be entered if needed, as in
+-
+ regfilter("region.reg", XPOS, YPOS)
+-
+ Region filtering can be applied most unambiguously if the positions
+ in the region file and in the table to be filtered are both give in
+ terms of absolute celestial coordinate units. In this case the
+ locations and sizes of the geometric shapes in the region file are
+ specified in angular units on the sky (e.g., positions given in
+ R.A. and Dec. and sizes in arcseconds or arcminutes). Similarly,
+ each row of the filtered table will have a celestial coordinate
+ associated with it. This association is usually implemented using
+ a set of so-called 'World Coordinate System' (or WCS) FITS keywords
+ that define the coordinate transformation that must be applied to
+ the values in the 'X' and 'Y' columns to calculate the coordinate.
+
+ Alternatively, one can perform spatial filtering using unitless
+ 'pixel' coordinates for the regions and row positions. In this
+ case the user must be careful to ensure that the positions in the 2
+ files are self-consistent. A typical problem is that the region
+ file may be generated using a binned image, but the unbinned
+ coordinates are given in the event table. The ROSAT events files,
+ for example, have X and Y pixel coordinates that range from 1 -
+ 15360. These coordinates are typically binned by a factor of 32 to
+ produce a 480x480 pixel image. If one then uses a region file
+ generated from this image (in image pixel units) to filter the
+ ROSAT events file, then the X and Y column values must be converted
+ to corresponding pixel units as in:
+-
+ regfilter("rosat.reg", X/32.+.5, Y/32.+.5)
+-
+ Note that this binning conversion is not necessary if the region
+ file is specified using celestial coordinate units instead of pixel
+ units because CFITSIO is then able to directly compare the
+ celestial coordinate of each row in the table with the celestial
+ coordinates in the region file without having to know anything
+ about how the image may have been binned.
+
+ The last "wcs cols" parameter should rarely be needed. If supplied,
+ this string contains the names of the 2 columns (space or comma
+ separated) which have the associated WCS keywords. If not supplied,
+ the filter will scan the X and Y expressions for column names.
+ If only one is found in each expression, those columns will be
+ used, otherwise an error will be returned.
+
+ These region shapes are supported (names are case insensitive):
+-
+ Point ( X1, Y1 ) <- One pixel square region
+ Line ( X1, Y1, X2, Y2 ) <- One pixel wide region
+ Polygon ( X1, Y1, X2, Y2, ... ) <- Rest are interiors with
+ Rectangle ( X1, Y1, X2, Y2, A ) | boundaries considered
+ Box ( Xc, Yc, Wdth, Hght, A ) V within the region
+ Diamond ( Xc, Yc, Wdth, Hght, A )
+ Circle ( Xc, Yc, R )
+ Annulus ( Xc, Yc, Rin, Rout )
+ Ellipse ( Xc, Yc, Rx, Ry, A )
+ Elliptannulus ( Xc, Yc, Rinx, Riny, Routx, Routy, Ain, Aout )
+ Sector ( Xc, Yc, Amin, Amax )
+-
+ where (Xc,Yc) is the coordinate of the shape's center; (X\#,Y\#) are
+ the coordinates of the shape's edges; Rxxx are the shapes' various
+ Radii or semimajor/minor axes; and Axxx are the angles of rotation
+ (or bounding angles for Sector) in degrees. For rotated shapes, the
+ rotation angle can be left off, indicating no rotation. Common
+ alternate names for the regions can also be used: rotbox = box;
+ rotrectangle = rectangle; (rot)rhombus = (rot)diamond; and pie
+ = sector. When a shape's name is preceded by a minus sign, '-',
+ the defined region is instead the area *outside* its boundary (ie,
+ the region is inverted). All the shapes within a single region
+ file are OR'd together to create the region, and the order is
+ significant. The overall way of looking at region files is that if
+ the first region is an excluded region then a dummy included region
+ of the whole detector is inserted in the front. Then each region
+ specification as it is processed overrides any selections inside of
+ that region specified by previous regions. Another way of thinking
+ about this is that if a previous excluded region is completely
+ inside of a subsequent included region the excluded region is
+ ignored.
+
+ The positional coordinates may be given either in pixel units,
+ decimal degrees or hh:mm:ss.s, dd:mm:ss.s units. The shape sizes
+ may be given in pixels, degrees, arcminutes, or arcseconds. Look
+ at examples of region file produced by fv/POW or ds9 for further
+ details of the region file format.
+
+ There are three functions that are primarily for use with SAO region
+ files and the FSAOI task, but they can be used directly. They
+ return a boolean true or false depending on whether a two
+ dimensional point is in the region or not:
+-
+ "point in a circular region"
+ circle(xcntr,ycntr,radius,Xcolumn,Ycolumn)
+
+ "point in an elliptical region"
+ ellipse(xcntr,ycntr,xhlf_wdth,yhlf_wdth,rotation,Xcolumn,Ycolumn)
+
+ "point in a rectangular region"
+ box(xcntr,ycntr,xfll_wdth,yfll_wdth,rotation,Xcolumn,Ycolumn)
+
+ where
+ (xcntr,ycntr) are the (x,y) position of the center of the region
+ (xhlf_wdth,yhlf_wdth) are the (x,y) half widths of the region
+ (xfll_wdth,yfll_wdth) are the (x,y) full widths of the region
+ (radius) is half the diameter of the circle
+ (rotation) is the angle(degrees) that the region is rotated with
+ respect to (xcntr,ycntr)
+ (Xcoord,Ycoord) are the (x,y) coordinates to test, usually column
+ names
+ NOTE: each parameter can itself be an expression, not merely a
+ column name or constant.
+-
+
+***5. Example Row Filters
+-
+ [ binary && mag <= 5.0] - Extract all binary stars brighter
+ than fifth magnitude (note that
+ the initial space is necessary to
+ prevent it from being treated as a
+ binning specification)
+
+ [#row >= 125 && #row <= 175] - Extract row numbers 125 through 175
+
+ [IMAGE[4,5] .gt. 100] - Extract all rows that have the
+ (4,5) component of the IMAGE column
+ greater than 100
+
+ [abs(sin(theta * #deg)) < 0.5] - Extract all rows having the
+ absolute value of the sine of theta
+ less than a half where the angles
+ are tabulated in degrees
+
+ [SUM( SPEC > 3*BACKGRND )>=1] - Extract all rows containing a
+ spectrum, held in vector column
+ SPEC, with at least one value 3
+ times greater than the background
+ level held in a keyword, BACKGRND
+
+ [VCOL=={1,4,2}] - Extract all rows whose vector column
+ VCOL contains the 3-elements 1, 4, and
+ 2.
+
+ [@rowFilter.txt] - Extract rows using the expression
+ contained within the text file
+ rowFilter.txt
+
+ [gtifilter()] - Search the current file for a GTI
+ extension, filter the TIME
+ column in the current table, using
+ START/STOP times taken from
+ columns in the GTI extension
+
+ [regfilter("pow.reg")] - Extract rows which have a coordinate
+ (as given in the X and Y columns)
+ within the spatial region specified
+ in the pow.reg region file.
+
+ [regfilter("pow.reg", Xs, Ys)] - Same as above, except that the
+ Xs and Ys columns will be used to
+ determine the coordinate of each
+ row in the table.
+-
+
+**J. Binning or Histogramming Specification
+
+The optional binning specifier is enclosed in square brackets and can
+be distinguished from a general row filter specification by the fact
+that it begins with the keyword 'bin' not immediately followed by an
+equals sign. When binning is specified, a temporary N-dimensional FITS
+primary array is created by computing the histogram of the values in
+the specified columns of a FITS table extension. After the histogram
+is computed the input FITS file containing the table is then closed and
+the temporary FITS primary array is opened and passed to the
+application program. Thus, the application program never sees the
+original FITS table and only sees the image in the new temporary file
+(which has no additional extensions). Obviously, the application
+program must be expecting to open a FITS image and not a FITS table in
+this case.
+
+The data type of the FITS histogram image may be specified by appending
+'b' (for 8-bit byte), 'i' (for 16-bit integers), 'j' (for 32-bit
+integer), 'r' (for 32-bit floating points), or 'd' (for 64-bit double
+precision floating point) to the 'bin' keyword (e.g. '[binr X]'
+creates a real floating point image). If the data type is not
+explicitly specified then a 32-bit integer image will be created by
+default, unless the weighting option is also specified in which case
+the image will have a 32-bit floating point data type by default.
+
+The histogram image may have from 1 to 4 dimensions (axes), depending
+on the number of columns that are specified. The general form of the
+binning specification is:
+-
+ [bin{bijrd} Xcol=min:max:binsize, Ycol= ..., Zcol=..., Tcol=...; weight]
+-
+in which up to 4 columns, each corresponding to an axis of the image,
+are listed. The column names are case insensitive, and the column
+number may be given instead of the name, preceded by a pound sign
+(e.g., [bin \#4=1:512]). If the column name is not specified, then
+CFITSIO will first try to use the 'preferred column' as specified by
+the CPREF keyword if it exists (e.g., 'CPREF = 'DETX,DETY'), otherwise
+column names 'X', 'Y', 'Z', and 'T' will be assumed for each of the 4
+axes, respectively. In cases where the column name could be confused
+with an arithmetic expression, enclose the column name in parentheses to
+force the name to be interpreted literally.
+
+Each column name may be followed by an equals sign and then the lower
+and upper range of the histogram, and the size of the histogram bins,
+separated by colons. Spaces are allowed before and after the equals
+sign but not within the 'min:max:binsize' string. The min, max and
+binsize values may be integer or floating point numbers, or they may be
+the names of keywords in the header of the table. If the latter, then
+the value of that keyword is substituted into the expression.
+
+Default values for the min, max and binsize quantities will be
+used if not explicitly given in the binning expression as shown
+in these examples:
+-
+ [bin x = :512:2] - use default minimum value
+ [bin x = 1::2] - use default maximum value
+ [bin x = 1:512] - use default bin size
+ [bin x = 1:] - use default maximum value and bin size
+ [bin x = :512] - use default minimum value and bin size
+ [bin x = 2] - use default minimum and maximum values
+ [bin x] - use default minimum, maximum and bin size
+ [bin 4] - default 2-D image, bin size = 4 in both axes
+ [bin] - default 2-D image
+-
+CFITSIO will use the value of the TLMINn, TLMAXn, and TDBINn keywords,
+if they exist, for the default min, max, and binsize, respectively. If
+they do not exist then CFITSIO will use the actual minimum and maximum
+values in the column for the histogram min and max values. The default
+binsize will be set to 1, or (max - min) / 10., whichever is smaller,
+so that the histogram will have at least 10 bins along each axis.
+
+A shortcut notation is allowed if all the columns/axes have the same
+binning specification. In this case all the column names may be listed
+within parentheses, followed by the (single) binning specification, as
+in:
+-
+ [bin (X,Y)=1:512:2]
+ [bin (X,Y) = 5]
+-
+
+The optional weighting factor is the last item in the binning specifier
+and, if present, is separated from the list of columns by a
+semi-colon. As the histogram is accumulated, this weight is used to
+incremented the value of the appropriated bin in the histogram. If the
+weighting factor is not specified, then the default weight = 1 is
+assumed. The weighting factor may be a constant integer or floating
+point number, or the name of a keyword containing the weighting value.
+Or the weighting factor may be the name of a table column in which case
+the value in that column, on a row by row basis, will be used.
+
+In some cases, the column or keyword may give the reciprocal of the
+actual weight value that is needed. In this case, precede the weight
+keyword or column name by a slash '/' to tell CFITSIO to use the
+reciprocal of the value when constructing the histogram.
+
+For complex or commonly used histograms, one can also place its
+description into a text file and import it into the binning
+specification using the syntax [bin @filename.txt]. The file's
+contents can extend over multiple lines, although it must still
+conform to the no-spaces rule for the min:max:binsize syntax and each
+axis specification must still be comma-separated. Any lines in the
+external text file that begin with 2 slash characters ('//') will be
+ignored and may be used to add comments into the file.
+
+ Examples:
+
+-
+ [bini detx, dety] - 2-D, 16-bit integer histogram
+ of DETX and DETY columns, using
+ default values for the histogram
+ range and binsize
+
+ [bin (detx, dety)=16; /exposure] - 2-D, 32-bit real histogram of DETX
+ and DETY columns with a bin size = 16
+ in both axes. The histogram values
+ are divided by the EXPOSURE keyword
+ value.
+
+ [bin time=TSTART:TSTOP:0.1] - 1-D lightcurve, range determined by
+ the TSTART and TSTOP keywords,
+ with 0.1 unit size bins.
+
+ [bin pha, time=8000.:8100.:0.1] - 2-D image using default binning
+ of the PHA column for the X axis,
+ and 1000 bins in the range
+ 8000. to 8100. for the Y axis.
+
+ [bin @binFilter.txt] - Use the contents of the text file
+ binFilter.txt for the binning
+ specifications.
+
+-
+*X. Template Files
+
+When a new FITS file is created with a call to fits\_create\_file, the
+name of a template file may be supplied in parentheses immediately
+following the name of the new file to be created. This template is
+used to define the structure of one or more HDUs in the new file. The
+template file may be another FITS file, in which case the newly created
+file will have exactly the same keywords in each HDU as in the template
+FITS file, but all the data units will be filled with zeros. The
+template file may also be an ASCII text file, where each line (in
+general) describes one FITS keyword record. The format of the ASCII
+template file is described in the following sections.
+
+**A Detailed Template Line Format
+
+The format of each ASCII template line closely follows the format of a
+FITS keyword record:
+-
+ KEYWORD = KEYVALUE / COMMENT
+-
+except that free format may be used (e.g., the equals sign may appear
+at any position in the line) and TAB characters are allowed and are
+treated the same as space characters. The KEYVALUE and COMMENT fields
+are optional. The equals sign character is also optional, but it is
+recommended that it be included for clarity. Any template line that
+begins with the pound '\#' character is ignored by the template parser
+and may be use to insert comments into the template file itself.
+
+The KEYWORD name field is limited to 8 characters in length and only
+the letters A-Z, digits 0-9, and the hyphen and underscore characters
+may be used, without any embedded spaces. Lowercase letters in the
+template keyword name will be converted to uppercase. Leading spaces
+in the template line preceding the keyword name are generally ignored,
+except if the first 8 characters of a template line are all blank, then
+the entire line is treated as a FITS comment keyword (with a blank
+keyword name) and is copied verbatim into the FITS header.
+
+The KEYVALUE field may have any allowed FITS data type: character
+string, logical, integer, real, complex integer, or complex real. The
+character string values need not be enclosed in single quote characters
+unless they are necessary to distinguish the string from a different
+data type (e.g. 2.0 is a real but '2.0' is a string). The keyword has
+an undefined (null) value if the template record only contains blanks
+following the "=" or between the "=" and the "/" comment field
+delimiter.
+
+String keyword values longer than 68 characters (the maximum length
+that will fit in a single FITS keyword record) are permitted using the
+CFITSIO long string convention. They can either be specified as a
+single long line in the template, or by using multiple lines where the
+continuing lines contain the 'CONTINUE' keyword, as in this example:
+-
+ LONGKEY = 'This is a long string value that is contin&'
+ CONTINUE 'ued over 2 records' / comment field goes here
+-
+The format of template lines with CONTINUE keyword is very strict: 3
+spaces must follow CONTINUE and the rest of the line is copied verbatim
+to the FITS file.
+
+The start of the optional COMMENT field must be preceded by "/", which
+is used to separate it from the keyword value field. Exceptions are if
+the KEYWORD name field contains COMMENT, HISTORY, CONTINUE, or if the
+first 8 characters of the template line are blanks.
+
+More than one Header-Data Unit (HDU) may be defined in the template
+file. The start of an HDU definition is denoted with a SIMPLE or
+XTENSION template line:
+
+1) SIMPLE begins a Primary HDU definition. SIMPLE may only appear as
+the first keyword in the template file. If the template file begins
+with XTENSION instead of SIMPLE, then a default empty Primary HDU is
+created, and the template is then assumed to define the keywords
+starting with the first extension following the Primary HDU.
+
+2) XTENSION marks the beginning of a new extension HDU definition. The
+previous HDU will be closed at this point and processing of the next
+extension begins.
+
+**B Auto-indexing of Keywords
+
+If a template keyword name ends with a "\#" character, it is said to be
+'auto-indexed'. Each "\#" character will be replaced by the current
+integer index value, which gets reset = 1 at the start of each new HDU
+in the file (or 7 in the special case of a GROUP definition). The
+FIRST indexed keyword in each template HDU definition is used as the
+'incrementor'; each subsequent occurrence of this SAME keyword will
+cause the index value to be incremented. This behavior can be rather
+subtle, as illustrated in the following examples in which the TTYPE
+keyword is the incrementor in both cases:
+-
+ TTYPE# = TIME
+ TFORM# = 1D
+ TTYPE# = RATE
+ TFORM# = 1E
+-
+will create TTYPE1, TFORM1, TTYPE2, and TFORM2 keywords. But if the
+template looks like,
+-
+ TTYPE# = TIME
+ TTYPE# = RATE
+ TFORM# = 1D
+ TFORM# = 1E
+-
+this results in a FITS files with TTYPE1, TTYPE2, TFORM2, and TFORM2,
+which is probably not what was intended!
+
+**C Template Parser Directives
+
+In addition to the template lines which define individual keywords, the
+template parser recognizes 3 special directives which are each preceded
+by the backslash character: \verb+ \include, \group+, and \verb+ \end+.
+
+The 'include' directive must be followed by a filename. It forces the
+parser to temporarily stop reading the current template file and begin
+reading the include file. Once the parser reaches the end of the
+include file it continues parsing the current template file. Include
+files can be nested, and HDU definitions can span multiple template
+files.
+
+The start of a GROUP definition is denoted with the 'group' directive,
+and the end of a GROUP definition is denoted with the 'end' directive.
+Each GROUP contains 0 or more member blocks (HDUs or GROUPs). Member
+blocks of type GROUP can contain their own member blocks. The GROUP
+definition itself occupies one FITS file HDU of special type (GROUP
+HDU), so if a template specifies 1 group with 1 member HDU like:
+-
+\group
+grpdescr = 'demo'
+xtension bintable
+# this bintable has 0 cols, 0 rows
+\end
+-
+then the parser creates a FITS file with 3 HDUs :
+-
+1) dummy PHDU
+2) GROUP HDU (has 1 member, which is bintable in HDU number 3)
+3) bintable (member of GROUP in HDU number 2)
+-
+Technically speaking, the GROUP HDU is a BINTABLE with 6 columns. Applications
+can define additional columns in a GROUP HDU using TFORMn and TTYPEn
+(where n is 7, 8, ....) keywords or their auto-indexing equivalents.
+
+For a more complicated example of a template file using the group directives,
+look at the sample.tpl file that is included in the CFITSIO distribution.
+
+**D Formal Template Syntax
+
+The template syntax can formally be defined as follows:
+-
+ TEMPLATE = BLOCK [ BLOCK ... ]
+
+ BLOCK = { HDU | GROUP }
+
+ GROUP = \GROUP [ BLOCK ... ] \END
+
+ HDU = XTENSION [ LINE ... ] { XTENSION | \GROUP | \END | EOF }
+
+ LINE = [ KEYWORD [ = ] ] [ VALUE ] [ / COMMENT ]
+
+ X ... - X can be present 1 or more times
+ { X | Y } - X or Y
+ [ X ] - X is optional
+-
+
+At the topmost level, the template defines 1 or more template blocks. Blocks
+can be either HDU (Header Data Unit) or a GROUP. For each block the parser
+creates 1 (or more for GROUPs) FITS file HDUs.
+
+
+**E Errors
+
+In general the fits\_execute\_template() function tries to be as atomic
+as possible, so either everything is done or nothing is done. If an
+error occurs during parsing of the template, fits\_execute\_template()
+will (try to) delete the top level BLOCK (with all its children if any)
+in which the error occurred, then it will stop reading the template file
+and it will return with an error.
+
+**F Examples
+
+1. This template file will create a 200 x 300 pixel image, with 4-byte
+integer pixel values, in the primary HDU:
+-
+ SIMPLE = T
+ BITPIX = 32
+ NAXIS = 2 / number of dimensions
+ NAXIS1 = 100 / length of first axis
+ NAXIS2 = 200 / length of second axis
+ OBJECT = NGC 253 / name of observed object
+-
+The allowed values of BITPIX are 8, 16, 32, -32, or -64,
+representing, respectively, 8-bit integer, 16-bit integer, 32-bit
+integer, 32-bit floating point, or 64 bit floating point pixels.
+
+2. To create a FITS table, the template first needs to include
+XTENSION = TABLE or BINTABLE to define whether it is an ASCII or binary
+table, and NAXIS2 to define the number of rows in the table. Two
+template lines are then needed to define the name (TTYPEn) and FITS data
+format (TFORMn) of the columns, as in this example:
+-
+ xtension = bintable
+ naxis2 = 40
+ ttype# = Name
+ tform# = 10a
+ ttype# = Npoints
+ tform# = j
+ ttype# = Rate
+ tunit# = counts/s
+ tform# = e
+-
+The above example defines a null primary array followed by a 40-row
+binary table extension with 3 columns called 'Name', 'Npoints', and
+'Rate', with data formats of '10A' (ASCII character string), '1J'
+(integer) and '1E' (floating point), respectively. Note that the other
+required FITS keywords (BITPIX, NAXIS, NAXIS1, PCOUNT, GCOUNT, TFIELDS,
+and END) do not need to be explicitly defined in the template because
+their values can be inferred from the other keywords in the template.
+This example also illustrates that the templates are generally
+case-insensitive (the keyword names and TFORMn values are converted to
+upper-case in the FITS file) and that string keyword values generally
+do not need to be enclosed in quotes.
+
+*XI. Local FITS Conventions
+
+CFITSIO supports several local FITS conventions which are not
+defined in the official NOST FITS standard and which are not
+necessarily recognized or supported by other FITS software packages.
+Programmers should be cautious about using these features, especially
+if the FITS files that are produced are expected to be processed by
+other software systems which do not use the CFITSIO interface.
+
+**A. 64-Bit Long Integers
+
+CFITSIO can read and write FITS images or table columns containing
+64-bit integer data values. This data type is not recognized in the
+official FITS Standard definition document, but it is likely that FITS
+will eventually support this data type, especially as computers that
+run 64-bit operating systems become more common. Support for reading
+and writing 64-bit integers in CFITSIO can be controlled with the
+\#define statement at the beginning of the fitsio2.h file by setting
+SUPPORT\_64BIT\_INTEGERS to 1 (enable) or 0 (disable).
+
+Under the convention used by CFITSIO, FITS 64-bit images have BITPIX =
+64, and the 64-bit binary table columns have TFORMn = 'K'. The use of
+these data types on platforms where the size of a 'long' (or 'longlong')
+integer = 8 bytes is rather intuitive. CFITSIO will write 64-bit
+'long' variable values to the FITS file and read them back into 'long'
+variables just as one would expect. CFITSIO also supports implicit
+data type conversion between 64-bit integer images and columns and any
+other supported data type, although some loss of numerical precision or
+numerical overflow is likely in this case.
+
+The situation is more difficult on 32-bit computing platforms that do
+not support an intrinsic 64-bit integer data type. In this case it is
+not possible to return the full 64 precision of the FITS data values when
+reading the values into a program variable. CFITSIO will still
+convert the 64-bit integer values into any other supported data type;
+the 64-bit double data type is probably the most useful in this case.
+It only provides about 52-bits of precision in the mantissa, however,
+so some lose of precision is possible.
+
+**B. Long String Keyword Values.
+
+The length of a standard FITS string keyword is limited to 68
+characters because it must fit entirely within a single FITS header
+keyword record. In some instances it is necessary to encode strings
+longer than this limit, so CFITSIO supports a local convention in which
+the string value is continued over multiple keywords. This
+continuation convention uses an ampersand character at the end of each
+substring to indicate that it is continued on the next keyword, and the
+continuation keywords all have the name CONTINUE without an equal sign
+in column 9. The string value may be continued in this way over as many
+additional CONTINUE keywords as is required. The following lines
+illustrate this continuation convention which is used in the value of
+the STRKEY keyword:
+-
+LONGSTRN= 'OGIP 1.0' / The OGIP Long String Convention may be used.
+STRKEY = 'This is a very long string keyword&' / Optional Comment
+CONTINUE ' value that is continued over 3 keywords in the & '
+CONTINUE 'FITS header.' / This is another optional comment.
+-
+It is recommended that the LONGSTRN keyword, as shown here, always be
+included in any HDU that uses this longstring convention as a warning
+to any software that must read the keywords. A routine called fits\_write\_key\_longwarn
+has been provided in CFITSIO to write this keyword if it does not
+already exist.
+
+This long string convention is supported by the following CFITSIO
+routines:
+-
+ fits_write_key_longstr - write a long string keyword value
+ fits_insert_key_longstr - insert a long string keyword value
+ fits_modify_key_longstr - modify a long string keyword value
+ fits_update_key_longstr - modify a long string keyword value
+ fits_read_key_longstr - read a long string keyword value
+ fits_delete_key - delete a keyword
+-
+The fits\_read\_key\_longstr routine is unique among all the CFITSIO
+routines in that it internally allocates memory for the long string
+value; all the other CFITSIO routines that deal with arrays require
+that the calling program pre-allocate adequate space to hold the array
+of data. Consequently, programs which use the fits\_read\_key\_longstr
+routine must be careful to free the allocated memory for the string
+when it is no longer needed.
+
+The following 2 routines also have limited support for this long string
+convention,
+-
+ fits_modify_key_str - modify an existing string keyword value
+ fits_update_key_str - update a string keyword value
+-
+in that they will correctly overwrite an existing long string value,
+but the new string value is limited to a maximum of 68 characters in
+length.
+
+The more commonly used CFITSIO routines to write string valued keywords
+(fits\_update\_key and fits\_write\_key) do not support this long
+string convention and only support strings up to 68 characters in
+length. This has been done deliberately to prevent programs from
+inadvertently writing keywords using this non-standard convention
+without the explicit intent of the programmer or user. The
+fits\_write\_key\_longstr routine must be called instead to write long
+strings. This routine can also be used to write ordinary string values
+less than 68 characters in length.
+
+**C. Arrays of Fixed-Length Strings in Binary Tables
+
+The definition of the FITS binary table extension format does not
+provide a simple way to specify that a character column contains an
+array of fixed-length strings. To support this feature, CFITSIO uses a
+local convention for the format of the TFORMn keyword value of the form
+'rAw' where 'r' is an integer specifying the total width in characters
+of the column, and 'w' is an integer specifying the (fixed) length of
+an individual unit string within the vector. For example, TFORM1 =
+'120A10' would indicate that the binary table column is 120 characters
+wide and consists of 12 10-character length strings. This convention
+is recognized by the CFITSIO routines that read or write strings in
+binary tables. The Binary Table definition document specifies that
+other optional characters may follow the data type code in the TFORM
+keyword, so this local convention is in compliance with the
+FITS standard although other FITS readers may not
+recognize this convention.
+
+The Binary Table definition document that was approved by the IAU in
+1994 contains an appendix describing an alternate convention for
+specifying arrays of fixed or variable length strings in a binary table
+character column (with the form 'rA:SSTRw/nnn)'. This appendix was not
+officially voted on by the IAU and hence is still provisional. CFITSIO
+does not currently support this proposal.
+
+**D. Keyword Units Strings
+
+One limitation of the current FITS Standard is that it does not define
+a specific convention for recording the physical units of a keyword
+value. The TUNITn keyword can be used to specify the physical units of
+the values in a table column, but there is no analogous convention for
+keyword values. The comment field of the keyword is often used for
+this purpose, but the units are usually not specified in a well defined
+format that FITS readers can easily recognize and extract.
+
+To solve this problem, CFITSIO uses a local convention in which the
+keyword units are enclosed in square brackets as the first token in the
+keyword comment field; more specifically, the opening square bracket
+immediately follows the slash '/' comment field delimiter and a single
+space character. The following examples illustrate keywords that use
+this convention:
+
+-
+EXPOSURE= 1800.0 / [s] elapsed exposure time
+V_HELIO = 16.23 / [km s**(-1)] heliocentric velocity
+LAMBDA = 5400. / [angstrom] central wavelength
+FLUX = 4.9033487787637465E-30 / [J/cm**2/s] average flux
+-
+
+In general, the units named in the IAU(1988) Style Guide are
+recommended, with the main exception that the preferred unit for angle
+is 'deg' for degrees.
+
+The fits\_read\_key\_unit and fits\_write\_key\_unit routines in
+CFITSIO read and write, respectively, the keyword unit strings in an
+existing keyword.
+
+**E. HIERARCH Convention for Extended Keyword Names
+
+CFITSIO supports the HIERARCH keyword convention which allows keyword
+names that are longer then 8 characters and may contain the full range
+of printable ASCII text characters. This convention
+was developed at the European Southern Observatory (ESO) to support
+hierarchical FITS keyword such as:
+-
+HIERARCH ESO INS FOCU POS = -0.00002500 / Focus position
+-
+Basically, this convention uses the FITS keyword 'HIERARCH' to indicate
+that this convention is being used, then the actual keyword name
+({\tt'ESO INS FOCU POS'} in this example) begins in column 10 and can
+contain any printable ASCII text characters, including spaces. The
+equals sign marks the end of the keyword name and is followed by the
+usual value and comment fields just as in standard FITS keywords.
+Further details of this convention are described at
+http://arcdev.hq.eso.org/dicb/dicd/dic-1-1.4.html (search for
+HIERARCH).
+
+This convention allows a much broader range of keyword names
+than is allowed by the FITS Standard. Here are more examples
+of such keywords:
+-
+HIERARCH LongKeyword = 47.5 / Keyword has > 8 characters, and mixed case
+HIERARCH XTE$TEMP = 98.6 / Keyword contains the '$' character
+HIERARCH Earth is a star = F / Keyword contains embedded spaces
+-
+CFITSIO will transparently read and write these keywords, so application
+programs do not in general need to know anything about the specific
+implementation details of the HIERARCH convention. In particular,
+application programs do not need to specify the `HIERARCH' part of the
+keyword name when reading or writing keywords (although it
+may be included if desired). When writing a keyword, CFITSIO first
+checks to see if the keyword name is legal as a standard FITS keyword
+(no more than 8 characters long and containing only letters, digits, or
+a minus sign or underscore). If so it writes it as a standard FITS
+keyword, otherwise it uses the hierarch convention to write the
+keyword. The maximum keyword name length is 67 characters, which
+leaves only 1 space for the value field. A more practical limit is
+about 40 characters, which leaves enough room for most keyword values.
+CFITSIO returns an error if there is not enough room for both the
+keyword name and the keyword value on the 80-character card, except for
+string-valued keywords which are simply truncated so that the closing
+quote character falls in column 80. In the current implementation,
+CFITSIO preserves the case of the letters when writing the keyword
+name, but it is case-insensitive when reading or searching for a
+keyword. The current implementation allows any ASCII text character
+(ASCII 32 to ASCII 126) in the keyword name except for the '='
+character. A space is also required on either side of the equal sign.
+
+**F. Tile-Compressed Image Format
+
+CFITSIO supports a convention for compressing n-dimensional images and
+storing the resulting byte stream in a variable-length column in a FITS
+binary table. The general principle used in this convention is to
+first divide the n-dimensional image into a rectangular grid of
+subimages or `tiles'. Each tile is then compressed as a continuous
+block of data, and the resulting compressed byte stream is stored in a
+row of a variable length column in a FITS binary table. By dividing the
+image into tiles it is generally possible to extract and uncompress
+subsections of the image without having to uncompress the whole image.
+The default tiling pattern treats each row of a 2-dimensional image (or
+higher dimensional cube) as a tile, such that each tile contains NAXIS1
+pixels. Any other rectangular tiling pattern may also be defined. In
+the case of relatively small images it may be sufficient to compress
+the entire image as a single tile, resulting in an output binary table
+with 1 row. In the case of 3-dimensional data cubes, it may be
+advantageous to treat each plane of the cube as a separate tile if
+application software typically needs to access the cube on a plane by
+plane basis.
+
+See section 5.6 ``Image Compression''
+for more information on using this tile-compressed image format.
+
+*XII. Optimizing Programs
+
+CFITSIO has been carefully designed to obtain the highest possible
+speed when reading and writing FITS files. In order to achieve the
+best performance, however, application programmers must be careful to
+call the CFITSIO routines appropriately and in an efficient sequence;
+inappropriate usage of CFITSIO routines can greatly slow down the
+execution speed of a program.
+
+The maximum possible I/O speed of CFITSIO depends of course on the type
+of computer system that it is running on. As a rough guide, the
+current generation of workstations can achieve speeds of 2 -- 10 MB/s
+when reading or writing FITS images and similar, or slightly slower
+speeds with FITS binary tables. Reading of FITS files can occur at
+even higher rates (30MB/s or more) if the FITS file is still cached in
+system memory following a previous read or write operation on the same
+file. To more accurately predict the best performance that is possible
+on any particular system, a diagnostic program called ``speed.c'' is
+included with the CFITSIO distribution which can be run to
+approximately measure the maximum possible speed of writing and reading
+a test FITS file.
+
+The following 2 sections provide some background on how CFITSIO
+internally manages the data I/O and describes some strategies that may
+be used to optimize the processing speed of software that uses
+CFITSIO.
+
+**A. How CFITSIO Manages Data I/O
+
+Many CFITSIO operations involve transferring only a small number of
+bytes to or from the FITS file (e.g, reading a keyword, or writing a
+row in a table); it would be very inefficient to physically read or
+write such small blocks of data directly in the FITS file on disk,
+therefore CFITSIO maintains a set of internal Input--Output (IO)
+buffers in RAM memory that each contain one FITS block (2880 bytes) of
+data. Whenever CFITSIO needs to access data in the FITS file, it first
+transfers the FITS block containing those bytes into one of the IO
+buffers in memory. The next time CFITSIO needs to access bytes in the
+same block it can then go to the fast IO buffer rather than using a
+much slower system disk access routine. The number of available IO
+buffers is determined by the NIOBUF parameter (in fitsio2.h) and is
+currently set to 40 by default.
+
+Whenever CFITSIO reads or writes data it first checks to see if that
+block of the FITS file is already loaded into one of the IO buffers.
+If not, and if there is an empty IO buffer available, then it will load
+that block into the IO buffer (when reading a FITS file) or will
+initialize a new block (when writing to a FITS file). If all the IO
+buffers are already full, it must decide which one to reuse (generally
+the one that has been accessed least recently), and flush the contents
+back to disk if it has been modified before loading the new block.
+
+The one major exception to the above process occurs whenever a large
+contiguous set of bytes are accessed, as might occur when reading or
+writing a FITS image. In this case CFITSIO bypasses the internal IO
+buffers and simply reads or writes the desired bytes directly in the
+disk file with a single call to a low-level file read or write
+routine. The minimum threshold for the number of bytes to read or
+write this way is set by the MINDIRECT parameter and is currently set
+to 3 FITS blocks = 8640 bytes. This is the most efficient way to read
+or write large chunks of data and can achieve IO transfer rates of
+5 -- 10MB/s or greater. Note that this fast direct IO process is not
+applicable when accessing columns of data in a FITS table because the
+bytes are generally not contiguous since they are interleaved by the
+other columns of data in the table. This explains why the speed for
+accessing FITS tables is generally slower than accessing
+FITS images.
+
+Given this background information, the general strategy for efficiently
+accessing FITS files should be apparent: when dealing with FITS
+images, read or write large chunks of data at a time so that the direct
+IO mechanism will be invoked; when accessing FITS headers or FITS
+tables, on the other hand, once a particular FITS block has been
+loading into one of the IO buffers, try to access all the needed
+information in that block before it gets flushed out of the IO buffer.
+It is important to avoid the situation where the same FITS block is
+being read then flushed from a IO buffer multiple times.
+
+The following section gives more specific suggestions for optimizing
+the use of CFITSIO.
+
+**B. Optimization Strategies
+
+1. When dealing with a FITS primary array or IMAGE extension, it is
+more efficient to read or write large chunks of the image at a time
+(at least 3 FITS blocks = 8640 bytes) so that the direct IO mechanism
+will be used as described in the previous section. Smaller chunks of
+data are read or written via the IO buffers, which is somewhat less
+efficient because of the extra copy operation and additional
+bookkeeping steps that are required. In principle it is more efficient
+to read or write as big an array of image pixels at one time as
+possible, however, if the array becomes so large that the operating
+system cannot store it all in RAM, then the performance may be degraded
+because of the increased swapping of virtual memory to disk.
+
+2. When dealing with FITS tables, the most important efficiency factor
+in the software design is to read or write the data in the FITS file in
+a single pass through the file. An example of poor program design
+would be to read a large, 3-column table by sequentially reading the
+entire first column, then going back to read the 2nd column, and
+finally the 3rd column; this obviously requires 3 passes through the
+file which could triple the execution time of an IO limited program.
+For small tables this is not important, but when reading multi-megabyte
+sized tables these inefficiencies can become significant. The more
+efficient procedure in this case is to read or write only as many rows
+of the table as will fit into the available internal IO buffers, then
+access all the necessary columns of data within that range of rows.
+Then after the program is completely finished with the data in those
+rows it can move on to the next range of rows that will fit in the
+buffers, continuing in this way until the entire file has been
+processed. By using this procedure of accessing all the columns of a
+table in parallel rather than sequentially, each block of the FITS file
+will only be read or written once.
+
+The optimal number of rows to read or write at one time in a given
+table depends on the width of the table row, on the number of IO
+buffers that have been allocated in CFITSIO, and also on the number of
+other FITS files that are open at the same time (since one IO buffer is
+always reserved for each open FITS file). The CFITSIO Iterator routine
+will automatically use the optimal-sized buffer, but there is also a
+CFITSIO routine that will return the optimal number of rows for a given
+table: fits\_get\_rowsize. It is not critical to use exactly the
+value of nrows returned by this routine, as long as one does not exceed
+it. Using a very small value however can also lead to poor performance
+because of the overhead from the larger number of subroutine calls.
+
+The optimal number of rows returned by fits\_get\_rowsize is valid only
+as long as the application program is only reading or writing data in
+the specified table. Any other calls to access data in the table
+header or in any other FITS file would cause additional blocks of data
+to be loaded into the IO buffers displacing data from the original
+table, and should be avoided during the critical period while the table
+is being read or written.
+
+Occasionally it is necessary to simultaneously access more than one
+FITS table, for example when transferring values from an input table to
+an output table. In cases like this, one should call
+fits\_get\_rowsize to get the optimal number of rows for each table
+separately, than reduce the number of rows proportionally. For
+example, if the optimal number of rows in the input table is 3600 and
+is 1400 in the output table, then these values should be cut in half to
+1800 and 700, respectively, if both tables are going to be accessed at
+the same time.
+
+3. Use the CFITSIO Iterator routine. This routine provides a
+more `object oriented' way of reading and writing FITS files
+which automatically uses the most appropriate data buffer size
+to achieve the maximum I/O throughput.
+
+4. Use binary table extensions rather than ASCII table
+extensions for better efficiency when dealing with tabular data. The
+I/O to ASCII tables is slower because of the overhead in formatting or
+parsing the ASCII data fields and because ASCII tables are about twice
+as large as binary tables with the same information content.
+
+5. Design software so that it reads the FITS header keywords in the
+same order in which they occur in the file. When reading keywords,
+CFITSIO searches forward starting from the position of the last keyword
+that was read. If it reaches the end of the header without finding the
+keyword, it then goes back to the start of the header and continues the
+search down to the position where it started. In practice, as long as
+the entire FITS header can fit at one time in the available internal IO
+buffers, then the header keyword access will be very fast and it makes
+little difference which order they are accessed.
+
+6. Avoid the use of scaling (by using the BSCALE and BZERO or TSCAL and
+TZERO keywords) in FITS files since the scaling operations add to the
+processing time needed to read or write the data. In some cases it may
+be more efficient to temporarily turn off the scaling (using fits\_set\_bscale or
+fits\_set\_tscale) and then read or write the raw unscaled values in the FITS
+file.
+
+7. Avoid using the `implicit data type conversion' capability in
+CFITSIO. For instance, when reading a FITS image with BITPIX = -32
+(32-bit floating point pixels), read the data into a single precision
+floating point data array in the program. Forcing CFITSIO to convert
+the data to a different data type can slow the program.
+
+8. Where feasible, design FITS binary tables using vector column
+elements so that the data are written as a contiguous set of bytes,
+rather than as single elements in multiple rows. For example, it is
+faster to access the data in a table that contains a single row
+and 2 columns with TFORM keywords equal to '10000E' and '10000J', than
+it is to access the same amount of data in a table with 10000 rows
+which has columns with the TFORM keywords equal to '1E' and '1J'. In
+the former case the 10000 floating point values in the first column are
+all written in a contiguous block of the file which can be read or
+written quickly, whereas in the second case each floating point value
+in the first column is interleaved with the integer value in the second
+column of the same row so CFITSIO has to explicitly move to the
+position of each element to be read or written.
+
+9. Avoid the use of variable length vector columns in binary tables,
+since any reading or writing of these data requires that CFITSIO first
+look up or compute the starting address of each row of data in the
+heap.
+
+10. When copying data from one FITS table to another, it is faster to
+transfer the raw bytes instead of reading then writing each column of
+the table. The CFITSIO routines fits\_read\_tblbytes and
+fits\_write\_tblbytes will perform low-level reads or writes of any
+contiguous range of bytes in a table extension. These routines can be
+used to read or write a whole row (or multiple rows for even greater
+efficiency) of a table with a single function call. These routines
+are fast because they bypass all the usual data scaling, error checking
+and machine dependent data conversion that is normally done by CFITSIO,
+and they allow the program to write the data to the output file in
+exactly the same byte order. For these same reasons, these routines
+can corrupt the FITS data file if used incorrectly because no
+validation or machine dependent conversion is performed by these
+routines. These routines are only recommended for optimizing critical
+pieces of code and should only be used by programmers who thoroughly
+understand the internal format of the FITS tables they are reading or
+writing.
+
+11. Another strategy for improving the speed of writing a FITS table,
+similar to the previous one, is to directly construct the entire byte
+stream for a whole table row (or multiple rows) within the application
+program and then write it to the FITS file with
+fits\_write\_tblbytes. This avoids all the overhead normally present
+in the column-oriented CFITSIO write routines. This technique should
+only be used for critical applications because it makes the code more
+difficult to understand and maintain, and it makes the code more system
+dependent (e.g., do the bytes need to be swapped before writing to the
+FITS file?).
+
+12. Finally, external factors such as the type of magnetic disk
+controller (SCSI or IDE), the size of the disk cache, the average seek
+speed of the disk, the amount of disk fragmentation, and the amount of
+RAM available on the system can all have a significant impact on
+overall I/O efficiency. For critical applications, a system
+administrator should review the proposed system hardware to identify any
+potential I/O bottlenecks.
+
+
+\appendix
+*1 Index of Routines
+\begin{tabular}{lr}
+fits\_add\_group\_member & \pageref{ffgtam} \\
+fits\_ascii\_tform & \pageref{ffasfm} \\
+fits\_binary\_tform & \pageref{ffbnfm} \\
+fits\_calculator & \pageref{ffcalc} \\
+fits\_calculator\_rng & \pageref{ffcalcrng} \\
+fits\_calc\_rows & \pageref{ffcrow} \\
+fits\_change\_group & \pageref{ffgtch} \\
+fits\_clear\_errmark & \pageref{ffpmrk} \\
+fits\_clear\_errmsg & \pageref{ffcmsg} \\
+fits\_close\_file & \pageref{ffclos} \\
+fits\_compact\_group & \pageref{ffgtcm} \\
+fits\_compare\_str & \pageref{ffcmps} \\
+fits\_compress\_heap & \pageref{ffcmph} \\
+fits\_copy\_col & \pageref{ffcpcl} \\
+fits\_copy\_data & \pageref{ffcpdt} \\
+fits\_copy\_file & \pageref{ffcpfl} \\
+fits\_copy\_group & \pageref{ffgtcp} \\
+fits\_copy\_hdu & \pageref{ffcopy} \\
+fits\_copy\_header & \pageref{ffcphd} \\
+fits\_copy\_key & \pageref{ffcpky} \\
+fits\_copy\_member & \pageref{ffgmcp} \\
+fits\_create\_diskfile & \pageref{ffinit} \\
+fits\_create\_file & \pageref{ffinit} \\
+fits\_create\_group & \pageref{ffgtcr} \\
+fits\_create\_hdu & \pageref{ffcrhd} \\
+fits\_create\_img & \pageref{ffcrim} \\
+fits\_create\_memfile & \pageref{ffimem} \\
+fits\_create\_tbl & \pageref{ffcrtb} \\
+fits\_create\_template & \pageref{fftplt} \\
+fits\_date2str & \pageref{ffdt2s} \\
+fits\_decode\_chksum & \pageref{ffdsum} \\
+fits\_decode\_tdim & \pageref{ffdtdm} \\
+
+\end{tabular}
+\begin{tabular}{lr}
+fits\_delete\_col & \pageref{ffdcol} \\
+fits\_delete\_file & \pageref{ffdelt} \\
+fits\_delete\_hdu & \pageref{ffdhdu} \\
+fits\_delete\_key & \pageref{ffdkey} \\
+fits\_delete\_record & \pageref{ffdrec} \\
+fits\_delete\_rowlist & \pageref{ffdrws} \\
+fits\_delete\_rowrange & \pageref{ffdrrg} \\
+fits\_delete\_rows & \pageref{ffdrow} \\
+fits\_encode\_chksum & \pageref{ffesum} \\
+fits\_file\_exists & \pageref{ffexist} \\
+fits\_file\_mode & \pageref{ffflmd} \\
+fits\_file\_name & \pageref{ffflnm} \\
+fits\_find\_first\_row & \pageref{ffffrw} \\
+fits\_find\_nextkey & \pageref{ffgnxk} \\
+fits\_find\_rows & \pageref{fffrow} \\
+fits\_flush\_buffer & \pageref{ffflus} \\
+fits\_flush\_file & \pageref{ffflus} \\
+fits\_get\_acolparms & \pageref{ffgacl} \\
+fits\_get\_bcolparms & \pageref{ffgbcl} \\
+fits\_get\_chksum & \pageref{ffgcks} \\
+fits\_get\_col\_display\_width & \pageref{ffgcdw} \\
+fits\_get\_colname & \pageref{ffgcnn} \\
+fits\_get\_colnum & \pageref{ffgcno} \\
+fits\_get\_coltype & \pageref{ffgtcl} \\
+fits\_get\_compression\_type & \pageref{ffgetcomp} \\
+fits\_get\_eqcoltype & \pageref{ffgtcl} \\
+fits\_get\_errstatus & \pageref{ffgerr} \\
+fits\_get\_hdrpos & \pageref{ffghps} \\
+fits\_get\_hdrspace & \pageref{ffghsp} \\
+fits\_get\_hdu\_num & \pageref{ffghdn} \\
+fits\_get\_hdu\_type & \pageref{ffghdt} \\
+fits\_get\_hduaddr & \pageref{ffghad} \\
+\end{tabular}
+\begin{tabular}{lr}
+fits\_get\_hduoff & \pageref{ffghad} \\
+fits\_get\_img\_dim & \pageref{ffgidm} \\
+fits\_get\_img\_equivtype & \pageref{ffgidt} \\
+fits\_get\_img\_param & \pageref{ffgipr} \\
+fits\_get\_img\_size & \pageref{ffgisz} \\
+fits\_get\_img\_type & \pageref{ffgidt} \\
+fits\_get\_keyclass & \pageref{ffgkcl} \\
+fits\_get\_keyname & \pageref{ffgknm} \\
+fits\_get\_keytype & \pageref{ffdtyp} \\
+fits\_get\_noise\_bits & \pageref{ffgetcomp} \\
+fits\_get\_num\_cols & \pageref{ffgnrw} \\
+fits\_get\_num\_groups & \pageref{ffgmng} \\
+fits\_get\_num\_hdus & \pageref{ffthdu} \\
+fits\_get\_num\_members & \pageref{ffgtnm} \\
+fits\_get\_num\_rows & \pageref{ffgnrw} \\
+fits\_get\_rowsize & \pageref{ffgrsz} \\
+fits\_get\_system\_time & \pageref{ffdt2s} \\
+fits\_get\_tile\_dim & \pageref{ffgetcomp} \\
+fits\_get\_tbcol & \pageref{ffgabc} \\
+fits\_get\_version & \pageref{ffvers} \\
+fits\_hdr2str & \pageref{ffhdr2str}, \pageref{hdr2str} \\
+fits\_insert\_atbl & \pageref{ffitab} \\
+fits\_insert\_btbl & \pageref{ffibin} \\
+fits\_insert\_col & \pageref{fficol} \\
+fits\_insert\_cols & \pageref{fficls} \\
+fits\_insert\_group & \pageref{ffgtis} \\
+fits\_insert\_img & \pageref{ffiimg} \\
+fits\_insert\_key\_null & \pageref{ffikyu} \\
+fits\_insert\_key\_TYP & \pageref{ffikyx} \\
+fits\_insert\_record & \pageref{ffirec} \\
+fits\_insert\_rows & \pageref{ffirow} \\
+fits\_iterate\_data & \pageref{ffiter} \\
+\end{tabular}
+\newpage
+\begin{tabular}{lr}
+fits\_make\_keyn & \pageref{ffkeyn} \\
+fits\_make\_nkey & \pageref{ffnkey} \\
+fits\_merge\_groups & \pageref{ffgtmg} \\
+fits\_modify\_card & \pageref{ffmcrd} \\
+fits\_modify\_comment & \pageref{ffmcom} \\
+fits\_modify\_key\_null & \pageref{ffmkyu} \\
+fits\_modify\_key\_TYP & \pageref{ffmkyx} \\
+fits\_modify\_name & \pageref{ffmnam} \\
+fits\_modify\_record & \pageref{ffmrec} \\
+fits\_modify\_vector\_len & \pageref{ffmvec} \\
+fits\_movabs\_hdu & \pageref{ffmahd} \\
+fits\_movnam\_hdu & \pageref{ffmnhd} \\
+fits\_movrel\_hdu & \pageref{ffmrhd} \\
+fits\_null\_check & \pageref{ffnchk} \\
+fits\_open\_data & \pageref{ffopen} \\
+fits\_open\_diskfile & \pageref{ffopen} \\
+fits\_open\_file & \pageref{ffopen} \\
+fits\_open\_image & \pageref{ffopen} \\
+fits\_open\_table & \pageref{ffopen} \\
+fits\_open\_group & \pageref{ffgtop} \\
+fits\_open\_member & \pageref{ffgmop} \\
+fits\_open\_memfile & \pageref{ffomem} \\
+fits\_parse\_extnum & \pageref{ffextn} \\
+fits\_parse\_input\_url & \pageref{ffiurl} \\
+fits\_parse\_range & \pageref{ffrwrg} \\
+fits\_parse\_rootname & \pageref{ffrtnm} \\
+fits\_parse\_template & \pageref{ffgthd} \\
+fits\_parse\_value & \pageref{ffpsvc} \\
+fits\_pix\_to\_world & \pageref{ffwldp} \\
+fits\_read\_2d\_TYP & \pageref{ffg2dx} \\
+fits\_read\_3d\_TYP & \pageref{ffg3dx} \\
+fits\_read\_atblhdr & \pageref{ffghtb} \\
+fits\_read\_btblhdr & \pageref{ffghbn} \\
+fits\_read\_card & \pageref{ffgcrd} \\
+fits\_read\_col & \pageref{ffgcv} \\
+fits\_read\_col\_bit\_ & \pageref{ffgcx} \\
+fits\_read\_col\_TYP & \pageref{ffgcvx} \\
+fits\_read\_colnull & \pageref{ffgcf} \\
+fits\_read\_colnull\_TYP & \pageref{ffgcfx} \\
+fits\_read\_descript & \pageref{ffgdes} \\
+fits\_read\_descripts & \pageref{ffgdes} \\
+fits\_read\_errmsg & \pageref{ffgmsg} \\
+fits\_read\_grppar\_TYP & \pageref{ffggpx} \\
+fits\_read\_img & \pageref{ffgpv} \\
+fits\_read\_img\_coord & \pageref{ffgics} \\
+fits\_read\_img\_TYP & \pageref{ffgpvx} \\
+fits\_read\_imghdr & \pageref{ffghpr} \\
+
+\end{tabular}
+\begin{tabular}{lr}
+fits\_read\_imgnull & \pageref{ffgpf} \\
+fits\_read\_imgnull\_TYP & \pageref{ffgpfx} \\
+fits\_read\_key & \pageref{ffgky} \\
+fits\_read\_key\_longstr & \pageref{ffgkls} \\
+fits\_read\_key\_triple & \pageref{ffgkyt} \\
+fits\_read\_key\_unit & \pageref{ffgunt} \\
+fits\_read\_key\_TYP & \pageref{ffgkyx} \\
+fits\_read\_keyn & \pageref{ffgkyn} \\
+fits\_read\_keys\_TYP & \pageref{ffgknx} \\
+fits\_read\_keyword & \pageref{ffgkey} \\
+fits\_read\_pix & \pageref{ffgpxv} \\
+fits\_read\_pixnull & \pageref{ffgpxf} \\
+fits\_read\_record & \pageref{ffgrec} \\
+fits\_read\_subset\_TYP & \pageref{ffgsvx} \pageref{ffgsvx2}\\
+fits\_read\_subsetnull\_TYP & \pageref{ffgsfx} \pageref{ffgsfx2} \\
+fits\_read\_tbl\_coord & \pageref{ffgtcs} \\
+fits\_read\_tblbytes & \pageref{ffgtbb} \\
+fits\_read\_tdim & \pageref{ffgtdm} \\
+fits\_remove\_group & \pageref{ffgtrm} \\
+fits\_remove\_member & \pageref{ffgmrm} \\
+fits\_reopen\_file & \pageref{ffreopen} \\
+fits\_report\_error & \pageref{ffrprt} \\
+fits\_resize\_img & \pageref{ffrsim} \\
+fits\_select\_rows & \pageref{ffsrow} \\
+fits\_set\_atblnull & \pageref{ffsnul} \\
+fits\_set\_bscale & \pageref{ffpscl} \\
+fits\_set\_btblnull & \pageref{fftnul} \\
+fits\_set\_compression\_type & \pageref{ffsetcomp} \\
+fits\_set\_hdrsize & \pageref{ffhdef} \\
+fits\_set\_hdustruc & \pageref{ffrdef} \\
+fits\_set\_imgnull & \pageref{ffpnul} \\
+fits\_set\_noise\_bits & \pageref{ffsetcomp} \\
+fits\_set\_tile\_dim & \pageref{ffsetcomp} \\
+fits\_set\_tscale & \pageref{fftscl} \\
+fits\_split\_names & \pageref{splitnames} \\
+fits\_str2date & \pageref{ffdt2s} \\
+fits\_str2time & \pageref{ffdt2s} \\
+fits\_test\_expr & \pageref{fftexp} \\
+fits\_test\_heap & \pageref{fftheap} \\
+fits\_test\_keyword & \pageref{fftkey} \\
+fits\_test\_record & \pageref{fftrec} \\
+fits\_time2str & \pageref{ffdt2s} \\
+fits\_transfer\_member & \pageref{ffgmtf} \\
+fits\_update\_card & \pageref{ffucrd} \\
+fits\_update\_chksum & \pageref{ffupck} \\
+fits\_update\_key & \pageref{ffuky} \\
+fits\_update\_key\_null & \pageref{ffukyu} \\
+fits\_update\_key\_TYP & \pageref{ffukyx} \\
+\end{tabular}
+\begin{tabular}{lr}
+
+fits\_uppercase & \pageref{ffupch} \\
+fits\_url\_type & \pageref{ffurlt} \\
+fits\_verify\_chksum & \pageref{ffvcks} \\
+fits\_verify\_group & \pageref{ffgtvf} \\
+fits\_world\_to\_pix & \pageref{ffxypx} \\
+fits\_write\_2d\_TYP & \pageref{ffp2dx} \\
+fits\_write\_3d\_TYP & \pageref{ffp3dx} \\
+fits\_write\_atblhdr & \pageref{ffphtb} \\
+fits\_write\_btblhdr & \pageref{ffphbn} \\
+fits\_write\_chksum & \pageref{ffpcks} \\
+fits\_write\_col & \pageref{ffpcl} \\
+fits\_write\_col\_bit & \pageref{ffpclx} \\
+fits\_write\_col\_TYP & \pageref{ffpcls} \\
+fits\_write\_col\_null & \pageref{ffpclu} \\
+fits\_write\_colnull & \pageref{ffpcn} \\
+fits\_write\_colnull\_TYP & \pageref{ffpcnx} \\
+fits\_write\_comment & \pageref{ffpcom} \\
+fits\_write\_date & \pageref{ffpdat} \\
+fits\_write\_descript & \pageref{ffpdes} \\
+fits\_write\_errmark & \pageref{ffpmrk} \\
+fits\_write\_errmsg & \pageref{ffpmsg} \\
+fits\_write\_grphdr & \pageref{ffphpr} \\
+fits\_write\_grppar\_TYP & \pageref{ffpgpx} \\
+fits\_write\_history & \pageref{ffphis} \\
+fits\_write\_img & \pageref{ffppr} \\
+fits\_write\_img\_null & \pageref{ffppru} \\
+fits\_write\_img\_TYP & \pageref{ffpprx} \\
+fits\_write\_imghdr & \pageref{ffphps} \\
+fits\_write\_imgnull & \pageref{ffppn} \\
+fits\_write\_imgnull\_TYP & \pageref{ffppnx} \\
+fits\_write\_key & \pageref{ffpky} \\
+fits\_write\_key\_longstr & \pageref{ffpkls} \\
+fits\_write\_key\_longwarn & \pageref{ffplsw} \\
+fits\_write\_key\_null & \pageref{ffpkyu} \\
+fits\_write\_key\_template & \pageref{ffpktp} \\
+fits\_write\_key\_triple & \pageref{ffpkyt} \\
+fits\_write\_key\_unit & \pageref{ffpunt} \\
+fits\_write\_key\_TYP & \pageref{ffpkyx} \\
+fits\_write\_keys\_TYP & \pageref{ffpknx} \\
+fits\_write\_null\_img & \pageref{ffpprn} \\
+fits\_write\_pix & \pageref{ffppx} \\
+fits\_write\_pixnull & \pageref{ffppxn} \\
+fits\_write\_record & \pageref{ffprec} \\
+fits\_write\_subset & \pageref{ffpss} \\
+fits\_write\_subset\_TYP & \pageref{ffpssx} \\
+fits\_write\_tblbytes & \pageref{ffptbb} \\
+fits\_write\_tdim & \pageref{ffptdm} \\
+fits\_write\_theap & \pageref{ffpthp} \\
+\end{tabular}
+\newpage
+
+\begin{tabular}{lr}
+ffasfm & \pageref{ffasfm} \\
+ffbnfm & \pageref{ffbnfm} \\
+ffcalc & \pageref{ffcalc} \\
+ffcalc\_rng & \pageref{ffcalcrng} \\
+ffclos & \pageref{ffclos} \\
+ffcmph & \pageref{ffcmph} \\
+ffcmps & \pageref{ffcmps} \\
+ffcmrk & \pageref{ffpmrk} \\
+ffcmsg & \pageref{ffcmsg} \\
+ffcopy & \pageref{ffcopy} \\
+ffcpcl & \pageref{ffcpcl} \\
+ffcpdt & \pageref{ffcpdt} \\
+ffcpfl & \pageref{ffcpfl} \\
+ffcphd & \pageref{ffcphd} \\
+ffcpky & \pageref{ffcpky} \\
+ffcrhd & \pageref{ffcrhd} \\
+ffcrim & \pageref{ffcrim} \\
+ffcrow & \pageref{ffcrow} \\
+ffcrtb & \pageref{ffcrtb} \\
+ffdcol & \pageref{ffdcol} \\
+ffdelt & \pageref{ffdelt} \\
+ffdhdu & \pageref{ffdhdu} \\
+ffdkey & \pageref{ffdkey} \\
+ffdkinit & \pageref{ffinit} \\
+ffdkopen & \pageref{ffopen} \\
+ffdopn & \pageref{ffopen} \\
+ffdrec & \pageref{ffdrec} \\
+ffdrow & \pageref{ffdrow} \\
+ffdrrg & \pageref{ffdrrg} \\
+ffdrws & \pageref{ffdrws} \\
+ffdsum & \pageref{ffdsum} \\
+ffdt2s & \pageref{ffdt2s} \\
+ffdtdm & \pageref{ffdtdm} \\
+ffdtyp & \pageref{ffdtyp} \\
+ffeqty & \pageref{ffgtcl} \\
+ffesum & \pageref{ffesum} \\
+ffexest & \pageref{ffexist} \\
+ffextn & \pageref{ffextn} \\
+ffffrw & \pageref{ffffrw} \\
+ffflmd & \pageref{ffflmd} \\
+ffflnm & \pageref{ffflnm} \\
+ffflsh & \pageref{ffflus} \\
+ffflus & \pageref{ffflus} \\
+fffrow & \pageref{fffrow} \\
+ffg2d\_ & \pageref{ffg2dx} \\
+ffg3d\_ & \pageref{ffg3dx} \\
+ffgabc & \pageref{ffgabc} \\
+\end{tabular}
+\begin{tabular}{lr}
+ffgacl & \pageref{ffgacl} \\
+ffgbcl & \pageref{ffgbcl} \\
+ffgcdw & \pageref{ffgcdw} \\
+ffgcf & \pageref{ffgcf} \\
+ffgcf\_ & \pageref{ffgcfx} \\
+ffgcks & \pageref{ffgcks} \\
+ffgcnn & \pageref{ffgcnn} \\
+ffgcno & \pageref{ffgcno} \\
+ffgcrd & \pageref{ffgcrd} \\
+ffgcv & \pageref{ffgcv} \\
+ffgcv\_ & \pageref{ffgcvx} \\
+ffgcx & \pageref{ffgcx} \\
+ffgdes & \pageref{ffgdes} \\
+ffgdess & \pageref{ffgdes} \\
+ffgerr & \pageref{ffgerr} \\
+ffggp\_ & \pageref{ffggpx} \\
+ffghad & \pageref{ffghad} \\
+ffghbn & \pageref{ffghbn} \\
+ffghdn & \pageref{ffghdn} \\
+ffghdt & \pageref{ffghdt} \\
+ffghof & \pageref{ffghad} \\
+ffghpr & \pageref{ffghpr} \\
+ffghps & \pageref{ffghps} \\
+ffghsp & \pageref{ffghsp} \\
+ffghtb & \pageref{ffghtb} \\
+ffgics & \pageref{ffgics} \\
+ffgidm & \pageref{ffgidm} \\
+ffgidt & \pageref{ffgidt} \\
+ffgiet & \pageref{ffgidt} \\
+ffgipr & \pageref{ffgipr} \\
+ffgisz & \pageref{ffgisz} \\
+ffgkcl & \pageref{ffgkcl} \\
+ffgkey & \pageref{ffgkey} \\
+ffgkls & \pageref{ffgkls} \\
+ffgkn\_ & \pageref{ffgknx} \\
+ffgknm & \pageref{ffgknm} \\
+ffgky & \pageref{ffgky} \\
+ffgkyn & \pageref{ffgkyn} \\
+ffgkyt & \pageref{ffgkyt} \\
+ffgky\_ & \pageref{ffgkyx} \\
+ffgmcp & \pageref{ffgmcp} \\
+ffgmng & \pageref{ffgmng} \\
+ffgmop & \pageref{ffgmop} \\
+ffgmrm & \pageref{ffgmrm} \\
+ffgmsg & \pageref{ffgmsg} \\
+ffgmtf & \pageref{ffgmtf} \\
+ffgncl & \pageref{ffgnrw} \\
+
+\end{tabular}
+\begin{tabular}{lr}
+ffgnrw & \pageref{ffgnrw} \\
+ffgnxk & \pageref{ffgnxk} \\
+ffgpf & \pageref{ffgpf} \\
+ffgpf\_ & \pageref{ffgpfx} \\
+ffgpv & \pageref{ffgpv} \\
+ffgpv\_ & \pageref{ffgpvx} \\
+ffgpxv & \pageref{ffgpxv} \\
+ffgpxf & \pageref{ffgpxf} \\
+ffgrec & \pageref{ffgrec} \\
+ffgrsz & \pageref{ffgrsz} \\
+ffgsdt & \pageref{ffdt2s} \\
+ffgsf\_ & \pageref{ffgsfx} \pageref{ffgsfx2} \\
+ffgstm & \pageref{ffdt2s} \\
+ffgsv\_ & \pageref{ffgsvx} \pageref{ffgsvx2}\\
+ffgtam & \pageref{ffgtam} \\
+ffgtbb & \pageref{ffgtbb} \\
+ffgtch & \pageref{ffgtch} \\
+ffgtcl & \pageref{ffgtcl} \\
+ffgtcm & \pageref{ffgtcm} \\
+ffgtcp & \pageref{ffgtcp} \\
+ffgtcr & \pageref{ffgtcr} \\
+ffgtcs & \pageref{ffgtcs} \\
+ffgtdm & \pageref{ffgtdm} \\
+ffgthd & \pageref{ffgthd} \\
+ffgtis & \pageref{ffgtis} \\
+ffgtmg & \pageref{ffgtmg} \\
+ffgtnm & \pageref{ffgtnm} \\
+ffgtop & \pageref{ffgtop} \\
+ffgtrm & \pageref{ffgtrm} \\
+ffgtvf & \pageref{ffgtvf} \\
+ffgunt & \pageref{ffgunt} \\
+ffhdef & \pageref{ffhdef} \\
+ffibin & \pageref{ffibin} \\
+fficls & \pageref{fficls} \\
+fficol & \pageref{fficol} \\
+ffiimg & \pageref{ffiimg} \\
+ffikls & \pageref{ffikyx} \\
+ffikyu & \pageref{ffikyu} \\
+ffiky\_ & \pageref{ffikyx} \\
+ffimem & \pageref{ffimem} \\
+ffinit & \pageref{ffinit} \\
+ffiopn & \pageref{ffopen} \\
+ffirec & \pageref{ffirec} \\
+ffirow & \pageref{ffirow} \\
+ffitab & \pageref{ffitab} \\
+ffiter & \pageref{ffiter} \\
+ffiurl & \pageref{ffiurl} \\
+
+\end{tabular}
+\begin{tabular}{lr}
+ffkeyn & \pageref{ffkeyn} \\
+ffmahd & \pageref{ffmahd} \\
+ffmcom & \pageref{ffmcom} \\
+ffmcrd & \pageref{ffmcrd} \\
+ffmkls & \pageref{ffmkyx} \\
+ffmkyu & \pageref{ffmkyu} \\
+ffmky\_ & \pageref{ffmkyx} \\
+ffmnam & \pageref{ffmnam} \\
+ffmnhd & \pageref{ffmnhd} \\
+ffmrec & \pageref{ffmrec} \\
+ffmrhd & \pageref{ffmrhd} \\
+ffmvec & \pageref{ffmvec} \\
+ffnchk & \pageref{ffnchk} \\
+ffnkey & \pageref{ffnkey} \\
+ffomem & \pageref{ffomem} \\
+ffopen & \pageref{ffopen} \\
+ffp2d\_ & \pageref{ffp2dx} \\
+ffp3d\_ & \pageref{ffp3dx} \\
+ffpcks & \pageref{ffpcks} \\
+ffpcl & \pageref{ffpcl} \\
+ffpcls & \pageref{ffpcls} \\
+ffpcl\_ & \pageref{ffpclx} \\
+ffpclu & \pageref{ffpclu} \\
+ffpcn & \pageref{ffpcn} \\
+ffpcn\_ & \pageref{ffpcnx} \\
+ffpcom & \pageref{ffpcom} \\
+ffpdat & \pageref{ffpdat} \\
+ffpdes & \pageref{ffpdes} \\
+ffpgp\_ & \pageref{ffpgpx} \\
+ffphbn & \pageref{ffphbn} \\
+ffphis & \pageref{ffphis} \\
+ffphpr & \pageref{ffphpr} \\
+ffphps & \pageref{ffphps} \\
+ffphtb & \pageref{ffphtb} \\
+ffpkls & \pageref{ffpkls} \\
+ffpkn\_ & \pageref{ffpknx} \\
+ffpktp & \pageref{ffpktp} \\
+ffpky & \pageref{ffpky} \\
+ffpkyt & \pageref{ffpkyt} \\
+ffpkyu & \pageref{ffpkyu} \\
+ffpky\_ & \pageref{ffpkyx} \\
+ffplsw & \pageref{ffplsw} \\
+ffpmrk & \pageref{ffpmrk} \\
+ffpmsg & \pageref{ffpmsg} \\
+ffpnul & \pageref{ffpnul} \\
+ffppn & \pageref{ffppn} \\
+ffppn\_ & \pageref{ffppnx} \\
+
+\end{tabular}
+\begin{tabular}{lr}
+ffppr & \pageref{ffppr} \\
+ffpprn & \pageref{ffpprn} \\
+ffppru & \pageref{ffppru} \\
+ffppr\_ & \pageref{ffpprx} \\
+ffppx & \pageref{ffppx} \\
+ffppxn & \pageref{ffppxn} \\
+ffprec & \pageref{ffprec} \\
+ffpscl & \pageref{ffpscl} \\
+ffpss & \pageref{ffpss} \\
+ffpss\_ & \pageref{ffpssx} \\
+ffpsvc & \pageref{ffpsvc} \\
+ffptbb & \pageref{ffptbb} \\
+ffptdm & \pageref{ffptdm} \\
+ffpthp & \pageref{ffpthp} \\
+ffpunt & \pageref{ffpunt} \\
+ffrdef & \pageref{ffrdef} \\
+ffreopen & \pageref{ffreopen} \\
+ffrprt & \pageref{ffrprt} \\
+ffrsim & \pageref{ffrsim} \\
+ffrtnm & \pageref{ffrtnm} \\
+ffrwrg & \pageref{ffrwrg} \\
+ffs2dt & \pageref{ffdt2s} \\
+ffs2tm & \pageref{ffdt2s} \\
+ffsnul & \pageref{ffsnul} \\
+ffsrow & \pageref{ffsrow} \\
+fftexp & \pageref{fftexp} \\
+ffthdu & \pageref{ffthdu} \\
+fftheap & \pageref{fftheap} \\
+fftkey & \pageref{fftkey} \\
+fftm2s & \pageref{ffdt2s} \\
+fftnul & \pageref{fftnul} \\
+fftopn & \pageref{ffopen} \\
+fftplt & \pageref{fftplt} \\
+fftrec & \pageref{fftrec} \\
+fftscl & \pageref{fftscl} \\
+ffucrd & \pageref{ffucrd} \\
+ffukls & \pageref{ffukyx} \\
+ffuky & \pageref{ffuky} \\
+ffukyu & \pageref{ffukyu} \\
+ffuky\_ & \pageref{ffukyx} \\
+ffupch & \pageref{ffupch} \\
+ffupck & \pageref{ffupck} \\
+ffurlt & \pageref{ffurlt} \\
+ffvcks & \pageref{ffvcks} \\
+ffvers & \pageref{ffvers} \\
+ffwldp & \pageref{ffwldp} \\
+ffxypx & \pageref{ffxypx} \\
+\end{tabular}
+
+
+
+*2 Parameter Definitions
+-
+anynul - set to TRUE (=1) if any returned values are undefined, else FALSE
+array - array of numerical data values to read or write
+ascii - encoded checksum string
+binspec - the input table binning specifier
+bitpix - bits per pixel. The following symbolic mnemonics are predefined:
+ BYTE_IMG = 8 (unsigned char)
+ SHORT_IMG = 16 (signed short integer)
+ LONG_IMG = 32 (signed long integer)
+ LONGLONG_IMG = 64 (signed long 64-bit integer)
+ FLOAT_IMG = -32 (float)
+ DOUBLE_IMG = -64 (double).
+ The LONGLONG_IMG type is experimental and is not officially
+ recognized in the FITS Standard document.
+ Two additional values, USHORT_IMG and ULONG_IMG are also available
+ for creating unsigned integer images. These are equivalent to
+ creating a signed integer image with BZERO offset keyword values
+ of 32768 or 2147483648, respectively, which is the convention that
+ FITS uses to store unsigned integers.
+card - header record to be read or written (80 char max, null-terminated)
+casesen - CASESEN (=1) for case-sensitive string matching, else CASEINSEN (=0)
+cmopt - grouping table "compact" option parameter. Allowed values are:
+ OPT_CMT_MBR and OPT_CMT_MBR_DEL.
+colname - name of the column (null-terminated)
+colnum - column number (first column = 1)
+colspec - the input file column specification; used to delete, create, or rename
+ table columns
+comment - the keyword comment field (72 char max, null-terminated)
+complm - should the checksum be complemented?
+comptype - compression algorithm to use: GZIP_1, RICE_1, or PLIO_1
+coordtype- type of coordinate projection (-SIN, -TAN, -ARC, -NCP,
+ -GLS, -MER, or -AIT)
+cpopt - grouping table copy option parameter. Allowed values are:
+ OPT_GCP_GPT, OPT_GCP_MBR, OPT_GCP_ALL, OPT_MCP_ADD, OPT_MCP_NADD,
+ OPT_MCP_REPL, amd OPT_MCP_MOV.
+create_col- If TRUE, then insert a new column in the table, otherwise
+ overwrite the existing column.
+current - if TRUE, then the current HDU will be copied
+dataok - was the data unit verification successful (=1) or
+ not (= -1). Equals zero if the DATASUM keyword is not present.
+datasum - 32-bit 1's complement checksum for the data unit
+dataend - address (in bytes) of the end of the HDU
+datastart- address (in bytes) of the start of the data unit
+datatype - specifies the data type of the value. Allowed value are: TSTRING,
+ TLOGICAL, TBYTE, TSBYTE, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG,
+ TFLOAT, TDOUBLE, TCOMPLEX, and TDBLCOMPLEX
+datestr - FITS date/time string: 'YYYY-MM-DDThh:mm:ss.ddd', 'YYYY-MM-dd',
+ or 'dd/mm/yy'
+day - calendar day (UTC) (1-31)
+decimals - number of decimal places to be displayed
+deltasize - increment for allocating more memory
+dim1 - declared size of the first dimension of the image or cube array
+dim2 - declared size of the second dimension of the data cube array
+dispwidth - display width of a column = length of string that will be read
+dtype - data type of the keyword ('C', 'L', 'I', 'F' or 'X')
+ C = character string
+ L = logical
+ I = integer
+ F = floating point number
+ X = complex, e.g., "(1.23, -4.56)"
+err_msg - error message on the internal stack (80 chars max)
+err_text - error message string corresponding to error number (30 chars max)
+exact - TRUE (=1) if the strings match exactly;
+ FALSE (=0) if wildcards are used
+exclist - array of pointers to keyword names to be excluded from search
+exists - flag indicating whether the file or compressed file exists on disk
+expr - boolean or arithmetic expression
+extend - TRUE (=1) if FITS file may have extensions, else FALSE (=0)
+extname - value of the EXTNAME keyword (null-terminated)
+extspec - the extension or HDU specifier; a number or name, version, and type
+extver - value of the EXTVER keyword = integer version number
+filename - full name of the FITS file, including optional HDU and filtering specs
+filetype - type of file (file://, ftp://, http://, etc.)
+filter - the input file filtering specifier
+firstchar- starting byte in the row (first byte of row = 1)
+firstfailed - member HDU ID (if positive) or grouping table GRPIDn index
+ value (if negative) that failed grouping table verification.
+firstelem- first element in a vector (ignored for ASCII tables)
+firstrow - starting row number (first row of table = 1)
+following- if TRUE, any HDUs following the current HDU will be copied
+fpixel - coordinate of the first pixel to be read or written in the
+ FITS array. The array must be of length NAXIS and have values such
+ that fpixel[0] is in the range 1 to NAXIS1, fpixel[1] is in the
+ range 1 to NAXIS2, etc.
+fptr - pointer to a 'fitsfile' structure describing the FITS file.
+frac - factional part of the keyword value
+gcount - number of groups in the primary array (usually = 1)
+gfptr - fitsfile* pointer to a grouping table HDU.
+group - GRPIDn/GRPLCn index value identifying a grouping table HDU, or
+ data group number (=0 for non-grouped data)
+grouptype - Grouping table parameter that specifies the columns to be
+ created in a grouping table HDU. Allowed values are: GT_ID_ALL_URI,
+ GT_ID_REF, GT_ID_POS, GT_ID_ALL, GT_ID_REF_URI, and GT_ID_POS_URI.
+grpname - value to use for the GRPNAME keyword value.
+hdunum - sequence number of the HDU (Primary array = 1)
+hduok - was the HDU verification successful (=1) or
+ not (= -1). Equals zero if the CHECKSUM keyword is not present.
+hdusum - 32 bit 1's complement checksum for the entire CHDU
+hdutype - type of HDU: IMAGE_HDU (=0), ASCII_TBL (=1), or BINARY_TBL (=2)
+header - returned character string containing all the keyword records
+headstart- starting address (in bytes) of the CHDU
+heapsize - size of the binary table heap, in bytes
+history - the HISTORY keyword comment string (70 char max, null-terminated)
+hour - hour within day (UTC) (0 - 23)
+inc - sampling interval for pixels in each FITS dimension
+inclist - array of pointers to matching keyword names
+incolnum - input column number; range = 1 to TFIELDS
+infile - the input filename, including path if specified
+infptr - pointer to a 'fitsfile' structure describing the input FITS file.
+intval - integer part of the keyword value
+iomode - file access mode: either READONLY (=0) or READWRITE (=1)
+keyname - name of a keyword (8 char max, null-terminated)
+keynum - position of keyword in header (1st keyword = 1)
+keyroot - root string for the keyword name (5 char max, null-terminated)
+keysexist- number of existing keyword records in the CHU
+keytype - header record type: -1=delete; 0=append or replace;
+ 1=append; 2=this is the END keyword
+longstr - arbitrarily long string keyword value (null-terminated)
+lpixel - coordinate of the last pixel to be read or written in the
+ FITS array. The array must be of length NAXIS and have values such
+ that lpixel[0] is in the range 1 to NAXIS1, lpixel[1] is in the
+ range 1 to NAXIS2, etc.
+match - TRUE (=1) if the 2 strings match, else FALSE (=0)
+maxdim - maximum number of values to return
+member - row number of a grouping table member HDU.
+memptr - pointer to the a FITS file in memory
+mem_realloc - pointer to a function for reallocating more memory
+memsize - size of the memory block allocated for the FITS file
+mfptr - fitsfile* pointer to a grouping table member HDU.
+mgopt - grouping table merge option parameter. Allowed values are:
+ OPT_MRG_COPY, and OPT_MRG_MOV.
+minute - minute within hour (UTC) (0 - 59)
+month - calendar month (UTC) (1 - 12)
+morekeys - space in the header for this many more keywords
+n_good_rows - number of rows evaluating to TRUE
+namelist - string containing a comma or space delimited list of names
+naxes - size of each dimension in the FITS array
+naxis - number of dimensions in the FITS array
+naxis1 - length of the X/first axis of the FITS array
+naxis2 - length of the Y/second axis of the FITS array
+naxis3 - length of the Z/third axis of the FITS array
+nchars - number of characters to read or write
+nelements- number of data elements to read or write
+newfptr - returned pointer to the reopened file
+newveclen- new value for the column vector repeat parameter
+nexc - number of names in the exclusion list (may = 0)
+nfound - number of keywords found (highest keyword number)
+nkeys - number of keywords in the sequence
+ninc - number of names in the inclusion list
+nmembers - Number of grouping table members (NAXIS2 value).
+nmove - number of HDUs to move (+ or -), relative to current position
+nocomments - if equal to TRUE, then no commentary keywords will be copied
+noisebits- number of bits to ignore when compressing floating point images
+nrows - number of rows in the table
+nstart - first integer value
+nullarray- set to TRUE (=1) if corresponding data element is undefined
+nulval - numerical value to represent undefined pixels
+nulstr - character string used to represent undefined values in ASCII table
+numval - numerical data value, of the appropriate data type
+offset - byte offset in the heap to the first element of the vector
+openfptr - pointer to a currently open FITS file
+overlap - number of bytes in the binary table heap pointed to by more than 1
+ descriptor
+outcolnum- output column number; range = 1 to TFIELDS + 1
+outfile - and optional output filename; the input file will be copied to this prior
+ to opening the file
+outfptr - pointer to a 'fitsfile' structure describing the output FITS file.
+pcount - value of the PCOUNT keyword = size of binary table heap
+previous - if TRUE, any previous HDUs in the input file will be copied.
+repeat - length of column vector (e.g. 12J); == 1 for ASCII table
+rmopt - grouping table remove option parameter. Allowed values are:
+ OPT_RM_GPT, OPT_RM_ENTRY, OPT_RM_MBR, and OPT_RM_ALL.
+rootname - root filename, minus any extension or filtering specifications
+rot - celestial coordinate rotation angle (degrees)
+rowlen - length of a table row, in characters or bytes
+rowlist - sorted list of row numbers to be deleted from the table
+rownum - number of the row (first row = 1)
+rowrange - list of rows or row ranges: '3,6-8,12,56-80' or '500-'
+row_status - array of True/False results for each row that was evaluated
+scale - linear scaling factor; true value = (FITS value) * scale + zero
+second - second within minute (0 - 60.9999999999) (leap second!)
+simple - TRUE (=1) if FITS file conforms to the Standard, else FALSE (=0)
+space - number of blank spaces to leave between ASCII table columns
+status - returned error status code (0 = OK)
+sum - 32 bit unsigned checksum value
+tbcol - byte position in row to start of column (1st col has tbcol = 1)
+tdisp - Fortran style display format for the table column
+tdimstr - the value of the TDIMn keyword
+templt - template string used in comparison (null-terminated)
+tfields - number of fields (columns) in the table
+tfopt - grouping table member transfer option parameter. Allowed values are:
+ OPT_MCP_ADD, and OPT_MCP_MOV.
+tform - format of the column (null-terminated); allowed values are:
+ ASCII tables: Iw, Aw, Fww.dd, Eww.dd, or Dww.dd
+ Binary tables: rL, rX, rB, rI, rJ, rA, rAw, rE, rD, rC, rM
+ where 'w'=width of the field, 'd'=no. of decimals, 'r'=repeat count.
+ Variable length array columns are denoted by a '1P' before the data type
+ character (e.g., '1PJ'). When creating a binary table, 2 addition tform
+ data type codes are recognized by CFITSIO: 'rU' and 'rV' for unsigned
+ 16-bit and unsigned 32-bit integer, respectively.
+
+theap - zero indexed byte offset of starting address of the heap
+ relative to the beginning of the binary table data
+tilesize - array of length NAXIS that specifies the dimensions of
+ the image compression tiles
+ttype - label or name for table column (null-terminated)
+tunit - physical unit for table column (null-terminated)
+typechar - symbolic code of the table column data type
+typecode - data type code of the table column. The negative of
+ the value indicates a variable length array column.
+ Datatype typecode Mnemonic
+ bit, X 1 TBIT
+ byte, B 11 TBYTE
+ logical, L 14 TLOGICAL
+ ASCII character, A 16 TSTRING
+ short integer, I 21 TSHORT
+ integer, J 41 TINT32BIT
+ long long integer, K 81 TLONGLONG
+ real, E 42 TFLOAT
+ double precision, D 82 TDOUBLE
+ complex, C 83 TCOMPLEX
+ double complex, M 163 TDBLCOMPLEX
+ The TLONGLONG column type is experimental and is not
+ recognized in the official FITS Standard document
+unit - the physical unit string (e.g., 'km/s') for a keyword
+unused - number of unused bytes in the binary table heap
+urltype - the file type of the FITS file (file://, ftp://, mem://, etc.)
+validheap- returned value = FALSE if any of the variable length array
+ address are outside the valid range of addresses in the heap
+value - the keyword value string (70 char max, null-terminated)
+version - current version number of the CFITSIO library
+width - width of the character string field
+xcol - number of the column containing the X coordinate values
+xinc - X axis coordinate increment at reference pixel (deg)
+xpix - X axis pixel location
+xpos - X axis celestial coordinate (usually RA) (deg)
+xrefpix - X axis reference pixel array location
+xrefval - X axis coordinate value at the reference pixel (deg)
+ycol - number of the column containing the X coordinate values
+year - calendar year (e.g. 1999, 2000, etc)
+yinc - Y axis coordinate increment at reference pixel (deg)
+ypix - y axis pixel location
+ypos - y axis celestial coordinate (usually DEC) (deg)
+yrefpix - Y axis reference pixel array location
+yrefval - Y axis coordinate value at the reference pixel (deg)
+zero - scaling offset; true value = (FITS value) * scale + zero
+-
+
+*3 CFITSIO Error Status Codes
+
+The following table lists all the error status codes used by CFITSIO.
+Programmers are encouraged to use the symbolic mnemonics (defined in
+the file fitsio.h) rather than the actual integer status values to
+improve the readability of their code.
+-
+ Symbolic Const Value Meaning
+ -------------- ----- -----------------------------------------
+ 0 OK, no error
+ SAME_FILE 101 input and output files are the same
+ TOO_MANY_FILES 103 tried to open too many FITS files at once
+ FILE_NOT_OPENED 104 could not open the named file
+ FILE_NOT_CREATED 105 could not create the named file
+ WRITE_ERROR 106 error writing to FITS file
+ END_OF_FILE 107 tried to move past end of file
+ READ_ERROR 108 error reading from FITS file
+ FILE_NOT_CLOSED 110 could not close the file
+ ARRAY_TOO_BIG 111 array dimensions exceed internal limit
+ READONLY_FILE 112 Cannot write to readonly file
+ MEMORY_ALLOCATION 113 Could not allocate memory
+ BAD_FILEPTR 114 invalid fitsfile pointer
+ NULL_INPUT_PTR 115 NULL input pointer to routine
+ SEEK_ERROR 116 error seeking position in file
+
+ BAD_URL_PREFIX 121 invalid URL prefix on file name
+ TOO_MANY_DRIVERS 122 tried to register too many IO drivers
+ DRIVER_INIT_FAILED 123 driver initialization failed
+ NO_MATCHING_DRIVER 124 matching driver is not registered
+ URL_PARSE_ERROR 125 failed to parse input file URL
+ RANGE_PARSE_ERROR 126 parse error in range list
+
+ SHARED_BADARG 151 bad argument in shared memory driver
+ SHARED_NULPTR 152 null pointer passed as an argument
+ SHARED_TABFULL 153 no more free shared memory handles
+ SHARED_NOTINIT 154 shared memory driver is not initialized
+ SHARED_IPCERR 155 IPC error returned by a system call
+ SHARED_NOMEM 156 no memory in shared memory driver
+ SHARED_AGAIN 157 resource deadlock would occur
+ SHARED_NOFILE 158 attempt to open/create lock file failed
+ SHARED_NORESIZE 159 shared memory block cannot be resized at the moment
+
+ HEADER_NOT_EMPTY 201 header already contains keywords
+ KEY_NO_EXIST 202 keyword not found in header
+ KEY_OUT_BOUNDS 203 keyword record number is out of bounds
+ VALUE_UNDEFINED 204 keyword value field is blank
+ NO_QUOTE 205 string is missing the closing quote
+ BAD_KEYCHAR 207 illegal character in keyword name or card
+ BAD_ORDER 208 required keywords out of order
+ NOT_POS_INT 209 keyword value is not a positive integer
+ NO_END 210 couldn't find END keyword
+ BAD_BITPIX 211 illegal BITPIX keyword value
+ BAD_NAXIS 212 illegal NAXIS keyword value
+ BAD_NAXES 213 illegal NAXISn keyword value
+ BAD_PCOUNT 214 illegal PCOUNT keyword value
+ BAD_GCOUNT 215 illegal GCOUNT keyword value
+ BAD_TFIELDS 216 illegal TFIELDS keyword value
+ NEG_WIDTH 217 negative table row size
+ NEG_ROWS 218 negative number of rows in table
+ COL_NOT_FOUND 219 column with this name not found in table
+ BAD_SIMPLE 220 illegal value of SIMPLE keyword
+ NO_SIMPLE 221 Primary array doesn't start with SIMPLE
+ NO_BITPIX 222 Second keyword not BITPIX
+ NO_NAXIS 223 Third keyword not NAXIS
+ NO_NAXES 224 Couldn't find all the NAXISn keywords
+ NO_XTENSION 225 HDU doesn't start with XTENSION keyword
+ NOT_ATABLE 226 the CHDU is not an ASCII table extension
+ NOT_BTABLE 227 the CHDU is not a binary table extension
+ NO_PCOUNT 228 couldn't find PCOUNT keyword
+ NO_GCOUNT 229 couldn't find GCOUNT keyword
+ NO_TFIELDS 230 couldn't find TFIELDS keyword
+ NO_TBCOL 231 couldn't find TBCOLn keyword
+ NO_TFORM 232 couldn't find TFORMn keyword
+ NOT_IMAGE 233 the CHDU is not an IMAGE extension
+ BAD_TBCOL 234 TBCOLn keyword value < 0 or > rowlength
+ NOT_TABLE 235 the CHDU is not a table
+ COL_TOO_WIDE 236 column is too wide to fit in table
+ COL_NOT_UNIQUE 237 more than 1 column name matches template
+ BAD_ROW_WIDTH 241 sum of column widths not = NAXIS1
+ UNKNOWN_EXT 251 unrecognizable FITS extension type
+ UNKNOWN_REC 252 unknown record; 1st keyword not SIMPLE or XTENSION
+ END_JUNK 253 END keyword is not blank
+ BAD_HEADER_FILL 254 Header fill area contains non-blank chars
+ BAD_DATA_FILL 255 Illegal data fill bytes (not zero or blank)
+ BAD_TFORM 261 illegal TFORM format code
+ BAD_TFORM_DTYPE 262 unrecognizable TFORM data type code
+ BAD_TDIM 263 illegal TDIMn keyword value
+ BAD_HEAP_PTR 264 invalid BINTABLE heap pointer is out of range
+
+ BAD_HDU_NUM 301 HDU number < 1
+ BAD_COL_NUM 302 column number < 1 or > tfields
+ NEG_FILE_POS 304 tried to move to negative byte location in file
+ NEG_BYTES 306 tried to read or write negative number of bytes
+ BAD_ROW_NUM 307 illegal starting row number in table
+ BAD_ELEM_NUM 308 illegal starting element number in vector
+ NOT_ASCII_COL 309 this is not an ASCII string column
+ NOT_LOGICAL_COL 310 this is not a logical data type column
+ BAD_ATABLE_FORMAT 311 ASCII table column has wrong format
+ BAD_BTABLE_FORMAT 312 Binary table column has wrong format
+ NO_NULL 314 null value has not been defined
+ NOT_VARI_LEN 317 this is not a variable length column
+ BAD_DIMEN 320 illegal number of dimensions in array
+ BAD_PIX_NUM 321 first pixel number greater than last pixel
+ ZERO_SCALE 322 illegal BSCALE or TSCALn keyword = 0
+ NEG_AXIS 323 illegal axis length < 1
+
+ NOT_GROUP_TABLE 340 Grouping function error
+ HDU_ALREADY_MEMBER 341
+ MEMBER_NOT_FOUND 342
+ GROUP_NOT_FOUND 343
+ BAD_GROUP_ID 344
+ TOO_MANY_HDUS_TRACKED 345
+ HDU_ALREADY_TRACKED 346
+ BAD_OPTION 347
+ IDENTICAL_POINTERS 348
+ BAD_GROUP_ATTACH 349
+ BAD_GROUP_DETACH 350
+
+ NGP_NO_MEMORY 360 malloc failed
+ NGP_READ_ERR 361 read error from file
+ NGP_NUL_PTR 362 null pointer passed as an argument.
+ Passing null pointer as a name of
+ template file raises this error
+ NGP_EMPTY_CURLINE 363 line read seems to be empty (used
+ internally)
+ NGP_UNREAD_QUEUE_FULL 364 cannot unread more then 1 line (or single
+ line twice)
+ NGP_INC_NESTING 365 too deep include file nesting (infinite
+ loop, template includes itself ?)
+ NGP_ERR_FOPEN 366 fopen() failed, cannot open template file
+ NGP_EOF 367 end of file encountered and not expected
+ NGP_BAD_ARG 368 bad arguments passed. Usually means
+ internal parser error. Should not happen
+ NGP_TOKEN_NOT_EXPECT 369 token not expected here
+
+ BAD_I2C 401 bad int to formatted string conversion
+ BAD_F2C 402 bad float to formatted string conversion
+ BAD_INTKEY 403 can't interpret keyword value as integer
+ BAD_LOGICALKEY 404 can't interpret keyword value as logical
+ BAD_FLOATKEY 405 can't interpret keyword value as float
+ BAD_DOUBLEKEY 406 can't interpret keyword value as double
+ BAD_C2I 407 bad formatted string to int conversion
+ BAD_C2F 408 bad formatted string to float conversion
+ BAD_C2D 409 bad formatted string to double conversion
+ BAD_DATATYPE 410 illegal datatype code value
+ BAD_DECIM 411 bad number of decimal places specified
+ NUM_OVERFLOW 412 overflow during data type conversion
+ DATA_COMPRESSION_ERR 413 error compressing image
+ DATA_DECOMPRESSION_ERR 414 error uncompressing image
+
+ BAD_DATE 420 error in date or time conversion
+
+ PARSE_SYNTAX_ERR 431 syntax error in parser expression
+ PARSE_BAD_TYPE 432 expression did not evaluate to desired type
+ PARSE_LRG_VECTOR 433 vector result too large to return in array
+ PARSE_NO_OUTPUT 434 data parser failed not sent an out column
+ PARSE_BAD_COL 435 bad data encounter while parsing column
+ PARSE_BAD_OUTPUT 436 Output file not of proper type
+
+ ANGLE_TOO_BIG 501 celestial angle too large for projection
+ BAD_WCS_VAL 502 bad celestial coordinate or pixel value
+ WCS_ERROR 503 error in celestial coordinate calculation
+ BAD_WCS_PROJ 504 unsupported type of celestial projection
+ NO_WCS_KEY 505 celestial coordinate keywords not found
+ APPROX_WCS_KEY 506 approximate wcs keyword values were returned
+-
+\end{document}
+
diff --git a/pkg/tbtables/cfitsio/cfitsio.ps b/pkg/tbtables/cfitsio/cfitsio.ps
new file mode 100644
index 00000000..53d0810c
--- /dev/null
+++ b/pkg/tbtables/cfitsio/cfitsio.ps
@@ -0,0 +1,12896 @@
+%!PS-Adobe-2.0
+%%Creator: dvips(k) 5.86 Copyright 1999 Radical Eye Software
+%%Title: cfitsio.dvi
+%%Pages: 168
+%%PageOrder: Ascend
+%%BoundingBox: 0 0 612 792
+%%EndComments
+%DVIPSWebPage: (www.radicaleye.com)
+%DVIPSCommandLine: dvips -N0 cfitsio
+%DVIPSParameters: dpi=600, compressed
+%DVIPSSource: TeX output 2004.12.02:1427
+%%BeginProcSet: texc.pro
+%!
+/TeXDict 300 dict def TeXDict begin/N{def}def/B{bind def}N/S{exch}N/X{S
+N}B/A{dup}B/TR{translate}N/isls false N/vsize 11 72 mul N/hsize 8.5 72
+mul N/landplus90{false}def/@rigin{isls{[0 landplus90{1 -1}{-1 1}ifelse 0
+0 0]concat}if 72 Resolution div 72 VResolution div neg scale isls{
+landplus90{VResolution 72 div vsize mul 0 exch}{Resolution -72 div hsize
+mul 0}ifelse TR}if Resolution VResolution vsize -72 div 1 add mul TR[
+matrix currentmatrix{A A round sub abs 0.00001 lt{round}if}forall round
+exch round exch]setmatrix}N/@landscape{/isls true N}B/@manualfeed{
+statusdict/manualfeed true put}B/@copies{/#copies X}B/FMat[1 0 0 -1 0 0]
+N/FBB[0 0 0 0]N/nn 0 N/IEn 0 N/ctr 0 N/df-tail{/nn 8 dict N nn begin
+/FontType 3 N/FontMatrix fntrx N/FontBBox FBB N string/base X array
+/BitMaps X/BuildChar{CharBuilder}N/Encoding IEn N end A{/foo setfont}2
+array copy cvx N load 0 nn put/ctr 0 N[}B/sf 0 N/df{/sf 1 N/fntrx FMat N
+df-tail}B/dfs{div/sf X/fntrx[sf 0 0 sf neg 0 0]N df-tail}B/E{pop nn A
+definefont setfont}B/Cw{Cd A length 5 sub get}B/Ch{Cd A length 4 sub get
+}B/Cx{128 Cd A length 3 sub get sub}B/Cy{Cd A length 2 sub get 127 sub}
+B/Cdx{Cd A length 1 sub get}B/Ci{Cd A type/stringtype ne{ctr get/ctr ctr
+1 add N}if}B/id 0 N/rw 0 N/rc 0 N/gp 0 N/cp 0 N/G 0 N/CharBuilder{save 3
+1 roll S A/base get 2 index get S/BitMaps get S get/Cd X pop/ctr 0 N Cdx
+0 Cx Cy Ch sub Cx Cw add Cy setcachedevice Cw Ch true[1 0 0 -1 -.1 Cx
+sub Cy .1 sub]/id Ci N/rw Cw 7 add 8 idiv string N/rc 0 N/gp 0 N/cp 0 N{
+rc 0 ne{rc 1 sub/rc X rw}{G}ifelse}imagemask restore}B/G{{id gp get/gp
+gp 1 add N A 18 mod S 18 idiv pl S get exec}loop}B/adv{cp add/cp X}B
+/chg{rw cp id gp 4 index getinterval putinterval A gp add/gp X adv}B/nd{
+/cp 0 N rw exit}B/lsh{rw cp 2 copy get A 0 eq{pop 1}{A 255 eq{pop 254}{
+A A add 255 and S 1 and or}ifelse}ifelse put 1 adv}B/rsh{rw cp 2 copy
+get A 0 eq{pop 128}{A 255 eq{pop 127}{A 2 idiv S 128 and or}ifelse}
+ifelse put 1 adv}B/clr{rw cp 2 index string putinterval adv}B/set{rw cp
+fillstr 0 4 index getinterval putinterval adv}B/fillstr 18 string 0 1 17
+{2 copy 255 put pop}for N/pl[{adv 1 chg}{adv 1 chg nd}{1 add chg}{1 add
+chg nd}{adv lsh}{adv lsh nd}{adv rsh}{adv rsh nd}{1 add adv}{/rc X nd}{
+1 add set}{1 add clr}{adv 2 chg}{adv 2 chg nd}{pop nd}]A{bind pop}
+forall N/D{/cc X A type/stringtype ne{]}if nn/base get cc ctr put nn
+/BitMaps get S ctr S sf 1 ne{A A length 1 sub A 2 index S get sf div put
+}if put/ctr ctr 1 add N}B/I{cc 1 add D}B/bop{userdict/bop-hook known{
+bop-hook}if/SI save N @rigin 0 0 moveto/V matrix currentmatrix A 1 get A
+mul exch 0 get A mul add .99 lt{/QV}{/RV}ifelse load def pop pop}N/eop{
+SI restore userdict/eop-hook known{eop-hook}if showpage}N/@start{
+userdict/start-hook known{start-hook}if pop/VResolution X/Resolution X
+1000 div/DVImag X/IEn 256 array N 2 string 0 1 255{IEn S A 360 add 36 4
+index cvrs cvn put}for pop 65781.76 div/vsize X 65781.76 div/hsize X}N
+/p{show}N/RMat[1 0 0 -1 0 0]N/BDot 260 string N/Rx 0 N/Ry 0 N/V{}B/RV/v{
+/Ry X/Rx X V}B statusdict begin/product where{pop false[(Display)(NeXT)
+(LaserWriter 16/600)]{A length product length le{A length product exch 0
+exch getinterval eq{pop true exit}if}{pop}ifelse}forall}{false}ifelse
+end{{gsave TR -.1 .1 TR 1 1 scale Rx Ry false RMat{BDot}imagemask
+grestore}}{{gsave TR -.1 .1 TR Rx Ry scale 1 1 false RMat{BDot}
+imagemask grestore}}ifelse B/QV{gsave newpath transform round exch round
+exch itransform moveto Rx 0 rlineto 0 Ry neg rlineto Rx neg 0 rlineto
+fill grestore}B/a{moveto}B/delta 0 N/tail{A/delta X 0 rmoveto}B/M{S p
+delta add tail}B/b{S p tail}B/c{-4 M}B/d{-3 M}B/e{-2 M}B/f{-1 M}B/g{0 M}
+B/h{1 M}B/i{2 M}B/j{3 M}B/k{4 M}B/w{0 rmoveto}B/l{p -4 w}B/m{p -3 w}B/n{
+p -2 w}B/o{p -1 w}B/q{p 1 w}B/r{p 2 w}B/s{p 3 w}B/t{p 4 w}B/x{0 S
+rmoveto}B/y{3 2 roll p a}B/bos{/SS save N}B/eos{SS restore}B end
+
+%%EndProcSet
+TeXDict begin 40258431 52099146 1000 600 600 (cfitsio.dvi)
+@start
+%DVIPSBitmapFont: Fa cmti10 10.95 17
+/Fa 17 118 df<49B712C018F818FE903B0003FE0003FF9438007F804BEC1FC0F00FE0F0
+07F014074BEC03F8F001FCA2140F4BEC00FEA3141F4B15FFA3143F5DA3027F5D5DA219FE
+14FF92C81203A34917FC4A1507A219F813034A150F19F0A20107EE1FE05CF03FC0A2010F
+EE7F804A16006060011F4B5A4A4A5A4D5AA2013F4B5A4AEC3FC04DC7FC017F15FEEE03FC
+4AEB0FF001FFEC7FE0B8128004FCC8FC16E0403E7BBD45>68 D<49B648B6FC495DA2D900
+0390C7000313004B5D4B5DA2180714074B5DA2180F140F4B5DA2181F141F4B5DA2183F14
+3F4B5DA2187F147F4B5DA218FF91B8FC96C7FCA292C712015B4A5DA2170313034A5DA217
+0713074A5DA2170F130F4A5DA2171F131F4A5DA2173F133F4A5DA2017F157FA24A5D496C
+4A7EB66CB67EA3483E7BBD44>72 D<001FB500F090B512F0485DA226003FF0C7380FFC00
+4AEC03F04A5D715A017F1503A24A5DA201FF150795C7FC91C8FCA2485E170E5BA2000316
+1E171C5BA20007163C17385BA2000F167817705BA2001F16F05F5BA2003F1501A2495DA2
+007F1503A2495DA2160794C8FC48C8FC5E160E161E6C151C163C5E5E5E6C6C13014B5A00
+1F4A5A6C6C011FC9FC6D133E6C6C13F83903FC07F0C6B512C0013F90CAFCEB07F83C406F
+BD44>85 D<147E49B47E903907C1C38090391F80EFC090383F00FF017E137F4914804848
+133F485AA248481400120F5B001F5C157E485AA215FE007F5C90C7FCA21401485C5AA214
+03EDF0385AA21407EDE078020F1370127C021F13F0007E013F13E0003E137FECF3E1261F
+01E313C03A0F8781E3803A03FF00FF00D800FC133E252977A72E>97
+D<EB1FC0EA0FFF5CA2EA003FA291C7FCA25BA2137EA213FEA25BA21201A25BA21203A25B
+147E3907F1FF809038F783E09038EF01F013FE390FF800F8A24913FC49137C485A157E5B
+15FE123FA290C7FCA248130115FC127EA2140300FE14F85AA2EC07F0A215E048130F15C0
+141F15800078EB3F00127C147E003C5B383E01F8381E03E06C485A6CB4C7FCEA01F81F40
+76BE2A>I<EC3F80903801FFE0903807E0F890381F803CEB3E0001FC131E485A485A1207
+4848133E49133C121F4848137C15F8EC03F0397F000FE0ECFF809038FFFC00B512C048C8
+FCA45AA61506150E151E007C143C15786C14F0EC01E06CEB07C0390F801F003807C0FC38
+01FFF038007F801F2976A72A>101 D<EC03F0EC0FFC91383E0E1C9138FC077E903901F0
+03FE1303903807E001D90FC013FCEB1F80A2EB3F004914F8137E01FE1303A2484814F0A2
+150712034914E0A2150F12074914C0A2151FA216805B153F1203ED7F006D5BA200015B00
+00495A9038F80F7E90387C1EFEEB1FF8903807E0FC90C7FC1401A25DA21403A25D001C13
+07007F5C48130F5D4A5A4AC7FC48137E00F85B387C03F0381FFFC0D803FEC8FC273B7CA7
+2A>103 D<1478EB01FCA21303A314F8EB00E01400AD137C48B4FC38038F80EA0707000E
+13C0121E121CEA3C0F1238A2EA781F00701380A2EAF03F140012005B137E13FE5BA21201
+5BA212035B1438120713E0000F1378EBC070A214F0EB80E0A2EB81C01383148038078700
+EA03FEEA00F8163E79BC1C>105 D<EB07F0EA03FF14E0A2EA000FA214C0A2131FA21480
+A2133FA21400A25BA2137EA213FEA25BA21201A25BA21203A25BA21207A25BA2120FA25B
+A2121FA25BA2123FA290C7FCA25A1307127EA2EAFE0F130E12FCA2131E131CA2EA7C3813
+78EA3C70EA1FE0EA0780144079BE17>108 D<D801F0D93F80137F3D07FC01FFE003FFC0
+3D0F3E07C1F80F83F03D0E1F0F00FC1E01F8001E011C90387C3800001C49D97E707F003C
+01F05C0038157F4A5C26783FC05C12704A91C7FC91C7127E00F003FE1301494A5CEA007E
+A20301140301FE5F495CA203031407000160495C180F03075D0003051F13E0494A1480A2
+030FEC3F810007F001C0495CA2031F91383E0380120F494AEC0700A2033F150E001FEF1E
+1C4991C7EA0FF80007C7000EEC03E0432979A74A>I<D801F0EB3F803A07FC01FFE03A0F
+3E07C1F83A0E1F0F00FC001E011C137C001C49137E003C13F012385C38783FC012705C91
+C7FC00F015FE495CEA007EA2150101FE5C5BA2150300015D5B15075E0003020F13704914
+C0A2031F13F00007ED80E05B1681EE01C0120F49EC0380A2EE0700001FEC0F0E49EB07FC
+0007C7EA01F02C2979A733>I<EC1FC0ECFFF8903803F07C90380FC01FEB1F8090393F00
+0F80017E14C0491307484814E0485A12075B000F15F0485AA2485AA2ED0FE0127F90C7FC
+A2151F4815C05AA2ED3F80A2ED7F00A248147E007C5C007E13015D4A5A003E495A6C495A
+4A5A260F803EC7FC3807C0FC3801FFF038003F80242977A72E>I<903903E001F890390F
+F807FE903A1E7C1E0F80903A1C3E3C07C0013C137801389038E003E0EB783F017001C013
+F0ED80019038F07F0001E015F8147E1603000113FEA2C75AA20101140717F05CA2010314
+0F17E05CA20107EC1FC0A24A1480163F010F15005E167E5E131F4B5A6E485A4B5A90393F
+B80F80DA9C1FC7FCEC0FFCEC03E049C9FCA2137EA213FEA25BA21201A25BA21203A2387F
+FFE0B5FCA22D3A80A72E>I<D801F013FC3A07FC07FF803A0F3E0F03C0260E1F1C13E000
+1EEB380F001C1370003CEBE01F123814C0D8783F14C00070903880070092C7FC91C8FC12
+F05BEA007EA313FE5BA312015BA312035BA312075BA3120F5BA3121F5B0007C9FC232979
+A726>114 D<EC7F80903801FFE0903807C0F890381F003C013E131C013C131E017C133E
+49137E15FEA2000114FCA215706D13007FEBFFC014FC6C13FF15806D13C06D13E0010F13
+F01300140F14071403120C123F387F80011403D8FF0013E0A300FCEB07C000F0EB0F8012
+700078EB1F006C133C381F01F83807FFE0C690C7FC1F297AA725>I<EB01C0EB03F01307
+A25CA2130FA25CA2131FA25CA2133FA291C7FCA2007FB51280B6FC1500D8007EC7FC13FE
+A25BA21201A25BA21203A25BA21207A25BA2120FA25BA2121F141C1380A2003F133C1438
+EB0078147014F05C495AEA1F03495A6C48C7FCEA07FCEA01F0193A78B81E>I<137C48B4
+141C26038F80137EEA0707000E7F001E15FE121CD83C0F5C12381501EA781F007001805B
+A2D8F03F1303140000005D5B017E1307A201FE5C5B150F1201495CA2151F0003EDC1C049
+1481A2153F1683EE0380A2ED7F07000102FF13005C01F8EBDF0F00009038079F0E90397C
+0F0F1C90391FFC07F8903907F001F02A2979A731>I E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fb cmmi10 10.95 1
+/Fb 1 63 df<126012F8B4FCEA7FC0EA1FF0EA07FCEA01FF38007FC0EB1FF0EB07FCEB01
+FF9038007FC0EC1FF0EC07FCEC01FF9138007FC0ED1FF0ED07FCED01FF9238007FC0EE1F
+F0EE07FCEE01FF9338007FC0EF1FF0EF07F8EF01FCA2EF07F8EF1FF0EF7FC0933801FF00
+EE07FCEE1FF0EE7FC04B48C7FCED07FCED1FF0ED7FC04A48C8FCEC07FCEC1FF0EC7FC049
+48C9FCEB07FCEB1FF0EB7FC04848CAFCEA07FCEA1FF0EA7FC048CBFC12FC1270363678B1
+47>62 D E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fc cmsy10 10.95 4
+/Fc 4 107 df<EB0FFCEB3FFF90B512C0000314F04880488048804880A2481580A3B712
+C0AA6C1580A36C1500A26C5C6C5C6C5C6C5CC614C0013F90C7FCEB0FFC22227BA72D>15
+D<153FEC03FFEC0FE0EC3F80EC7E00495A5C495AA2495AB3AA130F5C131F495A91C7FC13
+FEEA03F8EA7FE048C8FCEA7FE0EA03F8EA00FE133F806D7E130F801307B3AA6D7EA26D7E
+80EB007EEC3F80EC0FE0EC03FFEC003F205B7AC32D>102 D<12FCEAFFC0EA07F0EA01FC
+EA007E6D7E131F6D7EA26D7EB3AA801303806D7E1300147FEC1FC0EC07FEEC00FFEC07FE
+EC1FC0EC7F0014FC1301495A5C13075CB3AA495AA2495A133F017EC7FC485AEA07F0EAFF
+C000FCC8FC205B7AC32D>I<126012F0B3B3B3B3B11260045B76C319>106
+D E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fd cmbx12 12 58
+/Fd 58 122 df<ED0FFF4AB512C0020F14F0027F80903A01FFF803FC499038C000FE010F
+EB00034948497E49485B5C495A4C138001FF6E13005CA3705AEE01F893C8FCA74BB51280
+B9FCA5C69038E00003B3B0007FD9FFC1B6FCA538467EC53E>12 D<B612F8A91D097F9A25
+>45 D<EA07C0EA1FF0EA3FF8EA7FFCEAFFFEA7EA7FFCEA3FF8EA1FF0EA07C00F0F788E1F
+>I<EC3FF849B5FC010F14E0013F14F890397FF01FFC9039FFC007FE4890380001FF4848
+6D1380000716C049147F000F16E049143F001F16F0A2003F16F8A249141F007F16FCA600
+FF16FEB3A3007F16FCA56C6CEC3FF8A3001F16F0A2000F16E06D147F000716C06D14FF6C
+6C4913806C6D4813006C6D485A90397FF01FFC6DB55A010F14E0010314809026003FF8C7
+FC2F427CC038>48 D<EC03C01407141F147FEB03FF133FB6FCA413C3EA0003B3B3ADB712
+FCA5264177C038>I<ECFFE0010F13FE013F6D7E90B612E0000315F82607FC0313FE3A0F
+E0007FFFD81F806D138048C7000F13C0488001C015E001F07F00FF6E13F07F17F881A46C
+5A6C5A6C5AC9FC17F05DA217E05D17C04B13804B1300A2ED1FFC4B5A5E4B5A4B5A4A90C7
+FC4A5A4A5AEC0FF04A5AEC3F804AC7127814FE495A494814F8D907E014F0495A495A49C8
+FC017C140149140348B7FC4816E05A5A5A5A5AB8FC17C0A42D417BC038>I<ECFFF00107
+13FF011F14C0017F14F049C66C7ED803F8EB3FFED807E06D7E81D80FF86D138013FE001F
+16C07FA66C5A6C4815806C485BC814005D5E4B5A4B5A4B5A4A5B020F1380902607FFFEC7
+FC15F815FF16C090C713F0ED3FFCED0FFEEEFF80816F13C017E0A26F13F0A217F8A3EA0F
+C0EA3FF0487EA2487EA217F0A25D17E06C5A494913C05BD83F80491380D81FF0491300D8
+0FFEEBFFFE6CB612F800015D6C6C14C0011F49C7FC010113E02D427BC038>I<163FA25E
+5E5D5DA25D5D5D5DA25D92B5FCEC01F7EC03E7140715C7EC0F87EC1F07143E147E147C14
+F8EB01F0EB03E0130714C0EB0F80EB1F00133E5BA25B485A485A485A120F5B48C7FC123E
+5A12FCB91280A5C8000F90C7FCAC027FB61280A531417DC038>I<0007150301E0143F01
+FFEB07FF91B6FC5E5E5E5E5E16804BC7FC5D15E092C8FC01C0C9FCAAEC3FF001C1B5FC01
+C714C001DF14F09039FFE03FFC9138000FFE01FC6D7E01F06D13804915C0497F6C4815E0
+C8FC6F13F0A317F8A4EA0F80EA3FE0487E12FF7FA317F05B5D6C4815E05B007EC74813C0
+123E003F4A1380D81FC0491300D80FF0495AD807FEEBFFFC6CB612F0C65D013F1480010F
+01FCC7FC010113C02D427BC038>I<4AB47E021F13F0027F13FC49B6FC01079038807F80
+90390FFC001FD93FF014C04948137F4948EBFFE048495A5A1400485A120FA248486D13C0
+EE7F80EE1E00003F92C7FCA25B127FA2EC07FC91381FFF8000FF017F13E091B512F89039
+F9F01FFC9039FBC007FE9039FF8003FF17804A6C13C05B6F13E0A24915F0A317F85BA412
+7FA5123FA217F07F121FA2000F4A13E0A26C6C15C06D4913806C018014006C6D485A6C90
+38E01FFC6DB55A011F5C010714C0010191C7FC9038003FF02D427BC038>I<121E121F13
+FC90B712FEA45A17FC17F817F017E017C0A2481680007EC8EA3F00007C157E5E00785D15
+014B5A00F84A5A484A5A5E151FC848C7FC157E5DA24A5A14035D14074A5AA2141F5D143F
+A2147F5D14FFA25BA35B92C8FCA35BA55BAA6D5A6D5A6D5A2F447AC238>I<EC7FF00103
+B5FC010F14C0013F14F090397F801FFC3A01FC0003FE48486D7E497F4848EC7F80163F48
+4815C0A2001F151FA27FA27F7F01FE143F6D158002C0137F02F014006C01FC5B6E485A6C
+9038FF83FCEDE7F86CECFFE06C5D6C92C7FC6D14C06D80010F14F882013F8090B7FC4801
+3F14802607FC0F14C0260FF80314E04848C6FC496D13F0003F141F48481307496D13F815
+0000FF157F90C8123F161F160FA21607A36D15F0127F160F6D15E06C6C141F6DEC3FC06C
+6CEC7F80D80FFE903801FF003A07FFC00FFE6C90B55AC615F0013F14C0010F91C7FC0100
+13F02D427BC038>I<EC7FF0903807FFFE011F6D7E017F14E09039FFE03FF0489038800F
+F848496C7E48488048486D7E001F80003F1680A2484815C08117E0A212FF17F0A617F8A4
+5D127FA3003F5CA26C7E5D6C6C5B12076C6C133E6CEBC07C6CEBFFF8013F5B010F01C013
+F00101130090C8FCA217E05DA2EA03C0D80FF015C0487E486C491380A217004B5A150F5E
+49495A6C48495A01C0EBFFE0260FF0035B6CB65A6C4AC7FC6C14F86C6C13E0D907FEC8FC
+2D427BC038>I<EA07C0EA1FF0EA3FF8EA7FFCEAFFFEA7EA7FFCEA3FF8EA1FF0EA07C0C7
+FCAEEA07C0EA1FF0EA3FF8EA7FFCEAFFFEA7EA7FFCEA3FF8EA1FF0EA07C00F2C78AB1F>
+I<EE1F80A24C7EA24C7EA34C7EA24B7FA34B7FA24B7FA34B7F169F031F80161F82033F80
+ED3E07037E80157C8203FC804B7E02018115F0820203814B137F0207815D173F020F814B
+7F021F8292C77EA24A82023E80027E82027FB7FCA291B87EA2498302F0C8FCA20103834A
+157F0107834A153FA249488284011F8491C97E4984133E017E82B6020FB612F0A54C457C
+C455>65 D<B9FC18F018FE727E19E026003FFCC700077F05017F716C7E727E727EA27213
+80A37213C0A74E1380A24E1300A24E5A4E5A4E5A4D5B05075B94B5128091B700FCC7FC18
+F018FF19E002FCC7000113F8716C7EF01FFE727E7213801AC07213E0A27213F0A31AF8A7
+1AF0A2601AE0604E13C0604E138095B5120005075BBA12F86119C04EC7FC18E045447CC3
+50>I<DCFFF01470031F01FF14F04AB6EAE0010207EDF803023FEDFE0791B539E001FF0F
+4949C7EA3F9F010701F0EC0FFF4901C0804990C87E4948814948814948167F4849163F48
+49161F5A4A160F485B19074890CAFC19035A5BA2007F1801A34994C7FC12FFAE127F7F1A
+F0A2123FA27F6C18011AE06C7F19036C6D17C06E16077E6C6DEE0F806C6DEE1F006D6C5E
+6D6C167E6D6C6C5D6D6D4A5A6D01F0EC07F0010101FEEC1FE06D903AFFF001FF80023F90
+B6C7FC020715FC020115F0DA001F1480030001F8C8FC44467AC451>I<B9FC18F018FE72
+7E19E026003FFEC7001F13F805017F9438003FFF060F7F727F727F727F84737E737EA273
+7EA2737EA21B80A2851BC0A51BE0AD1BC0A51B8061A21B006162193F624F5A19FF624E5B
+06075B4E5B063F90C7FC4DB45A050F13F8BA5A19C04EC8FC18F095C9FC4B447CC356>I<
+BA12F8A485D8001F90C71201EF003F180F180318011800A2197E193EA3191EA21778A285
+A405F890C7FCA316011603161F92B5FCA5ED001F160316011600A2F101E01778A2F103C0
+A494C7FC1907A21A80A2190FA2191FA2193FF17F0061601807181F4DB5FCBBFC61A44344
+7DC34A>I<BA1280A419C026003FFEC7121F1701EF007F183F181F180F180719E01803A3
+1801A3EE01E0F000F0A419001603A31607160F167F91B6FCA59138FE007F160F16071603
+A31601A693C9FCAFB712F0A53C447CC346>I<DCFFF01470031F01FF14F04AB6EAE00102
+07EDF803023FEDFE0791B539E001FF0F4949C7EA3F9F010701F0EC0FFF4901C0804990C8
+7E4948814948814948167F4849163F4849161F5A4A160F485B19074890CAFC19035A5BA2
+007F1801A34994C8FC12FFAD057FB612F0127F7FA3003FDC0001EBF000A27F7EA26C7FA2
+6C7F807E6C7F6C7F6D7E6D6C5D6D6C7E6D6D5C6D01F05C010101FE143F6D903AFFF001FF
+9F023F90B6120F0207EDFC030201EDF000DA001F02C01330030001FCC9FC4C467AC458>
+I<B7D88003B612FEA526003FFEC9EBF800B3A791B9FCA54AC9FCB3AAB7D88003B612FEA5
+4F447CC358>I<B712E0A5D8001F90C7FCB3B3B3A4B712E0A523447DC32A>I<B76C0103B5
+12F8A526003FFEC93807E0004F5A4F5A077EC7FC614E5A4E5A4E5AF01F804EC8FC187E60
+4D5AEF07F0EF0FC04D5A4DC9FC177E4C5AEE03F04C5A4C5A4C7EEE7FF04C7E5D4B7F4B7F
+4B7FED3F3FDB7E1F7F03FC806E486C7F4B7E4B6C7F0380804B6C7F4A7F717E84717F8371
+7F85717F83717F85717F187F727E86727F84727F86727F84B76C90B612FCA54E447CC358
+>75 D<B712F0A526003FFECAFCB3B1F00780A4180F1900A460A360A2187EA218FE170117
+031707171F177FEE03FFB95AA539447CC343>I<B500FE067FB512806E95B6FCA26F5EA2
+D8003F50C7FC013D6DEE03DFA2013C6DEE079FA26E6CEE0F1FA26E6C161EA26E6C163CA3
+6E6C1678A26E6C16F0A26E6DEC01E0A26E6DEC03C0A36E6DEC0780A26F6CEC0F00A26F6C
+141EA26F6C5CA36F6C5CA26F6C5CA26F6D485AA26F6D485AA26F6D485AA3706C48C7FCA2
+93383FF81EA2706C5AA2706C5AA3706C5AA2705BA2705BA2705BA2B6057FB6128071C7FC
+A2173E171C61447CC36A>I<B64BB512FE8181A281D8003F6D91C7EA780081013D7F8113
+3C6E7E6E7F6E7F6E7F6E7F82806E7F6E7F6F7E6F7F83816F7F6F7F6F7F6F7F6F7F838270
+7F707F707F707F8482707F707F717E7113807113C019E0837113F07113F87113FC7113FE
+19FF847213F884848484A28484197F193F191FA2190F1907B61603190119001A78A24F44
+7CC358>I<B9FC18F018FE727E19E0D8001F90C7000F7F05017F716C7E727E727E721380
+A21AC084A21AE0A91AC0A24E1380A21A00604E5A4E5A4D485A050F5B92B712C096C7FC18
+FC18C092CBFCB3A7B712E0A543447DC34D>80 D<B812F8EFFFC018F818FE727ED8001F90
+C7003F13E005037F05007F727E727E727EA28684A286A762A24E90C7FCA24E5A61187F94
+3801FFF005075B053F138092B7C8FC18F818E018F892C77FEF3FFF050F7F717F717FA271
+7FA2717FA785A61B0F85A2187F73131F72141EB700E06DEB803E72EBE0FC72EBFFF80601
+14F0726C13E0CC0007138050457DC354>82 D<DAFFE0131C010701FE133C013F9038FF80
+7C90B6EAE0FC4815F9489038801FFF3907FC00014848EB007F4848143F4848140F491407
+007F15035B1601160012FF177CA27FA26D153C7F7F6D92C7FC6C7EEBFFE014FE6CEBFFF0
+15FF6C15E016FC6C816C6F7E6C826C826C6C81011F810107811300020F80140003077FED
+007F82040F1380828212F082A282A27EA218007EA26C5D6C5E6D14036D5D6D140701F84A
+5A01FFEC3FF002F8EBFFE0486CB65AD8FC1F92C7FCD8F80714FC48C614F0480107138031
+467AC43E>I<003FBA12E0A59026FE000FEB8003D87FE09338003FF049171F90C71607A2
+007E1803007C1801A300781800A400F819F8481978A5C81700B3B3A20107B8FCA545437C
+C24E>I<B76C010FB512F8A526003FFEC93803E000B3B3A9011F17076280190F6D606F15
+1F6D95C7FC6D6D5D197E6D6D5D6D6D1403DA7FFC4A5A6EB4EC3FF0020F9039F003FFE06E
+90B61280020193C8FC6E6C14FC030F14E09226007FFEC9FC4D457CC356>I<B792B6FCA5
+26003FFECAEAFC00806D606F15016D608119036D606F15076D606F150F6D6081191F6D6D
+93C7FC61027F163E6F157E023F167C8119FC6E6D5C18016E5E7013036E5E8218076E6D5C
+180F6E5E70131F6E93C8FC705B037F143E82187E033F147C7013FC6F5C17816F5C17C117
+C36F5C17E76F5C17FF6F5CA36F91C9FCA2705AA2705AA3705AA2705AA2705AA250457EC3
+55>I<B600FE017FB691B512FEA526007FFCC8D83FFEC9EA7C006E82013F701778807415
+F86D705F6F7014016D705FA26F7014036D64814E6D14076D646F70140F6D041E94C7FCA2
+6F023E6D5C6DDC3C7F151E81027F037C6D5CF0783F6F70147C023F4B6C1578A26F01016F
+13F86E4B6C5D16806E02036F485A4E7E04C0EEE0036E4A486C5DA2DCE00FEDF0076E4B6C
+5D16F06E4A6F48C8FC051E7F04F8705A6E4A027F131EA2DCFC7CEDFE3E037F0178023F13
+3C04FE16FF033F01F85E4D8004FF17F86F496E5BA36F496E5BA26F604D80A26F90C86C5B
+A36F486F90C9FCA26F48167EA30478163C6F457EC374>I<903801FFE0011F13FE017F6D
+7E48B612E03A03FE007FF84848EB1FFC6D6D7E486C6D7EA26F7FA36F7F6C5A6C5AEA00F0
+90C7FCA40203B5FC91B6FC1307013F13F19038FFFC01000313E0000F1380381FFE00485A
+5B127F5B12FF5BA35DA26D5B6C6C5B4B13F0D83FFE013EEBFFC03A1FFF80FC7F0007EBFF
+F86CECE01FC66CEB8007D90FFCC9FC322F7DAD36>97 D<EB7FC0B5FCA512037EB1ED0FF8
+92B57E02C314E002CF14F89139DFC03FFC9139FF000FFE02FCEB03FF4A6D13804A15C04A
+6D13E05CEF7FF0A218F8173FA318FCAC18F8A2177F18F0A3EFFFE06E15C06E5B6E491380
+027C491300496C495A903AFC1FC07FFC496CB512F0D9F00314C049C691C7FCC8EA1FF036
+467DC43E>I<EC3FFC49B512C0010F14F0013F14FC90397FF003FE9039FFC001FF000349
+5A48494813805B120F485AA2485A6F1300007F6E5AED00784991C7FCA212FFAC6C7EA312
+3F6DEC03C0A26C6C1407000F16806D140F6C6DEB1F006C6D133E6C01F05B3A007FFC03F8
+6DB55A010F14C0010391C7FC9038003FF82A2F7CAD32>I<EE03FEED07FFA5ED001F160F
+B1EC3FE0903803FFFC010FEBFF8F013F14CF9039FFF807FF48EBC00148903880007F4890
+C7123F4848141F49140F121F485AA3127F5BA212FFAC127FA37F123FA26C6C141FA26C6C
+143F0007157F6C6C91B5FC6CD9C00314FC6C9038F01FEF6DB5128F011FEBFE0F010713F8
+9026007FC0EBF80036467CC43E>I<EC3FF80103B57E010F14E0013F8090397FF83FF890
+39FFC007FC48496C7E48496C7E48486D1380485A001FED7FC05B003FED3FE0A2127F5B17
+F0161F12FFA290B7FCA401F0C9FCA5127FA27FA2123F17F06C7E16016C6C15E06C6C1403
+6C6DEB07C06C6DEB0F806C01F0EB3F0090397FFE01FE011FB55A010714F0010114C09026
+001FFEC7FC2C2F7DAD33>I<EDFF80020F13E0027F13F049B512F849EB8FFC90390FFE0F
+FE90381FFC1F14F8133FEB7FF0A2ED0FFCEBFFE0ED03F0ED00C01600ABB612F8A5C601E0
+C7FCB3B0007FEBFFE0A527467DC522>I<DAFFE0137E010F9039FE03FF80013FEBFF8F90
+B812C048D9C07F133F489038001FF84848EB0FFC4848903907FE1F80001F9238FF0F0049
+6D90C7FCA2003F82A8001F93C7FCA26D5B000F5D6C6C495A6C6C495A6C9038C07FF04890
+B55A1680D8078F49C8FC018013E0000F90CAFCA47F7F7F90B612C016FC6CEDFF8017E06C
+826C16FC7E000382000F82D81FF0C77ED83FC014074848020113808248C9FC177FA46D15
+FF007F17006D5C6C6C4A5A6C6C4A5AD80FFEEC3FF83B07FFC001FFF0000190B612C06C6C
+92C7FC010F14F8D9007F90C8FC32427DAC38>I<EB7FC0B5FCA512037EB1ED07FE92383F
+FF8092B512E002C114F89139C7F03FFC9138CF801F9139DF000FFE14DE14FC4A6D7E5CA2
+5CA35CB3A7B60083B512FEA537457CC43E>I<137C48B4FC4813804813C0A24813E0A56C
+13C0A26C13806C1300EA007C90C7FCAAEB7FC0EA7FFFA512037EB3AFB6FCA518467CC520
+>I<EB7FC0B5FCA512037EB293387FFFE0A593380FE0004C5A4CC7FC167E5EED03F8ED07
+E04B5A4B5A037FC8FC15FEECC1FCECC3FE14C7ECDFFF91B57E82A202F97F02E17F02C07F
+EC807F6F7E826F7E816F7F836F7F816F7F83707E163FB60003B512F8A535457DC43B>
+107 D<EB7FC0B5FCA512037EB3B3B3A3B61280A519457CC420>I<90277F8007FEEC0FFC
+B590263FFFC090387FFF8092B5D8F001B512E002816E4880913D87F01FFC0FE03FF8913D
+8FC00FFE1F801FFC0003D99F009026FF3E007F6C019E6D013C130F02BC5D02F86D496D7E
+A24A5D4A5DA34A5DB3A7B60081B60003B512FEA5572D7CAC5E>I<90397F8007FEB59038
+3FFF8092B512E0028114F8913987F03FFC91388F801F000390399F000FFE6C139E14BC02
+F86D7E5CA25CA35CB3A7B60083B512FEA5372D7CAC3E>I<EC1FFC49B512C0010714F001
+1F14FC90397FF80FFF9026FFC0017F48496C7F4848C7EA3FE000078248486E7E49140F00
+1F82A2003F82491407007F82A400FF1780AA007F1700A46C6C4A5AA2001F5E6D141F000F
+5E6C6C4A5AA26C6C6CEBFFE06C6D485B27007FF80F90C7FC6DB55A010F14F8010114C090
+26001FFCC8FC312F7DAD38>I<90397FC00FF8B590B57E02C314E002CF14F89139DFC03F
+FC9139FF001FFE000301FCEB07FF6C496D13804A15C04A6D13E05C7013F0A2EF7FF8A4EF
+3FFCACEF7FF8A318F017FFA24C13E06E15C06E5B6E4913806E4913006E495A9139DFC07F
+FC02CFB512F002C314C002C091C7FCED1FF092C9FCADB67EA536407DAC3E>I<DA3FE013
+1E902603FFFC133E010F01FF137E013F1480903AFFF80FE0FE489038E003F148EBC00148
+90388000FB4890C7127F49143F001F151F485A160F5B127FA3485AAC6C7EA46C7EA26C6C
+141F163F6C6C147F6C15FF6C6D5A6C9038E003EF6C9038F01FCF6DB5128F011FEBFE0F01
+0313F89038007FC091C7FCAD0307B512FCA536407CAC3B>I<90387F807FB53881FFE002
+8313F0028F13F8ED8FFC91389F1FFE000313BE6C13BC14F8A214F0ED0FFC9138E007F8ED
+01E092C7FCA35CB3A5B612E0A5272D7DAC2E>I<90391FFC038090B51287000314FF120F
+381FF003383FC00049133F48C7121F127E00FE140FA215077EA27F01E090C7FC13FE387F
+FFF014FF6C14C015F06C14FC6C800003806C15806C7E010F14C0EB003F020313E0140000
+F0143FA26C141F150FA27EA26C15C06C141FA26DEB3F8001E0EB7F009038F803FE90B55A
+00FC5CD8F03F13E026E007FEC7FC232F7CAD2C>I<EB01E0A51303A41307A2130FA2131F
+A2133F137F13FF1203000F90B51280B7FCA4C601E0C7FCB3A3ED01E0A9150302F013C013
+7F150790393FF80F8090391FFC1F006DB5FC6D13FC01015B9038003FE023407EBE2C>I<
+D97FC049B4FCB50103B5FCA50003EC000F6C81B3A85EA25EA25E7E6E491380017FD901F7
+13FE9138F807E76DB512C7010F1407010313FE9026007FF0EBFC00372E7CAC3E>I<B690
+3803FFFCA5000101E09038003E006C163C80017F5D8017F8013F5D6E1301011F5D6E1303
+010F5D6E13076D5DED800F6D92C7FC15C05E6DEBE01E163E6D143CEDF07C027F1378EDF8
+F8023F5B15FD021F5B15FF6E5BA36E5BA26E90C8FCA26E5AA26E5AA21578362C7EAB3B>
+I<B5D8FE1FB539801FFFF0A500019027C0003FE0C7EA7C007114786E17F86C6F6C5C6E16
+01017F6E6C5CA26E011F1403013F6F5C6E013F1407011F6F5CA26E0179140F010F048090
+C7FC6E01F95C6D02F0EBC01E15806D902681E07F5B18E003C3157C6D9139C03FF07815E7
+6DDA801F5B18F803FF14F96E9039000FFDE018FF6E486D5BA36E486D5BA26E486D90C8FC
+A24B7F02075DA26E48147C4B143C4C2C7EAB51>I<B500FE90383FFFF0A5C601F0903803
+E0006D6C495A013F4A5A6D6C49C7FC6E5B6D6C137E6DEB807C6D6D5A6DEBC1F0EDE3E06D
+EBF7C06EB45A806E90C8FC5D6E7E6E7F6E7FA24A7F4A7F8291381F3FFCEC3E1F027C7F4A
+6C7E49486C7F01036D7F49487E02C08049486C7F49C76C7E013E6E7E017E141FB500E090
+B512FCA5362C7EAB3B>I<B6903803FFFCA5000101E09038003E006C163C80017F5D8017
+F8013F5D6E1301011F5D6E1303010F5D6E13076D5DED800F6D92C7FC15C05E6DEBE01E16
+3E6D143CEDF07C027F1378EDF8F8023F5B15FD021F5B15FF6E5BA36E5BA26E90C8FCA26E
+5AA26E5AA21578A215F85D14015D001F1303D83F805B387FC007D8FFE05B140F92C9FC5C
+143E495A387FC1F8EB07F06CB45A6C5B000790CAFCEA01FC36407EAB3B>I
+E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fe cmtt10 10.95 93
+/Fe 93 127 df<121C127FEAFF80B3EA7F00B2123EC7FCA8121C127FA2EAFF80A3EA7F00
+A2121C09396DB830>33 D<00101304007C131F00FEEB3F80A26C137FA248133FB2007E14
+00007C7F003C131E00101304191C75B830>I<903907C007C0A2496C487EA8011F131FA2
+02C05BA3007FB7FCA2B81280A36C16006C5D3A007F807F80A2020090C7FCA9495BA2003F
+90B512FE4881B81280A36C1600A22701FC01FCC7FCA300031303A201F85BA76C486C5AA2
+29387DB730>I<1438147C14FCA4EB03FF011F13E090B512FC4880000780481580261FFE
+FD13C09039F0FC3FE0D83FC0131FD87F80EB0FF001001307007E15F800FE14035A1507A3
+6CEC03F0A2007F91C7FC138013C0EA3FF0EA1FFE13FF6C13FF6C14E0000114F86C6C7F01
+1F7F01037F0100148002FD13C09138FC7FE0151FED0FF015070018EC03F8127E1501B4FC
+A35AA26CEC03F07E01801307ED0FE0D83FC0131F01F0EB7FC0D81FFEB512806CB612006C
+5C6C5CC614F0013F13C0D907FEC7FCEB00FCA5147C143825477BBE30>I<D803C0EB01E0
+D80FF01303486C497E487E150F487ED87E7E495AEAFE7F5E486C133FA25E157FA24BC7FC
+6C5A5D387E7E01EA7FFED83FFC5B1403EA1FF86C48485AEA03C0C75B140FA25D141FA24A
+5AA25D147FA292C8FC5CA2495AA25C1303A25C1307A290390FF001E0ED07F84A487E011F
+497EA24A487E133F163F90267F807F1380ED7E1F14005BA25B1201A24848EB7F3F033F13
+004914FF12076F5A5B6F5A6C486D5A0001EC01E029477DBE30>I<EB07E0EB1FF8497E13
+7F497E803801FC7F497E810003131F13F0A6143F92C8FC91387F0FFF9026F87E1F138000
+0113FEEBF9FC13FB4A6C1300D9FFF013C06C13E0151F02C05BEB7F809038FF003F4892C7
+FC485C48EB807E5A15FE391FDFC0FC383F8FE014E1397F07F1F8EB03F300FEEBFBF0EB01
+FF5D7FEDC006027F130F91393F801F8015C06C137F6CEBFFE049EBF83F018701FC130026
+3FFFFBB5FC6C01F15B14E06C9038C03FFC00039038001FF8D801FCEB07E0293A7DB830>
+I<EA07C0EA0FF0EA1FF8A213FCA213FE120F1207EA007EA513FE13FCA2120113F81203EA
+07F0120FEA1FE0127FEAFFC013801300127C12380F1D70B730>I<141E147F14FF5BEB03
+FEEB07FCEB0FF0EB1FE0EB3FC0EB7F80EBFF00485A5B12035B485A120F5BA2485AA2123F
+5BA2127F90C7FCA412FEAD127FA47F123FA27F121FA26C7EA27F12076C7E7F12017F6C7E
+EB7F80EB3FC0EB1FE0EB0FF0EB07FCEB03FEEB01FF7F147F141E184771BE30>I<127812
+FE7E7F6C7E6C7EEA0FF06C7E6C7E6C7E6C7EEB7F80133F14C0131FEB0FE014F01307A2EB
+03F8A214FC1301A214FE1300A4147FAD14FEA4130114FCA2130314F8A2EB07F0A2130F14
+E0EB1FC0133F1480137FEBFF00485A485A485A485AEA3FE0485A485A90C7FC5A12781847
+78BE30>I<14E0497E497EA60038EC0380007EEC0FC0D8FF83EB3FE001C3137F9038F3F9
+FF267FFBFB13C06CB61280000FECFE00000314F86C5C6C6C13C0011F90C7FC017F13C048
+B512F04880000F14FE003FECFF80267FFBFB13C026FFF3F913E09038C3F87F0183133FD8
+7E03EB0FC00038EC0380000091C7FCA66D5A6D5A23277AAE30>I<143EA2147FAF007FB7
+FCA2B81280A36C1600A2C76CC8FCAF143EA229297DAF30>I<EA03E0EA0FF0EA1FF813FC
+EA3FFEA213FFA27EA27E1203EA007FA2137E13FEEA01FC1203EA07F8EA3FF0127FEAFFE0
+EA7F801300123C1019708B30>I<007FB612F0A2B712F8A36C15F0A225077B9E30>I<120F
+EA3FC0EA7FE0A2EAFFF0A4EA7FE0A2EA3FC0EA0F000C0C6E8B30>I<16F01501ED03F8A2
+1507A2ED0FF0A2ED1FE0A2ED3FC0A2ED7F80A2EDFF00A24A5AA25D1403A24A5AA24A5AA2
+4A5AA24A5AA24A5AA24AC7FCA2495AA25C1303A2495AA2495AA2495AA2495AA2495AA249
+C8FCA2485AA25B1203A2485AA2485AA2485AA2485AA2485AA248C9FCA25AA2127CA22547
+7BBE30>I<14FE903807FFC0497F013F13F8497F90B57E48EB83FF4848C6138049137F48
+48EB3FC04848EB1FE049130F001F15F0491307A24848EB03F8A290C712014815FCA400FE
+EC00FEAD6C14016C15FCA36D1303003F15F8A26D1307001F15F0A26D130F6C6CEB1FE0A2
+6C6CEB3FC06C6CEB7F806D13FF2601FF8313006CEBFFFE6D5B6D5B010F13E06D5BD900FE
+C7FC273A7CB830>I<EB03C0497EA2130FA2131FA2133F137F13FF1203123FB5FCA213EF
+138FEA7E0F1200B3B0003FB512F84814FCB612FEA26C14FC6C14F81F3977B830>I<EB07
+FC90383FFFC090B512F00003804814FE4880261FF80F1380263FE00113C09038C0007F48
+48EB3FE090C7121FED0FF04814075A6C15F81503A3127E1218C8FCA2150716F0150F16E0
+151F16C0153FED7F8015FF4A13005DEC07FC4A5A4A5A4A5A4A5A4A5A4990C7FC495A495A
+EB0FF0EB3FE0495A495A4890C8FC4848EB01F04848EB03F8485AEA1FE048B6FCB7FCA37E
+6C15F025397BB830>I<EB03FF013F13E090B512F84814FE4880481580260FFE0113C090
+38F0007F4848EB1FE0150F16F01507A26C5A6C5AC8FC150F16E0A2151FED3FC0157FEDFF
+8002071300903807FFFE495B5D8115FF6D1480D9000113C09138003FE0ED1FF0ED07F815
+0316FC150116FE1500A21218127EB4FCA2150116FC4814036C15F86C6C13076DEB1FF0D8
+3FF0133F3A1FFE01FFE06CB612C06C15806CECFE00C65C013F13F001031380273A7CB830
+>I<EC03FC4A7E140F141FA2143F147F157E14FEA2EB01FCEB03F8A2EB07F0A2EB0FE0EB
+1FC0A2EB3F80A2EB7F0013FEA2485A485AA2485AA2485A485AA2485AA248C7FC12FEB8FC
+1780A46C1600C8007EC7FCAA91387FFFFE91B6FCA46E5B29397DB830>I<000FB6128048
+15C05AA316800180C8FCAEEB83FF019F13C090B512F015FC8181D9FE0313809039F0007F
+C049133F0180EB1FE06CC7120F000E15F0C81207A216F81503A31218127EA2B4FC150716
+F048140F6C15E06C141F6DEB3FC06D137F3A3FE001FF80261FFC0F13006CB55A6C5C6C5C
+6C14E06C6C1380D90FFCC7FC25397BB730>I<EC0FF8EC7FFF49B51280010714E0131F49
+14F090387FF80F9039FFC007F84813803803FE005B485A4848EB03F0ED01E0484890C7FC
+5B123F5BA2127FEB000C903803FFE0010F13F8D8FF3F13FE48B6FCB7128016C09039FE00
+7FE001F8EB1FF001E0130F49EB07F849EB03FCA290C7120116FE1500A37EA46C7E15016D
+14FC121F6D1303000FEC07F86D130F6C6CEB1FF06DEB3FE03A03FF81FFC06C90B512806C
+15006D5B011F13F8010713E001011380273A7CB830>I<127CB712FC16FEA416FC48C7EA
+0FF816F0ED1FE0007CEC3FC0C8EA7F80EDFF00A24A5A4A5A5D14075D140F5D4A5AA24A5A
+A24AC7FCA25C5C13015CA213035CA213075CA4495AA6131F5CA96D5A6DC8FC273A7CB830
+>I<49B4FC011F13F0017F13FC90B57E0003ECFF804815C048010113E03A1FF8003FF049
+131FD83FC0EB07F8A24848EB03FC90C71201A56D1303003F15F86D13076C6CEB0FF06C6C
+EB1FE0D807FCEB7FC03A03FF83FF806C90B512006C6C13FC011F13F0497F90B512FE4880
+2607FE0013C0D80FF8EB3FE0D81FE0EB0FF04848EB07F8491303007F15FC90C712014815
+FE481400A66C14016C15FC6D1303003F15F86D1307D81FF0EB1FF06D133F3A0FFF01FFE0
+6C90B512C06C1580C6ECFE006D5B011F13F0010190C7FC273A7CB830>I<49B4FC010F13
+E0013F13F890B57E4880488048010113803A0FFC007FC0D81FF0EB3FE04848131F49EB0F
+F048481307A290C7EA03F85A4815FC1501A416FEA37E7E6D1303A26C6C13076C6C130F6D
+133FD80FFC13FF6CB6FC7E6C14FE6C14F9013FEBE1FC010F138190380060011400ED03F8
+A2150716F0150F000F15E0486C131F486CEB3FC0157FEDFF804A1300EC07FE391FF01FFC
+90B55A6C5C6C5C6C1480C649C7FCEB3FF0273A7CB830>I<120FEA3FC0EA7FE0A2EAFFF0
+A4EA7FE0A2EA3FC0EA0F00C7FCAF120FEA3FC0EA7FE0A2EAFFF0A4EA7FE0A2EA3FC0EA0F
+000C276EA630>I<EA03C0EA0FF0EA1FF8A2EA3FFCA4EA1FF8A2EA0FF0EA03C0C7FCAFEA
+03C0EA0FF0121F13F8123F13FCA3121FA2120F12031200120113F8120313F01207EA1FE0
+123FEA7FC0EAFF80EA7F00127E12380E3470A630>I<16F01503ED07F8151F157FEDFFF0
+14034A13C0021F138091383FFE00ECFFF8495B010713C0495BD93FFEC7FC495A3801FFF0
+485B000F13804890C8FCEA7FFC5BEAFFE05B7FEA7FF87FEA1FFF6C7F000313E06C7F3800
+7FFC6D7E90380FFF806D7F010113F06D7FEC3FFE91381FFF80020713C06E13F01400ED7F
+F8151F1507ED03F01500252F7BB230>I<007FB7FCA2B81280A36C16006C5DCBFCA7003F
+B612FE4881B81280A36C1600A229157DA530>I<1278127EB4FC13C07FEA7FF813FEEA1F
+FF6C13C000037F6C13F86C6C7EEB1FFF6D7F010313E06D7F9038007FFC6E7E91380FFF80
+6E13C0020113F080ED3FF8151F153FEDFFF05C020713C04A138091383FFE004A5A903801
+FFF0495B010F13804990C7FCEB7FFC48485A4813E0000F5B4890C8FCEA7FFE13F8EAFFE0
+5B90C9FC127E1278252F7BB230>I<EB1FFE90B512E0000314F8000F14FE488048158026
+7FF80313C09038C0007F48C7121F16E0150FA3127E151F0018EC7FC0C812FF020313804A
+13004A5AEC1FF84A5AEC7FC04A5A92C7FC495AA2495A5CA213075CA86D5A90C9FCA8EB01
+C0EB07F0A2497EA36D5AA2EB01C023397AB830>I<EC1FE0ECFFF8010313FE010F7F4914
+804914C090397FF03FE09038FF800F4890380007F0D803FC13033A07F801FBF89038F007
+FF380FE01F4A13FCEA1FC0495A003FEBFF0F903800FE07903901FC03FE007FEBF801EA7E
+03ECF000A2EAFE0700FC49137EAA00FE6D13FED87E0314FCA2ECF801D87F0114F8003FEB
+FC03903900FE07F0903880FF0F001F90387FFFE06D6C13C0EA0FE06E13803A07F007FE00
+9038F801F86C6CC7127C6CB414FE6CEB800390387FF01F6DB512FC6D14F86D14E0010314
+C00100EBFE00EC1FF0273A7CB830>I<147F4A7EA2497FA4497F14F7A401077F14E3A301
+0F7FA314C1A2011F7FA490383F80FEA590387F007FA4498049133F90B6FCA34881A39038
+FC001F00038149130FA4000781491307A2D87FFFEB7FFFB56CB51280A46C496C13002939
+7DB830>I<007FB512F0B612FE6F7E82826C813A03F8001FF815076F7E1501A26F7EA615
+015EA24B5A1507ED1FF0ED7FE090B65A5E4BC7FC6F7E16E0829039F8000FF8ED03FC6F7E
+1500167FA3EE3F80A6167F1700A25E4B5A1503ED1FFC007FB6FCB75A5E16C05E6C02FCC7
+FC29387EB730>I<91387F803C903903FFF03E49EBFC7E011F13FE49EBFFFE5B9038FFE0
+7F48EB801F3903FE000F484813075B48481303A2484813015B123F491300A2127F90C8FC
+167C16005A5AAC7E7EA2167C6D14FE123FA27F121F6D13016C6C14FCA26C6CEB03F86D13
+076C6CEB0FF03901FF801F6C9038E07FE06DB512C06D14806D1400010713FC6D13F09038
+007FC0273A7CB830>I<003FB512E04814FCB67E6F7E6C816C813A03F8007FF0ED1FF815
+0F6F7E6F7E15016F7EA2EE7F80A2163F17C0161FA4EE0FE0AC161F17C0A3163F1780A216
+7F17005E4B5A15034B5A150F4B5AED7FF0003FB65A485DB75A93C7FC6C14FC6C14E02B38
+7FB730>I<007FB7FCB81280A47ED803F8C7123FA8EE1F0093C7FCA4157C15FEA490B5FC
+A6EBF800A4157C92C8FCA5EE07C0EE0FE0A9007FB7FCB8FCA46C16C02B387EB730>I<00
+3FB712804816C0B8FCA27E7ED801FCC7121FA8EE0F8093C7FCA5153E157FA490B6FCA690
+38FC007FA4153E92C8FCAE383FFFF8487FB5FCA27E6C5B2A387EB730>I<02FF13F00103
+EBC0F8010F13F1013F13FD4913FF90B6FC4813C1EC007F4848133F4848131F49130F485A
+491307121F5B123F491303A2127F90C7FC6F5A92C8FC5A5AA892B5FC4A14805CA26C7F6C
+6D1400ED03F8A27F003F1407A27F121F6D130F120F7F6C6C131FA2D803FE133F6C6C137F
+ECC1FF6C90B5FC7F6D13FB010F13F30103EBC1F0010090C8FC293A7DB830>I<3B3FFF80
+0FFFE0486D4813F0B56C4813F8A26C496C13F06C496C13E0D803F8C7EAFE00B290B6FCA6
+01F8C7FCB3A23B3FFF800FFFE0486D4813F0B56C4813F8A26C496C13F06C496C13E02D38
+7FB730>I<007FB6FCB71280A46C1500260007F0C7FCB3B3A8007FB6FCB71280A46C1500
+213879B730>I<49B512F04914F85BA27F6D14F090C7EAFE00B3B3123C127EB4FCA24A5A
+1403EB8007397FF01FF86CB55A5D6C5C00075C000149C7FC38003FF025397AB730>I<D8
+3FFF90380FFF80486D4813C0B56C5AA26C497E6C496C1380D803F0903803F8004B5A4B5A
+151F4B5A5E4BC7FC15FE14014A5A5D4A5A4A5A141F5D4A5A4AC8FC5C13F18101F37F13F7
+90B57E14EFECC7F01483EC03F8140101FE7F496C7E5B157F497F82151F82150F826F7EA2
+6F7E1501821500D83FFF903803FFC0486D4813E0B56C5AA26C497E6C496C13C02B387FB7
+30>I<383FFFF8487FB57EA26C5B6C5BD801FCC9FCB3B0EE0F80EE1FC0A9003FB7FC5AB8
+FCA27E6C16802A387EB730>I<D83FF8ECFFE0486C4913F0486C4913F8A2007F16F06C6C
+4913E00007160001EF14BFEC800FA39039E7C01F3FA4ECE03F01E3133EA2ECF07EA201E1
+137CA2ECF8FCA201E013F8A214FDEC7DF0A3147FEC3FE0A3EC1FC0A2EC070091C7FCADD8
+3FFC903801FFE0486C4913F0B54913F8A26C486D13F06C486D13E02D387FB730>I<D83F
+FC90381FFF80486C4913C0B54913E0A26C6D6C13C06C6E13800003913801F800EBF7C0A3
+EBF3E0A314F013F1A214F8A213F014FCA2147C147EA2143E143FA2141FA21581A2140F15
+C1A2140715E1A2140315F1A21401A215F91400A3157DA3153FEA3FFF481380B5EAC01FA2
+6CEB800F6C496C5A2B387EB730>I<90383FFFE048B512FC000714FF4815804815C04815
+E0EBF80001E0133FD87F80EB0FF0A290C71207A44815F8481403B3A96C1407A26C15F0A3
+6D130FA26D131F6C6CEB3FE001F813FF90B6FC6C15C06C15806C1500000114FCD8003F13
+E0253A7BB830>I<007FB512F0B612FE6F7E16E0826C813903F8003FED0FFCED03FE1501
+6F7EA2821780163FA6167F17005EA24B5A1503ED0FFCED3FF890B6FC5E5E16804BC7FC15
+F001F8C9FCB0387FFFC0B57EA46C5B29387EB730>I<90383FFFE048B512FC000714FF48
+15804815C04815E0EBF80001E0133F4848EB1FF049130F90C71207A44815F8481403B3A8
+147E14FE6CEBFF076C15F0EC7F87A2EC3FC7018013CF9038C01FFFD83FE014E0EBF80F90
+B6FC6C15C06C15806C1500000114FCD8003F7FEB00016E7EA21680157F16C0153F16E015
+1F16F0150FED07E025467BB830>I<003FB57E4814F0B612FC15FF6C816C812603F8017F
+9138003FF0151F6F7E15071503821501A515035E1507150F4B5A153F4AB45A90B65A5E93
+C7FC5D8182D9F8007FED3FE0151F150F821507A817F8EEF1FCA53A3FFF8003FB4801C0EB
+FFF8B56C7E17F06C496C13E06C49EB7FC0C9EA1F002E397FB730>I<90390FF803C0D97F
+FF13E048B512C74814F74814FF5A381FF80F383FE001497E4848137F90C7123F5A48141F
+A2150FA37EED07C06C91C7FC7F7FEA3FF0EA1FFEEBFFF06C13FF6C14E0000114F86C8001
+1F13FF01031480D9003F13C014019138007FE0151FED0FF0A2ED07F8A2007C140312FEA5
+6C140716F07F6DEB0FE06D131F01F8EB3FC001FF13FF91B51280160000FD5CD8FC7F13F8
+D8F81F5BD878011380253A7BB830>I<003FB712C04816E0B8FCA43AFE003F800FA8007C
+ED07C0C791C7FCB3B1011FB5FC4980A46D91C7FC2B387EB730>I<3B7FFFC007FFFCB56C
+4813FEA46C496C13FCD803F8C7EA3F80B3B16D147F00011600A36C6C14FE6D13016D5CEC
+800390393FE00FF890391FF83FF06DB55A6D5C6D5C6D91C7FC9038007FFCEC1FF02F3980
+B730>I<D87FFE90380FFFC0B54913E06E5AA24A7E6C486D13C0D807F0903801FC00A26D
+130300035DA46C6C495AA46C6C495AA46D131F6D5CA3EC803F013F5CA46D6C48C7FCA490
+380FE0FEA401075B14F1A301035BA314FB01015BA314FFA26D5BA46E5A6E5A2B397EB730
+>I<D83FFC903801FFE0486C4913F000FF16F8A2007F16F06C486D13E0D81FC09038001F
+C0000F1680A76D143F00071600A7000390380F803E9039F01FC07EEC3FE0A3EC7FF0A214
+7D0001157CA29039F8FDF8FCA314F8A300005D01F913FCA2ECF07CA201FD137DA2017D5C
+ECE03DA3017F133FA2ECC01FA2013F5CA2EC800F6D486C5A2D397FB730>I<3A3FFF01FF
+F84801837F02C77FA202835B6C01015B3A01FC007F806D91C7FC00005C6D5BEB7F01EC81
+FCEB3F8314C3011F5B14E7010F5B14FF6D5BA26D5BA26D5BA26D90C8FCA4497FA2497FA2
+815B81EB0FE781EB1FC381EB3F8181EB7F0081497F49800001143F49800003141F498000
+07140FD87FFEEB7FFFB590B5128080A25C6C486D130029387DB730>I<D87FFF90381FFF
+C0B56C4813E0A46C496C13C0D803F8903803F8006D1307A26C6C495AA26C6C5C151F6D5C
+EC803F013F5CECC07F011F91C7FCA290380FE0FEA214F101075BA2903803FBF8A201015B
+14FF6D5BA26E5AA36E5AB1903803FFF8497F497FA26D5B6D5B2B387EB730>I<001FB612
+FC4815FE5AA490C7EA03FCED07F816F0150FED1FE016C0153FED7F80003E1500C85A4A5A
+5D14034A5A5D140F4A5A5D143F4A5A92C7FC5C495A5C1303495A5C130F495A5C133F495A
+91C8FC5B4848147C4914FE1203485A5B120F485A5B123F485A90B6FCB7FCA46C15FC2738
+7CB730>I<007FB5FCB61280A4150048C8FCB3B3B3A5B6FC1580A46C140019476DBE30>I<
+127CA212FEA27EA26C7EA26C7EA26C7EA26C7EA26C7EA26C7EA212017FA26C7EA26D7EA2
+6D7EA26D7EA26D7EA26D7EA26D7EA2130180A26D7EA26E7EA26E7EA26E7EA26E7EA26E7E
+A26E7EA2140181A26E7EA2ED7F80A2ED3FC0A2ED1FE0A2ED0FF0A2ED07F8A21503A2ED01
+F0150025477BBE30>I<007FB5FCB61280A47EC7123FB3B3B3A5007FB5FCB6FCA46C1400
+19477DBE30>I<1307EB1FC0EB7FF0497E000313FE000FEBFF80003F14E0D87FFD13F039
+FFF07FF8EBC01FEB800F38FE0003007CEB01F00010EB00401D0E77B730>I<007FB612F0
+A2B712F8A36C15F0A225077B7D30>I<EB7FF80003B5FC4814C04880488048809038E01F
+FC9038C003FE14016E7E6C487F6CC77FC8123FA491B5FC130F137F48B6FC12075A48EB80
+3F383FF800EA7FE0138048C7FC5AA4157F7E6C6C13FFEBC003263FF01FEBFF8090B712C0
+7E6C14EF000314876CD9FE01138026003FE0C8FC2A2A7BA830>97
+D<EA3FFC487E12FFA2127F123F1200AAEC03FE91381FFF80027F13E091B57E90B612FC82
+ECFE079138F001FF4A6C13804A137F4AEB3FC091C7121F17E049140FA217F01607A8160F
+A217E07F161F6EEB3FC0A26EEB7F806E13FFDAF00313009138FC0FFE91B55A5E495CD97E
+7F13C0D93C1F90C7FC90380003FC2C3980B730>I<ECFFE0010713FC011F7F017F7F90B6
+12804815C048EB807F3907FC003F485A485A49EB1F804848EB0F004990C7FC127F90C9FC
+A25A5AA87E7EA27F003FEC07C06DEB0FE06C7E6D131F6C6C14C0D807FE133F9039FFC0FF
+806C90B5FCC615006D5B011F13F801075B01011380232A7AA830>I<913801FFE04A7F5C
+A28080EC0007AAEB03FE90381FFF874913E790B6FC5A5A481303380FFC00D81FF0133F49
+131F485A150F4848130790C7FCA25AA25AA87E6C140FA27F003F141F6D133F6C7E6D137F
+390FF801FF2607FE07EBFFC06CB712E06C16F06C14F76D01C713E0011F010313C0D907FC
+C8FC2C397DB730>I<49B4FC010713E0011F13F8017F7F90B57E488048018113803A07FC
+007FC04848133FD81FE0EB1FE0150F484814F0491307127F90C7FCED03F85A5AB7FCA516
+F048C9FC7E7EA27F003FEC01F06DEB03F86C7E6C7E6D1307D807FEEB1FF03A03FFC07FE0
+6C90B5FC6C15C0013F14806DEBFE00010713F8010013C0252A7CA830>I<EDFF80020713
+E0021F13F05C4A13F891B5FC491387903803FE079138FC03F0903907F800C04A1300A800
+3FB612C04815E0B7FCA36C15C0260007F0C7FCB3A9003FB512FE4880B71280A26C15006C
+5C25397DB830>I<D903FC13FF90261FFF8713C04913DF90B712E05A5A2607FE07138F90
+3AF801FE07C048486C6CC7FCA2497F001F8149133FA56D137F000F92C7FC6D5BA26C6C48
+5AEBFE0790B55A5D485C15C001DF5BD9C3FCC8FC01C0C9FCA37F7F6CB512F015FF6C15C0
+4815F0488148813A3FE0001FFE0180130148C8127F007E8100FE168048151FA56C153F00
+7FED7F006D5C6C6C495A01F013076CB4EB7FFC6C90B55A6C5D000115C06C6C91C7FC011F
+13FC010113C02B3E7DA730>I<EA3FFC487E12FFA2127F123F1200AAEC01FE91380FFF80
+023F13E091B57E90B67EA29138FE07FCECF8039138E001FE14C0EC8000A291C7FCA25BB3
+A23B3FFFF81FFFF8486D4813FCB500FE14FEA26C01FC14FC6C496C13F82F3880B730>I<
+14E0EB03F8A2497EA36D5AA2EB00E091C8FCA9381FFFF8487F5AA27E7EEA0001B3A9003F
+B612C04815E0B7FCA27E6C15C023397AB830>I<EC01C0EC07F0A2EC0FF8A3EC07F0A2EC
+01C091C7FCA990B512F04814F8A47EEB0003B3B3A5EC07F0A2123C007EEB0FE0B4131FEC
+3FC0147F90B512806C14005C6C5B000F13F0000313C01D4E7CB830>I<EA7FF8487EA412
+7F1200AB0203B512804A14C017E0A217C06E14809139001FE0004B5A4B5A4BC7FC4A5A4A
+5AEC0FF84A5A4A5A4A5A4A5A01FD7F90B57E8114F7ECE3F8ECC1FCEC81FEEC00FF497F49
+6D7E6F7E826F7E15076F7E6F7E3B7FFFF81FFFE0B56C4813F017F8A217F06C496C13E02D
+387FB730>I<387FFFF8B57EA47EEA0001B3B3A8007FB612F0B712F8A46C15F025387BB7
+30>I<02FC137E3B7FC3FF01FF80D8FFEF01877F90B500CF7F15DF92B57E6C010F138726
+07FE07EB03F801FC13FE9039F803FC01A201F013F8A301E013F0B3A23C7FFE0FFF07FF80
+B548018F13C0A46C486C01071380322881A730>I<EC01FE3A3FFC0FFF80267FFE3F13E0
+00FF90B57E90B67E7E6C9038FE07FCC6EBF8039138E001FE14C0EC8000A291C7FCA25BB3
+A23B3FFFF81FFFF8486D4813FCB500FE14FEA26C01FC14FC6C496C13F82F2880A730>I<
+49B4FC010F13E0013F13F8497F90B57E0003ECFF8014013A07FC007FC04848EB3FE0D81F
+E0EB0FF0A24848EB07F8491303007F15FC90C71201A300FEEC00FEA86C14016C15FCA26D
+1303003F15F86D13076D130F6C6CEB1FF06C6CEB3FE06D137F3A07FF01FFC06C90B51280
+6C15006C6C13FC6D5B010F13E0010190C7FC272A7CA830>I<EC03FE3A3FFC1FFF80267F
+FE7F13E000FF90B57E90B612FC6C816CEBFE07C69038F001FF4A6C13804A137F4AEB3FC0
+91C7121F17E049140FA217F01607A8160FA217E07F161F6EEB3FC0A26EEB7F806E13FFDA
+F00313009138FC0FFE91B55A5E495C6E13C0021F90C7FCEC03FC91C9FCAD383FFFF8487F
+B57EA26C5B6C5B2C3C80A730>I<49B413F8010FEBC1FC013F13F14913FD48B6FC5A4813
+81390FFC007F49131F4848130F491307485A491303127F90C7FC15015A5AA77E7E15037F
+A26C6C1307150F6C6C131F6C6C133F01FC137F3907FF01FF6C90B5FC6C14FD6C14F9013F
+13F1010F13C1903803FE0190C7FCAD92B512F84A14FCA46E14F82E3C7DA730>I<ED07F8
+3A3FFF803FFF486DB51280B512C302CF14C06C13DF6C9038FFFC3FD8001F13E09238801F
+809238000F004A90C7FC5C5C5CA25CA45CAF003FB512FC4880B7FCA26C5C6C5C2A287EA7
+30>I<90381FFC1E48B5129F000714FF5A5A5A387FF007EB800100FEC7FC4880A46C143E
+007F91C7FC13E06CB4FC6C13FC6CEBFF806C14E0000114F86C6C7F01037F9038000FFF02
+001380007C147F00FEEC1FC0A2150F7EA27F151F6DEB3F806D137F9039FC03FF0090B6FC
+5D5D00FC14F0D8F83F13C026780FFEC7FC222A79A830>I<EB0780497E131FA9003FB612
+E04815F0B7FCA36C15E026001FC0C7FCB216F8ED01FCA5ECE003010FEB07F814F09138FC
+1FF06DB512E06D14C016806D14009038007FFCEC1FF026337EB130>I<D83FFCEB3FFC48
+6C497E00FF14FFA2007F147F003F143F00001400B3A41501A2150315076D130F903A7FC0
+7FFFF891B612FC6D15FE7F6D4913FC6D9038F87FF8010001C0C7FC2F2880A630>I<3B3F
+FFC07FFF80486DB512C0B515E0A26C16C06C496C13803B01F80003F000A26D130700005D
+A26D130F017E5CA2017F131F6D5CA2EC803F011F91C7FCA26E5A010F137EA2ECE0FE0107
+5BA214F101035BA3903801FBF0A314FF6D5BA36E5A6E5A2B277EA630>I<3B3FFFC01FFF
+E0486D4813F0B515F8A26C16F06C496C13E0D807E0C7EA3F00A26D5C0003157EA56D14FE
+00015DEC0F80EC1FC0EC3FE0A33A00FC7FF1F8A2147DA2ECFDF9017C5C14F8A3017E13FB
+A290393FF07FE0A3ECE03FA2011F5C90390F800F802D277FA630>I<3A3FFF81FFFC4801
+C37FB580A26C5D6C01815BC648C66CC7FC137FEC80FE90383F81FC90381FC3F8EB0FE3EC
+E7F06DB45A6D5B7F6D5B92C8FC147E147F5C497F81903803F7E0EB07E790380FE3F0ECC1
+F890381F81FC90383F80FE90387F007E017E137F01FE6D7E48486D7E267FFF80B5FCB500
+C1148014E3A214C16C0180140029277DA630>I<3B3FFFC07FFF80486DB512C0B515E0A2
+6C16C06C496C13803B01FC0003F000A2000014076D5C137E150F017F5C7F151FD91F805B
+A214C0010F49C7FCA214E00107137EA2EB03F0157C15FCEB01F85DA2EB00F9ECFDF0147D
+147FA26E5AA36E5AA35DA2143F92C8FCA25C147EA2000F13FE486C5AEA3FC1EBC3F81387
+EB8FF0EBFFE06C5B5C6C90C9FC6C5AEA01F02B3C7EA630>I<001FB612FC4815FE5AA316
+FC90C7EA0FF8ED1FF0ED3FE0ED7FC0EDFF80003E491300C7485A4A5A4A5A4A5A4A5A4A5A
+4A5A4990C7FC495A495A495A495A495A495A4948133E4890C7127F485A485A485A485A48
+5A48B7FCB8FCA46C15FE28277DA630>I<ED3FF0913803FFF8140F5C147F16F09138FFF0
+0092C7FC495A5CB3A21303495A133F383FFFF0B55A5C91C8FC14C080003F7F38003FF813
+076D7E1301B3A2806D7E15F091387FFFF016F8141F8014039138003FF025477BBE30>I<
+127CA212FEB3B3B3AD127CA207476CBE30>I<EA7FE0EAFFFE6D7E8014F07EC66C7E1307
+6D7E1301B3A2806D7E15E091387FFFE06E13F8801407141F5C4A13E09138FFE00092C7FC
+495A5CB3A21303495A137F387FFFF0B5FC14C05C49C8FCEA7FE025477BBE30>I<017C13
+3848B4137C48EB80FE4813C14813C348EBEFFC397FEFFFF0D8FF8713E0010713C0486C13
+80D87C0113003838007C1F0C78B730>I E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Ff cmbx12 14.4 62
+/Ff 62 123 df<922601FFFC903801FFE0033F9026FF801F13F84AB6D8E07F13FE020F03
+F9B6FC023FD9C00FB500C0138091277FFC0003D9FE0113C0902601FFE049495A49494949
+4813E04990C714F049484A13E0495A19C0495A7413C0017F17804A6E6E1380719138007E
+007192C7FCAEBCFCA526007FF8C7000301C0C8FCB3B3A7007FB5D8F803B612F0A553547D
+D34E>11 D<EEFFFC031FEBFF804AB612E0020781021F9038C00FF8913A7FFE0003FCDAFF
+F0EB00FE4949EB03FF4901805B4990C7487F49485CA2495A4D7F013F6F5B5CA37190C7FC
+715AEF01F894C9FCA90403B512C0BAFCA526003FFCC7120783B3B3A6003FB5D8FC03B612
+C0A542547DD34B>I<151E153E157E15FCEC01F8EC07F0EC0FE0EC1FC01580143FEC7F00
+14FE1301495A5C1307495AA2495A133F5C137FA2495AA24890C7FCA25A5BA21207A2485A
+A3121F5BA3123FA25BA3127FA55B12FFB3A3127F7FA5123FA37FA2121FA37F120FA36C7E
+A21203A27F7EA26C7FA26D7EA2133F80131F6D7EA26D7E1303806D7E1300147FEC3F8014
+1F15C0EC0FE0EC07F0EC01F8EC00FC157E153E151E1F7973D934>40
+D<127012F8127C127E7EEA1FC06C7E6C7E12037F6C7E6C7E7F6D7E133F806D7EA26D7E80
+130780A26D7EA26D7EA215807FA215C0A2EC7FE0A315F0143FA315F8A2141FA315FCA514
+0F15FEB3A315FC141FA515F8A3143FA215F0A3147F15E0A3ECFFC0A21580A25B1500A249
+5AA2495AA25C130F5C495AA2495A5C137F49C7FC5B485A485A5B1207485A485A48C8FC12
+7E127C5A12701F7979D934>I<B712F0AB240B7F9F2D>45 D<EA07F0487E487E487E487E
+B51280A76C13006C5A6C5A6C5A6C5A1111769025>I<EF01E01703EF07F0A2170FA2EF1F
+E0A218C0173FA2EF7F80A218005FA24C5AA25F1603A24C5AA25F160FA24C5AA25F163FA2
+4C5AA294C7FC5EA24B5AA25E1503A24B5AA25E150FA24B5AA25E153FA24B5AA293C8FC5D
+A24A5AA25D1403A25D1407A24A5AA25D141FA24A5AA25D147FA24AC9FCA25C1301A2495A
+A25C1307A2495AA25C131FA2495AA25C137FA249CAFCA25B1201A2485AA25B1207A2485A
+A25B121FA2485AA25B127FA248CBFCA25AA2127CA2347879D943>I<913803FFC0023F13
+FC91B6FC010315C0010F018113F0903A1FFC003FF849486D7E49486D7E49486D7E48496D
+138048496D13C0A24817E04890C813F0A34817F8A24817FC49157FA3007F17FEA600FF17
+FFB3A5007F17FEA6003F17FCA26D15FFA26C17F8A36C17F0A26C6D4913E0A26C6D4913C0
+6C17806E5B6C6D4913006D6C495AD91FFCEB3FF8903A0FFF81FFF06D90B55A01011580D9
+003F01FCC7FC020313C0384F7BCD43>I<157815FC14031407141F14FF130F0007B5FCB6
+FCA2147F13F0EAF800C7FCB3B3B3A6007FB712FEA52F4E76CD43>I<EC3FFE0103B512E0
+010F14FC013F14FF90B712C048D9C07F7F2703FE000F13F8D807F801037FD80FE06D7F48
+486D7F48488001F01680486C6E13C07F486C6E13E07FA27013F0A56C5AA26C5AEA0FF0EA
+03C0C914E05EA218C05E1880A24C13005F4C5A4B5B5F4B5B5F4B5B4B90C7FC4B5A5E4B5A
+ED7FE04B5A4A5B4A48C8FC4A5A5D4A48EB01F04A5AEC3F804AC7FC02FEEC03E0495A495A
+495A495AD91F80140749C8FC013E150F017FB7FC90B812C05A5A5A5A5A5A5AB9FC1880A4
+344E79CD43>I<91380FFFC091B512FC0107ECFF80011F15E090263FF8077F9026FF8001
+13FC4848C76C7ED803F86E7E491680D807FC8048B416C080486D15E0A4805CA36C17C06C
+5B6C90C75AD801FC1680C9FC4C13005FA24C5A4B5B4B5B4B13C04B5BDBFFFEC7FC91B512
+F816E016FCEEFF80DA000713E0030113F89238007FFE707E7013807013C018E07013F0A2
+18F8A27013FCA218FEA2EA03E0EA0FF8487E487E487EB57EA318FCA25E18F891C7FC6C17
+F0495C6C4816E001F04A13C06C484A1380D80FF84A13006CB44A5A6CD9F0075BC690B612
+F06D5D011F1580010302FCC7FCD9001F1380374F7ACD43>I<177C17FEA2160116031607
+160FA2161F163F167FA216FF5D5DA25D5DED1FBFED3F3F153E157C15FCEC01F815F0EC03
+E01407EC0FC01580EC1F005C147E147C5C1301495A495A5C495A131F49C7FC133E5B13FC
+485A5B485A1207485A485A90C8FC123E127E5ABA12C0A5C96C48C7FCAF020FB712C0A53A
+4F7CCE43>I<D80380150ED807E0157E01FEEC03FED9FFF0137F91B65A5F5F5F5F5F94C7
+FC5E5E16F016C093C8FC15F801E190C9FC01E0CAFCABEC0FFF027F13F001E3B512FE01E7
+6E7E9026FFF8077FDAC0017F49C713F8496E7E49143F4981496E7E6C481680C9FC18C082
+18E0A418F0A3EA0FE0487E487E487E487EA418E0A35B6C484A13C05B491680003EC85A00
+3F17006C6C4A5A6D5D6C6C4A5AD807F8495BD803FE01075B2701FFC03F5B6C90B65A013F
+4AC7FC6D14F8010314C09026007FF8C8FC344F79CD43>I<ED0FFF92B512E0020780021F
+14FC91397FFE03FE903A01FFF0007F4901C0EB3F804990C7121F4948EC7FC0494814FF49
+484913E049485B01FF5C485BA2485B5AA2486F13C04A6D1380486F1300177E94C7FC5AA2
+91CAFC5AA21508913801FFF8020713FFB54814C04A14F04AC66C7E023C6D7E4A6D7E4A6D
+7E7013804A15C0A24A15E07013F05C18F8A491C714FCA37EA67EA46C17F880A27E18F06C
+5D18E06C6D15C07E6E4913806C6D15006D6C495A6D6CEB7FFC6DB448485A6D90B55A0103
+15C0010092C7FC023F13FC020713C0364F7ACD43>I<121F7F7FEBFF8091B81280A45A19
+00606060A2606060485F0180C86CC7FC007EC95A4C5A007C4B5A5F4C5A160F4C5A484B5A
+4C5A94C8FC16FEC812014B5A5E4B5A150F4B5AA24B5AA24B5A15FFA24A90C9FCA25C5D14
+07A2140FA25D141FA2143FA4147F5DA314FFA55BAC6D5BA2EC3FC06E5A395279D043>I<
+913807FFC0027F13FC0103B67E010F15E090261FFC0113F8903A3FE0003FFCD97F80EB0F
+FE49C76C7E48488048486E1380000717C04980120F18E0177FA2121F7FA27F7F6E14FF02
+E015C014F802FE4913806C7FDBC00313009238F007FE6C02F85B9238FE1FF86C9138FFBF
+F06CEDFFE017806C4BC7FC6D806D81010F15E06D81010115FC010781011F81491680EBFF
+E748018115C048D9007F14E04848011F14F048487F48481303030014F8484880161F4848
+020713FC1601824848157F173FA2171FA2170FA218F8A27F007F17F06D151FA26C6CED3F
+E0001F17C06D157F6C6CEDFF806C6C6C010313006C01E0EB0FFE6C01FCEBFFFC6C6CB612
+F06D5D010F1580010102FCC7FCD9000F13C0364F7ACD43>I<91380FFF8091B512F80103
+14FE010F6E7E4901037F90267FF8007F4948EB3FF048496D7E484980486F7E4849808248
+17805A91C714C05A7013E0A218F0B5FCA318F8A618FCA46C5DA37EA25E6C7F6C5DA26C5D
+6C7F6C6D137B6C6D13F390387FF803011FB512E36D14C30103028313F89039007FFE03EC
+00401500A218F05EA3D801F816E0487E486C16C0487E486D491380A218005E5F4C5A91C7
+FC6C484A5A494A5A49495B6C48495BD803FC010F5B9027FF807FFEC7FC6C90B55A6C6C14
+F06D14C0010F49C8FC010013F0364F7ACD43>I<171F4D7E4D7EA24D7EA34C7FA24C7FA3
+4C7FA34C7FA24C7FA34C8083047F80167E8304FE804C7E03018116F8830303814C7E0307
+8116E083030F814C7E031F81168083033F8293C77E4B82157E8403FE824B800201835D84
+0203834B800207835D844AB87EA24A83A3DA3F80C88092C97E4A84A2027E8202FE844A82
+010185A24A820103854A82010785A24A82010F855C011F717FEBFFFCB600F8020FB712E0
+A55B547BD366>65 D<BA12C019FEF1FFC01AF01AFCD8000701F0C7000313FFDE007F7F73
+7F070F7F737F878587858785A287A84F5BA263616361634F5B4F5B077F90C7FC4E485A06
+0713F892B812E097C8FC861AF003F0C7000313FE9539003FFF80070F13E0737F07017F87
+737F747E1C807413C0A27413E0A31CF0A386A362A31CE0A2621CC0A250138097B5FC1C00
+4F5B19074F5B073F13F04EB55ABC128098C7FC1AF81AC007F8C8FC54527CD160>I<9326
+01FFFCEC01C0047FD9FFC013030307B600F81307033F03FE131F92B8EA803F0203DAE003
+EBC07F020F01FCC7383FF0FF023F01E0EC0FF94A01800203B5FC494848C9FC4901F88249
+49824949824949824949824990CA7E494883A2484983485B1B7F485B481A3FA24849181F
+A3485B1B0FA25AA298C7FC5CA2B5FCAE7EA280A2F307C07EA36C7FA21B0F6C6D1980A26C
+1A1F6C7F1C006C6D606C6D187EA26D6C606D6D4C5A6D6D16036D6D4C5A6D6D4C5A6D01FC
+4C5A6D6DEE7F806D6C6C6C4BC7FC6E01E0EC07FE020F01FEEC1FF80203903AFFE001FFF0
+020091B612C0033F93C8FC030715FCDB007F14E0040101FCC9FC525479D261>I<BA7E19
+FCF1FF801AF01AFCD8000701F0C7000F13FF060014C0071F7F070713F807017F737F747E
+747F747F86747F747F8886888688A2757EA31D8087A21DC0A51DE0A387A963A31DC0A51D
+80A2631D00A3515AA2646264505B6264505B505B5090C7FCF2FFFE4F5B07075B071F5B96
+B512C0060F91C8FCBB5A1AF01AC007FCC9FC19805B527CD167>I<BC1280A5D8000701F8
+C7000114C0F0001F19071901851A7F1A3F1A1FA2F20FE0A21A07A31A03A318F81BF01A01
+A497C7FC1701A317031707170F177F92B6FCA59238F8007F170F170717031701A317001B
+3EA31B7CA395C8FCA21BFCA21BF8A21A01A31A031BF01A071A0FA21A1F1A3FF27FE0F101
+FF1907191F0603B5FCBCFCA21BC0A34F517CD058>I<BB12FEA5D8000701F8C700077FF0
+007F191F190785858586861B80A21A1FA31A0FA41BC006F81307A497C7FCA31701A31703
+1707170F177F92B6FCA59238F8007F170F170717031701A31700A795C9FCB3B812F8A54A
+517CD055>I<932601FFFCEC01C0047FD9FFC013030307B600F81307033F03FE131F92B8
+EA803F0203DAE003EBC07F020F01FCC7383FF0FF023F01E0EC0FF94A01800203B5FC4948
+48C9FC4901F8824949824949824949824949824990CA7E494883A2484983485B1B7F485B
+481A3FA24849181FA3485B1B0FA25AA298C8FC5CA2B5FCAE6C057FB712E0A280A36C94C7
+003FEBC000A36C7FA36C7FA27E6C7FA26C7F6C7FA26D7E6D7F6D7F6D6D5E6D7F6D01FC93
+B5FC6D13FF6D6C6D5C6E01F0EC07FB020F01FEEC1FF10203903AFFF001FFE0020091B6EA
+C07F033FEE001F030703FC1307DB007F02E01301040149CAFC5B5479D26A>I<B8D8C003
+B8FCA5D8000701F8C9001FEBE000B3AE92BAFCA503F8C9121FB3B1B8D8C003B8FCA56052
+7CD169>I<B812C0A5D8000701F8C7FCB3B3B3B2B812C0A52A527CD132>I<B800C091B612
+F8A5D8000701F8C90003EBF8009738007F8051C7FC505AF203F8F20FF0505A505A505A50
+C8FCF101FCF107F84F5A4F5A4F5A4F5A07FEC9FCF003FC4E5A4E5A4E5A4E5A4E5ADD01FE
+CAFC4D5A4D5A4D5A4D7E173F4D7E4C487E4C7F5E4C804C804C80EEFF7F9226F9FE3F7FDB
+FBFC809226FFF81F7F4C7EDCC0077F0480804C7E4B6D804B6D804B8284727F727F868472
+7F727F8784728087737F85737F87737F85737F88857380747F888697B512FCB800C0013F
+ECFFFEA55F527CD169>75 D<B812F8A5D8000701F8CAFCB3B3A91A7CA41AFC1AF8A51901
+A31903A219071AF0190FA2191F193F197F19FF180360183F4DB5FCBB12E0A546527CD151
+>I<B600FC073FB512FE6F61A26F96B6FCA2D80007F5C00070EF01EFA202EF6DEF03CFA2
+02E76DEF078FA202E36DEF0F0FA202E16D171EA302E06D173CA26F6C1778A26F6C17F0A2
+6F6DED01E0A26F6DED03C0A36F6DED0780A26F6DED0F00A26F6D151EA26F6D5DA3706C5D
+A2706C5DA2706D495AA2706D495AA2706D495AA3706D49C7FCA2706D131EA2706D5BA271
+6C5BA3716C5BA271EB81E0A271EBC3C0A271EBE780A27101FFC8FCA3715BA2715BA2725A
+A2725AA2D93FFC6F5AB74DB712FEA2725AA2725A77527CD180>I<B600FC93B7FC8181A2
+82D800076E9239003FFC0070EE07E08282A28202EF7F02E77F02E380A202E18002E0806F
+7F6F7F6F7FA26F7F6F7F6F806F80A26F80707F707F707F707FA2707F7080708070808583
+717F717F717F717FA27114807114C07114E07213F07213F8A27213FC7213FE7213FF7214
+87A27214C77214E77313F77313FF85A285858585A28586868686A286868686A2D93FFC18
+7FB7173F1B1F1B0F1B07755A60527CD169>I<93380FFFC00303B6FC031F15E092B712FC
+0203D9FC0013FF020F01C0010F13C0023F90C7000313F0DA7FFC02007F494848ED7FFE49
+01E0ED1FFF49496F7F49496F7F4990C96C7F49854948707F4948707FA24849717E48864A
+83481B804A83481BC0A2481BE04A83A2481BF0A348497113F8A5B51AFCAF6C1BF86E5FA4
+6C1BF0A26E5F6C1BE0A36C6D4D13C0A26C6D4D1380A26C1B006C6D4D5A6E5E6C626D6C4C
+5B6D6D4B5B6D6D4B5B6D6D4B5B6D6D4B5B6D6D4B90C7FC6D6D4B5A6D01FF02035B023F01
+E0011F13F0020F01FC90B512C0020390B7C8FC020016FC031F15E0030392C9FCDB001F13
+E0565479D265>I<BAFC19F819FF1AE086D8000701F0C7001F13FC060113FF726C138073
+13C0070F13E01BF0857313F81BFCA27313FEA41BFFA81BFEA31BFC61A21BF84F13F04F13
+E0614F13C04F13004E485A061F5B92B812F01AC04FC7FC19E003F8CBFCB3AEB812C0A550
+527CD15C>I<B912F0F0FF8019F819FF1AC0D8000701F0C714F0060F7F060113FE727F73
+7F737F85737F87A2737FA387A863A2616363A24F5B4F5B4F90C8FC4F5A06035B060F13F0
+95B512C092B8C9FC19F819E019F89226F0000313FE9439007FFF80727F727F727F727F72
+7F8684A28684A787A71D1C75133EA38575137E73157C7513FC731401B86C6D9038F803F8
+07039038FE07F07390B512E0736C14C0080F1400CEEA7FFC5F537CD164>82
+D<91260FFF80130791B500F85B010702FF5B011FEDC03F49EDF07F9026FFFC006D5A4801
+E0EB0FFD4801800101B5FC4848C87E48488149150F001F824981123F4981007F82A28412
+FF84A27FA26D82A27F7F6D93C7FC14C06C13F014FF15F86CECFF8016FC6CEDFFC017F06C
+16FC6C16FF6C17C06C836C836D826D82010F821303010082021F16801400030F15C0ED00
+7F040714E01600173F050F13F08383A200788200F882A3187FA27EA219E07EA26CEFFFC0
+A27F6D4B13806D17006D5D01FC4B5A01FF4B5A02C04A5A02F8EC7FF0903B1FFFC003FFE0
+486C90B65AD8FC0393C7FC48C66C14FC48010F14F048D9007F90C8FC3C5479D24B>I<00
+3FBC1280A59126C0003F9038C0007F49C71607D87FF8060113C001E08449197F49193F90
+C8171FA2007E1A0FA3007C1A07A500FC1BE0481A03A6C994C7FCB3B3AC91B912F0A55351
+7BD05E>I<B800C00103B612FCA5D8000701F8CAEBF000F31F80B3B3B11B3FA26D97C7FC
+81637F1B7E6D6D17FE505A6E7E505A6E6D15076E4D5A6E6D4B5A6E6D4B5A6E01F84B5A6E
+6DDA03FFC8FC6E6CB46CEB0FFE6F9039F001FFF8030F90B65A030316C0DB007F92C9FC04
+0F14F8DC007F13805E537CD167>I<B700FE031FB512FEA5D8001F01F0CA383FFE00F307
+F06D626F170F6D62811B1F6D6D601B3F6D97C7FC6F5F6D197E821BFE6E6D5E1A016E6D5E
+1A036E60701507A26E6D5E1A0F6E6D5E1A1F6E6070153FA26E6D93C8FC626E6E147E1AFE
+6F5E711301A26F6D5C19036F6D5C19076F5E71130FA26F6D5C191F6F6D5C193F6F93C9FC
+715BA26FEC807E19FE706D5A18C1705C18E3705C18F318F770EBFFE0A2705CA2705CA370
+91CAFCA2705BA2715AA3715AA2715AA2715A715A5F537DD166>I<B700FC017FB600FE91
+B612F0A5D8003F01C0C8001F01E0C9EBF8006F71EE0FC06D7161876F1C1F6D7196C7FC6F
+8373606D1E3E6F836D7160876F1CFC6D666F4B801F016D66704A806E525A88704A17076E
+059F5F70021F80080F160F6E6570023F806EDC3E074CC8FC8870027E5F6EDC7C03163E70
+02FC804F6C167E6E1C7C700101814F6C16FC6E745B70010317016E4C6D5D060716C00580
+496D14036F63DDC00F16E04F6D14076F07F05BDDE01F170F6F92C76C5D1DF8DDF03E6E14
+1F6F98C9FCDDF87E16FC067C6E5C6FF1FE3EDDFCFC177E6F4A6E147C1DFFDDFFF06E14FC
+6F62A24E816F62A270496F5BA24E817061A295C97E7061A270487090CAFCA37048705AA2
+4D1601040360A27048705A84537DD18B>I<EC7FFF0107B512F0013F14FE90B77E48D9E0
+0F7F2703FE000113F0486C6D7F6EEB3FFC48826E131F83707FA36C496D7FA26C90C7FC6C
+5AC9FCA6037FB5FC020FB6FC91B7FC01071487013FEBF0074913803901FFFC004813F048
+5B485B485B4890C7FC5A5BA2485AA45EA26D5C007F151D163D6C6C02797F6C6D01F113F8
+6C9026C003E1EBFFE06C9026F81FC014F06C90B5487EC6ED001F011F01FC010713E00101
+01E090C8FC3C387CB641>97 D<EB3FF0B5FCA51203C6FCB3A4923801FFE0030F13FE033F
+EBFFC092B612F002F301017F913AF7F8003FFEDAFFE0EB0FFF03806D7F92C76C7F4A6E7F
+4A824A6E7FA2727EA285A28584A31A80AC1A00A44E5AA36118FF616E4A5BA26E4A5B6E4A
+5B6F495BDACFC04990C7FCDA87F0EB7FFC913A03FE03FFF849C6B612E0496D148049011F
+01FCC8FC90C7000313C041547BD24B>I<913801FFF8021FEBFF8091B612F0010315FC01
+0F9038C00FFE903A1FFE0001FFD97FFC491380D9FFF05B4817C048495B5C5A485BA2486F
+138091C7FC486F1300705A4892C8FC5BA312FFAD127F7FA27EA2EF03E06C7F17076C6D15
+C07E6E140F6CEE1F806C6DEC3F006C6D147ED97FFE5C6D6CEB03F8010F9038E01FF00103
+90B55A01001580023F49C7FC020113E033387CB63C>I<4DB47E0407B5FCA5EE001F1707
+B3A4913801FFE0021F13FC91B6FC010315C7010F9038E03FE74990380007F7D97FFC0101
+B5FC49487F4849143F484980485B83485B5A91C8FC5AA3485AA412FFAC127FA36C7EA37E
+A26C7F5F6C6D5C7E6C6D5C6C6D49B5FC6D6C4914E0D93FFED90FEFEBFF80903A0FFFC07F
+CF6D90B5128F0101ECFE0FD9003F13F8020301C049C7FC41547CD24B>I<913803FFC002
+3F13FC49B6FC010715C04901817F903A3FFC007FF849486D7E49486D7E4849130F48496D
+7E48178048497F18C0488191C7FC4817E0A248815B18F0A212FFA490B8FCA318E049CAFC
+A6127FA27F7EA218E06CEE01F06E14037E6C6DEC07E0A26C6DEC0FC06C6D141F6C6DEC3F
+806D6CECFF00D91FFEEB03FE903A0FFFC03FF8010390B55A010015C0021F49C7FC020113
+F034387CB63D>I<ED3FFC0203B5FC020F14C0023F14E09139FFF81FF0499038C03FF849
+EB807F49903800FFFC495A495AA2495AA2EE7FF8495AEE3FF0EE0FC093C7FCAEB712E0A5
+26007FF8C8FCB3B3A7007FB512FEA52E547CD329>I<DA3FFF14FF0103B5D8F00713C001
+0FDAFC1F13E0013FECFF7F90267FFC0F9038FF9FF09026FFE001EBF83F48496C13E04849
+90387FF01F4890C7D83FF813E0489338FC0FC0F0078048486E6CC7FCA2003F82A9001F5E
+A26C6C4A5AA26C5E6C6D495A6C6D495A6C6D485BDAFC0F5B4890B6C8FCD803EF14FC01C3
+14F02607C03F90C9FC91CBFCA2120FA37FA213F813FE90B7FC6C16F817FF18C06C836C83
+6C836D828448B9FC12074848C700031480D81FF8EC003F4848150748486F13C083485A83
+A56D5D007F18806D5D003F18006C6C4B5AD80FFEED1FFC6C6C6CEC7FF86C01E049485A6C
+01FE011F5B6C6CB71280010F03FCC7FC010115E0D9000F01FCC8FC3C4F7CB543>I<EB3F
+F0B5FCA51203C6FCB3A4EE1FFC93B512C0030314F0030F8092391FE07FFC92393F001FFE
+037C8003F07FDAF1E081ECF3C0DAF7807F8502FFC7FC5CA25CA45CB3ACB6D8F807B612C0
+A542537BD24B>I<137F497E000313E0487FA2487FA76C5BA26C5BC613806DC7FC90C8FC
+ADEB3FF0B5FCA512017EB3B3A6B612E0A51B547BD325>I<EB3FF0B5FCA51203C6FCB3A5
+4CB512F8A59339003FFE00EF1FF0EF3FC04D5A4DC7FCEE03FEEE07F84C5A4C5AEE7FC04C
+C8FC4B5A4B5AED0FF8ED1FE04B7E4B7EECF1FF02F37F02F77F91B6FC83159F030F7F02FE
+80DAF8077F4A7E6F7F6F7F83707E82707F84707F707F82707F84707F177F717E4D13C0B6
+D8F003B6FCA540537CD247>107 D<EB3FF0B5FCA512017EB3B3B3B1B612F0A51C537BD2
+25>I<D93FF0D91FFCEDFFE0B591B500C0010713FE030302F0011F6D7E030F6E017F8092
+271FE07FFCD9FF037F922A3F001FFE01F8007F0003027C9126FF03E080C602F06DD90780
+137FDAF1E0038FC77FDAF3C0159EDAF7806D01BC143F07FC8102FFC75C4A5EA24A5EA44A
+5EB3ACB6D8F807B6D8C03FB512FEA567367BB570>I<D93FF0EB1FFCB591B512C0030314
+F0030F8092391FE07FFC92393F001FFE0003027C80C602F07FDAF1E081ECF3C0DAF7807F
+8502FFC7FC5CA25CA45CB3ACB6D8F807B612C0A542367BB54B>I<913801FFE0021F13FE
+91B612C0010315F0010F9038807FFC903A1FFC000FFED97FF86D6C7E49486D7F48496D7F
+48496D7F4A147F48834890C86C7EA24883A248486F7EA3007F1880A400FF18C0AC007F18
+80A3003F18006D5DA26C5FA26C5F6E147F6C5F6C6D4A5A6C6D495B6C6D495B6D6C495BD9
+3FFE011F90C7FC903A0FFF807FFC6D90B55A010015C0023F91C8FC020113E03A387CB643
+>I<903A3FF001FFE0B5010F13FE033FEBFFC092B612F002F301017F913AF7F8007FFE00
+03D9FFE0EB1FFFC602806D7F92C76C7F4A824A6E7F4A6E7FA2717FA285187F85A4721380
+AC1A0060A36118FFA2615F616E4A5BA26E4A5B6E4A5B6F495B6F4990C7FC03F0EBFFFC91
+26FBFE075B02F8B612E06F1480031F01FCC8FC030313C092CBFCB1B612F8A5414D7BB54B
+>I<90397FE003FEB590380FFF80033F13E04B13F09238FE1FF89139E1F83FFC0003D9E3
+E013FEC6ECC07FECE78014EF150014EE02FEEB3FFC5CEE1FF8EE0FF04A90C7FCA55CB3AA
+B612FCA52F367CB537>114 D<903903FFF00F013FEBFE1F90B7FC120348EB003FD80FF8
+1307D81FE0130148487F4980127F90C87EA24881A27FA27F01F091C7FC13FCEBFFC06C13
+FF15F86C14FF16C06C15F06C816C816C81C681013F1580010F15C01300020714E0EC003F
+030713F015010078EC007F00F8153F161F7E160FA27E17E07E6D141F17C07F6DEC3F8001
+F8EC7F0001FEEB01FE9039FFC00FFC6DB55AD8FC1F14E0D8F807148048C601F8C7FC2C38
+7CB635>I<143EA6147EA414FEA21301A313031307A2130F131F133F13FF5A000F90B6FC
+B8FCA426003FFEC8FCB3A9EE07C0AB011FEC0F8080A26DEC1F0015806DEBC03E6DEBF0FC
+6DEBFFF86D6C5B021F5B020313802A4D7ECB34>I<D93FF8913801FFC0B50207B5FCA500
+03ED001FC61607B3AE5FA35FA2017F5D173B177B6D6C14F3DC01E313F06D6CD907C3EBFF
+C0903A0FFFC03F836D90B51203010114FE6D6C13F8020701E091C7FC42377BB54B>I<B6
+00F00107B5FCA5000101F8C8EA7FE06C6DED3F00A2017F163E6E157E013F167C6E15FC6D
+5E6F13016D5E8117036D5E6F13076D5E6F130F6D5E6F131F6D93C7FC815F6E6C133E177E
+023F147C6F13FC6E5C16816E5C16C3A26EEBE3E016E76E5C16FF6E5CA26E91C8FCA26F5A
+A36F5AA26F5AA26F5AA26F5A6F5A40367DB447>I<B6D8E07FB5D8C003B512C0A5000101
+F0C701F0C7381FF8006E027FED07E06C715DA26E023F150F017F705DA26E181F013F4B6C
+92C7FC6E606D70143E94B5FC6F177E6D4A6E137C03C001F315FC6D715B160303E001E114
+016D020702E05B03F013C06D71485A160F03F8D9807F13076D05F85B93381F003F03FC16
+0F027F4902FC5BDBFE3E011F131F023F04FE90C8FC167EDBFF7C010F5B6E01FCECFF3E4C
+6D137E6E5FA24C7F6E5F4C7F6E5FA24C7F6E5F4C147FA26E5F93C8123F6F5EA2033E6FC9
+FC5A367DB461>I<007FB500F090387FFFFEA5C66C48C7000F90C7FC6D6CEC07F86D6D5C
+6D6D495A6D4B5A6F495A6D6D91C8FC6D6D137E6D6D5B91387FFE014C5A6E6C485A6EEB8F
+E06EEBCFC06EEBFF806E91C9FCA26E5B6E5B6F7E6F7EA26F7F834B7F4B7F92B5FCDA01FD
+7F03F87F4A486C7E4A486C7E020F7FDA1FC0804A486C7F4A486C7F02FE6D7F4A6D7F495A
+49486D7F01076F7E49486E7E49486E7FEBFFF0B500FE49B612C0A542357EB447>I<B600
+F00107B5FCA5C601F8C8EA7FE06EED3F00A26D6C153E187E013F167C6E15FC6D5E6F1301
+6D5E6F13036D5E8117076D6D5C170F6D6D5C171F6D93C7FC6F5B027F143E6F137E023F14
+7C6F13FCA26E6D5A16816EEBC1F016C36E5C16E76E5C16FF6E5CA26E91C8FCA36F5AA26F
+5AA26F5AA26F5AA26F5AA35E150F5E151F93C9FC5DD81FC0133E486C137E486C137C486C
+13FC5D14015D14034A5A6C48485A49485A263FC07FCAFCEB81FE6CB45A6C13F000035BC6
+90CBFC404D7DB447>I<001FB8FC1880A3912680007F130001FCC7B5FC01F0495B495D49
+495B495B4B5B48C75C5D4B5B5F003E4A90C7FC92B5FC4A5B5E4A5B5CC7485B5E4A5B5C4A
+5B93C8FC91B5FC495B5D4949EB0F805B495B5D495B49151F4949140092C7FC495A485E48
+5B5C485E485B4A5C48495B4815074849495A91C712FFB8FCA37E31357CB43C>I
+E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fg cmbx12 20.74 23
+/Fg 23 121 df<EE3FFF0307B512F8033F14FF4AB712E0020716F8021F16FE4AD9F8077F
+91B5D8C00014C04991C7003F7F4901FC020F7F49496E7F49496E7F49496E7F49496E7F4B
+81498590B5C96C7FA24849707FA24886A248864A824886A34886A448864A82A4481B80A8
+B51AC0B3AA6C1B80A86C1B006E5EA46C62A36C62A36C6D4C5BA36C62A26C6D4C5BA26C6E
+4B5B6D616F92B5FC6D96C7FC6D6D4A5B6D6D4A5B6D6D4A5B6D6D4A5B6D01FF023F5B6D02
+C090B55A6ED9F8075C021F90B648C8FC020716F8020116E06E6C1580030702F8C9FCDB00
+3F90CAFC527379F061>48 D<EE01F0EE07F8160F163F167FED01FF150F153F4AB5FC143F
+010FB6FCB8FCA54A7E14C0EBF000C8FCB3B3B3B3AE007FBA12F0A8447171F061>I<9238
+0FFFE04AB67E020F15F0027F15FE49B87E4917E0010F17F8013F8349D9C01F14FF9027FF
+FC0001814801E06D6C80480180021F804890C86C8048486F8048486F8001FF6F804801C0
+6E8002F081486D18806E816E18C0B5821BE06E81A37214F0A56C5BA36C5B6C5B6C5B0003
+13C0C690C9FC90CA15E060A34E14C0A21B80601B0060626295B55A5F624D5C624D5C4D91
+C7FC614D5B4D13F04D5B6194B55A4C49C8FC4C5B4C5B4C13E04C5B604C90C9FCEE7FFC4C
+5A4B5B4B5B4B0180EC0FF04B90C8FC4B5A4B5A4B48ED1FE0EDFFE04A5B4A5B4A90C9FC4A
+48163F4A5ADA3FF017C05D4A48167F4A5A4990CA12FFD903FC160749BAFC5B4919805B5B
+90BBFC5A5A5A5A481A005A5ABCFCA462A44C7176F061>I<923801FFFE033FEBFFF84AB7
+FC020F16E0023F16F84A16FE49B97E49DA003F80010F01F0010714F04901800101804948
+C880D97FF86F7F02E081496C834801FC6F148014FF486E6E14C08181481AE081A96C5C1B
+C06C4A5C6C5C6D90C815806D5AD90FF85D90CA150062606295B55A4D5C624D5C4D5C4D91
+C7FC4D13FC4D5B4CB512E0047F1480037FB548C8FC92B612F818C018F8F0FF806F15F092
+C7003F13FC050713FF050114C071807213F8727F727F867214801BC07214E01BF0A27214
+F81BFCA37214FEA31BFFEBFF80000313E0487F001F13FC487FA2487FA2B67EA31BFEA360
+1BFCA292C8FC6C1AF84A5D4A18F06C494B14E05C6C01C04B14C06C90C915804E14006C6D
+4B5B6C01F092B55A6C01FC4A5C27007FFFC001075C6D01FE013F14C0010F90B85A6D4DC7
+FC010117F8D9003F16E0020F93C8FC020015F0030749C9FC507378F061>I<F10FF04F7E
+193FA2197F19FF60A260606060A2606095B5FCA25F5F5FA25F5F5F5F18BFEFFF3F5EEE03
+FE17FCEE07F8160FEE1FF0EE3FE017C0167FEEFF804B13005E4B5A15074B5A4B5A5E153F
+4B5A4B5A93C7FC4A5A14034A5A5D4A5A141F4A5A4A5A5D4AC8FC5B495A5C495A130F495A
+495A5C137F495A4890C9FC5B485A1207485A485A5B123F485A485A90BC12FCA8CB02F8C7
+FCB3A20307B912FCA856727BF161>I<0170187001FEEF01F86D6C160F02F8167FDAFF80
+EC07FF03FE49B5FC92B85A6262A26297C7FC61616119E061614EC8FC18F86018C095C9FC
+17F817C0020701F8CAFC91CDFCB0923801FFFC031FEBFFE092B612FC020315FF020F16C0
+4A16F0027FD9003F7FDAFFF0010F13FE038001037F4AC76C8002F86E804A6F7F4A6F7F4A
+834A6F7F91C980137E017C707F90CAFC1B80A21BC0A2841BE0A51BF0A313FE3803FF8000
+0F7F4813F0487F5A80B5FCA41BE0A44E14C05C7E4A18805C4A5D6C90C9150001E0606C6C
+5E6D606C6C4C5B7F000794B55A6C6C6C4A5C6C6D4A5C6E4A5C26007FF8021F49C7FC6DB4
+027F5B6DD9F007B55A6D90B712E0010317806D4CC8FC6D6C15F8021F15C002034AC9FCDA
+003F13804C7376F061>I<94381FFF800403B512F8043F14FE4BB77E030782031F16F003
+7F8292B5D8FC017F02039139C0001FFE4A49C7EA07FF021F01F8804A496E13804A01C014
+0F91B548023F13C04991C85A494992B5FC49494A14E0495B495E5D5B495BA290B55A5A5D
+487114C0A24891C91480731300735A48F00FF896C8FC485BA45AA44849903803FFE0041F
+13FE047FEBFFC04BB612F84B81030F15FFB590261FF8038092273FE0007F13E00480011F
+7F4BC76C7F03FE6E7F4B6E7FDAFDF86E7FDAFFF017804B6E14C01BE05D7313F05D1BF8A2
+92C914FC85A21BFE5CA31BFFA26C5BA87EA4807EA21BFE7EA37E1BFC6E5E6C1AF8A27E6F
+17F06C95B512E06D7F1BC06D6D4A14806D4C1400816D6D4A5B6D6D4A5B6D01FF4A13F001
+006E017F5B6ED9F007B55A6E90B7C7FC020F5E020316F86E16E0DA003F1580030702FCC8
+FCDB007F1380507378F061>I<EA03FCA2487E7F14C0ECFFF092BA12C0A45AA31C801C00
+63A2486263636363A26398C7FC48616249CAEA0FF801F0171F494D5A4F5A49604F5A007F
+4D90C8FC60494C5A4E5A614E5A4E5A48CA127F4E5A4D5B96C9FCCA485A4D5A170F4D5A60
+173F4D5A6017FF4C5BA25E4C90CAFCA24C5A161FA24C5AA2167FA24C5AA25DA24B5BA25D
+A25DA25F5DA25DA35DA392B5FCA25FA25CA45CA75CAD6E5CA26E91CBFCA26E5BED3FF8ED
+0FE0527775F461>I<93B57E031F14FC92B77E020316F0020F16FC023F16FF4A8349B5D8
+800314E04901F8C7003F7F4901C0020F7F4990C800037FD91FFC6F7F49486F6C7E137F4A
+7013804948827313C05A4A821BE05AA285487FA38080806E5E8003C017C08103F85D03FE
+17806F6C5C6C6F160004F05C04FC4A5A6C6F5D706C13FFDDE0015B6CDCF8035BDDFC0F13
+C06DDBFF1F5B6D93B5C7FC19FC6D17F06D5F6D17806D17E06D836D6C16FC6E16FF020F83
+6E17E06E83020F83023F8391B97E4984010701F0178049D9C07F16C0013FD9801F16E049
+EB00074948010116F048497F4849023F15F84849140F4A6E15FC48160148496E6C14FE4A
+151F488391C9120348050014FF193F49838500FF84854983A28586A3861BFEA27FA2007F
+1AFC7F1A7F1BF86C7FF2FFF06C7F6E4C13E06C6D4C13C06C6D5E6E4C13806C6D4C13006C
+6D6CED7FFE6C02E04A485A013F01FC020F13F06D9026FFC001B55A010791B712806D95C7
+FC010017FC021F16F002071680DA007F02FCC8FC030191C9FC507378F061>I<93B5FC03
+1F14F092B612FE02076F7E021F16E04A16F891B87E49DAF00713FF0107DA0001804901FC
+6D6C7F49496E7F49496E7F49496E7F90B5486E7F484A8048854891C86C7FA2487114805C
+481AC0A2487213E0A2484918F0A31BF8A2B5FCA27313FCA51BFEA71BFF61A27EA396B6FC
+7EA2806C5FA27E606C7F607E6C6E5C6CEF1FBF6D6DEC3F3F6D6D147F6D6D14FE6D6DEB01
+FC6D01FE130701019039FFC01FF86D91B500F014FE023F15C06E15800203ECFE00DA007F
+13F8030713C092C9FC4F13FCA41BF8A31BF0D91FF093B5FCEB7FFC496C18E0487F486E17
+C06048801B804E1400A26260624E5B4B5C626C91C8485B4A4B5B4A92B55A6C01F04A91C7
+FC02804A5B6C01E0020F5B6D6C023F13F002FE91B55A90273FFFE00F5C6D90B7C8FC0107
+16FC6D16F0010016C0023F92C9FC020714F09126007FFECAFC507378F061>I<F103F84F
+7E4F7EA24F7EA34F7FA24F7FA396B57EA24E80A34E80A24E80A34E80A24E80A34E81A24E
+81A219BFDEFF9F80191F4D6D80A218FE05036D8018FC05076D80A218F8050F6D8018F005
+1F6D80A260053F6E8060057F6E80A26005FF6E8095C7FC4C6F80A25F04036F805F04076F
+80A25F040F6F805F041F6F80A25F043F70805F047F7080A25F04FF708094C9FC4B7180A2
+5E030371805E4BBB7EA34B86A24B86A3DB3FE0CA6C805E037F7280A25E03FF7280A24A90
+CB6C80A25D02037380A24A487280A25D020F7380A24B84021F885D023F7480A24B85027F
+895D902607FFFC7380B86C031FB912E0A8837979F892>65 D<BDFC1CFEF4FFC01DF81DFF
+1EC01EF08AC7003F49C9000F14FE090180756C800A1F807680768076807680A27680A277
+7FA2208089A320C0A289A565A32080A3531400A29AB55AA2525C6764525C525C525C525C
+5249C7FC51B55A090714F0093F14C00807B6C8FC93BA12F81DC0651DFCF5FF801EF04CCA
+14FC0A3F13FF0A0F800A0314E076807614FC777F777F2080897714C020E0A27714F0A220
+F88920FCA47714FEA96520FCA45314F8A26520F06520E05314C0659AB61280521500525C
+1C0F5214F899B65A09075DC05A9CC7FC1EFC1EF01EC053C8FC1DE00AF8C9FC777679F58A
+>I<96267FFFE01670063FB6ED01F80503B700F01403053F04FC14074CB96C130F040706
+E0131F043F72133F93BA00FC137F0303DC00076D13FF030F03C09039003FFF814B02FCC8
+000713C3037F02E0030113F792B600806F6CB5FC02034ACA121F4A02F8834A02E0834A4A
+1701027F4A8391B548CC7E494A85495C4C854988494A85494A85495C8A4991CDFC90B548
+86A2484A1B7FA2481E3F5D481E1F5D5A1F0FA2485CA3481E075DA2F703F0489BC7FCA45D
+A2B6FCB27EA281A47EA2F703F06FF307F87EA36C80A21F0F7E6F1CF07E6F1B1F7E20E06C
+6E1B3F816DF57FC06D80F7FF806D806D6E4F13006D6E616D525A826D6E4F5A6D6E4F5A6E
+6D6C4E5A021F6EF0FFE06E6E4D5B6E02F84D5B6E02FE050F90C7FC02006E6CEE3FFE6F02
+F0EEFFFC031F02FE03035B6FDAFFC0021F13E0030303FF0103B55A030093B7C8FC043F18
+FC040718F0040118C0DC003F94C9FC050316F8DD003F1580DE007F01F0CAFC757A75F78C
+>I<92383FFFF80207B612E0027F15FC49B87E010717E0011F83499026F0007F13FC4948
+C7000F7F90B502036D7E486E6D806F6D80727F486E6E7F8486727FA28684A26C5C72806C
+5C6D90C8FC6D5AEB0FF8EB03E090CAFCA70507B6FC041FB7FC0303B8FC157F0203B9FC02
+1FECFE0391B612800103ECF800010F14C04991C7FC017F13FC90B512F04814C0485C4891
+C8FC485B5A485B5C5A5CA2B5FC5CA360A36E5DA26C5F6E5D187E6C6D846E4A48806C6D4A
+4814FC6C6ED90FF0ECFFFC6C02E090263FE07F14FE00019139FC03FFC06C91B6487E013F
+4B487E010F4B1307010303F01301D9003F0280D9003F13FC020101F8CBFC57507ACE5E>
+97 D<97380FFFE00607B6FCA8F00003190086B3AD93383FFF800307B512F8033F14FF4A
+B712C0020716F0021F16FC027F9039FE007FFE91B500F0EB0FFF01030280010190B5FC49
+49C87E49498149498149498149498190B548814884484A8192CAFC5AA2485BA25A5C5AA3
+5A5CA4B5FCAF7EA4807EA37EA2807EA26C7F616C6E5D6C606C80616D6D5D6D6D5D6D6D92
+B67E6D6D4A15FC010301FF0207EDFFFE6D02C0EB3FFE6D6C9039FC01FFF86E90B65A020F
+16C002031600DA007F14FC030F14E09226007FFEC749C7FC5F797AF76C>100
+D<93387FFF80030FB512FC037FECFF804AB712E0020716F8021F16FE027FD9F8077F49B5
+D8C000804991C7003F13E04901FC020F7F49496E7F49498049496E7F49496E7F90B55A48
+727E92C914804884485B1BC048841BE0485BA27313F05AA25C5AA21BF885A2B5FCA391BA
+FCA41BF002F8CCFCA67EA3807EA47E806CF103F0F207F86C7F1A0F6C6E17F06C191F6F17
+E06C6E163F6D6DEE7FC06D6D16FF6D6D4B13806D6D4B13006D6D6CEC0FFE6D02E0EC3FFC
+6D02F8ECFFF86D9126FFC00F5B023F91B65A020F178002034CC7FC020016F8031F15E003
+0392C8FCDB000F13E04D507BCE58>I<903801FFFCB6FCA8C67E131F7FB3AD95380FFFE0
+95B512FE05036E7E050F15E0053F15F84D81932701FFF01F7F4CD900077FDC07FC6D80DC
+0FF06D80DC1FC07F4C48824CC8FC047E6F7F5EEDFDF85E03FF707F5EA25EA25EA293C9FC
+A45DB3B3A6B8D8E003B81280A8617879F76C>104 D<EB01FCEB07FF011F13C0497F497F
+90B57EA24880A24880A76C5CA26C5CA26D5B6D5B6D5B010790C8FCEB01FC90CAFCB29038
+01FFFC007FB5FCA8C67E131F7FB3B3B3A5B81280A8297979F835>I<902601FFF891380F
+FFE0B692B512FE05036E7E050F15E0053F15F84D81932701FFF01F7F4CD900077FDC07FC
+6D80C66CDA0FF06D80011FDA1FC07F6D4A48824CC8FC047E6F7F5EEDF9F85E03FB707F5E
+15FF5EA25EA293C9FCA45DB3B3A6B8D8E003B81280A8614E79CD6C>110
+D<902601FFFCEC7FFEB6020FB512F0057F14FE4CB712C0040716F0041F82047F16FE93B5
+C66C7F92B500F0010F14C0C66C0380010380011F4AC76C806D4A6E8004F06F7F4C6F7F4C
+6F7F4C8193C915804B7014C0861DE0A27414F0A27414F8A47513FCA57513FEAF5113FCA5
+98B512F8A31DF0621DE0621DC0621D806F5E701800704B5B505B704B5B7092B55A04FC4A
+5C704A5C706C010F5C05E0013F49C7FC9227FE7FFC01B55A70B712F0040F16C0040393C8
+FC040015F8053F14C0050301F0C9FC94CCFCB3A6B812E0A85F6F7ACD6C>112
+D<902601FFF8EB07FEB691383FFFC094B512F00403804C14FE4C8093261FFC3F13809326
+3FE07F13C0DC7F80B5FCC66C5D011FDAFE0114E06DEBF9FC16F815FB16F016E015FF16C0
+7114C05E72138095381FFE0093C76C5AF001E095C8FCA25DA65DB3B3A2B812F8A8434E7A
+CD4F>114 D<15FFA75CA55CA45CA25CA25CA25CA25C91B5FCA25B5B5B131F5B90B9FC12
+0FBAFCA6D8000791C9FCB3B3A3F01FE0AE183F7014C07F187F7014806D16FF826D4B1300
+6E6D485AEEFE0F6E90B55A020F5D6E5D020115C06E6C5C031F49C7FC030113F03B6E7CEC
+4B>116 D<007FB7023FB612F0A8D8000302C0020191C7FC6D6E9138007FF0705E6D4E5A
+6E6D4A5B6E6D4A90C8FC6E6D5C704A5A6E4C5A6E6E5C6E6E495A6E6E495A7113FF6E6E48
+5B6F4A5B6F6D4890C9FC6F01FE5B71485A6FEC9FF86F14BF6FECFFF06F5D616F5D7091CA
+FC705B828470808270807080854C805E4C80854C804C81EE7FE7DCFFE3804B01C1804B01
+80804D804B487F4B486D7F031F6E7F4B486D7F4B48824B487F4C6D804A496D804A90C880
+4A844A48814A486F7F4A486F7F4B6F7F4A48844A486F80010F01F881B76C91B712FEA85F
+4D7DCC66>120 D E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fh cmsl10 10.95 39
+/Fh 39 91 df<1530157015E0EC03C0EC0780EC0F00141E5C147C5C5C495A1303495A5C
+130F49C7FCA2133E137E137C13FC5B1201A2485AA25B1207A2485AA3485AA448C8FCA45A
+127EA512FE5AA95AA87EA2127CA5123C123EA2121EA2121F7EA26C7EA26C7EA26C7E1200
+13707FA213181C5A74C323>40 D<497E806D7E1470147880A280A280A2EC0780A215C014
+03A215E0A3EC01F0A615F8AF140315F0A5140715E0A4140F15C0A3141F1580A3EC3F00A2
+143E147EA2147C14FC5C13015C13035C13075C495AA249C7FC131E133E5B13785B485A48
+5A12075B000EC8FC5A5A12F05A1D5A7FC323>I<007FB5FCA2B512FEA418067C961E>45
+D<121EEA3F80EA7FC012FFA41380EA7F00123C0A0A788919>I<1703EF0780170FA2EF1F
+00A2173EA25FA25FA24C5AA24C5AA24C5AA24C5AA24CC7FCA2163E167E167C5EA24B5AA2
+4B5AA24B5AA24B5AA24BC8FCA2153EA25DA25DA24A5AA24A5AA24A5AA24A5AA24AC9FCA2
+143EA25CA25CA2495AA2495AA2495AA2495A131F91CAFC133EA25BA25BA2485AA2485AA2
+485AA2485AA248CBFCA2123EA25AA25AA21270315B7FC32D>I<EC07F8EC3FFF9138FC0F
+C0903903F003E0903907C001F0D90F8013F849C7FC013E14FC017E147C017C147E13FC48
+5AA20003157F5B1207A2120F5BA2121F16FF5BA2123FA44848EB01FEA648C7EA03FCA5ED
+07F8A25A16F0A2150F16E0A3ED1FC0A21680007E143F1600157E123E003F5C4A5AD81F80
+5B000FEB07E06C6C485A2603F03FC7FC3800FFFCEB1FE0283F79BC2D>I<157015F01401
+1407143F903803FFE0137FEBFFCFEBF80F1300141F15C0A5143F1580A5147F1500A55C5C
+A513015CA513035CA513075CA5130F5CA3131F497EB612F8A31D3D78BC2D>I<EC01FE91
+380FFFE0023F13F89138FC07FC903901E001FE903907C000FF49C7EA7F80011E15C0163F
+4915E05B0170141F13FF80A35A163FA26C90C7FC137E0118EC7FC090C8FCEEFF80A24B13
+00A24B5A5E4B5A4B5A4B5A5E4B5A4BC7FC15FEEC01F84A5A4A5A4A5A4AC8FC143E5C5CEB
+01E04948130E49485B49C7FC131E495C13705B48485C484814F0000FB6FC5A485D5AB7FC
+5EA22B3D7CBC2D>I<EC07FC91383FFF809138F80FE0903903C007F09039078003FC9038
+0F0001011C14FE013C14FF137F1480EBFFC0A31480A291380003FE137E90C7FCED07FC16
+F8150F16F0ED1FE016C0ED3F80ED7E005DEC07F0903803FF8015F090380001FC6E7EED7F
+80ED3FC0A2ED1FE016F0A316F8A4120EEA3F80486C133F16F012FFA216E0157F5B48C7EA
+FFC000F01580007049130012786C495A003EEB07F86C495A390FE03FE00003B51280C649
+C7FCEB1FE0283F7ABC2D>I<161C163C167CA216FCED01F815031507150FA2151DED3BF0
+157315E315C31401EC038391380707E0140E141CA2143814709138E00FC0EB01C0148013
+03EB0700130E49EB1F805B133013705B485A4848EB3F0090C7FC5A120E5A5A48147E1260
+B8FCA3C73801FE00A25DA41403A25DA314074A7E0107B512F8A3283E7BBD2D>I<010614
+03D90780131F90390FF801FE91B512FC16F816F016E0168049EBFE0015F890381C7FC091
+C8FCA3133C1338A513781370A2EC1FE0ECFFF8903873E03E9038FF001F01FCEB0F804914
+C049EB07E04914F049130390C7FC16F8A61507A21206EA3F80487EA2150F00FF15F0A249
+14E090C7121F00FC15C000F0143F00701580ED7F0012786C14FE4A5A6C495A390F800FE0
+3907E03FC06CB5C7FCC613FCEB1FE0283F7ABC2D>I<ED7F80913803FFE091380FC0F091
+383E003802FC131C495A494813FE903807E003EB0FC090381F8007133FD97F0013FC01FE
+1303ED01F0484890C7FC1203A2485AA2120F5BA2001FEB3F809038E0FFE0393FE3C0F890
+38E7007C01EE7F01FC133F4848EB1F80A24914C05B16E0A2485AA216F05BA2ED3FE0A290
+C7FCA4157F16C0A316804814FF007E1500007F5C14016C5C4A5A6C6C485A4A5A6C6C485A
+2607E07FC7FC3803FFFEC613F8EB3FC0273F78BC2D>I<EA0380120713E090B712805AA2
+17005E485D5E001EC85A484A5A00385D150300784A5A00704AC7FC151E5D485CC8127015
+F04A5A4A5A4A5A4AC8FC140E141E5C147C14785C1301495AA213075C130F495AA2133F91
+C9FC5BA25B5B1201A312035BA21207A3485AA5121F5BA26C5AEA0780294074BD2D>I<EC
+03FC91381FFF8091387C07E0903901F001F0903903C000F84948137C49C7123E131E013E
+141F133C137C137813F8A3163F486C143E167E6D147C6C6C14FC6E13F89138C001F09138
+F003E090397FF807C09138FC0F0090383FFF3E6D13F86D13E06D7F01017F8101077F9039
+1F1FFF80D93E0F13C0EBF8072601F00113E048486C13F04848137F4848131F001FEC0FF8
+90C71207003E1403A2481401A300FC15F05AA3ED03E0A26CEC07C0007C1580007E140F00
+3EEC1F00003F143E6C6C5B6C6C485A3907F00FE00001B512806C6C48C7FCEB0FF0283F7A
+BC2D>I<EC07F8EC3FFE9138FC0F80903901F007C0903907E003E0D90FC013F090381F80
+01013F14F8EB7F004914FC48481300A24848EB01FEA21207A3485AA41503121F5BA31507
+A2000F15FC150FA2151F1207153F000315F86C6C137F000014EF90387C01CF90393E078F
+F090380FFE1FEB03F890C713E0A2ED3FC0A3ED7F8016005D003F5C487E4A5A00FF495A5D
+4A5A49485A48495A007049C7FC0078137E383E03FC381FFFF06C13C0D801FEC8FC273F79
+BC2D>I<17E016011603831607A2160FA2161F83163FA2167F167716F7EEE7FCED01E316
+C3150316831507EE03FEED0F01150E151E151C153C03387FED7800157015F05D4A488017
+7F4A5AA24AC7FCA2020E81173F5C021FB6FC5CA20270C7EA3FE0171F5CA2495AA2494881
+170F49C8FCA2130EA24982013C1507A2137CD801FE4B7E2607FF80EC3FFEB500F00107B5
+12FC19F85E3E417DC044>65 D<013FB7FC18E018FC903B007FE00007FE6E48903801FF80
+9438007FC05DF03FE0F01FF0A3027F16F892C8FCA54A16F04A153F19E0187F19C0F0FF80
+01014B13004A4A5A4D5AEF1FF04D5ADC03FFC7FC49B612F8EFFF8002F8C7EA3FE0EF0FF0
+EF07FC717E010715014A81711380A319C0130F5CA5011F4B13805C19005F601707013F4B
+5A4A4A5A4D5A4D5A017F913801FF8001FF020F90C7FCB812FC17F094C8FC3D3E7DBD40>
+I<DCFFC01338030F01F01378037F01FC13F0913A01FF803F01913A07FC000781DA1FE0EB
+03C3DA7FC0EB01E74AC812FF4948ED7FE0D907FC153F495A4948151F495A4948150F4948
+16C018074890C9FC485AA2485A000F1880491603121FA248481607A295C7FC485AA412FF
+5BA75BA2181C183C1838A27F007F1778187018F0003F5F6D150160001F16036C6C4B5A95
+C7FC6C6C5D6C6C151E6C6C5D6C6C15F86D6C495A6D6CEB07C0D91FF0EB1F80D907FE01FE
+C8FC0101B512F86D6C13E0DA07FEC9FC3D4276BF42>I<013FB7FC18E018F8903B007FF0
+000FFE6E48EB01FF9438007FC04B6E7E180F85727E727E147F4B6E7EA2727EA302FF1780
+92C9FCA54918C05CA41A8013034A5DA41A0013074A5DA261A24E5A130F4A5E180F61181F
+61011F4C5A5C4E5A4EC7FC4D5A4D5A013F4B5A4A4A5AEF3FE0EF7F80017F4A48C8FC01FF
+EC1FFCB812F0178004FCC9FC423E7DBD45>I<013FB812F8A39026007FF0C7127F6E4814
+0F18034B14011800A31978147F4B1570A502FF147092C7FCA3190017F0495D4A1301A216
+07161F91B6FC495DA29138FC003F160F1607160301075D5CA219E0180119C0010FEC0700
+4A90C712031980A218071900011F5E5C181EA2183E183C013F167C4A15FC4D5A1707017F
+151F01FF4AB45AB9FCA2603D3E7DBD3E>I<013FB812E0A3903A007FF000016E48EB003F
+180F4B14071803A31801147F4B15C0A514FF92C71270A395C7FC17F0495D5C1601160316
+07161F49B65AA39138FC003F160F160701075D4A1303A5010F4AC8FC5C93C9FCA4131F5C
+A5133F5CA3137FEBFFF0B612F8A33B3E7DBD3B>I<4BB46C1370031F01F013F0037F9038
+FC01E0913A03FF807E03913A0FF8000F83DA1FE0EB07C7DA7F80EB01EF4AC812FFD903FE
+16C04948157F4948153F495A4948151F495A4948168091C9120F5A485AA2485A000F1800
+4982121FA248485EA295C7FC485AA412FF5BA6043FB512E05BA29339001FFC00715AA260
+7F127FA2171F123F6D5EA2121F7F000F163F6C7E6C6C4B5A7F6C6C15FF6C6DEB01EFD93F
+C0EB07C7D91FF0EB1F87D907FE9038FE03800101B5EAF8016D6C01E0C8FCDA07FEC9FC3C
+4276BF47>I<013FB5D8F807B6FC04F015FEA29026007FF0C7380FFE006E486E5AA24B5D
+A4180F147F4B5DA4181F14FF92C85BA4183F5B4A5EA491B8FC5B6102FCC8127FA318FF13
+074A93C7FCA45F130F4A5DA41703131F4A5DA41707133F4A5DA3017F150F496C4A7EB6D8
+E01FB512FC6115C0483E7DBD44>I<011FB512FC5BA29039003FF8006E5AA25DA5143F5D
+A5147F5DA514FF92C7FCA55B5CA513035CA513075CA5130F5CA5131F5CA3133F497E007F
+B512F0A2B6FC263E7EBD21>I<013FB500F8010FB5FC4C5BA29026007FF0C7000313E06E
+486E130019FC4B15F04E5A4E5A4E5A061EC7FC027F5D4B5C4D5A4D5AEF07804DC8FC02FF
+141E92C7127C5FEE01E04C5A4C5A49021FC9FC4A5B5E4C7E5D03077F01035B9139FC1F3F
+E0153C4B6C7E15F09139FFE00FF84913C092380007FC5C4A6D7E5C707E130F4A6D7F8417
+7F717EA2011F6F7E5C717EA2717EA2013F6F7E5C84A2017F83496C4A13E0B600E0017F13
+FFA24B90B6FC483E7DBD47>75 D<013FB512FEA25E9026007FF8C8FCEC3FE0A25DA5147F
+5DA514FF92C9FCA55B5CA513035CA513075CA21838A21870130F5CA218E0A3011F15014A
+15C01703A21707EF0F80013F151F4A143F177FEFFF00017F140301FF143FB9FC5FA2353E
+7DBD39>I<90263FFFF093381FFFF85013F0629026007FF8EFF000023F4D5AA2023B9338
+01DFC0A2DA39FCED039FA2F1073F14790271040E5BEC70FE191C19381A7F02F01670DAE0
+7F94C7FC19E0A2F001C06201016D6C495A02C05FF00700A2180E6F6C14010103161C0280
+03385BA218706F7EF0E00313070200DA01C05BA2923907F00380A294380700075B010E90
+2603F80E5C5FA25F190F011E6D6C5A011C605FA2EEFDC0DB00FF141F013C5D013860013C
+92C7FC017C5C01FE027E143F2607FF80017C4A7EB500FC037FB512E004785E4A1338553E
+7CBD53>I<90263FFFE0023FB5FC6F16FEA29026003FF8020313C0021F030013004A6C15
+7C023B163C6F15381439810238167802787FDA707F157082153F82031F15F002F07FDAE0
+0F5D8215078203031401010180DAC0015D82811780047F1303010315C04A013F5C17E016
+1F17F0040F1307010715F891C7000791C7FC17FC160317FE04015B4915FF010E6E130E18
+8E177F18CEEF3FDE011E16FE011C6F5AA2170FA21707133C01386F5A133C017C150113FE
+2607FF801400B512FC18705C483E7DBD44>I<923803FF80031F13F09238FE01FE913903
+F0003FDA0FC0EB1FC0DA3F80EB07E0027EC76C7E49486E7E49488149486E7E4948157F49
+5A013F17804948ED3FC049C9FCA24848EE1FE012035B000718F05B120FA2485A19F8123F
+5BA2127FA219F04848163FA5F07FE0A35BF0FFC0A219805F19007F4D5A127F4D5A60003F
+160F6D5E001F4C5A4D5A6C6C4B5A95C7FC6C6C15FE00034B5A6C6C4A5A6C6C4A5A017FEC
+1FC06D6C495AD90FE001FEC8FC903903F807F80100B512C0DA0FFCC9FC3D4276BF47>I<
+013FB612FEEFFFE018F8903B007FF0000FFC6E48EB01FF7113804BEC7FC0183F19E0F01F
+F0A2147F5D19F8A402FFED3FF092C8FCA219E0A2F07FC05B4AEDFF8019004D5A4D5AEF0F
+F80103ED3FE04A903801FF8091B648C7FC17F002FCCAFCA213075CA5130F5CA5131F5CA5
+133F5CA3137F497EB612E0A25D3D3E7DBD3E>I<013FB612F017FF18E0903B007FF0003F
+F86E48EB07FCEF01FE4B6D7EF07F8019C0183F19E0147F4B15F0A502FFED7FE092C8FCA2
+19C0F0FF80A2494B13004A5D4D5AEF0FF04D5AEF7F800103DA07FEC7FC91B612F0178091
+39FC0007E0EE03F8EE00FC0107814A147F717EA284A2130F5CA484011F157F5CA4190201
+3F17075CA2F0F00F017F170E496C143FB600E0011F131C94380FF83C4B01071378CA3801
+FFE09438003F8040407DBD43>82 D<9238FF80070207EBE00F021FEBF81E91387F00FE02
+FCEB1F3ED903F0EB0FFE49481307494813034AEB01FC49C7FC491400133E137E177C4915
+78A57F1770A26D1500808080EB7FFEECFFE06D13FEEDFFC06D14F06D14FC010380010080
+143F02031480DA003F13C015031500EE7FE0163F161FA2160F121CA31607160F003C16C0
+A31780003E151F1700007E5D007F153E6D5C16FC01E0495AD87DF0495AD8FCFCEB0FC03A
+F87F803F8027F01FFFFEC7FCD8E00713F839C0007FC030427BBF33>I<0007B912F0A33C
+0FFE000FF8003F01F0160F01C04A13034848160190C7FC121EF000E048141F5E1238A212
+781270153F5E5AA3C81600157F5EA515FF93C9FCA55C5DA514035DA514075DA5140F5DA3
+141FEC7FFC0003B7FCA33C3D76BC42>I<B600E090B512FC4B15F8A2000101C0C7000F13
+006C49EC03FCEF01F091C9FC60A317015A495EA417031203495EA4170712074993C7FCA4
+5F120F49150EA4171E121F49151CA4173C123F491538A31778177017F05F001F15015F16
+036D4A5A000F93C8FC5E6C6C141E6C6C5C000115F86C6C495A017FEB07C090393FC03F80
+90260FFFFEC9FC010313F89038007FC03E4073BD44>I<B6020FB5FC19FEA2000301E002
+0113E06C01809138007F8091C9EA7E006C173C18386E15781870017F16F0604D5A804D5A
+133F4DC7FCA26E140E171E011F151C173C17386E1478010F15705FA24C5A8001074A5AA2
+4CC8FC5E6E130E0103141E161C163C16386E5B13015EA24B5A14FF6D495AA24BC9FC5D15
+8EEC7F9E159C15B8A215F0143F5DA25DA26E5AA292CAFCA2140E404074BD44>I<B6017F
+B5D88007B512804A1A00A2000701C0010101E0C713F06C90C80180EC3FC06C48735A99C7
+FC057F150E1B1E6D191C6C1A3C1B3805FF15787214705E636EEB03BF017F4E5AEE073F50
+5A040E7F051F4AC8FC161C6E170E013F143862167804706D5BEEF00F04E05D90381FE001
+04C015F003035E0480140106F85B9226070007130302F05F010F010E150797C9FC5D190E
+4BEB03FC616E5A01075F5D61DAF9C014FE05015BECFB8002FF6F5A7F92C75CA24A93CAFC
+835C606D5A605C604A15781870594074BD5D>I<010FB500F090B512F85B5FD9003F9026
+80003F1300DA0FFEC7EA1FF84BEC0FE00207168096C7FC6E6C141E181C6E6C143C606E6D
+5B4D5ADB7FC05B4D5A92383FE0074DC8FC92381FF01E171C6F6C5A5F923807FCF0EEFDE0
+6FB45A5F6F90C9FCA26F7FA2707EA216FF4B7FED03DF9238079FF0ED0F1F92380E0FF815
+1C92383C07FC15784B6C7EEC01E04B6C7EEC038002076D7F4AC7FC021E6E7E5C02386E7E
+5C02F06E7E495A49486E7E130749486E7E497E017F4B7E2603FFF091383FFF80007F01FC
+49B512FEB55CA2453E7EBD44>I<B66C0103B51280A3000101F0C8EBF0006C49ED7FC06D
+486FC7FC6E153E013F163C606D6C5D606D6C4A5A17036D6C4A5A95C8FC6E140E0103151E
+5F6D6C14385F6D6D13F04C5ADA7FC05B4C5AEDE007023F49C9FC161E91381FF01C5E9138
+0FF8785E6E6C5AEDFDC015FF6E5B93CAFC6E5AA35DA21403A45DA21407A45DA2140FA414
+1F4A7E013FB512F0A3413E75BD44>I<010FB712FEA39239C00007FCD91FFCC7EA0FF814
+F04AEC1FF00280EC3FE091C8EA7FC0013EEDFF80A2013C4A13004C5A494A5A4C5A13704C
+5A4C5A494A5A4C5AA290C74890C7FC4B5A4B5A4B5AA24B5A4B5A4B5A4B5AA24A90C8FC4A
+5A4A5A4A5AA24A5A4A5A4A48EB01C04A5AEF03804990C7FC495A495A494814071800495A
+49485C495A495A171E4890C8123E485A4848157E484815FE4C5A484814074848141F4848
+EB01FFB8FC5FA2373E7BBD38>I E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fi cmbx10 10.95 50
+/Fi 50 123 df<EDFFF8020F13FF027F8049B612E001079038C01FF090390FFE0007D91F
+F8497ED93FE0131F4948497E13FF5C5A91C7FCA2705A705AEE03C093C8FCA6EE03FCB8FC
+A50001903880001F160FB3AB007FD9FE03B512F0A534407EBF3A>12
+D<B612E0A91B097F9823>45 D<ECFFE0010713FC011F13FF017F14C0D9FFE07F48903880
+3FF03A03FE000FF848486D7EA248486D7E001F81A348486D1380A3007F16C0A500FF16E0
+B3A2007F16C0A5003F16806D5BA2001F1600A2000F5D6D13076C6C495A6C6C495A6C6D48
+5A6C9038E0FFE06DB55A011F91C7FC010713FC010013E02B3D7CBB34>48
+D<140F143F5C495A130F48B5FCB6FCA313F7EAFE071200B3B3A8007FB612F0A5243C78BB
+34>I<903803FF80013F13F890B512FE00036E7E4881260FF80F7F261FC0037F4848C67F
+486C6D7E6D6D7E487E6D6D7EA26F1380A46C5A6C5A6C5A0007C7FCC8FC4B1300A25E153F
+5E4B5AA24B5A5E4A5B4A5B4A48C7FC5D4A5AEC1FE04A5A4A5A9139FF000F80EB01FC495A
+4948EB1F00495AEB1F8049C7FC017E5C5B48B7FC485D5A5A5A5A5AB7FC5EA4293C7BBB34
+>I<903801FFE0010F13FE013F6D7E90B612E04801817F3A03FC007FF8D807F06D7E82D8
+0FFC131F6D80121F7FA56C5A5E6C48133FD801F05CC8FC4B5A5E4B5A4A5B020F5B902607
+FFFEC7FC15F815FEEDFFC0D9000113F06E6C7E6F7E6F7E6F7E1780A26F13C0A217E0EA0F
+C0487E487E487E487EA317C0A25D491580127F49491300D83FC0495A6C6C495A3A0FFE01
+FFF86CB65A6C5DC61580013F49C7FC010313E02B3D7CBB34>I<ED01F815031507A2150F
+151F153FA2157F15FF5C5CA25C5CEC1FBFEC3F3F143E147C14FCEB01F814F0EB03E01307
+EB0FC0EB1F801400133E137E5B485A5B485A1207485A5B48C7FC5A127E5AB812F8A5C838
+7FF800AA49B612F8A52D3C7DBB34>I<00071538D80FE0EB01F801FE133F90B6FC5E5E5E
+5E93C7FC5D15F85D15C04AC8FC0180C9FCA9ECFFC0018713FC019F13FF90B67E020113E0
+9039F8007FF0496D7E01C06D7E5B6CC77FC8120F82A31780A21207EA1FC0487E487E12FF
+7FA21700A25B4B5A6C5A01805C6CC7123F6D495AD81FE0495A260FFC075B6CB65A6C92C7
+FCC614FC013F13F0010790C8FC293D7BBB34>I<EC07FF023F13C049B512F001078049EB
+03FC90383FF80090397FE001FE9038FFC0034849487E48495AA2485A120FA2485A6F5A00
+3F6E5A6F5A92C8FC485AA21402EC3FFE00FF496C7E01F9B512E001FB809138E03FF89039
+FF800FFC4A6C7E825B6F13804915C0A317E05BA4127FA5123FA26D15C0121FA2000F4A13
+806D150012076C6C495A6C6D485A6C9038E07FF86DB55A6D5C6D1480010749C7FC010013
+F02B3D7CBB34>I<121F7F13F890B712F0A45A17E017C0178017005E5E5A007EC7EA01F8
+4B5A007C4A5A4B5A4B5A93C7FC485C157E5DC7485A4A5AA24A5A140F5D141F143F5D147F
+A214FF92C8FC5BA25BA3495AA3130FA5131FAA6D5A6D5A6D5A2C3F7ABD34>I<ECFFF001
+0713FE011F6D7E017F14E09039FFC07FF03A01FE001FF848486D7E48486D7E1503485A82
+81121FA27F7F7F6D5B02C05B14F06C6D485A9138FE0FF89138FF9FF06CECFFE06C5D5E6C
+92C7FC6C816D14E0011F80498090B67E48812607FE3F7F48486C1480381FF807D9F00114
+C048486C7E007F8049010F13E0150348487F81167FA2163FA36D15C0127FEE7F807F6C6C
+ECFF006C6C5B01FEEB07FE3A0FFFC03FFC6C90B55A000115E06C6C5C011F49C7FC010113
+F02B3D7CBB34>I<903801FFE0010F13FC013F13FF90B612C04801E07F489038003FF048
+486D7E000F6E7E485A6F7E123F48488081178012FFA217C0A517E0A4007F5CA4003F5C6C
+7E5D6C7E00075C3903FF80FB6C13FF6C6C13F36D13C3010F018313C090380008031400A2
+4B1380EA03F0487E486C1500487E4B5AA25E151F4B5A495C6C48EBFFE049485B2607FC0F
+5B6CB6C7FC6C14FC6C14F06D13C0D90FFEC8FC2B3D7CBB34>I<16FCA24B7EA24B7EA34B
+7FA24B7FA34B7FA24B7FA34B7F157C03FC7FEDF87FA2020180EDF03F0203804B7E020781
+15C082020F814B7E021F811500824A81023E7F027E81027C7FA202FC814A147F49B77EA3
+4982A2D907E0C7001F7F4A80010F835C83011F8391C87E4983133E83017E83017C81B500
+FC91B612FCA5463F7CBE4F>65 D<B812F8EFFF8018F018FC8426003FFCC7EA3FFF050F13
+807113C07113E08319F0A27113F8A719F05FA24D13E019C04D13804D1300EF3FFE933801
+FFF891B712E0188018F818FE02FCC7380FFF80050313C07113E07113F019F8F07FFCA2F0
+3FFEA219FFA38460A419FE187FA2F0FFFC4D13F85F4D13F0053F13E0BA12C0190018FC18
+F095C7FC403E7DBD4A>I<922607FFC0130E92B500FC131E020702FF133E023FEDC07E91
+B7EAE1FE01039138803FFB499039F80003FF4901C01300013F90C8127F4948151FD9FFF8
+150F48491507485B4A1503481701485B18004890CAFC197E5A5B193E127FA349170012FF
+AC127F7F193EA2123FA27F6C187E197C6C7F19FC6C6D16F86C6D150119F06C6D15036C6D
+ED07E0D97FFEED0FC06D6CED3F80010F01C0ECFF006D01F8EB03FE6D9039FF801FFC0100
+91B55A023F15E002071580020002FCC7FC030713C03F407ABE4C>I<B812F8EFFF8018F0
+18FC18FF26003FFCC76C13C005077F05017F716C7E727E727E727E721380A27213C0A272
+13E0A21AF084A21AF8A41AFCA5197FA319FFA51AF8A41AF0A2601AE0A24E13C0A24E1380
+4E1300604E5A4E5A4D485A050713E0057F5BBA5A4EC7FC18F818C005F8C8FC463E7DBD50
+>I<BAFCA4198026003FFEC7123F1707170183183FA2181FF00FC0A31807EE07C0A3F003
+E0A3160F95C7FC161F163F16FF91B6FCA54AC6FC163F161F040F147CA2160719F8A593C7
+1201A219F01803A21807A2180FF01FE0183F18FF1703173FBAFCA219C0A33E3D7DBC45>
+I<B912FEA48426003FFEC77E170F1703170084A284F01F80A3180FA2EE07C0A2F007C0A4
+040F90C7FCA2161F163F16FF91B6FCA54AC6FC163F161F160FA21607A693C9FCACB712E0
+A53A3D7DBC42>I<922607FFC0130E92B500FC131E020702FF133E023FEDC07E91B7EAE1
+FE01039138803FFB499039F80003FF4901C01300013F90C8127F4948151FD9FFF8150F48
+491507485B4A1503481701485B18004890CAFC197E5A5B193E127FA34994C7FC12FFAB04
+07B612FC127F7FA3003F92C7383FFE00A27F7EA26C7FA26C7F6C7FA26C7F6C7FD97FFE15
+7F6D6C7E010F01E014FF6D01F813036D9038FF801F010091B512F3023F15C00207ED803E
+02009138FE000E030701E090C7FC46407ABE52>I<B7D8803FB612E0A526003FFEC8000F
+EB8000B3A491B9FCA54AC8120FB3A7B7D8803FB612E0A54B3E7DBD52>I<B71280A52600
+3FFEC7FCB3B3B0B71280A5213E7DBD28>I<B712E0A526003FFEC9FCB3AD183EA4187E18
+7CA418FCA21701A2EF03F8A21707170F171F177FEE01FF160FB9FC18F0A4373E7DBD3F>
+76 D<B6037FB512E0A2818181D8003F6D9139001F800081A281816E7E6E7F6E7F80826E
+7F6E7F6E7F6E7F157F826F7F6F7F6F7F6F7F81836F7F6F7F707E701380A27013C07013E0
+7013F07013F87013FCA27013FEEF7FFF71139F7113DF8319FF8383838384A28484848484
+A284B600C080197F193F191FA24B3E7DBD52>78 D<ED3FFF0203B512F0021F14FE027F6E
+7E902701FFF80713E00107D9C00013F84990C7EA3FFCD93FFCEC0FFF49486E7F49486E7F
+48496E7F4A80488448496F7EA24890C96C7E4884A249161F003F84A34848701380A400FF
+19C0AD007F19806D5EA3003F1900A26D5E6C60A26C6D4B5AA26C6D4B5A6C6D4A5BA26C6D
+4A5B6C6D4A5B6D6C4A5B6DB4023F90C7FC6D01C0EBFFFE0107D9F80713F8010190B612E0
+6D5E021F4AC8FC020314F0DA003F90C9FC42407ABE4F>I<B812F017FF18C018F018FC26
+003FFCC77FEF1FFF7113807113C07113E0A27113F0A319F8A819F0A34D13E019C05F4D13
+80053F1300EFFFFE91B712F860188005FCC7FC4ACAFCB3A4B77EA53D3E7DBD47>I<B87E
+17FCEFFF8018F08428003FFC000113FE9338003FFF050F7F717F717FA2858385A761A25F
+61614D5B4D90C8FCEF3FFE4CB45A91B712F018C04DC9FC717E9126FC000F7F040113F070
+7F717EA2717EA2717EA685A6F207C019C0A271140F07E01380B76DEBF01F719038FC3F00
+7190B5FC716C5B061F13F8CB000113E04A3F7DBD4E>82 D<903A03FFC001C0011FEBF803
+017FEBFE0748B6128F4815DF48010013FFD80FF8130F48481303497F4848EB007F127F49
+143F161F12FF160FA27F1607A27F7F01FC91C7FCEBFF806C13F8ECFFC06C14FCEDFF806C
+15E016F86C816C816C816C16806C6C15C07F010715E0EB007F020714F0EC003F15030300
+13F8167F163F127800F8151FA2160FA27EA217F07E161F6C16E06D143F01E015C001F8EC
+7F8001FEEB01FF9026FFE00713004890B55A486C14F8D8F81F5CD8F00314C027E0003FFE
+C7FC2D407ABE3A>I<003FB912FCA5903BFE003FFE003FD87FF0EE0FFE01C01603491601
+90C71500197E127EA2007C183EA400FC183F48181FA5C81600B3AF010FB712F8A5403D7C
+BC49>I<903807FFC0013F13F848B6FC48812607FE037F260FF8007F6DEB3FF0486C806F
+7EA36F7EA26C5A6C5AEA01E0C8FC153F91B5FC130F137F3901FFFE0F4813E0000F138038
+1FFE00485A5B485A12FF5BA4151F7F007F143F6D90387BFF806C6C01FB13FE391FFF07F3
+6CEBFFE100031480C6EC003FD91FF890C7FC2F2B7DA933>97 D<13FFB5FCA512077EAFED
+FFE0020713FC021FEBFF80027F80DAFF8113F09139FC003FF802F06D7E4A6D7E4A13074A
+80701380A218C082A318E0AA18C0A25E1880A218005E6E5C6E495A6E495A02FCEB7FF090
+3AFCFF01FFE0496CB55AD9F01F91C7FCD9E00713FCC7000113C033407DBE3A>I<EC7FF0
+0107B5FC011F14C0017F14E09039FFF01FF0489038800FF848EB001F4848EB3FFC120F48
+5AA2485AA2007FEC1FF849EB0FF0ED03C000FF91C7FCAB127F7FA3003F153E7F001F157E
+6C6C147C6C6C14FC91388001F86C9038C003F0C69038F81FE06DB512C0011F14800107EB
+FE009038007FF0272B7DA92E>I<EE07F8ED07FFA5ED003F161FAFEC7FF0903807FFFE01
+1FEBFF9F017F14DF9039FFF01FFF48EBC00348EB00014848EB007F485A001F153F5B123F
+A2127F5BA212FFAA127FA37F123FA26C6C147F120F6D14FF6C6C01037F6C6D48EBFFE06C
+EBF03F6C6CB512BF6D143F010713FC010001E0EBE00033407DBE3A>I<ECFFF0010713FE
+011F6D7E017F809039FFE07FE0489038801FF048496C7E48486D7E48486D7E121F491301
+003F81A2485A6F1380A212FFA290B7FCA401F0C9FCA5127FA27F123FEE0F806C7E161F6C
+6C15006C6C5C6C6D137E6C9038E001FC6C9038F80FF8013FB55A6D14C0010391C7FC9038
+007FF8292B7DA930>I<EC07FE91387FFF8049B512C0010714E090390FFE3FF0EB1FF090
+393FE07FF8EB7FC013FF1480A2489038003FF0ED1FE0ED0FC092C7FCAAB612E0A5000101
+80C7FCB3AC007FEBFF80A525407DBF20>I<903A03FF8007F0013F9038F83FF8499038FC
+FFFC48B712FE48018313F93A07FC007FC34848EB3FE1001FEDF1FC4990381FF0F8170000
+3F81A7001F5DA26D133F000F5D6C6C495A3A03FF83FF8091B5C7FC4814FC01BF5BD80F03
+138090CAFCA2487EA27F13F06CB6FC16F016FC6C15FF17806C16C06C16E01207001F16F0
+393FE000034848EB003F49EC1FF800FF150F90C81207A56C6CEC0FF06D141F003F16E001
+F0147FD81FFC903801FFC02707FF800F13006C90B55AC615F8013F14E0010101FCC7FC2F
+3D7DA834>I<13FFB5FCA512077EAFED1FF8EDFFFE02036D7E4A80DA0FE07F91381F007F
+023C805C4A6D7E5CA25CA35CB3A4B5D8FE0FB512E0A5333F7CBE3A>I<EA01F8487E487E
+487E481380A66C13006C5A6C5A6C5AC8FCA913FFB5FCA512077EB3ABB512F8A515407CBF
+1D>I<13FFB5FCA512077EB3B3AFB512FCA5163F7CBE1D>108 D<01FFD91FF8ECFFC0B590
+B5010713F80203DAC01F13FE4A6E487FDA0FE09026F07F077F91261F003FEBF801000701
+3EDAF9F0806C0178ECFBC04A6DB4486C7FA24A92C7FC4A5CA34A5CB3A4B5D8FE07B5D8F0
+3FEBFF80A551297CA858>I<01FFEB1FF8B5EBFFFE02036D7E4A80DA0FE07F91381F007F
+0007013C806C5B4A6D7E5CA25CA35CB3A4B5D8FE0FB512E0A533297CA83A>I<EC7FF090
+3803FFFE011FEBFFC0017F14F09039FFE03FF8489038800FFC3A03FE0003FE48486D7E00
+0F168048486D13C0A2003F16E049147F007F16F0A400FF16F8AA007F16F0A46C6CECFFE0
+A2001F16C06C6C491380A26C6C4913003A03FF800FFE6C9038E03FFC6C6CB512F0011F14
+C0010791C7FC9038007FF02D2B7DA934>I<01FFEBFFE0B5000713FC021FEBFF80027F80
+DAFF8113F09139FC007FF8000701F06D7E6C496D7E4A130F4A6D7E1880A27013C0A38218
+E0AA4C13C0A318805E18005E6E5C6E495A6E495A02FCEBFFF0DAFF035B92B55A029F91C7
+FC028713FC028113C00280C9FCACB512FEA5333B7DA83A>I<3901FE01FE00FF903807FF
+804A13E04A13F0EC3F1F91387C3FF8000713F8000313F0EBFFE0A29138C01FF0ED0FE091
+388007C092C7FCA391C8FCB3A2B6FCA525297DA82B>114 D<90383FFC1E48B512BE0007
+14FE5A381FF00F383F800148C7FC007E147EA200FE143EA27E7F6D90C7FC13F8EBFFE06C
+13FF15C06C14F06C806C806C806C80C61580131F1300020713C014000078147F00F8143F
+151F7EA27E16806C143F6D140001E013FF9038F803FE90B55A15F0D8F87F13C026E00FFE
+C7FC222B7DA929>I<EB07C0A5130FA4131FA3133F137FA213FF5A1207001FEBFFFEB6FC
+A40001EBC000B3151FA96CEBE03EA2017F137EECF8FC90383FFFF86D13F0010713E00100
+1380203B7EB929>I<D9FF80EB0FF8B5EB0FFFA50007EC007F6C153FB3A5167FA316FF6C
+5C4B7F6C903AC007DFFFE09138F01F9F6DB5121F6D13FE010F13F8010101E0EBE000332A
+7CA83A>I<B500FC90383FFFC0A5000101C0903803E0006E1307A26C5E6E130F017F5D6E
+131F013F92C7FC6E5B011F143E6E137E010F147C6E13FCA26D5C15816D5C15C36D5C15E7
+6D5C15FF6E5BA36E90C8FCA26E5AA26E5AA26E5AA26E5AA232287EA737>I<B5D8FC03B5
+1280A5C69026E0007FC7FC6E13FE6D6C5B6D6C485A6D6C485A010F13076D6C485AED9FC0
+6DEBFF806D91C8FC6D5B6E5AA2143F6E7E140F814A7F4A7F4A7F02FE7F903801FC7F4948
+6C7E02F07F49486C7E49486C7E011F7F49486C7FD97F008001FE6D7FB5D8C007EBFFC0A5
+32287EA737>120 D<B500FC90383FFFC0A5000101C0903803E0006E1307A26C5E6E130F
+017F5D6E131F013F92C7FC6E5B011F143E6E137E010F147C6E13FCA26D5C15816D5C15C3
+6D5C15E76D5C15FF6E5BA36E90C8FCA26E5AA26E5AA26E5AA26E5AA35D14075D000E130F
+D83F805B387FC01FD8FFE090C9FC5C143E147E5CEBC1F8387FC3F0387E0FE06CB45A6C5B
+6C48CAFCEA03F8323B7EA737>I<003FB612F8A4D9F80113F001C014E0495A494813C04A
+1380007E15005C4A5A007C5C147F4A5A495B5DC65A495B495BA249EB007C495A5C137F49
+4813FC484913F85C5A48EBC00114804814034813004848130749131F007FECFFF0B7FCA4
+26287DA72E>I E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fj cmr10 10.95 92
+/Fj 92 124 df<4AB4EB0FE0021F9038E03FFC913A7F00F8FC1ED901FC90383FF03FD907
+F090397FE07F80494801FF13FF4948485BD93F805C137F0200ED7F00EF003E01FE6D91C7
+FC82ADB97EA3C648C76CC8FCB3AE486C4A7E007FD9FC3FEBFF80A339407FBF35>11
+D<EC03FE91383FFF809138FE03E0903903F800F0D90FE013384948137C90393F8001FE90
+387F00035B5BA2485A6F5AED007093C7FCAA16FEB7FCA33901FC000315011500B3AC486C
+497EB5D8F87F13FCA32E407EBF33>I<EC03FF023F13EE9138FE01FEEB03F090380FE003
+EB1FC0EB3F80EB7F005B5B150148481300AEB7FCA3D801FCC7FCB3AE486C497EB5D8F87F
+13FCA32E407EBF33>I<DA03FE49B4FC91273FFF801F13C0913BFE03E07F01F0903C03F0
+00F1FC0078D90FE0D97FF0131C49484948133E4948484913FF494848495A5B491500A248
+485C03016E5A0300153896C7FCAA197FBBFCA3D801FCC738FE00018485B3AC486C496CEC
+FF80B5D8F87FD9FC3F13FEA347407EBF4C>I<121EEA7F80EAFFC0A9EA7F80ACEA3F00AC
+121EAB120CC7FCA8121EEA7F80A2EAFFC0A4EA7F80A2EA1E000A4179C019>33
+D<001E130F397F803FC000FF137F01C013E0A201E013F0A3007F133F391E600F30000013
+00A401E01370491360A3000114E04913C00003130101001380481303000EEB070048130E
+0018130C0038131C003013181C1C7DBE2D>I<4B6C130C4B6C131EA20307143EA24C133C
+A2030F147CA293C71278A24B14F8A2031E5CA2033E1301A2033C5CA3037C1303A203785C
+A203F81307A24B5CA20201140F007FBAFCBB1280A26C1900C72707C0003EC8FC4B133CA3
+020F147CA292C71278A24A14F8A2021E5CA3023E1301007FBAFCBB1280A26C1900C727F8
+0007C0C8FC4A5CA20101140FA24A91C9FCA301035CA24A131EA20107143EA24A133CA201
+0F147CA291C71278A34914F8A2011E5CA2013E1301A2013C5CA201186D5A41517BBE4C>
+I<14E0A4EB07FC90383FFF8090B512E03901F8E3F03903E0E0FCD807C0133CD80F807FD8
+1F007F003E80003C1580007C140316C00078141F00F8143F157FA47EED3F806CEC0E0092
+C7FC127F138013C0EA3FF013FEEA1FFF6C13FC6C13FF6C14C06C806C6C13F8011F7F1303
+01007FECE7FF14E102E01380157F153FED1FC0A2003E140F127FD8FF801307A5130000FC
+158000F0140F1270007815005D6C141E153E6C5C6C5C3907C0E1F03903F8EFE0C6B51280
+D93FFEC7FCEB0FF8EB00E0A422497BC32D>I<013F1603D9FFC04B7E2601E0E0150F2607
+C070151F48486C4BC7FC023E157E48486C15FE48D90FC0EB03FC003ED90EF0EB0FF8DA0F
+3F13FD007E903A070FFFF1F0007C0200EB03E0160000FC6D6C495A170F604DC8FC5F173E
+5F17FC5F4C5A1603007CD907005B4C5A007E150F003E495C020E49C9FC003F5D6C49133E
+260F803C5B023813FC6C6C485B3A01E0E001F03800FFC090273F0003E0133F90C70007EC
+FFC09339C001E0E0923A0F8007C070031F49487E0400143C033E90381F001C037E497F03
+7C133E4B150F0201027E7F4B137C4A5A020702FCEB03805D4A5A141F92C7FC143E147E14
+7C5CA2495A0103037CEB07005C4948147E010F033E5B4A160E49C8123F496F5B013E9238
+0F803C49173801FC6F6C5A49923801E0E0496FB45A0160043FC7FC41497BC34C>I<EC0F
+80EC7FE0ECF870903803E0380107133CECC01CEB0F80011F131E150EA2EB3F00A55D1480
+A25D157815705D6D6C5A14C1ECC38002C7CAFC02EE91387FFFFCEB0FEC14FC4A020713C0
+6D48913801FE006E5DEF00F06D7E01074B5A496C5D011D1503D939FF4A5A017093C7FC49
+6D5B0001017F140E496C6C131E00036E131C2607801F143C000F6E5B001F6D6C1370263F
+000714F0486E485ADA03FE5B913801FF03486D495A0487C8FCED7FCFED3FFE6F4814386D
+5C150F007F6E6C14786D6D6C1470003F4A6C14F06D496C6C13E0001F91393E3FC0016C6C
+903AFC1FF003C03D07FC07F007FC1F800001B5D8C001B512006C6C90C7EA7FFCD90FF8EC
+0FF03E437CC047>I<121EEA7F8012FF13C0A213E0A3127FEA1E601200A413E013C0A312
+011380120313005A120E5A1218123812300B1C79BE19>I<1430147014E0EB01C0EB0380
+1307EB0F00131E133E133C5B13F85B12015B1203A2485AA2120F5BA2121F90C7FCA25AA3
+123E127EA6127C12FCB2127C127EA6123E123FA37EA27F120FA27F1207A26C7EA212017F
+12007F13787F133E131E7FEB07801303EB01C0EB00E014701430145A77C323>I<12C07E
+12707E7E121E7E6C7E7F12036C7E7F12007F1378137CA27FA2133F7FA21480130FA214C0
+A3130714E0A6130314F0B214E01307A614C0130FA31480A2131F1400A25B133EA25BA213
+7813F85B12015B485A12075B48C7FC121E121C5A5A5A5A145A7BC323>I<EB03C0A2805C
+A600F0140F00FC143F00FE147F00FF14FF393FC3C3FC390FE187F03903F18FC03900FDBF
+00EB3FFCEB0FF0EB03C0EB0FF0EB3FFCEBFDBF3903F18FC0390FE187F0393FC3C3FC39FF
+03C0FF00FE147F00FC143F00F0140F00001400A6805CA220277AC32D>I<1506150FB3A9
+007FB912E0BA12F0A26C18E0C8000FC9FCB3A915063C3C7BB447>I<121EEA7F8012FF13
+C0A213E0A3127FEA1E601200A413E013C0A312011380120313005A120E5A121812381230
+0B1C798919>I<B512FEA617067F961E>I<121EEA7F80A2EAFFC0A4EA7F80A2EA1E000A0A
+798919>I<ED0180ED03C01507A21680150FA216005DA2151E153EA2153C157CA2157815
+F8A25D1401A25D1403A25D1407A25D140FA24AC7FCA2141E143EA2143C147CA2147814F8
+A25C1301A25C1303A25C1307A25C130FA291C8FC5BA2131E133EA25BA2137813F8A25B12
+01A25B1203A25B1207A25B120FA290C9FC5AA2121E123EA2123C127CA2127812F8A25A12
+60225B7BC32D>I<EB01FE90380FFFC090383F03F090387C00F849137C48487F48487F48
+48EB0F80A2000F15C04848EB07E0A3003F15F0A290C712034815F8A64815FCB3A26C15F8
+A56C6CEB07F0A3001F15E0A36C6CEB0FC0A26C6CEB1F80000315006C6C133E6C6C5B017C
+5B90383F03F090380FFFC0D901FEC7FC263F7DBC2D>I<EB01C013031307131F137FEA07
+FFB5FC139FEAF81F1200B3B3ACEB7FF0B612F8A31D3D78BC2D>I<EB07FC90383FFF8090
+B512E03903F01FF83907C007FC390F0001FE001E6D7E001C1580003CEC7FC05AED3FE012
+70B4FC6DEB1FF07FA56C5A6CC7FC120CC813E0153FA216C0157F168015FF16004A5A5D4A
+5A4A5A5D4A5A4A5A4AC7FC147E147C5C495A495A495A495A49C71270133E133C5B4914E0
+485A485A485A48C7120148B6FCA25A4815C0B7FCA3243D7CBC2D>I<EB07FC90383FFF80
+9038F80FE03901E003F839078001FCD80F007F000E6D7E001E1580D81F80137F486C14C0
+7FA27F5BA2121F6C5AC8138015FF1600A24A5AA24A5A5DEC07E04A5A023FC7FCEB1FFCEC
+FF809038000FE0EC07F86E7E6E7E6E7E1680ED7FC0A216E0153FA216F0A2120C123F487E
+487EA316E0A249137F6CC713C01278EDFF807E6C4913006C495A3907C007FC3903F80FF0
+C6B55A013F1380D907F8C7FC243F7CBC2D>I<150E151E153EA2157EA215FE1401A21403
+EC077E1406140E141CA214381470A214E0EB01C0A2EB0380EB0700A2130E5BA25B5BA25B
+5B1201485A90C7FC5A120E120C121C5AA25A5AB8FCA3C8EAFE00AC4A7E49B6FCA3283E7E
+BD2D>I<00061403D80780131F01F813FE90B5FC5D5D5D15C092C7FC14FCEB3FE090C9FC
+ACEB01FE90380FFF8090383E03E090387001F8496C7E49137E497F90C713800006141FC8
+13C0A216E0150FA316F0A3120C127F7F12FFA416E090C7121F12FC007015C012780038EC
+3F80123C6CEC7F00001F14FE6C6C485A6C6C485A3903F80FE0C6B55A013F90C7FCEB07F8
+243F7CBC2D>I<EC1FE0ECFFF8903803F03E90380FC00F90391F000780133E017EEB1FC0
+49133F4848137F12035B12074848EB3F80ED1F00001F91C7FC5BA2123FA3485AA214FE90
+3887FF8039FF8F07E090389C01F09038B800FC01B0137E13F0497F16804914C0A2ED1FE0
+A34914F0A5127FA6123F6D14E0A2121FED3FC0A26C6C1480A20007EC7F006C6C137E6C6C
+5B6C6C485A90387E07F06DB45A010F1380D903FCC7FC243F7CBC2D>I<1238123C123F90
+B612FCA316F85A16F016E00078C712010070EC03C0ED078016005D48141E151C153C5DC8
+127015F04A5A5D14034A5A92C7FC5C141EA25CA2147C147814F8A213015C1303A31307A3
+130F5CA2131FA6133FAA6D5A0107C8FC26407BBD2D>I<EB03FC90381FFF8090387C07E0
+9038F001F83901E0007C48487F48487F48C7FCED0F80121E16C0003E1407A4123FA26DEB
+0F807F6C6C131F6D140001FC133E6C6C5B9038FF80786C6D5A6CEBF3E06CEBFF806C91C7
+FC133F6D13C06D7F013F13F801787F48486C7E3903E01FFF48486C1380260F800313C048
+487E489038007FE0003E143F007E141F007CEC0FF01507481403A31501A46C15E0007C14
+03A2007E15C06C14076CEC0F806DEB1F006C6C133ED807F05B3901FC03F86CB512E0011F
+1380D903FCC7FC243F7CBC2D>I<EB03FCEB1FFF90387E07C09038FC03F048486C7E4848
+6C7E4848137C000F147E4848137F81003F15805B007F15C0A2151F12FF16E0A516F0A512
+7F153FA36C7EA2001F147F120F6C6C13FF6D13DF000313013900F8039F90387E0F1FD91F
+FE13E0EB07F090C7FCA2ED3FC0A41680157FD80F801400487E486C13FEA24A5A5D49485A
+EB8007391E000FE0001F495A260FC07FC7FC3803FFFE6C13F838003FC0243F7CBC2D>I<
+121EEA7F80A2EAFFC0A4EA7F80A2EA1E00C7FCB3121EEA7F80A2EAFFC0A4EA7F80A2EA1E
+000A2779A619>I<121EEA7F80A2EAFFC0A4EA7F80A2EA1E00C7FCB3121E127FEAFF80A2
+13C0A4127F121E1200A412011380A3120313005A1206120E120C121C5A1230A20A3979A6
+19>I<007FB912E0BA12F0A26C18E0CDFCAE007FB912E0BA12F0A26C18E03C167BA147>
+61 D<EB0780EB1FE0A2497EA46D5AA2EB078090C8FCA8130380A4130791C7FCA65BA313
+1EA2133E133C137CA25B1201485A485A120F485A485A127FA248C7127C15FEEC01FFA480
+157F6C141EA26C6C133C1578390FC001E03907F00FC03901FFFE0038003FF020407BAC2B
+>I<EB1FF890B5FC3903E01FC0390F0007F0001EEB03F848EB01FC4814FE140000FE14FF
+7E7FA46CC7FC123EC7EA01FEA2EC03FCEC07F815F0EC0FC0EC1F80EC3F00143E5C147814
+F85C13015CA2495AA25CAB91C7FC90C8FCA8EB0780EB1FE0A2497EA46D5AA2EB07802040
+7BBF2B>I<ED7FE0913807FFFE91391F801F809139780001E0D901E0EB0078D90780141E
+49C87E011E6F7E0138ED01C0496F7E4916700001177848488249D93F80131C28070001FF
+F07F48902607E07C130F000E90260FC01E7F001E90263F00071480001C49903803800300
+3C01FED901C013C0003849ECFE010101EC00FF267803F8027F13E000701700495AA200F0
+18F000E01870495AA96D7E12F01270A26D7E007818E0263801FC5C01005C003C7F001C01
+7F49EB01C0001E6DEB077F000E903B0FC01E3F8380000F903B07E07C1F87006C903A01FF
+F007FE3C0380003F8001F86D90CAFC6C7E120013707F011EEE03F06D160F6D6CED3FC0D9
+01E0913801FE00D90078EC1FF0913A1F8003FF800207B500F8C7FC9126007FFEC8FC3C41
+7BBF47>I<15074B7EA34B7EA34B7EA34B7EA34B7E15E7A2913801C7FC15C3A291380381
+FEA34AC67EA3020E6D7EA34A6D7EA34A6D7EA34A6D7EA34A6D7EA349486D7E91B6FCA249
+819138800001A249C87EA24982010E157FA2011E82011C153FA2013C820138151FA20178
+82170F13FC00034C7ED80FFF4B7EB500F0010FB512F8A33D417DC044>I<B712FCEEFF80
+17F00001903980000FF86C6CC7EA03FE707E701380EF7FC0EF3FE0A2EF1FF0A218F8A317
+0F171FA318F0A2EF3FE0177F18C0EFFF804C1300EE03FCEE0FF8EE7FE091B6C7FC17E091
+C7EA07FCEE01FE933800FF80EF7FC0EF3FE0EF1FF018F8170F18FC1707A218FEA718FC17
+0FA2EF1FF818F0173FEF7FE0EFFFC00403138048486C90380FFE00B85A17E094C7FC373E
+7DBD40>I<DB3FF01306912603FFFE130E020F9038FF801E913A3FF007E03E9139FF8000
+F8D903FEC7EA7C7ED907F8EC1EFE4948140FD93FE0140749481403495A91C81201484815
+0012034848167E5B000F173EA24848161EA2123F5B180E127FA349160012FFAC127F7F18
+0EA2123FA27F001F171E181C6C7EA20007173C6D16386C6C1678000117706C6C16F06EEC
+01E06D6C15C06D6C1403D90FF0EC07806D6CEC1F00D903FE143E902600FF8013F891393F
+F007F0020FB512C0020391C7FC9138003FF037427BBF42>I<B712FCEEFF8017E0000190
+39C0001FF86C6C48EB03FEEE00FF717E717EEF0FE084717E717E170184717EA21980187F
+19C0A3F03FE0A519F0AB19E0A5F07FC0A21980A218FF19004D5AA24D5A6017074D5A4D5A
+EF7FC04DC7FCEE03FE48486CEB1FF8B85A178004FCC8FC3C3E7DBD45>I<B912E0A30001
+9038C000016C6C48EB001FEF0FF01703A217011700A31870A418381638A41800A21678A2
+16F81501150791B5FCA3EC8007150115001678A21638A2180EA3181C93C7FCA4183C1838
+A21878A318F8EF01F0A21707170F173F48486CEB03FFB912E0A3373E7DBD3E>I<B91280
+A300019038C000036C6C48EB007FEF1FC0170F1707A21703A31701A4EF00E0A21638A318
+00A31678A216F81501150791B5FCA3EC8007150115001678A21638A693C8FCAF3801FFE0
+B612F0A3333E7DBD3B>I<DB3FE0130C912603FFFE131C021F9038FF803C913A7FF00FC0
+7C9139FF0001F0D903FC90380078FC4948143DD91FE0141F4948140F4948140701FF1503
+4890C8FC491501485A000716005B000F177C5B001F173CA2485AA2181C127FA25B95C7FC
+12FFAB041FB512F0127FA26D9139000FFE00EF03FC123FA27F121FA26C7EA212077F1203
+6C7E7F6C7F6D6C14076D7E6D6C140FD907F8141ED903FEEC3C7C902600FF80EBF83C913A
+7FF007F01C021FB5EAC00C020391C8FC9138003FF03C427BBF47>I<B6D8C01FB512F8A3
+000101E0C7383FFC0026007F80EC0FF0B3A691B7FCA30280C7120FB3A92601FFE0EC3FFC
+B6D8C01FB512F8A33D3E7DBD44>I<B612F0A3C6EBF000EB3FC0B3B3B2EBFFF0B612F0A3
+1C3E7EBD21>I<011FB512FCA3D9000713006E5A1401B3B3A6123FEA7F80EAFFC0A44A5A
+1380D87F005B007C130700385C003C495A6C495A6C495A2603E07EC7FC3800FFF8EB3FC0
+26407CBD2F>I<B600C090387FFFFCA3000101E0C7000F138026007F80913807FE0018F8
+18E0604D5A4DC7FC173E5F5F4C5A4C5A4C5A4C5A4CC8FC163E5E5E4B5A4B5AED07804B7E
+151F4B7E4B7E15FF913881EFF8913883C7FCEC878791388F03FE91389E01FF14BCDAF800
+7F4A6D7E5C4A6D7E4A6D7EA2707E707EA2707E707EA2707F717E84173F717E717EA2717E
+848419802601FFE04A13C0B600C090B6FCA3403E7DBD47>I<B612F8A3000101E0C9FC38
+007F80B3B0EF0380A517071800A45FA35FA25F5F5F4C5A160748486C133FB8FCA3313E7D
+BD39>I<B500C093B512C0A300016D4BEBE000D8007F1880D977F0ED03BFA3D973F8ED07
+3FA3D971FC150EA2D970FE151CA3027F1538A36E6C1470A36E6C14E0A26E6CEB01C0A36E
+6CEB0380A36E6CEB0700A26E6C130EA36E6C5BA3037F5BA26F6C5AA36F6C5AA392380FE1
+C0A3923807F380A26FB4C7FCA36F5AA213F8486C6D5AD807FFEFFFE0B500F80178017FEB
+FFC0A34A3E7CBD53>I<B56C91B512F88080D8007F030713006EEC01FC6E6E5A1870EB77
+FCEB73FEA2EB71FF01707FA26E7E6E7EA26E7E6E7EA26E7E6E7EA26E7E6E7FA26F7E6F7E
+A26F7E6F7EA26F7E6F7EA26F7E6F1380A2EE7FC0EE3FE0A2EE1FF0EE0FF8A2EE07FCEE03
+FEA2EE01FF7013F0A2177F173FA2171F170FA2170701F81503487ED807FF1501B500F814
+00A218703D3E7DBD44>I<ED7FE0913807FFFE91391FC03F8091397E0007E04948EB03F8
+D907F0EB00FE4948147F49486E7E49486E7E49C86C7E01FE6F7E00018349150300038348
+486F7EA248486F7EA2001F188049167F003F18C0A3007F18E049163FA300FF18F0AC007F
+18E06D167FA4003F18C0A26C6CEEFF80A36C6C4B1300A26C6C4B5A00035F6D150700015F
+6C6C4B5A6D5E6D6C4A5A6D6C4A5A6D6C4AC7FC6D6C14FED901FCEB03F8D9007FEB0FE091
+391FC03F80912607FFFEC8FC9138007FE03C427BBF47>I<B712F8EEFF8017E000019039
+C0003FF86C6C48EB07FCEE01FE707EEF7F80EF3FC018E0A2EF1FF0A218F8A818F0A2EF3F
+E0A218C0EF7F80EFFF004C5AEE07FCEE3FF091B612C04CC7FC0280C9FCB3A73801FFE0B6
+12C0A3353E7DBD3E>I<ED7FE0913807FFFE91391FC03F8091397F000FE0D901FCEB03F8
+D907F0EB00FE4948147F49486E7E49486E7E49C86C7E498248486F7E4915030003834848
+6F7EA2000F834981001F1880A24848EE7FC0A3007F18E0A249163FA200FF18F0AC007F18
+E0A26D167FA3003F18C0A26C6CEEFF80A3000F18006D5D0007DA0F805B6C6C90393FE003
+FCED70706C6C496C485A6C6C48486C485A017FD9800E5BD93F819038061FC0D91FC19038
+073F80D90FE14AC7FCD907F1EB03FE902601FDC013F8903A007EE007E091271FF03FC013
+180207B5FC9139007FE1E0DB0001143883711378A2706C13F0EFFF0318FFA27113E0A371
+13C0711380711300715AEF01F83D527BBF47>I<B712C016FCEEFF800001D9C00013E06C
+6C48EB1FF0EE07FCEE01FE707E84717EA2717EA284A760177F606017FF95C7FCEE01FCEE
+07F8EE1FE0EEFF8091B500FCC8FC16F091388001FCED003FEE1FC0707E707E8316038316
+0183A383A484A4F0C004190EA28218E0057F131E2601FFE0161CB600C0EB3FF094381FF8
+3805071370CA3801FFE09438003F803F407DBD43>I<D907FC131890391FFF8038017FEB
+E0783901FC03F83A03F0007CF8D807C0133F4848130F001F140748C7FC003E1403007E14
+01A2007C140012FC1678A46C1538A27EA26C6C14007F7FEA3FF8EBFF806C13F86CEBFF80
+6C14F06C14FC6C14FF6C15C0013F14E0010714F0EB007F020713F89138007FFC150FED07
+FE15031501ED00FFA200E0157FA3163FA27EA3163E7E167E6C157C6C15FC6C15F86D1301
+6DEB03F06DEB07E0D8F9FCEB0FC03AF07F803F8090391FFFFE00D8E00713F839C0007FC0
+28427BBF33>I<003FB91280A3903AF0007FE001018090393FC0003F48C7ED1FC0007E17
+07127C00781703A300701701A548EF00E0A5C81600B3B14B7E4B7E0107B612FEA33B3D7D
+BC42>I<B600C090B512F8A3000101E0C70007130026007F80EC01FC715A1870B3B3A401
+3F16F06E5DA21701011F5E80010F15036E4A5A010793C7FC6D6C5C6D6C141E6D6C5C027F
+14F86E6C485A91390FF00FE00203B51280020049C8FCED1FF03D407DBD44>I<B691380F
+FFFEA3000301E0020113E06C01809138007F806CEF3F00017F163E181C6E153C013F1638
+A26E1578011F1670A26D6C5DA26E140101075EA26E140301035EA26D6C4AC7FCA2806D15
+0EA26F131E027F141CA26F133C023F1438A26E6C5BA26F13F0020F5CA2EDF80102075CA2
+6E6C485AA2EDFE07020191C8FCA26F5A6E130EA2ED7F9CA216DCED3FF8A36F5AA36F5AA2
+6F5AA36F5A3F407EBD44>I<B500FE017FB5D88007B5FCA3000301C0010101E0C713F86C
+90C849EC3FE07148EC0F807E7215006E143F017F190E84A26D6C60A24D7E6D6C60A2EFE7
+F86D6C60A2933801C3FC6E18F001076104037F6E0281140101036104077F17006D6C4D5A
+A2040EEB7F806D6C4DC7FCA24CEB3FC0DA7F80160EA24CEB1FE003C0161E023F171C0478
+14F0DBE070010F133C021F173804F014F84C1307DA0FF05EA2DBF1C0EB03FCDA07F95EA2
+DBFB80EB01FEDA03FF6F5AA293C8FCA26E5FA24B157F020094C8FCA24B81037C153EA203
+78151E0338151C58407EBD5D>I<007FB5D8C003B512E0A3C649C7EBFC00D93FF8EC3FE0
+6D48EC1F806D6C92C7FC171E6D6C141C6D6C143C5F6D6C14706D6D13F04C5ADA7FC05B02
+3F13036F485ADA1FF090C8FC020F5BEDF81E913807FC1C163C6E6C5A913801FF7016F06E
+5B6F5AA26F7E6F7EA28282153FED3BFEED71FF15F103E07F913801C07F0203804B6C7EEC
+07004A6D7E020E6D7E5C023C6D7E02386D7E14784A6D7E4A6D7F130149486E7E4A6E7E13
+0749C86C7E496F7E497ED9FFC04A7E00076DEC7FFFB500FC0103B512FEA33F3E7EBD44>
+I<B66C0103B51280A3000101F0C8EBF8006C6C48ED3FC0725A013F041EC7FC6D7E606D6C
+15386D6C1578606D6C5D6E14016D5E6D6D1303606E6C49C8FC6E6C5B170E6E6C131E171C
+6E6C5B6E6C137817706E6C13F06F5B6E13016EEB83C05FED7FC7DB3FE7C9FC16EFED1FFE
+5E150F6F5AB3A4ED1FFC020FB512FCA3413E7FBD44>I<003FB712F8A391C7EA1FF013F8
+01E0EC3FE00180EC7FC090C8FC003EEDFF80A2003C4A1300007C4A5A12784B5A4B5AA200
+704A5AA24B5A4B5AA2C8485A4A90C7FCA24A5A4A5AA24A5AA24A5A4A5AA24A5A4A5AA249
+90C8FCA2495A4948141CA2495A495AA2495A495A173C495AA24890C8FC485A1778485A48
+4815F8A24848140116034848140F4848143FED01FFB8FCA32E3E7BBD38>I<EAFFFCA4EA
+F000B3B3B3B3ABEAFFFCA40E5B77C319>I<486C13C00003130101001380481303000EEB
+070048130E0018130C0038131C003013180070133800601330A300E01370481360A400CF
+EB678039FFC07FE001E013F0A3007F133FA2003F131F01C013E0390F0007801C1C73BE2D
+>I<EAFFFCA4EA003CB3B3B3B3ABEAFFFCA40E5B7FC319>I<EA0180120313005A120E5A12
+181238123012701260A312E05AA412CFEAFFC013E0A3127FA2123F13C0EA0F000B1C7ABE
+19>96 D<EB0FF8EBFFFE3903F01F8039078007E0000F6D7E9038E001F8D81FF07F6E7EA3
+157F6C5AEA0380C8FCA4EC1FFF0103B5FC90381FF87FEB7F803801FC00EA07F8EA0FE048
+5A485AA248C7FCEE038012FEA315FFA3007F5BEC03BF3B3F80071F8700261FC00E13CF3A
+07F03C0FFE3A01FFF807FC3A003FC001F0292A7DA82D>I<EA01FC12FFA3120712031201
+B1EC03FC91381FFF8091387C07E09039FDE001F09039FFC000FC4A137E91C77E49158049
+141F17C0EE0FE0A217F0A2160717F8AA17F0A2160FA217E0161F17C06D1580EE3F006D5C
+6E13FE9039F3C001F89039F1E003F09039E0780FC09026C03FFFC7FCC7EA07F82D407EBE
+33>I<49B4FC010F13E090383F00F8017C131E4848131F4848137F0007ECFF80485A5B12
+1FA24848EB7F00151C007F91C7FCA290C9FC5AAB6C7EA3003FEC01C07F001F140316806C
+6C13076C6C14000003140E6C6C131E6C6C137890383F01F090380FFFC0D901FEC7FC222A
+7DA828>I<ED01FC15FFA3150715031501B114FF010713E190381F80F990387E003D4913
+1FD803F81307485A49130348481301121F123F5B127FA290C7FCA25AAA7E7FA2123FA26C
+7E000F14037F000714076C6C497E6C6C497ED8007C017913F890383F01F190380FFFC190
+3A01FE01FC002D407DBE33>I<EB01FE90380FFFC090383F03F09038FC01F848486C7E48
+48137E48487F000F158049131F001F15C04848130FA2127F16E090C7FCA25AA290B6FCA2
+90C9FCA67EA27F123F16E06C7E1501000F15C06C6C13036DEB07806C6C1400C66C131E01
+7E5B90381F80F8903807FFE0010090C7FC232A7EA828>I<EC1FC0EC7FF8903801F83C90
+3807E07E90380FC0FFEB1FC1EB3F811401137FEC00FE01FE137C1500AEB6FCA3C648C7FC
+B3AE487E007F13FFA320407EBF1C>I<167C903903F801FF903A1FFF078F8090397E0FDE
+1F9038F803F83803F001A23B07E000FC0600000F6EC7FC49137E001F147FA8000F147E6D
+13FE00075C6C6C485AA23901F803E03903FE0FC026071FFFC8FCEB03F80006CAFC120EA3
+120FA27F7F6CB512E015FE6C6E7E6C15E06C810003813A0FC0001FFC48C7EA01FE003E14
+0048157E825A82A46C5D007C153E007E157E6C5D6C6C495A6C6C495AD803F0EB0FC0D800
+FE017FC7FC90383FFFFC010313C0293D7EA82D>I<EA01FC12FFA3120712031201B1EC01
+FE913807FFC091381E07E091387803F09138E001F8D9FDC07F148001FF6D7E91C7FCA25B
+A25BB3A6486C497EB5D8F87F13FCA32E3F7DBE33>I<EA01E0EA07F8A2487EA46C5AA2EA
+01E0C8FCACEA01FC127FA3120712031201B3AC487EB512F0A3143E7DBD1A>I<1478EB01
+FEA2EB03FFA4EB01FEA2EB00781400AC147FEB7FFFA313017F147FB3B3A5123E127F38FF
+807E14FEA214FCEB81F8EA7F01387C03F0381E07C0380FFF803801FC00185185BD1C>I<
+EA01FC12FFA3120712031201B292B51280A392383FFC0016E0168093C7FC153C5D5D4A5A
+EC07C04A5A4AC8FC143E147F4A7E13FD9038FFDFC0EC9FE0140F496C7E01FC7F496C7E14
+01816E7E81826F7E151F826F7EA282486C14FEB539F07FFFE0A32B3F7EBE30>I<EA01FC
+12FFA3120712031201B3B3B1487EB512F8A3153F7DBE1A>I<2701F801FE14FF00FF9027
+07FFC00313E0913B1E07E00F03F0913B7803F03C01F80007903BE001F87000FC2603F9C0
+6D487F000101805C01FBD900FF147F91C75B13FF4992C7FCA2495CB3A6486C496CECFF80
+B5D8F87FD9FC3F13FEA347287DA74C>I<3901F801FE00FF903807FFC091381E07E09138
+7803F000079038E001F82603F9C07F0001138001FB6D7E91C7FC13FF5BA25BB3A6486C49
+7EB5D8F87F13FCA32E287DA733>I<14FF010713E090381F81F890387E007E01F8131F48
+48EB0F804848EB07C04848EB03E0000F15F04848EB01F8A2003F15FCA248C812FEA44815
+FFA96C15FEA36C6CEB01FCA3001F15F86C6CEB03F0A26C6CEB07E06C6CEB0FC06C6CEB1F
+80D8007EEB7E0090383F81FC90380FFFF0010090C7FC282A7EA82D>I<3901FC03FC00FF
+90381FFF8091387C0FE09039FDE003F03A07FFC001FC6C496C7E6C90C7127F49EC3F805B
+EE1FC017E0A2EE0FF0A3EE07F8AAEE0FF0A4EE1FE0A2EE3FC06D1580EE7F007F6E13FE91
+38C001F89039FDE007F09039FC780FC0DA3FFFC7FCEC07F891C9FCAD487EB512F8A32D3A
+7EA733>I<02FF131C0107EBC03C90381F80F090397F00387C01FC131CD803F8130E4848
+EB0FFC150748481303121F485A1501485AA448C7FCAA6C7EA36C7EA2001F14036C7E1507
+6C6C130F6C7E6C6C133DD8007E137990383F81F190380FFFC1903801FE0190C7FCAD4B7E
+92B512F8A32D3A7DA730>I<3901F807E000FFEB1FF8EC787CECE1FE3807F9C100031381
+EA01FB1401EC00FC01FF1330491300A35BB3A5487EB512FEA31F287EA724>I<90383FC0
+603901FFF8E03807C03F381F000F003E1307003C1303127C0078130112F81400A27E7E7E
+6D1300EA7FF8EBFFC06C13F86C13FE6C7F6C1480000114C0D8003F13E0010313F0EB001F
+EC0FF800E01303A214017E1400A27E15F07E14016C14E06CEB03C0903880078039F3E01F
+0038E0FFFC38C01FE01D2A7DA824>I<131CA6133CA4137CA213FCA2120112031207001F
+B512C0B6FCA2D801FCC7FCB3A215E0A912009038FE01C0A2EB7F03013F138090381F8700
+EB07FEEB01F81B397EB723>I<D801FC14FE00FF147FA3000714030003140100011400B3
+A51501A31503120015076DEB06FF017E010E13806D4913FC90381FC078903807FFE00100
+903880FE002E297DA733>I<B539E00FFFE0A32707FE000313006C48EB00FC5E00015D7F
+00005DA26D13016D5CA26D6C485AA2ECC007011F91C7FCA290380FE00EA2ECF01E010713
+1CA26D6C5AA2ECFC7801011370A2ECFEF001005BA2EC7FC0A36E5AA26EC8FCA3140E2B28
+7EA630>I<B53BC3FFFE03FFF8A3290FFE003FE00013C06C486D48EB3F806C4817006D01
+0F141E00016F131C15076D163C00004A6C1338A2017F5E4B7E151DD93F805DED3DFC1538
+D91FC04A5AED78FE9238707E03D90FE0017F5BEDE03F02F0140701070387C7FC9138F1C0
+1F02F9148F010315CE9138FB800F02FF14DE6D15FCED00076D5DA24A1303027E5CA2027C
+1301023C5C023813003D287EA642>I<B539F01FFFE0A30003D9C00F1300C690388007F8
+D97F0013E002805BD93FC05B011F49C7FC90380FE00EECF01E6D6C5A01035B6D6C5A6E5A
+EB00FF6E5A6E5A81141F814A7E81147BECF1FC903801E1FEECC0FF01037F49486C7ED90F
+007F011E6D7E013E130F496D7E01FC80486C80000F4A7EB539803FFFF8A32D277FA630>
+I<B539E00FFFE0A32707FE000313006C48EB01FC6F5A00015D7F00005DA2017F495AA2EC
+8003013F5CA26D6C48C7FCA26E5A010F130EA26D6C5AA2ECF83C01031338A26D6C5AA2EC
+FEF001005BA2EC7FC0A36E5AA36EC8FCA2140EA2141E141C143C1438A214780018137012
+7EB45BA2495AA248485AD87E07C9FCEA780EEA3C3CEA1FF8EA07E02B3A7EA630>I<001F
+B61280A2EBE0000180140049485A001E495A121C4A5A003C495A141F00385C4A5A147F5D
+4AC7FCC6485AA2495A495A130F5C495A90393FC00380A2EB7F80EBFF005A5B4848130712
+07491400485A48485BA248485B4848137F00FF495A90B6FCA221277EA628>I<B812F0A2
+2C0280982D>I E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fk cmr12 14.4 16
+/Fk 16 116 df<120FEA3FC0EA7FE0EAFFF0A6EA7FE0EA3FC0EA0F000C0C768B21>46
+D<EC1FF891B5FC010314C090390FF81FF090391FC003F849486C7E017EC7127E49800001
+168049141F4848EC0FC0000716E0491407000F16F0A34848EC03F8A2003F16FCA44848EC
+01FEA700FF16FFB3A5007F16FEA56D1403A2003F16FCA4001F16F8A26D1407000F16F0A2
+6C6CEC0FE0A26C6CEC1FC0A26C6CEC3F806C6CEC7F00017F14FE6D6C485A6D6C485A9039
+0FF81FF00103B512C0010091C7FCEC1FF830517BCE3B>48 D<EC7FE0903803FFFE010F6D
+7E013F14E0D9FF0013F8D801F8EB1FFCD803E06D7E4848EB03FF48486D138090C813C000
+1E16E0001C157F003CED3FF012380078ED1FF81270A2B4ED0FFC13C07FA66C5A6C5A000E
+C8FCC9EA1FF8A317F0163FA2EE7FE017C016FF17804B1300A24B5A4B5A5E4B5A4B5A4B5A
+5E4BC7FC15FE4A5A4A5A4A5A4A5A5D4A5A4AC8FC147E5C4948141CEB03E0495A49481438
+91C8FC131E5B5B491578485A48481570484815F048B7FCA25A5A5AB812E0A42E4F7ACE3B
+>50 D<160F5EA25E5EA25E5DA25D5DA25D151E151C153C5D157015F04A5A5D14035D4A5A
+5C140E5C143C14385C14F05C495A13035C130749C7FC130E131E5B133813785B5B120148
+5A5B120748C8FC120E121E5A123812785AB912F0A4C8000190C7FCAF4B7F4B7F020FB612
+E0A434507DCF3B>52 D<000316C001C0140301F8141F903AFFC003FF8091B612005E5E5E
+16E016804BC7FC019F13F8018113800180C9FCB0EC0FF0ECFFFE01836D7E903987F01FE0
+90399F0007F801BE6D7E01F86D7E496D7E49EC7F805BEE3FC04915E0C9121F17F0A317F8
+160FA317FCA5120EEA3F80487E12FF7FA217F85B161F5B48C813F012700078ED3FE0A26C
+16C0167F6CEDFF80001F16006C6C495A6C6C13036C6CEB07F8D801F8EB1FF06CB4EB7FE0
+6DB51280011F49C7FC010713F8010013C02E517ACE3B>I<B812FEEFFFE018FC18FF2600
+7FFCC7000F13C06D4802017F011F9238003FF8F00FFC727EF001FF727F737E737E737E19
+0F86737EA2737E737EA21B8085A21BC01A7F1BE0A4F23FF0A51BF8AE1BF0A4F27FE0A41B
+C01AFF1B80A24F1300A24F5AA24F5AA24F5A4F5A4F5A4F5A4F5A4E90C7FC4E5AF00FFCF0
+3FF8013FEEFFE0496C020F5BBAC8FC18FC18E04DC9FC4D527BD159>68
+D<B600FC030FB512E0A4C691CAEBFC00D97FFCEF3FF06D48EF1FC0011F616E71C7FC130F
+1A0E6E171E0107181CA26E173C6D1838816D60A26F16F06D6081027F4C5AA281023F4C5A
+A26F1507021F94C8FC81020F160EA26F151E0207161CA26F153C6E1638826E5EA27014F0
+6E5E821801037F5D82033F4A5AA2701307031F92C9FC82030F140EA270131E0307141CA2
+70133C6F143817806F5CA2EFC0F06F5C17E017E1047F5B17F193383FF380A217FF7090CA
+FCA2705AA3705AA3705AA2705AA3705A53547ED158>86 D<EB7F80B5FCA41203C6FC137F
+B3A6ED07FC92387FFF800281B512E0913987F00FF891398F8001FC029EC7B4FC02BC6E7E
+02F86E7E4A6E7E4A6E7E4A1407844A6E7EA2841701A284A283A21980AB19005FA360A24D
+5AA24D5A804D5A6E5D6E4A5AD97E784A5A6E4AC7FCD97C1EEB01FE6E495A903A7807E01F
+F00201B512C0902670007F90C8FC90C7EA0FF839547DD241>98 D<EC0FFE91387FFFE049
+B512F8903907F801FE90391FE0001FD93F80EB078049C7EA0FC001FE143F484815E00003
+157F485A485AA2485AEE3FC0003FED0F004991C7FCA2127FA35B12FFAB127F7FA3123F6D
+1570121F6D15F0000F16E06D140112076C6CEC03C06D15806C6C14076C6DEB0F00D93FC0
+131E6D6C137C903907FC03F06DB55AD9007F1380DA0FF8C7FC2C367CB434>I<EC0FF891
+B5FC010314C090390FF80FF090391FC003FC90397F8001FE49C77E4848EC7F804848143F
+49EC1FC0485A000FED0FE05B001F16F01607485AA2007F16F8A25B160312FF90B7FCA301
+80C9FCA8127F7FA2123FA26D1538121F17786C6C1570000716F06D15E06C6C14016C6CEC
+03C06C6C15806D6C130F6D6CEB1F00D90FF0133C903907FE01F80101B512E06D6C1380DA
+07FCC7FC2D367DB434>101 D<1378EA01FE487E487FA66C90C7FC6C5AEA007890C8FCB0
+EB7F80B5FCA41203C6FC137FB3B3A43801FFE0B61280A419507CCF21>105
+D<01FFD907FEEC03FFB590261FFFC0010F13E0037F01F0013F13F8912701F80FFC9038FC
+07FE913D03C003FE01E001FF000390260700019038038000C6010E6D6C48C76C7E6D48DA
+7F8E6E7E4A159CA24ADA3FF86E7E02605D14E04A5DA34A5DB3AD2601FFE0DAFFF0EC7FF8
+B6D8C07F9026FFE03FB512F0A45C347CB363>109 D<01FFEB07FCB590383FFF8092B512
+E0913901F00FF8913903C007FC000349C66C7EC6010E13016D486D7E5C143002706E7E14
+6014E05CA35CB3AD2601FFE0903801FFE0B600C0B612C0A43A347CB341>I<EC0FFC9138
+7FFF8049B512E0903907F807F890391FE001FE90393F80007F017EC7EA1F80496E7E4848
+6E7E00038248486E7EA248486E7EA248486E7EA2003F82A24848ED7F80A400FF17C0AB00
+7F1780A26D15FFA2003F1700A2001F5E6D1401000F5E6D140300075E6C6C4A5A6C6C4A5A
+A2D8007FEC3F806D6C49C7FC90391FE001FE903907F807F86DB55AD9007F1380DA0FFCC8
+FC32367CB43B>I<01FFEB1F80B5EB7FF0913801FFF8913803E1FC91380783FE0003EB0F
+07C6131EEB7F1C1438143091387003FC91386000F0160014E05CA45CB3AA8048487EB612
+F0A427347DB32E>114 D<D907FE13C090387FFF8148B512E33907F803FF390FC0007F48
+48133F48C7121F003E140F007E1407127C00FC1403A315017EA27E7F6C6C90C7FC13F013
+FF6C13F86CEBFF806C14E06C14F86C14FEC680013F1480010714C0D9003F13E014039138
+007FF0151F00E0140FED07F8A26C1403A215017EA36C15F0A26C14036C15E015076DEB0F
+C06DEB1F80D8FDF0EB3F0039F8FC01FE39F07FFFF8D8E01F13E0D8C00390C7FC25367CB4
+2E>I E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fl cmbx12 17.28 20
+/Fl 20 117 df<F00FE04E7EA24E7EA34E7EA24E7EA34D7FA24D80A24D80A34D80A24D80
+A34D80A2DD7FBF7FA2181F05FF8017FE04016D7FA24D7E04038217F804076D80A24D7E04
+0F8217E0041F6D80A24D7F043F825F047F6E7FA294C77E4C825E03016F7FA24C80030384
+5E03076F80A24C80030F845E031F6F80A24C81033F845E037F707F93B9FCA292BA7EA24A
+85A203FCC912070203865D020771805D86020F864B82021F865D87023F864B83027F8692
+CBFC874A864A840101875C496C728090381FFFC0B700E092B812FEA66F647BE37A>65
+D<4DB5ED03C0057F02F014070407B600FE140F047FDBFFC0131F4BB800F0133F030F05FC
+137F033F9127F8007FFE13FF92B6C73807FF814A02F0020113C3020702C09138007FE74A
+91C9001FB5FC023F01FC16074A01F08291B54882490280824991CB7E4949844949844949
+8449865D49498490B5FC484A84A2484A84A24891CD127FA25A4A1A3F5AA348491A1FA448
+99C7FCA25CA3B5FCB07EA380A27EA2F50FC0A26C7FA37E6E1A1F6C1D80A26C801D3F6C6E
+1A00A26C6E616D1BFE6D7F6F4E5A7F6D6D4E5A6D6D4E5A6D6D4E5A6D6E171F6D02E04D5A
+6E6DEFFF806E01FC4C90C7FC020F01FFEE07FE6E02C0ED1FF8020102F8ED7FF06E02FF91
+3803FFE0033F02F8013F1380030F91B648C8FC030117F86F6C16E004071680DC007F02F8
+C9FC050191CAFC626677E375>67 D<BD12E0A41CF0A2D8000102C0C71207F1003F1A0F1A
+031A001B7F1B3FF31FF81B0FA21B07A21B03A21B011CFCA31B00A419FCA21C7EA41C00A2
+1801A31803A21807180F183FEF01FF93B6FCA6EEC001EF003F180F18071803A21801A318
+00A896C9FCB3A5B912F8A657617AE065>70 D<B912E0A6C702E0C7FCB3B3B3B3AEB912E0
+A633627CE13C>73 D<BB7E1AFCF2FFC01BF81BFE757ED800010280C7001F80070114F073
+6C7F081F7F747F747F7414807414C0A27414E0A21DF0A27513F8A41DFCA91DF8A498B512
+F0A21DE0A25014C01D8062501400505B505B087F5B4FB512E0071F5C93B9C7FC1BFC1BF0
+1B8008F0C8FC04C0CCFCB3B3A2B97EA65E627AE16E>80 D<DBFFFCEC01E0020FD9FFE013
+03027F02FC130749B7130F0107EEC01F011F16F049D9C007EBF83F4948C7383FFE7FD9FF
+F8020FB5FC4801E014014849804849153F91C97E484882001F834982003F83845B007F18
+7FA2193FA200FF181FA27F190FA27FA26D17078080806C01F893C7FC80ECFF8015F86CEC
+FFC016FC6CEDFFE017FE6CEEFFE018F86C17FE6C717E6C846C846D17F86D836D836D8313
+036D18806D6C17C0020F17E01401DA000F16F01500040715F8EE007F1703050014FC183F
+84060713FE84A2007C8300FC83A2197FA3193F7EA31AFC7EA27F1AF86D177F7F1AF06D17
+FF6D18E06D5E01FF18C06E4B138002E04B130002F84B5A02FFED3FFC01CF01E0ECFFF801
+8301FF010F5B010191B65A6D6C5E48011F93C7FC48010315FC48D9003F14E048020149C8
+FC476677E35A>83 D<001FBEFCA64849C79126E0000F148002E0180091C8171F498601F8
+1A0349864986A2491B7FA2491B3F007F1DC090C9181FA4007E1C0FA600FE1DE0481C07A5
+CA95C7FCB3B3B3A3021FBAFCA663617AE070>I<913803FFFE027FEBFFF00103B612FE01
+0F6F7E4916E090273FFE001F7FD97FE001077FD9FFF801017F486D6D7F717E486D6E7F85
+717FA2717FA36C496E7FA26C5B6D5AEB1FC090C9FCA74BB6FC157F0207B7FC147F49B612
+07010F14C0013FEBFE004913F048B512C04891C7FC485B4813F85A5C485B5A5CA2B55AA4
+5FA25F806C5E806C047D7F6EEB01F96C6DD903F1EBFF806C01FED90FE114FF6C9027FFC0
+7FC01580000191B5487E6C6C4B7E011F02FC130F010302F001011400D9001F90CBFC4943
+7CC14E>97 D<92380FFFF04AB67E020F15F0023F15FC91B77E01039039FE001FFF4901F8
+010113804901E0010713C04901804913E0017F90C7FC49484A13F0A2485B485B5A5C5A71
+13E0485B7113C048701380943800FE0095C7FC485BA4B5FCAE7EA280A27EA2806C18FCA2
+6C6D150119F87E6C6D15036EED07F06C18E06C6D150F6D6DEC1FC06D01E0EC7F806D6DEC
+FF00010701FCEB03FE6D9039FFC03FFC010091B512F0023F5D020F1580020102FCC7FCDA
+000F13C03E437BC148>99 D<92380FFFC04AB512FC020FECFF80023F15E091B712F80103
+D9FE037F499039F0007FFF011F01C0011F7F49496D7F4990C76C7F49486E7F4849804884
+4A804884485B727E5A5C48717EA35A5C721380A2B5FCA391B9FCA41A0002C0CBFCA67EA3
+80A27EA27E6E160FF11F806C183F6C7FF17F006C7F6C6D16FE6C17016D6C4B5A6D6D4A5A
+6D01E04A5A6D6DEC3FE0010301FC49B45A6D9026FFC01F90C7FC6D6C90B55A021F15F802
+0715E0020092C8FC030713F041437CC14A>101 D<EE3FFC0307B51280033F14C04AB612
+F0020715F84A9038F03FFC4AEB807F913A7FFE00FFFE4A5A4B4813FF4913F05B4913E0A2
+4913C0A27013FE4949EB7FFCEF3FF8EF1FF0EF07C094C7FCB0B812C0A6D8001F01C0C8FC
+B3B3B0007FB612FCA638657CE431>I<F107F8DB7FFEEC3FFE020FB5D8F001B5FC027FDA
+FE03148049B7128F49DCDFFD13C0010FD9F00FEBFFC149D9800114014990C7EBFC034948
+6E6C7E4948EC3FFF48496E018113800780130048F0C03E97C7FC48496E7FA34884A96C60
+A36C6D4A5BA26C60A26C6D4A90C8FC6D6C4A5A6D6C4A5A6D6D485BDBF00F5B4990B612C0
+60D97C7F4AC9FCD9FC0F14F09126007FFECAFC92CCFC1201A47FA27F8014F091B77E18FE
+6CEFFFC019F06D17FC19FF6D846D846D846D84013F8490BAFC0003854801E0C712014890
+C9000F7F484816014848EE007F4848717E8512FF5B85A56D5F007F616D173F003F616D17
+7F6C6C4D5A6C01C003035B6C6D4B5B6C01F8031F5BC601FF92B5C7FC6D01F8011F5B011F
+90B712F8010717E0010094C8FC020F15F0DA003F01FCC9FC4A607CC151>I<EB0FE0EB3F
+F8497E48B5FCA24880A24880A76C5CA26C91C7FCA238007FFC6D5AEB0FE090C9FCAF9038
+07FF80007FB5FCA6C6FC7F7FB3B3AEB712C0A622657BE42C>105
+D<903807FF80B6FCA6C6FC7F7FB3B3B3B3ADB712E0A623647BE32C>108
+D<902607FF80D91FFFEEFFF8B691B500F00207EBFF80040702FC023F14E0041F02FF91B6
+12F84C6F488193267FE07F6D4801037F922781FE001F9027E00FF0007FC6DA83F86D9026
+F01FC06D7F6DD987F06D4A487F6DD98FC0DBF87EC7804C6D027C80039FC76E488203BEEE
+FDF003BC6E4A8003FC04FF834B5FA24B5FA24B94C8FCA44B5EB3B2B7D8F007B7D8803FB6
+12FCA67E417BC087>I<902607FF80EB1FFFB691B512F0040714FC041F14FF4C8193267F
+E07F7F922781FE001F7FC6DA83F86D7F6DD987F07F6DD98FC0814C7F039FC78015BE03BC
+8003FC825DA25DA25DA45DB3B2B7D8F007B71280A651417BC05A>I<923807FFE092B6FC
+020715E0021F15F8027F15FE494848C66C6C7E010701F0010F13E04901C001037F49496D
+7F4990C87F49486F7E49486F7E48496F13804819C04A814819E048496F13F0A24819F8A3
+48496F13FCA34819FEA4B518FFAD6C19FEA46C6D4B13FCA36C19F8A26C6D4B13F0A26C19
+E06C6D4B13C0A26C6D4B13806C6D4B13006D6C4B5A6D6D495B6D6D495B010701F0010F13
+E06D01FE017F5B010090B7C7FC023F15FC020715E0020092C8FC030713E048437CC151>
+I<D90FFFEB0FFCB690383FFF8093B512E04B14F04B14F8923907FC7FFC92390FE0FFFEC6
+EC1F806DD93F0113FF6D133E157E157C15F8A215F07013FEA24BEB7FFCEF3FF8EF0FE04B
+90C7FCA55DB3B0B712F8A638417BC042>114 D<913A3FFF8007800107B5EAF81F011FEC
+FE7F017F91B5FC48B8FC48EBE0014890C7121FD80FFC1407D81FF0801600485A007F167F
+49153FA212FF171FA27F7F7F6D92C7FC13FF14E014FF6C14F8EDFFC06C15FC16FF6C16C0
+6C16F06C826C826C826C82013F1680010F16C01303D9007F15E0020315F0EC001F150004
+1F13F81607007C150100FC81177F6C163FA2171F7EA26D16F0A27F173F6D16E06D157F6D
+16C001FEEDFF806D0203130002C0EB0FFE02FCEB7FFC01DFB65A010F5DD8FE0315C026F8
+007F49C7FC48010F13E035437BC140>I<EC07E0A6140FA5141FA3143FA2147FA214FF5B
+A25B5B5B5B137F48B5FC000F91B512FEB8FCA5D8001F01E0C8FCB3AFEF0FC0AC171F6D6D
+1480A2173F6D16006F5B6D6D137E6D6D5B6DEBFF836EEBFFF86E5C020F14C002035C9126
+003FFCC7FC325C7DDA3F>I E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fm cmbx12 24.88 41
+/Fm 41 123 df[<96380FFFFE060FB612E04DB712FC051F16FF94B912C0040784041F18
+F8047F9126FC001F7F4BB6008001017F030702F8C8EA3FFF4B02E0030F7F033F02804B7F
+4B49C9127F92B54893B57E4A02F05D4A4A4B804A4A5D4A4A84634A91C9FC4A5BA24A5B51
+80755C91B5FC5EA3755CA2755C755C755CE23FFEC8FCF40FF899CAFCAF083FB612FCBFFC
+A9C702FCC912038787B3B3B3B2003FB800F0013FB812F0A9>116
+144 123 271 129 12 D[<EB1FE0EBFFFC00037F486D7E488048804880A24880A281B6FC
+81A281A416807EA37EA27E7E6C14BF6C143FC613FCEB1FE090C7FC157F1600A55D5DA214
+015DA214035D1407A24A5AA24A5AA24A5A147F5D4AC7FC5B495A5C1307495A495A495AEB
+FFC0485B4890C8FC485A5B6C5A6C5A6C5A>33 70 111 270 65 39
+D[<F31FE0F37FF8A2517EA2507FA3507FA25080A35080A25080A35080A25080A397B67E
+A24F81A34F81A24F82A34F82A24F82A21AFBDF3FF981A2DF7FF1811AF06207FF6D80A24E
+01C081871A804E6E80A24E0100828761060F6E81A24E48838761063F6E81A24E48838761
+06FF6F80A24D498388614D7080A24D90C8FC768160050F7081A260051F708160053F7081
+A260057F70816005FF7180A2604C7280604C7280A295CAFC4C72815F040F7281A294BDFC
+4C88A24C88A34C88A293BE7E05E0CB7E5F4B7480A24B497280A294CCFC4B7481A24B4873
+81A25E031F7481A24B487381A25E037F7481A24B487480A25E4A7680A24A497480A293CE
+FC4A7681A24A4875814A7E0107B512FCB96C043FBA12FCA9>158
+145 120 272 175 65 D[<BFFC1EFEF6FFE01FFCF7FF8020F020FC20FF8DC7000392CA00
+1F15E00B0181776C800C1F807814FF0C03818A78818E79808B8E8B8E8B8EA27980A47915
+80AB551500A4555CA26A676A676A555C9CB65AA2545D5492C7FC545C5414F80C3F5C545C
+53B612800B0F4AC8FC0B7F14F80A1FB612E095BBC9FC1FF81F801FF8F7FF8020F820FE95
+CBECFFC00C1F14F00C07807814FE0C006E7E7980798079807980798079808E79158023C0
+8B23E08C23F0A223F88CA223FCA38C23FEAB5614FCA55614F8A39DB612F0A25515E06723
+C055158067551500555C555C9CB6FC545D0C075D0C1F15C09BB75A0B0F93C7FCC212FC69
+21E021800EFCC8FC20F020800DF0C9FC0CFCCAFC>143 142 120
+269 165 I[<0803B500C0EE01F00703B600FEEE03F8077FDBFFE015070607B800FC150F
+063F05FF151F4DBA00E0143F050F07F8147F053F07FE14FF94BC5B04039326F8000FECC0
+03040F4BC86CEBF007043F03C0030F6D5A93B648C900036D5A4B03F09339007FFF3F0307
+03C0051F90B5FC4B92CB7E033F02FC18034B02F08492B648844A0380193F4A92CD7E4A4A
+864A4A864A02F0864A4A864A8991B65A494B874992CF7E4C885B494A885E498B494A88A2
+495C8D90B65A8D5A5E48217FA24892D1FC223FA25A5DA248211FA3485CFA0FF09FC7FCA2
+5AA45DA3B6FCB27EA381A47EA46C80FA07F0FA0FF87EA2817EA36C6F1D1F23F07E827E22
+3F6D6E1EE0A26D6E1D7F23C06D6E1DFF7F705213806D806D55130070646D6F646D6F515A
+6E6E1B1F6E6E515A6E6E515A6E6E1BFF6E6E505B6E6E505B6E6F4F5B6E03E04F90C7FC6F
+6EF13FFE6F02FC4F5A030F02FF4E485A6F03C005075B030103F0051F5B6F03FE057F1380
+043FDAFFE00303B5C8FC040F03FE033F13FC0403DBFFF80107B55A040093B812E0053F1A
+80050F4FC9FC050119F8DD003F18C0060795CAFCDE007F16F0070393CBFCDF000314C0>
+141 146 115 271 168 I[<BE12FEF5FFFCF6FFC01FFCF7FF8020E020FC20FF21C0C700
+030380C8000116F0E2000F810B0015FE0C1F800C0315C00C00810D3F8079800D0714FE79
+807981796C808C7A807A808F7A807A808C8F7A818DA17E8DA17E8DA17EA27B80A2A17E8D
+A17EA28DA17EA3A113808DA3A113C0A57B15E0A6A113F0B3A2A113E0A569A113C0A5A113
+80A269A2A11300A3575CA2A15AA269A15A69A15AA2575CA15A69A15A9EB6FC5692C7FC6B
+565C68565C565C565C565C9DB65A5592C8FC0D075C555C0D3F5C9CB65A0C0315C00C0F5D
+0C7F92C9FC0B07B612FC52B712F0C212C09ECAFC20FC20F020800DFCCBFC1FE00CFCCCFC
+53CDFC>156 142 120 269 178 I[<C212F8A48DA5C7000303C0C9123FF5007F1E0F0C01
+80787E1F1F8B8B1F018BA27A7E8C8CA28CA28CA28C8EA28CA38CA38EA2E21FF0157FA67B
+7EA40A3F93C8FCA41C7FA21CFFA26363631B1F1B7F0807B5FC95B8FCA99538C00007F200
+7F1B1F1B07878787A21C7FA21C3FA3FA7FC01C1FA2FAFF80A6571300A299CAFCA369A26A
+A22107A3210F6AA2211FA2213FA2575AA221FFA26868565BA26868207F9DB5FC555C1F07
+1F1F1F7F0C03B6FC1E3F0B1FB7FCC35AA66AA3>138 141 120 268
+153 I[<C21280A421C0A5C7000303C0C81201F40007F5007F0C1F14E01E071E01787E8B
+8B8B8B7913F0A28B8BA2207FA3203F21F8201FA4200FA321FC2007A4F47FC0A3F803FEA4
+9DC7FCA31CFFA463A263A26363631B7F50B5FC1A1F95B8FCA99538C0001F1A01747E1B1F
+878787A287A287A41C7FAA99CBFCB3AFBC12F8A9>127 141 120
+268 146 I[<0803B500C0EE01F00703B600FE4C7E077FDBFFE015070607B800FC150F06
+3F05FF151F4DBA00E0143F050F07F8147F053F07FE14FF94BC5B04039326F8000FECC003
+040F4BC86CEBF007043F03C0030F6D5A93B648C900036D5A4B03F09339007FFF3F030703
+C0051F90B5FC4B92CB7E033F02FC18034B02F08492B648844A0380193F4A92CD7E4A4A86
+4A4A864A02F0864A4A864A8991B65A494B874992CF7E4C885B494A885E498B494A88A249
+5C8D90B65A8D5A5E48217FA24892D1FC223FA25A5DA248211FA3485C7C5A9FC9FCA25AA4
+5DA3B6FCB27EA381A20A0FBB12F8A27EA46C80A36C98C96C02F8C7FCA2817EA36C81A27E
+827E827FA26D80A26D806D80A26D806D80A26D816D816E806E806E806E6E97B6FC6E806E
+806E03C0606E816F02F8606F02FE60030F6E606F03E0173F030103F85F6F03FF933801FF
+FC043F03E00307497E040F03FF033F497E040304FC0107B5EAE00F040093B8487E053FF2
+0001050F07FCEB007F050107F0141FDD003F06C01407060795C81201DE007F04F8ED0070
+0703048093C8FCDF000302E0CDFC>157 146 115 271 183 I[<BC0207BB12F8A9C70003
+03C0CC001F4AC8FCB3B3B395BEFCA906C0CC121FB3B3B3A6BC0207BB12F8A9>165
+142 120 269 182 I[<BC12C0A9C7000103E0C8FCB3B3B3B3B3B3B0BC12C0A9>74
+142 122 269 87 I[<BC12F8A9C7000303C0CEFCB3B3B3B3A5F8FF80A4672100A667A368
+A21F07A41F0FA3555AA21F3FA21F7FA21FFFA2666668666666666653B5FC65650B1F5C1D
+7F0A03B6FC1C1F0903B7FCC1FCA468A5>121 142 120 269 140
+76 D[<B900E04EB912F884848484A2848585C700037094C7000302FCC7FC73DF000F90C8
+FC7C5A85858585A27081708170817081868270817081708187837181718171817181A271
+8171817181728188847281728172817281A2728172817381738189857381738173818985
+73817481748174818A867481748174818A8675817581758175818B877581758175818C88
+7681768176817681A276817681768177158021C0897715E07715F07715F87715FCA27715
+FE7715FF7815877815C722E78A7815F77815FF8AA28A8A8B8B8BA28B8B8B8BA28B8C8C8C
+8CA28C8C8C8CA28D8D8D8D8DA24A6D8849B500FE88B900FC86227FA2223F221F220F2207
+A27C5A>165 142 120 269 182 78 D[<97B512F0077FECFFE00607B712FE067FEEFFE0
+0503B912FC051FF0FF80057F19E00403BB12FC040F9226E0007F14FF043F02FCC7000315
+C04C02E0DA007F804BB60080031F14F8030702FCC9000314FE4B4A70804B02E0706C8003
+7F0280051F14E092B6CB6C804A4A72804A4A72804A02F00600804A4A737F4A4A73804A8B
+4A4A738091B6CD6C80494A7480A2494A7480494A7480498C4C86498D4C87498D494A7580
+A290B68B4C87488EA24892CF6C80A3488E4B88A2488EA3484A761580A34823C0A5484A76
+15E0A7B621F0B36C23E0A26F64A56C23C0A46F646C2380A36C23006F64A26C6AA270636C
+6AA26C6A70636C6A70636D69A26D6E98B65AA26D6E505DA26D6E5092C7FC6D6870626D6E
+505C6D686D6F4F5C6E6E4F5C6E6E4F5CA26E6E96B65A6E6E4E92C8FC6E6E4E5C020102FF
+060F14F86E6F4D5C6F6E4D5C6F02F094B65A030F6E4C92C9FC6F02FE04075C03016E6C03
+1F14F86F03F092B65A043F02FE020715C0040FDAFFF090B7CAFC040392B812FC04001AF0
+051F198005074ECBFCDD007F17E0060F94CCFCDE007F15E0070002F0CDFC>148
+146 115 271 175 I[<BE12F8F5FFF01EFF1FE01FFCF7FF8020E020F820FEC700030380
+C8000781E2003F15C00B03810B00810C3F8078800C07807880788178818E8B8E8B8E8B8E
+A28EA28B8EA42380AC2300A46A67A26AA26A676A676A9CB65A6A665492C7FC545C0C1F5C
+545C9BB612E00B075D0B3F5D0A07B648C8FC95BB12F820E0208055C9FC1FF09CCAFC1EF0
+0BF8CBFC06C0D0FCB3B3B2BCFCA9>137 142 120 269 159 I[<BD12FCF4FFFCF5FFE01E
+FCF6FFC01FF01FFE797E20E0C700030380C86C15F80A0181E2003F14FF0B07810B0115E0
+776C8078807880788078808A78818E7881A28E8B8EA37980A48EAA6AA3676AA26AA29CB6
+5AA26A545D9FCAFC66545C545C545C545C9BB612C0535D0B074ACBFC0B3F5C52B612F00A
+7F15C095BBCCFC1FF81FC054CDFC66F6FF801FE00680C7000315F8E1003F14FE0A0F800A
+0315C07681766C807780778077808C7781898D898D898DA38A8DAD8DACA1EB1FC0A1EB3F
+E08D8AA37880A1137FA114C078817818FF7C1580785F786F1500BB00FE6F6F5B796E495A
+7902FEEB1FFC799139FFC07FF80D0792B55A0D015F796C5E0E1F5E0E034BC7FCD4001F14
+F8E7003F13C0>163 144 120 269 173 82 D[<93260FFFF8163E4BB600E0153F031F03
+FE5D037FDBFFC05C0203B800F05B020F05FC5B4A05FF5B027FF0C00F91B526FE000FECF0
+1F010302C0D9007F6D5A4991C800076D5A4901FC030090B6FC4901F0163F4949160F4901
+808290B5170192CBFC4849844849181F87484984A2484984874886A248498588A24887A3
+88A2B58680A36E85A280A26E8580A2818103F0725A6C6E96C7FC15FE8116E06C15FEEEFF
+E017FF6C17F0F0FF806C18F8F1FFC06C19FCF2FF806C1AE01BF86C1AFE6C747E6D1AE088
+6D866D866D1AFF6D876D87010087806E86020F86020386020086153F030F851501DB001F
+19801601DC000F18C0EF007F060717E0F0003F070316F0F1003F1A0F080315F81A00871B
+1F877514FCA287007F86486C85A288A388A36D86A31EF87FA37F1EF0A26D626D1CE0A27F
+6D5013C0A26E1B806E96B5FC6E1B0002F8606E4E5B6E626E6C5F03E04D5B03F84D5B03FE
+057F5BDBFFC093B55A04F803035C496CD9FF80021F91C7FCD9FC1F02FF49B55AD9F80792
+B75A496C19F049C66149011F18804901074DC8FC90C817F848031F16C048030003FCC9FC
+007C04011480>102 146 115 271 129 I[<000FC312F8A6488EA304C0C7001F4AC71201
+03F8C8F0000F03C01C0192C9737E02FC1E1F4A1E0702E08A4A8A4A8A4890CA757EA24920
+3F49201FA349200FA2492007A4492003007F8EA4498CA848487A1380A6CC99C7FCB3B3B3
+B3AA030FBD12FCA9>145 140 120 267 162 I[<BC040FB912C0A9C7000303C0CD001F02
+E0C7FC9E26007FF8C8FC7C5AB3B3B3B3B36E555AA3848022FF6BA26F65726481696F9CC9
+FC72626F66210F6F6E505AA26F6E505A6F535A6F6E1AFF734E5B706E4E5B70637002F04E
+5B706E063F90CAFC706E4E5A7002FF4D485A04006F04075B7102E0043F5B7102FC4BB55A
+050FDAFF80020F14807103FC0103B6CBFC050192B812FC716C61061F19E0060319800600
+06FCCCFC071F17F007011780DF001F03F8CDFCE0001F49CEFC>162
+144 120 269 179 I<93B512FC037FECFFF00207B8FC023F17E091B912F84918FE010772
+7E499126C0007F14E04901E0C7000F80496D020380496D020014FE6F6F7F90B570806F6F
+8085486E6F807380A27380A28885886C5CA26D4982886D5B6D5B010713C0010190CAFC90
+CCFCA90603B7FC050FB8FC0403B9FC167F0307BAFC153F4AB7EA807F020FEDE000023F02
+FCC7FC91B612E0010392C8FC4914FC011F14F04914C0495C90B548C9FC485C485C485C48
+5C5A5D485CA24891CAFCA3B6FC5CA397B6FCA461806C60F107EF6C6E150F6F16CF6C183F
+6FDB7F8F806C6EDBFF0F14E06C02FCDA03FE15FE6C6E91260FFC0791B5FC6C6E6CD93FF8
+17806C923AF803FFF003013F91B6487E010FEF8000010394C77E010004FC141F021F03F0
+140702010380DA007F1400DA000701F8CDFC695F79DD71>97 D[<ED1FF0017FB5FCB7FC
+A9EA003F1307A27FB3B296383FFFC00607B512FE063FECFFE04DB712F8050716FF051F17
+C0057F17F094B5D8C00F8004F301FCC714FE04F701E0023F7F93B50080020F804DC86C14
+E005F80301804D6F804D707F05808294CA804C717F4C7180A24C71808BA27680A28B88A2
+8BA28BA3888BA52080B02000A56764A267A3676467A2525CA267647062704D91C7FC704D
+5BA2714C5B7193B55A05F04B5CDCBFF84B5CDC1FFC030F5C4B6CB44B91C8FC7001C0027F
+5B4B6C01F00103B55A4BC601FF013F14F04B6D90B712C04B011F94C9FC4B6D16FC4B0103
+16F092C86C15804A030F02F8CAFC90CB49CBFC>113 144 121 270
+129 I<94387FFFF0041FB612E093B712FE0307707E031F17F092B97E4A18FE020784021F
+9126F8000F14804A0280010014C04A49C74814E049B500F85C494A17F0494A5C495C494A
+4A14F84991C8FC5D495B90B5FC5D5A485C7314F05A4B6F14E05A7314C0487214804B9338
+3FFE00F20FF84896C8FCA4485CA5B6FCB07EA281A37EA36C80A37E6F18FE6CF201FFA26C
+6E5F1CFE6C801B076C6EEF0FFC6D7F70EE1FF86DF13FF06D6E167F6D6EEEFFE06D02F84B
+13C06D6E5D6D02FF030F13806D03C0023F1300023F02F0903801FFFC6E9126FF801F5B02
+0792B65A6E18C0020060033F4CC7FC030716F8030016C0041F4AC8FCDC007F13C0585F78
+DD67>I[<F53FE098B6FC4FB7FCA996C77E1B0FA287B3B294383FFF80040FB512FC93B712
+80030716E0031F16F8037F16FE4AB9128702074AC66C13C7021F02E0010713F74A91C890
+B6FC4A01FC153F49B548150F4902E081494A81494A814991CA7E495B8749498390B54883
+5A5D5AA2485CA25A5D5AA35AA25D5AA5B6FCB07EA57E81A37EA27EA2817EA26C80A26C62
+6C6E5F636D7F6D6D94B6FC6D606D6D1607705D6D6E4B81010102F0157F6D6E92B712FE6E
+01FE020301EF91B512806E6D6C011F13CF020FDAF801B5120F020391B612FE6E17F86E6C
+16E0030F16800301EDFC00DB003F14E0040049C74AC8FC>113 144
+120 270 129 I<94387FFFC0040FB6FC93B712E0030716FC031F16FF037F17C04AB912F0
+0207DAF80380021F912680003F13FE4A49C7000F7F4A01F802038049B5486E804902C06E
+6C7F494A6F7F4991C9FC49727F4949707F4B84498490B548707F5A4B198048855D481CC0
+86481CE05D5A871DF05AA25D5AA21DF887A2B6FCA392BBFCA51DF00380CDFCA77EA4817E
+A37EA2817EA26CF307F06FF00FF87E816C1B1F6F19F06C1B3F6D6DF07FE06D7FF4FFC06D
+6E4C13806D6E5E6D02F04C13006D6EEE1FFE6D6E4C5A6D6C01FFEEFFF86E02E002035B6E
+02FC021F5B02079126FFC003B55A6E92B7C7FC020060033F17F8030F17E003011780DB00
+3F03FCC8FC040315C0DC000F01F8C9FC5D5F7ADD6A>I[<95383FFF80050FB512F094B612
+FE040781041F16C0047F824BB87E0307DAF8077F031FDAC00F7F4B49C6487F4B495B92B5
+00F0814A4A5B4A5C4A93B612805F4A91C7FC5C5E5C5E5C731400A24C6E5B91B56F5BA273
+5B070313E00700138097C8FCB3A4BA12F8A9C702FCCBFCB3B3B3B3A2003FB9FCA9>81
+144 121 271 71 I<F5FFC093260FFFFC030F13F04BB600E0027F7F031F03FE49B512FE
+037F9226FF8007800203B8EAF01F020FDDFC3F15804A7148133F027FDA003F90B500F014
+C091B500F80107ED807F4902E00101ECFC00010702806D6C5B93C87E49496F7F49496F7F
+49496F6D6D1380491A8077130090B5486F6E6C5AF503F84875C8FCA2484A6F80A44887AB
+6C63A46C6E4B5CA26C63A26D6D4B5CA26D97C9FC6D6D4B5B6D6D4B5B6D6D4B5B705C0101
+02E049B512E06D02F801075C4902FF013F5C4992B648CAFC496002F317F090260FE07F16
+80031F4BCBFC90261FC00115E0DB000F01FCCCFC013F91CFFCA3137FA280A380A2808080
+6E7E15F092B812F06DF0FFE01BFEF3FFC06D1AF81CFE767E6D1BE06D87896D1BFE6D877F
+6E878A0103BD7E130F013F8890BEFC4802E0C9003F814891CBFC4801FC180F4849060180
+4849727E484985884849737F88A2B55A88A66E616C65A26E616C6D4F5B6C656E616C6D4F
+5B6C6D96B55A6C6D6C05035C6F5FC602F0051F49C7FC6D01FC057F5B6DD9FF800303B55A
+010F02F8033F14E06DDAFFE0010FB65A010192B9C8FCD9003F19F8020F19E0020196C9FC
+DA001F17F0030194CAFCDB000192CBFC6A887ADD74>I[<ED1FF0017FB5FCB7FCA9EA003F
+1307A27FB3B2963803FFFC073FEBFFE096B612F8060715FE061F6F7E4E16E095B87E4DD9
+FC03804DD9C000804D48C76C7FDD0FF880DD1FE0824D486E804D5A05FEC881DCF1FC815F
+04F385EEF7F04D81EEFFC0A24D84A294C9FCA25EA35EA45EB3B3AFB9D8E001B912C0A9>
+114 143 119 270 129 I[<EC3FC0ECFFF0010313FC497F497F498049804980A290B67E
+A24881A86C5DA26D5CA26D5C6D5C6D91C8FC6D5B6D5B010013F0EC3FC091CAFCB3A3ED1F
+F0017FB5FCB7FCA9EA003F1307A27FB3B3B3B0B91280A9>49 144
+119 271 65 I[<ED1FF0017FB5FCB7FCA9EA003F1307A27FB3B3B3B3B3B3ACB912C0A9>
+50 143 119 270 65 108 D<DB3FE0912601FFFC943801FFFC017FB5031FD9FFE0041FEB
+FFE0B792B600FC93B612FC060303FF030315FF060F04C0020F16C0063F04F0023F16F095
+B86C91B87E4DD9FC036E49D9FC03804DD9C0006E49D9C000804D48C7003F6D4948C7003F
+7FDD0FF86EDB0FF880D8003F4B48714848830107DB3FC06E9126C03FC06E804D484E5A6D
+4BC86F48C881DCE1FE6FDAE1FE814D61DCE3F8DEF3F884DCE7F0F0F7F04D6F4B81DCEFC0
+F0FFC0A2DCFF804F84A294C993C9FCA24C61A34C61A44C61B3B3AFB900E090B900E090B9
+12E0A9B35D77DCC2>I<DB3FE0913803FFFC017FB5033FEBFFE0B792B612F8060715FE06
+1F6F7E4E16E095B87E4DD9FC03804DD9C000804D48C76C7FDD0FF880D8003FDB1FE08201
+074B486E804D5A6D03FEC881DCE1FC815F04E385EEE7F04D81EEEFC0A2DCFF8084A294C9
+FCA25EA35EA45EB3B3AFB9D8E001B912C0A9725D77DC81>I<94381FFFF00407B612C004
+7F15FC0303B87E030F17E0037F17FC4ABAFC4A9126FC007F80020F02C0010714E04A49C8
+80027F01F8033F13FC91B5486F7F4902C003077F494A6F804991C96C8049497080494971
+7F49874949717FA290B548717F48884B83481D80A2481DC04B83481DE0A2481DF0A3484A
+7114F8A4481DFCA5B61BFEAF6C1DFCA56C6E4D14F8A36C1DF0A36C1DE06F5F6C1DC0A26C
+6E4D1480A26C1D006F5F6C646D6D4D5B6F94B5FC6D636D6D4C5C6D6E4B5C6D6E4B5C6D02
+F0031F5C6D6E4B91C7FC6D6C01FE92B512FC6ED9FFC001075C6E02FC017F5C020791B812
+C0020196C8FC6E6C17FC031F17F003031780DB007F03FCC9FC040715C0DC001F01F0CAFC
+675F7ADD74>I<DB1FF091381FFFC0017FB50203B6FCB7021F15E095B712FC050316FF05
+0F17C0053F17F094B912FC04F1DAC01F8004F79026FC00018093B500E06D6C14C0D8003F
+93C86C8001074B030F8005F86F806D03E06F804D6F804D8194CA6C7F4C864C71805E7680
+A27680A27680A28B88A28BA288A28BA4882080B0200064A467A26467A3525CA267646764
+67647062704D91C7FC7094B55AA2714B5C714B5C714B5C05F84B5C71033F5C05FF4B91C8
+FC06C049B55A04FB01F001075C04F801FF017F14F07190B712C0051F94C9FC7116FC0503
+16F0DD007F1580060F02F8CAFC060049CBFC96CDFCB3ACB912E0A9718579DC81>I<DB7F
+C049B47E90B6021F13F8B7027F13FE4DB67E4D15E04D814D814D01077F94263FF00F7F94
+387FC01F4D48487FD8003F16000107DAC1FE491480EEC3FC6D5DEEC7F05F16CF5F16DF4D
+6D1400A204FFC76C5BA2735B4C6E5B735B070013C04C92C8FCA45EA65EB3B3AAB912FCA9
+515D79DC5F>114 D<92261FFFF814F80203B638C001FC023FEDFC0791B8121F010317FF
+130F013F9038F8001F4990C8FCD9FFF8153F4801E0150F484915034849814890CAFC197F
+4848173F191F485AA2007F180FA31907487EA27FA28002E0705A6E93C8FC14FC14FF15F0
+6CECFF8016FCEEFFF06CEEFF8018F06C17FE727E6C18E0856C18FC6C846C727E6C856D84
+011F846D841303010084023F83140F020183EC001FDB007F16801603DC000F15C0170018
+3F060F14E0007F1703486C82727E857F85857FA2857F1BC07FA27F1B806D5F7F1B006E5E
+6E5F6E163F6E4C5A02FC4C5A6E03035B6E6C4A5B03F0023F5B03FF0107B55A01F991B7C7
+FCD9F07F16FCD9E01F16F0D9800716C0D9000193C8FC48D9003F14F8007C020349C9FC4B
+5F78DD5C>I[<ED03FEA81507A5150FA4151FA3153FA2157FA215FFA25CA25C5CA25C5C5C
+5C91B5FC13035B131F017F91B712F00007BAFCBBFCA7C74AC9FCB3B3AAF101FFB1616E17
+FE82A219076E17FC836EEE0FF871131F6E6EEB3FF071137F6E6EEBFFE06EDAFF0313C06E
+92B512806E1700033F5D6F5D03075D030015E0041F1480040001FCC7FC>72
+132 124 258 90 I<DB0FF8F01FF0017FB594B6FCB74BB7FCA9D8003F94C77E0107190F
+A26D85B3B3B063A463A263A27F6398B6FCA26DF001FB7015036EEF07F3E00FE3806E6D15
+1FE07FC314FF6E6D6CDAFF83EDFFC06E6E010313036E02FCEB3FFE6E91B612FC020017F8
+6F16E0031F16800303EDFE00DB007F14F8040102C093C8FC725E77DC81>I<B90303B7FC
+A9D8000702F8CA000FEBFE006D6E050013E0666D6E6164826D5090C7FC836E4F5AA26E6E
+4C5AA26E6E4C5AA26E6E5F1C3F836E4F5A836E4F5AA26E6E4B5BA26E6E4B90C8FCA26F6E
+5D1B07846F4D5A846F4D5AA26F6E4A5AA26F6E4A5AA26F6E5D1BFF846F4C5B846F4C90C9
+FCA2706E485AA27002C05B1A0F7002E05B1A1F19F0704B5A19F8704B5AA2706E485AA270
+6E5B96B5FC7093CAFCA3715CA2715CA2715CA2715CA3715CA2715CA2715CA27191CBFCA2
+725AA3725A725A725A705D7BDB7B>I<007FB86C49B712FEA9C792C9000F02C0C7FC6E6E
+030101F0C8FC715F6E6E4B5B6E6E4B5B6E4E90C9FC6E6E5E71151F6E6E4B5A6E6E4B5A6E
+4E5A6F6E495B72495B6F6E495B6F806F6E4990CAFC6F4C5A72495A6F6E495A6F6E495A6F
+03815B705E7014C307E75B7091B5CBFC705D705D705D6282705D715C8386718071807180
+837180864D814D815F4D81874D814D81DDFFF3804C13E14C01C1804C0180814E6C804C6E
+804C487F4C48824C486D804C486D804B496D804B497F73804B49834B90C86C804B486F80
+4B48814B486F804B48844C6F804A71804A496F804A49814A90CA814A487180023F728001
+0FB500E07080B8031FB812E0A9735C7CDB7B>120 D<007FB800C04AB71280A9D800034A
+CA000791C7FC6D080013F0775A6D6E4E5AA26E6E6064836E4F90C8FC836E4F5A836E4F5A
+A26E6E4C5AA26E6E5F1C3F6E6E5F1C7F836E4F5A846F4D5B846F4D90C9FCA26F6E4A5AA2
+6F6E5D1B0F846F4D5A846F4D5A846F4D5AA26F6E4A5AA2706E5C627002C091CAFC6219E0
+704B5A19F0704B5AA2706E485AA2706E485AA27002FE5B1A7F19FF704B5AA2715DA27192
+CBFCA2715CA2715CA3715CA2715CA2715CA2715CA2725BA27290CCFCA3725AA2725AA24E
+5AA24E5AA261187FA24E5AA24D5B13FE2603FF804A90CDFC000F13E0486D4A5A487F486D
+4A5AA260B56C141F4D5AA24D5A17FF604C5B4A4990CEFC6C5D4C5A6C49EB3FFC4A495A6C
+4948485A9026FE80075B270FFFC03F5B6C90B6CFFC6C5D6C15F86C6C5C011F14C0010749
+D0FC9038007FE071857CDB7B>I<0003BC12F81CFCA51CF80480C7123F03F0C84814F048
+028018E04AC9B612C04A5D02F04B15804A19004E5C4A5D4A4B5C6391C9485C604993B65A
+634D5D495D98C7FC4D5C4D5C000F5E62494B5C4D5C94B6FC624C5D4C92C8FC5EC95D4C5C
+5E4C5C614C5C93B6FC4B5D614B92C9FC5D4B5C604B5C5D4B4AEC07FC6092B65A5C604A92
+C8EA0FF84A5C5C5F4A5C4A5C4A181F5F91B65A495D491AF094C9123F495C5B494A167F5E
+494A16FF496090B65A4C5D484B5D484F13E04892C95A4B5E484A93B5FC481803484A151F
+4B0203B6FC4891BAFCBDFCA21CC0A47E565C7ADB67>I E
+%EndDVIPSBitmapFont
+end
+%%EndProlog
+%%BeginSetup
+%%Feature: *Resolution 600dpi
+TeXDict begin
+
+%%EndSetup
+%%Page: 1 1
+1 0 bop 240 1799 a Fm(CFITSIO)76 b(User's)g(Reference)i(Guide)727
+2258 y Fl(An)53 b(In)l(terface)f(to)i(FITS)g(F)-13 b(ormat)53
+b(Files)1263 2518 y(for)h(C)f(Programmers)1667 3013 y
+Fk(V)-10 b(ersion)38 b(2.5)1727 3916 y Fj(HEASAR)m(C)1764
+4029 y(Co)s(de)30 b(662)1363 4142 y(Go)s(ddard)f(Space)i(Fligh)m(t)f
+(Cen)m(ter)1522 4255 y(Green)m(b)s(elt,)g(MD)i(20771)1857
+4367 y(USA)1561 5239 y Fk(Decem)m(b)s(er)37 b(2004)p
+eop
+%%Page: 2 2
+2 1 bop 0 299 a Fj(ii)p eop
+%%Page: 3 3
+3 2 bop 0 1267 a Fm(Con)-6 b(ten)g(ts)0 1858 y Fi(1)84
+b(In)m(tro)s(duction)3136 b(1)136 2020 y Fj(1.1)125 b(A)30
+b(Brief)g(Ov)m(erview)84 b(.)46 b(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h
+(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)
+g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)131 b(1)136 2182
+y(1.2)94 b(Sources)30 b(of)h(FITS)f(Soft)m(w)m(are)h(and)f(Information)
+37 b(.)46 b(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g
+(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)131 b(1)136 2344 y(1.3)94
+b(Ac)m(kno)m(wledgemen)m(ts)60 b(.)46 b(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f
+(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)
+h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)131 b(2)136 2506
+y(1.4)94 b(Legal)31 b(Stu\013)92 b(.)46 b(.)g(.)f(.)h(.)g(.)f(.)h(.)g
+(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)
+g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)131
+b(3)0 2766 y Fi(2)119 b(Creating)34 b(the)h(CFITSIO)e(Library)2256
+b(5)136 2928 y Fj(2.1)94 b(Building)28 b(the)i(Library)57
+b(.)45 b(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)
+g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g
+(.)f(.)131 b(5)345 3090 y(2.1.1)106 b(Unix)30 b(Systems)44
+b(.)h(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g
+(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)
+f(.)131 b(5)345 3252 y(2.1.2)106 b(VMS)33 b(.)46 b(.)g(.)f(.)h(.)g(.)f
+(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)
+h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)131
+b(7)345 3413 y(2.1.3)106 b(Windo)m(ws)30 b(PCs)g(.)45
+b(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f
+(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)
+131 b(7)345 3575 y(2.1.4)106 b(Macin)m(tosh)31 b(PCs)55
+b(.)46 b(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)
+f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f
+(.)131 b(7)136 3737 y(2.2)94 b(T)-8 b(esting)31 b(the)f(Library)i(.)46
+b(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g
+(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)
+f(.)131 b(8)136 3899 y(2.3)94 b(Linking)29 b(Programs)h(with)f(CFITSIO)
+45 b(.)g(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)
+g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)131 b(9)136
+4061 y(2.4)94 b(Getting)31 b(Started)g(with)e(CFITSIO)60
+b(.)46 b(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)
+h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)131
+b(9)136 4223 y(2.5)94 b(Example)30 b(Program)86 b(.)46
+b(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g
+(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)
+f(.)85 b(10)0 4483 y Fi(3)119 b(A)35 b(FITS)f(Primer)2917
+b(13)0 4742 y(4)119 b(Programming)35 b(Guidelines)2482
+b(15)136 4904 y Fj(4.1)94 b(CFITSIO)29 b(De\014nitions)42
+b(.)j(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g
+(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)
+f(.)85 b(15)136 5066 y(4.2)94 b(Curren)m(t)30 b(Header)h(Data)h(Unit)d
+(\(CHDU\))87 b(.)46 b(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f
+(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85
+b(17)136 5228 y(4.3)94 b(F)-8 b(unction)31 b(Names)f(and)g(V)-8
+b(ariable)30 b(Datat)m(yp)s(es)41 b(.)46 b(.)g(.)g(.)f(.)h(.)g(.)f(.)h
+(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85
+b(18)136 5390 y(4.4)94 b(Supp)s(ort)29 b(for)h(Unsigned)f(In)m(tegers)i
+(and)f(Signed)f(Bytes)86 b(.)46 b(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h
+(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85 b(19)136 5552
+y(4.5)94 b(Dealing)31 b(with)e(Character)h(Strings)60
+b(.)46 b(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)
+h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85
+b(21)136 5714 y(4.6)94 b(Implicit)28 b(Data)k(T)m(yp)s(e)e(Con)m(v)m
+(ersion)64 b(.)46 b(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g
+(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85
+b(22)1912 5942 y(iii)p eop
+%%Page: 4 4
+4 3 bop 0 299 a Fj(iv)3310 b Fh(CONTENTS)136 555 y Fj(4.7)94
+b(Data)32 b(Scaling)87 b(.)46 b(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g
+(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)
+f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85 b(22)136
+720 y(4.8)94 b(Supp)s(ort)29 b(for)h(IEEE)g(Sp)s(ecial)e(V)-8
+b(alues)67 b(.)45 b(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g
+(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85
+b(23)136 885 y(4.9)94 b(Error)30 b(Status)g(V)-8 b(alues)31
+b(and)e(the)i(Error)e(Message)j(Stac)m(k)44 b(.)i(.)f(.)h(.)g(.)g(.)f
+(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85
+b(23)136 1049 y(4.10)49 b(V)-8 b(ariable-Length)31 b(Arra)m(ys)f(in)f
+(Binary)h(T)-8 b(ables)30 b(.)46 b(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g
+(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85
+b(24)136 1214 y(4.11)49 b(Multiple)29 b(Access)i(to)g(the)g(Same)f
+(FITS)g(File)f(.)45 b(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h
+(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85
+b(25)136 1379 y(4.12)49 b(When)31 b(the)f(Final)f(Size)h(of)h(the)f
+(FITS)g(HDU)h(is)e(Unkno)m(wn)34 b(.)45 b(.)h(.)g(.)g(.)f(.)h(.)g(.)f
+(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85 b(26)136
+1543 y(4.13)49 b(CFITSIO)29 b(Size)h(Limitations)39 b(.)46
+b(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g
+(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85
+b(26)0 1817 y Fi(5)f(Basic)36 b(CFITSIO)d(In)m(terface)h(Routines)2074
+b(29)136 1982 y Fj(5.1)94 b(CFITSIO)29 b(Error)h(Status)g(Routines)88
+b(.)45 b(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)
+g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85 b(29)136
+2146 y(5.2)94 b(FITS)30 b(File)g(Access)h(Routines)f(.)46
+b(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g
+(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85
+b(30)136 2311 y(5.3)94 b(HDU)32 b(Access)f(Routines)71
+b(.)46 b(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)
+f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f
+(.)85 b(33)136 2476 y(5.4)94 b(Header)31 b(Keyw)m(ord)f(Read/W)-8
+b(rite)32 b(Routines)39 b(.)45 b(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)
+g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85
+b(35)345 2640 y(5.4.1)106 b(Keyw)m(ord)30 b(Reading)g(Routines)64
+b(.)46 b(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)
+f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85 b(35)345
+2805 y(5.4.2)106 b(Keyw)m(ord)30 b(W)-8 b(riting)30 b(Routines)85
+b(.)46 b(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)
+f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85 b(37)136
+2970 y(5.5)94 b(Primary)29 b(Arra)m(y)i(or)f(IMA)m(GE)i(Extension)d
+(I/O)h(Routines)53 b(.)45 b(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f
+(.)h(.)g(.)f(.)h(.)g(.)f(.)85 b(39)136 3135 y(5.6)94
+b(Image)32 b(Compression)e(.)46 b(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h
+(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)
+g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85 b(42)136 3299
+y(5.7)94 b(ASCI)s(I)29 b(and)h(Binary)g(T)-8 b(able)30
+b(Routines)84 b(.)46 b(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g
+(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85
+b(45)345 3464 y(5.7.1)106 b(Create)32 b(New)e(T)-8 b(able)83
+b(.)46 b(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)
+g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85
+b(45)345 3629 y(5.7.2)106 b(Column)29 b(Information)g(Routines)h(.)46
+b(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g
+(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85 b(46)345 3793 y(5.7.3)106
+b(Routines)30 b(to)h(Edit)e(Ro)m(ws)i(or)f(Columns)38
+b(.)46 b(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)
+f(.)h(.)g(.)f(.)h(.)g(.)f(.)85 b(48)345 3958 y(5.7.4)106
+b(Read)31 b(and)f(W)-8 b(rite)30 b(Column)f(Data)j(Routines)65
+b(.)46 b(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)
+f(.)h(.)g(.)f(.)85 b(50)345 4123 y(5.7.5)106 b(Ro)m(w)31
+b(Selection)f(and)g(Calculator)f(Routines)87 b(.)46 b(.)g(.)f(.)h(.)g
+(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85
+b(51)136 4287 y(5.8)94 b(Utilit)m(y)30 b(Routines)c(.)45
+b(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f
+(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)
+h(.)g(.)f(.)85 b(53)345 4452 y(5.8.1)106 b(File)30 b(Chec)m(ksum)g
+(Routines)46 b(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g
+(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85
+b(53)345 4617 y(5.8.2)106 b(Date)32 b(and)e(Time)f(Utilit)m(y)h
+(Routines)89 b(.)46 b(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g
+(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85 b(54)345
+4781 y(5.8.3)106 b(General)31 b(Utilit)m(y)e(Routines)j(.)46
+b(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g
+(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85 b(56)0
+5055 y Fi(6)119 b(The)35 b(CFITSIO)e(Iterator)g(F)-9
+b(unction)2154 b(63)136 5220 y Fj(6.1)94 b(The)30 b(Iterator)i(W)-8
+b(ork)31 b(F)-8 b(unction)44 b(.)h(.)h(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g
+(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)
+f(.)h(.)g(.)f(.)85 b(64)136 5385 y(6.2)94 b(The)30 b(Iterator)i(Driv)m
+(er)e(F)-8 b(unction)77 b(.)46 b(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)
+h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h
+(.)g(.)f(.)85 b(66)136 5549 y(6.3)94 b(Guidelines)28
+b(for)i(Using)g(the)g(Iterator)i(F)-8 b(unction)44 b(.)i(.)g(.)f(.)h(.)
+g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g
+(.)f(.)85 b(67)136 5714 y(6.4)94 b(Complete)31 b(List)e(of)i(Iterator)g
+(Routines)61 b(.)46 b(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g
+(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85
+b(68)p eop
+%%Page: 5 5
+5 4 bop 0 299 a Fh(CONTENTS)3334 b Fj(v)0 555 y Fi(7)119
+b(Celestial)34 b(Co)s(ordinate)h(System)f(Routines)1882
+b(71)136 717 y Fj(7.1)125 b(Self-con)m(tained)30 b(W)m(CS)g(Routines)e
+(.)46 b(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f
+(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85
+b(72)0 978 y Fi(8)119 b(Hierarc)m(hical)36 b(Grouping)g(Routines)2163
+b(75)136 1140 y Fj(8.1)94 b(Grouping)29 b(T)-8 b(able)30
+b(Routines)86 b(.)46 b(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h
+(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)
+g(.)f(.)85 b(76)136 1302 y(8.2)94 b(Group)30 b(Mem)m(b)s(er)g(Routines)
+g(.)46 b(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)
+h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85
+b(78)0 1563 y Fi(9)119 b(Sp)s(ecialized)36 b(CFITSIO)d(In)m(terface)h
+(Routines)1777 b(81)136 1725 y Fj(9.1)94 b(FITS)30 b(File)g(Access)h
+(Routines)f(.)46 b(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g
+(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)
+f(.)85 b(81)136 1887 y(9.2)94 b(HDU)32 b(Access)f(Routines)71
+b(.)46 b(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)
+f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f
+(.)85 b(84)136 2049 y(9.3)94 b(Sp)s(ecialized)29 b(Header)h(Keyw)m(ord)
+h(Routines)73 b(.)45 b(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h
+(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85
+b(86)345 2211 y(9.3.1)106 b(Header)31 b(Information)e(Routines)63
+b(.)46 b(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)
+h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85 b(86)345 2373
+y(9.3.2)106 b(Read)31 b(and)f(W)-8 b(rite)30 b(the)h(Required)e(Keyw)m
+(ords)51 b(.)46 b(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f
+(.)h(.)g(.)f(.)h(.)g(.)f(.)85 b(86)345 2536 y(9.3.3)106
+b(W)-8 b(rite)31 b(Keyw)m(ord)f(Routines)25 b(.)46 b(.)f(.)h(.)g(.)f(.)
+h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f
+(.)h(.)g(.)f(.)h(.)g(.)f(.)85 b(88)345 2698 y(9.3.4)106
+b(Insert)30 b(Keyw)m(ord)g(Routines)88 b(.)45 b(.)h(.)g(.)f(.)h(.)g(.)g
+(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)
+f(.)h(.)g(.)f(.)85 b(90)345 2860 y(9.3.5)106 b(Read)31
+b(Keyw)m(ord)f(Routines)44 b(.)i(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)
+g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g
+(.)f(.)85 b(91)345 3022 y(9.3.6)106 b(Mo)s(dify)29 b(Keyw)m(ord)i
+(Routines)k(.)45 b(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g
+(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85
+b(92)345 3184 y(9.3.7)106 b(Up)s(date)31 b(Keyw)m(ord)f(Routines)25
+b(.)45 b(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)
+g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85 b(93)136
+3346 y(9.4)94 b(De\014ne)31 b(Data)h(Scaling)d(and)h(Unde\014ned)f
+(Pixel)g(P)m(arameters)43 b(.)j(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f
+(.)h(.)g(.)f(.)h(.)g(.)f(.)85 b(94)136 3508 y(9.5)94
+b(Sp)s(ecialized)29 b(FITS)g(Primary)g(Arra)m(y)i(or)f(IMA)m(GE)h
+(Extension)f(I/O)g(Routines)54 b(.)46 b(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)
+85 b(95)136 3670 y(9.6)94 b(Sp)s(ecialized)29 b(FITS)g(ASCI)s(I)g(and)h
+(Binary)f(T)-8 b(able)30 b(Routines)86 b(.)46 b(.)g(.)g(.)f(.)h(.)g(.)f
+(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85 b(99)345
+3832 y(9.6.1)106 b(General)31 b(Column)d(Routines)50
+b(.)45 b(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)
+g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85 b(99)345
+3994 y(9.6.2)106 b(Lo)m(w-Lev)m(el)32 b(T)-8 b(able)30
+b(Access)h(Routines)39 b(.)46 b(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f
+(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)40
+b(100)345 4156 y(9.6.3)106 b(W)-8 b(rite)31 b(Column)e(Data)j(Routines)
+51 b(.)46 b(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f
+(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)40 b(100)345
+4318 y(9.6.4)106 b(Read)31 b(Column)d(Data)k(Routines)71
+b(.)46 b(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)
+h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)40 b(102)0 4579
+y Fi(10)67 b(Extended)35 b(File)f(Name)g(Syn)m(tax)2278
+b(105)136 4741 y Fj(10.1)49 b(Ov)m(erview)83 b(.)46 b(.)g(.)g(.)f(.)h
+(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)
+g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g
+(.)f(.)40 b(105)136 4903 y(10.2)49 b(Filet)m(yp)s(e)60
+b(.)45 b(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)
+g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g
+(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)40 b(108)345 5066
+y(10.2.1)61 b(Notes)32 b(ab)s(out)e(HTTP)g(pro)m(xy)g(serv)m(ers)k(.)46
+b(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f
+(.)h(.)g(.)f(.)h(.)g(.)f(.)40 b(108)345 5228 y(10.2.2)61
+b(Notes)32 b(ab)s(out)e(the)h(ro)s(ot)f(\014let)m(yp)s(e)67
+b(.)46 b(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)
+h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)40 b(108)345
+5390 y(10.2.3)61 b(Notes)32 b(ab)s(out)e(the)h(shmem)e(\014let)m(yp)s
+(e:)69 b(.)46 b(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h
+(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)40 b(110)136 5552
+y(10.3)49 b(Base)32 b(Filename)88 b(.)45 b(.)h(.)g(.)f(.)h(.)g(.)g(.)f
+(.)h(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)
+h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)40
+b(111)136 5714 y(10.4)49 b(Output)30 b(File)f(Name)i(when)f(Op)s(ening)
+e(an)i(Existing)f(File)79 b(.)45 b(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g
+(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)40 b(113)p eop
+%%Page: 6 6
+6 5 bop 0 299 a Fj(vi)3310 b Fh(CONTENTS)136 555 y Fj(10.5)49
+b(T)-8 b(emplate)31 b(File)f(Name)h(when)e(Creating)h(a)h(New)f(File)55
+b(.)46 b(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)
+f(.)h(.)g(.)f(.)40 b(114)136 721 y(10.6)49 b(Image)32
+b(Tile-Compression)27 b(Sp)s(eci\014cation)89 b(.)45
+b(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g
+(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)40 b(114)136 887 y(10.7)49
+b(HDU)32 b(Lo)s(cation)e(Sp)s(eci\014cation)45 b(.)g(.)h(.)g(.)f(.)h(.)
+g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g
+(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)40 b(115)136 1053
+y(10.8)49 b(Image)32 b(Section)38 b(.)46 b(.)f(.)h(.)g(.)f(.)h(.)g(.)g
+(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)
+f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)40
+b(116)136 1219 y(10.9)49 b(Column)29 b(and)h(Keyw)m(ord)g(Filtering)e
+(Sp)s(eci\014cation)89 b(.)45 b(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f
+(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)40 b(117)136
+1385 y(10.10)t(Ro)m(w)31 b(Filtering)e(Sp)s(eci\014cation)80
+b(.)45 b(.)h(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)
+g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)40
+b(118)345 1551 y(10.10.1)16 b(General)31 b(Syn)m(tax)44
+b(.)i(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f
+(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)
+40 b(119)345 1718 y(10.10.2)16 b(Bit)31 b(Masks)43 b(.)j(.)g(.)f(.)h(.)
+g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g
+(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)40
+b(121)345 1884 y(10.10.3)16 b(V)-8 b(ector)32 b(Columns)91
+b(.)46 b(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)
+h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)40
+b(122)345 2050 y(10.10.4)16 b(Go)s(o)s(d)30 b(Time)g(In)m(terv)-5
+b(al)30 b(Filtering)59 b(.)46 b(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g
+(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)40
+b(123)345 2216 y(10.10.5)16 b(Spatial)29 b(Region)i(Filtering)56
+b(.)46 b(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)
+h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)40
+b(124)345 2382 y(10.10.6)16 b(Example)30 b(Ro)m(w)h(Filters)f(.)45
+b(.)h(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f
+(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)40
+b(126)136 2548 y(10.11)35 b(Binning)28 b(or)i(Histogramming)g(Sp)s
+(eci\014cation)f(.)46 b(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g
+(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)40 b(127)0
+2828 y Fi(11)32 b(T)-9 b(emplate)34 b(Files)2933 b(131)136
+2994 y Fj(11.1)49 b(Detailed)31 b(T)-8 b(emplate)30 b(Line)g(F)-8
+b(ormat)48 b(.)e(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)
+g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)40
+b(131)136 3160 y(11.2)49 b(Auto-indexing)29 b(of)i(Keyw)m(ords)73
+b(.)45 b(.)h(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)
+g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)40
+b(132)136 3326 y(11.3)49 b(T)-8 b(emplate)31 b(P)m(arser)g(Directiv)m
+(es)85 b(.)45 b(.)h(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h
+(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)40
+b(133)136 3492 y(11.4)49 b(F)-8 b(ormal)31 b(T)-8 b(emplate)31
+b(Syn)m(tax)j(.)46 b(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)
+h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h
+(.)g(.)f(.)40 b(133)136 3658 y(11.5)49 b(Errors)63 b(.)46
+b(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g
+(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)
+g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)40 b(134)136 3824 y(11.6)49
+b(Examples)71 b(.)46 b(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g
+(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)
+f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)40 b(134)0
+4105 y Fi(12)67 b(Lo)s(cal)35 b(FITS)g(Con)m(v)m(en)m(tions)2462
+b(137)136 4271 y Fj(12.1)49 b(64-Bit)32 b(Long)f(In)m(tegers)61
+b(.)45 b(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)
+g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g
+(.)f(.)40 b(137)136 4437 y(12.2)49 b(Long)31 b(String)e(Keyw)m(ord)h(V)
+-8 b(alues.)64 b(.)46 b(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f
+(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)
+40 b(138)136 4603 y(12.3)49 b(Arra)m(ys)31 b(of)f(Fixed-Length)h
+(Strings)d(in)h(Binary)h(T)-8 b(ables)77 b(.)46 b(.)f(.)h(.)g(.)g(.)f
+(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)40
+b(139)136 4769 y(12.4)49 b(Keyw)m(ord)31 b(Units)e(Strings)40
+b(.)46 b(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)
+f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f
+(.)40 b(139)136 4935 y(12.5)49 b(HIERAR)m(CH)31 b(Con)m(v)m(en)m(tion)g
+(for)f(Extended)g(Keyw)m(ord)g(Names)91 b(.)46 b(.)f(.)h(.)g(.)f(.)h(.)
+g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)40 b(140)136 5101
+y(12.6)49 b(Tile-Compressed)29 b(Image)i(F)-8 b(ormat)52
+b(.)46 b(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)
+h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)40
+b(140)0 5382 y Fi(13)67 b(Optimizing)34 b(Programs)2588
+b(143)136 5548 y Fj(13.1)49 b(Ho)m(w)32 b(CFITSIO)c(Manages)k(Data)g
+(I/O)78 b(.)46 b(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)
+h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)40
+b(143)136 5714 y(13.2)49 b(Optimization)29 b(Strategies)76
+b(.)46 b(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)
+h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)40
+b(144)p eop
+%%Page: 7 7
+7 6 bop 0 299 a Fh(CONTENTS)3284 b Fj(vii)0 555 y Fi(A)57
+b(Index)35 b(of)g(Routines)2789 b(147)0 806 y(B)62 b(P)m(arameter)34
+b(De\014nitions)2598 b(151)0 1057 y(C)60 b(CFITSIO)33
+b(Error)i(Status)f(Co)s(des)2255 b(157)p eop
+%%Page: 8 8
+8 7 bop 0 299 a Fj(viii)3258 b Fh(CONTENTS)p eop
+%%Page: 1 9
+1 8 bop 0 1225 a Fg(Chapter)65 b(1)0 1687 y Fm(In)-6
+b(tro)6 b(duction)0 2216 y Ff(1.1)180 b(A)45 b(Brief)g(Ov)l(erview)0
+2495 y Fj(CFITSIO)38 b(is)h(a)h(mac)m(hine-indep)s(enden)m(t)e(library)
+f(of)j(routines)e(for)i(reading)f(and)g(writing)e(data)k(\014les)d(in)h
+(the)0 2608 y(FITS)c(\(Flexible)f(Image)i(T)-8 b(ransp)s(ort)34
+b(System\))h(data)h(format.)56 b(It)35 b(can)h(also)f(read)g(IRAF)h
+(format)f(image)h(\014les)0 2721 y(and)g(ra)m(w)h(binary)e(data)i(arra)
+m(ys)g(b)m(y)g(con)m(v)m(erting)h(them)e(on)h(the)g(\015y)f(in)m(to)h
+(a)g(virtual)e(FITS)h(format)h(\014le.)59 b(This)0 2833
+y(library)30 b(is)i(written)g(in)f(ANSI)i(C)f(and)g(pro)m(vides)g(a)h
+(p)s(o)m(w)m(erful)e(y)m(et)j(simple)d(in)m(terface)i(for)g(accessing)g
+(FITS)f(\014les)0 2946 y(whic)m(h)j(will)f(run)h(on)h(most)h(commonly)f
+(used)g(computers)g(and)g(w)m(orkstations.)59 b(CFITSIO)35
+b(supp)s(orts)f(all)i(the)0 3059 y(features)26 b(describ)s(ed)d(in)h
+(the)h(o\016cial)g(NOST)f(de\014nition)f(of)j(the)f(FITS)g(format)h
+(and)e(can)i(read)f(and)g(write)g(all)f(the)0 3172 y(curren)m(tly)d
+(de\014ned)f(t)m(yp)s(es)i(of)g(extensions,)h(including)18
+b(ASCI)s(I)j(tables)g(\(T)-8 b(ABLE\),)23 b(Binary)e(tables)h(\(BINT)-8
+b(ABLE\))0 3285 y(and)27 b(IMA)m(GE)h(extensions.)39
+b(The)27 b(CFITSIO)f(routines)g(insulate)g(the)h(programmer)g(from)g
+(ha)m(ving)f(to)i(deal)f(with)0 3398 y(the)e(complicated)f(formatting)h
+(details)e(in)g(the)i(FITS)f(\014le,)h(ho)m(w)m(ev)m(er,)j(it)c(is)f
+(assumed)h(that)h(users)f(ha)m(v)m(e)i(a)f(general)0
+3511 y(kno)m(wledge)30 b(ab)s(out)g(the)h(structure)f(and)g(usage)h(of)
+f(FITS)g(\014les.)0 3671 y(CFITSIO)k(also)i(con)m(tains)h(a)f(set)h(of)
+f(F)-8 b(ortran)36 b(callable)f(wrapp)s(er)g(routines)f(whic)m(h)h
+(allo)m(w)h(F)-8 b(ortran)36 b(programs)0 3784 y(to)31
+b(call)e(the)h(CFITSIO)e(routines.)40 b(See)30 b(the)g(companion)f
+(\\FITSIO)g(User's)h(Guide")f(for)h(the)g(de\014nition)e(of)i(the)0
+3897 y(F)-8 b(ortran)39 b(subroutine)c(calling)i(sequences.)63
+b(These)38 b(wrapp)s(ers)e(replace)i(the)g(older)f(F)-8
+b(ortran)39 b(FITSIO)d(library)0 4010 y(whic)m(h)29 b(is)h(no)g(longer)
+g(supp)s(orted.)0 4170 y(The)20 b(CFITSIO)f(pac)m(k)-5
+b(age)23 b(w)m(as)e(initially)d(dev)m(elop)s(ed)i(b)m(y)g(the)h(HEASAR)
+m(C)g(\(High)g(Energy)f(Astroph)m(ysics)g(Science)0 4283
+y(Arc)m(hiv)m(e)34 b(Researc)m(h)h(Cen)m(ter\))f(at)h(the)f(NASA)g(Go)s
+(ddard)e(Space)j(Fligh)m(t)e(Cen)m(ter)h(to)h(con)m(v)m(ert)g(v)-5
+b(arious)33 b(existing)0 4396 y(and)25 b(newly)g(acquired)g
+(astronomical)h(data)g(sets)h(in)m(to)f(FITS)f(format)h(and)f(to)i
+(further)e(analyze)h(data)h(already)e(in)0 4509 y(FITS)i(format.)41
+b(New)28 b(features)g(con)m(tin)m(ue)g(to)h(b)s(e)e(added)h(to)g
+(CFITSIO)f(in)f(large)i(part)g(due)g(to)g(con)m(tributions)f(of)0
+4622 y(ideas)32 b(or)h(actual)g(co)s(de)g(from)f(users)g(of)h(the)g
+(pac)m(k)-5 b(age.)49 b(The)33 b(In)m(tegral)g(Science)f(Data)i(Cen)m
+(ter)f(in)f(Switzerland,)0 4734 y(and)h(the)g(XMM/ESTEC)h(pro)5
+b(ject)34 b(in)e(The)h(Netherlands)f(made)h(esp)s(ecially)f
+(signi\014can)m(t)g(con)m(tributions)g(that)0 4847 y(resulted)d(in)g
+(man)m(y)i(of)f(the)h(new)f(features)g(that)h(app)s(eared)f(in)f(v2.0)j
+(of)e(CFITSIO.)0 5322 y Ff(1.2)135 b(Sources)45 b(of)g(FITS)f(Soft)l(w)
+l(are)i(and)f(Information)0 5601 y Fj(The)22 b(latest)h(v)m(ersion)f
+(of)h(the)f(CFITSIO)f(source)i(co)s(de,)h(do)s(cumen)m(tation,)h(and)c
+(example)i(programs)f(are)h(a)m(v)-5 b(ailable)0 5714
+y(on)30 b(the)h(W)-8 b(orld-Wide)30 b(W)-8 b(eb)31 b(or)f(via)g(anon)m
+(ymous)g(ftp)g(from:)1927 5942 y(1)p eop
+%%Page: 2 10
+2 9 bop 0 299 a Fj(2)2452 b Fh(CHAPTER)30 b(1.)71 b(INTR)m(ODUCTION)382
+555 y Fe(http://heasarc.gsfc.nasa)o(.go)o(v/fi)o(tsio)382
+668 y(ftp://legacy.gsfc.nasa.g)o(ov/)o(soft)o(ware)o(/fi)o(tsio)o(/c)0
+902 y Fj(An)m(y)28 b(questions,)f(bug)g(rep)s(orts,)h(or)f(suggested)i
+(enhancemen)m(ts)f(related)f(to)i(the)e(CFITSIO)f(pac)m(k)-5
+b(age)30 b(should)c(b)s(e)0 1015 y(sen)m(t)31 b(to)g(the)g(primary)d
+(author:)382 1249 y Fe(Dr.)47 b(William)f(Pence)810 b(Telephone:)92
+b(\(301\))47 b(286-4599)382 1362 y(HEASARC,)e(Code)i(662)811
+b(E-mail:)45 b(pence@tetra.gsfc.nasa.gov)382 1475 y(NASA/Goddard)f
+(Space)j(Flight)f(Center)382 1588 y(Greenbelt,)f(MD)i(20771,)f(USA)0
+1822 y Fj(This)39 b(User's)j(Guide)e(assumes)h(that)h(readers)f
+(already)f(ha)m(v)m(e)j(a)f(general)f(understanding)d(of)k(the)f
+(de\014nition)0 1935 y(and)31 b(structure)g(of)h(FITS)e(format)i
+(\014les.)43 b(F)-8 b(urther)32 b(information)d(ab)s(out)j(FITS)f
+(formats)g(is)g(a)m(v)-5 b(ailable)31 b(from)g(the)0
+2048 y(FITS)h(Supp)s(ort)f(O\016ce)i(at)g Fe(http://fits.gsfc.nasa.gov)
+o Fj(.)42 b(In)32 b(particular,)g(the)h('NOST)f(FITS)g(Standard')0
+2161 y(giv)m(es)i(the)h(authoritativ)m(e)f(de\014nition)e(of)i(the)g
+(FITS)g(data)h(format,)g(and)f(the)g(`FITS)g(User's)g(Guide')f(pro)m
+(vides)0 2274 y(additional)28 b(historical)h(bac)m(kground)h(and)g
+(practical)g(advice)g(on)g(using)f(FITS)h(\014les.)0
+2434 y(The)38 b(HEASAR)m(C)g(also)h(pro)m(vides)e(a)i(v)m(ery)g
+(sophisticated)f(FITS)f(\014le)h(analysis)f(program)h(called)g(`Fv')h
+(whic)m(h)0 2547 y(can)34 b(b)s(e)f(used)g(to)h(displa)m(y)e(and)h
+(edit)g(the)h(con)m(ten)m(ts)i(of)e(an)m(y)g(FITS)f(\014le)f(as)i(w)m
+(ell)f(as)h(construct)g(new)f(FITS)g(\014les)0 2660 y(from)j(scratc)m
+(h.)61 b(The)36 b(displa)m(y)f(functions)g(in)g(Fv)i(allo)m(w)f(users)g
+(to)i(in)m(teractiv)m(ely)e(adjust)g(the)h(brigh)m(tness)f(and)0
+2773 y(con)m(trast)i(of)f(images,)h(pan,)g(zo)s(om,)h(and)d(blink)e
+(images,)39 b(and)d(measure)h(the)f(p)s(ositions)f(and)h(brigh)m
+(tnesses)g(of)0 2886 y(ob)5 b(jects)33 b(within)d(images.)46
+b(FITS)31 b(tables)h(can)h(b)s(e)e(displa)m(y)m(ed)g(lik)m(e)h(a)g
+(spread)g(sheet,)h(and)f(then)f(mo)s(di\014ed)f(using)0
+2999 y(p)s(o)m(w)m(erful)25 b(calculator)i(and)e(sorting)h(functions.)
+38 b(Fv)27 b(is)e(freely)h(a)m(v)-5 b(ailable)26 b(for)g(most)h(Unix)e
+(platforms,)i(Mac)g(PCs,)0 3112 y(and)34 b(Windo)m(ws)f(PCs.)52
+b(CFITSIO)33 b(users)h(ma)m(y)h(also)f(b)s(e)g(in)m(terested)h(in)e
+(the)h(FTOOLS)f(pac)m(k)-5 b(age)37 b(of)d(programs)0
+3225 y(that)27 b(can)f(b)s(e)g(used)f(to)i(manipulate)e(and)g(analyze)i
+(FITS)e(format)i(\014les.)38 b(Fv)27 b(and)e(FTOOLS)g(are)i(a)m(v)-5
+b(ailable)25 b(from)0 3337 y(their)k(resp)s(ectiv)m(e)i(W)-8
+b(eb)31 b(sites)f(at:)382 3572 y Fe(http://fv.gsfc.nasa.gov)382
+3685 y(http://heasarc.gsfc.nasa)o(.go)o(v/ft)o(ools)0
+4014 y Ff(1.3)135 b(Ac)l(kno)l(wledgemen)l(ts)0 4264
+y Fj(The)34 b(dev)m(elopmen)m(t)g(of)g(the)g(p)s(o)m(w)m(erful)f
+(features)h(in)f(CFITSIO)g(w)m(as)h(made)g(p)s(ossible)e(through)h
+(collab)s(orations)0 4377 y(with)d(man)m(y)h(p)s(eople)f(or)g
+(organizations)h(from)g(around)f(the)h(w)m(orld.)41 b(The)30
+b(follo)m(wing)g(in)f(particular)h(ha)m(v)m(e)i(made)0
+4490 y(esp)s(ecially)d(signi\014can)m(t)g(con)m(tributions:)0
+4650 y(Programmers)c(from)h(the)f(In)m(tegral)h(Science)g(Data)h(Cen)m
+(ter,)g(Switzerland)d(\(namely)-8 b(,)27 b(Jurek)d(Bork)m(o)m(wski,)k
+(Bruce)0 4763 y(O'Neel,)33 b(and)f(Don)h(Jennings\),)e(designed)g(the)i
+(concept)g(for)f(the)h(plug-in)d(I/O)i(driv)m(ers)f(that)i(w)m(as)g(in)
+m(tro)s(duced)0 4876 y(with)h(CFITSIO)f(2.0.)56 b(The)34
+b(use)h(of)g(`driv)m(ers')f(greatly)h(simpli\014ed)d(the)j(lo)m(w-lev)m
+(el)g(I/O,)g(whic)m(h)e(in)h(turn)g(made)0 4989 y(other)40
+b(new)f(features)i(in)d(CFITSIO)g(\(e.g.,)45 b(supp)s(ort)38
+b(for)h(compressed)h(FITS)f(\014les)g(and)g(supp)s(ort)f(for)i(IRAF)0
+5102 y(format)32 b(image)f(\014les\))g(m)m(uc)m(h)g(easier)h(to)g
+(implemen)m(t.)42 b(Jurek)31 b(Bork)m(o)m(wski)g(wrote)h(the)g(Shared)e
+(Memory)i(driv)m(er,)0 5215 y(and)23 b(Bruce)i(O'Neel)f(wrote)g(the)g
+(driv)m(ers)f(for)g(accessing)i(FITS)e(\014les)g(o)m(v)m(er)i(the)f
+(net)m(w)m(ork)h(using)d(the)j(FTP)-8 b(,)24 b(HTTP)-8
+b(,)0 5328 y(and)30 b(R)m(OOT)g(proto)s(cols.)0 5488
+y(The)45 b(ISDC)g(also)g(pro)m(vided)f(the)i(template)g(parsing)e
+(routines)g(\(written)h(b)m(y)g(Jurek)g(Bork)m(o)m(wski\))h(and)f(the)0
+5601 y(hierarc)m(hical)36 b(grouping)f(routines)h(\(written)h(b)m(y)g
+(Don)h(Jennings\).)59 b(The)37 b(ISDC)f(D)m(AL)i(\(Data)h(Access)f(La)m
+(y)m(er\))0 5714 y(routines)29 b(are)i(la)m(y)m(ered)g(on)f(top)h(of)f
+(CFITSIO)f(and)h(mak)m(e)h(extensiv)m(e)g(use)f(of)h(these)g(features.)
+p eop
+%%Page: 3 11
+3 10 bop 0 299 a Fh(1.4.)72 b(LEGAL)30 b(STUFF)2995 b
+Fj(3)0 555 y(Uw)m(e)25 b(Lammers)e(\(XMM/ESA/ESTEC,)h(The)g
+(Netherlands\))f(designed)g(the)h(high-p)s(erformance)e(lexical)h
+(pars-)0 668 y(ing)41 b(algorithm)g(that)h(is)f(used)g(to)i(do)e
+(on-the-\015y)h(\014ltering)e(of)i(FITS)f(tables.)75
+b(This)40 b(algorithm)h(essen)m(tially)0 781 y(pre-compiles)34
+b(the)i(user-supplied)c(selection)k(expression)e(in)m(to)i(a)g(form)g
+(that)g(can)g(b)s(e)f(rapidly)e(ev)-5 b(aluated)36 b(for)0
+894 y(eac)m(h)31 b(ro)m(w.)40 b(P)m(eter)31 b(Wilson)d(\(RSTX,)h
+(NASA/GSF)m(C\))i(then)e(wrote)h(the)g(parsing)e(routines)g(used)h(b)m
+(y)g(CFITSIO)0 1007 y(based)i(on)f(Lammers')h(design,)f(com)m(bined)g
+(with)g(other)h(tec)m(hniques)f(suc)m(h)h(as)g(the)g(CFITSIO)f
+(iterator)h(routine)0 1120 y(to)h(further)e(enhance)h(the)h(data)g(pro)
+s(cessing)e(throughput.)42 b(This)30 b(e\013ort)i(also)f(b)s
+(ene\014ted)f(from)h(a)h(m)m(uc)m(h)f(earlier)0 1233
+y(lexical)22 b(parsing)h(routine)f(that)i(w)m(as)g(dev)m(elop)s(ed)f(b)
+m(y)h(Ken)m(t)g(Blac)m(kburn)e(\(NASA/GSF)m(C\).)j(More)g(recen)m(tly)
+-8 b(,)26 b(Craig)0 1346 y(Markw)m(ardt)j(\(NASA/GSF)m(C\))g(implemen)m
+(ted)e(additional)f(functions)h(\(median,)h(a)m(v)m(erage,)k(stddev\))c
+(and)g(other)0 1458 y(enhancemen)m(ts)j(to)g(the)g(lexical)e(parser.)0
+1619 y(The)40 b(CFITSIO)g(iterator)h(function)e(is)h(lo)s(osely)g
+(based)h(on)f(similar)f(ideas)h(dev)m(elop)s(ed)g(for)h(the)g(XMM)g
+(Data)0 1732 y(Access)31 b(La)m(y)m(er.)0 1892 y(P)m(eter)25
+b(Wilson)e(\(RSTX,)h(NASA/GSF)m(C\))h(wrote)g(the)f(complete)h(set)f
+(of)h(F)-8 b(ortran-callable)24 b(wrapp)s(ers)e(for)i(all)f(the)0
+2005 y(CFITSIO)29 b(routines,)g(whic)m(h)g(in)g(turn)h(rely)f(on)i(the)
+f(CF)m(OR)-8 b(TRAN)31 b(macro)g(dev)m(elop)s(ed)f(b)m(y)g(Burkhard)f
+(Buro)m(w.)0 2165 y(The)h(syn)m(tax)i(used)e(b)m(y)h(CFITSIO)f(for)g
+(\014ltering)g(or)h(binning)c(input)i(FITS)i(\014les)f(is)g(based)g(on)
+h(ideas)g(dev)m(elop)s(ed)0 2278 y(for)41 b(the)g(AXAF)h(Science)f(Cen)
+m(ter)h(Data)h(Mo)s(del)d(b)m(y)h(Jonathan)g(McDo)m(w)m(ell,)k(An)m
+(tonella)c(F)-8 b(ruscione,)44 b(Aneta)0 2391 y(Siemigino)m(wsk)-5
+b(a)24 b(and)h(Bill)f(Jo)m(y)m(e.)41 b(See)26 b(h)m
+(ttp://heasarc.gsfc.nasa.go)m(v/do)s(cs/journal/axaf7.h)m(t)q(ml)31
+b(for)25 b(further)0 2503 y(description)j(of)j(the)g(AXAF)g(Data)h(Mo)s
+(del.)0 2664 y(The)j(\014le)f(decompression)g(co)s(de)h(w)m(ere)h(tak)m
+(en)g(directly)e(from)g(the)i(gzip)e(\(GNU)i(zip\))f(program)g(dev)m
+(elop)s(ed)f(b)m(y)0 2777 y(Jean-loup)29 b(Gailly)g(and)h(others.)0
+2937 y(The)e(new)h(compressed)g(image)g(data)h(format)f(\(where)g(the)g
+(image)g(is)f(tiled)g(and)g(the)h(compressed)g(b)m(yte)h(stream)0
+3050 y(from)k(eac)m(h)i(tile)f(is)e(stored)i(in)f(a)h(binary)e(table\))
+j(w)m(as)f(implemen)m(ted)e(in)h(collab)s(oration)g(with)f(Ric)m(hard)h
+(White)0 3163 y(\(STScI\),)c(P)m(erry)g(Green\014eld)g(\(STScI\))g(and)
+f(Doug)i(T)-8 b(o)s(dy)30 b(\(NO)m(A)m(O\).)0 3323 y(Doug)h(Mink)f
+(\(SA)m(O\))g(pro)m(vided)f(the)i(routines)e(for)h(con)m(v)m(erting)i
+(IRAF)e(format)h(images)f(in)m(to)h(FITS)e(format.)0
+3483 y(In)e(addition,)g(man)m(y)h(other)g(p)s(eople)f(ha)m(v)m(e)i
+(made)f(v)-5 b(aluable)27 b(con)m(tributions)f(to)j(the)f(dev)m
+(elopmen)m(t)g(of)g(CFITSIO.)0 3596 y(These)i(include)e(\(with)i(ap)s
+(ologies)g(to)h(others)f(that)h(ma)m(y)g(ha)m(v)m(e)h(inadv)m(erten)m
+(tly)e(b)s(een)f(omitted\):)0 3756 y(Stev)m(e)g(Allen,)e(Carl)g(Ak)m
+(erlof,)h(Keith)f(Arnaud,)h(Morten)g(Krabb)s(e)e(Barfo)s(ed,)j(Ken)m(t)
+f(Blac)m(kburn,)g(G)g(Bo)s(dammer,)0 3869 y(Romk)m(e)h(Bon)m(tek)m(o)s
+(e,)i(Lucio)c(Chiapp)s(etti,)f(Keith)h(Costorf,)h(Robin)f(Corb)s(et,)h
+(John)e(Da)m(vis,)j(Ric)m(hard)e(Fink,)h(Ning)0 3982
+y(Gan,)j(Emily)d(Greene,)j(Gretc)m(hen)g(Green,)f(Jo)s(e)g(Harrington,)
+g(Cheng)g(Ho,)h(Phil)d(Ho)s(dge,)i(Jim)f(Ingham,)h(Y)-8
+b(oshi-)0 4095 y(tak)j(a)44 b(Ishisaki,)g(Diab)f(Jerius,)h(Mark)g
+(Levine,)h(T)-8 b(o)s(dd)42 b(Karak)-5 b(askian,)46 b(Edw)m(ard)c
+(King,)j(Scott)f(Ko)s(c)m(h,)i(Claire)0 4208 y(Larkin,)c(Rob)f
+(Managan,)j(Eric)c(Mandel,)j(Ric)m(hard)d(Mathar,)k(John)c(Matto)m(x,)
+46 b(Carsten)41 b(Mey)m(er,)k(Emi)39 b(Miy-)0 4320 y(ata,)44
+b(Stefan)c(Mo)s(c)m(hnac)m(ki,)k(Mik)m(e)d(Noble,)h(Oliv)m(er)d(Ob)s
+(erdorf,)i(Cliv)m(e)e(P)m(age,)45 b(Arvind)38 b(P)m(armar,)43
+b(Je\013)e(P)m(edelt)m(y)-8 b(,)0 4433 y(Tim)31 b(P)m(earson,)j
+(Philipp)s(e)28 b(Prugniel,)j(Maren)h(Purv)m(es,)h(Scott)g(Randall,)f
+(Chris)e(Rogers,)k(Arnold)c(Rots,)k(Barry)0 4546 y(Sc)m(hlesinger,)h
+(Robin)f(Stebbins,)h(Andrew)f(Szymk)m(o)m(wiak,)j(Allyn)c(T)-8
+b(ennan)m(t,)37 b(P)m(eter)g(T)-8 b(eub)s(en,)35 b(James)h(Theiler,)0
+4659 y(Doug)c(T)-8 b(o)s(dy)g(,)32 b(Shiro)e(Ueno,)j(Stev)m(e)f(W)-8
+b(alton,)33 b(Arc)m(hie)f(W)-8 b(arno)s(c)m(k,)33 b(Alan)e(W)-8
+b(atson,)33 b(Dan)f(Whipple,)e(Wim)h(Wim-)0 4772 y(mers,)f(P)m(eter)i
+(Y)-8 b(oung,)31 b(Jianjun)d(Xu,)i(and)g(Nelson)g(Zarate.)0
+5216 y Ff(1.4)135 b(Legal)46 b(Stu\013)0 5488 y Fj(Cop)m(yrigh)m(t)36
+b(\(Unpublished{all)d(righ)m(ts)j(reserv)m(ed)h(under)e(the)i(cop)m
+(yrigh)m(t)g(la)m(ws)f(of)h(the)g(United)f(States\),)k(U.S.)0
+5601 y(Go)m(v)m(ernmen)m(t)30 b(as)g(represen)m(ted)e(b)m(y)h(the)g
+(Administrator)e(of)i(the)g(National)f(Aeronautics)h(and)f(Space)h
+(Adminis-)0 5714 y(tration.)41 b(No)31 b(cop)m(yrigh)m(t)f(is)g
+(claimed)f(in)g(the)i(United)e(States)i(under)e(Title)h(17,)h(U.S.)f
+(Co)s(de.)p eop
+%%Page: 4 12
+4 11 bop 0 299 a Fj(4)2452 b Fh(CHAPTER)30 b(1.)71 b(INTR)m(ODUCTION)0
+555 y Fj(P)m(ermission)28 b(to)i(freely)e(use,)i(cop)m(y)-8
+b(,)31 b(mo)s(dify)-8 b(,)28 b(and)h(distribute)e(this)h(soft)m(w)m
+(are)j(and)e(its)g(do)s(cumen)m(tation)g(without)0 668
+y(fee)g(is)e(hereb)m(y)h(gran)m(ted,)i(pro)m(vided)d(that)i(this)e(cop)
+m(yrigh)m(t)i(notice)f(and)g(disclaimer)e(of)i(w)m(arran)m(t)m(y)i(app)
+s(ears)d(in)g(all)0 781 y(copies.)41 b(\(Ho)m(w)m(ev)m(er,)33
+b(see)e(the)f(restriction)f(on)i(the)f(use)g(of)h(the)f(gzip)g
+(compression)g(co)s(de,)h(b)s(elo)m(w\).)0 941 y(DISCLAIMER:)0
+1101 y(THE)i(SOFTW)-10 b(ARE)32 b(IS)g(PR)m(O)m(VIDED)i('AS)f(IS')g
+(WITHOUT)f(ANY)i(W)-10 b(ARRANTY)33 b(OF)g(ANY)h(KIND,)f(EI-)0
+1214 y(THER)42 b(EXPRESSED,)f(IMPLIED,)i(OR)e(ST)-8 b(A)g(TUTOR)g(Y,)43
+b(INCLUDING,)f(BUT)h(NOT)e(LIMITED)h(TO,)0 1327 y(ANY)33
+b(W)-10 b(ARRANTY)33 b(THA)-8 b(T)32 b(THE)g(SOFTW)-10
+b(ARE)32 b(WILL)g(CONF)m(ORM)g(TO)g(SPECIFICA)-8 b(TIONS,)30
+b(ANY)0 1440 y(IMPLIED)38 b(W)-10 b(ARRANTIES)37 b(OF)h(MER)m(CHANT)-8
+b(ABILITY,)38 b(FITNESS)f(F)m(OR)h(A)g(P)-8 b(AR)g(TICULAR)38
+b(PUR-)0 1553 y(POSE,)24 b(AND)i(FREEDOM)f(FR)m(OM)h(INFRINGEMENT,)g
+(AND)f(ANY)h(W)-10 b(ARRANTY)25 b(THA)-8 b(T)25 b(THE)g(DOC-)0
+1666 y(UMENT)-8 b(A)g(TION)31 b(WILL)f(CONF)m(ORM)h(TO)e(THE)h(SOFTW)
+-10 b(ARE,)30 b(OR)g(ANY)h(W)-10 b(ARRANTY)31 b(THA)-8
+b(T)30 b(THE)0 1779 y(SOFTW)-10 b(ARE)31 b(WILL)h(BE)g(ERR)m(OR)g
+(FREE.)g(IN)g(NO)f(EVENT)h(SHALL)f(NASA)h(BE)g(LIABLE)g(F)m(OR)g(ANY)0
+1892 y(D)m(AMA)m(GES,)26 b(INCLUDING,)e(BUT)f(NOT)g(LIMITED)h(TO,)f
+(DIRECT,)g(INDIRECT,)g(SPECIAL)f(OR)h(CON-)0 2005 y(SEQUENTIAL)28
+b(D)m(AMA)m(GES,)k(ARISING)d(OUT)g(OF,)h(RESUL)-8 b(TING)29
+b(FR)m(OM,)h(OR)f(IN)h(ANY)g(W)-10 b(A)i(Y)30 b(CON-)0
+2118 y(NECTED)25 b(WITH)g(THIS)f(SOFTW)-10 b(ARE,)25
+b(WHETHER)g(OR)g(NOT)g(BASED)g(UPON)g(W)-10 b(ARRANTY,)26
+b(CON-)0 2230 y(TRA)m(CT,)d(TOR)-8 b(T)23 b(,)g(OR)g(OTHER)-10
+b(WISE,)22 b(WHETHER)i(OR)f(NOT)f(INJUR)-8 b(Y)24 b(W)-10
+b(AS)23 b(SUST)-8 b(AINED)23 b(BY)h(PER-)0 2343 y(SONS)h(OR)i(PR)m
+(OPER)-8 b(TY)26 b(OR)g(OTHER)-10 b(WISE,)26 b(AND)h(WHETHER)g(OR)f
+(NOT)g(LOSS)f(W)-10 b(AS)26 b(SUST)-8 b(AINED)0 2456
+y(FR)m(OM,)37 b(OR)e(AR)m(OSE)h(OUT)f(OF)h(THE)g(RESUL)-8
+b(TS)35 b(OF,)h(OR)f(USE)h(OF,)g(THE)g(SOFTW)-10 b(ARE)35
+b(OR)g(SER-)0 2569 y(VICES)29 b(PR)m(O)m(VIDED)j(HEREUNDER.")0
+2729 y(The)i(\014le)h(compress.c)g(con)m(tains)g(\(sligh)m(tly)f(mo)s
+(di\014ed\))f(source)i(co)s(de)g(that)h(originally)c(came)k(from)f
+(gzip-1.2.4,)0 2842 y(cop)m(yrigh)m(t)26 b(\(C\))g(1992-1993)k(b)m(y)c
+(Jean-loup)f(Gailly)-8 b(.)38 b(This)24 b(gzip)h(co)s(de)h(is)f
+(distributed)e(under)i(the)h(GNU)g(General)0 2955 y(Public)k(License)i
+(and)f(th)m(us)h(requires)f(that)i(an)m(y)f(soft)m(w)m(are)i(that)f
+(uses)f(the)g(CFITSIO)f(library)f(\(whic)m(h)h(in)g(turn)0
+3068 y(uses)e(the)g(gzip)g(co)s(de\))h(m)m(ust)f(conform)g(to)h(the)f
+(pro)m(visions)e(in)h(the)i(GNU)g(General)f(Public)e(License.)40
+b(A)29 b(cop)m(y)h(of)0 3181 y(the)h(GNU)g(license)e(is)g(included)f
+(at)j(the)g(b)s(eginning)c(of)k(compress.c)g(\014le.)0
+3341 y(An)h(alternate)i(v)m(ersion)e(of)h(the)g(compress.c)g(\014le)f
+(\(called)g(compress)p 2381 3341 28 4 v 33 w(alternate.c\))i(is)e(pro)m
+(vided)f(for)i(users)e(who)0 3454 y(w)m(an)m(t)24 b(to)g(use)e(the)i
+(CFITSIO)d(library)g(but)h(are)h(un)m(willing)d(or)j(unable)e(to)j
+(publicly)c(release)j(their)f(soft)m(w)m(are)i(under)0
+3567 y(the)i(terms)g(of)g(the)g(GNU)h(General)e(Public)f(License.)39
+b(This)24 b(alternate)i(v)m(ersion)g(con)m(tains)g(non-functional)e
+(stubs)0 3680 y(for)g(the)h(\014le)e(compression)h(and)f(uncompression)
+g(routines)g(used)h(b)m(y)g(CFITSIO.)f(Replace)i(the)f(\014le)g
+(`compress.c')0 3793 y(with)32 b(`compress)p 600 3793
+V 33 w(alternate.c')j(b)s(efore)e(compiling)e(the)i(CFITSIO)f(library)
+-8 b(.)48 b(This)31 b(will)g(pro)s(duce)h(a)i(v)m(ersion)f(of)0
+3906 y(CFITSIO)20 b(whic)m(h)h(do)s(es)g(not)h(supp)s(ort)e(reading)h
+(or)h(writing)e(compressed)h(FITS)g(\014les)g(but)g(is)g(otherwise)g
+(iden)m(tical)0 4019 y(to)31 b(the)g(standard)e(v)m(ersion.)p
+eop
+%%Page: 5 13
+5 12 bop 0 1225 a Fg(Chapter)65 b(2)0 1687 y Fm(Creating)77
+b(the)h(CFITSIO)e(Library)0 2216 y Ff(2.1)135 b(Building)45
+b(the)h(Library)0 2466 y Fj(The)h(CFITSIO)f(co)s(de)h(is)g(con)m
+(tained)g(in)f(ab)s(out)h(40)h(C)f(source)h(\014les)e(\(*.c\))j(and)e
+(header)g(\014les)f(\(*.h\).)93 b(On)0 2579 y(V)-10 b(AX/VMS)31
+b(systems)g(2)f(assem)m(bly-co)s(de)h(\014les)e(\(vmsieeed.mar)h(and)g
+(vmsieeer.mar\))h(are)f(also)h(needed.)0 2739 y(CFITSIO)e(has)h(curren)
+m(tly)f(b)s(een)h(tested)h(on)f(the)h(follo)m(wing)e(platforms:)95
+2959 y Fe(OPERATING)46 b(SYSTEM)523 b(COMPILER)143 3072
+y(Sun)47 b(OS)1002 b(gcc)47 b(and)g(cc)g(\(3.0.1\))143
+3185 y(Sun)g(Solaris)762 b(gcc)47 b(and)g(cc)143 3298
+y(Silicon)f(Graphics)g(IRIX)285 b(gcc)47 b(and)g(cc)143
+3411 y(Silicon)f(Graphics)g(IRIX64)189 b(MIPS)143 3523
+y(Dec)47 b(Alpha)f(OSF/1)572 b(gcc)47 b(and)g(cc)143
+3636 y(DECstation)93 b(Ultrix)428 b(gcc)143 3749 y(Dec)47
+b(Alpha)f(OpenVMS)476 b(cc)143 3862 y(DEC)47 b(VAX/VMS)762
+b(gcc)47 b(and)g(cc)143 3975 y(HP-UX)1049 b(gcc)143 4088
+y(IBM)47 b(AIX)954 b(gcc)143 4201 y(Linux)1049 b(gcc)143
+4314 y(MkLinux)953 b(DR3)143 4427 y(Windows)46 b(95/98/NT)523
+b(Borland)46 b(C++)h(V4.5)143 4540 y(Windows)f(95/98/NT/ME/XP)235
+b(Microsoft/Compaq)43 b(Visual)j(C++)h(v5.0,)g(v6.0)143
+4653 y(Windows)f(95/98/NT)523 b(Cygwin)46 b(gcc)143 4765
+y(MacOS)h(7.1)f(or)i(greater)332 b(Metrowerks)45 b(10.+)143
+4878 y(MacOS-X)h(10.1)h(or)g(greater)189 b(cc)47 b(\(gcc\))0
+5098 y Fj(CFITSIO)26 b(will)g(probably)g(run)g(on)i(most)g(other)h
+(Unix)d(platforms.)39 b(Cra)m(y)28 b(sup)s(ercomputers)e(are)j(curren)m
+(tly)e(not)0 5211 y(supp)s(orted.)0 5495 y Fd(2.1.1)112
+b(Unix)38 b(Systems)0 5714 y Fj(The)30 b(CFITSIO)f(library)f(is)h
+(built)f(on)j(Unix)e(systems)h(b)m(y)g(t)m(yping:)1927
+5942 y(5)p eop
+%%Page: 6 14
+6 13 bop 0 299 a Fj(6)1580 b Fh(CHAPTER)30 b(2.)112 b(CREA)-8
+b(TING)30 b(THE)g(CFITSIO)f(LIBRAR)-8 b(Y)48 555 y Fe(>)95
+b(./configure)45 b([--prefix=/target/insta)o(llat)o(ion)o(/pat)o(h])48
+668 y(>)95 b(make)476 b(\(or)95 b('make)46 b(shared'\))48
+781 y(>)95 b(make)47 b(install)93 b(\(this)46 b(step)h(is)g(optional\))
+0 1037 y Fj(at)24 b(the)g(op)s(erating)f(system)h(prompt.)38
+b(The)23 b(con\014gure)g(command)g(customizes)h(the)g(Mak)m(e\014le)g
+(for)g(the)g(particular)0 1150 y(system,)g(then)d(the)g(`mak)m(e')i
+(command)e(compiles)f(the)h(source)h(\014les)e(and)h(builds)d(the)j
+(library)-8 b(.)36 b(T)m(yp)s(e)21 b(`./con\014gure')0
+1263 y(and)34 b(not)h(simply)d(`con\014gure')j(to)h(ensure)e(that)h
+(the)g(con\014gure)g(script)e(in)h(the)h(curren)m(t)f(directory)g(is)g
+(run)g(and)0 1375 y(not)29 b(some)g(other)g(system-wide)f(con\014gure)g
+(script.)39 b(The)29 b(optional)f('pre\014x')g(argumen)m(t)h(to)g
+(con\014gure)g(giv)m(es)g(the)0 1488 y(path)f(to)i(the)f(directory)f
+(where)g(the)h(CFITSIO)f(library)e(and)i(include)f(\014les)g(should)g
+(b)s(e)h(installed)f(via)h(the)h(later)0 1601 y('mak)m(e)j(install')c
+(command.)41 b(F)-8 b(or)31 b(example,)143 1857 y Fe(>)48
+b(./configure)c(--prefix=/usr1/local)0 2113 y Fj(will)22
+b(cause)k(the)f('mak)m(e)h(install')d(command)i(to)h(cop)m(y)g(the)f
+(CFITSIO)e(lib)s(c\014tsio)f(\014le)j(to)g(/usr1/lo)s(cal/lib)e(and)i
+(the)0 2226 y(necessary)33 b(include)c(\014les)j(to)g(/usr1/lo)s
+(cal/include)f(\(assuming)g(of)h(course)g(that)h(the)f(pro)s(cess)g
+(has)g(p)s(ermission)0 2338 y(to)f(write)f(to)h(these)g(directories\).)
+0 2499 y(The)d('mak)m(e)h(shared')f(option)g(builds)d(a)k(shared)e(or)i
+(dynamic)e(v)m(ersion)h(of)g(the)h(CFITSIO)d(library)-8
+b(.)38 b(When)28 b(using)0 2612 y(the)f(shared)f(library)f(the)i
+(executable)g(co)s(de)g(is)f(not)h(copied)f(in)m(to)h(y)m(our)g
+(program)g(at)g(link)e(time)h(and)h(instead)f(the)0 2724
+y(program)h(lo)s(cates)h(the)g(necessary)g(library)d(co)s(de)j(at)g
+(run)e(time,)i(normally)e(through)g(LD)p 3065 2724 28
+4 v 33 w(LIBRAR)-8 b(Y)p 3514 2724 V 34 w(P)g(A)g(TH)28
+b(or)0 2837 y(some)j(other)f(metho)s(d.)41 b(The)29 b(adv)-5
+b(an)m(tages)33 b(of)d(using)f(a)i(shared)e(library)f(are:)143
+3093 y Fe(1.)95 b(Less)47 b(disk)f(space)h(if)g(you)g(build)f(more)h
+(than)f(1)i(program)143 3206 y(2.)95 b(Less)47 b(memory)f(if)h(more)g
+(than)f(one)h(copy)g(of)g(a)g(program)f(using)h(the)g(shared)334
+3319 y(library)f(is)h(running)f(at)h(the)g(same)g(time)f(since)h(the)g
+(system)f(is)h(smart)334 3432 y(enough)f(to)h(share)g(copies)f(of)h
+(the)g(shared)f(library)g(at)h(run)g(time.)143 3545 y(3.)95
+b(Possibly)46 b(easier)g(maintenance)e(since)j(a)g(new)g(version)f(of)h
+(the)g(shared)334 3658 y(library)f(can)h(be)g(installed)e(without)h
+(relinking)f(all)i(the)g(software)334 3770 y(that)g(uses)f(it)i(\(as)e
+(long)h(as)g(the)g(subroutine)e(names)i(and)f(calling)334
+3883 y(sequences)f(remain)h(unchanged\).)143 3996 y(4.)95
+b(No)47 b(run-time)f(penalty.)0 4252 y Fj(The)30 b(disadv)-5
+b(an)m(tages)31 b(are:)143 4508 y Fe(1.)47 b(More)g(hassle)f(at)h
+(runtime.)94 b(You)46 b(have)h(to)g(either)f(build)h(the)g(programs)286
+4621 y(specially)f(or)h(have)f(LD_LIBRARY_PATH)e(set)j(right.)143
+4733 y(2.)g(There)g(may)g(be)g(a)g(slight)f(start)h(up)g(penalty,)e
+(depending)h(on)h(where)f(you)h(are)286 4846 y(reading)f(the)h(shared)f
+(library)g(and)h(the)g(program)f(from)g(and)h(if)g(your)g(CPU)g(is)286
+4959 y(either)f(really)h(slow)f(or)h(really)f(heavily)g(loaded.)0
+5215 y Fj(On)32 b(Mac)i(OS)e(X)i(platforms)e(the)h('mak)m(e)h(shared')f
+(command)f(w)m(orks)h(lik)m(e)g(on)g(other)g(UNIX)g(platforms,)g(but)g
+(a)0 5328 y(.dylib)d(\014le)h(will)e(b)s(e)i(created)i(instead)f(of)g
+(.so.)46 b(If)31 b(installed)f(in)h(a)h(nonstandard)f(lo)s(cation,)h
+(add)f(its)h(lo)s(cation)f(to)0 5441 y(the)g(D)m(YLD)p
+422 5441 V 34 w(LIBRAR)-8 b(Y)p 872 5441 V 33 w(P)g(A)g(TH)31
+b(en)m(vironmen)m(t)f(v)-5 b(ariable)29 b(so)i(that)g(the)f(library)e
+(can)j(b)s(e)f(found)f(at)i(run)e(time.)0 5601 y(On)h(HP/UX)i(systems,)
+g(the)f(en)m(vironmen)m(t)g(v)-5 b(ariable)30 b(CFLA)m(GS)h(should)e(b)
+s(e)i(set)g(to)h(-Ae)g(b)s(efore)f(running)d(con-)0 5714
+y(\014gure)i(to)h(enable)f("extended)h(ANSI")f(features.)p
+eop
+%%Page: 7 15
+7 14 bop 0 299 a Fh(2.1.)72 b(BUILDING)31 b(THE)f(LIBRAR)-8
+b(Y)2507 b Fj(7)0 555 y(By)31 b(default,)g(a)g(set)h(of)f(F)-8
+b(ortran-callable)31 b(wrapp)s(er)e(routines)h(are)h(also)g(built)e
+(and)h(included)f(in)g(the)i(CFITSIO)0 668 y(library)-8
+b(.)68 b(If)40 b(these)g(wrapp)s(er)f(routines)g(are)h(not)h(needed)e
+(\(i.e.,)44 b(the)c(CFITSIO)f(library)e(will)h(not)i(b)s(e)g(link)m(ed)
+0 781 y(to)d(an)m(y)f(F)-8 b(ortran)37 b(applications)d(whic)m(h)h
+(call)g(FITSIO)g(subroutines\))f(then)i(they)g(ma)m(y)h(b)s(e)e
+(omitted)h(from)g(the)0 894 y(build)26 b(b)m(y)k(t)m(yping)f('mak)m(e)h
+(all-no\014tsio')f(instead)f(of)i(simply)d(t)m(yping)i('mak)m(e'.)42
+b(This)27 b(will)g(reduce)i(the)h(size)f(of)h(the)0 1007
+y(CFITSIO)f(library)f(sligh)m(tly)-8 b(.)0 1167 y(Most)37
+b(32-bit)g(op)s(erating)f(systems)g(ha)m(v)m(e)i(only)d(supp)s(orted)g
+(disk)g(\014les)g(up)g(to)i(2.1GB)i(\(2**31)g(b)m(ytes\))e(in)e(size.)0
+1280 y(Starting)c(with)f(v)m(ersion)h(2.1)h(of)g(CFITSIO,)e(FITS)h
+(\014les)f(larger)h(than)g(this)g(limit)e(\(up)i(to)h(6)g(terab)m
+(ytes\))h(can)f(b)s(e)0 1393 y(read)25 b(and)g(written)f(on)h
+(platforms)f(that)h(supp)s(ort)f(large)h(\014les)f(\(e.g.,)k(at)e
+(least)f(some)h(LINUX)f(platforms)f(and)h(So-)0 1506
+y(laris\).)36 b(T)-8 b(o)22 b(enable)e(this)g(feature,)j(CFITSIO)d(m)m
+(ust)h(b)s(e)f(compiled)f(with)h(the)h('-D)p 2731 1506
+28 4 v 34 w(LAR)m(GEFILE)p 3298 1506 V 33 w(SOUR)m(CE')g(and)0
+1619 y(`-D)p 129 1619 V 34 w(FILE)p 374 1619 V 32 w(OFFSET)p
+774 1619 V 32 w(BITS=64')g(compiler)e(\015ags.)37 b(Some)21
+b(platforms)e(ma)m(y)i(also)f(require)f(the)h(`-D)p 3380
+1619 V 34 w(LAR)m(GE)p 3736 1619 V 33 w(FILES')0 1732
+y(compiler)29 b(\015ag.)42 b(It)30 b(app)s(ears)g(that)h(in)e(most)i
+(cases)g(it)g(is)e(not)i(necessary)g(to)g(also)f(include)f(these)i
+(compiler)e(\015ags)0 1844 y(when)k(compiling)f(programs)h(that)i(link)
+d(to)i(the)g(CFITSIO)f(library)-8 b(.)49 b(See)34 b(the)g(`CFITSIO)f
+(Size)g(Limitations')0 1957 y(section)e(in)e(Chapter)g(4)i(for)f
+(further)f(details.)0 2118 y(It)g(ma)m(y)h(not)f(b)s(e)f(p)s(ossible)f
+(to)i(staticly)g(link)e(programs)i(that)g(use)g(CFITSIO)e(on)i(some)h
+(platforms)d(\(namely)-8 b(,)30 b(on)0 2230 y(Solaris)k(2.6\))j(due)e
+(to)i(the)e(net)m(w)m(ork)i(driv)m(ers)d(\(whic)m(h)h(pro)m(vide)g(FTP)
+g(and)g(HTTP)g(access)i(to)g(FITS)e(\014les\).)56 b(It)0
+2343 y(is)32 b(p)s(ossible)e(to)k(mak)m(e)f(b)s(oth)g(a)g(dynamic)e
+(and)h(a)i(static)f(v)m(ersion)f(of)h(the)g(CFITSIO)e(library)-8
+b(,)32 b(but)g(net)m(w)m(ork)i(\014le)0 2456 y(access)e(will)27
+b(not)k(b)s(e)f(p)s(ossible)e(using)h(the)h(static)h(v)m(ersion.)0
+2762 y Fd(2.1.2)112 b(VMS)0 2984 y Fj(On)28 b(V)-10 b(AX/VMS)31
+b(and)d(ALPHA/VMS)i(systems)f(the)h(mak)m(e)p 2100 2984
+V 34 w(g\015oat.com)h(command)e(\014le)f(ma)m(y)i(b)s(e)f(executed)h
+(to)0 3097 y(build)j(the)k(c\014tsio.olb)e(ob)5 b(ject)37
+b(library)d(using)h(the)h(default)g(G-\015oating)g(p)s(oin)m(t)g
+(option)f(for)h(double)f(v)-5 b(ariables.)0 3210 y(The)37
+b(mak)m(e)p 405 3210 V 33 w(d\015oat.com)i(and)d(mak)m(e)p
+1279 3210 V 34 w(ieee.com)i(\014les)f(ma)m(y)g(b)s(e)g(used)f(instead)h
+(to)h(build)c(the)j(library)e(with)h(the)0 3322 y(other)26
+b(\015oating)h(p)s(oin)m(t)e(options.)38 b(Note)28 b(that)f(the)f
+(getcwd)h(function)e(that)i(is)e(used)g(in)g(the)i(group.c)f(mo)s(dule)
+e(ma)m(y)0 3435 y(require)43 b(that)j(programs)e(using)f(CFITSIO)g(b)s
+(e)h(link)m(ed)g(with)f(the)i(ALPHA$LIBRAR)-8 b(Y:V)e(AX)m(CR)i(TL.OLB)
+0 3548 y(library)g(.)39 b(See)30 b(the)h(example)f(link)e(line)h(in)g
+(the)i(next)f(section)h(of)f(this)g(do)s(cumen)m(t.)0
+3854 y Fd(2.1.3)112 b(Windo)m(ws)37 b(PCs)0 4076 y Fj(A)28
+b(precompiled)e(DLL)i(v)m(ersion)f(of)h(CFITSIO)e(is)h(a)m(v)-5
+b(ailable)28 b(for)f(IBM-PC)h(users)g(of)g(the)g(Borland)f(or)h
+(Microsoft)0 4189 y(Visual)44 b(C++)g(compilers)g(in)g(the)i(\014les)e
+(c\014tsio)s(dll)p 1802 4189 V 31 w(2xxx)p 2022 4189
+V 33 w(b)s(orland.zip)e(and)j(c\014tsio)s(dll)p 3078
+4189 V 30 w(2xxx)p 3297 4189 V 33 w(v)m(cc.zip,)50 b(where)0
+4302 y('2xxx')45 b(represen)m(ts)f(the)g(curren)m(t)g(release)h(n)m(um)
+m(b)s(er.)81 b(These)44 b(zip)f(arc)m(hiv)m(es)h(also)h(con)m(tains)f
+(other)g(\014les)g(and)0 4414 y(instructions)28 b(on)i(ho)m(w)h(to)g
+(use)f(the)h(CFITSIO)d(DLL)j(library)-8 b(.)0 4575 y(The)28
+b(CFITSIO)g(library)e(ma)m(y)j(also)g(b)s(e)f(built)f(from)h(the)h
+(source)g(co)s(de)g(using)f(the)h(mak)m(e\014le.b)s(c)f(or)h(mak)m
+(e\014le.v)m(cc)0 4688 y(\014les.)54 b(Finally)-8 b(,)35
+b(the)g(mak)m(ep)s(c.bat)h(\014le)e(giv)m(es)i(an)f(example)g(of)g
+(building)c(CFITSIO)j(with)f(the)j(Borland)e(C++)0 4800
+y(v4.5)d(compiler)e(using)g(older)h(DOS)g(commands.)0
+5106 y Fd(2.1.4)112 b(Macin)m(tosh)38 b(PCs)0 5328 y
+Fj(When)30 b(building)d(on)j(Mac)h(OS-X,)g(users)e(should)g(follo)m(w)g
+(the)i(Unix)e(instructions,)f(ab)s(o)m(v)m(e.)0 5488
+y(The)h(classic)f(MacOS)h(v)m(ersion)g(\(OS)g(9)g(or)g(earlier\))f(of)i
+(the)f(CFITSIO)e(library)g(can)i(b)s(e)g(built)e(b)m(y)i(\(1\))h(un)e
+(binhex)0 5601 y(and)e(unstu\013)g(c\014tsio)p 714 5601
+V 33 w(mac.sit.hqx,)i(\(2\))g(put)e(CFitsioPPC.mcp)f(in)h(the)h
+(c\014tsio)g(directory)-8 b(,)28 b(and)e(\(3\))i(load)f(CFit-)0
+5714 y(sioPPC.mcp)i(in)m(to)i(Co)s(deW)-8 b(arrior)30
+b(Pro)g(5)h(and)f(mak)m(e.)42 b(This)29 b(builds)e(the)k(CFITSIO)e
+(library)f(for)i(PPC.)g(There)p eop
+%%Page: 8 16
+8 15 bop 0 299 a Fj(8)1580 b Fh(CHAPTER)30 b(2.)112 b(CREA)-8
+b(TING)30 b(THE)g(CFITSIO)f(LIBRAR)-8 b(Y)0 555 y Fj(are)31
+b(also)f(targets)i(for)e(b)s(oth)g(the)g(test)i(program)e(and)f(the)i
+(sp)s(eed)e(test)j(program.)0 715 y(T)-8 b(o)27 b(use)f(the)h(MacOS)g
+(p)s(ort)f(y)m(ou)h(can)g(add)f(C\014tsio)g(PPC.lib)e(to)j(y)m(our)g
+(Co)s(deW)-8 b(arrior)26 b(Pro)g(5)h(pro)5 b(ject.)40
+b(Note)28 b(that)0 828 y(this)h(only)h(has)g(b)s(een)g(tested)h(for)f
+(the)g(PPC)g(and)g(probably)e(w)m(on't)j(w)m(ork)g(on)f(68k)h(Macs.)0
+1162 y Ff(2.2)135 b(T)-11 b(esting)46 b(the)f(Library)0
+1412 y Fj(The)40 b(CFITSIO)e(library)g(should)g(b)s(e)h(tested)i(b)m(y)
+f(building)c(and)j(running)f(the)i(testprog.c)h(program)f(that)h(is)0
+1525 y(included)28 b(with)h(the)h(release.)41 b(On)30
+b(Unix)f(systems,)i(t)m(yp)s(e:)191 1782 y Fe(\045)47
+b(make)g(testprog)191 1895 y(\045)g(testprog)f(>)h(testprog.lis)191
+2008 y(\045)g(diff)g(testprog.lis)d(testprog.out)191
+2121 y(\045)j(cmp)g(testprog.fit)e(testprog.std)0 2378
+y Fj(On)30 b(VMS)g(systems,)g(\(assuming)g(cc)h(is)e(the)i(name)f(of)h
+(the)f(C)g(compiler)f(command\),)i(t)m(yp)s(e:)191 2636
+y Fe($)47 b(cc)h(testprog.c)191 2749 y($)f(link)g(testprog,)e
+(cfitsio/lib,)g(alpha$library:vaxcrtl/l)o(ib)191 2862
+y($)i(run)g(testprog)0 3119 y Fj(The)42 b(test)h(program)f(should)e
+(pro)s(duce)h(a)i(FITS)e(\014le)h(called)f(`testprog.\014t')j(that)f
+(is)e(iden)m(tical)g(to)i(the)f(`test-)0 3232 y(prog.std')35
+b(FITS)e(\014le)h(included)d(with)i(this)g(release.)53
+b(The)34 b(diagnostic)g(messages)h(\(whic)m(h)f(w)m(ere)h(pip)s(ed)d
+(to)j(the)0 3345 y(\014le)g(testprog.lis)h(in)f(the)i(Unix)e(example\))
+h(should)e(b)s(e)i(iden)m(tical)f(to)i(the)f(listing)e(con)m(tained)j
+(in)e(the)h(\014le)g(test-)0 3458 y(prog.out.)63 b(The)37
+b('di\013)7 b(')37 b(and)g('cmp')h(commands)g(sho)m(wn)f(ab)s(o)m(v)m
+(e)i(should)c(not)j(rep)s(ort)f(an)m(y)h(di\013erences)f(in)g(the)0
+3571 y(\014les.)64 b(\(There)38 b(ma)m(y)h(b)s(e)f(some)h(minor)e
+(format)i(di\013erences,)h(suc)m(h)e(as)h(the)g(presence)f(or)h
+(absence)g(of)f(leading)0 3684 y(zeros,)31 b(or)g(3)f(digit)g(exp)s
+(onen)m(ts)g(in)f(n)m(um)m(b)s(ers,)g(whic)m(h)g(can)i(b)s(e)f
+(ignored\).)0 3844 y(The)e(F)-8 b(ortran)30 b(wrapp)s(ers)d(in)g
+(CFITSIO)g(ma)m(y)j(b)s(e)e(tested)h(with)f(the)h(testf77)h(program)f
+(on)g(Unix)e(systems)i(with:)191 4101 y Fe(\045)47 b(f77)g(-o)g
+(testf77)f(testf77.f)g(-L.)g(-lcfitsio)g(-lnsl)g(-lsocket)95
+4214 y(or)191 4327 y(\045)h(f77)g(-f)g(-o)h(testf77)d(testf77.f)h(-L.)h
+(-lcfitsio)188 b(\(under)46 b(SUN)h(O/S\))95 4440 y(or)191
+4553 y(\045)g(f77)g(-o)g(testf77)f(testf77.f)g(-Wl,-L.)f(-lcfitsio)h
+(-lm)h(-lnsl)f(-lsocket)f(\(HP/UX\))191 4779 y(\045)i(testf77)f(>)i
+(testf77.lis)191 4892 y(\045)f(diff)g(testf77.lis)e(testf77.out)191
+5005 y(\045)i(cmp)g(testf77.fit)e(testf77.std)0 5262
+y Fj(On)31 b(mac)m(hines)g(running)f(SUN)h(O/S,)h(F)-8
+b(ortran)33 b(programs)e(m)m(ust)h(b)s(e)f(compiled)f(with)h(the)h('-f)
+7 b(')32 b(option)g(to)g(force)0 5375 y(double)24 b(precision)g(v)-5
+b(ariables)24 b(to)i(b)s(e)f(aligned)f(on)i(8-b)m(yte)h(b)s(oundarys)c
+(to)j(mak)m(e)h(the)e(fortran-declared)g(v)-5 b(ariables)0
+5488 y(compatible)32 b(with)f(C.)h(A)h(similar)d(compiler)h(option)h
+(ma)m(y)h(b)s(e)f(required)f(on)h(other)h(platforms.)47
+b(F)-8 b(ailing)31 b(to)i(use)0 5601 y(this)25 b(option)g(ma)m(y)h
+(cause)h(the)f(program)f(to)i(crash)e(on)h(FITSIO)f(routines)f(that)j
+(read)f(or)f(write)g(double)g(precision)0 5714 y(v)-5
+b(ariables.)p eop
+%%Page: 9 17
+9 16 bop 0 299 a Fh(2.3.)72 b(LINKING)30 b(PR)m(OGRAMS)h(WITH)f
+(CFITSIO)1975 b Fj(9)0 555 y(Also)30 b(note)h(that)f(on)g(some)h
+(systems,)f(the)h(output)e(listing)f(of)j(the)f(testf77)i(program)d(ma)
+m(y)i(di\013er)e(sligh)m(tly)f(from)0 668 y(the)j(testf77.std)h
+(template,)f(if)f(leading)f(zeros)i(are)g(not)g(prin)m(ted)e(b)m(y)i
+(default)f(b)s(efore)g(the)h(decimal)e(p)s(oin)m(t)h(when)0
+781 y(using)f(F)i(format.)0 941 y(A)37 b(few)f(other)g(utilit)m(y)f
+(programs)h(are)h(included)d(with)h(CFITSIO;)g(the)i(\014rst)e(four)h
+(of)g(this)g(programs)g(can)h(b)s(e)0 1054 y(compiled)c(an)i(link)m(ed)
+e(b)m(y)i(t)m(yping)f(`mak)m(e)i(program)p 1815 1054
+28 4 v 33 w(name')f(where)f(`program)p 2746 1054 V 33
+w(name')h(is)f(the)h(actual)g(name)g(of)0 1167 y(the)c(program:)191
+1467 y Fe(speed)46 b(-)i(measures)d(the)i(maximum)f(throughput)f(\(in)i
+(MB)g(per)g(second\))668 1580 y(for)g(writing)f(and)h(reading)f(FITS)g
+(files)h(with)f(CFITSIO.)191 1806 y(listhead)f(-)j(lists)e(all)h(the)g
+(header)f(keywords)g(in)h(any)g(FITS)f(file)191 2032
+y(fitscopy)f(-)j(copies)e(any)h(FITS)g(file)f(\(especially)f(useful)h
+(in)h(conjunction)811 2145 y(with)g(the)g(CFITSIO's)e(extended)h(input)
+g(filename)g(syntax\).)191 2371 y(cookbook)f(-)j(a)f(sample)f(program)g
+(that)h(performs)e(common)i(read)f(and)811 2483 y(write)h(operations)e
+(on)i(a)g(FITS)g(file.)191 2709 y(iter_a,)f(iter_b,)g(iter_c)g(-)h
+(examples)f(of)h(the)g(CFITSIO)f(iterator)f(routine)0
+3091 y Ff(2.3)135 b(Linking)45 b(Programs)h(with)f(CFITSIO)0
+3350 y Fj(When)25 b(linking)e(applications)h(soft)m(w)m(are)j(with)d
+(the)i(CFITSIO)e(library)-8 b(,)25 b(sev)m(eral)h(system)g(libraries)d
+(usually)g(need)0 3463 y(to)36 b(b)s(e)f(sp)s(eci\014ed)f(on)h(the)g
+(link)f(command)h(line.)54 b(On)34 b(Unix)h(systems,)i(the)e(most)h
+(reliable)d(w)m(a)m(y)k(to)f(determine)0 3576 y(what)26
+b(libraries)e(are)i(required)f(is)g(to)i(t)m(yp)s(e)f('mak)m(e)i
+(testprog')f(and)f(see)h(what)f(libraries)e(the)i(con\014gure)g(script)
+f(has)0 3689 y(added.)39 b(The)25 b(t)m(ypical)h(libraries)d(that)j
+(need)g(to)g(b)s(e)g(added)f(are)h(-lm)g(\(the)g(math)g(library\))e
+(and)h(-lnsl)f(and)i(-lso)s(c)m(k)m(et)0 3802 y(\(needed)k(only)f(for)h
+(FTP)g(and)f(HTTP)g(\014le)g(access\).)43 b(These)30
+b(latter)g(2)g(libraries)d(are)k(not)f(needed)g(on)g(VMS)g(and)0
+3915 y(Windo)m(ws)f(platforms,)h(b)s(ecause)g(FTP)h(\014le)e(access)j
+(is)d(not)i(curren)m(tly)e(supp)s(orted)g(on)h(those)h(platforms.)0
+4075 y(Note)i(that)g(when)e(upgrading)f(to)j(a)f(new)m(er)g(v)m(ersion)
+f(of)h(CFITSIO)f(it)g(is)g(usually)f(necessary)i(to)h(recompile,)f(as)0
+4188 y(w)m(ell)d(as)i(relink,)e(the)h(programs)g(that)h(use)f(CFITSIO,)
+f(b)s(ecause)i(the)f(de\014nitions)e(in)h(\014tsio.h)h(often)g(c)m
+(hange.)0 4569 y Ff(2.4)135 b(Getting)46 b(Started)g(with)f(CFITSIO)0
+4829 y Fj(In)27 b(order)h(to)g(e\013ectiv)m(ely)h(use)f(the)g(CFITSIO)e
+(library)g(it)h(is)g(recommended)h(that)g(new)f(users)h(b)s(egin)e(b)m
+(y)i(reading)0 4942 y(the)g(\\CFITSIO)g(Quic)m(k)f(Start)h(Guide".)40
+b(It)28 b(con)m(tains)g(all)g(the)g(basic)g(information)e(needed)i(to)h
+(write)e(programs)0 5055 y(that)d(p)s(erform)f(most)h(t)m(yp)s(es)g(of)
+g(op)s(erations)f(on)h(FITS)f(\014les.)38 b(The)23 b(set)i(of)f
+(example)f(FITS)h(utilit)m(y)e(programs)h(that)0 5168
+y(are)29 b(a)m(v)-5 b(ailable)28 b(from)g(the)g(CFITSIO)f(w)m(eb)i
+(site)f(are)h(also)f(v)m(ery)h(useful)e(for)h(learning)f(ho)m(w)h(to)h
+(use)f(CFITSIO.)f(T)-8 b(o)0 5281 y(learn)22 b(ev)m(en)h(more)g(ab)s
+(out)f(the)h(capabilities)d(of)j(the)g(CFITSIO)e(library)f(the)j(follo)
+m(wing)e(steps)h(are)h(recommended:)0 5441 y(1.)41 b(Read)31
+b(the)f(follo)m(wing)f(short)h(`FITS)g(Primer')f(c)m(hapter)i(for)f(an)
+h(o)m(v)m(erview)g(of)f(the)h(structure)f(of)g(FITS)g(\014les.)0
+5601 y(2.)40 b(Review)27 b(the)g(Programming)f(Guidelines)f(in)h
+(Chapter)g(4)i(to)g(b)s(ecome)f(familiar)e(with)h(the)i(con)m(v)m(en)m
+(tions)g(used)0 5714 y(b)m(y)i(the)h(CFITSIO)e(in)m(terface.)p
+eop
+%%Page: 10 18
+10 17 bop 0 299 a Fj(10)1535 b Fh(CHAPTER)30 b(2.)112
+b(CREA)-8 b(TING)30 b(THE)g(CFITSIO)f(LIBRAR)-8 b(Y)0
+555 y Fj(3.)74 b(Refer)41 b(to)h(the)g(co)s(okb)s(o)s(ok.c,)j
+(listhead.c,)f(and)c(\014tscop)m(y)-8 b(.c)43 b(programs)e(that)h(are)g
+(included)c(with)i(this)h(re-)0 668 y(lease)g(for)f(examples)g(of)h
+(routines)e(that)i(p)s(erform)e(v)-5 b(arious)40 b(common)h(FITS)f
+(\014le)f(op)s(erations.)71 b(T)m(yp)s(e)40 b('mak)m(e)0
+781 y(program)p 339 781 28 4 v 33 w(name')30 b(to)h(compile)f(and)f
+(link)g(these)i(programs)f(on)g(Unix)f(systems.)0 941
+y(4.)40 b(W)-8 b(rite)29 b(a)f(simple)e(program)i(to)g(read)g(or)g
+(write)f(a)i(FITS)e(\014le)g(using)g(the)h(Basic)g(In)m(terface)h
+(routines)e(describ)s(ed)0 1054 y(in)i(Chapter)h(5.)0
+1214 y(5.)79 b(Scan)43 b(through)f(the)h(more)g(sp)s(ecialized)f
+(routines)f(that)j(are)f(describ)s(ed)e(in)h(the)h(follo)m(wing)f(c)m
+(hapters)h(to)0 1327 y(b)s(ecome)31 b(familiar)d(with)h(the)i
+(functionalit)m(y)d(that)j(they)g(pro)m(vide.)0 1660
+y Ff(2.5)135 b(Example)46 b(Program)0 1910 y Fj(The)c(follo)m(wing)g
+(listing)f(sho)m(ws)h(an)h(example)g(of)g(ho)m(w)g(to)g(use)g(the)g
+(CFITSIO)f(routines)f(in)h(a)h(C)g(program.)0 2023 y(Refer)26
+b(to)g(the)g(co)s(okb)s(o)s(ok.c)g(program)f(that)i(is)d(included)f
+(with)h(the)i(CFITSIO)e(distribution)e(for)j(other)h(example)0
+2136 y(routines.)0 2296 y(This)37 b(program)i(creates)h(a)f(new)f(FITS)
+g(\014le,)j(con)m(taining)d(a)h(FITS)f(image.)67 b(An)38
+b(`EXPOSURE')h(k)m(eyw)m(ord)g(is)0 2409 y(written)26
+b(to)h(the)f(header,)i(then)e(the)h(image)f(data)i(are)f(written)e(to)i
+(the)g(FITS)f(\014le)f(b)s(efore)i(closing)e(the)i(FITS)f(\014le.)0
+2665 y Fe(#include)46 b("fitsio.h")92 b(/*)47 b(required)f(by)h(every)g
+(program)e(that)i(uses)g(CFITSIO)93 b(*/)0 2778 y(main\(\))0
+2891 y({)191 3004 y(fitsfile)45 b(*fptr;)333 b(/*)47
+b(pointer)f(to)h(the)g(FITS)g(file;)f(defined)g(in)h(fitsio.h)f(*/)191
+3117 y(int)h(status,)f(ii,)h(jj;)191 3230 y(long)94 b(fpixel)46
+b(=)i(1,)f(naxis)f(=)i(2,)f(nelements,)e(exposure;)191
+3343 y(long)i(naxes[2])e(=)j({)f(300,)g(200)g(};)142
+b(/*)47 b(image)g(is)g(300)g(pixels)f(wide)h(by)g(200)g(rows)f(*/)191
+3456 y(short)g(array[200][300];)191 3681 y(status)g(=)h(0;)429
+b(/*)48 b(initialize)d(status)h(before)g(calling)g(fitsio)g(routines)f
+(*/)191 3794 y(fits_create_file\(&fptr,)c("testfile.fits",)j
+(&status\);)140 b(/*)48 b(create)e(new)h(file)f(*/)191
+4020 y(/*)h(Create)f(the)h(primary)f(array)g(image)h(\(16-bit)e(short)i
+(integer)f(pixels)g(*/)191 4133 y(fits_create_img\(fptr,)c(SHORT_IMG,)j
+(naxis,)h(naxes,)g(&status\);)191 4359 y(/*)h(Write)f(a)i(keyword;)d
+(must)i(pass)g(the)g(ADDRESS)e(of)j(the)f(value)f(*/)191
+4472 y(exposure)f(=)j(1500.;)191 4585 y(fits_update_key\(fptr,)42
+b(TLONG,)k("EXPOSURE",)f(&exposure,)430 4698 y("Total)h(Exposure)f
+(Time",)h(&status\);)191 4924 y(/*)h(Initialize)e(the)i(values)f(in)h
+(the)g(image)g(with)f(a)i(linear)e(ramp)g(function)g(*/)191
+5036 y(for)h(\(jj)g(=)g(0;)g(jj)h(<)f(naxes[1];)e(jj++\))382
+5149 y(for)i(\(ii)g(=)g(0;)g(ii)g(<)h(naxes[0];)d(ii++\))573
+5262 y(array[jj][ii])f(=)j(ii)h(+)f(jj;)191 5488 y(nelements)e(=)j
+(naxes[0])d(*)j(naxes[1];)474 b(/*)48 b(number)e(of)h(pixels)f(to)h
+(write)g(*/)191 5714 y(/*)g(Write)f(the)h(array)g(of)g(integers)e(to)j
+(the)f(image)f(*/)p eop
+%%Page: 11 19
+11 18 bop 0 299 a Fh(2.5.)72 b(EXAMPLE)31 b(PR)m(OGRAM)2618
+b Fj(11)191 555 y Fe(fits_write_img\(fptr,)42 b(TSHORT,)k(fpixel,)g
+(nelements,)f(array[0],)g(&status\);)191 781 y(fits_close_file\(fptr,)d
+(&status\);)570 b(/*)47 b(close)g(the)g(file)f(*/)191
+1007 y(fits_report_error\(stderr)o(,)c(status\);)93 b(/*)47
+b(print)g(out)g(any)f(error)h(messages)e(*/)191 1120
+y(return\()h(status)g(\);)0 1233 y(})p eop
+%%Page: 12 20
+12 19 bop 0 299 a Fj(12)1535 b Fh(CHAPTER)30 b(2.)112
+b(CREA)-8 b(TING)30 b(THE)g(CFITSIO)f(LIBRAR)-8 b(Y)p
+eop
+%%Page: 13 21
+13 20 bop 0 1225 a Fg(Chapter)65 b(3)0 1687 y Fm(A)78
+b(FITS)f(Primer)0 2180 y Fj(This)22 b(section)j(giv)m(es)f(a)h(brief)d
+(o)m(v)m(erview)j(of)f(the)h(structure)e(of)i(FITS)e(\014les.)37
+b(Users)24 b(should)f(refer)g(to)i(the)g(do)s(cumen-)0
+2293 y(tation)i(a)m(v)-5 b(ailable)27 b(from)g(the)g(NOST,)f(as)i
+(describ)s(ed)d(in)h(the)h(in)m(tro)s(duction,)f(for)h(more)g(detailed)
+g(information)e(on)0 2406 y(FITS)30 b(formats.)0 2566
+y(FITS)e(w)m(as)h(\014rst)g(dev)m(elop)s(ed)f(in)f(the)i(late)h(1970's)
+h(as)e(a)g(standard)f(data)i(in)m(terc)m(hange)f(format)g(b)s(et)m(w)m
+(een)h(v)-5 b(arious)0 2679 y(astronomical)34 b(observ)-5
+b(atories.)51 b(Since)33 b(then)h(FITS)f(has)h(b)s(ecome)g(the)h
+(standard)e(data)i(format)f(supp)s(orted)e(b)m(y)0 2791
+y(most)f(astronomical)f(data)h(analysis)e(soft)m(w)m(are)j(pac)m(k)-5
+b(ages.)0 2952 y(A)34 b(FITS)f(\014le)f(consists)h(of)h(one)g(or)g
+(more)g(Header)g(+)f(Data)i(Units)e(\(HDUs\),)j(where)d(the)h(\014rst)f
+(HDU)h(is)f(called)0 3065 y(the)k(`Primary)e(HDU',)j(or)f(`Primary)e
+(Arra)m(y'.)60 b(The)36 b(primary)f(arra)m(y)i(con)m(tains)g(an)f
+(N-dimensional)f(arra)m(y)i(of)0 3177 y(pixels,)26 b(suc)m(h)h(as)h(a)f
+(1-D)h(sp)s(ectrum,)f(a)h(2-D)g(image,)h(or)e(a)g(3-D)i(data)f(cub)s
+(e.)39 b(Fiv)m(e)27 b(di\013eren)m(t)g(primary)e(data)j(t)m(yp)s(es)0
+3290 y(are)e(supp)s(orted:)37 b(Unsigned)24 b(8-bit)i(b)m(ytes,)h(16)g
+(and)e(32-bit)h(signed)e(in)m(tegers,)j(and)f(32)g(and)f(64-bit)h
+(\015oating)g(p)s(oin)m(t)0 3403 y(reals.)40 b(FITS)29
+b(also)h(has)g(a)g(con)m(v)m(en)m(tion)i(for)d(storing)h(16)h(and)e
+(32-bit)h(unsigned)e(in)m(tegers)j(\(see)g(the)f(later)g(section)0
+3516 y(en)m(titled)d(`Unsigned)g(In)m(tegers')i(for)e(more)h
+(details\).)39 b(The)27 b(primary)f(HDU)j(ma)m(y)f(also)g(consist)f(of)
+h(only)f(a)h(header)0 3629 y(with)h(a)i(n)m(ull)d(arra)m(y)j(con)m
+(taining)f(no)g(data)h(pixels.)0 3789 y(An)m(y)i(n)m(um)m(b)s(er)e(of)h
+(additional)f(HDUs)i(ma)m(y)g(follo)m(w)f(the)g(primary)f(arra)m(y;)j
+(these)f(additional)e(HDUs)i(are)g(called)0 3902 y(FITS)d
+(`extensions'.)40 b(There)30 b(are)h(curren)m(tly)e(3)i(t)m(yp)s(es)g
+(of)f(extensions)g(de\014ned)f(b)m(y)h(the)h(FITS)f(standard:)136
+4171 y Fc(\017)46 b Fj(Image)31 b(Extension)f(-)h(a)f(N-dimensional)e
+(arra)m(y)j(of)g(pixels,)e(lik)m(e)g(in)g(a)i(primary)d(arra)m(y)136
+4368 y Fc(\017)46 b Fj(ASCI)s(I)29 b(T)-8 b(able)30 b(Extension)g(-)g
+(ro)m(ws)h(and)e(columns)g(of)i(data)g(in)e(ASCI)s(I)g(c)m(haracter)j
+(format)136 4564 y Fc(\017)46 b Fj(Binary)30 b(T)-8 b(able)30
+b(Extension)f(-)i(ro)m(ws)f(and)g(columns)f(of)i(data)g(in)e(binary)f
+(represen)m(tation)0 4833 y(In)33 b(eac)m(h)i(case)g(the)f(HDU)h
+(consists)f(of)g(an)g(ASCI)s(I)e(Header)i(Unit)g(follo)m(w)m(ed)f(b)m
+(y)h(an)g(optional)f(Data)i(Unit.)51 b(F)-8 b(or)0 4946
+y(historical)34 b(reasons,)j(eac)m(h)f(Header)g(or)g(Data)h(unit)d(m)m
+(ust)h(b)s(e)g(an)g(exact)i(m)m(ultiple)c(of)j(2880)h(8-bit)e(b)m(ytes)
+h(long.)0 5059 y(An)m(y)30 b(un)m(used)g(space)g(is)g(padded)f(with)g
+(\014ll)f(c)m(haracters)k(\(ASCI)s(I)d(blanks)g(or)i(zeros\).)0
+5219 y(Eac)m(h)i(Header)f(Unit)g(consists)g(of)g(an)m(y)g(n)m(um)m(b)s
+(er)f(of)i(80-c)m(haracter)i(k)m(eyw)m(ord)d(records)g(or)g(`card)h
+(images')f(whic)m(h)0 5332 y(ha)m(v)m(e)g(the)e(general)h(form:)95
+5601 y Fe(KEYNAME)46 b(=)i(value)e(/)i(comment)d(string)95
+5714 y(NULLKEY)h(=)334 b(/)48 b(comment:)d(This)i(keyword)f(has)g(no)i
+(value)1905 5942 y Fj(13)p eop
+%%Page: 14 22
+14 21 bop 0 299 a Fj(14)2398 b Fh(CHAPTER)30 b(3.)112
+b(A)30 b(FITS)g(PRIMER)0 555 y Fj(The)35 b(k)m(eyw)m(ord)i(names)f(ma)m
+(y)g(b)s(e)g(up)f(to)h(8)h(c)m(haracters)g(long)f(and)f(can)h(only)g
+(con)m(tain)g(upp)s(ercase)f(letters,)j(the)0 668 y(digits)23
+b(0-9,)k(the)e(h)m(yphen,)g(and)f(the)h(underscore)e(c)m(haracter.)41
+b(The)24 b(k)m(eyw)m(ord)h(name)g(is)e(\(usually\))g(follo)m(w)m(ed)i
+(b)m(y)f(an)0 781 y(equals)k(sign)g(and)g(a)g(space)i(c)m(haracter)g
+(\(=)e(\))h(in)e(columns)h(9)h(-)f(10)i(of)f(the)f(record,)h(follo)m(w)
+m(ed)g(b)m(y)f(the)h(v)-5 b(alue)28 b(of)h(the)0 894
+y(k)m(eyw)m(ord)34 b(whic)m(h)f(ma)m(y)h(b)s(e)f(either)g(an)h(in)m
+(teger,)h(a)f(\015oating)f(p)s(oin)m(t)g(n)m(um)m(b)s(er,)h(a)g(c)m
+(haracter)h(string)d(\(enclosed)i(in)0 1007 y(single)26
+b(quotes\),)k(or)e(a)g(b)s(o)s(olean)f(v)-5 b(alue)27
+b(\(the)h(letter)g(T)g(or)f(F\).)i(A)f(k)m(eyw)m(ord)g(ma)m(y)h(also)e
+(ha)m(v)m(e)i(a)g(n)m(ull)c(or)j(unde\014ned)0 1120 y(v)-5
+b(alue)30 b(if)f(there)i(is)e(no)h(sp)s(eci\014ed)f(v)-5
+b(alue)30 b(string,)g(as)g(in)f(the)i(second)f(example,)h(ab)s(o)m(v)m
+(e)0 1280 y(The)42 b(last)g(k)m(eyw)m(ord)h(in)e(the)i(header)f(is)f
+(alw)m(a)m(ys)i(the)g(`END')g(k)m(eyw)m(ord)g(whic)m(h)e(has)h(no)h(v)
+-5 b(alue)41 b(or)i(commen)m(t)0 1393 y(\014elds.)c(There)30
+b(are)h(man)m(y)f(rules)f(go)m(v)m(erning)i(the)f(exact)i(format)f(of)f
+(a)h(k)m(eyw)m(ord)f(record)h(\(see)g(the)f(NOST)g(FITS)0
+1506 y(Standard\))c(so)i(it)e(is)h(b)s(etter)g(to)h(rely)e(on)h
+(standard)g(in)m(terface)g(soft)m(w)m(are)i(lik)m(e)d(CFITSIO)g(to)i
+(correctly)g(construct)0 1619 y(or)i(to)h(parse)g(the)f(k)m(eyw)m(ord)h
+(records)f(rather)g(than)h(try)f(to)h(deal)f(directly)f(with)g(the)h
+(ra)m(w)h(FITS)f(formats.)0 1779 y(Eac)m(h)37 b(Header)g(Unit)e(b)s
+(egins)g(with)g(a)h(series)g(of)g(required)f(k)m(eyw)m(ords)h(whic)m(h)
+f(dep)s(end)g(on)h(the)g(t)m(yp)s(e)h(of)f(HDU.)0 1892
+y(These)31 b(required)f(k)m(eyw)m(ords)i(sp)s(ecify)f(the)g(size)h(and)
+f(format)h(of)g(the)g(follo)m(wing)e(Data)j(Unit.)44
+b(The)31 b(header)g(ma)m(y)0 2005 y(con)m(tain)g(other)g(optional)e(k)m
+(eyw)m(ords)i(to)h(describ)s(e)d(other)h(asp)s(ects)h(of)g(the)g(data,)
+g(suc)m(h)g(as)g(the)f(units)f(or)i(scaling)0 2118 y(v)-5
+b(alues.)43 b(Other)31 b(COMMENT)g(or)g(HISTOR)-8 b(Y)30
+b(k)m(eyw)m(ords)i(are)g(also)f(frequen)m(tly)g(added)f(to)i(further)e
+(do)s(cumen)m(t)0 2230 y(the)h(data)g(\014le.)0 2391
+y(The)36 b(optional)f(Data)j(Unit)e(immediately)e(follo)m(ws)i(the)g
+(last)g(2880-b)m(yte)j(blo)s(c)m(k)d(in)f(the)h(Header)h(Unit.)58
+b(Some)0 2503 y(HDUs)31 b(do)f(not)h(ha)m(v)m(e)g(a)g(Data)h(Unit)e
+(and)g(only)f(consist)h(of)h(the)f(Header)h(Unit.)0 2664
+y(If)24 b(there)i(is)e(more)h(than)f(one)h(HDU)h(in)e(the)h(FITS)f
+(\014le,)h(then)g(the)g(Header)h(Unit)e(of)h(the)g(next)g(HDU)h
+(immediately)0 2777 y(follo)m(ws)e(the)g(last)h(2880-b)m(yte)i(blo)s(c)
+m(k)d(of)h(the)f(previous)f(Data)k(Unit)c(\(or)i(Header)g(Unit)f(if)f
+(there)i(is)f(no)g(Data)i(Unit\).)0 2937 y(The)k(main)f(required)g(k)m
+(eyw)m(ords)h(in)f(FITS)h(primary)f(arra)m(ys)h(or)h(image)f
+(extensions)g(are:)136 3172 y Fc(\017)46 b Fj(BITPIX)39
+b({)h(de\014nes)f(the)g(data)h(t)m(yp)s(e)g(of)f(the)h(arra)m(y:)59
+b(8,)42 b(16,)h(32,)g(-32,)g(-64)d(for)f(unsigned)f(8{bit)h(b)m(yte,)
+227 3284 y(16{bit)h(signed)f(in)m(teger,)j(32{bit)f(signed)d(in)m
+(teger,)43 b(32{bit)d(IEEE)f(\015oating)g(p)s(oin)m(t,)i(and)f(64{bit)g
+(IEEE)227 3397 y(double)29 b(precision)g(\015oating)h(p)s(oin)m(t,)g
+(resp)s(ectiv)m(ely)-8 b(.)136 3585 y Fc(\017)46 b Fj(NAXIS)30
+b({)h(the)g(n)m(um)m(b)s(er)e(of)h(dimensions)e(in)h(the)i(arra)m(y)-8
+b(,)31 b(usually)d(0,)j(1,)g(2,)g(3,)g(or)g(4.)136 3773
+y Fc(\017)46 b Fj(NAXISn)30 b({)h(\(n)f(ranges)g(from)g(1)h(to)g
+(NAXIS\))g(de\014nes)e(the)i(size)f(of)h(eac)m(h)g(dimension.)0
+4008 y(FITS)e(tables)h(start)h(with)e(the)h(k)m(eyw)m(ord)g(XTENSION)g
+(=)f(`T)-8 b(ABLE')31 b(\(for)f(ASCI)s(I)f(tables\))h(or)g(XTENSION)f
+(=)0 4120 y(`BINT)-8 b(ABLE')32 b(\(for)e(binary)f(tables\))h(and)g(ha)
+m(v)m(e)i(the)e(follo)m(wing)f(main)g(k)m(eyw)m(ords:)136
+4355 y Fc(\017)46 b Fj(TFIELDS)30 b({)h(n)m(um)m(b)s(er)e(of)h
+(\014elds)f(or)i(columns)e(in)g(the)h(table)136 4543
+y Fc(\017)46 b Fj(NAXIS2)31 b({)g(n)m(um)m(b)s(er)e(of)h(ro)m(ws)h(in)e
+(the)h(table)136 4731 y Fc(\017)46 b Fj(TTYPEn)29 b({)i(for)f(eac)m(h)i
+(column)d(\(n)h(ranges)h(from)f(1)g(to)h(TFIELDS\))g(giv)m(es)f(the)h
+(name)f(of)h(the)f(column)136 4918 y Fc(\017)46 b Fj(TF)m(ORMn)31
+b({)f(the)h(data)g(t)m(yp)s(e)f(of)h(the)g(column)136
+5106 y Fc(\017)46 b Fj(TUNITn)30 b({)g(the)h(ph)m(ysical)e(units)g(of)h
+(the)h(column)e(\(optional\))0 5341 y(Users)e(should)e(refer)i(to)g
+(the)h(FITS)e(Supp)s(ort)f(O\016ce)i(at)h Fe(http://fits.gsfc.nasa.go)o
+(v)21 b Fj(for)27 b(futher)f(informa-)0 5454 y(tion)k(ab)s(out)g(the)h
+(FITS)e(format)i(and)f(related)g(soft)m(w)m(are)i(pac)m(k)-5
+b(ages.)p eop
+%%Page: 15 23
+15 22 bop 0 1225 a Fg(Chapter)65 b(4)0 1687 y Fm(Programming)77
+b(Guidelines)0 2216 y Ff(4.1)135 b(CFITSIO)44 b(De\014nitions)0
+2466 y Fj(An)m(y)30 b(program)g(that)h(uses)f(the)h(CFITSIO)d(in)m
+(terface)j(m)m(ust)f(include)e(the)j(\014tsio.h)e(header)h(\014le)g
+(with)f(the)h(state-)0 2579 y(men)m(t)95 2818 y Fe(#include)46
+b("fitsio.h")0 3057 y Fj(This)29 b(header)i(\014le)g(con)m(tains)g(the)
+g(protot)m(yp)s(es)h(for)f(all)f(the)h(CFITSIO)f(user)g(in)m(terface)i
+(routines)e(as)h(w)m(ell)f(as)i(the)0 3170 y(de\014nitions)e(of)i(v)-5
+b(arious)31 b(constan)m(ts)i(used)e(in)g(the)i(in)m(terface.)46
+b(It)32 b(also)g(de\014nes)f(a)i(C)f(structure)f(of)h(t)m(yp)s(e)h
+(`\014ts\014le')0 3283 y(that)j(is)f(used)g(b)m(y)g(CFITSIO)f(to)j
+(store)f(the)g(relev)-5 b(an)m(t)36 b(parameters)g(that)g(de\014ne)f
+(the)h(format)g(of)g(a)g(particular)0 3396 y(FITS)c(\014le.)47
+b(Application)31 b(programs)i(m)m(ust)g(de\014ne)f(a)h(p)s(oin)m(ter)f
+(to)h(this)f(structure)h(for)f(eac)m(h)i(FITS)e(\014le)g(that)i(is)0
+3508 y(to)i(b)s(e)f(op)s(ened.)56 b(This)34 b(structure)h(is)g
+(initialized)d(\(i.e.,)38 b(memory)d(is)g(allo)s(cated)g(for)h(the)g
+(structure\))f(when)g(the)0 3621 y(FITS)h(\014le)f(is)h(\014rst)f(op)s
+(ened)h(or)g(created)i(with)d(the)h(\014ts)p 1949 3621
+28 4 v 33 w(op)s(en)p 2172 3621 V 32 w(\014le)f(or)i(\014ts)p
+2596 3621 V 32 w(create)p 2864 3621 V 34 w(\014le)f(routines.)58
+b(This)34 b(\014ts\014le)0 3734 y(p)s(oin)m(ter)c(is)h(then)g(passed)g
+(as)g(the)h(\014rst)e(argumen)m(t)i(to)g(ev)m(ery)g(other)g(CFITSIO)d
+(routine)i(that)h(op)s(erates)g(on)f(the)0 3847 y(FITS)h(\014le.)47
+b(Application)31 b(programs)i(m)m(ust)g(not)g(directly)e(read)i(or)g
+(write)f(elemen)m(ts)h(in)f(this)g(\014ts\014le)f(structure)0
+3960 y(b)s(ecause)f(the)h(de\014nition)d(of)j(the)f(structure)g(ma)m(y)
+h(c)m(hange)g(in)f(future)f(v)m(ersions)h(of)g(CFITSIO.)0
+4120 y(A)45 b(n)m(um)m(b)s(er)e(of)i(sym)m(b)s(olic)e(constan)m(ts)j
+(are)f(also)f(de\014ned)g(in)f(\014tsio.h)h(for)g(the)h(con)m(v)m
+(enience)h(of)f(application)0 4233 y(programmers.)55
+b(Use)35 b(of)h(these)f(sym)m(b)s(olic)f(constan)m(ts)i(rather)f(than)g
+(the)h(actual)f(n)m(umeric)f(v)-5 b(alue)35 b(will)d(help)i(to)0
+4346 y(mak)m(e)d(the)g(source)f(co)s(de)h(more)g(readable)e(and)h
+(easier)h(for)f(others)g(to)h(understand.)0 4585 y Fe(String)46
+b(Lengths,)g(for)h(use)f(when)h(allocating)e(character)g(arrays:)95
+4811 y(#define)h(FLEN_FILENAME)e(1025)j(/*)g(max)g(length)f(of)h(a)h
+(filename)857 b(*/)95 4924 y(#define)46 b(FLEN_KEYWORD)140
+b(72)95 b(/*)47 b(max)g(length)f(of)h(a)h(keyword)905
+b(*/)95 5036 y(#define)46 b(FLEN_CARD)284 b(81)95 b(/*)47
+b(max)g(length)f(of)h(a)h(FITS)f(header)f(card)476 b(*/)95
+5149 y(#define)46 b(FLEN_VALUE)236 b(71)95 b(/*)47 b(max)g(length)f(of)
+h(a)h(keyword)e(value)g(string)285 b(*/)95 5262 y(#define)46
+b(FLEN_COMMENT)140 b(73)95 b(/*)47 b(max)g(length)f(of)h(a)h(keyword)e
+(comment)g(string)189 b(*/)95 5375 y(#define)46 b(FLEN_ERRMSG)188
+b(81)95 b(/*)47 b(max)g(length)f(of)h(a)h(CFITSIO)e(error)g(message)237
+b(*/)95 5488 y(#define)46 b(FLEN_STATUS)188 b(31)95 b(/*)47
+b(max)g(length)f(of)h(a)h(CFITSIO)e(status)g(text)g(string)h(*/)95
+5714 y(Note)g(that)g(FLEN_KEYWORD)d(is)j(longer)f(than)h(the)g(nominal)
+f(8-character)f(keyword)1905 5942 y Fj(15)p eop
+%%Page: 16 24
+16 23 bop 0 299 a Fj(16)1763 b Fh(CHAPTER)29 b(4.)112
+b(PR)m(OGRAMMING)32 b(GUIDELINES)95 555 y Fe(name)47
+b(length)f(because)g(the)h(HIERARCH)e(convention)g(supports)h(longer)g
+(keyword)g(names.)0 781 y(Access)g(modes)g(when)h(opening)f(a)h(FITS)g
+(file:)95 1007 y(#define)f(READONLY)94 b(0)95 1120 y(#define)46
+b(READWRITE)g(1)0 1346 y(BITPIX)g(data)h(type)f(code)h(values)f(for)h
+(FITS)g(images:)95 1571 y(#define)f(BYTE_IMG)284 b(8)96
+b(/*)f(8-bit)46 b(unsigned)f(integers)h(*/)95 1684 y(#define)g
+(SHORT_IMG)189 b(16)95 b(/*)47 b(16-bit)141 b(signed)46
+b(integers)g(*/)95 1797 y(#define)g(LONG_IMG)237 b(32)95
+b(/*)47 b(32-bit)141 b(signed)46 b(integers)g(*/)95 1910
+y(#define)g(FLOAT_IMG)141 b(-32)95 b(/*)47 b(32-bit)f(single)g
+(precision)f(floating)h(point)g(*/)95 2023 y(#define)g(DOUBLE_IMG)93
+b(-64)i(/*)47 b(64-bit)f(double)g(precision)f(floating)h(point)g(*/)95
+2249 y(The)h(following)f(4)h(data)g(type)f(codes)h(are)g(also)f
+(supported)g(by)h(CFITSIO:)95 2362 y(#define)f(LONGLONG_IMG)f(64)i(/*)g
+(64-bit)f(long)h(signed)f(integers)f(*/)95 2475 y(#define)h(SBYTE_IMG)
+93 b(10)143 b(/*)95 b(8-bit)46 b(signed)g(integers,)g(equivalent)f(to)i
+(*/)1241 2588 y(/*)95 b(BITPIX)46 b(=)h(8,)h(BSCALE)e(=)h(1,)g(BZERO)g
+(=)g(-128)g(*/)95 2700 y(#define)f(USHORT_IMG)93 b(20)i(/*)47
+b(16-bit)f(unsigned)g(integers,)f(equivalent)g(to)i(*/)1241
+2813 y(/*)95 b(BITPIX)46 b(=)h(16,)g(BSCALE)f(=)i(1,)f(BZERO)f(=)i
+(32768)e(*/)95 2926 y(#define)g(ULONG_IMG)141 b(40)95
+b(/*)47 b(32-bit)f(unsigned)g(integers,)f(equivalent)g(to)i(*/)1241
+3039 y(/*)95 b(BITPIX)46 b(=)h(32,)g(BSCALE)f(=)i(1,)f(BZERO)f(=)i
+(2147483648)d(*/)0 3265 y(Codes)h(for)h(the)g(data)g(type)f(of)i
+(binary)e(table)g(columns)g(and/or)g(for)h(the)0 3378
+y(data)g(type)f(of)h(variables)f(when)g(reading)g(or)h(writing)f
+(keywords)g(or)h(data:)1432 3604 y(DATATYPE)714 b(TFORM)46
+b(CODE)95 3717 y(#define)g(TBIT)476 b(1)96 b(/*)1335
+b('X')47 b(*/)95 3830 y(#define)f(TBYTE)381 b(11)95 b(/*)47
+b(8-bit)f(unsigned)g(byte,)332 b('B')47 b(*/)95 3942
+y(#define)f(TLOGICAL)237 b(14)95 b(/*)47 b(logicals)e(\(int)i(for)g
+(keywords)236 b(*/)1289 4055 y(/*)95 b(and)46 b(char)h(for)g(table)f
+(cols)142 b('L')47 b(*/)95 4168 y(#define)f(TSTRING)285
+b(16)95 b(/*)47 b(ASCII)f(string,)666 b('A')47 b(*/)95
+4281 y(#define)f(TSHORT)333 b(21)95 b(/*)47 b(signed)f(short,)666
+b('I')47 b(*/)95 4394 y(#define)f(TINT32BIT)189 b(41)95
+b(/*)47 b(signed)f(32-bit)g(int,)428 b('J')47 b(*/)95
+4507 y(#define)f(TLONG)381 b(41)95 b(/*)47 b(signed)f(long,)905
+b(*/)95 4620 y(#define)46 b(TFLOAT)333 b(42)95 b(/*)47
+b(single)f(precision)f(float,)189 b('E')47 b(*/)95 4733
+y(#define)f(TDOUBLE)285 b(82)95 b(/*)47 b(double)f(precision)f(float,)
+189 b('D')47 b(*/)95 4846 y(#define)f(TCOMPLEX)237 b(83)95
+b(/*)47 b(complex)f(\(pair)g(of)h(floats\))141 b('C')47
+b(*/)95 4959 y(#define)f(TDBLCOMPLEX)f(163)95 b(/*)47
+b(double)f(complex)g(\(2)h(doubles\))e('M')i(*/)95 5185
+y(The)g(following)f(data)g(type)h(codes)f(are)h(also)g(supported)e(by)i
+(CFITSIO:)95 5297 y(#define)f(TINT)429 b(31)95 b(/*)47
+b(int)1335 b(*/)95 5410 y(#define)46 b(TSBYTE)333 b(12)95
+b(/*)47 b(8-bit)f(signed)g(byte,)428 b('S')47 b(*/)95
+5523 y(#define)f(TUINT)381 b(30)95 b(/*)47 b(unsigned)e(int)715
+b('V')47 b(*/)95 5636 y(#define)f(TUSHORT)285 b(20)95
+b(/*)47 b(unsigned)e(short)619 b('U')95 b(*/)p eop
+%%Page: 17 25
+17 24 bop 0 299 a Fh(4.2.)72 b(CURRENT)30 b(HEADER)h(D)m(A)-8
+b(T)g(A)32 b(UNIT)e(\(CHDU\))1786 b Fj(17)95 555 y Fe(#define)46
+b(TULONG)333 b(40)95 b(/*)47 b(unsigned)e(long)858 b(*/)95
+668 y(#define)46 b(TLONGLONG)189 b(81)95 b(/*)47 b(64-bit)f(long)h
+(signed)f(integer)f('K')i(*/)0 894 y(HDU)g(type)g(code)f(values)g
+(\(value)g(returned)g(when)h(moving)f(to)h(new)g(HDU\):)95
+1120 y(#define)f(IMAGE_HDU)93 b(0)i(/*)48 b(Primary)d(Array)i(or)g
+(IMAGE)f(HDU)h(*/)95 1233 y(#define)f(ASCII_TBL)93 b(1)i(/*)48
+b(ASCII)94 b(table)46 b(HDU)h(*/)95 1346 y(#define)f(BINARY_TBL)f(2)95
+b(/*)48 b(Binary)e(table)g(HDU)h(*/)95 1458 y(#define)f(ANY_HDU)142
+b(-1)94 b(/*)48 b(matches)d(any)i(type)g(of)g(HDU)g(*/)0
+1684 y(Column)f(name)h(and)g(string)f(matching)f(case-sensitivity:)95
+1910 y(#define)h(CASESEN)142 b(1)g(/*)48 b(do)f(case-sensitive)d
+(string)i(match)g(*/)95 2023 y(#define)g(CASEINSEN)g(0)142
+b(/*)48 b(do)f(case-insensitive)c(string)j(match)h(*/)0
+2249 y(Logical)f(states)g(\(if)h(TRUE)f(and)h(FALSE)g(are)g(not)g
+(already)e(defined\):)95 2475 y(#define)h(TRUE)h(1)95
+2588 y(#define)f(FALSE)h(0)0 2813 y(Values)f(to)h(represent)f
+(undefined)f(floating)g(point)i(numbers:)95 3039 y(#define)f
+(FLOATNULLVALUE)e(-9.11912E-36F)95 3152 y(#define)i(DOUBLENULLVALUE)e
+(-9.1191291391491E-36)0 3378 y(Image)i(compression)f(algorithm)g
+(definitions)95 3604 y(#define)h(RICE_1)285 b(11)95 3717
+y(#define)46 b(GZIP_1)285 b(21)95 3830 y(#define)46 b(PLIO_1)285
+b(31)0 4306 y Ff(4.2)135 b(Curren)l(t)46 b(Header)f(Data)h(Unit)g
+(\(CHDU\))0 4585 y Fj(The)37 b(concept)h(of)g(the)f(Curren)m(t)g
+(Header)g(and)g(Data)i(Unit,)g(or)e(CHDU,)h(is)e(fundamen)m(tal)h(to)h
+(the)f(use)g(of)h(the)0 4698 y(CFITSIO)31 b(library)-8
+b(.)44 b(A)32 b(simple)f(FITS)g(image)i(ma)m(y)g(only)e(con)m(tain)i(a)
+f(single)f(Header)i(and)f(Data)h(unit)e(\(HDU\),)0 4811
+y(but)39 b(in)f(general)i(FITS)f(\014les)g(can)h(con)m(tain)g(m)m
+(ultiple)e(Header)i(Data)h(Units)e(\(also)h(kno)m(wn)f(as)h
+(`extensions'\),)0 4924 y(concatenated)c(one)f(after)f(the)h(other)f
+(in)f(the)h(\014le.)52 b(The)33 b(user)h(can)g(sp)s(ecify)f(whic)m(h)g
+(HDU)i(should)d(b)s(e)h(initially)0 5036 y(op)s(ened)j(at)i(run)d(time)
+i(b)m(y)g(giving)f(the)h(HDU)h(name)f(or)g(n)m(um)m(b)s(er)f(after)h
+(the)g(ro)s(ot)h(\014le)e(name.)60 b(F)-8 b(or)38 b(example,)0
+5149 y('m)m(y\014le.\014ts[4]')h(op)s(ens)e(the)h(5th)h(HDU)g(in)e(the)
+h(\014le)f(\(note)i(that)g(the)f(n)m(um)m(b)s(ering)e(starts)j(with)e
+(0\),)k(and)c('m)m(y-)0 5262 y(\014le.\014ts[EVENTS])j(op)s(ens)g(the)h
+(HDU)h(with)d(the)i(name)g('EVENTS')g(\(as)g(de\014ned)f(b)m(y)h(the)g
+(EXTNAME)g(or)0 5375 y(HDUNAME)35 b(k)m(eyw)m(ords\).)50
+b(If)33 b(no)g(HDU)h(is)e(sp)s(eci\014ed)g(then)h(CFITSIO)e(op)s(ens)i
+(the)g(\014rst)g(HDU)h(\(the)g(primary)0 5488 y(arra)m(y\))24
+b(b)m(y)e(default.)38 b(The)22 b(CFITSIO)f(routines)h(whic)m(h)g(read)g
+(and)g(write)h(data)g(only)f(op)s(erate)h(within)e(the)i(op)s(ened)0
+5601 y(HDU,)32 b(Other)e(CFITSIO)f(routines)h(are)h(pro)m(vided)e(to)j
+(mo)m(v)m(e)g(to)f(and)f(op)s(en)g(an)m(y)h(other)g(existing)f(HDU)h
+(within)0 5714 y(the)g(FITS)e(\014le)h(or)g(to)h(app)s(end)e(or)h
+(insert)f(new)h(HDUs)h(in)e(the)i(FITS)f(\014le.)p eop
+%%Page: 18 26
+18 25 bop 0 299 a Fj(18)1763 b Fh(CHAPTER)29 b(4.)112
+b(PR)m(OGRAMMING)32 b(GUIDELINES)0 555 y Ff(4.3)135 b(F)-11
+b(unction)44 b(Names)i(and)f(V)-11 b(ariable)46 b(Datat)l(yp)t(es)0
+806 y Fj(Most)33 b(of)f(the)g(CFITSIO)f(routines)g(ha)m(v)m(e)i(b)s
+(oth)e(a)i(short)e(name)h(as)h(w)m(ell)e(as)h(a)g(longer)g(descriptiv)m
+(e)f(name.)45 b(The)0 919 y(short)32 b(name)g(is)f(only)g(5)i(or)f(6)g
+(c)m(haracters)h(long)f(and)g(is)f(similar)e(to)k(the)f(subroutine)e
+(name)i(in)f(the)h(F)-8 b(ortran-77)0 1032 y(v)m(ersion)37
+b(of)h(FITSIO.)f(The)h(longer)f(name)h(is)f(more)h(descriptiv)m(e)f
+(and)g(it)g(is)g(recommended)h(that)g(it)g(b)s(e)f(used)0
+1145 y(instead)30 b(of)g(the)h(short)f(name)g(to)h(more)g(clearly)f(do)
+s(cumen)m(t)g(the)g(source)h(co)s(de.)0 1305 y(Man)m(y)c(of)f(the)g
+(CFITSIO)f(routines)g(come)i(in)d(families)g(whic)m(h)h(di\013er)g
+(only)g(in)g(the)h(data)h(t)m(yp)s(e)f(of)g(the)g(asso)s(ciated)0
+1418 y(parameter\(s\).)45 b(The)31 b(data)h(t)m(yp)s(e)g(of)g(these)g
+(routines)e(is)h(indicated)f(b)m(y)h(the)h(su\016x)e(of)i(the)g
+(routine)e(name.)44 b(The)0 1530 y(short)27 b(routine)g(names)h(ha)m(v)
+m(e)h(a)f(1)g(or)f(2)h(c)m(haracter)i(su\016x)c(\(e.g.,)31
+b('j')c(in)g('\013pkyj'\))h(while)d(the)j(long)f(routine)g(names)0
+1643 y(ha)m(v)m(e)32 b(a)e(4)h(c)m(haracter)h(or)e(longer)g(su\016x)g
+(as)g(sho)m(wn)g(in)f(the)i(follo)m(wing)e(table:)191
+1905 y Fe(Long)285 b(Short)94 b(Data)191 2018 y(Names)237
+b(Names)94 b(Type)191 2131 y(-----)237 b(-----)94 b(----)191
+2244 y(_bit)381 b(x)190 b(bit)191 2357 y(_byt)381 b(b)190
+b(unsigned)46 b(byte)191 2469 y(_sbyt)333 b(sb)142 b(signed)46
+b(byte)191 2582 y(_sht)381 b(i)190 b(short)47 b(integer)191
+2695 y(_lng)381 b(j)190 b(long)47 b(integer)191 2808
+y(_lnglng)237 b(jj)142 b(8-byte)46 b(LONGLONG)g(integer)g(\(see)g(note)
+h(below\))191 2921 y(_usht)333 b(ui)142 b(unsigned)46
+b(short)g(integer)191 3034 y(_ulng)333 b(uj)142 b(unsigned)46
+b(long)g(integer)191 3147 y(_uint)333 b(uk)142 b(unsigned)46
+b(int)h(integer)191 3260 y(_int)381 b(k)190 b(int)47
+b(integer)191 3373 y(_flt)381 b(e)190 b(real)47 b(exponential)e
+(floating)g(point)i(\(float\))191 3486 y(_fixflt)237
+b(f)190 b(real)47 b(fixed-decimal)d(format)i(floating)g(point)g
+(\(float\))191 3599 y(_dbl)381 b(d)190 b(double)46 b(precision)g(real)g
+(floating-point)e(\(double\))191 3711 y(_fixdbl)237 b(g)190
+b(double)46 b(precision)g(fixed-format)e(floating)i(point)g(\(double\))
+191 3824 y(_cmp)381 b(c)190 b(complex)46 b(reals)g(\(pairs)h(of)g
+(float)f(values\))191 3937 y(_fixcmp)237 b(fc)142 b(complex)46
+b(reals,)g(fixed-format)f(floating)g(point)191 4050 y(_dblcmp)237
+b(m)190 b(double)46 b(precision)g(complex)f(\(pairs)i(of)g(double)f
+(values\))191 4163 y(_fixdblcmp)93 b(fm)142 b(double)46
+b(precision)g(complex,)f(fixed-format)g(floating)g(point)191
+4276 y(_log)381 b(l)190 b(logical)46 b(\(int\))191 4389
+y(_str)381 b(s)190 b(character)46 b(string)0 4650 y Fj(The)32
+b(logical)g(data)i(t)m(yp)s(e)f(corresp)s(onds)e(to)j(`in)m(t')e(for)h
+(logical)f(k)m(eyw)m(ord)h(v)-5 b(alues,)33 b(and)f(`b)m(yte')i(for)f
+(logical)f(binary)0 4763 y(table)39 b(columns.)66 b(In)39
+b(other)g(w)m(ords,)i(the)f(v)-5 b(alue)38 b(when)h(writing)e(a)j
+(logical)e(k)m(eyw)m(ord)i(m)m(ust)f(b)s(e)g(stored)g(in)f(an)0
+4876 y(`in)m(t')g(v)-5 b(ariable,)38 b(and)g(m)m(ust)f(b)s(e)g(stored)h
+(in)f(a)h(`c)m(har')h(arra)m(y)f(when)f(reading)g(or)g(writing)f(to)j
+(`L')f(columns)e(in)h(a)0 4989 y(binary)e(table.)59 b(Inplicit)34
+b(data)j(t)m(yp)s(e)f(con)m(v)m(ersion)h(is)f(not)h(supp)s(orted)d(for)
+i(logical)g(table)h(columns,)g(but)f(is)f(for)0 5102
+y(k)m(eyw)m(ords,)30 b(so)f(a)h(logical)e(k)m(eyw)m(ord)i(ma)m(y)f(b)s
+(e)g(read)f(and)h(cast)h(to)g(an)m(y)f(n)m(umerical)f(data)h(t)m(yp)s
+(e;)h(a)g(returned)d(v)-5 b(alue)0 5215 y(=)30 b(0)h(indicates)e
+(false,)h(and)g(an)m(y)h(other)f(v)-5 b(alue)30 b(=)g(true.)0
+5375 y(The)37 b(`in)m(t')h(data)g(t)m(yp)s(e)g(ma)m(y)g(b)s(e)f(2)h(b)m
+(ytes)h(long)e(on)g(some)h(IBM)h(PC)e(compatible)g(systems)g(and)g(is)g
+(usually)f(4)0 5488 y(b)m(ytes)27 b(long)f(on)h(most)g(other)g
+(systems.)39 b(Some)27 b(64-bit)g(mac)m(hines,)g(ho)m(w)m(ev)m(er,)i
+(lik)m(e)d(the)h(Dec)h(Alpha/OSF,)e(de\014ne)0 5601 y(the)j(`short',)h
+(`in)m(t',)g(and)e(`long')h(in)m(teger)h(data)g(t)m(yp)s(es)f(to)h(b)s
+(e)e(2,)i(4,)g(and)f(8)g(b)m(ytes)h(long,)f(resp)s(ectiv)m(ely)-8
+b(.)40 b(The)29 b(FITS)0 5714 y(standard)j(only)g(supp)s(orts)g(2)h
+(and)g(4)g(b)m(yte)h(in)m(teger)f(data)h(t)m(yp)s(es,)g(so)f(CFITSIO)f
+(in)m(ternally)f(con)m(v)m(erts)j(b)s(et)m(w)m(een)p
+eop
+%%Page: 19 27
+19 26 bop 0 299 a Fh(4.4.)72 b(SUPPOR)-8 b(T)30 b(F)m(OR)g(UNSIGNED)h
+(INTEGERS)f(AND)h(SIGNED)f(BYTES)942 b Fj(19)0 555 y(4)31
+b(and)f(8)g(b)m(ytes)h(when)f(reading)f(or)h(writing)f(`long')h(in)m
+(tegers)h(on)f(Alpha/OSF)f(systems.)0 715 y(The)e(8-b)m(yte)i
+('LONGLONG')f(in)m(teger)g(data)g(t)m(yp)s(e)g(is)e(supp)s(orted)g(on)i
+(most)f(platforms.)39 b(CFITSIO)26 b(de\014nes)h(the)0
+828 y(LONGLONG)i(data)g(t)m(yp)s(e)g(to)h(b)s(e)e(equiv)-5
+b(alen)m(t)29 b(to)g('long)g(long')g(on)f(most)i(Unix)d(platforms)h
+(and)g(on)h(Mac)h(OS-X.)0 941 y(Since)36 b(most)i(Windo)m(ws)e
+(compilers)g(don't)h(supp)s(ort)e(the)j('long)f(long')g(data)g(t)m(yp)s
+(e,)j(LONGLONG)d(is)f(de\014ned)0 1054 y(instead)e(to)h(b)s(e)f(equiv)
+-5 b(alen)m(t)33 b(to)i(')p 1141 1054 28 4 v 1175 1054
+V 66 w(in)m(t64'.)54 b(If)34 b(the)g(compiler)f(do)s(es)h(not)h(supp)s
+(ort)d(a)j(8-b)m(yte)h(in)m(teger)f(data)g(t)m(yp)s(e)0
+1167 y(then)d(LONGLONG)h(is)f(de\014ned)f(to)i(b)s(e)f(equiv)-5
+b(alen)m(t)33 b(to)g('long'.)48 b(Note)34 b(that)f(the)g(C)f(format)h
+(sp)s(eci\014er)e(to)i(prin)m(t)0 1280 y(out)38 b(these)g(long)g(in)m
+(teger)g(v)-5 b(alues)37 b(is)g("\045lld")g(on)h(most)g(unix)e(mac)m
+(hines,)k(except)e(on)g(OSF)g(platforms)e(where)0 1393
+y("\045ld")d(m)m(ust)g(b)s(e)f(used.)49 b(On)32 b(Windo)m(ws)g
+(platform)h(that)g(ha)m(v)m(e)i(the)p 2385 1393 V 2417
+1393 V 99 w(in)m(t64)e(data)h(t)m(yp)s(e,)h(the)e(format)h(sp)s
+(eci\014er)0 1506 y(is)29 b("\045INT64d".)0 1666 y(When)23
+b(dealing)f(with)g(the)i(FITS)f(b)m(yte)h(data)g(t)m(yp)s(e)f(it)g(is)g
+(imp)s(ortan)m(t)f(to)i(remem)m(b)s(er)f(that)h(the)g(ra)m(w)f(v)-5
+b(alues)23 b(\(b)s(efore)0 1779 y(an)m(y)i(scaling)e(b)m(y)h(the)h
+(BSCALE)e(and)h(BZER)m(O,)g(or)h(TSCALn)d(and)i(TZER)m(On)f(k)m(eyw)m
+(ord)i(v)-5 b(alues\))24 b(in)f(b)m(yte)i(arra)m(ys)0
+1892 y(\(BITPIX)37 b(=)f(8\))h(or)f(b)m(yte)i(columns)d(\(TF)m(ORMn)i
+(=)f('B'\))h(are)g(in)m(terpreted)f(as)h(unsigned)d(b)m(ytes)j(with)f
+(v)-5 b(alues)0 2005 y(ranging)33 b(from)h(0)g(to)h(255.)53
+b(Some)34 b(C)g(compilers)f(de\014ne)g(a)h('c)m(har')h(v)-5
+b(ariable)33 b(as)i(signed,)f(so)g(it)g(is)f(imp)s(ortan)m(t)g(to)0
+2118 y(explicitly)28 b(declare)i(a)h(n)m(umeric)e(c)m(har)i(v)-5
+b(ariable)29 b(as)i('unsigned)d(c)m(har')j(to)g(a)m(v)m(oid)g(an)m(y)g
+(am)m(biguit)m(y)0 2278 y(One)22 b(feature)h(of)g(the)g(CFITSIO)e
+(routines)h(is)f(that)j(they)f(can)g(op)s(erate)g(on)f(a)h(`X')h
+(\(bit\))e(column)g(in)f(a)i(binary)e(table)0 2391 y(as)33
+b(though)f(it)g(w)m(ere)h(a)g(`B')g(\(b)m(yte\))h(column.)46
+b(F)-8 b(or)33 b(example)f(a)h(`11X')h(data)f(t)m(yp)s(e)g(column)e
+(can)i(b)s(e)f(in)m(terpreted)0 2503 y(the)c(same)h(as)f(a)g(`2B')i
+(column)d(\(i.e.,)i(2)f(unsigned)e(8-bit)i(b)m(ytes\).)41
+b(In)27 b(some)i(instances,)f(it)f(can)i(b)s(e)e(more)h(e\016cien)m(t)0
+2616 y(to)j(read)f(and)g(write)g(whole)f(b)m(ytes)i(at)g(a)g(time,)f
+(rather)h(than)f(reading)f(or)i(writing)d(eac)m(h)k(individual)25
+b(bit.)0 2777 y(The)36 b(complex)h(and)f(double)g(precision)f(complex)i
+(data)h(t)m(yp)s(es)f(are)g(not)g(directly)f(supp)s(orted)f(in)h(ANSI)g
+(C)h(so)0 2889 y(these)g(data)g(t)m(yp)s(es)f(should)e(b)s(e)i(in)m
+(terpreted)g(as)g(pairs)f(of)i(\015oat)g(or)f(double)f(v)-5
+b(alues,)37 b(resp)s(ectiv)m(ely)-8 b(,)38 b(where)e(the)0
+3002 y(\014rst)30 b(v)-5 b(alue)29 b(in)h(eac)m(h)h(pair)e(is)h(the)g
+(real)g(part,)h(and)e(the)i(second)f(is)g(the)g(imaginary)f(part.)0
+3470 y Ff(4.4)135 b(Supp)t(ort)44 b(for)h(Unsigned)h(In)l(tegers)g(and)
+f(Signed)g(Bytes)0 3747 y Fj(Although)32 b(FITS)g(do)s(es)g(not)h
+(directly)f(supp)s(ort)f(unsigned)f(in)m(tegers)j(as)g(one)g(of)g(its)g
+(fundamen)m(tal)e(data)j(t)m(yp)s(es,)0 3860 y(FITS)27
+b(can)h(still)e(b)s(e)h(used)g(to)i(e\016cien)m(tly)f(store)g(unsigned)
+e(in)m(teger)i(data)h(v)-5 b(alues)27 b(in)g(images)h(and)f(binary)f
+(tables.)0 3973 y(The)42 b(con)m(v)m(en)m(tion)i(used)e(in)f(FITS)h
+(\014les)g(is)f(to)j(store)f(the)g(unsigned)d(in)m(tegers)j(as)g
+(signed)f(in)m(tegers)h(with)e(an)0 4086 y(asso)s(ciated)33
+b(o\013set)g(\(sp)s(eci\014ed)e(b)m(y)h(the)g(BZER)m(O)g(or)g(TZER)m
+(On)f(k)m(eyw)m(ord\).)47 b(F)-8 b(or)33 b(example,)f(to)h(store)g
+(unsigned)0 4199 y(16-bit)f(in)m(teger)g(v)-5 b(alues)31
+b(in)f(a)i(FITS)f(image)h(the)f(image)h(w)m(ould)f(b)s(e)f(de\014ned)h
+(as)h(a)g(signed)e(16-bit)i(in)m(teger)g(\(with)0 4312
+y(BITPIX)d(k)m(eyw)m(ord)g(=)g(SHOR)-8 b(T)p 1132 4312
+V 32 w(IMG)30 b(=)e(16\))j(with)c(the)j(k)m(eyw)m(ords)f(BSCALE)f(=)h
+(1.0)h(and)f(BZER)m(O)g(=)f(32768.)0 4425 y(Th)m(us)34
+b(the)h(unsigned)e(v)-5 b(alues)34 b(of)h(0,)i(32768,)h(and)d(65535,)j
+(for)d(example,)h(are)f(ph)m(ysically)e(stored)i(in)f(the)h(FITS)0
+4538 y(image)k(as)f(-32768,)43 b(0,)e(and)d(32767,)k(resp)s(ectiv)m
+(ely;)g(CFITSIO)37 b(automatically)h(adds)f(the)i(BZER)m(O)f(o\013set)h
+(to)0 4650 y(these)g(v)-5 b(alues)38 b(when)g(they)g(are)h(read.)65
+b(Similarly)-8 b(,)38 b(in)f(the)i(case)h(of)e(unsigned)f(32-bit)i(in)m
+(tegers)f(the)h(BITPIX)0 4763 y(k)m(eyw)m(ord)c(w)m(ould)e(b)s(e)h
+(equal)g(to)i(LONG)p 1392 4763 V 32 w(IMG)f(=)g(32)g(and)f(BZER)m(O)g
+(w)m(ould)g(b)s(e)g(equal)g(to)h(2147483648)k(\(i.e.)54
+b(2)0 4876 y(raised)29 b(to)i(the)g(31st)g(p)s(o)m(w)m(er\).)0
+5036 y(The)j(CFITSIO)g(in)m(terface)h(routines)f(will)e(e\016cien)m
+(tly)j(and)f(transparen)m(tly)h(apply)e(the)i(appropriate)f(o\013set)i
+(in)0 5149 y(these)29 b(cases)h(so)f(in)f(general)h(application)e
+(programs)i(do)g(not)g(need)f(to)i(b)s(e)e(concerned)h(with)f(ho)m(w)h
+(the)g(unsigned)0 5262 y(v)-5 b(alues)43 b(are)i(actually)f(stored)g
+(in)e(the)j(FITS)e(\014le.)81 b(As)44 b(a)g(con)m(v)m(enience)i(for)d
+(users,)k(CFITSIO)c(has)h(sev)m(eral)0 5375 y(prede\014ned)19
+b(constan)m(ts)j(for)f(the)g(v)-5 b(alue)20 b(of)h(BITPIX)g(\(USHOR)-8
+b(T)p 2189 5375 V 33 w(IMG,)21 b(ULONG)p 2790 5375 V
+33 w(IMG\))h(and)e(for)h(the)g(TF)m(ORMn)0 5488 y(v)-5
+b(alue)35 b(in)f(the)i(case)g(of)g(binary)e(tables)h(\(`U')i(and)e
+(`V'\))h(whic)m(h)e(programmers)h(can)h(use)f(when)g(creating)h(FITS)0
+5601 y(\014les)i(con)m(taining)g(unsigned)f(in)m(teger)i(v)-5
+b(alues.)65 b(The)39 b(follo)m(wing)e(co)s(de)i(fragmen)m(t)g
+(illustrates)e(ho)m(w)i(to)h(write)e(a)0 5714 y(FITS)30
+b(1-D)h(primary)e(arra)m(y)h(of)h(unsigned)d(16-bit)j(in)m(tegers:)p
+eop
+%%Page: 20 28
+20 27 bop 0 299 a Fj(20)1763 b Fh(CHAPTER)29 b(4.)112
+b(PR)m(OGRAMMING)32 b(GUIDELINES)286 555 y Fe(unsigned)46
+b(short)g(uarray[100];)286 668 y(int)h(naxis,)f(status;)286
+781 y(long)h(naxes[10],)e(group,)h(firstelem,)f(nelements;)334
+894 y(...)286 1007 y(status)h(=)i(0;)286 1120 y(naxis)f(=)g(1;)286
+1233 y(naxes[0])f(=)h(100;)286 1346 y(fits_create_img\(fptr,)42
+b(USHORT_IMG,)j(naxis,)h(naxes,)g(&status\);)286 1571
+y(firstelem)g(=)h(1;)286 1684 y(nelements)f(=)h(100;)286
+1797 y(fits_write_img\(fptr,)c(TUSHORT,)i(firstelem,)g(nelements,)1241
+1910 y(uarray,)h(&status\);)334 2023 y(...)0 2264 y Fj(In)40
+b(the)h(ab)s(o)m(v)m(e)i(example,)g(the)f(2nd)e(parameter)h(in)f
+(\014ts)p 1998 2264 28 4 v 33 w(create)p 2267 2264 V
+34 w(img)g(tells)g(CFITSIO)g(to)i(write)e(the)h(header)0
+2377 y(k)m(eyw)m(ords)34 b(appropriate)f(for)g(an)g(arra)m(y)i(of)e
+(16-bit)h(unsigned)e(in)m(tegers)i(\(i.e.,)h(BITPIX)e(=)g(16)i(and)e
+(BZER)m(O)g(=)0 2490 y(32768\).)41 b(Then)23 b(the)h(\014ts)p
+834 2490 V 32 w(write)p 1069 2490 V 32 w(img)g(routine)f(writes)f(the)j
+(arra)m(y)f(of)g(unsigned)e(short)h(in)m(tegers)h(\(uarra)m(y\))h(in)m
+(to)f(the)0 2603 y(primary)f(arra)m(y)i(of)g(the)g(FITS)f(\014le.)38
+b(Similarly)-8 b(,)23 b(a)i(32-bit)h(unsigned)c(in)m(teger)j(image)h
+(ma)m(y)f(b)s(e)f(created)i(b)m(y)f(setting)0 2716 y(the)34
+b(second)f(parameter)h(in)e(\014ts)p 1130 2716 V 33 w(create)p
+1399 2716 V 34 w(img)h(equal)g(to)h(`ULONG)p 2330 2716
+V 33 w(IMG')g(and)f(b)m(y)h(calling)d(the)j(\014ts)p
+3491 2716 V 33 w(write)p 3727 2716 V 32 w(img)0 2829
+y(routine)i(with)f(the)i(second)f(parameter)h(=)f(TULONG)h(to)g(write)f
+(the)g(arra)m(y)h(of)g(unsigned)e(long)h(image)h(pixel)0
+2942 y(v)-5 b(alues.)0 3102 y(An)27 b(analogous)g(set)g(of)g(routines)f
+(are)h(a)m(v)-5 b(ailable)27 b(for)f(reading)g(or)h(writing)e(unsigned)
+g(in)m(teger)i(v)-5 b(alues)27 b(and)f(signed)0 3215
+y(b)m(yte)i(v)-5 b(alues)27 b(in)g(a)h(FITS)f(binary)f(table)i
+(extension.)39 b(When)28 b(sp)s(ecifying)d(the)j(TF)m(ORMn)g(k)m(eyw)m
+(ord)g(v)-5 b(alue)27 b(whic)m(h)0 3328 y(de\014nes)36
+b(the)h(format)g(of)g(a)h(column,)f(CFITSIO)e(recognized)j(3)f
+(additional)e(data)i(t)m(yp)s(e)g(co)s(des)g(b)s(esides)e(those)0
+3440 y(already)29 b(de\014ned)g(in)f(the)i(FITS)f(standard:)40
+b(`U')30 b(meaning)f(a)h(16-bit)g(unsigned)e(in)m(teger)i(column,)f
+(`V')h(for)g(a)g(32-)0 3553 y(bit)25 b(unsigned)e(in)m(teger)j(column,)
+g(and)f('S')g(for)g(a)h(signed)f(b)m(yte)h(column.)38
+b(These)25 b(non-standard)g(data)h(t)m(yp)s(e)g(co)s(des)0
+3666 y(are)36 b(not)g(actually)g(written)f(in)m(to)g(the)h(FITS)g
+(\014le)e(but)i(instead)f(are)h(just)f(used)g(in)m(ternally)f(within)f
+(CFITSIO.)0 3779 y(The)d(follo)m(wing)f(co)s(de)h(fragmen)m(t)h
+(illustrates)e(ho)m(w)h(to)h(use)f(these)h(features:)286
+4020 y Fe(unsigned)46 b(short)g(uarray[100];)286 4133
+y(unsigned)g(int)95 b(varray[100];)286 4359 y(int)47
+b(colnum,)f(tfields,)g(status;)286 4472 y(long)h(nrows,)f(firstrow,)f
+(firstelem,)g(nelements,)g(pcount;)286 4698 y(char)i(extname[])e(=)j
+("Test_table";)521 b(/*)47 b(extension)f(name)g(*/)286
+4924 y(/*)i(define)e(the)h(name,)f(data)h(type,)f(and)h(physical)e
+(units)i(for)g(the)g(2)g(columns)f(*/)286 5036 y(char)h(*ttype[])f(=)h
+({)g("Col_1",)f("Col_2",)g("Col_3")f(};)286 5149 y(char)i(*tform[])f(=)
+h({)g("1U",)285 b("1V",)190 b("1S"};)94 b(/*)47 b(special)f(CFITSIO)g
+(codes)g(*/)286 5262 y(char)h(*tunit[])f(=)h({)g(")h(",)381
+b(")48 b(",)190 b(")47 b(")h(};)334 5375 y(...)525 5601
+y(/*)f(write)g(the)f(header)h(keywords)e(*/)286 5714
+y(status)94 b(=)48 b(0;)p eop
+%%Page: 21 29
+21 28 bop 0 299 a Fh(4.5.)72 b(DEALING)31 b(WITH)f(CHARA)m(CTER)g
+(STRINGS)1816 b Fj(21)286 555 y Fe(nrows)142 b(=)48 b(1;)286
+668 y(tfields)e(=)i(3)286 781 y(pcount)94 b(=)48 b(0;)286
+894 y(fits_create_tbl\(fptr,)42 b(BINARY_TBL,)j(nrows,)h(tfields,)g
+(ttype,)g(tform,)764 1007 y(tunit,)g(extname,)f(&status\);)525
+1233 y(/*)i(write)g(the)f(unsigned)g(shorts)g(to)h(the)g(1st)g(column)f
+(*/)286 1346 y(colnum)190 b(=)47 b(1;)286 1458 y(firstrow)94
+b(=)47 b(1;)286 1571 y(firstelem)f(=)h(1;)286 1684 y(nelements)f(=)h
+(100;)286 1797 y(fits_write_col\(fptr,)c(TUSHORT,)i(colnum,)h
+(firstrow,)f(firstelem,)668 1910 y(nelements,)g(uarray,)h(&status\);)
+525 2136 y(/*)h(now)g(write)f(the)h(unsigned)f(longs)g(to)h(the)g(2nd)g
+(column)f(*/)286 2249 y(colnum)190 b(=)47 b(2;)286 2362
+y(fits_write_col\(fptr,)c(TUINT,)j(colnum,)g(firstrow,)f(firstelem,)668
+2475 y(nelements,)g(varray,)h(&status\);)334 2588 y(...)0
+2865 y Fj(Note)22 b(that)g(the)f(non-standard)f(TF)m(ORM)h(v)-5
+b(alues)20 b(for)h(the)g(3)g(columns,)h(`U')f(and)g(`V',)h(tell)e
+(CFITSIO)f(to)j(write)e(the)0 2978 y(k)m(eyw)m(ords)27
+b(appropriate)e(for)h(unsigned)e(16-bit)j(and)e(unsigned)g(32-bit)h(in)
+m(tegers,)i(resp)s(ectiv)m(ely)d(\(i.e.,)j(TF)m(ORMn)0
+3091 y(=)39 b('1I')i(and)e(TZER)m(On)f(=)h(32678)j(for)e(unsigned)d
+(16-bit)j(in)m(tegers,)j(and)c(TF)m(ORMn)h(=)f('1J')h(and)f(TZER)m(On)0
+3204 y(=)c(2147483648)40 b(for)35 b(unsigned)e(32-bit)i(in)m(tegers\).)
+56 b(The)35 b('S')g(TF)m(ORMn)g(v)-5 b(alue)35 b(tells)g(CFITSIO)e(to)j
+(write)f(the)0 3317 y(k)m(eyw)m(ords)30 b(appropriate)f(for)h(a)g
+(signed)f(8-bit)h(b)m(yte)g(column)f(with)f(TF)m(ORMn)i(=)g('1B')h(and)
+e(TZER)m(On)g(=)g(-128.)0 3430 y(The)h(calls)f(to)j(\014ts)p
+628 3430 28 4 v 32 w(write)p 863 3430 V 32 w(col)e(then)g(write)g(the)h
+(arra)m(ys)f(of)h(unsigned)d(in)m(teger)j(v)-5 b(alues)30
+b(to)h(the)f(columns.)0 3784 y Ff(4.5)135 b(Dealing)47
+b(with)e(Character)h(Strings)0 4039 y Fj(The)36 b(c)m(haracter)j
+(string)c(v)-5 b(alues)37 b(in)e(a)i(FITS)f(header)h(or)g(in)e(an)i
+(ASCI)s(I)e(column)h(in)f(a)j(FITS)e(table)g(extension)0
+4152 y(are)j(generally)g(padded)f(out)h(with)f(non-signi\014can)m(t)g
+(space)h(c)m(haracters)i(\(ASCI)s(I)d(32\))i(to)g(\014ll)d(up)h(the)h
+(header)0 4264 y(record)33 b(or)h(the)f(column)g(width.)48
+b(When)33 b(reading)g(a)h(FITS)e(string)h(v)-5 b(alue,)34
+b(the)f(CFITSIO)f(routines)h(will)d(strip)0 4377 y(o\013)38
+b(these)f(non-signi\014can)m(t)f(trailing)f(spaces)i(and)g(will)d
+(return)i(a)i(n)m(ull-terminated)d(string)h(v)-5 b(alue)36
+b(con)m(taining)0 4490 y(only)d(the)h(signi\014can)m(t)e(c)m
+(haracters.)52 b(Leading)33 b(spaces)h(in)f(a)h(FITS)f(string)f(are)i
+(considered)f(signi\014can)m(t.)50 b(If)33 b(the)0 4603
+y(string)h(con)m(tains)h(all)f(blanks,)h(then)f(CFITSIO)g(will)e
+(return)i(a)h(single)e(blank)h(c)m(haracter,)k(i.e,)e(the)f(\014rst)f
+(blank)0 4716 y(is)29 b(considered)f(to)j(b)s(e)e(signi\014can)m(t,)g
+(since)g(it)g(distinguishes)e(the)j(string)e(from)i(a)g(n)m(ull)d(or)j
+(unde\014ned)e(string,)h(but)0 4829 y(the)i(remaining)d(trailing)g
+(spaces)j(are)g(not)g(signi\014can)m(t.)0 4989 y(Similarly)-8
+b(,)37 b(when)g(writing)f(string)h(v)-5 b(alues)37 b(to)i(a)g(FITS)e
+(\014le)g(the)h(CFITSIO)f(routines)g(exp)s(ect)h(to)h(get)g(a)g(n)m
+(ull-)0 5102 y(terminated)32 b(string)g(as)h(input;)f(CFITSIO)f(will)f
+(pad)i(the)h(string)f(with)f(blanks)g(if)h(necessary)h(when)f(writing)e
+(it)0 5215 y(to)h(the)g(FITS)e(\014le.)0 5375 y(When)j(calling)f
+(CFITSIO)g(routines)h(that)h(return)e(a)i(c)m(haracter)h(string)e(it)g
+(is)f(vital)h(that)h(the)g(size)f(of)h(the)g(c)m(har)0
+5488 y(arra)m(y)38 b(b)s(e)g(large)g(enough)f(to)i(hold)d(the)i(en)m
+(tire)g(string)f(of)h(c)m(haracters,)k(otherwise)37 b(CFITSIO)f(will)f
+(o)m(v)m(erwrite)0 5601 y(whatev)m(er)g(memory)e(lo)s(cations)g(follo)m
+(w)g(the)h(c)m(har)h(arra)m(y)-8 b(,)35 b(p)s(ossibly)c(causing)i(the)h
+(program)g(to)g(execute)h(incor-)0 5714 y(rectly)-8 b(.)41
+b(This)29 b(t)m(yp)s(e)h(of)h(error)f(can)h(b)s(e)f(di\016cult)e(to)j
+(debug,)f(so)h(programmers)f(should)e(alw)m(a)m(ys)j(ensure)f(that)h
+(the)p eop
+%%Page: 22 30
+22 29 bop 0 299 a Fj(22)1763 b Fh(CHAPTER)29 b(4.)112
+b(PR)m(OGRAMMING)32 b(GUIDELINES)0 555 y Fj(c)m(har)27
+b(arra)m(ys)g(are)g(allo)s(cated)g(enough)f(space)i(to)f(hold)f(the)g
+(longest)h(p)s(ossible)e(string,)h Fi(including)i Fj(the)f(terminat-)0
+668 y(ing)j(NULL)h(c)m(haracter.)45 b(The)30 b(\014tsio.h)g(\014le)h
+(con)m(tains)g(the)g(follo)m(wing)f(de\014ned)g(constan)m(ts)i(whic)m
+(h)e(programmers)0 781 y(are)h(strongly)f(encouraged)h(to)g(use)f
+(whenev)m(er)g(they)h(are)f(allo)s(cating)g(space)h(for)f(c)m(har)h
+(arra)m(ys:)0 1025 y Fe(#define)46 b(FLEN_FILENAME)e(1025)j(/*)g(max)g
+(length)f(of)h(a)g(filename)f(*/)0 1138 y(#define)g(FLEN_KEYWORD)140
+b(72)95 b(/*)47 b(max)g(length)f(of)h(a)g(keyword)94
+b(*/)0 1251 y(#define)46 b(FLEN_CARD)284 b(81)95 b(/*)47
+b(length)f(of)h(a)h(FITS)e(header)g(card)h(*/)0 1364
+y(#define)f(FLEN_VALUE)236 b(71)95 b(/*)47 b(max)g(length)f(of)h(a)g
+(keyword)f(value)h(string)f(*/)0 1477 y(#define)g(FLEN_COMMENT)140
+b(73)95 b(/*)47 b(max)g(length)f(of)h(a)g(keyword)f(comment)g(string)g
+(*/)0 1590 y(#define)g(FLEN_ERRMSG)188 b(81)95 b(/*)47
+b(max)g(length)f(of)h(a)g(CFITSIO)f(error)h(message)e(*/)0
+1703 y(#define)h(FLEN_STATUS)188 b(31)95 b(/*)47 b(max)g(length)f(of)h
+(a)g(CFITSIO)f(status)g(text)h(string)f(*/)0 1947 y Fj(F)-8
+b(or)23 b(example,)g(when)e(declaring)g(a)h(c)m(har)g(arra)m(y)h(to)f
+(hold)f(the)h(v)-5 b(alue)21 b(string)g(of)h(FITS)f(k)m(eyw)m(ord,)k
+(use)c(the)h(follo)m(wing)0 2060 y(statemen)m(t:)191
+2304 y Fe(char)47 b(value[FLEN_VALUE];)0 2548 y Fj(Note)41
+b(that)f(FLEN)p 686 2548 28 4 v 33 w(KEYW)m(ORD)g(is)e(longer)h(than)g
+(needed)g(for)g(the)h(nominal)d(8-c)m(haracter)42 b(k)m(eyw)m(ord)e
+(name)0 2661 y(b)s(ecause)30 b(the)h(HIERAR)m(CH)f(con)m(v)m(en)m(tion)
+i(supp)s(orts)c(longer)i(k)m(eyw)m(ord)h(names.)0 2992
+y Ff(4.6)135 b(Implicit)46 b(Data)g(T)l(yp)t(e)f(Con)l(v)l(ersion)0
+3242 y Fj(The)29 b(CFITSIO)e(routines)h(that)i(read)f(and)f(write)h(n)m
+(umerical)e(data)j(can)g(p)s(erform)d(implicit)f(data)k(t)m(yp)s(e)f
+(con)m(v)m(er-)0 3355 y(sion.)38 b(This)24 b(means)i(that)g(the)g(data)
+g(t)m(yp)s(e)g(of)g(the)g(v)-5 b(ariable)24 b(or)i(arra)m(y)g(in)e(the)
+i(program)g(do)s(es)f(not)h(need)f(to)i(b)s(e)e(the)0
+3468 y(same)g(as)f(the)h(data)g(t)m(yp)s(e)g(of)f(the)h(v)-5
+b(alue)24 b(in)f(the)h(FITS)g(\014le.)38 b(Data)26 b(t)m(yp)s(e)f(con)m
+(v)m(ersion)f(is)g(supp)s(orted)e(for)i(n)m(umerical)0
+3581 y(and)37 b(string)f(data)h(t)m(yp)s(es)h(\(if)e(the)h(string)f
+(con)m(tains)i(a)f(v)-5 b(alid)36 b(n)m(um)m(b)s(er)g(enclosed)g(in)g
+(quotes\))i(when)e(reading)h(a)0 3694 y(FITS)30 b(header)h(k)m(eyw)m
+(ord)g(v)-5 b(alue)30 b(and)g(for)h(n)m(umeric)f(v)-5
+b(alues)30 b(when)g(reading)g(or)g(writing)f(v)-5 b(alues)30
+b(in)g(the)h(primary)0 3807 y(arra)m(y)24 b(or)g(a)h(table)e(column.)38
+b(CFITSIO)22 b(returns)h(status)h(=)f(NUM)p 2267 3807
+V 34 w(O)m(VERFLO)m(W)i(if)d(the)i(con)m(v)m(erted)i(data)e(v)-5
+b(alue)0 3920 y(exceeds)33 b(the)g(range)g(of)g(the)f(output)g(data)i
+(t)m(yp)s(e.)47 b(Implicit)30 b(data)j(t)m(yp)s(e)g(con)m(v)m(ersion)g
+(is)e(not)i(supp)s(orted)d(within)0 4032 y(binary)f(tables)h(for)g
+(string,)f(logical,)i(complex,)f(or)g(double)f(complex)h(data)h(t)m(yp)
+s(es.)0 4193 y(In)g(addition,)f(an)m(y)h(table)g(column)f(ma)m(y)i(b)s
+(e)f(read)g(as)h(if)e(it)h(con)m(tained)g(string)f(v)-5
+b(alues.)43 b(In)31 b(the)g(case)i(of)e(n)m(umeric)0
+4306 y(columns)e(the)i(returned)e(string)g(will)f(b)s(e)i(formatted)h
+(using)d(the)j(TDISPn)e(displa)m(y)g(format)h(if)g(it)g(exists.)0
+4637 y Ff(4.7)135 b(Data)46 b(Scaling)0 4887 y Fj(When)38
+b(reading)e(n)m(umerical)h(data)h(v)-5 b(alues)37 b(in)f(the)i(primary)
+e(arra)m(y)i(or)g(a)g(table)g(column,)h(the)e(v)-5 b(alues)37
+b(will)f(b)s(e)0 5000 y(scaled)h(automatically)h(b)m(y)f(the)g(BSCALE)g
+(and)g(BZER)m(O)g(\(or)h(TSCALn)e(and)h(TZER)m(On\))f(header)h(v)-5
+b(alues)37 b(if)0 5113 y(they)31 b(are)f(presen)m(t)h(in)e(the)h
+(header.)41 b(The)30 b(scaled)g(data)h(that)g(is)e(returned)h(to)h(the)
+f(reading)g(program)g(will)e(ha)m(v)m(e)382 5357 y Fe(output)46
+b(value)g(=)i(\(FITS)e(value\))g(*)i(BSCALE)e(+)h(BZERO)0
+5601 y Fj(\(a)30 b(corresp)s(onding)d(form)m(ula)h(using)g(TSCALn)f
+(and)i(TZER)m(On)e(is)h(used)h(when)f(reading)g(from)h(table)g
+(columns\).)0 5714 y(In)i(the)i(case)g(of)f(in)m(teger)g(output)g(v)-5
+b(alues)31 b(the)i(\015oating)f(p)s(oin)m(t)f(scaled)g(v)-5
+b(alue)32 b(is)f(truncated)h(to)h(an)f(in)m(teger)g(\(not)p
+eop
+%%Page: 23 31
+23 30 bop 0 299 a Fh(4.8.)72 b(SUPPOR)-8 b(T)30 b(F)m(OR)g(IEEE)g
+(SPECIAL)f(V)-10 b(ALUES)1863 b Fj(23)0 555 y(rounded)35
+b(to)j(the)f(nearest)h(in)m(teger\).)61 b(The)36 b(\014ts)p
+1673 555 28 4 v 32 w(set)p 1816 555 V 34 w(bscale)h(and)f(\014ts)p
+2430 555 V 32 w(set)p 2573 555 V 34 w(tscale)h(routines)f(\(describ)s
+(ed)f(in)h(the)0 668 y(`Adv)-5 b(anced')29 b(c)m(hapter\))h(ma)m(y)g(b)
+s(e)e(used)h(to)g(o)m(v)m(erride)h(the)f(scaling)f(parameters)h
+(de\014ned)f(in)g(the)h(header)g(\(e.g.,)i(to)0 781 y(turn)e(o\013)i
+(the)g(scaling)e(so)i(that)g(the)f(program)g(can)h(read)f(the)h(ra)m(w)
+f(unscaled)g(v)-5 b(alues)29 b(from)h(the)h(FITS)e(\014le\).)0
+941 y(When)44 b(writing)f(n)m(umerical)g(data)i(to)g(the)g(primary)e
+(arra)m(y)i(or)f(to)h(a)g(table)g(column)e(the)i(data)g(v)-5
+b(alues)44 b(will)0 1054 y(generally)27 b(b)s(e)h(automatically)g(in)m
+(v)m(ersely)g(scaled)g(b)m(y)g(the)g(v)-5 b(alue)28 b(of)g(the)h
+(BSCALE)e(and)h(BZER)m(O)g(\(or)h(TSCALn)0 1167 y(and)35
+b(TZER)m(On\))f(k)m(eyw)m(ord)i(v)-5 b(alues)34 b(if)h(they)g(they)g
+(exist)h(in)e(the)h(header.)55 b(These)35 b(k)m(eyw)m(ords)h(m)m(ust)f
+(ha)m(v)m(e)i(b)s(een)0 1280 y(written)30 b(to)i(the)g(header)f(b)s
+(efore)g(an)m(y)g(data)h(is)f(written)f(for)h(them)g(to)h(ha)m(v)m(e)h
+(an)m(y)e(immediate)g(e\013ect.)45 b(One)30 b(ma)m(y)0
+1393 y(also)g(use)h(the)f(\014ts)p 623 1393 V 33 w(set)p
+767 1393 V 33 w(bscale)h(and)e(\014ts)p 1367 1393 V 33
+w(set)p 1511 1393 V 33 w(tscale)i(routines)f(to)h(de\014ne)f(or)g(o)m
+(v)m(erride)h(the)g(scaling)e(k)m(eyw)m(ords)i(in)0 1506
+y(the)e(header)g(\(e.g.,)i(to)e(turn)f(o\013)h(the)g(scaling)f(so)h
+(that)h(the)f(program)f(can)h(write)f(the)h(ra)m(w)g(unscaled)f(v)-5
+b(alues)28 b(in)m(to)0 1619 y(the)e(FITS)g(\014le\).)39
+b(If)25 b(scaling)g(is)h(p)s(erformed,)f(the)i(in)m(v)m(erse)f(scaled)g
+(output)f(v)-5 b(alue)26 b(that)h(is)e(written)g(in)m(to)h(the)h(FITS)0
+1732 y(\014le)i(will)f(ha)m(v)m(e)430 1992 y Fe(FITS)46
+b(value)h(=)g(\(\(input)f(value\))g(-)h(BZERO\))f(/)i(BSCALE)0
+2252 y Fj(\(a)39 b(corresp)s(onding)c(form)m(ula)i(using)g(TSCALn)f
+(and)h(TZER)m(On)g(is)g(used)g(when)f(writing)g(to)j(table)f
+(columns\).)0 2365 y(Rounding)33 b(to)j(the)g(nearest)g(in)m(teger,)h
+(rather)e(than)g(truncation,)i(is)d(p)s(erformed)g(when)g(writing)f(in)
+m(teger)j(data)0 2478 y(t)m(yp)s(es)30 b(to)i(the)e(FITS)g(\014le.)0
+2812 y Ff(4.8)135 b(Supp)t(ort)44 b(for)h(IEEE)h(Sp)t(ecial)f(V)-11
+b(alues)0 3062 y Fj(The)26 b(ANSI/IEEE-754)h(\015oating-p)s(oin)m(t)f
+(n)m(um)m(b)s(er)f(standard)g(de\014nes)h(certain)g(sp)s(ecial)f(v)-5
+b(alues)25 b(that)i(are)g(used)e(to)0 3175 y(represen)m(t)j(suc)m(h)g
+(quan)m(tities)f(as)h(Not-a-Num)m(b)s(er)h(\(NaN\),)h(denormalized,)d
+(under\015o)m(w,)g(o)m(v)m(er\015o)m(w,)j(and)d(in\014nit)m(y)-8
+b(.)0 3288 y(\(See)29 b(the)f(App)s(endix)d(in)i(the)h(NOST)g(FITS)f
+(standard)g(or)h(the)g(NOST)g(FITS)f(User's)h(Guide)f(for)h(a)g(list)f
+(of)h(these)0 3401 y(v)-5 b(alues\).)54 b(The)34 b(CFITSIO)f(routines)h
+(that)h(read)g(\015oating)f(p)s(oin)m(t)g(data)i(in)d(FITS)h(\014les)g
+(recognize)h(these)h(IEEE)0 3514 y(sp)s(ecial)22 b(v)-5
+b(alues)24 b(and)f(b)m(y)g(default)g(in)m(terpret)h(the)g(o)m(v)m
+(er\015o)m(w)h(and)e(in\014nit)m(y)e(v)-5 b(alues)24
+b(as)g(b)s(eing)e(equiv)-5 b(alen)m(t)23 b(to)i(a)f(NaN,)0
+3627 y(and)36 b(con)m(v)m(ert)i(the)e(under\015o)m(w)f(and)h
+(denormalized)f(v)-5 b(alues)35 b(in)m(to)i(zeros.)59
+b(In)36 b(some)g(cases)i(programmers)d(ma)m(y)0 3740
+y(w)m(an)m(t)d(access)h(to)g(the)e(ra)m(w)h(IEEE)f(v)-5
+b(alues,)31 b(without)g(an)m(y)h(mo)s(di\014cation)e(b)m(y)h(CFITSIO.)f
+(This)g(can)i(b)s(e)f(done)g(b)m(y)0 3853 y(calling)26
+b(the)j(\014ts)p 567 3853 V 32 w(read)p 771 3853 V 33
+w(img)e(or)h(\014ts)p 1209 3853 V 33 w(read)p 1414 3853
+V 32 w(col)g(routines)f(while)f(sp)s(ecifying)g(0.0)j(as)f(the)g(v)-5
+b(alue)28 b(of)g(the)g(NULL)-10 b(V)g(AL)0 3966 y(parameter.)59
+b(This)35 b(will)e(force)k(CFITSIO)e(to)i(simply)d(pass)i(the)h(IEEE)f
+(v)-5 b(alues)35 b(through)h(to)h(the)g(application)0
+4079 y(program)31 b(without)f(an)m(y)i(mo)s(di\014cation.)42
+b(This)29 b(is)i(not)g(fully)e(supp)s(orted)h(on)h(V)-10
+b(AX/VMS)32 b(mac)m(hines,)f(ho)m(w)m(ev)m(er,)0 4192
+y(where)f(there)g(is)g(no)g(easy)h(w)m(a)m(y)g(to)h(b)m(ypass)e(the)g
+(default)g(in)m(terpretation)f(of)i(the)g(IEEE)e(sp)s(ecial)g(v)-5
+b(alues.)0 4526 y Ff(4.9)135 b(Error)46 b(Status)f(V)-11
+b(alues)45 b(and)g(the)g(Error)g(Message)h(Stac)l(k)0
+4776 y Fj(Nearly)35 b(all)f(the)i(CFITSIO)e(routines)g(return)g(an)h
+(error)g(status)h(v)-5 b(alue)34 b(in)g(2)i(w)m(a)m(ys:)51
+b(as)36 b(the)f(v)-5 b(alue)35 b(of)h(the)f(last)0 4889
+y(parameter)29 b(in)e(the)h(function)f(call,)i(and)f(as)g(the)h
+(returned)e(v)-5 b(alue)28 b(of)g(the)h(function)e(itself.)39
+b(This)26 b(pro)m(vides)i(some)0 5002 y(\015exibilit)m(y)33
+b(in)h(the)i(w)m(a)m(y)h(programmers)e(can)h(test)h(if)e(an)g(error)h
+(o)s(ccurred,)g(as)g(illustrated)e(in)g(the)i(follo)m(wing)f(2)0
+5115 y(co)s(de)c(fragmen)m(ts:)191 5375 y Fe(if)47 b(\()h
+(fits_write_record\(fptr,)41 b(card,)46 b(&status\))g(\))430
+5488 y(printf\(")f(Error)h(occurred)g(while)g(writing)g(keyword."\);)0
+5714 y(or,)p eop
+%%Page: 24 32
+24 31 bop 0 299 a Fj(24)1763 b Fh(CHAPTER)29 b(4.)112
+b(PR)m(OGRAMMING)32 b(GUIDELINES)191 668 y Fe(fits_write_record\(fptr,)
+41 b(card,)47 b(&status\);)191 781 y(if)g(\()h(status)e(\))430
+894 y(printf\(")f(Error)h(occurred)g(while)g(writing)g(keyword."\);)0
+1109 y Fj(A)27 b(listing)e(of)j(all)e(the)h(CFITSIO)f(status)i(co)s(de)
+f(v)-5 b(alues)27 b(is)f(giv)m(en)h(at)h(the)g(end)e(of)i(this)e(do)s
+(cumen)m(t.)39 b(Programmers)0 1222 y(are)33 b(encouraged)g(to)g(use)f
+(the)h(sym)m(b)s(olic)d(mnemonics)h(\(de\014ned)h(in)f(\014tsio.h\))h
+(rather)g(than)g(the)h(actual)g(in)m(teger)0 1335 y(status)e(v)-5
+b(alues)29 b(to)j(impro)m(v)m(e)e(the)g(readabilit)m(y)f(of)i(their)e
+(co)s(de.)0 1495 y(The)j(CFITSIO)f(library)e(uses)j(an)g(`inherited)f
+(status')i(con)m(v)m(en)m(tion)g(for)f(the)h(status)f(parameter)h(whic)
+m(h)e(means)0 1608 y(that)37 b(if)e(a)i(routine)e(is)h(called)f(with)g
+(a)i(p)s(ositiv)m(e)e(input)g(v)-5 b(alue)36 b(of)g(the)h(status)f
+(parameter)h(as)g(input,)f(then)g(the)0 1721 y(routine)i(will)d(exit)k
+(immediately)e(without)g(c)m(hanging)i(the)f(v)-5 b(alue)38
+b(of)h(the)g(status)g(parameter.)65 b(Th)m(us,)40 b(if)e(one)0
+1834 y(passes)24 b(the)h(status)g(v)-5 b(alue)24 b(returned)g(from)g
+(eac)m(h)i(CFITSIO)d(routine)g(as)i(input)e(to)i(the)g(next)g(CFITSIO)e
+(routine,)0 1947 y(then)28 b(whenev)m(er)g(an)g(error)g(is)g(detected)h
+(all)f(further)f(CFITSIO)f(pro)s(cessing)h(will)f(cease.)42
+b(This)26 b(con)m(v)m(en)m(tion)k(can)0 2060 y(simplify)f(the)k(error)f
+(c)m(hec)m(king)i(in)d(application)g(programs)h(b)s(ecause)h(it)f(is)g
+(not)h(necessary)g(to)g(c)m(hec)m(k)i(the)d(v)-5 b(alue)0
+2173 y(of)30 b(the)g(status)h(parameter)f(after)h(ev)m(ery)g(single)d
+(CFITSIO)h(routine)g(call.)40 b(If)30 b(a)g(program)g(con)m(tains)g(a)h
+(sequence)0 2285 y(of)d(sev)m(eral)h(CFITSIO)e(calls,)h(one)g(can)h
+(just)e(c)m(hec)m(k)j(the)f(status)f(v)-5 b(alue)28 b(after)h(the)f
+(last)g(call.)39 b(Since)28 b(the)g(returned)0 2398 y(status)33
+b(v)-5 b(alues)32 b(are)h(generally)f(distinctiv)m(e,)g(it)h(should)d
+(b)s(e)j(p)s(ossible)d(to)j(determine)f(whic)m(h)g(routine)g
+(originally)0 2511 y(returned)d(the)i(error)f(status.)0
+2671 y(CFITSIO)c(also)h(main)m(tains)g(an)g(in)m(ternal)f(stac)m(k)j
+(of)f(error)f(messages)h(\(80-c)m(haracter)j(maxim)m(um)26
+b(length\))h(whic)m(h)0 2784 y(in)35 b(man)m(y)h(cases)h(pro)m(vide)e
+(a)h(more)g(detailed)g(explanation)f(of)h(the)g(cause)h(of)f(the)g
+(error)g(than)f(is)g(pro)m(vided)g(b)m(y)0 2897 y(the)40
+b(error)e(status)i(n)m(um)m(b)s(er)e(alone.)68 b(It)39
+b(is)g(recommended)g(that)g(the)h(error)f(message)h(stac)m(k)h(b)s(e)e
+(prin)m(ted)f(out)0 3010 y(whenev)m(er)h(a)g(program)g(detects)h(a)f
+(CFITSIO)e(error.)66 b(The)38 b(function)g(\014ts)p 2653
+3010 28 4 v 32 w(rep)s(ort)p 2931 3010 V 32 w(error)h(will)d(prin)m(t)i
+(out)h(the)0 3123 y(en)m(tire)30 b(error)f(message)h(stac)m(k,)i(or)d
+(alternativ)m(ely)h(one)g(ma)m(y)g(call)f(\014ts)p 2376
+3123 V 32 w(read)p 2580 3123 V 33 w(errmsg)g(to)h(get)h(the)f(error)f
+(messages)0 3236 y(one)i(at)g(a)g(time.)0 3563 y Ff(4.10)136
+b(V)-11 b(ariable-Length)45 b(Arra)l(ys)g(in)g(Binary)g(T)-11
+b(ables)0 3813 y Fj(CFITSIO)33 b(pro)m(vides)h(easy-to-use)i(supp)s
+(ort)d(for)i(reading)f(and)g(writing)f(data)i(in)f(v)-5
+b(ariable)33 b(length)h(\014elds)g(of)h(a)0 3926 y(binary)f(table.)55
+b(The)35 b(v)-5 b(ariable)34 b(length)g(columns)g(ha)m(v)m(e)j(TF)m
+(ORMn)e(k)m(eyw)m(ord)h(v)-5 b(alues)34 b(of)i(the)f(form)g
+(`1Pt\(len\)')0 4039 y(where)25 b(`t')i(is)d(the)i(data)g(t)m(yp)s(e)g
+(co)s(de)g(\(e.g.,)j(I,)c(J,)h(E,)f(D,)i(etc.\))40 b(and)25
+b(`len')h(is)e(an)i(in)m(teger)g(sp)s(ecifying)d(the)j(maxim)m(um)0
+4152 y(length)g(of)h(the)h(v)m(ector)g(in)e(the)h(table.)39
+b(If)27 b(the)g(v)-5 b(alue)26 b(of)h(`len')g(is)f(not)h(sp)s
+(eci\014ed)e(when)h(the)h(table)g(is)f(created)i(\(e.g.,)0
+4264 y(if)33 b(the)h(TF)m(ORM)h(k)m(eyw)m(ord)g(v)-5
+b(alue)33 b(is)g(simply)f(sp)s(eci\014ed)h(as)h('1PE')h(instead)e(of)h
+('1PE\(400\))j(\),)f(then)d(CFITSIO)0 4377 y(will)27
+b(automatically)i(scan)g(the)h(table)f(when)g(it)g(is)f(closed)h(to)h
+(determine)f(the)g(maxim)m(um)f(length)h(of)h(the)f(v)m(ector)0
+4490 y(and)h(will)d(app)s(end)i(this)g(v)-5 b(alue)30
+b(to)h(the)g(TF)m(ORMn)f(v)-5 b(alue.)0 4650 y(The)29
+b(same)h(routines)f(that)h(read)f(and)g(write)g(data)h(in)f(an)g
+(ordinary)f(\014xed)h(length)g(binary)f(table)h(extension)h(are)0
+4763 y(also)40 b(used)e(for)i(v)-5 b(ariable)38 b(length)h(\014elds,)h
+(ho)m(w)m(ev)m(er,)k(the)c(routine)e(parameters)i(tak)m(e)h(on)f(a)g
+(sligh)m(tly)d(di\013eren)m(t)0 4876 y(in)m(terpretation)30
+b(as)g(describ)s(ed)f(b)s(elo)m(w.)0 5036 y(All)35 b(the)h(data)h(in)e
+(a)i(v)-5 b(ariable)35 b(length)g(\014eld)g(is)g(written)h(in)m(to)g
+(an)g(area)h(called)f(the)g(`heap')g(whic)m(h)f(follo)m(ws)h(the)0
+5149 y(main)30 b(\014xed-length)h(FITS)f(binary)g(table.)43
+b(The)31 b(size)g(of)g(the)h(heap,)f(in)f(b)m(ytes,)i(is)f(sp)s
+(eci\014ed)e(b)m(y)i(the)h(PCOUNT)0 5262 y(k)m(eyw)m(ord)21
+b(in)e(the)i(FITS)f(header.)37 b(When)20 b(creating)h(a)g(new)f(binary)
+f(table,)j(the)f(initial)d(v)-5 b(alue)20 b(of)g(PCOUNT)g(should)0
+5375 y(usually)25 b(b)s(e)j(set)g(to)g(zero.)41 b(CFITSIO)26
+b(will)f(recompute)j(the)g(size)f(of)h(the)g(heap)g(as)g(the)g(data)g
+(is)f(written)f(and)i(will)0 5488 y(automatically)d(up)s(date)f(the)i
+(PCOUNT)e(k)m(eyw)m(ord)h(v)-5 b(alue)25 b(when)f(the)h(table)g(is)f
+(closed.)39 b(When)25 b(writing)e(v)-5 b(ariable)0 5601
+y(length)33 b(data)h(to)g(a)g(table,)h(CFITSIO)d(will)e(automatically)k
+(extend)f(the)h(size)f(of)h(the)g(heap)f(area)h(if)f(necessary)-8
+b(,)0 5714 y(so)31 b(that)g(an)m(y)f(follo)m(wing)f(HDUs)i(do)f(not)h
+(get)h(o)m(v)m(erwritten.)p eop
+%%Page: 25 33
+25 32 bop 0 299 a Fh(4.11.)73 b(MUL)-8 b(TIPLE)30 b(A)m(CCESS)f(TO)g
+(THE)i(SAME)f(FITS)f(FILE)1515 b Fj(25)0 555 y(By)30
+b(default)e(the)i(heap)f(data)i(area)f(starts)g(immediately)e(after)i
+(the)f(last)h(ro)m(w)f(of)h(the)g(\014xed-length)e(table.)41
+b(This)0 668 y(default)26 b(starting)g(lo)s(cation)h(ma)m(y)g(b)s(e)f
+(o)m(v)m(erridden)g(b)m(y)h(the)g(THEAP)f(k)m(eyw)m(ord,)i(but)f(this)e
+(is)h(not)h(recommended.)0 781 y(If)34 b(additional)e(ro)m(ws)i(of)g
+(data)h(are)g(added)e(to)i(the)f(table,)i(CFITSIO)c(will)g
+(automatically)i(shift)e(the)j(the)f(heap)0 894 y(do)m(wn)g(to)i(mak)m
+(e)f(ro)s(om)g(for)f(the)h(new)f(ro)m(ws,)i(but)e(it)h(is)e(ob)m
+(viously)h(b)s(e)g(more)h(e\016cien)m(t)g(to)g(initially)c(create)37
+b(the)0 1007 y(table)30 b(with)e(the)i(necessary)g(n)m(um)m(b)s(er)f
+(of)h(blank)e(ro)m(ws,)i(so)g(that)g(the)g(heap)g(do)s(es)f(not)h
+(needed)g(to)g(b)s(e)f(constan)m(tly)0 1120 y(mo)m(v)m(ed.)0
+1280 y(When)g(writing)f(to)i(a)g(v)-5 b(ariable)29 b(length)g(\014eld)f
+(the)i(en)m(tire)f(arra)m(y)h(of)g(v)-5 b(alues)29 b(for)h(a)g(giv)m
+(en)f(ro)m(w)h(of)g(the)g(table)f(m)m(ust)0 1393 y(b)s(e)e(written)f
+(with)h(a)h(single)e(call)g(to)j(\014ts)p 1363 1393 28
+4 v 32 w(write)p 1598 1393 V 32 w(col.)40 b(The)27 b(total)h(length)f
+(of)h(the)g(arra)m(y)g(is)e(giv)m(en)i(b)m(y)f(nelemen)m(ts)g(+)0
+1506 y(\014rstelem)33 b(-)g(1.)51 b(Additional)31 b(elemen)m(ts)j
+(cannot)g(b)s(e)f(app)s(ended)f(to)i(an)f(existing)g(v)m(ector)i(at)f
+(a)g(later)f(time)h(since)0 1619 y(an)m(y)c(attempt)g(to)g(do)f(so)g
+(will)e(simply)f(o)m(v)m(erwrite)k(all)e(the)i(previously)c(written)j
+(data.)41 b(Note)30 b(also)f(that)h(the)f(new)0 1732
+y(data)c(will)d(b)s(e)i(written)g(to)h(a)g(new)f(area)i(of)f(the)f
+(heap)h(and)f(the)h(heap)f(space)h(used)f(b)m(y)h(the)f(previous)g
+(write)f(cannot)0 1844 y(b)s(e)32 b(reclaimed.)45 b(F)-8
+b(or)34 b(this)d(reason)h(eac)m(h)i(ro)m(w)f(of)f(a)h(v)-5
+b(ariable)31 b(length)h(\014eld)f(should)f(only)i(b)s(e)f(written)h
+(once.)47 b(An)0 1957 y(exception)37 b(to)g(this)f(general)g(rule)f(o)s
+(ccurs)i(when)e(setting)i(elemen)m(ts)g(of)g(an)f(arra)m(y)h(as)g
+(unde\014ned.)57 b(One)36 b(m)m(ust)0 2070 y(\014rst)30
+b(write)g(a)i(dumm)m(y)d(v)-5 b(alue)31 b(in)m(to)g(the)g(arra)m(y)g
+(with)f(\014ts)p 1977 2070 V 32 w(write)p 2212 2070 V
+32 w(col,)i(and)e(then)h(call)f(\014ts)p 3086 2070 V
+32 w(write)p 3321 2070 V 32 w(col)p 3464 2070 V 33 w(n)m(ul)g(to)i
+(\015ag)0 2183 y(the)g(desired)e(elemen)m(ts)i(as)g(unde\014ned.)43
+b(\(Do)33 b(not)f(use)g(the)g(\014ts)p 2197 2183 V 32
+w(write)p 2432 2183 V 32 w(coln)m(ull)e(routines)g(with)h(v)-5
+b(ariable)31 b(length)0 2296 y(\014elds\).)45 b(Note)33
+b(that)g(the)f(ro)m(ws)h(of)f(a)g(table,)h(whether)f(\014xed)f(or)h(v)
+-5 b(ariable)31 b(length,)i(do)f(not)g(ha)m(v)m(e)h(to)g(b)s(e)f
+(written)0 2409 y(consecutiv)m(ely)f(and)e(ma)m(y)i(b)s(e)f(written)f
+(in)h(an)m(y)g(order.)0 2569 y(When)40 b(writing)f(to)i(a)g(v)-5
+b(ariable)39 b(length)h(ASCI)s(I)f(c)m(haracter)j(\014eld)d(\(e.g.,)45
+b(TF)m(ORM)c(=)f('1P)-8 b(A'\))43 b(only)c(a)i(single)0
+2682 y(c)m(haracter)22 b(string)d(can)i(b)s(e)e(written.)37
+b(The)20 b(`\014rstelem')f(and)h(`nelemen)m(ts')h(parameter)f(v)-5
+b(alues)20 b(in)f(the)h(\014ts)p 3526 2682 V 33 w(write)p
+3762 2682 V 32 w(col)0 2795 y(routine)34 b(are)i(ignored)e(and)g(the)i
+(n)m(um)m(b)s(er)d(of)j(c)m(haracters)g(to)g(write)e(is)h(simply)d
+(determined)i(b)m(y)h(the)g(length)g(of)0 2908 y(the)c(input)d(n)m
+(ull-terminated)g(c)m(haracter)k(string.)0 3068 y(The)21
+b(\014ts)p 305 3068 V 33 w(write)p 541 3068 V 32 w(descript)f(routine)h
+(is)f(useful)g(in)g(situations)h(where)g(m)m(ultiple)e(ro)m(ws)j(of)g
+(a)g(v)-5 b(ariable)20 b(length)h(column)0 3181 y(ha)m(v)m(e)32
+b(the)e(iden)m(tical)f(arra)m(y)i(of)g(v)-5 b(alues.)40
+b(One)30 b(can)g(simply)e(write)i(the)g(arra)m(y)h(once)g(for)g(the)f
+(\014rst)g(ro)m(w,)g(and)g(then)0 3294 y(use)c(\014ts)p
+280 3294 V 32 w(write)p 515 3294 V 32 w(descript)f(to)h(write)f(the)h
+(same)h(descriptor)d(v)-5 b(alues)26 b(in)m(to)g(the)g(other)g(ro)m
+(ws;)h(all)e(the)h(ro)m(ws)g(will)d(then)0 3407 y(p)s(oin)m(t)29
+b(to)i(the)g(same)g(storage)h(lo)s(cation)e(th)m(us)g(sa)m(ving)g(disk)
+f(space.)0 3567 y(When)35 b(reading)f(from)g(a)i(v)-5
+b(ariable)33 b(length)i(arra)m(y)g(\014eld)f(one)h(can)g(only)g(read)f
+(as)i(man)m(y)f(elemen)m(ts)g(as)g(actually)0 3680 y(exist)h(in)e(that)
+j(ro)m(w)e(of)h(the)g(table;)j(reading)c(do)s(es)h(not)g(automatically)
+f(con)m(tin)m(ue)h(with)f(the)h(next)g(ro)m(w)g(of)g(the)0
+3793 y(table)28 b(as)g(o)s(ccurs)g(when)f(reading)g(an)h(ordinary)f
+(\014xed)g(length)g(table)h(\014eld.)39 b(A)m(ttempts)29
+b(to)g(read)f(more)g(than)g(this)0 3906 y(will)h(cause)k(an)e(error)h
+(status)g(to)g(b)s(e)f(returned.)44 b(One)32 b(can)g(determine)f(the)h
+(n)m(um)m(b)s(er)e(of)i(elemen)m(ts)g(in)f(eac)m(h)i(ro)m(w)0
+4019 y(of)e(a)f(v)-5 b(ariable)29 b(column)h(with)f(the)h(\014ts)p
+1329 4019 V 33 w(read)p 1534 4019 V 32 w(descript)g(routine.)0
+4432 y Ff(4.11)136 b(Multiple)45 b(Access)g(to)g(the)g(Same)h(FITS)d
+(File)0 4698 y Fj(CFITSIO)35 b(supp)s(orts)g(sim)m(ultaneous)g(read)h
+(and)g(write)g(access)h(to)h(m)m(ultiple)c(HDUs)j(in)e(the)i(same)g
+(FITS)f(\014le.)0 4811 y(Th)m(us,)43 b(one)e(can)h(op)s(en)e(the)h
+(same)h(FITS)e(\014le)g(t)m(wice)i(within)c(a)k(single)d(program)i(and)
+g(mo)m(v)m(e)h(to)g(2)f(di\013eren)m(t)0 4924 y(HDUs)30
+b(in)e(the)i(\014le,)f(and)g(then)g(read)h(and)e(write)h(data)h(or)g(k)
+m(eyw)m(ords)g(to)g(the)g(2)f(extensions)h(just)e(as)i(if)f(one)g(w)m
+(ere)0 5036 y(accessing)e(2)g(completely)f(separate)h(FITS)f(\014les.)
+38 b(Since)26 b(in)f(general)h(it)g(is)g(not)h(p)s(ossible)d(to)j(ph)m
+(ysically)d(op)s(en)i(the)0 5149 y(same)36 b(\014le)f(t)m(wice)h(and)f
+(then)g(exp)s(ect)h(to)g(b)s(e)f(able)g(to)i(sim)m(ultaneously)c(\(or)j
+(in)e(alternating)h(succession\))h(write)0 5262 y(to)f(2)f(di\013eren)m
+(t)g(lo)s(cations)g(in)e(the)j(\014le,)f(CFITSIO)f(recognizes)i(when)e
+(the)h(\014le)f(to)i(b)s(e)f(op)s(ened)f(\(in)g(the)i(call)e(to)0
+5375 y(\014ts)p 127 5375 V 32 w(op)s(en)p 349 5375 V
+33 w(\014le\))28 b(has)g(already)g(b)s(een)g(op)s(ened)g(and)g(instead)
+g(of)h(actually)f(op)s(ening)f(the)i(\014le)f(again,)h(just)f
+(logically)0 5488 y(links)g(the)j(new)f(\014le)g(to)h(the)g(old)e
+(\014le.)41 b(\(This)29 b(only)h(applies)e(if)i(the)h(\014le)e(is)h(op)
+s(ened)g(more)g(than)g(once)i(within)c(the)0 5601 y(same)g(program,)g
+(and)f(do)s(es)h(not)f(prev)m(en)m(t)i(the)f(same)g(\014le)e(from)h(b)s
+(eing)g(sim)m(ultaneously)e(op)s(ened)i(b)m(y)g(more)h(than)0
+5714 y(one)h(program\).)40 b(Then)28 b(b)s(efore)g(CFITSIO)f(reads)h
+(or)h(writes)f(to)h(either)f(\(logical\))h(\014le,)f(it)g(mak)m(es)i
+(sure)d(that)j(an)m(y)p eop
+%%Page: 26 34
+26 33 bop 0 299 a Fj(26)1763 b Fh(CHAPTER)29 b(4.)112
+b(PR)m(OGRAMMING)32 b(GUIDELINES)0 555 y Fj(mo)s(di\014cations)e(made)h
+(to)h(the)g(other)g(\014le)e(ha)m(v)m(e)j(b)s(een)e(completely)g
+(\015ushed)e(from)i(the)h(in)m(ternal)e(bu\013ers)h(to)h(the)0
+668 y(\014le.)43 b(Th)m(us,)30 b(in)g(principle,)f(one)i(could)f(op)s
+(en)h(a)h(\014le)e(t)m(wice,)i(in)e(one)i(case)g(p)s(oin)m(ting)e(to)i
+(the)f(\014rst)g(extension)g(and)0 781 y(in)i(the)i(other)g(p)s(oin)m
+(ting)d(to)k(the)e(2nd)g(extension)h(and)e(then)i(write)e(data)j(to)f
+(b)s(oth)f(extensions,)h(in)e(an)m(y)i(order,)0 894 y(without)24
+b(danger)i(of)f(corrupting)g(the)g(\014le,)h(There)f(ma)m(y)h(b)s(e)f
+(some)h(e\016ciency)f(p)s(enalties)f(in)g(doing)h(this)f(ho)m(w)m(ev)m
+(er,)0 1007 y(since)j(CFITSIO)g(has)h(to)h(\015ush)d(all)h(the)h(in)m
+(ternal)f(bu\013ers)g(related)h(to)h(one)f(\014le)f(b)s(efore)h(switc)m
+(hing)e(to)j(the)f(other,)0 1120 y(so)i(it)g(w)m(ould)f(still)f(b)s(e)i
+(pruden)m(t)f(to)i(minimize)d(the)i(n)m(um)m(b)s(er)f(of)i(times)e(one)
+i(switc)m(hes)f(bac)m(k)h(and)e(forth)h(b)s(et)m(w)m(een)0
+1233 y(doing)f(I/O)i(to)g(di\013eren)m(t)f(HDUs)h(in)e(the)h(same)h
+(\014le.)0 1571 y Ff(4.12)136 b(When)44 b(the)h(Final)h(Size)f(of)g
+(the)g(FITS)f(HDU)h(is)g(Unkno)l(wn)0 1822 y Fj(It)27
+b(is)g(not)g(required)e(to)j(kno)m(w)f(the)h(total)g(size)f(of)g(a)h
+(FITS)e(data)i(arra)m(y)g(or)f(table)g(b)s(efore)g(b)s(eginning)d(to)k
+(write)f(the)0 1935 y(data)32 b(to)f(the)g(FITS)f(\014le.)42
+b(In)30 b(the)h(case)h(of)f(the)g(primary)e(arra)m(y)i(or)g(an)f(image)
+i(extension,)e(one)i(should)c(initially)0 2047 y(create)j(the)e(arra)m
+(y)h(with)d(the)j(size)f(of)g(the)g(highest)f(dimension)f(\(largest)j
+(NAXISn)e(k)m(eyw)m(ord\))i(set)g(to)g(a)f(dumm)m(y)0
+2160 y(v)-5 b(alue,)25 b(suc)m(h)f(as)g(1.)39 b(Then)23
+b(after)i(all)e(the)i(data)f(ha)m(v)m(e)i(b)s(een)d(written)g(and)h
+(the)g(true)g(dimensions)e(are)i(kno)m(wn,)h(then)0 2273
+y(the)33 b(NAXISn)f(v)-5 b(alue)32 b(should)f(b)s(e)h(up)s(dated)g
+(using)f(the)i(\014ts)p 2069 2273 28 4 v 33 w(up)s(date)p
+2378 2273 V 32 w(k)m(ey)g(routine)f(b)s(efore)h(mo)m(ving)f(to)i
+(another)0 2386 y(extension)c(or)g(closing)g(the)g(FITS)g(\014le.)0
+2546 y(When)f(writing)e(to)i(FITS)g(tables,)g(CFITSIO)e(automatically)i
+(k)m(eeps)h(trac)m(k)g(of)f(the)g(highest)g(ro)m(w)g(n)m(um)m(b)s(er)e
+(that)0 2659 y(is)k(written)g(to,)i(and)e(will)e(increase)j(the)g(size)
+g(of)g(the)g(table)f(if)g(necessary)-8 b(.)46 b(CFITSIO)30
+b(will)f(also)j(automatically)0 2772 y(insert)j(space)i(in)e(the)h
+(FITS)f(\014le)h(if)f(necessary)-8 b(,)39 b(to)e(ensure)e(that)i(the)f
+(data)h('heap',)h(if)d(it)h(exists,)h(and/or)g(an)m(y)0
+2885 y(additional)26 b(HDUs)j(that)g(follo)m(w)e(the)i(table)f(do)g
+(not)h(get)g(o)m(v)m(erwritten)g(as)f(new)g(ro)m(ws)g(are)h(written)e
+(to)i(the)g(table.)0 3045 y(As)37 b(a)h(general)f(rule)f(it)h(is)f(b)s
+(est)h(to)h(sp)s(ecify)e(the)i(initial)c(n)m(um)m(b)s(er)i(of)i(ro)m
+(ws)f(=)g(0)g(when)g(the)g(table)g(is)g(created,)0 3158
+y(then)h(let)g(CFITSIO)f(k)m(eep)i(trac)m(k)g(of)g(the)f(n)m(um)m(b)s
+(er)f(of)i(ro)m(ws)f(that)h(are)f(actually)g(written.)64
+b(The)38 b(application)0 3271 y(program)e(should)e(not)j(man)m(ually)e
+(up)s(date)g(the)i(n)m(um)m(b)s(er)e(of)h(ro)m(ws)g(in)f(the)i(table)f
+(\(as)h(giv)m(en)f(b)m(y)g(the)h(NAXIS2)0 3384 y(k)m(eyw)m(ord\))j
+(since)e(CFITSIO)f(do)s(es)i(this)f(automatically)-8
+b(.)66 b(If)38 b(a)i(table)e(is)g(initially)e(created)k(with)d(more)i
+(than)0 3497 y(zero)i(ro)m(ws,)j(then)c(this)g(will)d(usually)i(b)s(e)h
+(considered)f(as)i(the)g(minim)m(um)d(size)i(of)h(the)g(table,)i(ev)m
+(en)e(if)f(few)m(er)0 3610 y(ro)m(ws)30 b(are)g(actually)f(written)g
+(to)i(the)f(table.)40 b(Th)m(us,)30 b(if)e(a)j(table)e(is)g(initially)d
+(created)31 b(with)e(NAXIS2)h(=)f(20,)j(and)0 3723 y(CFITSIO)f(only)h
+(writes)f(10)j(ro)m(ws)e(of)h(data)g(b)s(efore)f(closing)g(the)h
+(table,)g(then)f(NAXIS2)h(will)d(remain)h(equal)h(to)0
+3836 y(20.)50 b(If)33 b(ho)m(w)m(ev)m(er,)i(30)g(ro)m(ws)e(of)g(data)h
+(are)g(written)e(to)i(this)e(table,)i(then)f(NAXIS2)h(will)c(b)s(e)j
+(increased)f(from)h(20)0 3949 y(to)f(30.)44 b(The)31
+b(one)g(exception)h(to)g(this)e(automatic)i(up)s(dating)d(of)i(the)h
+(NAXIS2)f(k)m(eyw)m(ord)h(is)e(if)g(the)i(application)0
+4061 y(program)c(directly)e(mo)s(di\014es)g(the)j(v)-5
+b(alue)27 b(of)h(NAXIS2)g(\(up)f(or)h(do)m(wn\))g(itself)f(just)g(b)s
+(efore)h(closing)f(the)h(table.)40 b(In)0 4174 y(this)27
+b(case,)j(CFITSIO)d(do)s(es)h(not)h(up)s(date)e(NAXIS2)i(again,)g
+(since)f(it)g(assumes)g(that)h(the)f(application)f(program)0
+4287 y(m)m(ust)32 b(ha)m(v)m(e)h(had)f(a)g(go)s(o)s(d)g(reason)h(for)f
+(c)m(hanging)g(the)g(v)-5 b(alue)32 b(directly)-8 b(.)45
+b(This)30 b(is)h(not)i(recommended,)f(ho)m(w)m(ev)m(er,)0
+4400 y(and)j(is)g(only)g(pro)m(vided)g(for)g(bac)m(kw)m(ard)h
+(compatibilit)m(y)e(with)h(soft)m(w)m(are)i(that)g(initially)32
+b(creates)37 b(a)f(table)g(with)0 4513 y(a)e(large)g(n)m(um)m(b)s(er)f
+(of)h(ro)m(ws,)h(than)f(decreases)g(the)h(NAXIS2)f(v)-5
+b(alue)33 b(to)i(the)f(actual)g(smaller)f(v)-5 b(alue)33
+b(just)g(b)s(efore)0 4626 y(closing)c(the)i(table.)0
+4964 y Ff(4.13)136 b(CFITSIO)44 b(Size)h(Limitations)0
+5215 y Fj(CFITSIO)29 b(places)i(v)m(ery)g(few)g(restrictions)e(on)i
+(the)g(size)f(of)h(FITS)f(\014les)g(that)h(it)g(reads)f(or)h(writes.)41
+b(There)30 b(are)i(a)0 5328 y(few)e(limits,)e(ho)m(w)m(ev)m(er,)k(that)
+f(ma)m(y)g(a\013ect)h(some)f(extreme)g(cases:)0 5488
+y(1.)43 b(The)31 b(maxim)m(um)f(n)m(um)m(b)s(er)g(of)h(FITS)f(\014les)g
+(that)i(ma)m(y)g(b)s(e)e(sim)m(ultaneously)f(op)s(ened)i(b)m(y)g
+(CFITSIO)e(is)h(set)i(b)m(y)0 5601 y(NMAXFILES)i(as)g(de\014ned)f(in)g
+(\014tsio2.h.)51 b(It)34 b(is)f(curren)m(tly)g(set)i(=)f(300)h(b)m(y)f
+(default.)51 b(CFITSIO)32 b(will)f(allo)s(cate)0 5714
+y(ab)s(out)i(80)g(*)h(NMAXFILES)f(b)m(ytes)g(of)g(memory)g(for)g(in)m
+(ternal)e(use.)48 b(Note)34 b(that)g(the)f(underlying)d(C)i(compiler)p
+eop
+%%Page: 27 35
+27 34 bop 0 299 a Fh(4.13.)73 b(CFITSIO)28 b(SIZE)h(LIMIT)-8
+b(A)g(TIONS)2300 b Fj(27)0 555 y(or)39 b(op)s(erating)g(system,)k(ma)m
+(y)d(ha)m(v)m(e)g(a)g(smaller)e(limit)g(on)h(the)h(n)m(um)m(b)s(er)e
+(of)i(op)s(ened)e(\014les.)67 b(The)39 b(C)h(sym)m(b)s(olic)0
+668 y(constan)m(t)31 b(F)m(OPEN)p 690 668 28 4 v 34 w(MAX)f(is)f(in)m
+(tended)g(to)i(de\014ne)e(the)i(maxim)m(um)e(n)m(um)m(b)s(er)f(of)j
+(\014les)e(that)h(ma)m(y)h(op)s(en)e(at)i(once)0 781
+y(\(including)d(an)m(y)j(other)g(text)h(or)f(binary)e(\014les)h(that)i
+(ma)m(y)f(b)s(e)g(op)s(en,)f(not)h(just)g(FITS)f(\014les\).)42
+b(On)30 b(some)h(systems)0 894 y(it)f(has)g(b)s(een)g(found)f(that)i
+(gcc)g(supp)s(orts)e(a)h(maxim)m(um)g(of)g(255)i(op)s(ened)e(\014les.)0
+1054 y(Note)d(that)e(op)s(ening)f(and)h(op)s(erating)g(on)g(man)m(y)g
+(FITS)g(\014les)f(sim)m(ultaneously)f(in)h(parallel)f(ma)m(y)j(b)s(e)f
+(less)f(e\016cien)m(t)0 1167 y(than)k(op)s(erating)g(on)g(smaller)f
+(groups)h(of)h(\014les)e(in)g(series.)40 b(CFITSIO)27
+b(only)g(has)h(NIOBUF)h(n)m(um)m(b)s(er)f(of)g(in)m(ternal)0
+1280 y(bu\013ers)j(\(set)j(=)e(40)i(b)m(y)e(default\))h(that)g(are)g
+(used)f(for)g(temp)s(orary)g(storage)i(of)f(the)g(most)g(recen)m(t)h
+(data)f(records)0 1393 y(that)40 b(ha)m(v)m(e)g(b)s(een)e(read)h(or)g
+(written)f(in)f(the)i(FITS)f(\014les.)66 b(If)38 b(the)h(n)m(um)m(b)s
+(er)f(of)h(op)s(ened)f(\014les)g(is)g(greater)i(than)0
+1506 y(NIOBUF,)j(then)f(CFITSIO)e(ma)m(y)j(w)m(aste)h(more)e(time)g
+(\015ushing)d(and)j(re-reading)g(or)g(re-writing)e(the)j(same)0
+1619 y(records)30 b(in)f(the)i(FITS)e(\014les.)0 1779
+y(2.)54 b(By)35 b(default,)g(CFITSIO)e(can)i(handle)f(FITS)g(\014les)f
+(up)h(to)h(2.1)h(GB)g(in)d(size)i(\(2**31)i(b)m(ytes\).)54
+b(This)33 b(\014le)h(size)0 1892 y(limit)k(is)i(often)g(imp)s(osed)f(b)
+m(y)h(32-bit)h(op)s(erating)e(systems.)71 b(More)41 b(recen)m(tly)-8
+b(,)44 b(as)d(64-bit)f(op)s(erating)g(systems)0 2005
+y(b)s(ecome)33 b(more)g(common,)g(an)g(industry-wide)c(standard)j(\(at)
+i(least)e(on)h(Unix)e(systems\))i(has)g(b)s(een)f(dev)m(elop)s(ed)0
+2118 y(to)39 b(supp)s(ort)d(larger)h(sized)h(\014les)f(\(see)h(h)m
+(ttp://ftp.sas.com/standards/large.\014le/\).)66 b(Starting)38
+b(with)e(v)m(ersion)0 2230 y(2.1)45 b(of)e(CFITSIO,)f(larger)h(FITS)g
+(\014les)f(up)h(to)h(6)g(terab)m(ytes)h(in)d(size)h(ma)m(y)h(b)s(e)f
+(read)g(and)g(written)g(on)g(sup-)0 2343 y(p)s(orted)f(platforms.)75
+b(In)42 b(order)g(to)h(supp)s(ort)e(these)h(larger)g(\014les,)j
+(CFITSIO)c(m)m(ust)h(b)s(e)g(compiled)f(with)g(the)0
+2456 y('-D)p 129 2456 V 34 w(LAR)m(GEFILE)p 696 2456
+V 33 w(SOUR)m(CE')h(and)g(`-D)p 1491 2456 V 34 w(FILE)p
+1736 2456 V 33 w(OFFSET)p 2137 2456 V 32 w(BITS=64')h(compiler)e
+(\015ags.)78 b(Some)43 b(platforms)0 2569 y(ma)m(y)c(also)f(require)f
+(the)h(`-D)p 1002 2569 V 34 w(LAR)m(GE)p 1358 2569 V
+33 w(FILES')g(compiler)f(\015ag.)64 b(This)37 b(causes)h(the)h
+(compiler)e(to)i(allo)s(cate)f(8-)0 2682 y(b)m(ytes)27
+b(instead)f(of)h(4-b)m(ytes)h(for)f(the)g(`o\013)p 1371
+2682 V 33 w(t')g(data)h(t)m(yp)s(e)f(that)g(is)f(used)g(to)h(store)h
+(\014le)e(o\013set)h(p)s(ositions.)38 b(It)27 b(app)s(ears)0
+2795 y(that)i(in)d(most)j(cases)g(it)e(is)g(not)h(necessary)h(to)g
+(also)f(include)d(these)k(compiler)d(\015ags)j(when)e(compiling)e
+(programs)0 2908 y(that)31 b(link)d(to)j(the)g(CFITSIO)e(library)-8
+b(.)0 3068 y(If)21 b(CFITSIO)e(is)h(compiled)g(with)g(the)h(-D)p
+1386 3068 V 33 w(LAR)m(GEFILE)p 1952 3068 V 34 w(SOUR)m(CE)f(and)g(-D)p
+2654 3068 V 34 w(FILE)p 2899 3068 V 33 w(OFFSET)p 3300
+3068 V 32 w(BITS=64)h(\015ags)0 3181 y(on)36 b(a)g(platform)f(that)h
+(supp)s(orts)e(large)i(\014les,)h(then)e(it)h(can)g(read)g(and)f(write)
+g(FITS)g(\014les)g(that)h(con)m(tain)g(up)f(to)0 3294
+y(2**31)k(2880-b)m(yte)g(FITS)d(records,)j(or)d(appro)m(ximately)g(6)h
+(terab)m(ytes)h(in)e(size.)59 b(It)37 b(is)f(still)f(required)f(that)k
+(the)0 3407 y(v)-5 b(alue)29 b(of)g(the)g(NAXISn)f(and)h(PCOUNT)f(k)m
+(eyw)m(ords)h(in)f(eac)m(h)i(extension)f(b)s(e)f(within)f(the)i(range)h
+(of)f(a)g(signed)f(4-)0 3520 y(b)m(yte)d(in)m(teger)g(\(max)g(v)-5
+b(alue)25 b(=)f(2,147,483,648\).)44 b(Th)m(us,)25 b(eac)m(h)h
+(dimension)c(of)j(an)f(image)h(\(giv)m(en)g(b)m(y)g(the)g(NAXISn)0
+3633 y(k)m(eyw)m(ords\),)32 b(the)f(total)h(width)d(of)i(a)g(table)g
+(\(NAXIS1)h(k)m(eyw)m(ord\),)g(the)f(n)m(um)m(b)s(er)f(of)h(ro)m(ws)g
+(in)e(a)i(table)g(\(NAXIS2)0 3745 y(k)m(eyw)m(ord\),)d(and)d(the)h
+(total)h(size)f(of)g(the)g(v)-5 b(ariable-length)25 b(arra)m(y)h(heap)g
+(in)f(binary)f(tables)i(\(PCOUNT)f(k)m(eyw)m(ord\))0
+3858 y(m)m(ust)30 b(b)s(e)g(less)g(than)g(this)f(limit.)0
+4019 y(Curren)m(tly)-8 b(,)30 b(supp)s(ort)f(for)i(large)g(\014les)f
+(within)e(CFITSIO)h(has)i(b)s(een)f(tested)i(on)f(the)g(Lin)m(ux,)f
+(Solaris,)f(and)h(IBM)0 4131 y(AIX)g(op)s(erating)g(systems.)p
+eop
+%%Page: 28 36
+28 35 bop 0 299 a Fj(28)1763 b Fh(CHAPTER)29 b(4.)112
+b(PR)m(OGRAMMING)32 b(GUIDELINES)p eop
+%%Page: 29 37
+29 36 bop 0 1225 a Fg(Chapter)65 b(5)0 1687 y Fm(Basic)77
+b(CFITSIO)f(In)-6 b(terface)77 b(Routines)0 2180 y Fj(This)29
+b(c)m(hapter)j(describ)s(es)d(the)j(basic)e(routines)g(in)g(the)h
+(CFITSIO)e(user)i(in)m(terface)g(that)h(pro)m(vide)e(all)g(the)i(func-)
+0 2293 y(tions)i(normally)f(needed)i(to)g(read)g(and)f(write)g(most)i
+(FITS)e(\014les.)53 b(It)35 b(is)f(recommended)g(that)i(these)f
+(routines)0 2406 y(b)s(e)d(used)g(for)g(most)h(applications)e(and)h
+(that)h(the)f(more)h(adv)-5 b(anced)33 b(routines)e(describ)s(ed)g(in)g
+(the)i(next)f(c)m(hapter)0 2518 y(only)d(b)s(e)h(used)g(in)f(sp)s
+(ecial)g(circumstances)h(when)f(necessary)-8 b(.)0 2679
+y(The)30 b(follo)m(wing)f(con)m(v)m(en)m(tions)i(are)g(used)e(in)h
+(this)f(c)m(hapter)i(in)e(the)h(description)f(of)h(eac)m(h)i(function:)
+0 2839 y(1.)39 b(Most)25 b(functions)d(ha)m(v)m(e)j(2)f(names:)37
+b(a)24 b(long)g(descriptiv)m(e)e(name)i(and)f(a)i(short)e(concise)h
+(name.)38 b(Both)25 b(names)f(are)0 2952 y(listed)e(on)h(the)g(\014rst)
+f(line)g(of)h(the)h(follo)m(wing)d(descriptions,)i(separated)g(b)m(y)h
+(a)f(slash)f(\(/\))i(c)m(haracter.)40 b(Programmers)0
+3065 y(ma)m(y)27 b(use)g(either)f(name)h(in)e(their)h(programs)h(but)f
+(the)h(long)f(names)h(are)g(recommended)f(to)i(help)d(do)s(cumen)m(t)i
+(the)0 3177 y(co)s(de)k(and)e(mak)m(e)j(it)e(easier)g(to)h(read.)0
+3338 y(2.)42 b(A)30 b(righ)m(t)g(arro)m(w)h(sym)m(b)s(ol)e(\()p
+Fb(>)p Fj(\))i(is)f(used)g(in)f(the)i(function)e(descriptions)f(to)k
+(separate)f(the)g(input)e(parameters)0 3451 y(from)k(the)g(output)f
+(parameters)i(in)e(the)h(de\014nition)e(of)i(eac)m(h)h(routine.)48
+b(This)31 b(sym)m(b)s(ol)h(is)g(not)h(actually)g(part)g(of)0
+3563 y(the)e(C)f(calling)e(sequence.)0 3724 y(3.)41 b(The)30
+b(function)f(parameters)i(are)g(de\014ned)e(in)g(more)h(detail)g(in)f
+(the)h(alphab)s(etical)f(listing)f(in)h(App)s(endix)f(B.)0
+3884 y(4.)39 b(The)23 b(\014rst)g(argumen)m(t)g(in)g(almost)g(all)g
+(the)g(functions)f(is)h(a)h(p)s(oin)m(ter)e(to)i(a)g(structure)f(of)h
+(t)m(yp)s(e)g(`\014ts\014le'.)37 b(Memory)0 3997 y(for)26
+b(this)f(structure)g(is)g(allo)s(cated)h(b)m(y)g(CFITSIO)e(when)h(the)h
+(FITS)g(\014le)f(is)g(\014rst)g(op)s(ened)g(or)h(created)h(and)e(is)g
+(freed)0 4110 y(when)k(the)i(FITS)f(\014le)f(is)g(closed.)0
+4270 y(5.)53 b(The)34 b(last)g(argumen)m(t)g(in)f(almost)i(all)e(the)h
+(functions)f(is)g(the)i(error)f(status)g(parameter.)53
+b(It)35 b(m)m(ust)f(b)s(e)f(equal)0 4383 y(to)k(0)g(on)f(input,)g
+(otherwise)g(the)g(function)f(will)f(immediately)g(exit)i(without)g
+(doing)f(an)m(ything.)58 b(A)36 b(non-zero)0 4496 y(output)27
+b(v)-5 b(alue)26 b(indicates)h(that)g(an)g(error)g(o)s(ccurred)g(in)f
+(the)h(function.)38 b(In)27 b(most)g(cases)h(the)g(status)f(v)-5
+b(alue)27 b(is)f(also)0 4608 y(returned)j(as)i(the)f(v)-5
+b(alue)30 b(of)h(the)f(function)f(itself.)0 4935 y Ff(5.1)135
+b(CFITSIO)44 b(Error)h(Status)h(Routines)0 5168 y Fi(1)81
+b Fj(Return)27 b(a)j(descriptiv)m(e)d(text)j(string)d(\(30)j(c)m(har)f
+(max.\))41 b(corresp)s(onding)27 b(to)i(a)g(CFITSIO)e(error)h(status)h
+(co)s(de.)95 5385 y Fe(void)47 b(fits_get_errstatus)c(/)k(ffgerr)f
+(\(int)h(status,)f(>)h(char)g(*err_text\))0 5601 y Fi(2)81
+b Fj(Return)35 b(the)h(top)g(\(oldest\))g(80-c)m(haracter)j(error)c
+(message)i(from)e(the)h(in)m(ternal)f(CFITSIO)f(stac)m(k)j(of)f(error)
+227 5714 y(messages)45 b(and)e(shift)g(an)m(y)h(remaining)e(messages)j
+(on)f(the)g(stac)m(k)h(up)e(one)h(lev)m(el.)81 b(Call)42
+b(this)h(routine)1905 5942 y(29)p eop
+%%Page: 30 38
+30 37 bop 0 299 a Fj(30)1379 b Fh(CHAPTER)30 b(5.)71
+b(BASIC)30 b(CFITSIO)f(INTERF)-10 b(A)m(CE)30 b(R)m(OUTINES)227
+555 y Fj(rep)s(eatedly)25 b(to)i(get)g(eac)m(h)g(message)f(in)f
+(sequence.)39 b(The)26 b(function)e(returns)h(a)h(v)-5
+b(alue)25 b(=)g(0)h(and)g(a)g(n)m(ull)d(error)227 668
+y(message)32 b(when)d(the)i(error)f(stac)m(k)i(is)d(empt)m(y)-8
+b(.)95 923 y Fe(int)47 b(fits_read_errmsg)d(/)j(ffgmsg)f(\(char)h
+(*err_msg\))0 1178 y Fi(3)81 b Fj(Prin)m(t)29 b(out)i(the)g(error)f
+(message)i(corresp)s(onding)d(to)i(the)g(input)e(status)i(v)-5
+b(alue)30 b(and)g(all)g(the)h(error)f(messages)227 1291
+y(on)d(the)h(CFITSIO)e(stac)m(k)j(to)f(the)f(sp)s(eci\014ed)f(\014le)g
+(stream)i(\(normally)e(to)i(stdout)f(or)g(stderr\).)40
+b(If)26 b(the)i(input)227 1404 y(status)j(v)-5 b(alue)30
+b(=)g(0)h(then)f(this)f(routine)g(do)s(es)h(nothing.)95
+1659 y Fe(void)47 b(fits_report_error)c(/)48 b(ffrprt)e(\(FILE)g
+(*stream,)g(>)h(status\))0 1914 y Fi(4)81 b Fj(The)44
+b(\014ts)p 461 1914 28 4 v 32 w(write)p 696 1914 V 32
+w(errmark)g(routine)g(puts)g(an)h(in)m(visible)c(mark)m(er)k(on)g(the)g
+(CFITSIO)e(error)h(stac)m(k.)85 b(The)227 2027 y(\014ts)p
+354 2027 V 33 w(clear)p 574 2027 V 33 w(errmark)31 b(routine)h(can)h
+(then)f(b)s(e)f(used)h(to)h(delete)g(an)m(y)g(more)f(recen)m(t)i(error)
+e(messages)h(on)g(the)227 2140 y(stac)m(k,)42 b(bac)m(k)c(to)g(the)g(p)
+s(osition)e(of)i(the)g(mark)m(er.)63 b(This)36 b(preserv)m(es)h(an)m(y)
+h(older)f(error)g(messages)i(on)f(the)227 2253 y(stac)m(k.)77
+b(The)41 b(\014ts)p 855 2253 V 32 w(clear)p 1074 2253
+V 33 w(errmsg)g(routine)g(simply)e(clears)j(all)f(the)h(messages)g
+(\(and)g(marks\))f(from)h(the)227 2365 y(stac)m(k.)g(These)31
+b(routines)e(are)i(called)e(without)h(an)m(y)g(argumen)m(ts.)95
+2620 y Fe(void)47 b(fits_write_errmark)c(/)k(ffpmrk)f(\(void\))95
+2733 y(void)h(fits_clear_errmark)c(/)k(ffcmrk)f(\(void\))95
+2846 y(void)h(fits_clear_errmsg)c(/)48 b(ffcmsg)e(\(void\))0
+3179 y Ff(5.2)135 b(FITS)44 b(File)i(Access)e(Routines)0
+3419 y Fi(1)81 b Fj(Op)s(en)29 b(an)h(existing)f(data)i(\014le.)227
+3663 y Fe(int)47 b(fits_open_file)d(/)k(ffopen)418 3776
+y(\(fitsfile)d(**fptr,)h(char)h(*filename,)e(int)i(iomode,)f(>)h(int)g
+(*status\))227 4002 y(int)g(fits_open_diskfile)c(/)k(ffdkopen)418
+4115 y(\(fitsfile)e(**fptr,)h(char)h(*filename,)e(int)i(iomode,)f(>)h
+(int)g(*status\))227 4340 y(int)g(fits_open_data)d(/)k(ffdopn)418
+4453 y(\(fitsfile)d(**fptr,)h(char)h(*filename,)e(int)i(iomode,)f(>)h
+(int)g(*status\))227 4679 y(int)g(fits_open_table)d(/)j(fftopn)418
+4792 y(\(fitsfile)e(**fptr,)h(char)h(*filename,)e(int)i(iomode,)f(>)h
+(int)g(*status\))227 5018 y(int)g(fits_open_image)d(/)j(ffiopn)418
+5131 y(\(fitsfile)e(**fptr,)h(char)h(*filename,)e(int)i(iomode,)f(>)h
+(int)g(*status\))227 5375 y Fj(The)41 b(iomo)s(de)g(parameter)h
+(determines)f(the)g(read/write)g(access)i(allo)m(w)m(ed)f(in)e(the)h
+(\014le)g(and)g(can)h(ha)m(v)m(e)227 5488 y(v)-5 b(alues)31
+b(of)h(READONL)-8 b(Y)32 b(\(0\))g(or)g(READ)m(WRITE)g(\(1\).)44
+b(The)31 b(\014lename)g(parameter)h(giv)m(es)g(the)f(name)h(of)227
+5601 y(the)f(\014le)f(to)h(b)s(e)f(op)s(ened,)h(follo)m(w)m(ed)f(b)m(y)
+h(an)f(optional)g(argumen)m(t)h(giving)f(the)h(name)f(or)h(index)e(n)m
+(um)m(b)s(er)h(of)227 5714 y(the)d(extension)f(within)f(the)h(FITS)g
+(\014le)g(that)h(should)e(b)s(e)h(mo)m(v)m(ed)i(to)f(and)f(op)s(ened)g
+(\(e.g.,)k Fe(myfile.fits+3)p eop
+%%Page: 31 39
+31 38 bop 0 299 a Fh(5.2.)72 b(FITS)30 b(FILE)g(A)m(CCESS)f(R)m
+(OUTINES)2244 b Fj(31)227 555 y(or)36 b Fe(myfile.fits[3])d
+Fj(mo)m(v)m(es)k(to)g(the)g(3rd)f(extension)f(within)f(the)j(\014le,)g
+(and)e Fe(myfile.fits[events])227 668 y Fj(mo)m(v)m(es)d(to)f(the)g
+(extension)f(with)f(the)h(k)m(eyw)m(ord)h(EXTNAME)g(=)f('EVENTS'\).)227
+816 y(The)37 b(\014ts)p 548 816 28 4 v 32 w(op)s(en)p
+770 816 V 32 w(disk\014le)e(routine)h(is)g(similar)e(to)k(the)f(\014ts)
+p 2241 816 V 33 w(op)s(en)p 2464 816 V 32 w(\014le)f(routine)g(except)i
+(that)f(it)g(do)s(es)g(not)227 929 y(supp)s(ort)22 b(the)h(extended)h
+(\014lename)e(syn)m(tax)i(in)e(the)i(input)d(\014le)i(name.)38
+b(This)22 b(routine)g(simply)f(tries)i(to)h(op)s(en)227
+1042 y(the)36 b(sp)s(eci\014ed)d(input)h(\014le)g(on)h(magnetic)h
+(disk.)54 b(This)33 b(routine)h(is)h(mainly)e(for)i(use)g(in)f(cases)i
+(where)f(the)227 1155 y(\014lename)e(\(or)i(directory)e(path\))h(con)m
+(tains)g(square)g(or)g(curly)e(brac)m(k)m(et)k(c)m(haracters)f(that)f
+(w)m(ould)f(confuse)227 1268 y(the)e(extended)f(\014lename)g(parser.)
+227 1416 y(The)j(\014ts)p 544 1416 V 32 w(op)s(en)p 766
+1416 V 32 w(data)h(routine)d(is)h(similar)e(to)k(the)f(\014ts)p
+2113 1416 V 32 w(op)s(en)p 2335 1416 V 33 w(\014le)e(routine)h(except)i
+(that)f(it)g(will)d(mo)m(v)m(e)k(to)227 1529 y(the)23
+b(\014rst)f(HDU)h(con)m(taining)f(signi\014can)m(t)f(data,)k(if)d(a)h
+(HDU)g(name)f(or)h(n)m(um)m(b)s(er)e(to)i(op)s(en)f(w)m(as)h(not)f
+(explicitly)227 1642 y(sp)s(eci\014ed)36 b(as)h(part)h(of)f(the)h
+(\014lename.)60 b(In)37 b(this)f(case,)k(it)d(will)e(lo)s(ok)i(for)g
+(the)g(\014rst)g(IMA)m(GE)h(HDU)g(with)227 1755 y(NAXIS)e(>)f(0,)j(or)d
+(the)h(\014rst)f(table)g(that)i(do)s(es)e(not)h(con)m(tain)g(the)g
+(strings)e(`GTI')i(\(Go)s(o)s(d)g(Time)e(In)m(terv)-5
+b(al)227 1868 y(extension\))31 b(or)f(`OBST)-8 b(ABLE')31
+b(in)e(the)h(EXTNAME)h(k)m(eyw)m(ord)g(v)-5 b(alue.)227
+2016 y(The)25 b(\014ts)p 536 2016 V 32 w(op)s(en)p 758
+2016 V 32 w(table)g(and)f(\014ts)p 1305 2016 V 33 w(op)s(en)p
+1528 2016 V 32 w(image)h(routines)f(are)h(similar)e(to)i(\014ts)p
+2828 2016 V 33 w(op)s(en)p 3051 2016 V 32 w(data)h(except)f(they)h
+(will)227 2129 y(mo)m(v)m(e)h(to)g(the)f(\014rst)f(signi\014can)m(t)f
+(table)i(HDU)g(or)g(image)g(HDU)g(in)e(the)i(\014le,)g(resp)s(ectiv)m
+(ely)-8 b(,)27 b(if)d(a)i(HDU)h(name)227 2242 y(or)k(n)m(um)m(b)s(er)e
+(is)g(not)i(sp)s(eci\014ed)d(as)j(part)f(of)h(the)f(\014lename.)227
+2390 y(IRAF)c(images)f(\(.imh)g(format)h(\014les\))e(and)h(ra)m(w)h
+(binary)d(data)k(arra)m(ys)e(ma)m(y)h(also)g(b)s(e)f(op)s(ened)f(with)g
+(READ-)227 2503 y(ONL)-8 b(Y)37 b(access.)60 b(CFITSIO)35
+b(will)f(automatically)i(test)i(if)d(the)i(input)d(\014le)i(is)f(an)i
+(IRAF)f(image,)j(and)d(if,)227 2616 y(so)c(will)d(con)m(v)m(ert)k(it)e
+(on)g(the)h(\015y)f(in)m(to)h(a)g(virtual)d(FITS)i(image)h(b)s(efore)f
+(it)g(is)g(op)s(ened)f(b)m(y)i(the)g(application)227
+2729 y(program.)64 b(If)37 b(the)h(input)f(\014le)g(is)g(a)h(ra)m(w)g
+(binary)f(data)h(arra)m(y)h(of)f(n)m(um)m(b)s(ers,)h(then)e(the)i(data)
+f(t)m(yp)s(e)h(and)227 2842 y(dimensions)34 b(of)i(the)g(arra)m(y)h(m)m
+(ust)f(b)s(e)f(sp)s(eci\014ed)f(in)h(square)h(brac)m(k)m(ets)h(follo)m
+(wing)e(the)h(name)g(of)h(the)f(\014le)227 2955 y(\(e.g.)56
+b('ra)m(w\014le.dat[i512,512]')38 b(op)s(ens)c(a)i(512)g(x)f(512)h
+(short)e(in)m(teger)i(image\).)55 b(See)35 b(the)g(`Extended)g(File)227
+3068 y(Name)k(Syn)m(tax')g(c)m(hapter)g(for)e(more)i(details)e(on)h(ho)
+m(w)g(to)h(sp)s(ecify)e(the)h(ra)m(w)h(\014le)e(name.)64
+b(The)38 b(ra)m(w)g(\014le)227 3181 y(is)j(con)m(v)m(erted)h(on)f(the)h
+(\015y)f(in)m(to)g(a)g(virtual)f(FITS)g(image)i(in)e(memory)h(that)h
+(is)e(then)h(op)s(ened)g(b)m(y)g(the)227 3294 y(application)29
+b(program)h(with)f(READONL)-8 b(Y)31 b(access.)227 3442
+y(Programs)g(can)g(read)f(the)h(input)d(\014le)i(from)g(the)h('stdin')e
+(\014le)h(stream)h(if)e(a)i(dash)f(c)m(haracter)i(\('-'\))g(is)e(giv)m
+(en)227 3555 y(as)f(the)f(\014lename.)39 b(Files)28 b(can)g(also)g(b)s
+(e)g(op)s(ened)f(o)m(v)m(er)j(the)e(net)m(w)m(ork)h(using)e(FTP)h(or)g
+(HTTP)g(proto)s(cols)g(b)m(y)227 3668 y(supplying)f(the)k(appropriate)e
+(URL)i(as)f(the)h(\014lename.)227 3816 y(The)43 b(input)e(\014le)h(can)
+i(b)s(e)f(mo)s(di\014ed)e(in)g(v)-5 b(arious)43 b(w)m(a)m(ys)h(to)g
+(create)g(a)g(virtual)d(\014le)i(\(usually)e(stored)i(in)227
+3929 y(memory\))31 b(that)g(is)f(then)g(op)s(ened)f(b)m(y)i(the)f
+(application)f(program)h(b)m(y)h(supplying)c(a)k(\014ltering)e(or)h
+(binning)227 4042 y(sp)s(eci\014er)d(in)g(square)h(brac)m(k)m(ets)h
+(follo)m(wing)e(the)h(\014lename.)39 b(Some)29 b(of)f(the)g(more)h
+(common)f(\014ltering)f(meth-)227 4155 y(o)s(ds)32 b(are)h(illustrated)
+e(in)g(the)i(follo)m(wing)f(paragraphs,)h(but)f(users)g(should)e(refer)
+j(to)g(the)g('Extended)g(File)227 4268 y(Name)e(Syn)m(tax')g(c)m
+(hapter)g(for)f(a)h(complete)g(description)d(of)j(the)f(full)f(\014le)g
+(\014ltering)g(syn)m(tax.)227 4416 y(When)e(op)s(ening)e(an)i(image,)g
+(a)h(rectangular)e(subset)g(of)h(the)g(ph)m(ysical)e(image)i(ma)m(y)h
+(b)s(e)e(op)s(ened)f(b)m(y)i(listing)227 4529 y(the)k(\014rst)e(and)h
+(last)g(pixel)f(in)g(eac)m(h)j(dimension)c(\(and)i(optional)f(pixel)g
+(skipping)f(factor\):)227 4765 y Fe(myimage.fits[101:200,301:)o(400])
+227 5001 y Fj(will)f(create)k(and)e(op)s(en)f(a)i(100x100)i(pixel)c
+(virtual)g(image)h(of)h(that)g(section)f(of)h(the)f(ph)m(ysical)f
+(image,)j(and)227 5114 y Fe(myimage.fits[*,-*])d Fj(op)s(ens)k(a)h
+(virtual)e(image)i(that)g(is)f(the)h(same)g(size)g(as)f(the)h(ph)m
+(ysical)f(image)h(but)227 5227 y(has)d(b)s(een)g(\015ipp)s(ed)e(in)h
+(the)h(v)m(ertical)h(direction.)227 5375 y(When)d(op)s(ening)f(a)h
+(table,)h(the)f(\014ltering)e(syn)m(tax)j(can)f(b)s(e)f(used)h(to)g
+(add)g(or)g(delete)g(columns)f(or)h(k)m(eyw)m(ords)227
+5488 y(in)f(the)h(virtual)f(table:)39 b Fe(myfile.fits[events][col)j
+(!time;)k(PI)h(=)h(PHA*1.2])26 b Fj(op)s(ens)h(a)h(virtual)f(ta-)227
+5601 y(ble)k(in)f(whic)m(h)g(the)i(TIME)f(column)f(has)h(b)s(een)g
+(deleted)g(and)g(a)g(new)g(PI)g(column)g(has)g(b)s(een)g(added)f(with)
+227 5714 y(a)41 b(v)-5 b(alue)39 b(1.2)j(times)d(that)i(of)f(the)h(PHA)
+f(column.)69 b(Similarly)-8 b(,)39 b(one)i(can)f(\014lter)g(a)g(table)g
+(to)h(k)m(eep)g(only)p eop
+%%Page: 32 40
+32 39 bop 0 299 a Fj(32)1379 b Fh(CHAPTER)30 b(5.)71
+b(BASIC)30 b(CFITSIO)f(INTERF)-10 b(A)m(CE)30 b(R)m(OUTINES)227
+555 y Fj(those)35 b(ro)m(ws)e(that)i(satisfy)e(a)h(selection)g
+(criterion:)46 b Fe(myfile.fits[events][pha)c(>)47 b(50])33
+b Fj(creates)j(and)227 668 y(op)s(ens)31 b(a)g(virtual)f(table)h(con)m
+(taining)g(only)f(those)i(ro)m(ws)f(with)f(a)h(PHA)h(v)-5
+b(alue)30 b(greater)j(than)e(50.)44 b(A)31 b(large)227
+781 y(n)m(um)m(b)s(er)d(of)h(b)s(o)s(olean)g(and)f(mathematical)i(op)s
+(erators)f(can)g(b)s(e)g(used)f(in)g(the)h(selection)g(expression.)39
+b(One)227 894 y(can)25 b(also)f(\014lter)g(table)g(ro)m(ws)g(using)f
+('Go)s(o)s(d)i(Time)e(In)m(terv)-5 b(al')25 b(extensions,)g(and)f
+(spatial)f(region)h(\014lters)g(as)g(in)227 1007 y Fe
+(myfile.fits[events][gtifi)o(lter)o(\(\)])14 b Fj(and)19
+b Fe(myfile.fits[events][regfil)o(ter)o(\()42 b("stars.rng"\)])p
+Fj(.)227 1167 y(Finally)-8 b(,)31 b(table)g(columns)f(ma)m(y)i(b)s(e)f
+(binned)e(or)i(histogrammed)g(to)h(generate)h(a)e(virtual)f(image.)44
+b(F)-8 b(or)32 b(ex-)227 1280 y(ample,)c Fe(myfile.fits[events][bin)41
+b(\(X,Y\)=4])26 b Fj(will)e(result)j(in)f(a)i(2-dimensional)d(image)j
+(calculated)227 1393 y(b)m(y)35 b(binning)c(the)k(X)f(and)g(Y)h
+(columns)e(in)g(the)i(ev)m(en)m(t)h(table)e(with)f(a)i(bin)e(size)h(of)
+h(4)f(in)g(eac)m(h)h(dimension.)227 1506 y(The)30 b(TLMINn)g(and)f
+(TLMAXn)h(k)m(eyw)m(ords)h(will)d(b)s(e)h(used)h(b)m(y)g(default)g(to)h
+(determine)e(the)i(range)f(of)h(the)227 1619 y(image.)227
+1779 y(A)j(single)e(program)h(can)g(op)s(en)g(the)h(same)f(FITS)g
+(\014le)f(more)i(than)f(once)h(and)f(then)g(treat)h(the)g(resulting)227
+1892 y(\014ts\014le)29 b(p)s(oin)m(ters)g(as)h(though)g(they)g(w)m(ere)
+h(completely)f(indep)s(enden)m(t)e(FITS)h(\014les.)39
+b(Using)30 b(this)f(facilit)m(y)-8 b(,)30 b(a)227 2005
+y(program)i(can)f(op)s(en)g(a)h(FITS)f(\014le)f(t)m(wice,)j(mo)m(v)m(e)
+g(to)f(2)g(di\013eren)m(t)f(extensions)g(within)e(the)i(\014le,)g(and)g
+(then)227 2118 y(read)g(and)e(write)h(data)h(in)e(those)i(extensions)f
+(in)f(an)m(y)i(order.)0 2397 y Fi(2)81 b Fj(Create)31
+b(and)f(op)s(en)f(a)i(new)f(empt)m(y)h(output)f(FITS)f(\014le.)227
+2677 y Fe(int)47 b(fits_create_file)d(/)j(ffinit)418
+2790 y(\(fitsfile)e(**fptr,)h(char)h(*filename,)e(>)i(int)g(*status\))
+227 3016 y(int)g(fits_create_diskfile)42 b(/)48 b(ffdkinit)418
+3129 y(\(fitsfile)d(**fptr,)h(char)h(*filename,)e(>)i(int)g(*status\))
+227 3409 y Fj(An)36 b(error)h(will)d(b)s(e)i(returned)f(if)g(the)i(sp)s
+(eci\014ed)e(\014le)h(already)g(exists,)i(unless)d(the)i(\014lename)e
+(is)h(pre\014xed)227 3522 y(with)29 b(an)h(exclamation)g(p)s(oin)m(t)f
+(\(!\).)42 b(In)29 b(that)i(case)g(CFITSIO)d(will)g(o)m(v)m(erwrite)i
+(\(delete\))h(an)m(y)g(existing)e(\014le)227 3635 y(with)35
+b(the)h(same)h(name.)57 b(Note)38 b(that)e(the)h(exclamation)f(p)s(oin)
+m(t)f(is)g(a)i(sp)s(ecial)d(UNIX)i(c)m(haracter)i(so)e(if)f(it)227
+3748 y(is)d(used)f(on)h(the)h(command)f(line)f(it)h(m)m(ust)g(b)s(e)g
+(preceded)g(b)m(y)g(a)g(bac)m(kslash)g(to)i(force)e(the)h(UNIX)g(shell)
+d(to)227 3860 y(accept)i(the)f(c)m(haracter)h(as)e(part)g(of)h(the)g
+(\014lename.)227 4021 y(The)26 b(output)h(\014le)f(will)e(b)s(e)i
+(written)g(to)h(the)g('stdout')g(\014le)f(stream)h(if)f(a)h(dash)f(c)m
+(haracter)i(\('-'\))g(or)f(the)g(string)227 4134 y('stdout')34
+b(is)e(giv)m(en)h(as)h(the)f(\014lename.)48 b(Similarly)-8
+b(,)31 b('-.gz')k(or)e('stdout.gz')i(will)c(cause)i(the)h(\014le)e(to)i
+(b)s(e)e(gzip)227 4247 y(compressed)e(b)s(efore)g(it)g(is)g(written)f
+(out)i(to)g(the)f(stdout)h(stream.)227 4407 y(Optionally)-8
+b(,)38 b(the)f(name)h(of)f(a)h(template)g(\014le)e(that)i(is)e(used)h
+(to)h(de\014ne)f(the)g(structure)g(of)g(the)h(new)f(\014le)227
+4520 y(ma)m(y)i(b)s(e)f(sp)s(eci\014ed)e(in)h(paren)m(theses)i(follo)m
+(wing)d(the)j(output)e(\014le)h(name.)64 b(The)38 b(template)g(\014le)g
+(ma)m(y)h(b)s(e)227 4633 y(another)32 b(FITS)e(\014le,)h(in)f(whic)m(h)
+g(case)j(the)e(new)g(\014le,)g(at)h(the)g(time)f(it)f(is)h(op)s(ened,)g
+(will)d(b)s(e)j(an)g(exact)i(cop)m(y)227 4746 y(of)38
+b(the)g(template)h(\014le)e(except)h(that)h(the)f(data)g(structures)g
+(\(images)g(and)f(tables\))h(will)d(b)s(e)j(\014lled)d(with)227
+4858 y(zeros.)41 b(Alternativ)m(ely)-8 b(,)29 b(the)g(template)h
+(\014le)e(ma)m(y)h(b)s(e)f(an)h(ASCI)s(I)e(format)i(text)h(\014le)e
+(con)m(taining)h(directiv)m(es)227 4971 y(that)g(de\014ne)e(the)h(k)m
+(eyw)m(ords)g(to)g(b)s(e)g(created)h(in)d(eac)m(h)j(HDU)g(of)f(the)g
+(\014le.)39 b(See)28 b(the)g('Extended)f(File)g(Name)227
+5084 y(Syn)m(tax')k(section)g(for)f(a)h(complete)f(description)f(of)h
+(the)h(template)g(\014le)e(syn)m(tax.)227 5245 y(The)g(\014ts)p
+540 5245 28 4 v 33 w(create)p 809 5245 V 34 w(disk\014le)e(routine)i
+(is)g(similar)e(to)j(the)g(\014ts)p 2238 5245 V 32 w(create)p
+2506 5245 V 34 w(\014le)f(routine)g(except)h(that)g(it)f(do)s(es)h(not)
+227 5357 y(supp)s(ort)36 b(the)i(extended)g(\014lename)f(syn)m(tax)h
+(in)f(the)h(input)e(\014le)h(name.)63 b(This)36 b(routine)h(simply)e
+(tries)i(to)227 5470 y(create)f(the)e(sp)s(eci\014ed)e(\014le)h(on)g
+(magnetic)i(disk.)49 b(This)32 b(routine)h(is)g(mainly)f(for)i(use)f
+(in)g(cases)h(where)g(the)227 5583 y(\014lename)f(\(or)i(directory)e
+(path\))h(con)m(tains)g(square)g(or)g(curly)e(brac)m(k)m(et)k(c)m
+(haracters)f(that)f(w)m(ould)f(confuse)227 5696 y(the)e(extended)f
+(\014lename)g(parser.)p eop
+%%Page: 33 41
+33 40 bop 0 299 a Fh(5.3.)72 b(HDU)31 b(A)m(CCESS)e(R)m(OUTINES)2488
+b Fj(33)0 555 y Fi(3)81 b Fj(Close)27 b(a)g(previously)e(op)s(ened)i
+(FITS)g(\014le.)39 b(The)27 b(\014rst)f(routine)h(simply)e(closes)i
+(the)h(\014le,)f(whereas)g(the)h(second)227 668 y(one)41
+b(also)f(DELETES)f(THE)h(FILE,)g(whic)m(h)f(can)i(b)s(e)e(useful)g(in)g
+(cases)i(where)e(a)i(FITS)e(\014le)h(has)g(b)s(een)227
+781 y(partially)29 b(created,)i(but)f(then)g(an)g(error)g(o)s(ccurs)g
+(whic)m(h)g(prev)m(en)m(ts)g(it)g(from)g(b)s(eing)f(completed.)95
+1033 y Fe(int)47 b(fits_close_file)d(/)j(ffclos)g(\(fitsfile)e(*fptr,)h
+(>)h(int)g(*status\))95 1258 y(int)g(fits_delete_file)d(/)j(ffdelt)f
+(\(fitsfile)g(*fptr,)g(>)h(int)g(*status\))0 1510 y Fi(4)81
+b Fj(Return)21 b(the)i(name,)h(I/O)e(mo)s(de)g(\(READONL)-8
+b(Y)24 b(or)e(READ)m(WRITE\),)i(and/or)e(the)g(\014le)g(t)m(yp)s(e)g
+(\(e.g.)40 b('\014le://',)227 1623 y('ftp://'\))32 b(of)f(the)f(op)s
+(ened)g(FITS)g(\014le.)95 1875 y Fe(int)47 b(fits_file_name)d(/)k
+(ffflnm)e(\(fitsfile)f(*fptr,)h(>)i(char)e(*filename,)f(int)i
+(*status\))95 2100 y(int)g(fits_file_mode)d(/)k(ffflmd)e(\(fitsfile)f
+(*fptr,)h(>)i(int)f(*iomode,)e(int)i(*status\))95 2326
+y(int)g(fits_url_type)e(/)i(ffurlt)f(\(fitsfile)f(*fptr,)h(>)i(char)f
+(*urltype,)e(int)i(*status\))0 2659 y Ff(5.3)135 b(HDU)46
+b(Access)e(Routines)0 2909 y Fj(The)30 b(follo)m(wing)f(functions)g(p)s
+(erform)g(op)s(erations)g(on)i(Header-Data)h(Units)e(\(HDUs\))i(as)e(a)
+h(whole.)0 3161 y Fi(1)81 b Fj(Mo)m(v)m(e)44 b(to)g(a)f(di\013eren)m(t)
+f(HDU)h(in)f(the)h(\014le.)76 b(The)43 b(\014rst)f(routine)f(mo)m(v)m
+(es)j(to)g(a)f(sp)s(eci\014ed)e(absolute)h(HDU)227 3273
+y(n)m(um)m(b)s(er)g(\(starting)g(with)g(1)g(for)h(the)g(primary)d(arra)
+m(y\))k(in)d(the)i(FITS)f(\014le,)j(and)d(the)g(second)h(routine)227
+3386 y(mo)m(v)m(es)35 b(a)e(relativ)m(e)g(n)m(um)m(b)s(er)f(HDUs)i
+(forw)m(ard)e(or)h(bac)m(kw)m(ard)h(from)f(the)g(curren)m(t)g(HDU.)h(A)
+f(n)m(ull)e(p)s(oin)m(ter)227 3499 y(ma)m(y)g(b)s(e)f(giv)m(en)g(for)g
+(the)g(hdut)m(yp)s(e)f(parameter)i(if)e(it's)h(v)-5 b(alue)30
+b(is)f(not)i(needed.)40 b(The)30 b(third)e(routine)i(mo)m(v)m(es)227
+3612 y(to)39 b(the)g(\(\014rst\))f(HDU)i(whic)m(h)d(has)h(the)h(sp)s
+(eci\014ed)d(extension)i(t)m(yp)s(e)h(and)f(EXTNAME)g(and)g(EXTVER)227
+3725 y(k)m(eyw)m(ord)26 b(v)-5 b(alues)25 b(\(or)h(HDUNAME)h(and)e
+(HDUVER)h(k)m(eyw)m(ords\).)40 b(The)24 b(hdut)m(yp)s(e)h(parameter)h
+(ma)m(y)g(ha)m(v)m(e)227 3838 y(a)d(v)-5 b(alue)21 b(of)h(IMA)m(GE)p
+935 3838 28 4 v 34 w(HDU,)h(ASCI)s(I)p 1476 3838 V 31
+w(TBL,)f(BINAR)-8 b(Y)p 2101 3838 V 34 w(TBL,)22 b(or)g(ANY)p
+2676 3838 V 34 w(HDU)g(where)g(ANY)p 3396 3838 V 33 w(HDU)h(means)227
+3951 y(that)33 b(only)f(the)g(extname)i(and)d(extv)m(er)j(v)-5
+b(alues)32 b(will)d(b)s(e)j(used)g(to)h(lo)s(cate)g(the)g(correct)g
+(extension.)47 b(If)32 b(the)227 4064 y(input)h(v)-5
+b(alue)35 b(of)g(extv)m(er)h(is)e(0)i(then)e(the)i(EXTVER)e(k)m(eyw)m
+(ord)i(is)e(ignored)g(and)h(the)g(\014rst)f(HDU)i(with)e(a)227
+4177 y(matc)m(hing)27 b(EXTNAME)h(\(or)f(HDUNAME\))i(k)m(eyw)m(ord)e
+(will)d(b)s(e)j(found.)38 b(If)27 b(no)f(matc)m(hing)h(HDU)h(is)e
+(found)227 4290 y(in)f(the)h(\014le)f(then)h(the)g(curren)m(t)g(HDU)g
+(will)e(remain)h(unc)m(hanged)g(and)h(a)g(status)g(=)g(BAD)p
+3246 4290 V 33 w(HDU)p 3484 4290 V 34 w(NUM)h(will)227
+4403 y(b)s(e)j(returned.)95 4654 y Fe(int)47 b(fits_movabs_hdu)d(/)j
+(ffmahd)286 4767 y(\(fitsfile)f(*fptr,)g(int)h(hdunum,)e(>)j(int)f
+(*hdutype,)e(int)i(*status\))95 4993 y(int)g(fits_movrel_hdu)d(/)j
+(ffmrhd)286 5106 y(\(fitsfile)f(*fptr,)g(int)h(nmove,)f(>)h(int)g
+(*hdutype,)e(int)i(*status\))95 5332 y(int)g(fits_movnam_hdu)d(/)j
+(ffmnhd)286 5445 y(\(fitsfile)f(*fptr,)g(int)h(hdutype,)e(char)i
+(*extname,)e(int)i(extver,)f(>)h(int)g(*status\))0 5696
+y Fi(2)81 b Fj(Return)29 b(the)i(total)g(n)m(um)m(b)s(er)e(of)i(HDUs)f
+(in)g(the)g(FITS)g(\014le.)40 b(The)29 b(curren)m(t)i(HDU)g(remains)e
+(unc)m(hanged.)p eop
+%%Page: 34 42
+34 41 bop 0 299 a Fj(34)1379 b Fh(CHAPTER)30 b(5.)71
+b(BASIC)30 b(CFITSIO)f(INTERF)-10 b(A)m(CE)30 b(R)m(OUTINES)95
+555 y Fe(int)47 b(fits_get_num_hdus)c(/)48 b(ffthdu)286
+668 y(\(fitsfile)e(*fptr,)g(>)h(int)g(*hdunum,)f(int)h(*status\))0
+922 y Fi(3)81 b Fj(Return)31 b(the)h(n)m(um)m(b)s(er)f(of)h(the)h
+(curren)m(t)e(HDU)i(\(CHDU\))h(in)c(the)j(FITS)e(\014le)g(\(where)h
+(the)g(primary)f(arra)m(y)h(=)227 1034 y(1\).)42 b(This)28
+b(function)h(returns)h(the)g(HDU)h(n)m(um)m(b)s(er)e(rather)h(than)h(a)
+f(status)h(v)-5 b(alue.)95 1288 y Fe(int)47 b(fits_get_hdu_num)d(/)j
+(ffghdn)286 1401 y(\(fitsfile)f(*fptr,)g(>)h(int)g(*hdunum\))0
+1654 y Fi(4)81 b Fj(Return)38 b(the)h(t)m(yp)s(e)h(of)f(the)h(curren)m
+(t)f(HDU)h(in)e(the)h(FITS)g(\014le.)66 b(The)39 b(p)s(ossible)e(v)-5
+b(alues)38 b(for)h(hdut)m(yp)s(e)f(are:)227 1767 y(IMA)m(GE)p
+546 1767 28 4 v 34 w(HDU,)31 b(ASCI)s(I)p 1095 1767 V
+32 w(TBL,)f(or)g(BINAR)-8 b(Y)p 1840 1767 V 34 w(TBL.)95
+2021 y Fe(int)47 b(fits_get_hdu_type)c(/)48 b(ffghdt)286
+2133 y(\(fitsfile)e(*fptr,)g(>)h(int)g(*hdutype,)e(int)i(*status\))0
+2387 y Fi(5)81 b Fj(Cop)m(y)24 b(all)f(or)h(part)g(of)g(the)g(HDUs)h
+(in)e(the)h(FITS)g(\014le)f(asso)s(ciated)h(with)f(infptr)f(and)i(app)s
+(end)e(them)i(to)h(the)g(end)227 2500 y(of)f(the)f(FITS)f(\014le)h
+(asso)s(ciated)g(with)f(outfptr.)38 b(If)23 b('previous')f(is)g(true)h
+(\(not)h(0\),)i(then)d(an)m(y)g(HDUs)h(preceding)227
+2613 y(the)35 b(curren)m(t)f(HDU)g(in)f(the)i(input)d(\014le)h(will)f
+(b)s(e)h(copied)h(to)h(the)f(output)g(\014le.)51 b(Similarly)-8
+b(,)32 b('curren)m(t')j(and)227 2726 y('follo)m(wing')28
+b(determine)g(whether)g(the)h(curren)m(t)g(HDU,)g(and/or)g(an)m(y)g
+(follo)m(wing)e(HDUs)j(in)d(the)i(input)e(\014le)227
+2838 y(will)g(b)s(e)i(copied)h(to)g(the)g(output)f(\014le.)40
+b(Th)m(us,)29 b(if)f(all)h(3)h(parameters)g(are)g(true,)g(then)g(the)f
+(en)m(tire)h(input)e(\014le)227 2951 y(will)33 b(b)s(e)h(copied.)55
+b(On)35 b(exit,)h(the)g(curren)m(t)f(HDU)h(in)d(the)j(input)d(\014le)i
+(will)d(b)s(e)j(unc)m(hanged,)h(and)f(the)g(last)227
+3064 y(HDU)c(in)e(the)i(output)f(\014le)f(will)f(b)s(e)i(the)g(curren)m
+(t)h(HDU.)95 3318 y Fe(int)47 b(fits_copy_file)d(/)k(ffcpfl)286
+3431 y(\(fitsfile)e(*infptr,)f(fitsfile)h(*outfptr,)f(int)i(previous,)e
+(int)i(current,)477 3544 y(int)g(following,)e(>)j(int)f(*status\))0
+3797 y Fi(6)81 b Fj(Cop)m(y)34 b(the)h(curren)m(t)f(HDU)h(from)f(the)g
+(FITS)g(\014le)g(asso)s(ciated)g(with)g(infptr)e(and)i(app)s(end)e(it)i
+(to)h(the)g(end)f(of)227 3910 y(the)39 b(FITS)e(\014le)g(asso)s(ciated)
+i(with)e(outfptr.)64 b(Space)38 b(ma)m(y)h(b)s(e)e(reserv)m(ed)i(for)f
+(MOREKEYS)f(additional)227 4023 y(k)m(eyw)m(ords)31 b(in)e(the)i
+(output)f(header.)95 4276 y Fe(int)47 b(fits_copy_hdu)e(/)i(ffcopy)286
+4389 y(\(fitsfile)f(*infptr,)f(fitsfile)h(*outfptr,)f(int)i(morekeys,)e
+(>)j(int)f(*status\))0 4642 y Fi(7)81 b Fj(Cop)m(y)43
+b(the)h(header)g(\(and)f(not)h(the)g(data\))h(from)e(the)h(CHDU)g(asso)
+s(ciated)g(with)f(infptr)e(to)k(the)f(CHDU)227 4755 y(asso)s(ciated)27
+b(with)e(outfptr.)39 b(If)26 b(the)h(curren)m(t)f(output)g(HDU)h(is)f
+(not)g(completely)g(empt)m(y)-8 b(,)29 b(then)d(the)h(CHDU)227
+4868 y(will)32 b(b)s(e)i(closed)g(and)g(a)h(new)f(HDU)h(will)d(b)s(e)i
+(app)s(ended)e(to)j(the)g(output)f(\014le.)52 b(An)34
+b(empt)m(y)h(output)f(data)227 4981 y(unit)29 b(will)f(b)s(e)i(created)
+h(with)e(all)g(v)-5 b(alues)30 b(initially)d(=)j(0\).)95
+5235 y Fe(int)47 b(fits_copy_header)d(/)j(ffcphd)286
+5348 y(\(fitsfile)f(*infptr,)f(fitsfile)h(*outfptr,)f(>)i(int)g
+(*status\))0 5601 y Fi(8)81 b Fj(Delete)34 b(the)f(CHDU)h(in)e(the)h
+(FITS)f(\014le.)49 b(An)m(y)33 b(follo)m(wing)f(HDUs)h(will)e(b)s(e)h
+(shifted)g(forw)m(ard)h(in)f(the)h(\014le,)g(to)227 5714
+y(\014ll)j(in)g(the)h(gap)h(created)g(b)m(y)g(the)f(deleted)g(HDU.)i
+(In)d(the)i(case)g(of)g(deleting)e(the)i(primary)d(arra)m(y)j(\(the)p
+eop
+%%Page: 35 43
+35 42 bop 0 299 a Fh(5.4.)72 b(HEADER)31 b(KEYW)m(ORD)g(READ/WRITE)g(R)
+m(OUTINES)1495 b Fj(35)227 555 y(\014rst)30 b(HDU)h(in)e(the)i
+(\014le\))f(then)g(the)h(curren)m(t)f(primary)e(arra)m(y)j(will)d(b)s
+(e)i(replace)g(b)m(y)h(a)g(n)m(ull)d(primary)g(arra)m(y)227
+668 y(con)m(taining)j(the)h(minim)m(um)c(set)k(of)g(required)d(k)m(eyw)
+m(ords)j(and)e(no)i(data.)44 b(If)31 b(there)g(are)h(more)f(extensions)
+227 781 y(in)e(the)h(\014le)f(follo)m(wing)g(the)h(one)g(that)h(is)e
+(deleted,)h(then)g(the)g(the)g(CHDU)h(will)c(b)s(e)j(rede\014ned)e(to)j
+(p)s(oin)m(t)e(to)227 894 y(the)e(follo)m(wing)e(extension.)40
+b(If)26 b(there)h(are)g(no)g(follo)m(wing)e(extensions)h(then)h(the)g
+(CHDU)g(will)d(b)s(e)i(rede\014ned)227 1007 y(to)36 b(p)s(oin)m(t)e(to)
+h(the)g(previous)e(HDU.)j(The)e(output)h(hdut)m(yp)s(e)e(parameter)i
+(returns)f(the)h(t)m(yp)s(e)g(of)f(the)h(new)227 1120
+y(CHDU.)c(A)g(n)m(ull)d(p)s(oin)m(ter)h(ma)m(y)i(b)s(e)f(giv)m(en)h
+(for)f(hdut)m(yp)s(e)f(if)g(the)i(returned)e(v)-5 b(alue)30
+b(is)f(not)i(needed.)95 1401 y Fe(int)47 b(fits_delete_hdu)d(/)j
+(ffdhdu)286 1514 y(\(fitsfile)f(*fptr,)g(>)h(int)g(*hdutype,)e(int)i
+(*status\))0 1872 y Ff(5.4)135 b(Header)46 b(Keyw)l(ord)g(Read/W)-11
+b(rite)46 b(Routines)0 2128 y Fj(These)35 b(routines)f(read)g(or)h
+(write)g(k)m(eyw)m(ords)g(in)f(the)h(Curren)m(t)f(Header)h(Unit)f
+(\(CHU\).)i(Wild)e(card)g(c)m(haracters)0 2240 y(\(*,)28
+b(?,)g(or)e(#\))h(ma)m(y)g(b)s(e)f(used)g(when)f(sp)s(ecifying)g(the)i
+(name)f(of)h(the)g(k)m(eyw)m(ord)g(to)g(b)s(e)f(read:)39
+b(a)27 b(')10 b(?')39 b(will)24 b(matc)m(h)k(an)m(y)0
+2353 y(single)33 b(c)m(haracter)i(at)g(that)f(p)s(osition)e(in)h(the)h
+(k)m(eyw)m(ord)h(name)f(and)f(a)h('*')h(will)d(matc)m(h)i(an)m(y)h
+(length)e(\(including)0 2466 y(zero\))d(string)e(of)h(c)m(haracters.)42
+b(The)28 b('#')h(c)m(haracter)i(will)26 b(matc)m(h)k(an)m(y)f
+(consecutiv)m(e)h(string)e(of)h(decimal)f(digits)f(\(0)0
+2579 y(-)35 b(9\).)55 b(When)35 b(a)g(wild)e(card)i(is)f(used)g(the)h
+(routine)f(will)e(only)i(searc)m(h)i(for)f(a)g(matc)m(h)h(from)e(the)h
+(curren)m(t)g(header)0 2692 y(p)s(osition)25 b(to)j(the)f(end)f(of)h
+(the)g(header)g(and)f(will)e(not)j(resume)g(the)g(searc)m(h)g(from)g
+(the)g(top)g(of)g(the)g(header)g(bac)m(k)g(to)0 2805
+y(the)k(original)f(header)h(p)s(osition)e(as)j(is)e(done)h(when)f(no)h
+(wildcards)e(are)j(included)c(in)i(the)h(k)m(eyw)m(ord)h(name.)43
+b(The)0 2918 y(\014ts)p 127 2918 28 4 v 32 w(read)p 331
+2918 V 33 w(record)32 b(routine)f(ma)m(y)h(b)s(e)g(used)f(to)h(set)h
+(the)f(starting)g(p)s(osition)e(when)h(doing)g(wild)e(card)j(searc)m
+(hs.)46 b(A)0 3031 y(status)29 b(v)-5 b(alue)29 b(of)g(KEY)p
+809 3031 V 32 w(NO)p 980 3031 V 33 w(EXIST)f(is)g(returned)f(if)h(the)h
+(sp)s(eci\014ed)e(k)m(eyw)m(ord)j(to)f(b)s(e)g(read)f(is)g(not)i(found)
+d(in)h(the)0 3144 y(header.)0 3459 y Fd(5.4.1)112 b(Keyw)m(ord)38
+b(Reading)f(Routines)0 3684 y Fi(1)81 b Fj(Return)33
+b(the)h(n)m(um)m(b)s(er)e(of)i(existing)f(k)m(eyw)m(ords)i(\(not)f
+(coun)m(ting)g(the)g(END)g(k)m(eyw)m(ord\))h(and)e(the)h(amoun)m(t)h
+(of)227 3797 y(space)e(curren)m(tly)e(a)m(v)-5 b(ailable)31
+b(for)h(more)g(k)m(eyw)m(ords.)46 b(It)32 b(returns)e(morek)m(eys)j(=)f
+(-1)g(if)f(the)h(header)g(has)g(not)227 3910 y(y)m(et)27
+b(b)s(een)d(closed.)39 b(Note)26 b(that)g(CFITSIO)d(will)g(dynamically)
+g(add)h(space)i(if)e(required)f(when)h(writing)f(new)227
+4023 y(k)m(eyw)m(ords)32 b(to)g(a)f(header)g(so)h(in)e(practice)h
+(there)h(is)e(no)h(limit)e(to)j(the)f(n)m(um)m(b)s(er)f(of)i(k)m(eyw)m
+(ords)f(that)h(can)g(b)s(e)227 4136 y(added)e(to)h(a)f(header.)41
+b(A)30 b(n)m(ull)e(p)s(oin)m(ter)i(ma)m(y)g(b)s(e)g(en)m(tered)h(for)f
+(the)g(morek)m(eys)h(parameter)g(if)e(it's)h(v)-5 b(alue)30
+b(is)227 4249 y(not)h(needed.)95 4530 y Fe(int)47 b(fits_get_hdrspace)c
+(/)48 b(ffghsp)286 4642 y(\(fitsfile)e(*fptr,)g(>)h(int)g(*keysexist,)e
+(int)i(*morekeys,)e(int)i(*status\))0 4924 y Fi(2)81
+b Fj(Return)28 b(the)h(sp)s(eci\014ed)e(k)m(eyw)m(ord.)41
+b(In)29 b(the)g(\014rst)f(routine,)h(the)g(datat)m(yp)s(e)h(parameter)g
+(sp)s(eci\014es)d(the)i(desired)227 5036 y(returned)e(data)h(t)m(yp)s
+(e)g(of)g(the)g(k)m(eyw)m(ord)h(v)-5 b(alue)27 b(and)g(can)h(ha)m(v)m
+(e)h(one)f(of)g(the)g(follo)m(wing)e(sym)m(b)s(olic)h(constan)m(t)227
+5149 y(v)-5 b(alues:)46 b(TSTRING,)33 b(TLOGICAL)f(\(==)h(in)m(t\),)i
+(TBYTE,)e(TSHOR)-8 b(T,)33 b(TUSHOR)-8 b(T,)32 b(TINT,)h(TUINT,)227
+5262 y(TLONG,)39 b(TULONG,)f(TFLO)m(A)-8 b(T,)39 b(TDOUBLE,)g
+(TCOMPLEX,)e(and)h(TDBLCOMPLEX.)h(Within)227 5375 y(the)c(con)m(text)h
+(of)e(this)g(routine,)g(TSTRING)g(corresp)s(onds)e(to)j(a)g('c)m(har*')
+h(data)f(t)m(yp)s(e,)h(i.e.,)f(a)g(p)s(oin)m(ter)e(to)227
+5488 y(a)e(c)m(haracter)i(arra)m(y)-8 b(.)43 b(Data)32
+b(t)m(yp)s(e)f(con)m(v)m(ersion)g(will)d(b)s(e)i(p)s(erformed)g(for)g
+(n)m(umeric)g(v)-5 b(alues)30 b(if)g(the)g(k)m(eyw)m(ord)227
+5601 y(v)-5 b(alue)35 b(do)s(es)g(not)g(ha)m(v)m(e)h(the)f(same)h(data)
+g(t)m(yp)s(e.)55 b(If)34 b(the)h(v)-5 b(alue)35 b(of)g(the)g(k)m(eyw)m
+(ord)h(is)e(unde\014ned)f(\(i.e.,)k(the)227 5714 y(v)-5
+b(alue)30 b(\014eld)f(is)h(blank\))f(then)h(an)g(error)g(status)h(=)f
+(V)-10 b(ALUE)p 2280 5714 V 33 w(UNDEFINED)31 b(will)d(b)s(e)i
+(returned.)p eop
+%%Page: 36 44
+36 43 bop 0 299 a Fj(36)1379 b Fh(CHAPTER)30 b(5.)71
+b(BASIC)30 b(CFITSIO)f(INTERF)-10 b(A)m(CE)30 b(R)m(OUTINES)227
+555 y Fj(The)36 b(second)g(routine)f(returns)g(the)h(k)m(eyw)m(ord)h(v)
+-5 b(alue)35 b(as)h(a)h(c)m(haracter)h(string)d(\(a)h(literal)f(cop)m
+(y)i(of)f(what)227 668 y(is)d(in)f(the)i(v)-5 b(alue)33
+b(\014eld\))f(regardless)h(of)g(the)h(in)m(trinsic)d(data)j(t)m(yp)s(e)
+g(of)f(the)h(k)m(eyw)m(ord.)50 b(The)33 b(third)f(routine)227
+781 y(returns)d(the)i(en)m(tire)f(80-c)m(haracter)j(header)e(record)f
+(of)g(the)h(k)m(eyw)m(ord.)227 927 y(If)f(a)h(NULL)f(commen)m(t)i(p)s
+(oin)m(ter)d(is)g(supplied)f(then)i(the)g(commen)m(t)i(string)d(will)f
+(not)i(b)s(e)g(returned.)95 1160 y Fe(int)47 b(fits_read_key)e(/)i
+(ffgky)286 1273 y(\(fitsfile)f(*fptr,)g(int)h(datatype,)e(char)i
+(*keyname,)e(>)i(DTYPE)g(*value,)334 1386 y(char)g(*comment,)e(int)i
+(*status\))95 1612 y(int)g(fits_read_keyword)c(/)48 b(ffgkey)286
+1725 y(\(fitsfile)e(*fptr,)g(char)g(*keyname,)g(>)h(char)g(*value,)f
+(char)g(*comment,)334 1838 y(int)h(*status\))95 2063
+y(int)g(fits_read_card)d(/)k(ffgcrd)286 2176 y(\(fitsfile)e(*fptr,)g
+(char)g(*keyname,)g(>)h(char)g(*card,)f(int)h(*status\))0
+2410 y Fi(3)81 b Fj(Return)27 b(the)h(n)m(th)h(header)f(record)g(in)f
+(the)h(CHU.)h(The)e(\014rst)h(k)m(eyw)m(ord)h(in)d(the)j(header)f(is)f
+(at)i(k)m(eyn)m(um)f(=)g(1;)i(if)227 2523 y(k)m(eyn)m(um)g(=)f(0)i
+(then)e(these)h(routines)f(simply)e(reset)k(the)f(in)m(ternal)e
+(CFITSIO)g(p)s(oin)m(ter)h(to)i(the)f(b)s(eginning)227
+2635 y(of)f(the)g(header)g(so)g(that)g(subsequen)m(t)f(k)m(eyw)m(ord)h
+(op)s(erations)g(will)d(start)j(at)h(the)f(top)g(of)f(the)h(header)g
+(\(e.g.,)227 2748 y(prior)38 b(to)i(searc)m(hing)f(for)g(k)m(eyw)m
+(ords)h(using)e(wild)e(cards)j(in)f(the)i(k)m(eyw)m(ord)g(name\).)68
+b(The)38 b(\014rst)h(routine)227 2861 y(returns)j(the)h(en)m(tire)g
+(80-c)m(haracter)i(header)e(record,)j(while)41 b(the)i(second)g
+(routine)f(parses)g(the)h(record)227 2974 y(and)35 b(returns)f(the)i
+(name,)h(v)-5 b(alue,)36 b(and)f(commen)m(t)h(\014elds)e(as)i(separate)
+g(c)m(haracter)h(strings.)54 b(If)35 b(a)h(NULL)227 3087
+y(commen)m(t)c(p)s(oin)m(ter)d(is)g(giv)m(en)i(on)f(input,)f(then)h
+(the)g(commen)m(t)i(string)d(will)f(not)j(b)s(e)e(returned.)95
+3320 y Fe(int)47 b(fits_read_record)d(/)j(ffgrec)286
+3433 y(\(fitsfile)f(*fptr,)g(int)h(keynum,)e(>)j(char)f(*card,)f(int)h
+(*status\))95 3659 y(int)g(fits_read_keyn)d(/)k(ffgkyn)286
+3772 y(\(fitsfile)e(*fptr,)g(int)h(keynum,)e(>)j(char)f(*keyname,)e
+(char)h(*value,)334 3885 y(char)h(*comment,)e(int)i(*status\))0
+4118 y Fi(4)81 b Fj(Return)44 b(the)i(next)g(k)m(eyw)m(ord)g(whose)f
+(name)h(matc)m(hes)g(one)g(of)g(the)f(strings)g(in)f('inclist')g(but)h
+(do)s(es)g(not)227 4231 y(matc)m(h)31 b(an)m(y)g(of)g(the)f(strings)f
+(in)g('exclist'.)41 b(The)30 b(strings)f(in)g(inclist)f(and)i(exclist)g
+(ma)m(y)g(con)m(tain)h(wild)d(card)227 4344 y(c)m(haracters)34
+b(\(*,)f(?,)f(and)f(#\))h(as)g(describ)s(ed)e(at)j(the)f(b)s(eginning)d
+(of)j(this)f(section.)45 b(This)30 b(routine)h(searc)m(hes)227
+4457 y(from)k(the)g(curren)m(t)g(header)g(p)s(osition)e(to)j(the)f(end)
+f(of)h(the)h(header,)g(only)-8 b(,)36 b(and)e(do)s(es)h(not)g(con)m
+(tin)m(ue)h(the)227 4570 y(searc)m(h)c(from)e(the)h(top)g(of)g(the)g
+(header)g(bac)m(k)g(to)h(the)f(original)e(p)s(osition.)40
+b(The)31 b(curren)m(t)f(header)h(p)s(osition)227 4683
+y(ma)m(y)e(b)s(e)e(reset)h(with)f(the)h(\013grec)g(routine.)39
+b(Note)29 b(that)g(nexc)f(ma)m(y)g(b)s(e)f(set)h(=)g(0)g(if)f(there)h
+(are)g(no)g(k)m(eyw)m(ords)227 4796 y(to)h(b)s(e)f(excluded.)38
+b(This)27 b(routine)g(returns)g(status)h(=)g(KEY)p 2268
+4796 28 4 v 32 w(NO)p 2439 4796 V 33 w(EXIST)f(if)g(a)i(matc)m(hing)f
+(k)m(eyw)m(ord)h(is)e(not)227 4909 y(found.)95 5142 y
+Fe(int)47 b(fits_find_nextkey)c(/)48 b(ffgnxk)286 5255
+y(\(fitsfile)e(*fptr,)g(char)g(**inclist,)f(int)i(ninc,)g(char)f
+(**exclist,)334 5368 y(int)h(nexc,)f(>)i(char)e(*card,)h(int)94
+b(*status\))0 5601 y Fi(5)81 b Fj(Return)25 b(the)h(ph)m(ysical)e
+(units)h(string)g(from)g(an)h(existing)f(k)m(eyw)m(ord.)39
+b(This)25 b(routine)g(uses)g(a)h(lo)s(cal)g(con)m(v)m(en)m(tion,)227
+5714 y(sho)m(wn)f(in)f(the)h(follo)m(wing)f(example,)i(in)e(whic)m(h)g
+(the)i(k)m(eyw)m(ord)f(units)f(are)i(enclosed)f(in)f(square)h(brac)m(k)
+m(ets)h(in)p eop
+%%Page: 37 45
+37 44 bop 0 299 a Fh(5.4.)72 b(HEADER)31 b(KEYW)m(ORD)g(READ/WRITE)g(R)
+m(OUTINES)1495 b Fj(37)227 555 y(the)30 b(b)s(eginning)d(of)j(the)g(k)m
+(eyw)m(ord)g(commen)m(t)g(\014eld.)39 b(A)30 b(n)m(ull)e(string)g(is)h
+(returned)f(if)h(no)g(units)f(are)i(de\014ned)227 668
+y(for)g(the)h(k)m(eyw)m(ord.)239 913 y Fe(VELOCITY=)809
+b(12.3)46 b(/)i([km/s])e(orbital)g(speed)95 1139 y(int)h
+(fits_read_key_unit)c(/)48 b(ffgunt)286 1252 y(\(fitsfile)e(*fptr,)g
+(char)g(*keyname,)g(>)h(char)g(*unit,)f(int)h(*status\))0
+1497 y Fi(6)81 b Fj(Concatenate)39 b(the)f(header)f(k)m(eyw)m(ords)h
+(in)f(the)g(CHDU)h(in)m(to)g(a)g(single)e(long)h(string)g(of)h(c)m
+(haracters.)64 b(This)227 1610 y(pro)m(vides)27 b(a)i(con)m(v)m(enien)m
+(t)g(w)m(a)m(y)g(of)g(passing)e(all)g(or)h(part)g(of)g(the)h(header)f
+(information)e(in)h(a)i(FITS)e(HDU)i(to)227 1723 y(other)i
+(subroutines.)38 b(Eac)m(h)31 b(80-c)m(haracter)h(\014xed-length)e(k)m
+(eyw)m(ord)g(record)g(is)f(app)s(ended)f(to)j(the)f(output)227
+1836 y(c)m(haracter)j(string,)e(in)f(order,)h(with)f(no)h(in)m(terv)m
+(ening)g(separator)h(or)f(terminating)f(c)m(haracters.)45
+b(The)31 b(last)227 1949 y(header)i(record)g(is)f(terminated)h(with)f
+(a)h(NULL)g(c)m(haracter.)50 b(This)32 b(routine)g(allo)s(cates)h
+(memory)g(for)g(the)227 2062 y(returned)c(c)m(haracter)j(arra)m(y)-8
+b(,)32 b(so)f(the)f(calling)f(program)h(m)m(ust)g(free)h(the)g(memory)f
+(when)f(\014nished.)227 2210 y(Selected)g(k)m(eyw)m(ords)f(ma)m(y)h(b)s
+(e)e(excluded)g(from)h(the)g(returned)f(c)m(haracter)j(string.)39
+b(If)27 b(the)i(second)f(param-)227 2323 y(eter)h(\(no)s(commen)m(ts\))
+g(is)e(TR)m(UE)h(\(nonzero\))h(then)e(an)m(y)i(COMMENT,)f(HISTOR)-8
+b(Y,)27 b(or)h(blank)f(k)m(eyw)m(ords)227 2435 y(in)i(the)i(header)f
+(will)e(not)i(b)s(e)g(copied)g(to)h(the)g(output)f(string.)227
+2583 y(The)25 b('exclist')h(parameter)g(ma)m(y)g(b)s(e)f(used)g(to)h
+(supply)d(a)j(list)f(of)g(k)m(eyw)m(ords)h(that)h(are)f(to)g(b)s(e)f
+(excluded)f(from)227 2696 y(the)29 b(output)g(c)m(haracter)h(string.)40
+b(Wild)27 b(card)i(c)m(haracters)h(\(*,)g(?,)f(and)g(#\))g(ma)m(y)g(b)s
+(e)f(used)g(in)g(the)h(excluded)227 2809 y(k)m(eyw)m(ord)h(names.)41
+b(If)29 b(no)g(additional)f(k)m(eyw)m(ords)i(are)g(to)g(b)s(e)f
+(excluded,)g(then)g(set)h(nexc)g(=)f(0)h(and)f(sp)s(ecify)227
+2922 y(NULL)i(for)f(the)g(the)h(**header)g(parameter.)95
+3167 y Fe(int)47 b(fits_hdr2str)286 3280 y(\(fitsfile)f(*fptr,)g(int)h
+(nocomments,)d(char)j(**exclist,)e(int)i(nexc,)286 3393
+y(>)h(char)e(**header,)g(int)h(*nkeys,)e(int)i(*status\))0
+3681 y Fd(5.4.2)112 b(Keyw)m(ord)38 b(W)-9 b(riting)35
+b(Routines)0 3888 y Fi(1)81 b Fj(W)-8 b(rite)31 b(a)h(k)m(eyw)m(ord)g
+(of)f(the)h(appropriate)e(data)i(t)m(yp)s(e)g(in)m(to)f(the)h(CHU.)f
+(The)g(\014rst)g(routine)f(simply)f(app)s(ends)227 4001
+y(a)34 b(new)f(k)m(eyw)m(ord)h(whereas)f(the)g(second)h(routine)e(will)
+f(up)s(date)h(the)i(v)-5 b(alue)32 b(and)h(commen)m(t)h(\014elds)e(of)i
+(the)227 4114 y(k)m(eyw)m(ord)g(if)f(it)g(already)g(exists,)h
+(otherwise)f(it)g(app)s(ends)f(a)i(new)f(k)m(eyw)m(ord.)51
+b(Note)35 b(that)f(the)g(address)e(to)227 4227 y(the)37
+b(v)-5 b(alue,)37 b(and)e(not)i(the)f(v)-5 b(alue)35
+b(itself,)i(m)m(ust)f(b)s(e)f(en)m(tered.)59 b(The)35
+b(datat)m(yp)s(e)i(parameter)g(sp)s(eci\014es)e(the)227
+4340 y(data)40 b(t)m(yp)s(e)f(of)g(the)g(k)m(eyw)m(ord)g(v)-5
+b(alue)39 b(with)e(one)i(of)g(the)g(follo)m(wing)f(v)-5
+b(alues:)57 b(TSTRING,)38 b(TLOGICAL)227 4452 y(\(==)e(in)m(t\),)i
+(TBYTE,)f(TSHOR)-8 b(T,)35 b(TUSHOR)-8 b(T,)36 b(TINT,)g(TUINT,)g
+(TLONG,)g(TULONG,)g(TFLO)m(A)-8 b(T,)227 4565 y(TDOUBLE.)24
+b(Within)e(the)h(con)m(text)i(of)f(this)e(routine,)i(TSTRING)f(corresp)
+s(onds)f(to)i(a)g('c)m(har*')g(data)h(t)m(yp)s(e,)227
+4678 y(i.e.,)j(a)e(p)s(oin)m(ter)g(to)h(a)f(c)m(haracter)i(arra)m(y)-8
+b(.)40 b(A)27 b(n)m(ull)d(p)s(oin)m(ter)h(ma)m(y)i(b)s(e)f(en)m(tered)h
+(for)f(the)g(commen)m(t)h(parameter)227 4791 y(in)i(whic)m(h)g(case)j
+(the)e(k)m(eyw)m(ord)h(commen)m(t)h(\014eld)d(will)e(b)s(e)j(unmo)s
+(di\014ed)d(or)k(left)f(blank.)95 5036 y Fe(int)47 b(fits_write_key)d
+(/)k(ffpky)286 5149 y(\(fitsfile)e(*fptr,)g(int)h(datatype,)e(char)i
+(*keyname,)e(DTYPE)h(*value,)477 5262 y(char)h(*comment,)e(>)j(int)f
+(*status\))95 5488 y(int)g(fits_update_key)d(/)j(ffuky)286
+5601 y(\(fitsfile)f(*fptr,)g(int)h(datatype,)e(char)i(*keyname,)e
+(DTYPE)h(*value,)477 5714 y(char)h(*comment,)e(>)j(int)f(*status\))p
+eop
+%%Page: 38 46
+38 45 bop 0 299 a Fj(38)1379 b Fh(CHAPTER)30 b(5.)71
+b(BASIC)30 b(CFITSIO)f(INTERF)-10 b(A)m(CE)30 b(R)m(OUTINES)0
+555 y Fi(2)81 b Fj(W)-8 b(rite)43 b(a)h(k)m(eyw)m(ord)f(with)f(a)i(n)m
+(ull)d(or)i(unde\014ned)e(v)-5 b(alue)42 b(\(i.e.,)47
+b(the)d(v)-5 b(alue)42 b(\014eld)g(in)g(the)h(k)m(eyw)m(ord)h(is)e
+(left)227 668 y(blank\).)69 b(The)40 b(\014rst)f(routine)g(simply)f
+(app)s(ends)g(a)j(new)e(k)m(eyw)m(ord)i(whereas)f(the)g(second)g
+(routine)g(will)227 781 y(up)s(date)27 b(the)h(v)-5 b(alue)28
+b(and)f(commen)m(t)i(\014elds)d(of)i(the)g(k)m(eyw)m(ord)g(if)f(it)g
+(already)h(exists,)g(otherwise)f(it)h(app)s(ends)227
+894 y(a)h(new)g(k)m(eyw)m(ord.)40 b(A)29 b(n)m(ull)e(p)s(oin)m(ter)h
+(ma)m(y)h(b)s(e)g(en)m(tered)g(for)g(the)g(commen)m(t)g(parameter)h(in)
+d(whic)m(h)h(case)i(the)227 1007 y(k)m(eyw)m(ord)h(commen)m(t)h
+(\014eld)c(will)g(b)s(e)i(unmo)s(di\014ed)d(or)k(left)f(blank.)95
+1261 y Fe(int)47 b(fits_write_key_null)c(/)k(ffpkyu)286
+1374 y(\(fitsfile)f(*fptr,)g(char)g(*keyname,)g(char)g(*comment,)g(>)h
+(int)g(*status\))95 1599 y(int)g(fits_update_key_null)c(/)k(ffukyu)286
+1712 y(\(fitsfile)f(*fptr,)g(char)g(*keyname,)g(char)g(*comment,)g(>)h
+(int)g(*status\))0 1966 y Fi(3)81 b Fj(W)-8 b(rite)39
+b(\(app)s(end\))f(a)h(COMMENT)g(or)g(HISTOR)-8 b(Y)38
+b(k)m(eyw)m(ord)i(to)f(the)g(CHU.)h(The)e(commen)m(t)i(or)f(history)227
+2079 y(string)30 b(will)d(b)s(e)j(con)m(tin)m(ued)g(o)m(v)m(er)i(m)m
+(ultiple)c(k)m(eyw)m(ords)j(if)e(it)h(is)f(longer)h(than)g(70)i(c)m
+(haracters.)95 2333 y Fe(int)47 b(fits_write_comment)c(/)48
+b(ffpcom)286 2446 y(\(fitsfile)e(*fptr,)g(char)g(*comment,)g(>)h(int)g
+(*status\))95 2672 y(int)g(fits_write_history)c(/)48
+b(ffphis)286 2785 y(\(fitsfile)e(*fptr,)g(char)g(*history,)g(>)h(int)g
+(*status\))0 3039 y Fi(4)81 b Fj(W)-8 b(rite)28 b(the)h(D)m(A)-8
+b(TE)29 b(k)m(eyw)m(ord)g(to)g(the)g(CHU.)f(The)g(k)m(eyw)m(ord)h(v)-5
+b(alue)28 b(will)d(con)m(tain)k(the)g(curren)m(t)f(system)g(date)227
+3152 y(as)k(a)g(c)m(haracter)h(string)d(in)g('yyyy-mm-ddThh:mm:ss')f
+(format.)44 b(If)31 b(a)h(D)m(A)-8 b(TE)32 b(k)m(eyw)m(ord)g(already)f
+(exists)227 3264 y(in)c(the)g(header,)i(then)e(this)f(routine)h(will)e
+(simply)g(up)s(date)i(the)h(k)m(eyw)m(ord)g(v)-5 b(alue)27
+b(with)f(the)i(curren)m(t)g(date.)95 3518 y Fe(int)47
+b(fits_write_date)d(/)j(ffpdat)286 3631 y(\(fitsfile)f(*fptr,)g(>)h
+(int)g(*status\))0 3885 y Fi(5)81 b Fj(W)-8 b(rite)33
+b(a)h(user)f(sp)s(eci\014ed)f(k)m(eyw)m(ord)i(record)f(in)m(to)g(the)h
+(CHU.)g(This)d(is)i(a)h(lo)m(w{lev)m(el)f(routine)g(whic)m(h)f(can)i(b)
+s(e)227 3998 y(used)f(to)h(write)e(an)m(y)i(arbitrary)e(record)h(in)m
+(to)h(the)f(header.)50 b(The)32 b(record)i(m)m(ust)f(conform)g(to)h
+(the)g(all)e(the)227 4111 y(FITS)e(format)h(requiremen)m(ts.)95
+4365 y Fe(int)47 b(fits_write_record)c(/)48 b(ffprec)286
+4478 y(\(fitsfile)e(*fptr,)g(char)g(*card,)g(>)i(int)f(*status\))0
+4732 y Fi(6)81 b Fj(Up)s(date)34 b(an)g(80-c)m(haracter)j(record)e(in)e
+(the)h(CHU.)h(If)f(a)h(k)m(eyw)m(ord)f(with)g(the)g(input)f(name)h
+(already)g(exists,)227 4845 y(then)f(it)g(is)f(o)m(v)m(erwritten)h(b)m
+(y)g(the)g(v)-5 b(alue)33 b(of)g(card.)49 b(This)31 b(could)h(mo)s
+(dify)f(the)j(k)m(eyw)m(ord)f(name)g(as)h(w)m(ell)e(as)227
+4958 y(the)e(v)-5 b(alue)29 b(and)f(commen)m(t)j(\014elds.)39
+b(If)29 b(the)g(k)m(eyw)m(ord)h(do)s(esn't)f(already)g(exist)g(then)h
+(a)f(new)g(k)m(eyw)m(ord)h(card)227 5070 y(is)g(app)s(ended)e(to)j(the)
+g(header.)95 5324 y Fe(int)47 b(fits_update_card)d(/)j(ffucrd)286
+5437 y(\(fitsfile)f(*fptr,)g(char)g(*keyname,)g(char)g(*card,)g(>)i
+(int)f(*status\))0 5691 y Fi(7)81 b Fj(Mo)s(dify)29 b(\(o)m(v)m
+(erwrite\))i(the)g(commen)m(t)g(\014eld)e(of)i(an)f(existing)f(k)m(eyw)
+m(ord.)p eop
+%%Page: 39 47
+39 46 bop 0 299 a Fh(5.5.)72 b(PRIMAR)-8 b(Y)31 b(ARRA)-8
+b(Y)31 b(OR)f(IMA)m(GE)h(EXTENSION)f(I/O)g(R)m(OUTINES)1011
+b Fj(39)95 555 y Fe(int)47 b(fits_modify_comment)c(/)k(ffmcom)286
+668 y(\(fitsfile)f(*fptr,)g(char)g(*keyname,)g(char)g(*comment,)g(>)h
+(int)g(*status\))0 907 y Fi(8)81 b Fj(W)-8 b(rite)32
+b(the)g(ph)m(ysical)f(units)g(string)g(in)m(to)h(an)g(existing)f(k)m
+(eyw)m(ord.)46 b(This)31 b(routine)g(uses)h(a)g(lo)s(cal)g(con)m(v)m
+(en)m(tion,)227 1020 y(sho)m(wn)g(in)f(the)i(follo)m(wing)e(example,)i
+(in)e(whic)m(h)g(the)i(k)m(eyw)m(ord)g(units)e(are)i(enclosed)f(in)f
+(square)h(brac)m(k)m(ets)227 1133 y(in)d(the)i(b)s(eginning)d(of)i(the)
+h(k)m(eyw)m(ord)g(commen)m(t)g(\014eld.)239 1372 y Fe(VELOCITY=)809
+b(12.3)46 b(/)i([km/s])e(orbital)g(speed)95 1598 y(int)h
+(fits_write_key_unit)c(/)k(ffpunt)286 1711 y(\(fitsfile)f(*fptr,)g
+(char)g(*keyname,)g(char)g(*unit,)g(>)i(int)f(*status\))0
+1950 y Fi(9)81 b Fj(Rename)30 b(an)h(existing)e(k)m(eyw)m(ord,)i
+(preserving)e(the)h(curren)m(t)h(v)-5 b(alue)29 b(and)h(commen)m(t)i
+(\014elds.)95 2189 y Fe(int)47 b(fits_modify_name)d(/)j(ffmnam)286
+2302 y(\(fitsfile)f(*fptr,)g(char)g(*oldname,)g(char)g(*newname,)g(>)h
+(int)g(*status\))0 2541 y Fi(10)f Fj(Delete)36 b(a)f(k)m(eyw)m(ord)g
+(record.)54 b(The)34 b(space)i(o)s(ccupied)d(b)m(y)i(the)g(k)m(eyw)m
+(ord)g(is)f(reclaimed)g(b)m(y)g(mo)m(ving)h(all)f(the)227
+2654 y(follo)m(wing)d(header)i(records)f(up)g(one)h(ro)m(w)f(in)g(the)g
+(header.)48 b(The)32 b(\014rst)g(routine)f(deletes)i(a)g(k)m(eyw)m(ord)
+g(at)h(a)227 2767 y(sp)s(eci\014ed)22 b(p)s(osition)g(in)h(the)h
+(header)f(\(the)i(\014rst)e(k)m(eyw)m(ord)h(is)f(at)h(p)s(osition)e
+(1\),)k(whereas)e(the)g(second)g(routine)227 2880 y(deletes)29
+b(a)g(sp)s(eci\014cally)d(named)i(k)m(eyw)m(ord.)41 b(Wild)27
+b(card)h(c)m(haracters)i(ma)m(y)f(b)s(e)f(used)g(when)f(sp)s(ecifying)g
+(the)227 2993 y(name)k(of)f(the)h(k)m(eyw)m(ord)g(to)g(b)s(e)e
+(deleted.)95 3232 y Fe(int)47 b(fits_delete_record)c(/)48
+b(ffdrec)286 3345 y(\(fitsfile)e(*fptr,)g(int)142 b(keynum,)94
+b(>)47 b(int)g(*status\))95 3571 y(int)g(fits_delete_key)d(/)j(ffdkey)
+286 3684 y(\(fitsfile)f(*fptr,)g(char)g(*keyname,)g(>)h(int)g
+(*status\))0 4014 y Ff(5.5)135 b(Primary)46 b(Arra)l(y)f(or)g(IMA)l(GE)
+f(Extension)i(I/O)f(Routines)0 4264 y Fj(These)22 b(routines)f(read)i
+(or)f(write)g(data)h(v)-5 b(alues)22 b(in)f(the)h(primary)f(data)i
+(arra)m(y)g(\(i.e.,)i(the)d(\014rst)g(HDU)h(in)e(a)i(FITS)e(\014le\))0
+4377 y(or)32 b(an)g(IMA)m(GE)h(extension.)46 b(There)31
+b(are)i(also)f(routines)f(to)i(get)g(information)d(ab)s(out)i(the)g
+(data)h(t)m(yp)s(e)g(and)e(size)0 4490 y(of)c(the)g(image.)40
+b(Users)27 b(should)e(also)i(read)g(the)g(follo)m(wing)e(c)m(hapter)j
+(on)f(the)g(CFITSIO)e(iterator)j(function)d(whic)m(h)0
+4603 y(pro)m(vides)32 b(a)i(more)f(`ob)5 b(ject)35 b(orien)m(ted')e
+(metho)s(d)g(of)g(reading)f(and)h(writing)e(images.)50
+b(The)32 b(iterator)i(function)e(is)0 4716 y(a)f(little)f(more)h
+(complicated)f(to)i(use,)f(but)f(the)h(adv)-5 b(an)m(tages)32
+b(are)f(that)h(it)e(usually)f(tak)m(es)j(less)e(co)s(de)h(to)g(p)s
+(erform)0 4829 y(the)j(same)h(op)s(eration,)f(and)f(the)i(resulting)d
+(program)h(oftens)i(runs)d(faster)i(b)s(ecause)g(the)h(FITS)e(\014les)g
+(are)h(read)0 4942 y(and)c(written)f(using)g(the)i(most)f(e\016cien)m
+(t)h(blo)s(c)m(k)f(size.)0 5102 y(C)25 b(programmers)h(should)e(note)i
+(that)g(the)h(ordering)d(of)i(arra)m(ys)g(in)f(FITS)g(\014les,)h(and)f
+(hence)h(in)f(all)f(the)i(CFITSIO)0 5215 y(calls,)38
+b(is)e(more)h(similar)e(to)i(the)h(dimensionalit)m(y)c(of)j(arra)m(ys)g
+(in)f(F)-8 b(ortran)38 b(rather)f(than)f(C.)h(F)-8 b(or)38
+b(instance)f(if)f(a)0 5328 y(FITS)28 b(image)h(has)f(NAXIS1)h(=)f(100)i
+(and)e(NAXIS2)h(=)f(50,)i(then)e(a)h(2-D)h(arra)m(y)f(just)f(large)h
+(enough)f(to)i(hold)d(the)0 5441 y(image)k(should)d(b)s(e)i(declared)g
+(as)g(arra)m(y[50][100])k(and)c(not)h(as)f(arra)m(y[100][50].)0
+5601 y(The)h(`datat)m(yp)s(e')h(parameter)g(sp)s(eci\014es)d(the)j
+(data)g(t)m(yp)s(e)f(of)g(the)g(`n)m(ulv)-5 b(al')30
+b(and)h(`arra)m(y')h(p)s(oin)m(ters)e(and)g(can)i(ha)m(v)m(e)0
+5714 y(one)h(of)g(the)g(follo)m(wing)e(v)-5 b(alues:)45
+b(TBYTE,)33 b(TSBYTE,)f(TSHOR)-8 b(T,)32 b(TUSHOR)-8
+b(T,)32 b(TINT,)h(TUINT,)f(TLONG,)p eop
+%%Page: 40 48
+40 47 bop 0 299 a Fj(40)1379 b Fh(CHAPTER)30 b(5.)71
+b(BASIC)30 b(CFITSIO)f(INTERF)-10 b(A)m(CE)30 b(R)m(OUTINES)0
+555 y Fj(TLONGLONG,)c(TULONG,)g(TFLO)m(A)-8 b(T,)27 b(TDOUBLE.)f
+(Automatic)h(data)g(t)m(yp)s(e)g(con)m(v)m(ersion)f(is)f(p)s(erformed)g
+(if)0 668 y(the)j(data)h(t)m(yp)s(e)f(of)f(the)i(FITS)e(arra)m(y)h
+(\(as)g(de\014ned)f(b)m(y)h(the)g(BITPIX)f(k)m(eyw)m(ord\))i(di\013ers)
+d(from)i(that)g(sp)s(eci\014ed)e(b)m(y)0 781 y('datat)m(yp)s(e'.)54
+b(The)34 b(data)h(v)-5 b(alues)34 b(are)g(also)h(automatically)f
+(scaled)g(b)m(y)g(the)h(BSCALE)f(and)f(BZER)m(O)h(k)m(eyw)m(ord)0
+894 y(v)-5 b(alues)30 b(as)g(they)h(are)g(b)s(eing)e(read)h(or)g
+(written)g(in)f(the)h(FITS)g(arra)m(y)-8 b(.)0 1147 y
+Fi(1)81 b Fj(Get)39 b(the)f(data)h(t)m(yp)s(e)f(or)g(equiv)-5
+b(alen)m(t)37 b(data)i(t)m(yp)s(e)f(of)g(the)h(image.)64
+b(The)37 b(\014rst)g(routine)g(returns)g(the)h(ph)m(ys-)227
+1260 y(ical)j(data)g(t)m(yp)s(e)h(of)f(the)g(FITS)f(image,)k(as)e(giv)m
+(en)f(b)m(y)g(the)g(BITPIX)g(k)m(eyw)m(ord,)j(with)c(allo)m(w)m(ed)h(v)
+-5 b(alues)227 1373 y(of)44 b(BYTE)p 609 1373 28 4 v
+33 w(IMG)g(\(8\),)k(SHOR)-8 b(T)p 1376 1373 V 32 w(IMG)44
+b(\(16\),)49 b(LONG)p 2140 1373 V 33 w(IMG)44 b(\(32\),)49
+b(FLO)m(A)-8 b(T)p 2948 1373 V 33 w(IMG)44 b(\(-32\),)49
+b(and)43 b(DOU-)227 1486 y(BLE)p 415 1486 V 33 w(IMG)f(\(-64\).)75
+b(The)40 b(second)i(routine)e(is)g(similar,)i(except)g(that)g(if)e(the)
+h(image)h(pixel)d(v)-5 b(alues)41 b(are)227 1599 y(scaled,)28
+b(with)f(non-default)f(v)-5 b(alues)27 b(for)g(the)h(BZER)m(O)f(and)g
+(BSCALE)g(k)m(eyw)m(ords,)h(then)f(the)h(routine)f(will)227
+1712 y(return)35 b(the)h('equiv)-5 b(alen)m(t')35 b(data)h(t)m(yp)s(e)g
+(that)g(is)f(needed)g(to)i(store)f(the)g(scaled)f(v)-5
+b(alues.)56 b(F)-8 b(or)36 b(example,)h(if)227 1824 y(BITPIX)27
+b(=)f(16)i(and)e(BSCALE)h(=)f(0.1)i(then)f(the)g(equiv)-5
+b(alen)m(t)26 b(data)i(t)m(yp)s(e)f(is)f(FLO)m(A)-8 b(T)p
+3196 1824 V 33 w(IMG.)28 b(Similarly)23 b(if)227 1937
+y(BITPIX)28 b(=)g(16,)i(BSCALE)d(=)h(1,)h(and)f(BZER)m(O)g(=)g(32768,)j
+(then)d(the)g(the)h(pixel)d(v)-5 b(alues)28 b(span)f(the)i(range)227
+2050 y(of)i(an)f(unsigned)e(short)i(in)m(teger)h(and)f(the)h(returned)e
+(data)i(t)m(yp)s(e)f(will)e(b)s(e)i(USHOR)-8 b(T)p 3168
+2050 V 32 w(IMG.)95 2303 y Fe(int)47 b(fits_get_img_type)c(/)48
+b(ffgidt)286 2416 y(\(fitsfile)e(*fptr,)g(>)h(int)g(*bitpix,)f(int)h
+(*status\))95 2642 y(int)g(fits_get_img_equivtype)42
+b(/)48 b(ffgiet)286 2755 y(\(fitsfile)e(*fptr,)g(>)h(int)g(*bitpix,)f
+(int)h(*status\))0 3008 y Fi(2)81 b Fj(Get)34 b(the)g(n)m(um)m(b)s(er)e
+(of)i(dimensions,)e(and/or)i(the)g(size)f(of)h(eac)m(h)h(dimension)c
+(in)h(the)i(image)g(.)50 b(The)33 b(n)m(um)m(b)s(er)227
+3121 y(of)h(axes)f(in)f(the)h(image)h(is)e(giv)m(en)h(b)m(y)g(naxis,)g
+(and)g(the)g(size)g(of)g(eac)m(h)i(dimension)30 b(is)i(giv)m(en)h(b)m
+(y)g(the)h(naxes)227 3234 y(arra)m(y)d(\(a)g(maxim)m(um)f(of)g(maxdim)f
+(dimensions)f(will)f(b)s(e)j(returned\).)95 3487 y Fe(int)47
+b(fits_get_img_dim)d(/)j(ffgidm)286 3600 y(\(fitsfile)f(*fptr,)g(>)h
+(int)g(*naxis,)f(int)h(*status\))95 3826 y(int)g(fits_get_img_size)c(/)
+48 b(ffgisz)286 3939 y(\(fitsfile)e(*fptr,)g(int)h(maxdim,)e(>)j(long)f
+(*naxes,)e(int)i(*status\))95 4164 y(int)g(fits_get_img_param)c(/)48
+b(ffgipr)286 4277 y(\(fitsfile)e(*fptr,)g(int)h(maxdim,)e(>)j(int)f
+(*bitpix,)e(int)i(*naxis,)f(long)h(*naxes,)334 4390 y(int)g(*status\))0
+4643 y Fi(3)81 b Fj(Create)23 b(a)f(new)g(primary)e(arra)m(y)j(or)f
+(IMA)m(GE)i(extension)d(with)g(a)i(sp)s(eci\014ed)e(data)i(t)m(yp)s(e)f
+(and)g(size.)37 b(If)22 b(the)h(FITS)227 4756 y(\014le)29
+b(is)g(curren)m(tly)f(empt)m(y)i(then)g(a)g(primary)e(arra)m(y)i(is)f
+(created,)i(otherwise)e(a)h(new)f(IMA)m(GE)i(extension)e(is)227
+4869 y(app)s(ended)g(to)i(the)g(\014le.)95 5122 y Fe(int)47
+b(fits_create_img)d(/)j(ffcrim)286 5235 y(\()h(fitsfile)d(*fptr,)h(int)
+h(bitpix,)f(int)h(naxis,)f(long)h(*naxes,)f(>)h(int)g(*status\))0
+5488 y Fi(4)81 b Fj(W)-8 b(rite)39 b(a)g(rectangular)f(subimage)g(\(or)
+h(the)g(whole)f(image\))h(to)g(the)g(FITS)f(data)h(arra)m(y)-8
+b(.)67 b(The)38 b(fpixel)f(and)227 5601 y(lpixel)27 b(arra)m(ys)j(giv)m
+(e)g(the)g(co)s(ordinates)f(of)g(the)h(\014rst)f(\(lo)m(w)m(er)h(left)f
+(corner\))h(and)f(last)g(\(upp)s(er)f(righ)m(t)h(corner\))227
+5714 y(pixels)g(in)g(FITS)h(image)g(to)h(b)s(e)f(written)f(to.)p
+eop
+%%Page: 41 49
+41 48 bop 0 299 a Fh(5.5.)72 b(PRIMAR)-8 b(Y)31 b(ARRA)-8
+b(Y)31 b(OR)f(IMA)m(GE)h(EXTENSION)f(I/O)g(R)m(OUTINES)1011
+b Fj(41)95 555 y Fe(int)47 b(fits_write_subset)c(/)48
+b(ffpss)286 668 y(\(fitsfile)e(*fptr,)g(int)h(datatype,)e(long)i
+(*fpixel,)e(long)i(*lpixel,)334 781 y(DTYPE)f(*array,)g(>)i(int)f
+(*status\))0 1018 y Fi(5)81 b Fj(W)-8 b(rite)38 b(pixels)f(in)m(to)h
+(the)h(FITS)f(data)h(arra)m(y)-8 b(.)66 b('fpixel')37
+b(is)g(an)h(arra)m(y)h(of)g(length)f(NAXIS)g(whic)m(h)f(giv)m(es)i(the)
+227 1131 y(co)s(ordinate)k(of)g(the)g(starting)f(pixel)f(to)j(b)s(e)e
+(written)g(to,)k(suc)m(h)d(that)g(fpixel[0])f(is)g(in)f(the)i(range)g
+(1)g(to)227 1244 y(NAXIS1,)30 b(fpixel[1])d(is)g(in)g(the)i(range)g(1)f
+(to)h(NAXIS2,)h(etc.)41 b(The)28 b(\014rst)f(routine)h(simply)d(writes)
+j(the)g(arra)m(y)227 1357 y(of)e(pixels)d(to)j(the)g(FITS)f(\014le)f
+(\(doing)h(data)h(t)m(yp)s(e)g(con)m(v)m(ersion)f(if)g(necessary\))h
+(whereas)f(the)g(second)h(routine)227 1470 y(will)f(substitute)i(the)h
+(appropriate)f(FITS)g(n)m(ull)f(v)-5 b(alue)27 b(for)h(an)m(y)g(elemen)
+m(ts)g(whic)m(h)f(are)h(equal)f(to)i(the)f(input)227
+1582 y(v)-5 b(alue)25 b(of)h(n)m(ulv)-5 b(al)23 b(\(note)j(that)g(this)
+f(parameter)g(giv)m(es)h(the)g(address)e(of)h(the)h(n)m(ull)d(v)-5
+b(alue,)26 b(not)g(the)f(n)m(ull)e(v)-5 b(alue)227 1695
+y(itself)7 b(\).)45 b(F)-8 b(or)33 b(in)m(teger)f(FITS)f(arra)m(ys,)i
+(the)g(FITS)e(n)m(ull)f(v)-5 b(alue)31 b(is)g(de\014ned)g(b)m(y)h(the)g
+(BLANK)g(k)m(eyw)m(ord)h(\(an)227 1808 y(error)h(is)f(returned)h(if)f
+(the)h(BLANK)h(k)m(eyw)m(ord)f(do)s(esn't)h(exist\).)52
+b(F)-8 b(or)35 b(\015oating)f(p)s(oin)m(t)g(FITS)f(arra)m(ys)i(the)227
+1921 y(sp)s(ecial)29 b(IEEE)h(NaN)h(\(Not-a-Num)m(b)s(er\))h(v)-5
+b(alue)30 b(will)e(b)s(e)h(written)h(in)m(to)g(the)h(FITS)e(\014le.)40
+b(If)30 b(a)h(n)m(ull)d(p)s(oin)m(ter)227 2034 y(is)40
+b(en)m(tered)h(for)f(n)m(ulv)-5 b(al,)42 b(then)e(the)g(n)m(ull)f(v)-5
+b(alue)40 b(is)f(ignored)h(and)f(this)h(routine)f(b)s(eha)m(v)m(es)i
+(the)g(same)g(as)227 2147 y(\014ts)p 354 2147 28 4 v
+33 w(write)p 590 2147 V 32 w(pix.)95 2384 y Fe(int)47
+b(fits_write_pix)d(/)k(ffppx)286 2497 y(\(fitsfile)e(*fptr,)g(int)h
+(datatype,)e(long)i(*fpixel,)e(long)i(nelements,)334
+2610 y(DTYPE)f(*array,)g(int)h(*status\);)95 2836 y(int)g
+(fits_write_pixnull)c(/)48 b(ffppxn)286 2949 y(\(fitsfile)e(*fptr,)g
+(int)h(datatype,)e(long)i(*fpixel,)e(long)i(nelements,)334
+3061 y(DTYPE)f(*array,)g(DTYPE)h(*nulval,)e(>)j(int)f(*status\);)0
+3298 y Fi(6)81 b Fj(Set)24 b(FITS)g(data)i(arra)m(y)f(elemen)m(ts)g
+(equal)f(to)h(the)g(appropriate)e(n)m(ull)g(pixel)g(v)-5
+b(alue.)38 b(F)-8 b(or)25 b(in)m(teger)g(FITS)f(arra)m(ys,)227
+3411 y(the)34 b(FITS)e(n)m(ull)f(v)-5 b(alue)33 b(is)f(de\014ned)g(b)m
+(y)h(the)h(BLANK)f(k)m(eyw)m(ord)h(\(an)f(error)g(is)f(returned)g(if)g
+(the)i(BLANK)227 3524 y(k)m(eyw)m(ord)23 b(do)s(esn't)g(exist\).)38
+b(F)-8 b(or)23 b(\015oating)f(p)s(oin)m(t)g(FITS)g(arra)m(ys)g(the)h
+(sp)s(ecial)e(IEEE)h(NaN)h(\(Not-a-Num)m(b)s(er\))227
+3637 y(v)-5 b(alue)33 b(will)d(b)s(e)j(written)f(in)m(to)h(the)h(FITS)e
+(\014le.)48 b(Note)34 b(that)g('\014rstelem')f(is)f(a)i(scalar)f
+(giving)f(the)h(o\013set)h(to)227 3750 y(the)d(\014rst)e(pixel)g(to)i
+(b)s(e)f(written)f(in)h(the)g(equiv)-5 b(alen)m(t)30
+b(1-dimensional)e(arra)m(y)j(of)g(image)f(pixels.)95
+3987 y Fe(int)47 b(fits_write_null_img)c(/)k(ffpprn)286
+4100 y(\(fitsfile)f(*fptr,)g(long)g(firstelem,)f(long)i(nelements,)e(>)
+i(int)g(*status\))0 4337 y Fi(7)81 b Fj(Read)33 b(a)h(rectangular)g
+(subimage)f(\(or)h(the)g(whole)f(image\))h(from)f(the)h(FITS)f(data)h
+(arra)m(y)-8 b(.)52 b(The)33 b(fpixel)f(and)227 4450
+y(lpixel)27 b(arra)m(ys)j(giv)m(e)g(the)g(co)s(ordinates)f(of)g(the)h
+(\014rst)f(\(lo)m(w)m(er)h(left)f(corner\))h(and)f(last)g(\(upp)s(er)f
+(righ)m(t)h(corner\))227 4563 y(pixels)c(to)j(b)s(e)e(read)h(from)g
+(the)g(FITS)f(image.)40 b(Unde\014ned)25 b(FITS)h(arra)m(y)i(elemen)m
+(ts)f(will)d(b)s(e)i(returned)g(with)227 4675 y(a)k(v)-5
+b(alue)29 b(=)f(*n)m(ullv)-5 b(al,)28 b(\(note)i(that)g(this)e
+(parameter)i(giv)m(es)f(the)h(address)e(of)h(the)h(n)m(ull)d(v)-5
+b(alue,)29 b(not)h(the)f(n)m(ull)227 4788 y(v)-5 b(alue)35
+b(itself)7 b(\))35 b(unless)f(n)m(ulv)-5 b(al)34 b(=)i(0)g(or)f(*n)m
+(ulv)-5 b(al)35 b(=)g(0,)j(in)c(whic)m(h)g(case)j(no)f(c)m(hec)m(ks)h
+(for)e(unde\014ned)f(pixels)227 4901 y(will)28 b(b)s(e)i(p)s(erformed.)
+95 5138 y Fe(int)47 b(fits_read_subset)d(/)j(ffgsv)286
+5251 y(\(fitsfile)f(*fptr,)g(int)94 b(datatype,)46 b(long)g(*fpixel,)g
+(long)g(*lpixel,)g(long)h(*inc,)334 5364 y(DTYPE)f(*nulval,)g(>)h
+(DTYPE)g(*array,)f(int)h(*anynul,)e(int)i(*status\))0
+5601 y Fi(8)81 b Fj(Read)32 b(pixels)f(from)h(the)g(FITS)g(data)h(arra)
+m(y)-8 b(.)48 b('fpixel')31 b(is)h(the)g(starting)g(pixel)f(lo)s
+(cation)h(and)g(is)g(an)g(arra)m(y)h(of)227 5714 y(length)g(NAXIS)g
+(suc)m(h)g(that)h(fpixel[0])e(is)g(in)g(the)i(range)f(1)h(to)g(NAXIS1,)
+g(fpixel[1])e(is)h(in)f(the)h(range)h(1)f(to)p eop
+%%Page: 42 50
+42 49 bop 0 299 a Fj(42)1379 b Fh(CHAPTER)30 b(5.)71
+b(BASIC)30 b(CFITSIO)f(INTERF)-10 b(A)m(CE)30 b(R)m(OUTINES)227
+555 y Fj(NAXIS2,)f(etc.)41 b(The)28 b(nelemen)m(ts)g(parameter)g(sp)s
+(eci\014es)f(the)h(n)m(um)m(b)s(er)f(of)h(pixels)f(to)i(read.)39
+b(If)28 b(fpixel)e(is)h(set)227 668 y(to)36 b(the)f(\014rst)f(pixel,)h
+(and)g(nelemen)m(ts)f(is)g(set)i(equal)f(to)g(the)g(NAXIS1)h(v)-5
+b(alue,)36 b(then)e(this)g(routine)g(w)m(ould)227 781
+y(read)28 b(the)g(\014rst)f(ro)m(w)h(of)g(the)h(image.)40
+b(Alternativ)m(ely)-8 b(,)28 b(if)f(nelemen)m(ts)h(is)f(set)h(equal)g
+(to)g(NAXIS1)g(*)h(NAXIS2)227 894 y(then)h(it)g(w)m(ould)f(read)i(an)f
+(en)m(tire)g(2D)h(image,)g(or)g(the)f(\014rst)g(plane)f(of)i(a)g(3-D)g
+(datacub)s(e.)227 1063 y(The)39 b(\014rst)f(routine)g(will)f(return)g
+(an)m(y)j(unde\014ned)d(pixels)g(in)h(the)h(FITS)f(arra)m(y)i(equal)e
+(to)i(the)f(v)-5 b(alue)39 b(of)227 1176 y(*n)m(ullv)-5
+b(al)41 b(\(note)i(that)g(this)e(parameter)i(giv)m(es)g(the)f(address)g
+(of)g(the)h(n)m(ull)d(v)-5 b(alue,)45 b(not)e(the)f(n)m(ull)e(v)-5
+b(alue)227 1289 y(itself)7 b(\))39 b(unless)f(n)m(ulv)-5
+b(al)37 b(=)i(0)h(or)f(*n)m(ulv)-5 b(al)38 b(=)h(0,)j(in)c(whic)m(h)g
+(case)j(no)e(c)m(hec)m(ks)i(for)e(unde\014ned)e(pixels)h(will)227
+1402 y(b)s(e)c(p)s(erformed.)51 b(The)34 b(second)g(routine)g(is)f
+(similar)f(except)j(that)g(an)m(y)g(unde\014ned)d(pixels)g(will)g(ha)m
+(v)m(e)k(the)227 1515 y(corresp)s(onding)29 b(n)m(ullarra)m(y)f(elemen)
+m(t)j(set)g(equal)f(to)h(TR)m(UE)g(\(=)f(1\).)95 1813
+y Fe(int)47 b(fits_read_pix)e(/)i(ffgpxv)286 1926 y(\(fitsfile)f
+(*fptr,)g(int)94 b(datatype,)46 b(long)g(*fpixel,)g(long)g(nelements,)
+334 2039 y(DTYPE)g(*nulval,)g(>)h(DTYPE)g(*array,)f(int)h(*anynul,)e
+(int)i(*status\))95 2265 y(int)g(fits_read_pixnull)c(/)48
+b(ffgpxf)286 2378 y(\(fitsfile)e(*fptr,)g(int)94 b(datatype,)46
+b(long)g(*fpixel,)g(long)g(nelements,)334 2491 y(>)i(DTYPE)e(*array,)g
+(char)g(*nullarray,)f(int)i(*anynul,)f(int)g(*status\))0
+2869 y Ff(5.6)135 b(Image)46 b(Compression)0 3129 y Fj(CFITSIO)29
+b(no)m(w)h(transparen)m(tly)g(supp)s(orts)e(2)j(t)m(yp)s(es)f(of)h
+(image)g(compression:)0 3289 y(1\))j(The)f(en)m(tire)h(FITS)e(\014le)h
+(ma)m(y)h(b)s(e)f(externally)g(compressed)g(with)f(the)i(gzip)f(or)g
+(Unix)f(compress)i(algorithm,)0 3402 y(pro)s(ducing)22
+b(a)j(*.gz)h(or)f(*.Z)g(\014le,)g(resp)s(ectiv)m(ely)-8
+b(.)38 b(When)25 b(reading)e(compressed)i(\014les)e(of)i(this)e(t)m(yp)
+s(e,)k(CFITSIO)c(\014rst)0 3515 y(uncompresses)j(the)i(en)m(tire)f
+(\014le)f(in)m(to)h(memory)g(b)s(efore)g(p)s(erforming)e(the)i
+(requested)g(read)g(op)s(erations.)39 b(Output)0 3628
+y(\014les)30 b(can)h(b)s(e)f(directly)f(written)h(in)f(the)i(gzip)f
+(compressed)g(format)h(if)f(the)h(user-sp)s(eci\014ed)d(\014lename)i
+(ends)g(with)0 3741 y(`.gz'.)42 b(In)29 b(this)f(case,)j(CFITSIO)d
+(initially)e(writes)j(the)h(uncompressed)e(\014le)h(in)f(memory)i(and)f
+(then)g(compresses)0 3853 y(it)k(and)f(writes)g(it)h(to)g(disk)f(when)g
+(the)h(FITS)f(\014le)h(is)f(closed,)h(th)m(us)g(sa)m(ving)g(user)f
+(disk)g(space.)49 b(Read)33 b(and)g(write)0 3966 y(access)c(to)g(these)
+f(compressed)f(FITS)g(\014les)g(is)g(generally)g(quite)g(fast;)i(the)f
+(main)e(limitation)g(is)h(that)h(there)g(m)m(ust)0 4079
+y(b)s(e)i(enough)g(a)m(v)-5 b(ailable)30 b(memory)g(\(or)h(sw)m(ap)f
+(space\))h(to)g(hold)e(the)i(en)m(tire)f(uncompressed)f(FITS)h(\014le.)
+0 4239 y(2\))36 b(CFITSIO)d(also)i(supp)s(orts)e(a)i(new)m(er)g(image)h
+(compression)e(format)h(in)f(whic)m(h)f(the)i(image)h(is)e(divided)e
+(in)m(to)0 4352 y(a)43 b(grid)e(of)h(rectangular)g(tiles,)j(and)c(eac)m
+(h)j(tile)d(of)i(pixels)d(is)i(individually)36 b(compressed.)76
+b(The)42 b(compressed)0 4465 y(tiles)36 b(are)h(stored)g(in)e(ro)m(ws)i
+(of)f(a)i(v)-5 b(ariable)35 b(length)h(arra)m(y)h(column)f(in)f(a)i
+(FITS)f(binary)f(table,)j(but)e(CFITSIO)0 4578 y(recognizes)31
+b(that)f(the)g(binary)f(table)g(extension)h(con)m(tains)g(an)g(image)g
+(and)g(treats)h(it)e(as)h(if)f(it)h(w)m(ere)g(an)g(IMA)m(GE)0
+4691 y(extension.)46 b(This)31 b(tile-compressed)g(format)i(is)e(esp)s
+(ecially)g(w)m(ell)g(suited)g(for)h(compressing)g(v)m(ery)g(large)h
+(images)0 4804 y(b)s(ecause)e(a\))h(the)g(FITS)e(header)h(k)m(eyw)m
+(ords)h(remain)e(uncompressed)g(for)h(rapid)e(read)i(access,)i(and)e(b)
+s(ecause)g(b\))0 4917 y(it)j(is)g(p)s(ossible)e(to)j(extract)i(and)d
+(uncompress)f(sections)i(of)f(the)h(image)g(without)f(ha)m(ving)g(to)h
+(uncompress)f(the)0 5030 y(en)m(tire)e(image.)45 b(This)30
+b(format)j(is)e(also)g(m)m(uc)m(h)h(more)g(e\013ectiv)m(e)i(in)d
+(compressing)f(\015oating)i(p)s(oin)m(t)f(images)h(\(using)0
+5143 y(a)f(lossy)e(compression)h(algorithm\))g(than)g(simply)e
+(compressing)h(the)i(image)f(using)f(gzip)h(or)g(compress.)0
+5303 y(A)g(detailed)g(description)e(of)j(this)e(format)i(is)e(a)m(v)-5
+b(ailable)30 b(at:)0 5601 y Fe(http://heasarc.gsfc.nasa)o(.gov)o(/doc)o
+(s/s)o(oftw)o(are/)o(fit)o(sio/)334 5714 y(compression/compress_imag)o
+(e.h)o(tml)p eop
+%%Page: 43 51
+43 50 bop 0 299 a Fh(5.6.)72 b(IMA)m(GE)31 b(COMPRESSION)2567
+b Fj(43)0 555 y(The)36 b(N-dimensional)f(FITS)h(image)h(can)g(b)s(e)g
+(divided)d(in)m(to)j(an)m(y)g(desired)e(rectangular)i(grid)f(of)h
+(compression)0 668 y(tiles.)75 b(By)43 b(default)e(the)i(tiles)e(are)h
+(c)m(hosen)h(to)g(corresp)s(ond)e(to)i(the)f(ro)m(ws)h(of)f(the)g
+(image,)k(eac)m(h)d(con)m(taining)0 781 y(NAXIS1)36 b(pixels.)56
+b(F)-8 b(or)36 b(example,)h(a)g(800)g(x)f(800)h(x)f(4)g(pixel)e(data)j
+(cub)s(e)e(w)m(ould)g(b)s(e)g(divided)e(in)i(to)h(3200)i(tiles)0
+894 y(con)m(taining)30 b(800)h(pixels)d(eac)m(h)k(b)m(y)e(default.)40
+b(Alternativ)m(ely)-8 b(,)30 b(this)f(data)i(cub)s(e)e(could)g(b)s(e)h
+(divided)d(in)m(to)j(256)i(tiles)0 1007 y(that)c(are)g(eac)m(h)g(100)h
+(X)e(100)i(X)e(1)h(pixels)d(in)h(size,)i(or)f(4)h(tiles)e(con)m
+(taining)h(800)i(x)e(800)h(X)g(1)g(pixels,)e(or)h(a)h(single)e(tile)0
+1120 y(con)m(taining)j(the)h(en)m(tire)f(data)h(cub)s(e.)40
+b(Note)31 b(that)f(the)f(image)h(dimensions)d(are)j(not)f(required)f
+(to)i(b)s(e)f(an)h(in)m(teger)0 1233 y(m)m(ultiple)j(of)j(the)g(tile)e
+(dimensions,)h(so,)i(for)e(example,)i(this)e(data)h(cub)s(e)f(could)f
+(also)i(b)s(e)f(divided)d(in)m(to)k(250)h(X)0 1346 y(200)32
+b(pixel)c(tiles,)i(in)f(whic)m(h)g(case)j(the)e(last)g(tile)g(in)f(eac)
+m(h)j(ro)m(w)e(w)m(ould)f(only)h(con)m(tain)g(50)i(X)e(200)i(pixels.)0
+1506 y(Curren)m(tly)-8 b(,)29 b(3)i(image)f(compression)g(algorithms)f
+(are)h(supp)s(orted:)39 b(Rice,)31 b(GZIP)-8 b(,)30 b(and)g(PLIO.)g
+(Rice)g(and)f(GZIP)0 1619 y(are)34 b(general)f(purp)s(ose)f(algorithms)
+g(that)i(can)g(b)s(e)f(used)g(to)h(compress)f(almost)h(an)m(y)f(image.)
+51 b(The)32 b(PLIO)h(algo-)0 1732 y(rithm,)38 b(on)f(the)g(other)h
+(hand,)g(is)e(more)i(sp)s(ecialized)d(and)i(w)m(as)h(dev)m(elop)s(ed)e
+(for)h(use)g(in)f(IRAF)i(to)g(store)g(pixel)0 1844 y(data)31
+b(qualit)m(y)f(masks.)41 b(It)30 b(is)g(designed)f(to)i(only)f(w)m(ork)
+g(on)h(images)f(con)m(taining)g(p)s(ositiv)m(e)g(in)m(tegers)g(with)g
+(v)-5 b(alues)0 1957 y(up)29 b(to)i(ab)s(out)g(2**24.)42
+b(Other)30 b(image)h(compression)e(algorithms)h(ma)m(y)h(b)s(e)e(supp)s
+(orted)g(in)g(the)h(future.)0 2118 y(The)41 b(3)g(supp)s(orted)f(image)
+h(compression)f(algorithms)g(are)i(all)e('loss-less')h(when)f(applied)f
+(to)j(in)m(teger)g(FITS)0 2230 y(images;)34 b(the)f(pixel)e(v)-5
+b(alues)31 b(are)i(preserv)m(ed)g(exactly)g(with)e(no)i(loss)e(of)i
+(information)e(during)f(the)j(compression)0 2343 y(and)i(uncompression)
+f(pro)s(cess.)57 b(Floating)36 b(p)s(oin)m(t)f(FITS)g(images)h(\(whic)m
+(h)f(ha)m(v)m(e)i(BITPIX)f(=)f(-32)i(or)f(-64\))i(are)0
+2456 y(\014rst)33 b(quan)m(tized)h(in)m(to)g(scaled)g(in)m(teger)h
+(pixel)d(v)-5 b(alues)33 b(b)s(efore)h(b)s(eing)f(compressed.)51
+b(This)32 b(tec)m(hnique)i(pro)s(duces)0 2569 y(m)m(uc)m(h)27
+b(higher)e(compression)h(factors)h(than)g(simply)d(using)h(GZIP)h(to)i
+(compress)e(the)h(image,)h(but)e(it)g(also)h(means)0
+2682 y(that)46 b(the)f(original)f(\015oating)h(v)-5 b(alue)45
+b(pixel)e(v)-5 b(alues)45 b(ma)m(y)h(not)f(b)s(e)g(precisely)f
+(returned)g(when)g(the)h(image)h(is)0 2795 y(uncompressed.)55
+b(When)35 b(done)h(prop)s(erly)-8 b(,)35 b(this)g(only)f(discards)g
+(the)i('noise')g(from)f(the)h(\015oating)f(p)s(oin)m(t)g(v)-5
+b(alues)0 2908 y(without)25 b(losing)h(an)m(y)g(signi\014can)m(t)g
+(information.)37 b(The)26 b(amoun)m(t)h(of)g(noise)f(that)h(is)e
+(discarded)g(can)i(b)s(e)e(con)m(trolled)0 3021 y(b)m(y)30
+b(the)h('noise)p 511 3021 28 4 v 32 w(bits')f(compression)f(parameter.)
+0 3181 y(No)42 b(sp)s(ecial)e(action)i(is)e(required)g(to)i(read)g
+(tile-compressed)e(images)i(b)s(ecause)f(all)g(the)g(CFITSIO)f
+(routines)0 3294 y(that)33 b(read)g(normal)f(uncompressed)g(FITS)g
+(images)h(can)g(also)g(read)g(images)g(in)e(the)i(tile-compressed)f
+(format;)0 3407 y(CFITSIO)39 b(essen)m(tially)h(treats)h(the)g(binary)e
+(table)h(that)i(con)m(tains)f(the)f(compressed)h(tiles)e(as)i(if)f(it)g
+(w)m(ere)h(an)0 3520 y(IMA)m(GE)31 b(extension.)0 3680
+y(When)d(creating)h(\(writing\))f(a)h(new)f(image)h(with)e(CFITSIO,)h
+(a)h(normal)e(uncompressed)h(FITS)g(primary)e(arra)m(y)0
+3793 y(or)k(IMA)m(GE)h(extension)f(will)d(b)s(e)i(written)h(unless)e
+(the)i(tile-compressed)f(format)i(has)f(b)s(een)f(sp)s(eci\014ed)f(in)h
+(1)h(of)h(2)0 3906 y(p)s(ossible)d(w)m(a)m(ys:)0 4066
+y(1\))d(A)m(t)g(run)d(time,)j(when)e(sp)s(ecifying)f(the)i(name)g(of)g
+(the)g(output)g(FITS)f(\014le)g(to)i(b)s(e)e(created)i(at)g(run)d
+(time,)j(the)g(user)0 4179 y(can)j(indicate)g(that)g(images)h(should)d
+(b)s(e)h(written)h(in)e(tile-compressed)i(format)g(b)m(y)g(enclosing)g
+(the)g(compression)0 4292 y(parameters)23 b(in)e(square)h(brac)m(k)m
+(ets)i(follo)m(wing)d(the)h(ro)s(ot)h(disk)e(\014le)g(name.)39
+b(The)21 b(`imcop)m(y')i(example)f(program)g(that)0 4405
+y(included)30 b(with)i(the)i(CFITSIO)d(distribution)f(can)j(b)s(e)g
+(used)f(for)h(this)g(purp)s(ose)e(to)j(compress)f(or)g(uncompress)0
+4517 y(images.)58 b(Here)36 b(are)h(some)f(examples)g(of)g(the)g
+(extended)g(\014le)f(name)h(syn)m(tax)h(for)f(sp)s(ecifying)e
+(tile-compressed)0 4630 y(output)c(images:)191 4924 y
+Fe(myfile.fit[compress])185 b(-)48 b(use)f(the)g(default)e(compression)
+g(algorithm)g(\(Rice\))1432 5036 y(and)i(the)g(default)e(tile)i(size)g
+(\(row)f(by)i(row\))191 5262 y(myfile.fit[compress)42
+b(GZIP])47 b(-)g(use)g(the)g(specified)e(compression)g(algorithm;)191
+5375 y(myfile.fit[compress)d(Rice])238 b(only)46 b(the)h(first)g
+(letter)f(of)h(the)g(algorithm)191 5488 y(myfile.fit[compress)42
+b(PLIO])238 b(name)46 b(is)i(required.)191 5714 y(myfile.fit[compress)
+42 b(R)48 b(100,100])141 b(-)47 b(use)g(Rice)g(compression)e(and)p
+eop
+%%Page: 44 52
+44 51 bop 0 299 a Fj(44)1379 b Fh(CHAPTER)30 b(5.)71
+b(BASIC)30 b(CFITSIO)f(INTERF)-10 b(A)m(CE)30 b(R)m(OUTINES)1861
+555 y Fe(100)47 b(x)h(100)f(pixel)f(tile)h(size)191 781
+y(myfile.fit[compress)42 b(R)48 b(100,100;2])d(-)i(as)h(above,)e(and)h
+(also)f(use)h(noisebits)e(=)j(2)0 1031 y Fj(2\))29 b(Before)g(calling)d
+(the)i(CFITSIO)e(routine)h(to)i(write)e(the)h(image)g(header)g(k)m(eyw)
+m(ords)g(\(e.g.,)j(\014ts)p 3335 1031 28 4 v 32 w(create)p
+3603 1031 V 34 w(image\))0 1144 y(the)37 b(programmer)g(can)g(call)g
+(the)g(routines)f(describ)s(ed)f(b)s(elo)m(w)h(to)i(sp)s(ecify)e(the)h
+(compression)f(algorithm)h(and)0 1257 y(the)d(tiling)e(pattern)i(that)h
+(is)e(to)i(b)s(e)e(used.)51 b(There)34 b(are)h(3)f(routines)f(for)h(sp)
+s(ecifying)e(the)i(v)-5 b(arious)33 b(compression)0 1370
+y(parameters)e(and)e(3)i(corresp)s(onding)e(routines)g(to)i(return)e
+(the)i(curren)m(t)f(v)-5 b(alues)30 b(of)g(the)h(parameters:)95
+1619 y Fe(int)47 b(fits_set_compression_type\()o(fit)o(sfil)o(e)42
+b(*fptr,)k(int)h(comptype,)e(int)i(*status\))95 1732
+y(int)g(fits_set_tile_dim\(fitsfile)41 b(*fptr,)46 b(int)h(ndim,)f
+(long)h(*tilesize,)e(int)i(*status\))95 1845 y(int)g
+(fits_set_noise_bits\(fitsfi)o(le)41 b(*fptr,)47 b(int)f(noisebits,)f
+(int)i(*status\))95 2071 y(int)g(fits_get_compression_type\()o(fit)o
+(sfil)o(e)42 b(*fptr,)k(int)h(*comptype,)e(int)i(*status\))95
+2184 y(int)g(fits_get_tile_dim\(fitsfile)41 b(*fptr,)46
+b(int)h(ndim,)f(long)h(*tilesize,)e(int)i(*status\))95
+2297 y(int)g(fits_get_noise_bits\(fitsfi)o(le)41 b(*fptr,)47
+b(int)f(*noisebits,)f(int)i(*status\))0 2547 y Fj(3)24
+b(sym)m(b)s(olic)d(constan)m(ts)k(are)e(de\014ned)f(for)h(use)g(as)g
+(the)h(v)-5 b(alue)22 b(of)i(the)f(`compt)m(yp)s(e')h(parameter:)38
+b(GZIP)p 3447 2547 V 32 w(1,)25 b(RICE)p 3802 2547 V
+32 w(1,)0 2660 y(or)i(PLIO)p 336 2660 V 32 w(1.)39 b(En)m(tering)26
+b(NULL)h(for)f(compt)m(yp)s(e)h(will)d(turn)i(o\013)h(the)g
+(tile-compression)e(and)h(cause)h(normal)f(FITS)0 2773
+y(images)k(to)i(b)s(e)d(written.)0 2933 y(The)h('noisebits')g
+(parameter)i(is)e(only)g(used)g(when)g(compressing)g(\015oating)h(p)s
+(oin)m(t)f(images.)43 b(The)30 b(default)g(v)-5 b(alue)0
+3046 y(is)24 b(4.)40 b(Decreasing)25 b(the)h(v)-5 b(alue)24
+b(of)h(noisebits)f(will)e(impro)m(v)m(e)j(the)h(o)m(v)m(erall)f
+(compression)f(e\016ciency)h(at)h(the)f(exp)s(ense)0
+3159 y(of)31 b(losing)e(more)h(information.)0 3319 y(A)g(small)e
+(example)h(program)g(called)g('imcop)m(y')g(is)g(included)e(with)h
+(CFITSIO)g(that)i(can)f(b)s(e)g(used)g(to)h(compress)0
+3432 y(\(or)44 b(uncompress\))g(an)m(y)g(FITS)g(image.)82
+b(This)42 b(program)i(can)h(b)s(e)e(used)h(to)g(exp)s(erimen)m(t)g
+(with)f(the)h(v)-5 b(arious)0 3545 y(compression)29 b(options)h(on)g
+(existing)g(FITS)f(images)i(as)f(sho)m(wn)g(in)f(these)i(examples:)0
+3794 y Fe(1\))95 b(imcopy)46 b(infile.fit)f('outfile.fit[compress]')334
+4020 y(This)i(will)f(use)h(the)g(default)f(compression)f(algorithm)g
+(\(Rice\))h(and)h(the)334 4133 y(default)f(tile)h(size)f(\(row)h(by)g
+(row\))0 4359 y(2\))95 b(imcopy)46 b(infile.fit)f
+('outfile.fit[compress)d(GZIP]')334 4585 y(This)47 b(will)f(use)h(the)g
+(GZIP)g(compression)e(algorithm)g(and)i(the)g(default)334
+4698 y(tile)g(size)f(\(row)h(by)g(row\).)94 b(The)47
+b(allowed)f(compression)f(algorithms)g(are)334 4811 y(Rice,)h(GZIP,)h
+(and)g(PLIO.)94 b(Only)46 b(the)h(first)g(letter)f(of)h(the)g
+(algorithm)334 4924 y(name)g(needs)f(to)h(be)g(specified.)0
+5149 y(3\))95 b(imcopy)46 b(infile.fit)f('outfile.fit[compress)d(G)47
+b(100,100]')334 5375 y(This)g(will)f(use)h(the)g(GZIP)g(compression)e
+(algorithm)g(and)i(100)g(X)g(100)g(pixel)334 5488 y(tiles.)0
+5714 y(4\))95 b(imcopy)46 b(infile.fit)f('outfile.fit[compress)d(R)47
+b(100,100;)f(4]')p eop
+%%Page: 45 53
+45 52 bop 0 299 a Fh(5.7.)72 b(ASCI)s(I)29 b(AND)i(BINAR)-8
+b(Y)31 b(T)-8 b(ABLE)31 b(R)m(OUTINES)1864 b Fj(45)334
+668 y Fe(This)47 b(will)f(use)h(the)g(Rice)g(compression)e(algorithm,)g
+(100)h(X)i(100)f(pixel)334 781 y(tiles,)f(and)h(noise_bits)e(=)j(4)f
+(\(assuming)e(the)i(input)g(image)f(has)h(a)334 894 y(floating)f(point)
+g(data)h(type\).)93 b(Decreasing)45 b(the)i(value)g(of)g(noisebits)334
+1007 y(will)g(improve)f(the)g(overall)g(compression)f(efficiency)g(at)i
+(the)g(expense)334 1120 y(of)g(losing)f(more)h(information.)0
+1346 y(5\))95 b(imcopy)46 b(infile.fit)f(outfile.fit)334
+1571 y(If)i(the)g(input)g(file)f(is)h(in)h(tile-compressed)43
+b(format,)j(then)h(it)g(will)f(be)334 1684 y(uncompressed)f(to)i(the)g
+(output)f(file.)94 b(Otherwise,)45 b(it)i(simply)f(copies)334
+1797 y(the)h(input)f(image)h(to)g(the)g(output)f(image.)0
+2023 y(6\))95 b(imcopy)46 b('infile.fit[1001:1500,20)o(01:2)o(500])o(')
+89 b(outfile.fit)334 2249 y(This)47 b(extracts)e(a)j(500)f(X)g(500)g
+(pixel)f(section)g(of)h(the)g(much)g(larger)334 2362
+y(input)f(image)h(\(which)f(may)h(be)g(in)g(tile-compressed)d
+(format\).)93 b(The)334 2475 y(output)46 b(is)h(a)h(normal)e
+(uncompressed)e(FITS)j(image.)0 2700 y(7\))95 b(imcopy)46
+b('infile.fit[1001:1500,20)o(01:2)o(500])o(')89 b(outfile.fit.gz)334
+2926 y(Same)47 b(as)g(above,)f(except)g(the)h(output)f(file)h(is)g
+(externally)e(compressed)334 3039 y(using)h(the)h(gzip)g(algorithm.)0
+3513 y Ff(5.7)135 b(ASCI)t(I)45 b(and)f(Binary)h(T)-11
+b(able)45 b(Routines)0 3768 y Fj(These)36 b(routines)f(p)s(erform)g
+(read)i(and)e(write)h(op)s(erations)g(on)g(columns)f(of)i(data)g(in)e
+(FITS)h(ASCI)s(I)e(or)j(Binary)0 3881 y(tables.)46 b(Note)33
+b(that)g(in)d(the)j(follo)m(wing)d(discussions,)g(the)i(\014rst)g(ro)m
+(w)g(and)f(column)g(in)g(a)h(table)g(is)g(at)g(p)s(osition)f(1)0
+3994 y(not)g(0.)0 4154 y(Users)k(should)f(also)i(read)f(the)h(follo)m
+(wing)e(c)m(hapter)j(on)e(the)h(CFITSIO)e(iterator)i(function)f(whic)m
+(h)f(pro)m(vides)h(a)0 4267 y(more)j(`ob)5 b(ject)39
+b(orien)m(ted')f(metho)s(d)g(of)g(reading)f(and)h(writing)e(table)i
+(columns.)62 b(The)37 b(iterator)i(function)d(is)i(a)0
+4380 y(little)c(more)i(complicated)f(to)h(use,)h(but)e(the)g(adv)-5
+b(an)m(tages)38 b(are)d(that)i(it)e(usually)e(tak)m(es)k(less)d(co)s
+(de)i(to)g(p)s(erform)0 4493 y(the)e(same)h(op)s(eration,)f(and)f(the)i
+(resulting)d(program)h(oftens)i(runs)d(faster)i(b)s(ecause)g(the)h
+(FITS)e(\014les)g(are)h(read)0 4606 y(and)c(written)f(using)g(the)i
+(most)f(e\016cien)m(t)h(blo)s(c)m(k)f(size.)0 4924 y
+Fd(5.7.1)112 b(Create)38 b(New)f(T)-9 b(able)0 5149 y
+Fi(1)81 b Fj(Create)40 b(a)f(new)g(ASCI)s(I)e(or)i(bin)m(table)f(table)
+h(extension.)67 b(If)39 b(the)g(FITS)g(\014le)f(is)g(curren)m(tly)g
+(empt)m(y)i(then)f(a)227 5262 y(dumm)m(y)25 b(primary)e(arra)m(y)j
+(will)d(b)s(e)i(created)i(b)s(efore)e(app)s(ending)e(the)j(table)f
+(extension)h(to)g(it.)39 b(The)25 b(tblt)m(yp)s(e)227
+5375 y(parameter)39 b(de\014nes)e(the)h(t)m(yp)s(e)h(of)f(table)g(and)f
+(can)i(ha)m(v)m(e)g(v)-5 b(alues)38 b(of)g(ASCI)s(I)p
+2924 5375 28 4 v 31 w(TBL)g(or)g(BINAR)-8 b(Y)p 3659
+5375 V 34 w(TBL.)227 5488 y(The)29 b(naxis2)f(parameter)i(giv)m(es)f
+(the)h(initial)c(n)m(um)m(b)s(er)i(of)h(ro)m(ws)g(to)h(b)s(e)f(created)
+h(in)e(the)h(table,)g(and)g(should)227 5601 y(normally)f(b)s(e)h(set)h
+(=)g(0.)40 b(CFITSIO)29 b(will)e(automatically)i(increase)h(the)f(size)
+h(of)g(the)g(table)f(as)h(additional)227 5714 y(ro)m(ws)d(are)g
+(written.)39 b(A)27 b(non-zero)g(n)m(um)m(b)s(er)f(of)h(ro)m(ws)g(ma)m
+(y)g(b)s(e)f(sp)s(eci\014ed)f(to)j(reserv)m(e)f(space)h(for)e(that)i
+(man)m(y)p eop
+%%Page: 46 54
+46 53 bop 0 299 a Fj(46)1379 b Fh(CHAPTER)30 b(5.)71
+b(BASIC)30 b(CFITSIO)f(INTERF)-10 b(A)m(CE)30 b(R)m(OUTINES)227
+555 y Fj(ro)m(ws,)41 b(ev)m(en)e(if)f(a)h(few)m(er)g(n)m(um)m(b)s(er)e
+(of)i(ro)m(ws)f(will)e(b)s(e)i(written.)65 b(The)38 b(tunit)f(and)h
+(extname)i(parameters)227 668 y(are)e(optional)e(and)h(a)h(n)m(ull)d(p)
+s(oin)m(ter)h(ma)m(y)i(b)s(e)f(giv)m(en)g(if)g(they)g(are)h(not)f
+(de\014ned.)61 b(The)37 b(FITS)f(Standard)227 781 y(recommends)29
+b(that)h(only)f(letters,)h(digits,)f(and)g(the)g(underscore)g(c)m
+(haracter)i(b)s(e)e(used)g(in)f(column)g(names)227 894
+y(\(the)d(tt)m(yp)s(e)g(parameter\))g(with)d(no)i(em)m(b)s(edded)f
+(spaces.)40 b(T)-8 b(railing)21 b(blank)i(c)m(haracters)j(are)e(not)h
+(signi\014can)m(t.)227 1007 y(It)36 b(is)f(recommended)g(that)i(all)e
+(the)h(column)e(names)i(in)e(a)j(giv)m(en)e(table)h(b)s(e)f(unique)f
+(within)f(the)j(\014rst)g(8)227 1120 y(c)m(haracters,)25
+b(and)c(strongly)f(recommended)h(that)h(the)f(names)h(b)s(e)e(unique)g
+(within)e(the)k(\014rst)e(16)i(c)m(haracters.)95 1478
+y Fe(int)47 b(fits_create_tbl)d(/)j(ffcrtb)286 1591 y(\(fitsfile)f
+(*fptr,)g(int)h(tbltype,)e(long)i(naxis2,)f(int)h(tfields,)e(char)i
+(*ttype[],)334 1704 y(char)g(*tform[],)e(char)i(*tunit[],)e(char)i
+(*extname,)e(int)i(*status\))0 1992 y Fd(5.7.2)112 b(Column)37
+b(Information)f(Routines)0 2199 y Fi(1)81 b Fj(Get)30
+b(the)g(n)m(um)m(b)s(er)e(of)i(ro)m(ws)g(or)f(columns)f(in)h(the)h
+(curren)m(t)f(FITS)g(table.)40 b(The)29 b(n)m(um)m(b)s(er)f(of)i(ro)m
+(ws)g(is)e(giv)m(en)i(b)m(y)227 2312 y(the)k(NAXIS2)f(k)m(eyw)m(ord)h
+(and)e(the)i(n)m(um)m(b)s(er)e(of)h(columns)f(is)g(giv)m(en)h(b)m(y)g
+(the)h(TFIELDS)e(k)m(eyw)m(ord)i(in)e(the)227 2424 y(header)e(of)h(the)
+g(table.)95 2670 y Fe(int)47 b(fits_get_num_rows)c(/)48
+b(ffgnrw)286 2783 y(\(fitsfile)e(*fptr,)g(>)h(long)g(*nrows,)f(int)h
+(*status\);)95 3008 y(int)g(fits_get_num_cols)c(/)48
+b(ffgncl)286 3121 y(\(fitsfile)e(*fptr,)g(>)h(int)g(*ncols,)f(int)h
+(*status\);)0 3366 y Fi(2)81 b Fj(Get)25 b(the)f(table)h(column)e(n)m
+(um)m(b)s(er)g(\(and)h(name\))h(of)f(the)h(column)e(whose)h(name)g
+(matc)m(hes)i(an)e(input)f(template)227 3479 y(name.)48
+b(If)32 b(casesen)i(=)e(CASESEN)g(then)g(the)h(column)e(name)i(matc)m
+(h)h(will)c(b)s(e)i(case-sensitiv)m(e,)i(whereas)227
+3592 y(if)26 b(casesen)i(=)e(CASEINSEN)g(then)h(the)g(case)h(will)c(b)s
+(e)i(ignored.)39 b(As)27 b(a)g(general)g(rule,)f(the)h(column)f(names)
+227 3705 y(should)j(b)s(e)g(treated)j(as)e(case)i(INsensitiv)m(e.)227
+3853 y(The)26 b(input)f(column)g(name)h(template)h(ma)m(y)g(b)s(e)f
+(either)g(the)h(exact)h(name)e(of)h(the)f(column)f(to)j(b)s(e)d(searc)m
+(hed)227 3966 y(for,)k(or)f(it)g(ma)m(y)h(con)m(tain)g(wild)d(card)i(c)
+m(haracters)i(\(*,)g(?,)f(or)f(#\),)h(or)f(it)g(ma)m(y)h(con)m(tain)g
+(the)f(in)m(teger)h(n)m(um)m(b)s(er)227 4079 y(of)k(the)f(desired)e
+(column)h(\(with)g(the)i(\014rst)e(column)g(=)h(1\).)46
+b(The)32 b(`*')h(wild)d(card)i(c)m(haracter)h(matc)m(hes)h(an)m(y)227
+4192 y(sequence)h(of)g(c)m(haracters)h(\(including)c(zero)j(c)m
+(haracters\))i(and)d(the)h(`?')53 b(c)m(haracter)36 b(matc)m(hes)g(an)m
+(y)f(single)227 4305 y(c)m(haracter.)42 b(The)29 b(#)h(wildcard)d(will)
+g(matc)m(h)k(an)m(y)e(consecutiv)m(e)i(string)e(of)g(decimal)g(digits)f
+(\(0-9\).)43 b(If)29 b(more)227 4418 y(than)43 b(one)f(column)g(name)g
+(in)f(the)i(table)g(matc)m(hes)g(the)g(template)g(string,)i(then)d(the)
+h(\014rst)e(matc)m(h)j(is)227 4530 y(returned)28 b(and)h(the)g(status)h
+(v)-5 b(alue)29 b(will)d(b)s(e)j(set)h(to)g(COL)p 2171
+4530 28 4 v 32 w(NOT)p 2408 4530 V 32 w(UNIQUE)f(as)h(a)f(w)m(arning)f
+(that)i(a)g(unique)227 4643 y(matc)m(h)e(w)m(as)g(not)f(found.)39
+b(T)-8 b(o)27 b(\014nd)f(the)h(other)g(cases)h(that)g(matc)m(h)g(the)g
+(template,)g(call)e(the)i(routine)e(again)227 4756 y(lea)m(ving)f(the)g
+(input)e(status)i(v)-5 b(alue)25 b(equal)f(to)i(COL)p
+1950 4756 V 32 w(NOT)p 2187 4756 V 32 w(UNIQUE)f(and)f(the)h(next)h
+(matc)m(hing)f(name)g(will)227 4869 y(then)30 b(b)s(e)g(returned.)40
+b(Rep)s(eat)30 b(this)g(pro)s(cess)g(un)m(til)e(a)j(status)g(=)f(COL)p
+2628 4869 V 32 w(NOT)p 2865 4869 V 32 w(F)m(OUND)i(is)d(returned.)227
+5017 y(The)36 b(FITS)g(Standard)g(recommends)g(that)i(only)d(letters,)k
+(digits,)e(and)f(the)h(underscore)f(c)m(haracter)j(b)s(e)227
+5130 y(used)32 b(in)g(column)g(names)g(\(with)g(no)h(em)m(b)s(edded)f
+(spaces\).)49 b(T)-8 b(railing)30 b(blank)i(c)m(haracters)i(are)f(not)h
+(signif-)227 5243 y(ican)m(t.)57 b(It)36 b(is)f(recommended)g(that)h
+(all)f(the)h(column)e(names)i(in)e(a)i(giv)m(en)g(table)g(b)s(e)f
+(unique)f(within)f(the)227 5356 y(\014rst)i(8)i(c)m(haracters,)h(and)e
+(strongly)f(recommended)g(that)i(the)f(names)g(b)s(e)f(unique)f(within)
+f(the)j(\014rst)f(16)227 5469 y(c)m(haracters.)95 5714
+y Fe(int)47 b(fits_get_colnum)d(/)j(ffgcno)p eop
+%%Page: 47 55
+47 54 bop 0 299 a Fh(5.7.)72 b(ASCI)s(I)29 b(AND)i(BINAR)-8
+b(Y)31 b(T)-8 b(ABLE)31 b(R)m(OUTINES)1864 b Fj(47)286
+555 y Fe(\(fitsfile)46 b(*fptr,)g(int)h(casesen,)e(char)i(*templt,)e(>)
+j(int)f(*colnum,)334 668 y(int)g(*status\))95 894 y(int)g
+(fits_get_colname)d(/)j(ffgcnn)286 1007 y(\(fitsfile)f(*fptr,)g(int)h
+(casesen,)e(char)i(*templt,)e(>)j(char)e(*colname,)334
+1120 y(int)h(*colnum,)f(int)g(*status\))0 1350 y Fi(3)81
+b Fj(Return)30 b(the)i(data)g(t)m(yp)s(e,)h(v)m(ector)g(rep)s(eat)f(v)
+-5 b(alue,)31 b(and)g(the)h(width)e(in)g(b)m(ytes)i(of)g(a)g(column)e
+(in)g(an)i(ASCI)s(I)e(or)227 1463 y(binary)k(table.)55
+b(Allo)m(w)m(ed)35 b(v)-5 b(alues)35 b(for)g(the)h(data)g(t)m(yp)s(e)f
+(in)f(ASCI)s(I)g(tables)h(are:)51 b(TSTRING,)35 b(TSHOR)-8
+b(T,)227 1576 y(TLONG,)36 b(TFLO)m(A)-8 b(T,)36 b(and)f(TDOUBLE.)i
+(Binary)d(tables)i(also)g(supp)s(ort)e(these)i(t)m(yp)s(es:)52
+b(TLOGICAL,)227 1689 y(TBIT,)38 b(TBYTE,)h(TCOMPLEX)e(and)h
+(TDBLCOMPLEX.)h(The)f(negativ)m(e)h(of)g(the)g(data)g(t)m(yp)s(e)g(co)s
+(de)227 1802 y(v)-5 b(alue)31 b(is)f(returned)g(if)g(it)g(is)h(a)g(v)-5
+b(ariable)30 b(length)g(arra)m(y)i(column.)42 b(Note)32
+b(that)g(in)d(the)j(case)g(of)f(a)g('J')h(32-bit)227
+1914 y(in)m(teger)f(binary)d(table)i(column,)f(this)g(routine)g(will)e
+(return)i(data)i(t)m(yp)s(e)f(=)g(TINT32BIT)g(\(whic)m(h)f(in)g(fact)
+227 2027 y(is)35 b(equiv)-5 b(alen)m(t)35 b(to)i(TLONG\).)f(With)f
+(most)h(curren)m(t)g(C)f(compilers,)h(a)h(v)-5 b(alue)35
+b(in)f(a)j('J')f(column)e(has)i(the)227 2140 y(same)29
+b(size)f(as)h(an)f('in)m(t')h(v)-5 b(ariable,)28 b(and)f(ma)m(y)j(not)e
+(b)s(e)g(equiv)-5 b(alen)m(t)28 b(to)h(a)g('long')f(v)-5
+b(ariable,)28 b(whic)m(h)f(is)h(64-bits)227 2253 y(long)i(on)h(an)f
+(increasing)f(n)m(um)m(b)s(er)g(of)h(compilers.)227 2398
+y(The)22 b('rep)s(eat')h(parameter)g(returns)f(the)g(v)m(ector)i(rep)s
+(eat)f(coun)m(t)g(on)f(the)h(binary)e(table)h(TF)m(ORMn)g(k)m(eyw)m
+(ord)227 2511 y(v)-5 b(alue.)59 b(\(ASCI)s(I)35 b(table)i(columns)e
+(alw)m(a)m(ys)i(ha)m(v)m(e)h(rep)s(eat)e(=)g(1\).)60
+b(The)36 b('width')f(parameter)i(returns)f(the)227 2624
+y(width)29 b(in)g(b)m(ytes)i(of)g(a)f(single)f(column)h(elemen)m(t)h
+(\(e.g.,)h(a)f('10D')h(binary)d(table)h(column)f(will)f(ha)m(v)m(e)k
+(width)227 2737 y(=)d(8,)i(an)e(ASCI)s(I)f(table)h('F12.2')j(column)d
+(will)e(ha)m(v)m(e)j(width)e(=)h(12,)i(and)e(a)h(binary)d(table'60A')k
+(c)m(haracter)227 2850 y(string)36 b(column)g(will)f(ha)m(v)m(e)j
+(width)e(=)h(60\);)42 b(Note)c(that)g(this)e(routine)h(supp)s(orts)e
+(the)i(lo)s(cal)g(con)m(v)m(en)m(tion)227 2963 y(for)42
+b(sp)s(ecifying)d(arra)m(ys)k(of)f(\014xed)f(length)g(strings)f(within)
+g(a)i(binary)e(table)h(c)m(haracter)j(column)c(using)227
+3076 y(the)h(syn)m(tax)g(TF)m(ORM)g(=)g('rAw')f(where)g('r')h(is)f(the)
+h(total)g(n)m(um)m(b)s(er)e(of)i(c)m(haracters)h(\(=)f(the)g(width)e
+(of)227 3189 y(the)g(column\))f(and)f('w')i(is)e(the)i(width)e(of)h(a)h
+(unit)e(string)g(within)f(the)j(column.)64 b(Th)m(us)37
+b(if)g(the)i(column)227 3302 y(has)34 b(TF)m(ORM)h(=)f('60A12')j(then)d
+(this)f(means)h(that)h(eac)m(h)g(ro)m(w)g(of)f(the)h(table)f(con)m
+(tains)g(5)h(12-c)m(haracter)227 3415 y(substrings)22
+b(within)g(the)i(60-c)m(haracter)j(\014eld,)e(and)e(th)m(us)h(in)f
+(this)g(case)i(this)f(routine)f(will)e(return)i(t)m(yp)s(eco)s(de)227
+3528 y(=)36 b(TSTRING,)f(rep)s(eat)h(=)f(60,)j(and)d(width)f(=)i(12.)57
+b(The)35 b(n)m(um)m(b)s(er)g(of)h(substings)e(in)g(an)m(y)i(binary)e
+(table)227 3640 y(c)m(haracter)i(string)d(\014eld)f(can)i(b)s(e)g
+(calculated)g(b)m(y)f(\(rep)s(eat/width\).)52 b(A)34
+b(n)m(ull)d(p)s(oin)m(ter)i(ma)m(y)i(b)s(e)e(giv)m(en)h(for)227
+3753 y(an)m(y)d(of)g(the)f(output)g(parameters)h(that)g(are)g(not)f
+(needed.)227 3899 y(The)46 b(second)g(routine,)j(\014t)p
+1188 3899 28 4 v 33 w(get)p 1341 3899 V 34 w(eqcolt)m(yp)s(e)d(is)f
+(similar)f(except)j(that)f(in)f(the)h(case)i(of)e(scaled)g(in)m(teger)
+227 4012 y(columns)34 b(it)g(returns)g(the)h('equiv)-5
+b(alen)m(t')35 b(data)h(t)m(yp)s(e)f(that)h(is)e(needed)g(to)i(store)g
+(the)f(scaled)g(v)-5 b(alues,)36 b(and)227 4125 y(not)28
+b(necessarily)f(the)h(ph)m(ysical)e(data)i(t)m(yp)s(e)g(of)g(the)g
+(unscaled)e(v)-5 b(alues)28 b(as)f(stored)h(in)f(the)g(FITS)g(table.)40
+b(F)-8 b(or)227 4237 y(example)37 b(if)g(a)h('1I')g(column)e(in)g(a)i
+(binary)e(table)h(has)h(TSCALn)d(=)j(1)f(and)g(TZER)m(On)f(=)i(32768,)j
+(then)227 4350 y(this)28 b(column)f(e\013ectiv)m(ely)j(con)m(tains)e
+(unsigned)f(short)h(in)m(teger)h(v)-5 b(alues,)28 b(and)g(th)m(us)h
+(the)f(returned)g(v)-5 b(alue)28 b(of)227 4463 y(t)m(yp)s(eco)s(de)34
+b(will)c(b)s(e)j(TUSHOR)-8 b(T,)32 b(not)h(TSHOR)-8 b(T.)33
+b(Similarly)-8 b(,)30 b(if)i(a)i(column)e(has)g(TTYPEn)g(=)h('1I')h
+(and)227 4576 y(TSCALn)29 b(=)h(0.12,)i(then)e(the)h(returned)e(t)m(yp)
+s(eco)s(de)i(will)c(b)s(e)j(TFLO)m(A)-8 b(T.)95 4806
+y Fe(int)47 b(fits_get_coltype)d(/)j(ffgtcl)286 4919
+y(\(fitsfile)f(*fptr,)g(int)h(colnum,)e(>)j(int)f(*typecode,)e(long)h
+(*repeat,)334 5032 y(long)h(*width,)f(int)g(*status\))95
+5258 y(int)h(fits_get_eqcoltype)c(/)48 b(ffeqty)286 5371
+y(\(fitsfile)e(*fptr,)g(int)h(colnum,)e(>)j(int)f(*typecode,)e(long)h
+(*repeat,)334 5484 y(long)h(*width,)f(int)g(*status\))0
+5714 y Fi(4)81 b Fj(Return)29 b(the)h(displa)m(y)e(width)g(of)i(a)h
+(column.)39 b(This)28 b(is)h(the)h(length)g(of)g(the)g(string)f(that)i
+(will)c(b)s(e)i(returned)g(b)m(y)p eop
+%%Page: 48 56
+48 55 bop 0 299 a Fj(48)1379 b Fh(CHAPTER)30 b(5.)71
+b(BASIC)30 b(CFITSIO)f(INTERF)-10 b(A)m(CE)30 b(R)m(OUTINES)227
+555 y Fj(the)k(\014ts)p 514 555 28 4 v 32 w(read)p 718
+555 V 33 w(col)f(routine)f(when)g(reading)g(the)i(column)d(as)j(a)f
+(formatted)h(string.)48 b(The)32 b(displa)m(y)g(width)227
+668 y(is)c(determined)g(b)m(y)h(the)g(TDISPn)f(k)m(eyw)m(ord,)i(if)e
+(presen)m(t,)i(otherwise)e(b)m(y)h(the)g(data)h(t)m(yp)s(e)f(of)h(the)f
+(column.)95 1039 y Fe(int)47 b(fits_get_col_display_width)41
+b(/)47 b(ffgcdw)286 1152 y(\(fitsfile)f(*fptr,)g(int)h(colnum,)e(>)j
+(int)f(*dispwidth,)e(int)h(*status\))0 1410 y Fi(5)81
+b Fj(Return)27 b(the)i(n)m(um)m(b)s(er)e(of)i(and)e(size)i(of)f(the)h
+(dimensions)d(of)i(a)h(table)f(column)g(in)f(a)h(binary)f(table.)40
+b(Normally)227 1523 y(this)27 b(information)g(is)g(giv)m(en)h(b)m(y)g
+(the)h(TDIMn)f(k)m(eyw)m(ord,)h(but)e(if)h(this)f(k)m(eyw)m(ord)h(is)f
+(not)i(presen)m(t)f(then)g(this)227 1635 y(routine)i(returns)f(naxis)g
+(=)h(1)h(and)f(naxes[0])h(equal)f(to)h(the)g(rep)s(eat)f(coun)m(t)h(in)
+e(the)i(TF)m(ORM)g(k)m(eyw)m(ord.)95 1893 y Fe(int)47
+b(fits_read_tdim)d(/)k(ffgtdm)286 2006 y(\(fitsfile)e(*fptr,)g(int)h
+(colnum,)e(int)i(maxdim,)f(>)i(int)f(*naxis,)334 2119
+y(long)g(*naxes,)f(int)g(*status\))0 2377 y Fi(6)81 b
+Fj(Deco)s(de)33 b(the)g(input)e(TDIMn)i(k)m(eyw)m(ord)g(string)e
+(\(e.g.)50 b('\(100,200\)'\))37 b(and)32 b(return)g(the)h(n)m(um)m(b)s
+(er)e(of)i(and)f(size)227 2490 y(of)c(the)g(dimensions)d(of)j(a)g
+(binary)e(table)h(column.)39 b(If)27 b(the)h(input)e(tdimstr)g(c)m
+(haracter)j(string)e(is)g(n)m(ull,)f(then)227 2603 y(this)e(routine)f
+(returns)g(naxis)g(=)i(1)f(and)g(naxes[0])i(equal)d(to)j(the)e(rep)s
+(eat)h(coun)m(t)g(in)e(the)h(TF)m(ORM)h(k)m(eyw)m(ord.)227
+2716 y(This)k(routine)g(is)h(called)f(b)m(y)h(\014ts)p
+1350 2716 V 33 w(read)p 1555 2716 V 33 w(tdim.)95 2973
+y Fe(int)47 b(fits_decode_tdim)d(/)j(ffdtdm)286 3086
+y(\(fitsfile)f(*fptr,)g(char)g(*tdimstr,)g(int)h(colnum,)e(int)i
+(maxdim,)f(>)i(int)e(*naxis,)334 3199 y(long)h(*naxes,)f(int)g
+(*status\))0 3457 y Fi(7)81 b Fj(W)-8 b(rite)22 b(a)h(TDIMn)f(k)m(eyw)m
+(ord)h(whose)f(v)-5 b(alue)22 b(has)h(the)f(form)g('\(l,m,n...\)')39
+b(where)22 b(l,)h(m,)h(n...)38 b(are)23 b(the)g(dimensions)227
+3570 y(of)31 b(a)g(m)m(ultidimension)26 b(arra)m(y)31
+b(column)e(in)g(a)i(binary)d(table.)95 3828 y Fe(int)47
+b(fits_write_tdim)d(/)j(ffptdm)286 3941 y(\(fitsfile)f(*fptr,)g(int)h
+(colnum,)e(int)i(naxis,)f(long)h(*naxes,)f(>)h(int)g(*status\))0
+4231 y Fd(5.7.3)112 b(Routines)37 b(to)g(Edit)f(Ro)m(ws)h(or)g(Columns)
+0 4440 y Fi(1)81 b Fj(Insert)22 b(or)h(delete)g(ro)m(ws)f(in)g(an)h
+(ASCI)s(I)e(or)i(binary)e(table.)38 b(When)22 b(inserting)f(ro)m(ws)i
+(all)f(the)h(ro)m(ws)g(follo)m(wing)e(ro)m(w)227 4553
+y(FR)m(O)m(W)29 b(are)f(shifted)f(do)m(wn)g(b)m(y)h(NR)m(O)m(WS)g(ro)m
+(ws;)h(if)e(FR)m(O)m(W)i(=)e(0)h(then)f(the)h(blank)f(ro)m(ws)h(are)g
+(inserted)e(at)227 4666 y(the)h(b)s(eginning)d(of)j(the)f(table.)40
+b(The)26 b(\014rst)g(delete)h(routine)e(deletes)i(NR)m(O)m(WS)g
+(consecutiv)m(e)h(ro)m(ws)e(starting)227 4779 y(with)i(ro)m(w)i(FIRSTR)
+m(O)m(W.)g(The)f(second)g(delete)h(routine)e(tak)m(es)j(an)e(input)f
+(string)g(that)i(lists)e(the)i(ro)m(ws)f(or)227 4891
+y(ro)m(w)24 b(ranges)f(\(e.g.,)k('5-10,12,20-30'\),)k(whereas)23
+b(the)h(third)d(delete)j(routine)e(tak)m(es)j(an)e(input)f(in)m(teger)h
+(arra)m(y)227 5004 y(that)35 b(sp)s(eci\014es)e(eac)m(h)i(individual)30
+b(ro)m(w)k(to)h(b)s(e)f(deleted.)52 b(In)34 b(b)s(oth)f(latter)i
+(cases,)h(the)e(input)f(list)g(of)h(ro)m(ws)227 5117
+y(to)e(delete)f(m)m(ust)f(b)s(e)g(sorted)h(in)e(ascending)h(order.)41
+b(These)31 b(routines)e(up)s(date)h(the)h(NAXIS2)g(k)m(eyw)m(ord)g(to)
+227 5230 y(re\015ect)g(the)g(new)f(n)m(um)m(b)s(er)f(of)h(ro)m(ws)h(in)
+e(the)h(table.)95 5488 y Fe(int)47 b(fits_insert_rows)d(/)j(ffirow)286
+5601 y(\(fitsfile)f(*fptr,)g(long)g(firstrow,)g(long)g(nrows,)g(>)i
+(int)f(*status\))p eop
+%%Page: 49 57
+49 56 bop 0 299 a Fh(5.7.)72 b(ASCI)s(I)29 b(AND)i(BINAR)-8
+b(Y)31 b(T)-8 b(ABLE)31 b(R)m(OUTINES)1864 b Fj(49)95
+555 y Fe(int)47 b(fits_delete_rows)d(/)j(ffdrow)286 668
+y(\(fitsfile)f(*fptr,)g(long)g(firstrow,)g(long)g(nrows,)g(>)i(int)f
+(*status\))95 894 y(int)g(fits_delete_rowrange)c(/)k(ffdrrg)286
+1007 y(\(fitsfile)f(*fptr,)g(char)g(*rangelist,)f(>)j(int)e(*status\))
+95 1233 y(int)h(fits_delete_rowlist)c(/)k(ffdrws)286
+1346 y(\(fitsfile)f(*fptr,)g(long)g(*rowlist,)g(long)g(nrows,)g(>)i
+(int)f(*status\))0 1600 y Fi(2)81 b Fj(Insert)36 b(or)h(delete)h
+(column\(s\))e(in)g(an)h(ASCI)s(I)f(or)h(binary)e(table.)61
+b(When)37 b(inserting,)g(COLNUM)g(sp)s(eci\014es)227
+1713 y(the)28 b(column)f(n)m(um)m(b)s(er)g(that)h(the)g(\(\014rst\))g
+(new)f(column)g(should)f(o)s(ccup)m(y)i(in)f(the)h(table.)40
+b(NCOLS)26 b(sp)s(eci\014es)227 1826 y(ho)m(w)35 b(man)m(y)g(columns)e
+(are)i(to)g(b)s(e)f(inserted.)52 b(An)m(y)35 b(existing)f(columns)f
+(from)h(this)g(p)s(osition)e(and)i(higher)227 1939 y(are)c(shifted)e(o)
+m(v)m(er)i(to)g(allo)m(w)e(ro)s(om)h(for)g(the)h(new)e(column\(s\).)40
+b(The)29 b(index)e(n)m(um)m(b)s(er)h(on)h(all)f(the)h(follo)m(wing)227
+2051 y(k)m(eyw)m(ords)34 b(will)c(b)s(e)j(incremen)m(ted)g(or)g
+(decremen)m(ted)h(if)e(necessary)i(to)g(re\015ect)g(the)f(new)g(p)s
+(osition)e(of)j(the)227 2164 y(column\(s\))25 b(in)f(the)i(table:)38
+b(TBCOLn,)26 b(TF)m(ORMn,)h(TTYPEn,)e(TUNITn,)h(TNULLn,)g(TSCALn,)f
+(TZE-)227 2277 y(R)m(On,)43 b(TDISPn,)g(TDIMn,)g(TLMINn,)g(TLMAXn,)g
+(TDMINn,)g(TDMAXn,)h(TCTYPn,)e(TCRPXn,)227 2390 y(TCR)-10
+b(VLn,)29 b(TCDL)-8 b(Tn,)30 b(TCR)m(OTn,)f(and)h(TCUNIn.)95
+2644 y Fe(int)47 b(fits_insert_col)d(/)j(fficol)286 2757
+y(\(fitsfile)f(*fptr,)g(int)h(colnum,)e(char)i(*ttype,)f(char)h
+(*tform,)334 2870 y(>)h(int)e(*status\))95 3096 y(int)h
+(fits_insert_cols)d(/)j(fficls)286 3209 y(\(fitsfile)f(*fptr,)g(int)h
+(colnum,)e(int)i(ncols,)f(char)h(**ttype,)334 3322 y(char)g(**tform,)e
+(>)j(int)f(*status\))95 3548 y(int)g(fits_delete_col)d(/)j
+(ffdcol\(fitsfile)d(*fptr,)i(int)h(colnum,)f(>)h(int)g(*status\))0
+3802 y Fi(3)81 b Fj(Cop)m(y)32 b(a)h(column)f(from)g(one)h(HDU)g(to)h
+(another)e(\(or)h(to)h(the)f(same)g(HDU\).)h(If)e(create)p
+3129 3802 28 4 v 34 w(col)h(=)f(TR)m(UE,)h(then)227 3915
+y(a)40 b(new)e(column)g(will)e(b)s(e)j(inserted)f(in)f(the)i(output)g
+(table,)i(at)f(p)s(osition)d(`outcolumn',)k(otherwise)e(the)227
+4028 y(existing)e(output)h(column)e(will)g(b)s(e)h(o)m(v)m(erwritten)h
+(\(in)f(whic)m(h)g(case)i(it)e(m)m(ust)h(ha)m(v)m(e)h(a)f(compatible)f
+(data)227 4141 y(t)m(yp)s(e\).)k(If)29 b(outcoln)m(um)g(is)f(greater)j
+(than)e(the)h(n)m(um)m(b)s(er)e(of)h(column)f(in)g(the)i(table,)g(then)
+f(the)g(new)g(column)227 4254 y(will)g(b)s(e)i(app)s(ended)f(to)j(the)f
+(end)f(of)g(the)h(table.)45 b(Note)33 b(that)f(the)g(\014rst)f(column)f
+(in)h(a)h(table)f(is)g(at)i(coln)m(um)227 4366 y(=)j(1.)58
+b(The)36 b(standard)f(indexed)f(k)m(eyw)m(ords)j(that)f(related)g(to)h
+(the)f(column)f(\(e.g.,)k(TDISPn,)e(TUNITn,)227 4479
+y(TCRPXn,)30 b(TCDL)-8 b(Tn,)29 b(etc.\))43 b(will)27
+b(also)k(b)s(e)e(copied.)95 4734 y Fe(int)47 b(fits_copy_col)e(/)i
+(ffcpcl)286 4846 y(\(fitsfile)f(*infptr,)f(fitsfile)h(*outfptr,)f(int)i
+(incolnum,)e(int)i(outcolnum,)334 4959 y(int)g(create_col,)e(>)i(int)g
+(*status\);)0 5214 y Fi(4)81 b Fj(Mo)s(dify)36 b(the)h(v)m(ector)i
+(length)e(of)g(a)h(binary)d(table)i(column)f(\(e.g.,)41
+b(c)m(hange)e(a)e(column)f(from)h(TF)m(ORMn)g(=)227 5327
+y('1E')31 b(to)h('20E'\).)g(The)e(v)m(ector)i(length)d(ma)m(y)i(b)s(e)f
+(increased)g(or)g(decreased)h(from)f(the)g(curren)m(t)h(v)-5
+b(alue.)95 5581 y Fe(int)47 b(fits_modify_vector_len)42
+b(/)48 b(ffmvec)286 5694 y(\(fitsfile)e(*fptr,)g(int)h(colnum,)e(long)i
+(newveclen,)e(>)j(int)e(*status\))p eop
+%%Page: 50 58
+50 57 bop 0 299 a Fj(50)1379 b Fh(CHAPTER)30 b(5.)71
+b(BASIC)30 b(CFITSIO)f(INTERF)-10 b(A)m(CE)30 b(R)m(OUTINES)0
+555 y Fd(5.7.4)112 b(Read)38 b(and)h(W)-9 b(rite)35 b(Column)i(Data)g
+(Routines)0 775 y Fj(The)e(follo)m(wing)e(routines)i(write)f(or)h(read)
+g(data)h(v)-5 b(alues)35 b(in)f(the)h(curren)m(t)g(ASCI)s(I)f(or)h
+(binary)f(table)h(extension.)0 888 y(If)e(a)g(write)f(op)s(eration)h
+(extends)g(b)s(ey)m(ond)f(the)h(curren)m(t)g(size)g(of)g(the)g(table,)h
+(then)f(the)g(n)m(um)m(b)s(er)f(of)h(ro)m(ws)g(in)f(the)0
+1001 y(table)i(will)e(automatically)i(b)s(e)f(increased)h(and)f(the)i
+(NAXIS2)f(k)m(eyw)m(ord)h(v)-5 b(alue)34 b(will)d(b)s(e)j(up)s(dated.)
+51 b(A)m(ttempts)0 1114 y(to)31 b(read)f(b)s(ey)m(ond)g(the)h(end)e(of)
+i(the)f(table)h(will)c(result)j(in)f(an)h(error.)0 1274
+y(Automatic)c(data)f(t)m(yp)s(e)g(con)m(v)m(ersion)g(is)f(p)s(erformed)
+g(for)g(n)m(umerical)g(data)h(t)m(yp)s(es)g(\(only\))g(if)f(the)h(data)
+h(t)m(yp)s(e)f(of)g(the)0 1387 y(column)f(\(de\014ned)h(b)m(y)g(the)h
+(TF)m(ORMn)f(k)m(eyw)m(ord\))h(di\013ers)e(from)h(the)h(data)g(t)m(yp)s
+(e)f(of)h(the)f(calling)f(routine.)38 b(ASCI)s(I)0 1500
+y(and)20 b(binary)e(tables)i(supp)s(ort)f(the)i(follo)m(wing)d(data)j
+(t)m(yp)s(e)g(v)-5 b(alues:)35 b(TSTRING,)20 b(TBYTE,)g(TSBYTE,)g
+(TSHOR)-8 b(T,)0 1613 y(TUSHOR)g(T,)22 b(TINT,)g(TUINT,)f(TLONG,)i
+(TLONGLONG,)f(TULONG,)g(TFLO)m(A)-8 b(T,)23 b(or)f(TDOUBLE.)h(Binary)0
+1726 y(tables)37 b(also)g(supp)s(ort)e(TLOGICAL)h(\(in)m(ternally)g
+(mapp)s(ed)g(to)h(the)h(`c)m(har')g(data)g(t)m(yp)s(e\),)h(TCOMPLEX,)e
+(and)0 1839 y(TDBLCOMPLEX.)0 1999 y(Note)25 b(that)g(within)c(the)j
+(con)m(text)i(of)e(these)g(routines,)h(the)f(TSTRING)f(data)h(t)m(yp)s
+(e)g(corresp)s(onds)f(to)h(a)h(C)e('c)m(har**')0 2112
+y(data)35 b(t)m(yp)s(e,)h(i.e.,)g(a)f(p)s(oin)m(ter)e(to)j(an)e(arra)m
+(y)h(of)g(p)s(oin)m(ters)e(to)i(an)g(arra)m(y)g(of)g(c)m(haracters.)54
+b(This)33 b(is)g(di\013eren)m(t)h(from)0 2225 y(the)e(k)m(eyw)m(ord)h
+(reading)e(and)g(writing)f(routines)h(where)h(TSTRING)f(corresp)s(onds)
+g(to)h(a)h(C)e('c)m(har*')j(data)f(t)m(yp)s(e,)0 2338
+y(i.e.,)f(a)f(single)f(p)s(oin)m(ter)g(to)i(an)f(arra)m(y)g(of)g(c)m
+(haracters.)45 b(When)30 b(reading)h(strings)e(from)i(a)g(table,)h(the)
+f(c)m(har)h(arra)m(ys)0 2451 y(ob)m(viously)d(m)m(ust)h(ha)m(v)m(e)i(b)
+s(een)e(allo)s(cated)g(long)g(enough)g(to)h(hold)e(the)i(whole)e(FITS)h
+(table)g(string.)0 2611 y(Numerical)h(data)i(v)-5 b(alues)32
+b(are)h(automatically)g(scaled)f(b)m(y)g(the)h(TSCALn)e(and)h(TZER)m
+(On)f(k)m(eyw)m(ord)i(v)-5 b(alues)32 b(\(if)0 2724 y(they)f(exist\).)0
+2884 y(In)25 b(the)g(case)i(of)e(binary)f(tables)h(with)f(v)m(ector)j
+(elemen)m(ts,)g(the)f('felem')f(parameter)h(de\014nes)f(the)g(starting)
+g(elemen)m(t)0 2997 y(\(b)s(eginning)g(with)h(1,)i(not)g(0\))g(within)d
+(the)i(cell)g(\(a)h(cell)e(is)g(de\014ned)g(as)i(the)f(in)m(tersection)
+g(of)h(a)f(ro)m(w)h(and)e(a)i(column)0 3110 y(and)e(ma)m(y)h(con)m
+(tain)g(a)h(single)d(v)-5 b(alue)26 b(or)h(a)g(v)m(ector)h(of)f(v)-5
+b(alues\).)39 b(The)26 b(felem)h(parameter)g(is)f(ignored)f(when)h
+(dealing)0 3223 y(with)33 b(ASCI)s(I)f(tables.)51 b(Similarly)-8
+b(,)32 b(in)g(the)j(case)f(of)h(binary)d(tables)h(the)i('nelemen)m(ts')
+f(parameter)g(sp)s(eci\014es)f(the)0 3336 y(total)27
+b(n)m(um)m(b)s(er)e(of)h(v)m(ector)i(v)-5 b(alues)26
+b(to)h(b)s(e)e(read)h(or)h(written)e(\(con)m(tin)m(uing)h(on)g
+(subsequen)m(t)f(ro)m(ws)i(if)e(required\))g(and)0 3448
+y(not)31 b(the)f(n)m(um)m(b)s(er)f(of)i(table)f(cells.)0
+3714 y Fi(1)81 b Fj(W)-8 b(rite)30 b(elemen)m(ts)h(in)m(to)f(an)h(ASCI)
+s(I)e(or)h(binary)e(table)j(column.)0 3980 y(The)38 b(\014rst)f
+(routine)g(simply)f(writes)h(the)h(arra)m(y)h(of)f(v)-5
+b(alues)38 b(to)h(the)f(FITS)g(\014le)f(\(doing)g(data)i(t)m(yp)s(e)g
+(con)m(v)m(ersion)0 4093 y(if)g(necessary\))i(whereas)f(the)h(second)f
+(routine)g(will)d(substitute)j(the)g(appropriate)f(FITS)h(n)m(ull)e(v)
+-5 b(alue)40 b(for)g(all)0 4206 y(elemen)m(ts)33 b(whic)m(h)f(are)h
+(equal)g(to)g(the)g(input)e(v)-5 b(alue)33 b(of)g(n)m(ulv)-5
+b(al)31 b(\(note)j(that)f(this)f(parameter)h(giv)m(es)h(the)f(address)0
+4319 y(of)40 b(n)m(ulv)-5 b(al,)42 b(not)e(the)g(n)m(ull)e(v)-5
+b(alue)40 b(itself)7 b(\).)70 b(F)-8 b(or)40 b(in)m(teger)h(columns)e
+(the)h(FITS)g(n)m(ull)e(v)-5 b(alue)39 b(is)h(de\014ned)f(b)m(y)h(the)0
+4432 y(TNULLn)32 b(k)m(eyw)m(ord)i(\(an)g(error)e(is)h(returned)f(if)g
+(the)i(k)m(eyw)m(ord)f(do)s(esn't)g(exist\).)50 b(F)-8
+b(or)34 b(\015oating)f(p)s(oin)m(t)f(columns)0 4545 y(the)i(sp)s(ecial)
+f(IEEE)h(NaN)h(\(Not-a-Num)m(b)s(er\))h(v)-5 b(alue)34
+b(will)d(b)s(e)j(written)f(in)m(to)i(the)f(FITS)g(\014le.)51
+b(If)34 b(a)h(n)m(ull)d(p)s(oin)m(ter)0 4658 y(is)g(en)m(tered)h(for)g
+(n)m(ulv)-5 b(al,)32 b(then)h(the)g(n)m(ull)e(v)-5 b(alue)32
+b(is)g(ignored)g(and)h(this)f(routine)f(b)s(eha)m(v)m(es)j(the)f(same)g
+(as)h(the)f(\014rst)0 4771 y(routine.)39 b(The)26 b(second)i(routine)e
+(m)m(ust)h(not)h(b)s(e)e(used)h(to)h(write)e(to)i(v)-5
+b(ariable)26 b(length)h(arra)m(y)h(columns.)38 b(The)27
+b(third)0 4883 y(routine)i(simply)f(writes)i(unde\014ned)e(pixel)h(v)-5
+b(alues)29 b(to)i(the)g(column.)95 5149 y Fe(int)47 b(fits_write_col)d
+(/)k(ffpcl)286 5262 y(\(fitsfile)e(*fptr,)g(int)h(datatype,)e(int)i
+(colnum,)f(long)g(firstrow,)334 5375 y(long)h(firstelem,)e(long)h
+(nelements,)f(DTYPE)i(*array,)f(>)h(int)g(*status\))95
+5601 y(int)g(fits_write_colnull)c(/)48 b(ffpcn)286 5714
+y(\(fitsfile)e(*fptr,)g(int)h(datatype,)e(int)i(colnum,)f(long)g
+(firstrow,)p eop
+%%Page: 51 59
+51 58 bop 0 299 a Fh(5.7.)72 b(ASCI)s(I)29 b(AND)i(BINAR)-8
+b(Y)31 b(T)-8 b(ABLE)31 b(R)m(OUTINES)1864 b Fj(51)286
+555 y Fe(long)47 b(firstelem,)e(long)i(nelements,)e(DTYPE)h(*array,)g
+(DTYPE)g(*nulval,)286 668 y(>)i(int)f(*status\))143 894
+y(int)g(fits_write_col_null)c(/)k(ffpclu)334 1007 y(\(fitsfile)e
+(*fptr,)h(int)h(colnum,)f(long)h(firstrow,)e(long)i(firstelem,)382
+1120 y(long)f(nelements,)f(>)j(int)f(*status\))0 1375
+y Fi(2)81 b Fj(Read)33 b(elemen)m(ts)h(from)f(an)g(ASCI)s(I)f(or)i
+(binary)d(table)i(column.)49 b(The)33 b(data)h(t)m(yp)s(e)g(parameter)g
+(sp)s(eci\014es)e(the)227 1488 y(data)c(t)m(yp)s(e)g(of)g(the)f(`n)m
+(ulv)-5 b(al')27 b(and)g(`arra)m(y')h(p)s(oin)m(ters;)g(Unde\014ned)d
+(arra)m(y)j(elemen)m(ts)g(will)d(b)s(e)i(returned)f(with)227
+1601 y(a)k(v)-5 b(alue)29 b(=)f(*n)m(ullv)-5 b(al,)28
+b(\(note)i(that)g(this)e(parameter)i(giv)m(es)f(the)h(address)e(of)h
+(the)h(n)m(ull)d(v)-5 b(alue,)29 b(not)h(the)f(n)m(ull)227
+1714 y(v)-5 b(alue)30 b(itself)7 b(\))30 b(unless)f(n)m(ulv)-5
+b(al)30 b(=)g(0)h(or)g(*n)m(ulv)-5 b(al)29 b(=)i(0,)g(in)e(whic)m(h)h
+(case)i(no)e(c)m(hec)m(king)i(for)e(unde\014ned)f(pixels)227
+1827 y(will)i(b)s(e)i(p)s(erformed.)48 b(The)33 b(second)g(routine)g
+(is)f(similar)f(except)j(that)g(an)m(y)g(unde\014ned)d(pixels)h(will)f
+(ha)m(v)m(e)227 1940 y(the)g(corresp)s(onding)d(n)m(ullarra)m(y)h
+(elemen)m(t)i(set)g(equal)f(to)h(TR)m(UE)f(\(=)h(1\).)227
+2089 y(An)m(y)c(column,)f(regardless)f(of)h(it's)g(in)m(trinsic)e(data)
+j(t)m(yp)s(e,)g(ma)m(y)g(b)s(e)e(read)i(as)f(a)g(string.)39
+b(It)26 b(should)e(b)s(e)i(noted)227 2202 y(ho)m(w)m(ev)m(er)32
+b(that)f(reading)e(a)i(n)m(umeric)e(column)g(as)i(a)g(string)e(is)g(10)
+j(-)e(100)i(times)e(slo)m(w)m(er)g(than)g(reading)g(the)227
+2315 y(same)22 b(column)f(as)g(a)h(n)m(um)m(b)s(er)e(due)h(to)i(the)e
+(large)h(o)m(v)m(erhead)h(in)d(constructing)h(the)h(formatted)g
+(strings.)36 b(The)227 2428 y(displa)m(y)24 b(format)i(of)f(the)h
+(returned)e(strings)g(will)f(b)s(e)i(determined)f(b)m(y)h(the)h(TDISPn)
+e(k)m(eyw)m(ord,)j(if)d(it)h(exists,)227 2541 y(otherwise)31
+b(b)m(y)g(the)g(data)h(t)m(yp)s(e)f(of)g(the)g(column.)42
+b(The)30 b(length)h(of)g(the)g(returned)f(strings)g(\(not)h(including)
+227 2654 y(the)26 b(n)m(ull)d(terminating)i(c)m(haracter\))i(can)f(b)s
+(e)f(determined)f(with)g(the)i(\014ts)p 2703 2654 28
+4 v 32 w(get)p 2855 2654 V 34 w(col)p 3000 2654 V 33
+w(displa)m(y)p 3313 2654 V 31 w(width)e(routine.)227
+2767 y(The)30 b(follo)m(wing)f(TDISPn)g(displa)m(y)g(formats)h(are)h
+(curren)m(tly)e(supp)s(orted:)418 3011 y Fe(Iw.m)142
+b(Integer)418 3124 y(Ow.m)g(Octal)47 b(integer)418 3237
+y(Zw.m)142 b(Hexadecimal)45 b(integer)418 3350 y(Fw.d)142
+b(Fixed)47 b(floating)e(point)418 3463 y(Ew.d)142 b(Exponential)45
+b(floating)h(point)418 3576 y(Dw.d)142 b(Exponential)45
+b(floating)h(point)418 3689 y(Gw.d)142 b(General;)46
+b(uses)g(Fw.d)h(if)g(significance)e(not)i(lost,)f(else)h(Ew.d)227
+3934 y Fj(where)24 b(w)h(is)e(the)i(width)e(in)g(c)m(haracters)j(of)f
+(the)g(displa)m(y)m(ed)e(v)-5 b(alues,)26 b(m)e(is)g(the)g(minim)m(um)e
+(n)m(um)m(b)s(er)i(of)g(digits)227 4046 y(displa)m(y)m(ed,)j(and)g(d)g
+(is)g(the)g(n)m(um)m(b)s(er)g(of)g(digits)g(to)h(the)g(righ)m(t)f(of)g
+(the)h(decimal.)39 b(The)27 b(.m)g(\014eld)f(is)h(optional.)95
+4302 y Fe(int)47 b(fits_read_col)e(/)i(ffgcv)286 4415
+y(\(fitsfile)f(*fptr,)g(int)h(datatype,)e(int)i(colnum,)f(long)g
+(firstrow,)g(long)g(firstelem,)334 4528 y(long)h(nelements,)e(DTYPE)h
+(*nulval,)g(DTYPE)g(*array,)g(int)h(*anynul,)e(int)i(*status\))95
+4753 y(int)g(fits_read_colnull)c(/)48 b(ffgcf)286 4866
+y(\(fitsfile)e(*fptr,)g(int)h(datatype,)e(int)i(colnum,)f(long)g
+(firstrow,)g(long)g(firstelem,)286 4979 y(long)h(nelements,)e(DTYPE)h
+(*array,)g(char)h(*nullarray,)e(int)h(*anynul,)g(int)h(*status\))0
+5269 y Fd(5.7.5)112 b(Ro)m(w)37 b(Selection)f(and)j(Calculator)d
+(Routines)0 5488 y Fj(These)21 b(routines)e(all)h(parse)h(and)f(ev)-5
+b(aluate)22 b(an)e(input)f(string)h(con)m(taining)h(a)g(user)f
+(de\014ned)g(arithmetic)g(expression.)0 5601 y(The)29
+b(\014rst)f(3)i(routines)e(select)i(ro)m(ws)f(in)f(a)i(FITS)e(table,)i
+(based)f(on)g(whether)g(the)g(expression)f(ev)-5 b(aluates)30
+b(to)g(true)0 5714 y(\(not)e(equal)e(to)i(zero\))g(or)f(false)g
+(\(zero\).)41 b(The)27 b(other)g(routines)f(ev)-5 b(aluate)28
+b(the)f(expression)f(and)g(calculate)i(a)f(v)-5 b(alue)p
+eop
+%%Page: 52 60
+52 59 bop 0 299 a Fj(52)1379 b Fh(CHAPTER)30 b(5.)71
+b(BASIC)30 b(CFITSIO)f(INTERF)-10 b(A)m(CE)30 b(R)m(OUTINES)0
+555 y Fj(for)c(eac)m(h)i(ro)m(w)f(of)g(the)g(table.)39
+b(The)26 b(allo)m(w)m(ed)h(expression)e(syn)m(tax)j(is)d(describ)s(ed)g
+(in)g(the)i(ro)m(w)g(\014lter)f(section)g(in)g(the)0
+668 y(`Extended)32 b(File)f(Name)i(Syn)m(tax')g(c)m(hapter)g(of)f(this)
+f(do)s(cumen)m(t.)46 b(The)32 b(expression)f(ma)m(y)i(also)f(b)s(e)f
+(written)h(to)h(a)0 781 y(text)h(\014le,)g(and)f(the)h(name)f(of)h(the)
+f(\014le,)h(prep)s(ended)d(with)h(a)i('@')g(c)m(haracter)h(ma)m(y)f(b)s
+(e)f(supplied)d(for)j(the)h('expr')0 894 y(parameter)d(\(e.g.)42
+b('@\014lename.txt'\).)f(The)30 b(expression)f(in)g(the)h(\014le)g(can)
+g(b)s(e)g(arbitrarily)d(complex)j(and)g(extend)0 1007
+y(o)m(v)m(er)35 b(m)m(ultiple)d(lines)h(of)h(the)g(\014le.)52
+b(Lines)32 b(that)j(b)s(egin)e(with)g(2)h(slash)f(c)m(haracters)j
+(\('//'\))g(will)c(b)s(e)h(ignored)h(and)0 1120 y(ma)m(y)d(b)s(e)f
+(used)f(to)i(add)f(commen)m(ts)h(to)h(the)e(\014le.)0
+1342 y Fi(1)81 b Fj(Ev)-5 b(aluate)37 b(a)g(b)s(o)s(olean)f(expression)
+g(o)m(v)m(er)i(the)g(indicated)d(ro)m(ws,)k(returning)c(an)i(arra)m(y)h
+(of)f(\015ags)g(indicating)227 1455 y(whic)m(h)29 b(ro)m(ws)i(ev)-5
+b(aluated)30 b(to)h(TR)m(UE/F)-10 b(ALSE)95 1676 y Fe(int)47
+b(fits_find_rows)d(/)k(fffrow)286 1789 y(\(fitsfile)e(*fptr,)93
+b(char)47 b(*expr,)f(long)h(firstrow,)e(long)i(nrows,)286
+1902 y(>)h(long)e(*n_good_rows,)f(char)h(*row_status,)92
+b(int)47 b(*status\))0 2124 y Fi(2)81 b Fj(Find)28 b(the)j(\014rst)f
+(ro)m(w)g(whic)m(h)f(satis\014es)h(the)h(input)d(b)s(o)s(olean)h
+(expression)95 2346 y Fe(int)47 b(fits_find_first_row)c(/)k(ffffrw)286
+2459 y(\(fitsfile)f(*fptr,)93 b(char)47 b(*expr,)f(>)i(long)e(*rownum,)
+g(int)h(*status\))0 2681 y Fi(3)81 b Fj(Ev)-5 b(aluate)34
+b(an)g(expression)g(on)g(all)f(ro)m(ws)i(of)f(a)h(table.)53
+b(If)34 b(the)g(input)f(and)h(output)g(\014les)f(are)i(not)g(the)f
+(same,)227 2794 y(cop)m(y)39 b(the)f(TR)m(UE)g(ro)m(ws)h(to)f(the)h
+(output)e(\014le.)63 b(If)38 b(the)g(\014les)f(are)i(the)f(same,)j
+(delete)d(the)g(F)-10 b(ALSE)38 b(ro)m(ws)227 2907 y(\(preserv)m(e)31
+b(the)g(TR)m(UE)f(ro)m(ws\).)95 3129 y Fe(int)47 b(fits_select_rows)d
+(/)j(ffsrow)286 3242 y(\(fitsfile)f(*infptr,)f(fitsfile)h(*outfptr,)93
+b(char)46 b(*expr,)94 b(>)48 b(int)f(*status)e(\))0 3463
+y Fi(4)81 b Fj(Calculate)26 b(an)h(expression)e(for)i(the)f(indicated)g
+(ro)m(ws)g(of)h(a)g(table,)h(returning)d(the)i(results,)f(cast)i(as)f
+(datat)m(yp)s(e)227 3576 y(\(TSHOR)-8 b(T,)32 b(TDOUBLE,)h(etc\),)h(in)
+d(arra)m(y)-8 b(.)48 b(If)31 b(n)m(ulv)-5 b(al==NULL,)31
+b(UNDEFs)i(will)c(b)s(e)j(zero)s(ed)g(out.)47 b(F)-8
+b(or)227 3689 y(v)m(ector)37 b(results,)e(the)g(n)m(um)m(b)s(er)e(of)i
+(elemen)m(ts)h(returned)d(ma)m(y)j(b)s(e)e(less)g(than)h(nelemen)m(ts)f
+(if)g(nelemen)m(ts)h(is)227 3802 y(not)d(an)g(ev)m(en)h(m)m(ultiple)c
+(of)j(the)g(result)f(dimension.)42 b(Call)31 b(\014ts)p
+2392 3802 28 4 v 32 w(test)p 2570 3802 V 34 w(expr)g(to)h(obtain)g(the)
+g(dimensions)d(of)227 3915 y(the)i(results.)95 4137 y
+Fe(int)47 b(fits_calc_rows)d(/)k(ffcrow)286 4250 y(\(fitsfile)e(*fptr,)
+93 b(int)47 b(datatype,)f(char)g(*expr,)g(long)h(firstrow,)334
+4363 y(long)g(nelements,)e(void)h(*nulval,)g(>)h(void)g(*array,)94
+b(int)46 b(*anynul,)g(int)h(*status\))0 4585 y Fi(5)81
+b Fj(Ev)-5 b(aluate)32 b(an)h(expression)e(and)i(write)e(the)i(result)f
+(either)g(to)i(a)f(column)e(\(if)h(the)h(expression)e(is)h(a)h
+(function)227 4698 y(of)d(other)g(columns)f(in)f(the)i(table\))g(or)g
+(to)g(a)h(k)m(eyw)m(ord)f(\(if)f(the)h(expression)e(ev)-5
+b(aluates)31 b(to)f(a)g(constan)m(t)i(and)227 4811 y(is)e(not)g(a)h
+(function)e(of)i(other)f(columns)g(in)f(the)h(table\).)41
+b(In)30 b(the)h(former)e(case,)j(the)f(parName)f(parameter)227
+4924 y(is)39 b(the)h(name)f(of)h(the)g(column)e(\(whic)m(h)h(ma)m(y)h
+(or)f(ma)m(y)h(not)g(already)f(exist\))h(in)m(to)f(whic)m(h)g(to)h
+(write)f(the)227 5036 y(results,)e(and)g(parInfo)e(con)m(tains)i(an)g
+(optional)e(TF)m(ORM)i(k)m(eyw)m(ord)g(v)-5 b(alue)37
+b(if)e(a)i(new)f(column)g(is)f(b)s(eing)227 5149 y(created.)42
+b(If)28 b(a)h(TF)m(ORM)h(v)-5 b(alue)28 b(is)g(not)h(sp)s(eci\014ed)f
+(then)g(a)i(default)e(format)h(will)e(b)s(e)h(used,)h(dep)s(ending)d
+(on)227 5262 y(the)35 b(expression.)53 b(If)34 b(the)h(expression)e(ev)
+-5 b(aluates)36 b(to)f(a)g(constan)m(t,)i(then)e(the)g(result)e(will)f
+(b)s(e)i(written)g(to)227 5375 y(the)28 b(k)m(eyw)m(ord)g(name)f(giv)m
+(en)g(b)m(y)h(the)f(parName)h(parameter,)h(and)d(the)i(parInfo)e
+(parameter)i(ma)m(y)g(b)s(e)f(used)227 5488 y(to)k(supply)d(an)i
+(optional)g(commen)m(t)h(for)f(the)g(k)m(eyw)m(ord.)42
+b(If)29 b(the)i(k)m(eyw)m(ord)g(do)s(es)f(not)g(already)g(exist,)g
+(then)227 5601 y(the)g(name)f(of)h(the)g(k)m(eyw)m(ord)g(m)m(ust)f(b)s
+(e)g(preceded)g(with)f(a)i('#')f(c)m(haracter,)j(otherwise)d(the)g
+(result)g(will)e(b)s(e)227 5714 y(written)j(to)h(a)g(column)e(with)g
+(that)i(name.)p eop
+%%Page: 53 61
+53 60 bop 0 299 a Fh(5.8.)72 b(UTILITY)30 b(R)m(OUTINES)2693
+b Fj(53)95 555 y Fe(int)47 b(fits_calculator)d(/)j(ffcalc)286
+668 y(\(fitsfile)f(*infptr,)f(char)i(*expr,)f(fitsfile)f(*outfptr,)h
+(char)g(*parName,)334 781 y(char)h(*parInfo,)e(>)95 b(int)47
+b(*status\))0 1032 y Fi(6)81 b Fj(This)37 b(calculator)j(routine)f(is)f
+(similar)f(to)j(the)g(previous)e(routine,)j(except)g(that)f(the)g
+(expression)e(is)h(only)227 1145 y(ev)-5 b(aluated)41
+b(o)m(v)m(er)g(the)f(sp)s(eci\014ed)f(ro)m(w)h(ranges.)70
+b(nranges)39 b(sp)s(eci\014es)g(the)h(n)m(um)m(b)s(er)f(of)h(ro)m(w)h
+(ranges,)i(and)227 1258 y(\014rstro)m(w)30 b(and)g(lastro)m(w)g(giv)m
+(e)h(the)g(starting)f(and)g(ending)f(ro)m(w)h(n)m(um)m(b)s(er)f(of)i
+(eac)m(h)g(range.)95 1509 y Fe(int)47 b(fits_calculator_rng)c(/)k
+(ffcalc_rng)286 1622 y(\(fitsfile)f(*infptr,)f(char)i(*expr,)f
+(fitsfile)f(*outfptr,)h(char)g(*parName,)334 1735 y(char)h(*parInfo,)e
+(int)i(nranges,)e(long)i(*firstrow,)e(long)i(*lastrow)334
+1848 y(>)95 b(int)47 b(*status\))0 2099 y Fi(7)81 b Fj(Ev)-5
+b(aluate)30 b(the)h(giv)m(en)f(expression)f(and)h(return)f(information)
+g(on)h(the)h(result.)95 2350 y Fe(int)47 b(fits_test_expr)d(/)k(fftexp)
+286 2463 y(\(fitsfile)e(*fptr,)g(char)g(*expr,)g(>)i(int)f(*datatype,)e
+(long)h(*nelem,)g(int)h(*naxis,)334 2575 y(long)g(*naxes,)f(int)g
+(*status\))0 2908 y Ff(5.8)135 b(Utilit)l(y)47 b(Routines)0
+3161 y Fd(5.8.1)112 b(File)37 b(Chec)m(ksum)g(Routines)0
+3380 y Fj(The)c(follo)m(wing)e(routines)h(either)h(compute)g(or)h(v)-5
+b(alidate)32 b(the)i(c)m(hec)m(ksums)f(for)g(the)h(CHDU.)g(The)e(D)m(A)
+-8 b(T)g(ASUM)0 3493 y(k)m(eyw)m(ord)33 b(is)e(used)g(to)i(store)f(the)
+h(n)m(umerical)d(v)-5 b(alue)32 b(of)g(the)g(32-bit,)h(1's)g(complemen)
+m(t)f(c)m(hec)m(ksum)h(for)f(the)g(data)0 3606 y(unit)25
+b(alone.)39 b(If)25 b(there)h(is)g(no)f(data)i(unit)e(then)g(the)h(v)-5
+b(alue)26 b(is)f(set)h(to)h(zero.)40 b(The)26 b(n)m(umerical)e(v)-5
+b(alue)26 b(is)f(stored)h(as)g(an)0 3719 y(ASCI)s(I)20
+b(string)h(of)i(digits,)f(enclosed)g(in)e(quotes,)25
+b(b)s(ecause)d(the)g(v)-5 b(alue)22 b(ma)m(y)g(b)s(e)f(to)s(o)i(large)f
+(to)h(represen)m(t)f(as)g(a)h(32-bit)0 3832 y(signed)k(in)m(teger.)40
+b(The)27 b(CHECKSUM)g(k)m(eyw)m(ord)i(is)e(used)g(to)h(store)h(the)f
+(ASCI)s(I)e(enco)s(ded)i(COMPLEMENT)f(of)0 3945 y(the)f(c)m(hec)m(ksum)
+h(for)f(the)h(en)m(tire)f(HDU.)h(Storing)e(the)i(complemen)m(t,)g
+(rather)f(than)g(the)h(actual)f(c)m(hec)m(ksum,)i(forces)0
+4058 y(the)k(c)m(hec)m(ksum)h(for)f(the)h(whole)e(HDU)i(to)g(equal)f
+(zero.)47 b(If)31 b(the)i(\014le)e(has)h(b)s(een)f(mo)s(di\014ed)f
+(since)i(the)g(c)m(hec)m(ksums)0 4170 y(w)m(ere)39 b(computed,)i(then)e
+(the)g(HDU)g(c)m(hec)m(ksum)h(will)c(usually)g(not)j(equal)g(zero.)66
+b(These)39 b(c)m(hec)m(ksum)g(k)m(eyw)m(ord)0 4283 y(con)m(v)m(en)m
+(tions)33 b(are)g(based)f(on)g(a)g(pap)s(er)f(b)m(y)h(Rob)g(Seaman)g
+(published)d(in)i(the)h(pro)s(ceedings)f(of)h(the)h(AD)m(ASS)f(IV)0
+4396 y(conference)h(in)d(Baltimore)i(in)e(No)m(v)m(em)m(b)s(er)j(1994)h
+(and)d(a)h(later)g(revision)e(in)g(June)h(1995.)47 b(See)32
+b(App)s(endix)d(B)j(for)0 4509 y(the)f(de\014nition)d(of)i(the)h
+(parameters)f(used)g(in)f(these)i(routines.)0 4760 y
+Fi(1)81 b Fj(Compute)33 b(and)g(write)g(the)h(D)m(A)-8
+b(T)g(ASUM)35 b(and)e(CHECKSUM)g(k)m(eyw)m(ord)h(v)-5
+b(alues)33 b(for)g(the)h(CHDU)g(in)m(to)g(the)227 4873
+y(curren)m(t)e(header.)46 b(If)32 b(the)g(k)m(eyw)m(ords)h(already)f
+(exist,)g(their)g(v)-5 b(alues)31 b(will)f(b)s(e)h(up)s(dated)g(only)g
+(if)h(necessary)227 4986 y(\(i.e.,)f(if)f(the)g(\014le)g(has)g(b)s(een)
+f(mo)s(di\014ed)g(since)g(the)i(original)e(k)m(eyw)m(ord)h(v)-5
+b(alues)30 b(w)m(ere)h(computed\).)95 5237 y Fe(int)47
+b(fits_write_chksum)c(/)48 b(ffpcks)286 5350 y(\(fitsfile)e(*fptr,)g(>)
+h(int)g(*status\))0 5601 y Fi(2)81 b Fj(Up)s(date)28
+b(the)h(CHECKSUM)e(k)m(eyw)m(ord)i(v)-5 b(alue)28 b(in)f(the)i(CHDU,)g
+(assuming)e(that)i(the)f(D)m(A)-8 b(T)g(ASUM)30 b(k)m(eyw)m(ord)227
+5714 y(exists)35 b(and)g(already)g(has)g(the)h(correct)g(v)-5
+b(alue.)55 b(This)34 b(routine)g(calculates)i(the)g(new)f(c)m(hec)m
+(ksum)h(for)f(the)p eop
+%%Page: 54 62
+54 61 bop 0 299 a Fj(54)1379 b Fh(CHAPTER)30 b(5.)71
+b(BASIC)30 b(CFITSIO)f(INTERF)-10 b(A)m(CE)30 b(R)m(OUTINES)227
+555 y Fj(curren)m(t)40 b(header)g(unit,)i(adds)d(it)h(to)h(the)f(data)h
+(unit)e(c)m(hec)m(ksum,)44 b(enco)s(des)c(the)g(v)-5
+b(alue)40 b(in)m(to)g(an)g(ASCI)s(I)227 668 y(string,)30
+b(and)g(writes)f(the)i(string)e(to)i(the)g(CHECKSUM)e(k)m(eyw)m(ord.)95
+897 y Fe(int)47 b(fits_update_chksum)c(/)48 b(ffupck)286
+1010 y(\(fitsfile)e(*fptr,)g(>)h(int)g(*status\))0 1238
+y Fi(3)81 b Fj(V)-8 b(erify)34 b(the)g(CHDU)h(b)m(y)g(computing)e(the)i
+(c)m(hec)m(ksums)g(and)f(comparing)g(them)g(with)f(the)i(k)m(eyw)m
+(ords.)53 b(The)227 1351 y(data)34 b(unit)e(is)g(v)m(eri\014ed)g
+(correctly)h(if)f(the)i(computed)f(c)m(hec)m(ksum)g(equals)g(the)g(v)-5
+b(alue)33 b(of)g(the)g(D)m(A)-8 b(T)g(ASUM)227 1464 y(k)m(eyw)m(ord.)64
+b(The)37 b(c)m(hec)m(ksum)i(for)f(the)g(en)m(tire)f(HDU)i(\(header)f
+(plus)e(data)j(unit\))d(is)h(correct)i(if)e(it)h(equals)227
+1577 y(zero.)47 b(The)32 b(output)f(D)m(A)-8 b(T)g(A)m(OK)34
+b(and)d(HDUOK)i(parameters)f(in)f(this)g(routine)g(are)h(in)m(tegers)h
+(whic)m(h)e(will)227 1690 y(ha)m(v)m(e)36 b(a)f(v)-5
+b(alue)34 b(=)g(1)h(if)e(the)i(data)g(or)f(HDU)h(is)f(v)m(eri\014ed)f
+(correctly)-8 b(,)37 b(a)e(v)-5 b(alue)34 b(=)g(0)h(if)e(the)i(D)m(A)-8
+b(T)g(ASUM)36 b(or)227 1803 y(CHECKSUM)29 b(k)m(eyw)m(ord)g(is)g(not)g
+(presen)m(t,)h(or)f(v)-5 b(alue)29 b(=)g(-1)h(if)e(the)i(computed)f(c)m
+(hec)m(ksum)h(is)e(not)i(correct.)95 2144 y Fe(int)47
+b(fits_verify_chksum)c(/)48 b(ffvcks)286 2257 y(\(fitsfile)e(*fptr,)g
+(>)h(int)g(*dataok,)f(int)h(*hduok,)e(int)i(*status\))0
+2486 y Fi(4)81 b Fj(Compute)40 b(and)g(return)g(the)h(c)m(hec)m(ksum)g
+(v)-5 b(alues)40 b(for)h(the)g(CHDU)g(without)f(creating)h(or)g(mo)s
+(difying)d(the)227 2599 y(CHECKSUM)33 b(and)h(D)m(A)-8
+b(T)g(ASUM)35 b(k)m(eyw)m(ords.)52 b(This)32 b(routine)h(is)g(used)g
+(in)m(ternally)f(b)m(y)i(\013v)m(c)m(ks,)i(but)d(ma)m(y)227
+2711 y(b)s(e)d(useful)f(in)g(other)h(situations)f(as)i(w)m(ell.)95
+2940 y Fe(int)47 b(fits_get_chksum/)d(/ffgcks)286 3053
+y(\(fitsfile)i(*fptr,)g(>)h(unsigned)f(long)g(*datasum,)g(unsigned)f
+(long)i(*hdusum,)334 3166 y(int)g(*status\))0 3394 y
+Fi(5)81 b Fj(Enco)s(de)23 b(a)h(c)m(hec)m(ksum)g(v)-5
+b(alue)23 b(in)m(to)g(a)h(16-c)m(haracter)j(string.)37
+b(If)23 b(complm)g(is)f(non-zero)j(\(true\))f(then)f(the)h(32-bit)227
+3507 y(sum)30 b(v)-5 b(alue)30 b(will)d(b)s(e)j(complemen)m(ted)g(b)s
+(efore)g(enco)s(ding.)95 3736 y Fe(int)47 b(fits_encode_chksum)c(/)48
+b(ffesum)286 3849 y(\(unsigned)e(long)g(sum,)h(int)g(complm,)f(>)h
+(char)g(*ascii\);)0 4077 y Fi(6)81 b Fj(Deco)s(de)24
+b(a)f(16-c)m(haracter)j(c)m(hec)m(ksum)e(string)e(in)m(to)g(a)i
+(unsigned)d(long)h(v)-5 b(alue.)38 b(If)23 b(is)f(non-zero)h(\(true\).)
+39 b(then)23 b(the)227 4190 y(32-bit)32 b(sum)e(v)-5
+b(alue)31 b(will)e(b)s(e)i(complemen)m(ted)g(after)h(deco)s(ding.)43
+b(The)31 b(c)m(hec)m(ksum)h(v)-5 b(alue)31 b(is)g(also)g(returned)227
+4303 y(as)g(the)f(v)-5 b(alue)30 b(of)h(the)f(function.)95
+4532 y Fe(unsigned)46 b(long)h(fits_decode_chksum)42
+b(/)48 b(ffdsum)525 4645 y(\(char)e(*ascii,)g(int)h(complm,)f(>)h
+(unsigned)f(long)h(*sum\);)0 4930 y Fd(5.8.2)112 b(Date)38
+b(and)g(Time)e(Utilit)m(y)e(Routines)0 5149 y Fj(The)29
+b(follo)m(wing)f(routines)h(help)f(to)j(construct)f(or)f(parse)h(the)g
+(FITS)f(date/time)h(strings.)40 b(Starting)29 b(in)f(the)i(y)m(ear)0
+5262 y(2000,)k(the)d(FITS)g(D)m(A)-8 b(TE)32 b(k)m(eyw)m(ord)g(v)-5
+b(alues)30 b(\(and)i(the)f(v)-5 b(alues)31 b(of)g(other)h(`D)m(A)-8
+b(TE-')33 b(k)m(eyw)m(ords\))f(m)m(ust)f(ha)m(v)m(e)i(the)0
+5375 y(form)j('YYYY-MM-DD')k(\(date)e(only\))e(or)h
+('YYYY-MM-DDThh:mm:ss.ddd...')61 b(\(date)38 b(and)e(time\))g(where)0
+5488 y(the)30 b(n)m(um)m(b)s(er)f(of)i(decimal)e(places)h(in)f(the)h
+(seconds)g(v)-5 b(alue)30 b(is)f(optional.)40 b(These)30
+b(times)g(are)g(in)f(UTC.)h(The)g(older)0 5601 y('dd/mm/yy')d(date)g
+(format)g(ma)m(y)h(not)f(b)s(e)f(used)g(for)h(dates)h(after)f(01)h(Jan)
+m(uary)e(2000.)42 b(See)27 b(App)s(endix)d(B)j(for)g(the)0
+5714 y(de\014nition)h(of)j(the)f(parameters)h(used)e(in)g(these)i
+(routines.)p eop
+%%Page: 55 63
+55 62 bop 0 299 a Fh(5.8.)72 b(UTILITY)30 b(R)m(OUTINES)2693
+b Fj(55)0 555 y Fi(1)81 b Fj(Get)23 b(the)f(curren)m(t)f(system)i
+(date.)38 b(C)22 b(already)f(pro)m(vides)g(standard)g(library)f
+(routines)h(for)g(getting)i(the)f(curren)m(t)227 668
+y(date)k(and)e(time,)i(but)e(this)g(routine)g(is)g(pro)m(vided)g(for)g
+(compatibilit)m(y)g(with)f(the)i(F)-8 b(ortran)26 b(FITSIO)e(library)-8
+b(.)227 781 y(The)30 b(returned)f(y)m(ear)j(has)e(4)g(digits)f(\(1999,)
+k(2000,)g(etc.\))95 1026 y Fe(int)47 b(fits_get_system_date/ffgsd)o(t)
+286 1139 y(\()h(>)f(int)g(*day,)g(int)f(*month,)g(int)h(*year,)f(int)h
+(*status)f(\))0 1384 y Fi(2)81 b Fj(Get)34 b(the)g(curren)m(t)g(system)
+f(date)i(and)e(time)g(string)g(\('YYYY-MM-DDThh:mm:ss'\).)53
+b(The)33 b(time)h(will)d(b)s(e)227 1497 y(in)25 b(UTC/GMT)h(if)f(a)m(v)
+-5 b(ailable,)26 b(as)h(indicated)d(b)m(y)i(a)g(returned)f(timeref)g(v)
+-5 b(alue)26 b(=)f(0.)40 b(If)26 b(the)g(returned)e(v)-5
+b(alue)227 1610 y(of)31 b(timeref)f(=)h(1)g(then)f(this)g(indicates)f
+(that)j(it)e(w)m(as)h(not)g(p)s(ossible)d(to)j(con)m(v)m(ert)i(the)d
+(lo)s(cal)g(time)h(to)g(UTC,)227 1722 y(and)f(th)m(us)g(the)h(lo)s(cal)
+e(time)h(w)m(as)h(returned.)95 1967 y Fe(int)47 b
+(fits_get_system_time/ffgst)o(m)286 2080 y(\(>)h(char)e(*datestr,)f
+(int)95 b(*timeref,)45 b(int)i(*status\))0 2325 y Fi(3)81
+b Fj(Construct)26 b(a)i(date)g(string)e(from)h(the)g(input)e(date)j(v)
+-5 b(alues.)39 b(If)27 b(the)g(y)m(ear)h(is)f(b)s(et)m(w)m(een)g(1900)i
+(and)e(1998,)j(inclu-)227 2438 y(siv)m(e,)37 b(then)d(the)i(returned)d
+(date)j(string)e(will)e(ha)m(v)m(e)37 b(the)e(old)f(FITS)g(format)i
+(\('dd/mm/yy'\),)h(otherwise)227 2551 y(the)32 b(date)f(string)f(will)f
+(ha)m(v)m(e)j(the)g(new)e(FITS)h(format)g(\('YYYY-MM-DD'\).)36
+b(Use)31 b(\014ts)p 3229 2551 28 4 v 33 w(time2str)g(instead)227
+2664 y(to)g(alw)m(a)m(ys)g(return)f(a)g(date)h(string)f(using)f(the)h
+(new)g(FITS)g(format.)95 2909 y Fe(int)47 b(fits_date2str/ffdt2s)286
+3022 y(\(int)g(year,)f(int)h(month,)f(int)h(day,)g(>)g(char)g
+(*datestr,)e(int)i(*status\))0 3267 y Fi(4)81 b Fj(Construct)34
+b(a)i(new-format)f(date)h(+)f(time)g(string)f
+(\('YYYY-MM-DDThh:mm:ss.ddd...'\).)57 b(If)34 b(the)i(y)m(ear,)227
+3379 y(mon)m(th,)d(and)e(da)m(y)h(v)-5 b(alues)31 b(all)g(=)g(0)h(then)
+g(only)f(the)h(time)f(is)g(enco)s(ded)g(with)g(format)h
+('hh:mm:ss.ddd...'.)227 3492 y(The)j(decimals)f(parameter)i(sp)s
+(eci\014es)d(ho)m(w)j(man)m(y)f(decimal)f(places)h(of)g(fractional)g
+(seconds)g(to)h(include)227 3605 y(in)29 b(the)i(string.)40
+b(If)29 b(`decimals')h(is)g(negativ)m(e,)h(then)g(only)e(the)i(date)g
+(will)c(b)s(e)j(return)f(\('YYYY-MM-DD'\).)95 3850 y
+Fe(int)47 b(fits_time2str/fftm2s)286 3963 y(\(int)g(year,)f(int)h
+(month,)f(int)h(day,)g(int)g(hour,)f(int)h(minute,)f(double)g(second,)
+286 4076 y(int)h(decimals,)f(>)h(char)g(*datestr,)e(int)i(*status\))0
+4321 y Fi(5)81 b Fj(Return)44 b(the)g(date)i(as)f(read)f(from)h(the)g
+(input)d(string,)48 b(where)c(the)h(string)f(ma)m(y)h(b)s(e)f(in)g
+(either)g(the)h(old)227 4434 y(\('dd/mm/yy'\))29 b(or)f(new)f
+(\('YYYY-MM-DDThh:mm:ss')k(or)d('YYYY-MM-DD'\))j(FITS)d(format.)40
+b(Null)227 4547 y(p)s(oin)m(ters)30 b(ma)m(y)g(b)s(e)g(supplied)d(for)j
+(an)m(y)h(un)m(w)m(an)m(ted)g(output)f(date)h(parameters.)95
+4792 y Fe(int)47 b(fits_str2date/ffs2dt)286 4904 y(\(char)g(*datestr,)e
+(>)i(int)g(*year,)f(int)h(*month,)f(int)h(*day,)f(int)h(*status\))0
+5149 y Fi(6)81 b Fj(Return)30 b(the)h(date)h(and)f(time)g(as)g(read)g
+(from)g(the)h(input)d(string,)h(where)h(the)h(string)e(ma)m(y)i(b)s(e)e
+(in)g(either)h(the)227 5262 y(old)d(or)g(new)g(FITS)g(format.)40
+b(The)28 b(returned)f(hours,)h(min)m(utes,)g(and)g(seconds)g(v)-5
+b(alues)28 b(will)d(b)s(e)j(set)h(to)g(zero)227 5375
+y(if)j(the)i(input)d(string)h(do)s(es)h(not)h(include)d(the)i(time)g
+(\('dd/mm/yy')g(or)h('YYYY-MM-DD'\))j(.)c(Similarly)-8
+b(,)227 5488 y(the)36 b(returned)e(y)m(ear,)j(mon)m(th,)g(and)d(date)i
+(v)-5 b(alues)35 b(will)d(b)s(e)j(set)h(to)g(zero)g(if)e(the)h(date)h
+(is)e(not)i(included)c(in)227 5601 y(the)d(input)e(string)h
+(\('hh:mm:ss.ddd...'\).)40 b(Null)27 b(p)s(oin)m(ters)g(ma)m(y)j(b)s(e)
+e(supplied)d(for)k(an)m(y)g(un)m(w)m(an)m(ted)g(output)227
+5714 y(date)i(and)f(time)g(parameters.)p eop
+%%Page: 56 64
+56 63 bop 0 299 a Fj(56)1379 b Fh(CHAPTER)30 b(5.)71
+b(BASIC)30 b(CFITSIO)f(INTERF)-10 b(A)m(CE)30 b(R)m(OUTINES)95
+555 y Fe(int)47 b(fits_str2time/ffs2tm)286 668 y(\(char)g(*datestr,)e
+(>)i(int)g(*year,)f(int)h(*month,)f(int)h(*day,)f(int)h(*hour,)286
+781 y(int)g(*minute,)f(double)g(*second,)f(int)i(*status\))0
+1068 y Fd(5.8.3)112 b(General)38 b(Utilit)m(y)c(Routines)0
+1286 y Fj(The)c(follo)m(wing)f(utilit)m(y)f(routines)i(ma)m(y)h(b)s(e)e
+(useful)g(for)h(certain)g(applications.)0 1520 y Fi(1)81
+b Fj(Return)30 b(the)h(revision)e(n)m(um)m(b)s(er)h(of)h(the)g(CFITSIO)
+f(library)-8 b(.)40 b(The)31 b(revision)e(n)m(um)m(b)s(er)h(will)e(b)s
+(e)i(incremen)m(ted)227 1633 y(with)f(eac)m(h)j(new)e(release)g(of)h
+(CFITSIO.)95 1867 y Fe(float)47 b(fits_get_version)c(/)48
+b(ffvers)e(\()h(>)h(float)e(*version\))0 2100 y Fi(2)81
+b Fj(W)-8 b(rite)33 b(an)h(80-c)m(haracter)i(message)e(to)g(the)g
+(CFITSIO)e(error)h(stac)m(k.)51 b(Application)31 b(programs)i(should)f
+(not)227 2213 y(normally)d(write)g(to)j(the)e(stac)m(k,)i(but)e(there)g
+(ma)m(y)h(b)s(e)f(some)h(situations)e(where)h(this)f(is)h(desirable.)95
+2447 y Fe(void)47 b(fits_write_errmsg)c(/)48 b(ffpmsg)e(\(char)g
+(*err_msg\))0 2681 y Fi(3)81 b Fj(Con)m(v)m(ert)31 b(a)g(c)m(haracter)h
+(string)d(to)i(upp)s(ercase)e(\(op)s(erates)j(in)d(place\).)95
+2914 y Fe(void)47 b(fits_uppercase)d(/)j(ffupch)g(\(char)f(*string\))0
+3148 y Fi(4)81 b Fj(Compare)43 b(the)i(input)d(template)i(string)f
+(against)h(the)h(reference)f(string)f(to)i(see)g(if)e(they)h(matc)m(h.)
+82 b(The)227 3261 y(template)35 b(string)f(ma)m(y)h(con)m(tain)f
+(wildcard)e(c)m(haracters:)51 b('*')35 b(will)d(matc)m(h)j(an)m(y)g
+(sequence)g(of)f(c)m(haracters)227 3374 y(\(including)26
+b(zero)k(c)m(haracters\))h(and)d('\045')i(will)c(matc)m(h)k(an)m(y)f
+(single)f(c)m(haracter)j(in)c(the)j(reference)f(string.)39
+b(If)227 3487 y(casesen)25 b(=)f(CASESEN)f(=)h(TR)m(UE)h(then)e(the)i
+(matc)m(h)g(will)d(b)s(e)h(case)j(sensitiv)m(e,)f(otherwise)e(the)i
+(case)g(of)g(the)227 3600 y(letters)h(will)d(b)s(e)i(ignored)f(if)h
+(casesen)h(=)f(CASEINSEN)f(=)h(F)-10 b(ALSE.)25 b(The)g(returned)g(MA)
+-8 b(TCH)25 b(parameter)227 3713 y(will)30 b(b)s(e)h(TR)m(UE)i(if)e
+(the)h(2)h(strings)e(matc)m(h,)j(and)d(EXA)m(CT)h(will)e(b)s(e)h(TR)m
+(UE)i(if)e(the)h(matc)m(h)h(is)f(exact)h(\(i.e.,)227
+3826 y(if)27 b(no)h(wildcard)e(c)m(haracters)j(w)m(ere)g(used)e(in)f
+(the)j(matc)m(h\).)41 b(Both)28 b(strings)f(m)m(ust)h(b)s(e)f(68)i(c)m
+(haracters)h(or)e(less)227 3938 y(in)h(length.)95 4172
+y Fe(void)47 b(fits_compare_str)c(/)48 b(ffcmps)334 4285
+y(\(char)e(*templt,)g(char)h(*string,)e(int)i(casesen,)f(>)h(int)g
+(*match,)f(int)h(*exact\))0 4519 y Fi(5)81 b Fj(Split)28
+b(a)k(string)e(con)m(taining)g(a)i(list)d(of)i(names)g(\(t)m(ypically)g
+(\014le)f(names)h(or)g(column)e(names\))j(in)m(to)f(individual)227
+4632 y(name)23 b(tok)m(ens)g(b)m(y)g(a)g(sequence)g(of)g(calls)e(to)j
+(\014ts)p 1814 4632 28 4 v 32 w(split)p 2020 4632 V 31
+w(names.)38 b(The)22 b(names)h(in)e(the)i(list)e(m)m(ust)h(b)s(e)g
+(delimited)227 4745 y(b)m(y)45 b(a)f(comma)i(and/or)e(spaces.)83
+b(This)43 b(routine)g(ignores)h(spaces)h(and)f(commas)h(that)g(o)s
+(ccur)f(within)227 4857 y(paren)m(theses,)36 b(brac)m(k)m(ets,)h(or)e
+(curly)e(brac)m(k)m(ets.)54 b(It)35 b(also)f(strips)f(an)m(y)i(leading)
+e(and)h(trailing)e(blanks)h(from)227 4970 y(the)e(returned)e(name.)227
+5116 y(This)g(routine)g(is)h(similar)d(to)k(the)g(ANSI)f(C)g('strtok')h
+(function:)227 5262 y(The)37 b(\014rst)f(call)g(to)i(\014ts)p
+1033 5262 V 32 w(split)p 1239 5262 V 31 w(names)f(has)g(a)g(non-n)m
+(ull)d(input)h(string.)60 b(It)37 b(\014nds)e(the)i(\014rst)f(name)h
+(in)f(the)227 5375 y(string)25 b(and)g(terminates)g(it)h(b)m(y)f(o)m(v)
+m(erwriting)g(the)h(next)g(c)m(haracter)h(of)f(the)g(string)e(with)h(a)
+h(n)m(ull)d(terminator)227 5488 y(and)31 b(returns)g(a)h(p)s(oin)m(ter)
+e(to)j(the)e(name.)45 b(Eac)m(h)32 b(subsequen)m(t)f(call,)h(indicated)
+e(b)m(y)h(a)h(NULL)g(v)-5 b(alue)31 b(of)h(the)227 5601
+y(input)e(string,)i(returns)f(the)h(next)h(name,)f(searc)m(hing)g(from)
+g(just)g(past)g(the)g(end)f(of)i(the)f(previous)f(name.)227
+5714 y(It)g(returns)e(NULL)h(when)g(no)g(further)f(names)h(are)h
+(found.)p eop
+%%Page: 57 65
+57 64 bop 0 299 a Fh(5.8.)72 b(UTILITY)30 b(R)m(OUTINES)2693
+b Fj(57)143 555 y Fe(char)47 b(*fits_split_names\(char)42
+b(*namelist\))0 797 y Fj(The)30 b(follo)m(wing)f(example)h(sho)m(ws)g
+(ho)m(w)g(a)h(string)e(w)m(ould)h(b)s(e)f(split)g(in)m(to)h(3)h(names:)
+191 1039 y Fe(myfile[1][bin)44 b(\(x,y\)=4],)h(file2.fits)93
+b(file3.fits)191 1152 y(^^^^^^^^^^^^^^^^^^^^^^)c(^^^^^^^^^^)k
+(^^^^^^^^^^)382 1264 y(1st)47 b(name)619 b(2nd)47 b(name)190
+b(3rd)47 b(name)0 1506 y Fi(6)81 b Fj(T)-8 b(est)34 b(that)g(the)g(k)m
+(eyw)m(ord)g(name)f(con)m(tains)h(only)e(legal)i(c)m(haracters)h
+(\(A-Z,0-9,)h(h)m(yphen,)d(and)g(underscore\))227 1619
+y(or)e(that)g(the)f(k)m(eyw)m(ord)h(record)f(con)m(tains)h(only)e
+(legal)h(prin)m(table)f(ASCI)s(I)g(c)m(haracters)95 1861
+y Fe(int)47 b(fits_test_keyword)c(/)48 b(fftkey)e(\(char)g(*keyname,)g
+(>)h(int)g(*status\))95 2087 y(int)g(fits_test_record)d(/)j(fftrec)f
+(\(char)h(*card,)f(>)h(int)g(*status\))0 2328 y Fi(7)81
+b Fj(T)-8 b(est)25 b(whether)f(the)h(curren)m(t)f(header)h(con)m(tains)
+f(an)m(y)h(NULL)g(\(ASCI)s(I)e(0\))j(c)m(haracters.)40
+b(These)24 b(c)m(haracters)j(are)227 2441 y(illegal)33
+b(in)g(the)i(header,)g(but)f(they)g(will)e(go)j(undetected)g(b)m(y)f
+(most)h(of)g(the)f(CFITSIO)f(k)m(eyw)m(ord)i(header)227
+2554 y(routines,)28 b(b)s(ecause)g(the)h(n)m(ull)d(is)h(in)m(terpreted)
+g(as)i(the)f(normal)f(end-of-string)h(terminator.)40
+b(This)26 b(routine)227 2667 y(returns)i(the)g(p)s(osition)f(of)i(the)g
+(\014rst)f(n)m(ull)e(c)m(haracter)k(in)e(the)g(header,)h(or)g(zero)g
+(if)f(there)h(are)g(no)f(n)m(ulls.)38 b(F)-8 b(or)227
+2780 y(example)36 b(a)g(returned)f(v)-5 b(alue)36 b(of)g(110)h(w)m
+(ould)e(indicate)g(that)i(the)f(\014rst)f(NULL)h(is)f(lo)s(cated)h(in)f
+(the)h(30th)227 2893 y(c)m(haracter)28 b(of)f(the)g(second)f(k)m(eyw)m
+(ord)h(in)e(the)i(header)f(\(recall)g(that)h(eac)m(h)h(header)e(record)
+h(is)e(80)i(c)m(haracters)227 3006 y(long\).)44 b(Note)33
+b(that)f(this)f(is)f(one)i(of)g(the)g(few)f(CFITSIO)f(routines)g(in)h
+(whic)m(h)f(the)i(returned)e(v)-5 b(alue)31 b(is)g(not)227
+3119 y(necessarily)f(equal)f(to)j(the)e(status)h(v)-5
+b(alue\).)95 3360 y Fe(int)47 b(fits_null_check)d(/)j(ffnchk)g(\(char)f
+(*card,)g(>)h(int)g(*status\))0 3602 y Fi(8)81 b Fj(P)m(arse)25
+b(a)g(header)g(k)m(eyw)m(ord)g(record)g(and)f(return)g(the)h(name)g(of)
+g(the)g(k)m(eyw)m(ord,)i(and)d(the)h(length)g(of)g(the)g(name.)227
+3715 y(The)34 b(k)m(eyw)m(ord)h(name)f(normally)f(o)s(ccupies)g(the)i
+(\014rst)e(8)i(c)m(haracters)g(of)g(the)f(record,)i(except)f(under)e
+(the)227 3828 y(HIERAR)m(CH)e(con)m(v)m(en)m(tion)g(where)f(the)h(name)
+f(can)h(b)s(e)f(up)f(to)i(70)g(c)m(haracters)h(in)d(length.)95
+4070 y Fe(int)47 b(fits_get_keyname)d(/)j(ffgknm)286
+4182 y(\(char)g(*card,)f(>)h(char)g(*keyname,)e(int)i(*keylength,)e
+(int)i(*status\))0 4424 y Fi(9)81 b Fj(P)m(arse)29 b(a)h(header)f(k)m
+(eyw)m(ord)h(record,)f(returning)f(the)h(v)-5 b(alue)29
+b(\(as)h(a)f(literal)f(c)m(haracter)j(string\))d(and)h(commen)m(t)227
+4537 y(strings.)39 b(If)27 b(the)g(k)m(eyw)m(ord)h(has)f(no)g(v)-5
+b(alue)27 b(\(columns)f(9-10)j(not)f(equal)e(to)i('=)g('\),)g(then)f(a)
+h(n)m(ull)d(v)-5 b(alue)27 b(string)227 4650 y(is)j(returned)f(and)h
+(the)g(commen)m(t)i(string)d(is)g(set)i(equal)f(to)h(column)e(9)i(-)g
+(80)g(of)g(the)f(input)f(string.)95 4892 y Fe(int)47
+b(fits_parse_value)d(/)j(ffpsvc)286 5005 y(\(char)g(*card,)f(>)h(char)g
+(*value,)f(char)g(*comment,)g(int)h(*status\))0 5246
+y Fi(10)f Fj(Construct)26 b(an)h(arra)m(y)g(indexed)e(k)m(eyw)m(ord)i
+(name)f(\(R)m(OOT)g(+)h(nnn\).)38 b(This)25 b(routine)g(app)s(ends)g
+(the)i(sequence)227 5359 y(n)m(um)m(b)s(er)i(to)i(the)g(ro)s(ot)g
+(string)e(to)i(create)h(a)f(k)m(eyw)m(ord)g(name)f(\(e.g.,)i('NAXIS')f
+(+)f(2)h(=)f('NAXIS2'\))95 5601 y Fe(int)47 b(fits_make_keyn)d(/)k
+(ffkeyn)286 5714 y(\(char)f(*keyroot,)e(int)i(value,)f(>)h(char)g
+(*keyname,)e(int)i(*status\))p eop
+%%Page: 58 66
+58 65 bop 0 299 a Fj(58)1379 b Fh(CHAPTER)30 b(5.)71
+b(BASIC)30 b(CFITSIO)f(INTERF)-10 b(A)m(CE)30 b(R)m(OUTINES)0
+555 y Fi(11)46 b Fj(Construct)41 b(a)h(sequence)f(k)m(eyw)m(ord)h(name)
+g(\(n)f(+)g(R)m(OOT\).)g(This)f(routine)g(concatenates)k(the)e
+(sequence)227 668 y(n)m(um)m(b)s(er)20 b(to)j(the)e(fron)m(t)h(of)g
+(the)f(ro)s(ot)h(string)f(to)h(create)h(a)f(k)m(eyw)m(ord)g(name)g
+(\(e.g.,)j(1)d(+)f('CTYP')g(=)g('1CTYP'\))95 1045 y Fe(int)47
+b(fits_make_nkey)d(/)k(ffnkey)286 1158 y(\(int)f(value,)f(char)h
+(*keyroot,)e(>)i(char)g(*keyname,)e(int)i(*status\))0
+1422 y Fi(12)f Fj(Determine)40 b(the)h(data)f(t)m(yp)s(e)h(of)f(a)h(k)m
+(eyw)m(ord)f(v)-5 b(alue)40 b(string.)69 b(This)38 b(routine)i(parses)f
+(the)i(k)m(eyw)m(ord)f(v)-5 b(alue)227 1535 y(string)27
+b(to)i(determine)e(its)g(data)i(t)m(yp)s(e.)40 b(Returns)27
+b('C',)h('L',)h('I',)f('F')h(or)f('X',)g(for)g(c)m(haracter)i(string,)d
+(logical,)227 1648 y(in)m(teger,)k(\015oating)g(p)s(oin)m(t,)e(or)i
+(complex,)f(resp)s(ectiv)m(ely)-8 b(.)95 1912 y Fe(int)47
+b(fits_get_keytype)d(/)j(ffdtyp)286 2025 y(\(char)g(*value,)f(>)h(char)
+g(*dtype,)e(int)i(*status\))0 2288 y Fi(13)f Fj(Return)35
+b(the)g(class)g(of)h(an)f(input)f(header)h(record.)56
+b(The)35 b(record)g(is)f(classi\014ed)g(in)m(to)i(one)f(of)h(the)f
+(follo)m(wing)227 2401 y(categories)c(\(the)f(class)f(v)-5
+b(alues)29 b(are)g(de\014ned)f(in)g(\014tsio.h\).)40
+b(Note)31 b(that)f(this)e(is)g(one)i(of)f(the)g(few)g(CFITSIO)227
+2514 y(routines)h(that)g(do)s(es)h(not)f(return)f(a)i(status)g(v)-5
+b(alue.)334 2778 y Fe(Class)94 b(Value)619 b(Keywords)95
+2891 y(TYP_STRUC_KEY)92 b(10)j(SIMPLE,)46 b(BITPIX,)g(NAXIS,)g(NAXISn,)
+g(EXTEND,)g(BLOCKED,)1002 3004 y(GROUPS,)g(PCOUNT,)g(GCOUNT,)g(END)1002
+3117 y(XTENSION,)g(TFIELDS,)f(TTYPEn,)h(TBCOLn,)g(TFORMn,)g(THEAP,)1002
+3230 y(and)h(the)g(first)f(4)i(COMMENT)e(keywords)f(in)i(the)g(primary)
+f(array)1002 3343 y(that)h(define)f(the)h(FITS)g(format.)95
+3456 y(TYP_CMPRS_KEY)92 b(20)j(The)47 b(experimental)e(keywords)g(used)
+i(in)g(the)g(compressed)1002 3569 y(image)g(format)f(ZIMAGE,)g
+(ZCMPTYPE,)f(ZNAMEn,)h(ZVALn,)1002 3681 y(ZTILEn,)g(ZBITPIX,)g
+(ZNAXISn,)f(ZSCALE,)h(ZZERO,)g(ZBLANK)95 3794 y(TYP_SCAL_KEY)140
+b(30)95 b(BSCALE,)46 b(BZERO,)g(TSCALn,)g(TZEROn)95 3907
+y(TYP_NULL_KEY)140 b(40)95 b(BLANK,)46 b(TNULLn)95 4020
+y(TYP_DIM_KEY)188 b(50)95 b(TDIMn)95 4133 y(TYP_RANG_KEY)140
+b(60)95 b(TLMINn,)46 b(TLMAXn,)g(TDMINn,)g(TDMAXn,)g(DATAMIN,)f
+(DATAMAX)95 4246 y(TYP_UNIT_KEY)140 b(70)95 b(BUNIT,)46
+b(TUNITn)95 4359 y(TYP_DISP_KEY)140 b(80)95 b(TDISPn)95
+4472 y(TYP_HDUID_KEY)d(90)j(EXTNAME,)46 b(EXTVER,)g(EXTLEVEL,)f
+(HDUNAME,)g(HDUVER,)h(HDULEVEL)95 4585 y(TYP_CKSUM_KEY)f(100)94
+b(CHECKSUM,)46 b(DATASUM)95 4698 y(TYP_WCS_KEY)141 b(110)94
+b(CTYPEn,)46 b(CUNITn,)g(CRVALn,)g(CRPIXn,)g(CROTAn,)f(CDELTn)1002
+4811 y(CDj_is,)h(PVj_ms,)g(LONPOLEs,)f(LATPOLEs)1002
+4924 y(TCTYPn,)h(TCTYns,)g(TCUNIn,)g(TCUNns,)g(TCRVLn,)f(TCRVns,)h
+(TCRPXn,)1002 5036 y(TCRPks,)g(TCDn_k,)g(TCn_ks,)g(TPVn_m,)g(TPn_ms,)f
+(TCDLTn,)h(TCROTn)1002 5149 y(jCTYPn,)g(jCTYns,)g(jCUNIn,)g(jCUNns,)g
+(jCRVLn,)f(jCRVns,)h(iCRPXn,)1002 5262 y(iCRPns,)g(jiCDn,)94
+b(jiCDns,)46 b(jPVn_m,)g(jPn_ms,)f(jCDLTn,)h(jCROTn)1002
+5375 y(\(i,j,m,n)g(are)h(integers,)e(s)i(is)h(any)f(letter\))95
+5488 y(TYP_REFSYS_KEY)d(120)j(EQUINOXs,)f(EPOCH,)g(MJD-OBSs,)f
+(RADECSYS,)g(RADESYSs)95 5601 y(TYP_COMM_KEY)140 b(130)47
+b(COMMENT,)f(HISTORY,)f(\(blank)h(keyword\))95 5714 y(TYP_CONT_KEY)140
+b(140)47 b(CONTINUE)p eop
+%%Page: 59 67
+59 66 bop 0 299 a Fh(5.8.)72 b(UTILITY)30 b(R)m(OUTINES)2693
+b Fj(59)95 555 y Fe(TYP_USER_KEY)140 b(150)47 b(all)g(other)g(keywords)
+95 781 y(int)g(fits_get_keyclass)c(/)48 b(ffgkcl)e(\(char)g(*card\))0
+1034 y Fi(14)g Fj(P)m(arse)28 b(the)g('TF)m(ORM')g(binary)e(table)h
+(column)g(format)g(string.)39 b(This)26 b(routine)g(parses)h(the)h
+(input)e(TF)m(ORM)227 1147 y(c)m(haracter)38 b(string)c(and)h(returns)g
+(the)g(in)m(teger)h(data)h(t)m(yp)s(e)f(co)s(de,)h(the)f(rep)s(eat)g
+(coun)m(t)g(of)g(the)f(\014eld,)h(and,)227 1260 y(in)e(the)g(case)i(of)
+f(c)m(haracter)h(string)e(\014elds,)g(the)h(length)f(of)h(the)g(unit)e
+(string.)53 b(See)34 b(App)s(endix)e(B)j(for)g(the)227
+1373 y(allo)m(w)m(ed)k(v)-5 b(alues)37 b(for)i(the)f(returned)g(t)m(yp)
+s(eco)s(de)h(parameter.)65 b(A)39 b(n)m(ull)d(p)s(oin)m(ter)i(ma)m(y)h
+(b)s(e)f(giv)m(en)g(for)h(an)m(y)227 1486 y(output)30
+b(parameters)h(that)g(are)g(not)f(needed.)143 1739 y
+Fe(int)47 b(fits_binary_tform)c(/)48 b(ffbnfm)334 1852
+y(\(char)e(*tform,)g(>)i(int)f(*typecode,)e(long)h(*repeat,)g(long)g
+(*width,)382 1965 y(int)h(*status\))0 2218 y Fi(15)f
+Fj(P)m(arse)38 b(the)f('TF)m(ORM')h(k)m(eyw)m(ord)g(v)-5
+b(alue)36 b(that)i(de\014nes)e(the)h(column)f(format)i(in)d(an)i(ASCI)s
+(I)f(table.)61 b(This)227 2331 y(routine)28 b(parses)h(the)g(input)e
+(TF)m(ORM)i(c)m(haracter)h(string)e(and)h(returns)e(the)i(data)h(t)m
+(yp)s(e)f(co)s(de,)h(the)f(width)227 2443 y(of)f(the)f(column,)g(and)g
+(\(if)g(it)g(is)f(a)i(\015oating)f(p)s(oin)m(t)g(column\))f(the)i(n)m
+(um)m(b)s(er)e(of)h(decimal)g(places)g(to)h(the)f(righ)m(t)227
+2556 y(of)39 b(the)f(decimal)f(p)s(oin)m(t.)64 b(The)38
+b(returned)f(data)i(t)m(yp)s(e)f(co)s(des)g(are)h(the)g(same)f(as)h
+(for)f(the)g(binary)f(table,)227 2669 y(with)25 b(the)i(follo)m(wing)e
+(additional)f(rules:)37 b(in)m(teger)27 b(columns)e(that)i(are)f(b)s
+(et)m(w)m(een)h(1)g(and)f(4)g(c)m(haracters)i(wide)227
+2782 y(are)i(de\014ned)e(to)j(b)s(e)d(short)i(in)m(tegers)f(\(co)s(de)h
+(=)g(TSHOR)-8 b(T\).)29 b(Wider)f(in)m(teger)i(columns)e(are)i
+(de\014ned)e(to)j(b)s(e)227 2895 y(regular)38 b(in)m(tegers)g(\(co)s
+(de)h(=)f(TLONG\).)h(Similarly)-8 b(,)37 b(Fixed)h(decimal)f(p)s(oin)m
+(t)g(columns)g(\(with)h(TF)m(ORM)227 3008 y(=)d('Fw.d'\))g(are)h
+(de\014ned)d(to)j(b)s(e)e(single)g(precision)f(reals)i(\(co)s(de)g(=)g
+(TFLO)m(A)-8 b(T\))35 b(if)f(w)h(is)f(b)s(et)m(w)m(een)h(1)h(and)227
+3121 y(7)42 b(c)m(haracters)h(wide,)g(inclusiv)m(e.)72
+b(Wider)40 b('F')i(columns)e(will)f(return)h(a)i(double)e(precision)g
+(data)i(co)s(de)227 3234 y(\(=)32 b(TDOUBLE\).)h('Ew.d')f(format)g
+(columns)f(will)e(ha)m(v)m(e)34 b(dataco)s(de)f(=)e(TFLO)m(A)-8
+b(T,)33 b(and)e('Dw.d')i(format)227 3347 y(columns)44
+b(will)f(ha)m(v)m(e)k(dataco)s(de)f(=)f(TDOUBLE.)g(A)h(n)m(ull)d(p)s
+(oin)m(ter)i(ma)m(y)g(b)s(e)g(giv)m(en)h(for)f(an)m(y)g(output)227
+3460 y(parameters)31 b(that)g(are)g(not)f(needed.)95
+3713 y Fe(int)47 b(fits_ascii_tform)d(/)j(ffasfm)286
+3826 y(\(char)g(*tform,)f(>)h(int)g(*typecode,)e(long)i(*width,)e(int)i
+(*decimals,)334 3939 y(int)g(*status\))0 4192 y Fi(16)f
+Fj(Calculate)30 b(the)h(starting)f(column)g(p)s(ositions)e(and)i(total)
+h(ASCI)s(I)e(table)i(width)d(based)j(on)f(the)h(input)d(arra)m(y)227
+4304 y(of)f(ASCI)s(I)e(table)h(TF)m(ORM)h(v)-5 b(alues.)39
+b(The)26 b(SP)-8 b(A)m(CE)27 b(input)d(parameter)j(de\014nes)f(ho)m(w)h
+(man)m(y)f(blank)g(spaces)227 4417 y(to)40 b(lea)m(v)m(e)h(b)s(et)m(w)m
+(een)f(eac)m(h)g(column)f(\(it)g(is)f(recommended)h(to)h(ha)m(v)m(e)h
+(one)e(space)h(b)s(et)m(w)m(een)g(columns)e(for)227 4530
+y(b)s(etter)31 b(h)m(uman)e(readabilit)m(y\).)95 4783
+y Fe(int)47 b(fits_get_tbcol)d(/)k(ffgabc)286 4896 y(\(int)f(tfields,)f
+(char)g(**tform,)g(int)h(space,)f(>)h(long)g(*rowlen,)334
+5009 y(long)g(*tbcol,)f(int)g(*status\))0 5262 y Fi(17)g
+Fj(P)m(arse)27 b(a)g(template)g(header)f(record)g(and)g(return)g(a)g
+(formatted)h(80-c)m(haracter)j(string)25 b(suitable)g(for)h(app)s(end-)
+227 5375 y(ing)39 b(to)g(\(or)h(deleting)e(from\))h(a)g(FITS)g(header)g
+(\014le.)66 b(This)37 b(routine)h(is)g(useful)g(for)g(parsing)g(lines)f
+(from)227 5488 y(an)c(ASCI)s(I)f(template)h(\014le)f(and)h
+(reformatting)g(them)g(in)m(to)g(legal)g(FITS)f(header)h(records.)49
+b(The)32 b(format-)227 5601 y(ted)i(string)f(ma)m(y)h(then)f(b)s(e)g
+(passed)h(to)g(the)g(\014ts)p 1880 5601 28 4 v 32 w(write)p
+2115 5601 V 32 w(record,)h(\013mcrd,)f(or)g(\014ts)p
+3007 5601 V 32 w(delete)p 3271 5601 V 33 w(k)m(ey)h(routines)d(to)227
+5714 y(app)s(end)d(or)h(mo)s(dify)f(a)i(FITS)e(header)h(record.)p
+eop
+%%Page: 60 68
+60 67 bop 0 299 a Fj(60)1379 b Fh(CHAPTER)30 b(5.)71
+b(BASIC)30 b(CFITSIO)f(INTERF)-10 b(A)m(CE)30 b(R)m(OUTINES)95
+555 y Fe(int)47 b(fits_parse_template)c(/)k(ffgthd)286
+668 y(\(char)g(*templt,)e(>)j(char)e(*card,)g(int)h(*keytype,)f(int)h
+(*status\))0 932 y Fj(The)31 b(input)f(templt)h(c)m(haracter)i(string)e
+(generally)g(should)e(con)m(tain)j(3)g(tok)m(ens:)44
+b(\(1\))33 b(the)f(KEYNAME,)g(\(2\))h(the)0 1045 y(V)-10
+b(ALUE,)37 b(and)f(\(3\))i(the)f(COMMENT)g(string.)58
+b(The)37 b(TEMPLA)-8 b(TE)36 b(string)g(m)m(ust)g(adhere)h(to)h(the)e
+(follo)m(wing)0 1158 y(format:)0 1421 y Fi(-)80 b Fj(The)32
+b(KEYNAME)h(tok)m(en)h(m)m(ust)f(b)s(egin)e(in)h(columns)f(1-8)j(and)e
+(b)s(e)g(a)h(maxim)m(um)f(of)h(8)g(c)m(haracters)h(long.)48
+b(A)227 1534 y(legal)28 b(FITS)g(k)m(eyw)m(ord)h(name)f(ma)m(y)h(only)e
+(con)m(tain)i(the)g(c)m(haracters)g(A-Z,)g(0-9,)h(and)e('-')h(\(min)m
+(us)e(sign\))h(and)227 1647 y(underscore.)40 b(This)26
+b(routine)i(will)e(automatically)i(con)m(v)m(ert)i(an)m(y)f(lo)m(w)m
+(ercase)h(c)m(haracters)g(to)g(upp)s(ercase)d(in)227
+1760 y(the)k(output)f(string.)41 b(If)30 b(the)h(\014rst)f(8)h(c)m
+(haracters)h(of)f(the)g(template)g(line)e(are)i(blank)e(then)i(the)g
+(remainder)227 1873 y(of)g(the)f(line)f(is)h(considered)f(to)i(b)s(e)f
+(a)g(FITS)g(commen)m(t)h(\(with)f(a)h(blank)e(k)m(eyw)m(ord)h(name\).)0
+2137 y Fi(-)80 b Fj(The)26 b(V)-10 b(ALUE)26 b(tok)m(en)h(m)m(ust)e(b)s
+(e)h(separated)g(from)f(the)i(KEYNAME)f(tok)m(en)h(b)m(y)f(one)g(or)g
+(more)g(spaces)g(and/or)227 2250 y(an)g('=')g(c)m(haracter.)41
+b(The)25 b(data)h(t)m(yp)s(e)g(of)g(the)g(V)-10 b(ALUE)26
+b(tok)m(en)g(\(n)m(umeric,)g(logical,)h(or)f(c)m(haracter)h(string\))e
+(is)227 2363 y(automatically)32 b(determined)e(and)i(the)g(output)f
+(CARD)h(string)f(is)g(formatted)h(accordingly)-8 b(.)45
+b(The)31 b(v)-5 b(alue)227 2476 y(tok)m(en)34 b(ma)m(y)f(b)s(e)f
+(forced)g(to)i(b)s(e)e(in)m(terpreted)f(as)i(a)g(string)f(\(e.g.)48
+b(if)32 b(it)g(is)f(a)i(string)f(of)g(n)m(umeric)g(digits\))f(b)m(y)227
+2588 y(enclosing)f(it)g(in)f(single)g(quotes.)0 2852
+y Fi(-)80 b Fj(The)28 b(COMMENT)g(tok)m(en)h(is)e(optional,)h(but)g(if)
+f(presen)m(t)h(m)m(ust)g(b)s(e)g(separated)g(from)g(the)g(V)-10
+b(ALUE)29 b(tok)m(en)g(b)m(y)227 2965 y(at)i(least)g(one)g(blank)e
+(space)i(and)e(a)i('/')g(c)m(haracter.)0 3229 y Fi(-)80
+b Fj(One)29 b(exception)g(to)g(the)g(ab)s(o)m(v)m(e)i(rules)c(is)h
+(that)h(if)f(the)h(\014rst)g(non-blank)e(c)m(haracter)j(in)e(the)h
+(\014rst)f(8)h(c)m(haracters)227 3342 y(of)24 b(the)h(template)f
+(string)f(is)g(a)h(min)m(us)f(sign)g(\('-'\))i(follo)m(w)m(ed)f(b)m(y)g
+(a)g(single)f(tok)m(en,)j(or)e(a)h(single)d(tok)m(en)j(follo)m(w)m(ed)
+227 3455 y(b)m(y)k(an)g(equal)g(sign,)g(then)g(it)f(is)h(in)m
+(terpreted)f(as)i(the)f(name)g(of)h(a)f(k)m(eyw)m(ord)h(whic)m(h)e(is)g
+(to)i(b)s(e)e(deleted)h(from)227 3568 y(the)i(FITS)e(header.)0
+3831 y Fi(-)80 b Fj(The)32 b(second)g(exception)g(is)f(that)i(if)e(the)
+h(template)g(string)f(starts)i(with)d(a)j(min)m(us)d(sign)h(and)g(is)g
+(follo)m(w)m(ed)h(b)m(y)227 3944 y(2)h(tok)m(ens)g(\(without)f(an)g
+(equals)g(sign)g(b)s(et)m(w)m(een)h(them\))f(then)g(the)h(second)f(tok)
+m(en)i(is)d(in)m(terpreted)h(as)h(the)227 4057 y(new)f(name)h(for)f
+(the)h(k)m(eyw)m(ord)g(sp)s(eci\014ed)e(b)m(y)i(\014rst)f(tok)m(en.)48
+b(In)32 b(this)f(case)j(the)f(old)f(k)m(eyw)m(ord)h(name)f(\(\014rst)
+227 4170 y(tok)m(en\))c(is)d(returned)f(in)h(c)m(haracters)i(1-8)g(of)g
+(the)f(returned)e(CARD)j(string,)f(and)f(the)h(new)f(k)m(eyw)m(ord)i
+(name)227 4283 y(\(the)35 b(second)e(tok)m(en\))j(is)d(returned)f(in)h
+(c)m(haracters)i(41-48)h(of)e(the)g(returned)e(CARD)i(string.)50
+b(These)34 b(old)227 4396 y(and)i(new)f(names)h(ma)m(y)h(then)f(b)s(e)f
+(passed)g(to)i(the)f(\013mnam)g(routine)f(whic)m(h)g(will)e(c)m(hange)k
+(the)f(k)m(eyw)m(ord)227 4509 y(name.)0 4773 y(The)30
+b(k)m(eyt)m(yp)s(e)h(output)f(parameter)h(indicates)e(ho)m(w)i(the)f
+(returned)g(CARD)g(string)f(should)g(b)s(e)g(in)m(terpreted:)382
+5036 y Fe(keytype)857 b(interpretation)382 5149 y(-------)475
+b(-------------------------)o(----)o(---)o(----)o(----)o(---)o(----)o
+(--)525 5262 y(-2)572 b(Rename)46 b(the)h(keyword)f(with)h(name)f(=)i
+(the)f(first)f(8)h(characters)e(of)j(CARD)1193 5375 y(to)f(the)g(new)g
+(name)g(given)f(in)h(characters)e(41)j(-)f(48)g(of)g(CARD.)525
+5601 y(-1)572 b(delete)46 b(the)h(keyword)f(with)h(this)f(name)h(from)g
+(the)f(FITS)h(header.)p eop
+%%Page: 61 69
+61 68 bop 0 299 a Fh(5.8.)72 b(UTILITY)30 b(R)m(OUTINES)2693
+b Fj(61)573 555 y Fe(0)572 b(append)46 b(the)h(CARD)g(string)f(to)h
+(the)g(FITS)g(header)f(if)h(the)1193 668 y(keyword)f(does)h(not)g
+(already)e(exist,)h(otherwise)g(update)1193 781 y(the)h(keyword)f
+(value)g(and/or)g(comment)g(field)h(if)g(is)g(already)f(exists.)573
+1007 y(1)572 b(This)47 b(is)g(a)g(HISTORY)f(or)h(COMMENT)f(keyword;)g
+(append)g(it)h(to)g(the)g(header)573 1233 y(2)572 b(END)47
+b(record;)f(do)h(not)g(explicitly)e(write)h(it)i(to)f(the)g(FITS)f
+(file.)0 1458 y Fj(EXAMPLES:)30 b(The)g(follo)m(wing)f(lines)f
+(illustrate)h(v)-5 b(alid)29 b(input)f(template)j(strings:)286
+1682 y Fe(INTVAL)46 b(7)i(/)f(This)g(is)g(an)g(integer)f(keyword)286
+1795 y(RVAL)524 b(34.6)142 b(/)239 b(This)46 b(is)i(a)f(floating)f
+(point)g(keyword)286 1908 y(EVAL=-12.45E-03)92 b(/)47
+b(This)g(is)g(a)g(floating)f(point)g(keyword)g(in)h(exponential)e
+(notation)286 2021 y(lval)i(F)g(/)h(This)f(is)g(a)g(boolean)f(keyword)
+859 2134 y(This)h(is)g(a)g(comment)f(keyword)g(with)h(a)g(blank)f
+(keyword)g(name)286 2247 y(SVAL1)h(=)g('Hello)f(world')142
+b(/)95 b(this)47 b(is)g(a)g(string)f(keyword)286 2360
+y(SVAL2)94 b('123.5')g(this)47 b(is)g(also)f(a)i(string)e(keyword)286
+2473 y(sval3)94 b(123+)h(/)g(this)47 b(is)g(also)f(a)i(string)e
+(keyword)g(with)g(the)h(value)g('123+)189 b(')286 2586
+y(#)48 b(the)f(following)e(template)h(line)g(deletes)g(the)h(DATE)g
+(keyword)286 2699 y(-)h(DATE)286 2812 y(#)g(the)f(following)e(template)
+h(line)g(modifies)g(the)h(NAME)f(keyword)g(to)h(OBJECT)286
+2924 y(-)h(NAME)e(OBJECT)0 3149 y Fi(18)g Fj(P)m(arse)35
+b(the)g(input)e(string)h(con)m(taining)g(a)h(list)f(of)h(ro)m(ws)f(or)h
+(ro)m(w)g(ranges,)h(and)e(return)g(in)m(teger)h(arra)m(ys)g(con-)227
+3262 y(taining)25 b(the)h(\014rst)f(and)g(last)h(ro)m(w)g(in)e(eac)m(h)
+j(range.)40 b(F)-8 b(or)26 b(example,)h(if)d(ro)m(wlist)h(=)g("3-5,)k
+(6,)e(8-9")h(then)d(it)h(will)227 3375 y(return)34 b(n)m(umranges)h(=)g
+(3,)h(rangemin)e(=)h(3,)i(6,)g(8)e(and)g(rangemax)g(=)g(5,)i(6,)g(9.)55
+b(A)m(t)36 b(most,)h('maxranges')227 3488 y(n)m(um)m(b)s(er)31
+b(of)h(ranges)f(will)e(b)s(e)j(returned.)43 b('maxro)m(ws')32
+b(is)f(the)h(maxim)m(um)f(n)m(um)m(b)s(er)f(of)i(ro)m(ws)g(in)e(the)i
+(table;)227 3601 y(an)m(y)e(ro)m(ws)f(or)g(ranges)g(larger)g(than)g
+(this)f(will)e(b)s(e)j(ignored.)39 b(The)29 b(ro)m(ws)g(m)m(ust)g(b)s
+(e)f(sp)s(eci\014ed)g(in)f(increasing)227 3714 y(order,)33
+b(and)f(the)g(ranges)h(m)m(ust)f(not)g(o)m(v)m(erlap.)47
+b(A)33 b(min)m(us)d(sign)i(ma)m(y)h(b)s(e)e(use)h(to)h(sp)s(ecify)e
+(all)g(the)i(ro)m(ws)f(to)227 3827 y(the)h(upp)s(er)d(or)j(lo)m(w)m(er)
+g(b)s(ound,)e(so)i("50-")h(means)e(all)g(the)h(ro)m(ws)f(from)g(50)h
+(to)h(the)e(end)g(of)h(the)f(table,)i(and)227 3940 y("-")e(means)e(all)
+f(the)i(ro)m(ws)f(in)f(the)i(table,)f(from)g(1)h(-)g(maxro)m(ws.)191
+4165 y Fe(int)47 b(fits_parse_range)c(/)48 b(ffrwrg\(char)c(*rowlist,)i
+(long)g(maxrows,)g(int)h(maxranges,)e(>)334 4278 y(int)i(*numranges,)e
+(long)h(*rangemin,)f(long)i(*rangemax,)e(int)i(*status\))0
+4503 y Fi(19)f Fj(Chec)m(k)37 b(that)g(the)g(Header)g(\014ll)e(b)m
+(ytes)i(\(if)f(an)m(y\))h(are)g(all)f(blank.)58 b(These)36
+b(are)h(the)g(b)m(ytes)g(that)g(ma)m(y)h(follo)m(w)227
+4615 y(END)e(k)m(eyw)m(ord)g(and)f(b)s(efore)g(the)h(b)s(eginning)d(of)
+j(data)g(unit,)f(or)h(the)g(end)f(of)g(the)h(HDU)g(if)f(there)g(is)g
+(no)227 4728 y(data)c(unit.)191 4953 y Fe(int)47 b(ffchfl\(fitsfile)c
+(*fptr,)k(>)g(int)g(*status\))0 5178 y Fi(20)f Fj(Chec)m(k)30
+b(that)g(the)f(Data)i(\014ll)c(b)m(ytes)j(\(if)f(an)m(y\))h(are)g(all)e
+(zero)i(\(for)f(IMA)m(GE)i(or)e(BINAR)-8 b(Y)30 b(T)-8
+b(able)29 b(HDU\))i(or)e(all)227 5291 y(blanks)f(\(for)h(ASCI)s(I)f
+(table)h(HDU\).)h(These)f(\014le)f(b)m(ytes)i(ma)m(y)f(b)s(e)g(lo)s
+(cated)g(after)h(the)f(last)g(v)-5 b(alid)27 b(data)j(b)m(yte)227
+5404 y(in)f(the)i(HDU)g(and)f(b)s(efore)g(the)g(ph)m(ysical)f(end)h(of)
+h(the)f(HDU.)191 5629 y Fe(int)47 b(ffcdfl\(fitsfile)c(*fptr,)k(>)g
+(int)g(*status\))p eop
+%%Page: 62 70
+62 69 bop 0 299 a Fj(62)1379 b Fh(CHAPTER)30 b(5.)71
+b(BASIC)30 b(CFITSIO)f(INTERF)-10 b(A)m(CE)30 b(R)m(OUTINES)p
+eop
+%%Page: 63 71
+63 70 bop 0 1225 a Fg(Chapter)65 b(6)0 1687 y Fm(The)77
+b(CFITSIO)f(Iterator)i(F)-19 b(unction)0 2180 y Fj(The)41
+b(\014ts)p 325 2180 28 4 v 33 w(iterate)p 615 2180 V
+33 w(data)i(function)d(in)h(CFITSIO)f(pro)m(vides)h(a)h(unique)d(metho)
+s(d)j(of)g(executing)g(an)f(arbitrary)0 2293 y(user-supplied)33
+b(`w)m(ork')k(function)e(that)i(op)s(erates)g(on)g(ro)m(ws)f(of)h(data)
+g(in)e(FITS)h(tables)g(or)g(on)h(pixels)d(in)i(FITS)0
+2406 y(images.)i(Rather)24 b(than)e(explicitly)f(reading)h(and)h
+(writing)e(the)i(FITS)g(images)g(or)g(columns)f(of)h(data,)i(one)f
+(instead)0 2518 y(calls)34 b(the)i(CFITSIO)d(iterator)j(routine,)g
+(passing)e(to)i(it)f(the)g(name)g(of)h(the)f(user's)g(w)m(ork)g
+(function)f(that)i(is)e(to)0 2631 y(b)s(e)c(executed)h(along)f(with)f
+(a)i(list)e(of)h(all)f(the)i(table)f(columns)f(or)h(image)g(arra)m(ys)h
+(that)g(are)f(to)h(b)s(e)f(passed)g(to)h(the)0 2744 y(w)m(ork)37
+b(function.)60 b(The)37 b(CFITSIO)e(iterator)j(function)e(then)h(do)s
+(es)g(all)f(the)h(w)m(ork)g(of)h(allo)s(cating)e(memory)h(for)0
+2857 y(the)28 b(arra)m(ys,)h(reading)e(the)h(input)d(data)k(from)e(the)
+h(FITS)f(\014le,)g(passing)g(them)h(to)g(the)g(w)m(ork)g(function,)f
+(and)g(then)0 2970 y(writing)34 b(an)m(y)j(output)f(data)h(bac)m(k)h
+(to)f(the)f(FITS)g(\014le)f(after)i(the)g(w)m(ork)g(function)e(exits.)
+58 b(Because)38 b(it)e(is)g(often)0 3083 y(more)h(e\016cien)m(t)h(to)g
+(pro)s(cess)f(only)f(a)i(subset)f(of)g(the)g(total)h(table)g(ro)m(ws)f
+(at)h(one)f(time,)i(the)f(iterator)f(function)0 3196
+y(can)f(determine)f(the)i(optim)m(um)e(amoun)m(t)h(of)g(data)h(to)g
+(pass)e(in)g(eac)m(h)i(iteration)f(and)f(rep)s(eatly)g(call)h(the)g(w)m
+(ork)0 3309 y(function)29 b(un)m(til)g(the)h(en)m(tire)h(table)f(b)s
+(een)f(pro)s(cessed.)0 3469 y(F)-8 b(or)37 b(man)m(y)f(applications)e
+(this)g(single)h(CFITSIO)f(iterator)j(function)d(can)i(e\013ectiv)m
+(ely)h(replace)f(all)f(the)h(other)0 3582 y(CFITSIO)g(routines)h(for)g
+(reading)g(or)g(writing)f(data)i(in)e(FITS)h(images)h(or)f(tables.)63
+b(Using)36 b(the)i(iterator)g(has)0 3695 y(sev)m(eral)31
+b(imp)s(ortan)m(t)e(adv)-5 b(an)m(tages)32 b(o)m(v)m(er)g(the)f
+(traditional)d(metho)s(d)i(of)h(reading)e(and)h(writing)e(FITS)i(data)h
+(\014les:)136 3961 y Fc(\017)46 b Fj(It)33 b(cleanly)f(separates)i(the)
+f(data)h(I/O)f(from)f(the)h(routine)f(that)i(op)s(erates)f(on)g(the)g
+(data.)49 b(This)31 b(leads)h(to)227 4074 y(a)f(more)g(mo)s(dular)d
+(and)i(`ob)5 b(ject)31 b(orien)m(ted')g(programming)e(st)m(yle.)136
+4268 y Fc(\017)46 b Fj(It)27 b(simpli\014es)c(the)k(application)e
+(program)i(b)m(y)f(eliminating)e(the)j(need)g(to)g(allo)s(cate)g
+(memory)g(for)f(the)h(data)227 4381 y(arra)m(ys)e(and)f(eliminates)f
+(most)h(of)h(the)f(calls)g(to)h(the)g(CFITSIO)d(routines)i(that)h
+(explicitly)d(read)i(and)g(write)227 4494 y(the)31 b(data.)136
+4689 y Fc(\017)46 b Fj(It)32 b(ensures)e(that)i(the)g(data)g(are)g(pro)
+s(cessed)f(as)h(e\016cien)m(tly)f(as)g(p)s(ossible.)42
+b(This)30 b(is)g(esp)s(ecially)g(imp)s(ortan)m(t)227
+4801 y(when)44 b(pro)s(cessing)f(tabular)h(data)i(since)e(the)h
+(iterator)g(function)e(will)f(calculate)j(the)g(most)g(e\016cien)m(t)
+227 4914 y(n)m(um)m(b)s(er)36 b(of)i(ro)m(ws)g(in)e(the)i(table)f(to)h
+(b)s(e)f(passed)g(at)i(one)e(time)h(to)g(the)g(user's)e(w)m(ork)i
+(function)e(on)i(eac)m(h)227 5027 y(iteration.)136 5222
+y Fc(\017)46 b Fj(Mak)m(es)39 b(it)d(p)s(ossible)f(for)i(larger)g(pro)5
+b(jects)37 b(to)h(dev)m(elop)f(a)h(library)c(of)k(w)m(ork)f(functions)f
+(that)h(all)f(ha)m(v)m(e)j(a)227 5335 y(uniform)28 b(calling)h
+(sequence)i(and)f(are)h(all)e(indep)s(enden)m(t)f(of)j(the)f(details)g
+(of)g(the)h(FITS)e(\014le)h(format.)0 5601 y(There)g(are)h(basically)e
+(2)j(steps)e(in)g(using)f(the)i(CFITSIO)e(iterator)i(function.)41
+b(The)30 b(\014rst)g(step)h(is)f(to)h(design)f(the)0
+5714 y(w)m(ork)c(function)e(itself)g(whic)m(h)g(m)m(ust)i(ha)m(v)m(e)g
+(a)g(prescrib)s(ed)d(set)j(of)g(input)e(parameters.)39
+b(One)25 b(of)h(these)g(parameters)1905 5942 y(63)p eop
+%%Page: 64 72
+64 71 bop 0 299 a Fj(64)1455 b Fh(CHAPTER)30 b(6.)112
+b(THE)30 b(CFITSIO)e(ITERA)-8 b(TOR)30 b(FUNCTION)0 555
+y Fj(is)e(a)h(structure)g(con)m(taining)g(p)s(oin)m(ters)e(to)j(the)f
+(arra)m(ys)h(of)f(data;)h(the)f(w)m(ork)h(function)d(can)j(p)s(erform)d
+(an)m(y)i(desired)0 668 y(op)s(erations)j(on)i(these)f(arra)m(ys)h(and)
+e(do)s(es)h(not)g(need)g(to)h(w)m(orry)f(ab)s(out)g(ho)m(w)g(the)h
+(input)d(data)j(w)m(ere)f(read)g(from)0 781 y(the)e(\014le)e(or)h(ho)m
+(w)h(the)f(output)g(data)h(get)h(written)d(bac)m(k)i(to)h(the)e
+(\014le.)0 941 y(The)24 b(second)h(step)g(is)e(to)j(design)d(the)i
+(driv)m(er)f(routine)f(that)j(op)s(ens)e(all)f(the)i(necessary)g(FITS)f
+(\014les)g(and)g(initializes)0 1054 y(the)41 b(input)f(parameters)h(to)
+h(the)g(iterator)f(function.)72 b(The)41 b(driv)m(er)f(program)h(calls)
+f(the)i(CFITSIO)e(iterator)0 1167 y(function)29 b(whic)m(h)g(then)h
+(reads)g(the)h(data)g(and)f(passes)g(it)g(to)h(the)g(user's)e(w)m(ork)i
+(function.)0 1327 y(The)20 b(follo)m(wing)f(2)i(sections)f(describ)s(e)
+f(these)i(steps)g(in)e(more)h(detail.)37 b(There)20 b(are)h(also)f(sev)
+m(eral)h(example)f(programs)0 1440 y(included)28 b(with)h(the)h
+(CFITSIO)f(distribution)e(whic)m(h)i(illustrate)g(ho)m(w)h(to)h(use)f
+(the)h(iterator)f(function.)0 1789 y Ff(6.1)135 b(The)45
+b(Iterator)h(W)-11 b(ork)45 b(F)-11 b(unction)0 2043
+y Fj(The)42 b(user-supplied)d(iterator)k(w)m(ork)g(function)e(m)m(ust)h
+(ha)m(v)m(e)i(the)f(follo)m(wing)e(set)i(of)g(input)d(parameters)j
+(\(the)0 2156 y(function)29 b(can)i(b)s(e)e(giv)m(en)i(an)m(y)g
+(desired)d(name\):)95 2429 y Fe(int)47 b(user_fn\()f(long)h(totaln,)e
+(long)i(offset,)f(long)g(firstn,)g(long)h(nvalues,)716
+2542 y(int)g(narrays,)e(iteratorCol)g(*data,)94 b(void)47
+b(*userPointer)d(\))136 2815 y Fc(\017)i Fj(totaln)23
+b({)g(the)f(total)i(n)m(um)m(b)s(er)d(of)h(table)h(ro)m(ws)f(or)g
+(image)h(pixels)e(that)i(will)c(b)s(e)j(passed)g(to)h(the)g(w)m(ork)f
+(function)227 2928 y(during)28 b(1)j(or)g(more)f(iterations.)136
+3129 y Fc(\017)46 b Fj(o\013set)d({)f(the)h(o\013set)f(applied)e(to)j
+(the)f(\014rst)f(table)h(ro)m(w)g(or)g(image)g(pixel)e(to)j(b)s(e)e
+(passed)g(to)i(the)f(w)m(ork)227 3241 y(function.)54
+b(In)34 b(other)i(w)m(ords,)g(this)e(is)g(the)h(n)m(um)m(b)s(er)f(of)h
+(ro)m(ws)h(or)f(pixels)e(that)j(are)f(skipp)s(ed)e(o)m(v)m(er)j(b)s
+(efore)227 3354 y(starting)29 b(the)h(iterations.)40
+b(If)28 b(o\013set)j(=)e(0,)h(then)f(all)f(the)h(table)h(ro)m(ws)f(or)g
+(image)h(pixels)d(will)g(b)s(e)h(passed)h(to)227 3467
+y(the)i(w)m(ork)f(function.)136 3668 y Fc(\017)46 b Fj(\014rstn)26
+b({)i(the)f(n)m(um)m(b)s(er)f(of)i(the)f(\014rst)g(table)g(ro)m(w)g(or)
+g(image)h(pixel)d(\(starting)j(with)e(1\))i(that)f(is)g(b)s(eing)e
+(passed)227 3781 y(in)k(this)h(particular)e(call)i(to)h(the)g(w)m(ork)f
+(function.)136 3982 y Fc(\017)46 b Fj(n)m(v)-5 b(alues)34
+b({)h(the)f(n)m(um)m(b)s(er)g(of)g(table)g(ro)m(ws)h(or)f(image)h
+(pixels)d(that)j(are)g(b)s(eing)e(passed)h(in)f(this)h(particular)227
+4095 y(call)g(to)i(the)f(w)m(ork)f(function.)53 b(n)m(v)-5
+b(alues)34 b(will)e(alw)m(a)m(ys)j(b)s(e)f(less)g(than)g(or)h(equal)f
+(to)i(totaln)f(and)f(will)e(ha)m(v)m(e)227 4208 y(the)i(same)f(v)-5
+b(alue)33 b(on)g(eac)m(h)h(iteration,)g(except)g(p)s(ossibly)d(on)i
+(the)g(last)g(call)g(whic)m(h)f(ma)m(y)h(ha)m(v)m(e)i(a)e(smaller)227
+4321 y(v)-5 b(alue.)136 4522 y Fc(\017)46 b Fj(narra)m(ys)31
+b({)g(the)g(n)m(um)m(b)s(er)f(of)h(arra)m(ys)g(of)g(data)h(that)f(are)g
+(b)s(eing)f(passed)g(to)i(the)f(w)m(ork)g(function.)41
+b(There)30 b(is)227 4635 y(one)h(arra)m(y)g(for)f(eac)m(h)i(image)e(or)
+g(table)h(column.)136 4835 y Fc(\017)46 b Fj(*data)31
+b({)e(arra)m(y)h(of)f(structures,)g(one)h(for)f(eac)m(h)h(column)e(or)h
+(image.)41 b(Eac)m(h)29 b(structure)g(con)m(tains)g(a)h(p)s(oin)m(ter)
+227 4948 y(to)h(the)g(arra)m(y)g(of)f(data)h(as)g(w)m(ell)e(as)i(other)
+g(descriptiv)m(e)e(parameters)i(ab)s(out)f(that)h(arra)m(y)-8
+b(.)136 5149 y Fc(\017)46 b Fj(*userP)m(oin)m(ter)25
+b({)h(a)f(user)f(supplied)e(p)s(oin)m(ter)i(that)i(can)f(b)s(e)f(used)h
+(to)g(pass)g(ancillary)e(information)g(from)i(the)227
+5262 y(driv)m(er)g(function)g(to)h(the)g(w)m(ork)g(function.)38
+b(This)24 b(p)s(oin)m(ter)h(is)g(passed)h(to)g(the)h(CFITSIO)d
+(iterator)i(function)227 5375 y(whic)m(h)36 b(then)g(passes)g(it)g(on)h
+(to)g(the)f(w)m(ork)h(function)e(without)h(an)m(y)h(mo)s(di\014cation.)
+57 b(It)37 b(ma)m(y)g(p)s(oin)m(t)e(to)j(a)227 5488 y(single)27
+b(n)m(um)m(b)s(er,)h(to)h(an)f(arra)m(y)h(of)g(v)-5 b(alues,)28
+b(to)h(a)g(structure)f(con)m(taining)g(an)g(arbitrary)f(set)i(of)g
+(parameters)227 5601 y(of)e(di\013eren)m(t)g(t)m(yp)s(es,)h(or)f(it)g
+(ma)m(y)g(b)s(e)g(a)g(n)m(ull)e(p)s(oin)m(ter)h(if)g(it)h(is)f(not)h
+(needed.)40 b(The)26 b(w)m(ork)h(function)f(m)m(ust)h(cast)227
+5714 y(this)j(p)s(oin)m(ter)f(to)i(the)g(appropriate)e(data)i(t)m(yp)s
+(e)g(b)s(efore)f(using)e(it)i(it.)p eop
+%%Page: 65 73
+65 72 bop 0 299 a Fh(6.1.)72 b(THE)30 b(ITERA)-8 b(TOR)30
+b(W)m(ORK)g(FUNCTION)2021 b Fj(65)0 555 y(The)23 b(totaln,)j(o\013set,)
+h(narra)m(ys,)e(data,)h(and)d(userP)m(oin)m(ter)h(parameters)g(are)g
+(guaran)m(teed)h(to)g(ha)m(v)m(e)g(the)f(same)g(v)-5
+b(alue)0 668 y(on)35 b(eac)m(h)i(iteration.)55 b(Only)33
+b(\014rstn,)j(n)m(v)-5 b(alues,)36 b(and)e(the)i(arra)m(ys)f(of)h(data)
+g(p)s(oin)m(ted)e(to)i(b)m(y)f(the)h(data)g(structures)0
+781 y(ma)m(y)31 b(c)m(hange)g(on)g(eac)m(h)g(iterativ)m(e)g(call)f(to)h
+(the)f(w)m(ork)h(function.)0 941 y(Note)43 b(that)g(the)f(iterator)g
+(treats)h(an)f(image)g(as)g(a)g(long)g(1-D)h(arra)m(y)f(of)h(pixels)d
+(regardless)h(of)h(it's)g(in)m(trinsic)0 1054 y(dimensionalit)m(y)-8
+b(.)48 b(The)33 b(total)i(n)m(um)m(b)s(er)d(of)i(pixels)e(is)h(just)g
+(the)h(pro)s(duct)e(of)i(the)g(size)g(of)f(eac)m(h)i(dimension,)e(and)0
+1167 y(the)g(order)g(of)g(the)g(pixels)e(is)h(the)h(same)g(as)g(the)h
+(order)e(that)h(they)h(are)f(stored)g(in)f(the)h(FITS)f(\014le.)47
+b(If)33 b(the)g(w)m(ork)0 1280 y(function)26 b(needs)h(to)h(kno)m(w)f
+(the)h(n)m(um)m(b)s(er)e(and)h(size)g(of)h(the)f(image)h(dimensions)c
+(then)j(these)h(parameters)g(can)g(b)s(e)0 1393 y(passed)i(via)g(the)g
+(userP)m(oin)m(ter)h(structure.)0 1553 y(The)f(iteratorCol)g(structure)
+g(is)f(curren)m(tly)h(de\014ned)f(as)h(follo)m(ws:)0
+1780 y Fe(typedef)46 b(struct)94 b(/*)47 b(structure)e(for)i(the)g
+(iterator)e(function)h(column)g(information)f(*/)0 1893
+y({)143 2005 y(/*)i(structure)f(elements)f(required)h(as)h(input)f(to)h
+(fits_iterate_data:)c(*/)95 2231 y(fitsfile)j(*fptr;)332
+b(/*)48 b(pointer)d(to)j(the)f(HDU)f(containing)f(the)i(column)f(or)i
+(image)e(*/)95 2344 y(int)286 b(colnum;)e(/*)48 b(column)e(number)g(in)
+h(the)g(table;)f(ignored)g(for)h(images)189 b(*/)95 2457
+y(char)238 b(colname[70];)44 b(/*)k(name)e(\(TTYPEn\))g(of)h(the)g
+(column;)f(null)g(for)h(images)285 b(*/)95 2570 y(int)h(datatype;)188
+b(/*)48 b(output)e(data)g(type)h(\(converted)e(if)i(necessary\))e(*/)95
+2683 y(int)286 b(iotype;)e(/*)48 b(type:)e(InputCol,)f(InputOutputCol,)
+f(or)j(OutputCol)e(*/)95 2909 y(/*)j(output)e(structure)f(elements)h
+(that)g(may)h(be)g(useful)f(for)h(the)g(work)g(function:)e(*/)95
+3135 y(void)238 b(*array;)189 b(/*)47 b(pointer)f(to)h(the)g(array)f
+(\(and)h(the)g(null)g(value\))f(*/)95 3247 y(long)238
+b(repeat;)189 b(/*)47 b(binary)f(table)h(vector)f(repeat)g(value;)g
+(set)238 b(*/)1050 3360 y(/*)g(equal)46 b(to)i(1)f(for)g(images)810
+b(*/)95 3473 y(long)238 b(tlmin;)f(/*)47 b(legal)g(minimum)e(data)i
+(value,)f(if)h(any)477 b(*/)95 3586 y(long)238 b(tlmax;)f(/*)47
+b(legal)g(maximum)e(data)i(value,)f(if)h(any)477 b(*/)95
+3699 y(char)238 b(unit[70];)93 b(/*)47 b(physical)f(unit)g(string)g
+(\(BUNIT)h(or)g(TUNITn\))189 b(*/)95 3812 y(char)238
+b(tdisp[70];)45 b(/*)i(suggested)e(display)h(format;)g(null)h(if)g
+(none)190 b(*/)0 4038 y(})47 b(iteratorCol;)0 4264 y
+Fj(Instead)34 b(of)g(directly)e(reading)h(or)h(writing)e(the)h(elemen)m
+(ts)i(in)d(this)h(structure,)h(it)g(is)e(recommended)i(that)g(pro-)0
+4377 y(grammers)c(use)g(the)h(access)h(functions)c(that)j(are)g(pro)m
+(vided)e(for)h(this)g(purp)s(ose.)0 4538 y(The)25 b(\014rst)g(\014v)m
+(e)h(elemen)m(ts)g(in)f(this)f(structure)i(m)m(ust)f(b)s(e)g(initially)
+e(de\014ned)h(b)m(y)i(the)g(driv)m(er)e(routine)h(b)s(efore)g(calling)0
+4650 y(the)f(iterator)g(routine.)37 b(The)23 b(CFITSIO)f(iterator)i
+(routine)f(uses)g(this)f(information)g(to)i(determine)f(what)g(column)0
+4763 y(or)32 b(arra)m(y)h(to)h(pass)e(to)h(the)g(w)m(ork)f(function,)g
+(and)g(whether)g(the)g(arra)m(y)h(is)f(to)h(b)s(e)f(input)f(to)i(the)f
+(w)m(ork)h(function,)0 4876 y(output)g(from)g(the)h(w)m(ork)f
+(function,)g(or)h(b)s(oth.)49 b(The)33 b(CFITSIO)f(iterator)h(function)
+f(\014lls)g(in)g(the)h(v)-5 b(alues)33 b(of)h(the)0 4989
+y(remaining)28 b(structure)i(elemen)m(ts)h(b)s(efore)f(passing)f(it)h
+(to)h(the)g(w)m(ork)f(function.)0 5149 y(The)d(arra)m(y)g(structure)g
+(elemen)m(t)h(is)e(a)h(p)s(oin)m(ter)f(to)i(the)g(actual)f(data)h(arra)
+m(y)g(and)e(it)h(m)m(ust)g(b)s(e)f(cast)j(to)e(the)h(correct)0
+5262 y(data)k(t)m(yp)s(e)f(b)s(efore)f(it)h(is)f(used.)41
+b(The)31 b(`rep)s(eat')g(structure)g(elemen)m(t)g(giv)m(e)g(the)h(n)m
+(um)m(b)s(er)d(of)i(data)h(v)-5 b(alues)30 b(in)g(eac)m(h)0
+5375 y(ro)m(w)g(of)g(the)g(table,)h(so)f(that)h(the)f(total)h(n)m(um)m
+(b)s(er)d(of)i(data)h(v)-5 b(alues)29 b(in)g(the)h(arra)m(y)h(is)e(giv)
+m(en)h(b)m(y)g(rep)s(eat)g(*)g(n)m(v)-5 b(alues.)0 5488
+y(In)36 b(the)g(case)i(of)e(image)h(arra)m(ys)g(and)e(ASCI)s(I)g
+(tables,)j(rep)s(eat)f(will)d(alw)m(a)m(ys)i(b)s(e)g(equal)g(to)h(1.)59
+b(When)37 b(the)f(data)0 5601 y(t)m(yp)s(e)k(is)e(a)i(c)m(haracter)h
+(string,)g(the)f(arra)m(y)g(p)s(oin)m(ter)e(is)h(actually)g(a)h(p)s
+(oin)m(ter)e(to)j(an)e(arra)m(y)h(of)g(string)e(p)s(oin)m(ters)0
+5714 y(\(i.e.,)30 b(c)m(har)f(**arra)m(y\).)42 b(The)29
+b(other)g(output)g(structure)f(elemen)m(ts)i(are)f(pro)m(vided)f(for)g
+(con)m(v)m(enience)j(in)c(case)j(that)p eop
+%%Page: 66 74
+66 73 bop 0 299 a Fj(66)1455 b Fh(CHAPTER)30 b(6.)112
+b(THE)30 b(CFITSIO)e(ITERA)-8 b(TOR)30 b(FUNCTION)0 555
+y Fj(information)k(is)h(needed)g(within)e(the)j(w)m(ork)g(function.)55
+b(An)m(y)35 b(other)h(information)e(ma)m(y)i(b)s(e)f(passed)h(from)f
+(the)0 668 y(driv)m(er)29 b(routine)h(to)h(the)f(w)m(ork)h(function)e
+(via)h(the)g(userP)m(oin)m(ter)g(parameter.)0 828 y(Up)s(on)h
+(completion,)h(the)g(w)m(ork)h(routine)e(m)m(ust)h(return)f(an)h(in)m
+(teger)g(status)g(v)-5 b(alue,)33 b(with)d(0)j(indicating)d(success)0
+941 y(and)h(an)m(y)g(other)g(v)-5 b(alue)31 b(indicating)e(an)i(error)g
+(whic)m(h)f(will)e(cause)k(the)f(iterator)h(function)e(to)i
+(immediately)d(exit)0 1054 y(at)e(that)f(p)s(oin)m(t.)38
+b(Return)25 b(status)i(v)-5 b(alues)25 b(in)f(the)i(range)h(1)f({)g
+(1000)i(should)23 b(b)s(e)j(a)m(v)m(oided)g(since)f(these)i(are)f
+(reserv)m(ed)0 1167 y(for)d(use)g(b)m(y)h(CFITSIO.)e(A)i(return)e
+(status)i(v)-5 b(alue)23 b(of)h(-1)g(ma)m(y)g(b)s(e)f(used)f(to)j
+(force)f(the)f(CFITSIO)f(iterator)i(function)0 1280 y(to)j(stop)g(at)g
+(that)h(p)s(oin)m(t)d(and)h(return)g(con)m(trol)h(to)g(the)g(driv)m(er)
+e(routine)h(after)h(writing)d(an)m(y)j(output)f(arra)m(ys)h(to)h(the)0
+1393 y(FITS)e(\014le.)39 b(CFITSIO)26 b(do)s(es)g(not)i(considered)e
+(this)g(to)i(b)s(e)e(an)h(error)g(condition,)g(so)g(an)m(y)g(further)f
+(pro)s(cessing)g(b)m(y)0 1506 y(the)31 b(application)d(program)i(will)e
+(con)m(tin)m(ue)j(normally)-8 b(.)0 1837 y Ff(6.2)135
+b(The)45 b(Iterator)h(Driv)l(er)g(F)-11 b(unction)0 2087
+y Fj(The)33 b(iterator)g(driv)m(er)f(function)g(m)m(ust)i(op)s(en)e
+(the)i(necessary)f(FITS)g(\014les)f(and)h(p)s(osition)e(them)i(to)h
+(the)g(correct)0 2200 y(HDU.)23 b(It)f(m)m(ust)g(also)h(initialize)c
+(the)j(follo)m(wing)f(parameters)h(in)f(the)i(iteratorCol)f(structure)f
+(\(de\014ned)g(ab)s(o)m(v)m(e\))j(for)0 2313 y(eac)m(h)31
+b(column)e(or)h(image)g(b)s(efore)f(calling)g(the)h(CFITSIO)e(iterator)
+i(function.)39 b(Sev)m(eral)30 b(`constructor')h(routines)0
+2426 y(are)g(pro)m(vided)e(in)g(CFITSIO)g(for)h(this)f(purp)s(ose.)136
+2670 y Fc(\017)46 b Fj(*fptr)30 b({)h(The)f(\014ts\014le)f(p)s(oin)m
+(ter)g(to)j(the)e(table)g(or)h(image.)136 2853 y Fc(\017)46
+b Fj(coln)m(um)29 b({)g(the)h(n)m(um)m(b)s(er)e(of)h(the)h(column)e(in)
+g(the)h(table.)41 b(This)27 b(v)-5 b(alue)29 b(is)f(ignored)g(in)g(the)
+i(case)g(of)g(images.)227 2966 y(If)j(coln)m(um)g(equals)g(0,)h(then)g
+(the)f(column)f(name)i(will)c(b)s(e)j(used)g(to)h(iden)m(tify)e(the)h
+(column)g(to)h(b)s(e)e(passed)227 3079 y(to)f(the)g(w)m(ork)f
+(function.)136 3261 y Fc(\017)46 b Fj(colname)31 b({)f(the)g(name)h
+(\(TTYPEn)e(k)m(eyw)m(ord\))i(of)f(the)h(column.)39 b(This)28
+b(is)i(only)f(required)f(if)h(coln)m(um)h(=)g(0)227 3374
+y(and)g(is)f(ignored)h(for)g(images.)136 3556 y Fc(\017)46
+b Fj(datat)m(yp)s(e)29 b({)g(The)e(desired)g(data)h(t)m(yp)s(e)g(of)h
+(the)f(arra)m(y)g(to)h(b)s(e)e(passed)h(to)h(the)f(w)m(ork)g(function.)
+39 b(F)-8 b(or)28 b(n)m(umer-)227 3669 y(ical)f(data)h(the)f(data)h(t)m
+(yp)s(e)g(do)s(es)f(not)g(need)g(to)h(b)s(e)f(the)g(same)h(as)f(the)h
+(actual)f(data)h(t)m(yp)s(e)g(in)e(the)h(FITS)g(\014le,)227
+3782 y(in)g(whic)m(h)h(case)h(CFITSIO)e(will)f(do)j(the)f(con)m(v)m
+(ersion.)41 b(Allo)m(w)m(ed)28 b(v)-5 b(alues)28 b(are:)40
+b(TSTRING,)28 b(TLOGICAL,)227 3895 y(TBYTE,)37 b(TSBYTE,)f(TSHOR)-8
+b(T,)36 b(TUSHOR)-8 b(T,)37 b(TINT,)f(TLONG,)h(TULONG,)f(TFLO)m(A)-8
+b(T,)38 b(TDOU-)227 4008 y(BLE.)33 b(If)g(the)g(input)e(v)-5
+b(alue)32 b(of)h(data)h(t)m(yp)s(e)f(equals)f(0,)j(then)d(the)h
+(existing)f(data)i(t)m(yp)s(e)f(of)g(the)g(column)f(or)227
+4121 y(image)f(will)d(b)s(e)h(used)h(without)f(an)m(y)i(con)m(v)m
+(ersion.)136 4303 y Fc(\017)46 b Fj(iot)m(yp)s(e)36 b({)g(de\014nes)e
+(whether)h(the)h(data)g(arra)m(y)g(is)f(to)h(b)s(e)f(input)f(to)i(the)g
+(w)m(ork)f(function)g(\(i.e,)i(read)e(from)227 4416 y(the)42
+b(FITS)e(\014le\),)j(or)e(output)g(from)g(the)g(w)m(ork)g(function)f
+(\(i.e.,)k(written)c(to)i(the)f(FITS)g(\014le\))f(or)h(b)s(oth.)227
+4529 y(Allo)m(w)m(ed)28 b(v)-5 b(alues)28 b(are)g(InputCol,)f
+(OutputCol,)h(or)g(InputOutputCol.)37 b(V)-8 b(ariable-length)27
+b(arra)m(y)i(columns)227 4642 y(are)h(supp)s(orted)e(as)i(InputCol)d
+(or)j(InputOutputCol)c(t)m(yp)s(es,)k(but)f(ma)m(y)h(not)g(b)s(e)e
+(used)h(for)g(an)h(OutputCol)227 4755 y(t)m(yp)s(e.)0
+4999 y(After)h(the)f(driv)m(er)f(routine)g(has)h(initialized)e(all)h
+(these)h(parameters,)h(it)f(can)h(then)f(call)f(the)i(CFITSIO)e
+(iterator)0 5112 y(function:)95 5357 y Fe(int)47 b
+(fits_iterate_data\(int)42 b(narrays,)k(iteratorCol)f(*data,)h(long)g
+(offset,)286 5470 y(long)h(nPerLoop,)e(int)i(\(*workFn\)\()e(\),)i
+(void)g(*userPointer,)d(int)j(*status\);)136 5714 y Fc(\017)f
+Fj(narra)m(ys)31 b({)f(the)h(n)m(um)m(b)s(er)e(of)h(columns)f(or)i
+(images)f(that)h(are)g(to)g(b)s(e)f(passed)g(to)h(the)f(w)m(ork)h
+(function.)p eop
+%%Page: 67 75
+67 74 bop 0 299 a Fh(6.3.)72 b(GUIDELINES)30 b(F)m(OR)h(USING)f(THE)g
+(ITERA)-8 b(TOR)30 b(FUNCTION)1200 b Fj(67)136 555 y
+Fc(\017)46 b Fj(*data)32 b({)f(p)s(oin)m(ter)e(to)i(arra)m(y)g(of)f
+(structures)g(con)m(taining)g(information)f(ab)s(out)h(eac)m(h)h
+(column)f(or)g(image.)136 736 y Fc(\017)46 b Fj(o\013set)31
+b({)f(if)e(p)s(ositiv)m(e,)h(this)g(n)m(um)m(b)s(er)f(of)i(ro)m(ws)f
+(at)h(the)g(b)s(eginning)d(of)j(the)f(table)h(\(or)g(pixels)d(in)i(the)
+g(image\))227 849 y(will)f(b)s(e)i(skipp)s(ed)e(and)h(will)f(not)j(b)s
+(e)e(passed)h(to)h(the)g(w)m(ork)f(function.)136 1030
+y Fc(\017)46 b Fj(nP)m(erLo)s(op)38 b(-)h(sp)s(eci\014es)d(the)j(n)m
+(um)m(b)s(er)e(of)h(table)g(ro)m(ws)h(\(or)f(n)m(um)m(b)s(er)f(of)i
+(image)f(pixels\))f(that)i(are)g(to)g(b)s(e)227 1143
+y(passed)29 b(to)h(the)f(w)m(ork)h(function)d(on)i(eac)m(h)i
+(iteration.)40 b(If)28 b(nP)m(erLo)s(op)h(=)g(0)g(then)g(CFITSIO)f
+(will)f(calculate)227 1256 y(the)22 b(optim)m(um)f(n)m(um)m(b)s(er)f
+(for)h(greatest)j(e\016ciency)-8 b(.)38 b(If)21 b(nP)m(erLo)s(op)g(is)g
+(negativ)m(e,)k(then)c(all)g(the)h(ro)m(ws)f(or)h(pixels)227
+1368 y(will)33 b(b)s(e)i(passed)g(at)h(one)g(time,)h(and)d(the)i(w)m
+(ork)g(function)e(will)f(only)h(b)s(e)h(called)g(once.)56
+b(If)35 b(an)m(y)h(v)-5 b(ariable)227 1481 y(length)32
+b(arra)m(ys)h(are)g(b)s(eing)e(pro)s(cessed,)i(then)g(the)f(nP)m(erLo)s
+(op)h(v)-5 b(alue)32 b(is)f(ignored,)i(and)f(the)h(iterator)g(will)227
+1594 y(alw)m(a)m(ys)e(pro)s(cess)f(one)h(ro)m(w)f(of)h(the)f(table)h
+(at)g(a)g(time.)136 1775 y Fc(\017)46 b Fj(*w)m(orkFn)f(-)f(the)h(name)
+f(\(actually)g(the)h(address\))f(of)g(the)g(w)m(ork)h(function)e(that)i
+(is)e(to)i(b)s(e)f(called)f(b)m(y)227 1888 y(\014ts)p
+354 1888 28 4 v 33 w(iterate)p 644 1888 V 33 w(data.)136
+2069 y Fc(\017)j Fj(*userP)m(oin)m(ter)33 b(-)g(this)f(is)g(a)h(user)f
+(supplied)e(p)s(oin)m(ter)i(that)h(can)g(b)s(e)g(used)f(to)h(pass)g
+(ancillary)e(information)227 2182 y(from)i(the)g(driv)m(er)f(routine)g
+(to)i(the)f(w)m(ork)g(function.)47 b(It)33 b(ma)m(y)h(p)s(oin)m(t)e(to)
+i(a)f(single)f(n)m(um)m(b)s(er,)g(an)h(arra)m(y)-8 b(,)35
+b(or)227 2295 y(to)c(a)g(structure)f(con)m(taining)g(an)g(arbitrary)f
+(set)i(of)g(parameters.)136 2476 y Fc(\017)46 b Fj(*status)30
+b(-)f(The)f(CFITSIO)f(error)h(status.)41 b(Should)26
+b(=)i(0)h(on)g(input;)e(a)i(non-zero)h(output)e(v)-5
+b(alue)28 b(indicates)227 2588 y(an)j(error.)0 2828 y(When)f(\014ts)p
+392 2828 V 32 w(iterate)p 681 2828 V 34 w(data)h(is)e(called)g(it)g
+(\014rst)h(allo)s(cates)g(memory)g(to)h(hold)d(all)h(the)h(requested)g
+(columns)f(of)h(data)0 2941 y(or)f(image)h(pixel)d(arra)m(ys.)41
+b(It)29 b(then)g(reads)g(the)h(input)d(data)j(from)f(the)g(FITS)f
+(tables)h(or)h(images)f(in)m(to)g(the)h(arra)m(ys)0 3054
+y(then)h(passes)h(the)g(structure)f(with)f(p)s(oin)m(ters)h(to)h(these)
+g(data)h(arra)m(ys)f(to)g(the)g(w)m(ork)g(function.)43
+b(After)32 b(the)g(w)m(ork)0 3167 y(function)k(returns,)h(the)h
+(iterator)f(function)f(writes)g(an)m(y)h(output)g(columns)e(of)i(data)h
+(or)f(images)g(bac)m(k)h(to)g(the)0 3279 y(FITS)31 b(\014les.)45
+b(It)32 b(then)g(rep)s(eats)g(this)f(pro)s(cess)h(for)f(an)m(y)i
+(remaining)d(sets)i(of)h(ro)m(ws)f(or)g(image)g(pixels)e(un)m(til)h(it)
+g(has)0 3392 y(pro)s(cessed)c(the)i(en)m(tire)f(table)f(or)h(image)h
+(or)f(un)m(til)e(the)i(w)m(ork)g(function)f(returns)g(a)h(non-zero)h
+(status)f(v)-5 b(alue.)39 b(The)0 3505 y(iterator)32
+b(then)g(frees)g(the)h(memory)e(that)i(it)f(initially)c(allo)s(cated)k
+(and)g(returns)f(con)m(trol)h(to)h(the)f(driv)m(er)f(routine)0
+3618 y(that)g(called)f(it.)0 3949 y Ff(6.3)135 b(Guidelines)46
+b(for)f(Using)h(the)f(Iterator)h(F)-11 b(unction)0 4199
+y Fj(The)34 b(totaln,)h(o\013set,)i(\014rstn,)d(and)f(n)m(v)-5
+b(alues)34 b(parameters)g(that)h(are)f(passed)g(to)h(the)f(w)m(ork)g
+(function)f(are)i(useful)0 4312 y(for)f(determining)e(ho)m(w)i(m)m(uc)m
+(h)g(of)h(the)f(data)h(has)f(b)s(een)f(pro)s(cessed)h(and)f(ho)m(w)h(m)
+m(uc)m(h)g(remains)f(left)h(to)h(do.)52 b(On)0 4425 y(the)36
+b(v)m(ery)h(\014rst)f(call)f(to)i(the)f(w)m(ork)h(function)e(\014rstn)g
+(will)e(b)s(e)j(equal)g(to)h(o\013set)g(+)f(1;)k(the)c(w)m(ork)g
+(function)f(ma)m(y)0 4538 y(need)c(to)g(p)s(erform)f(v)-5
+b(arious)30 b(initialization)d(tasks)32 b(b)s(efore)e(starting)h(to)g
+(pro)s(cess)g(the)g(data.)43 b(Similarly)-8 b(,)28 b(\014rstn)h(+)0
+4650 y(n)m(v)-5 b(alues)28 b(-)g(1)h(will)c(b)s(e)j(equal)f(to)i
+(totaln)g(on)f(the)g(last)g(iteration,)h(at)g(whic)m(h)e(p)s(oin)m(t)g
+(the)h(w)m(ork)h(function)d(ma)m(y)j(need)0 4763 y(to)k(p)s(erform)f
+(some)h(clean)g(up)e(op)s(erations)h(b)s(efore)h(exiting)f(for)g(the)h
+(last)g(time.)47 b(The)33 b(w)m(ork)f(function)g(can)h(also)0
+4876 y(force)e(an)f(early)g(termination)f(of)i(the)g(iterations)e(b)m
+(y)i(returning)d(a)j(status)g(v)-5 b(alue)29 b(=)h(-1.)0
+5036 y(The)f(narra)m(ys)g(and)g(iteratorCol.datat)m(yp)s(e)h(argumen)m
+(ts)g(allo)m(w)e(the)i(w)m(ork)f(function)f(to)i(double)e(c)m(hec)m(k)j
+(that)f(the)0 5149 y(n)m(um)m(b)s(er)k(of)i(input)e(arra)m(ys)i(and)f
+(their)f(data)j(t)m(yp)s(es)e(ha)m(v)m(e)i(the)f(exp)s(ected)g(v)-5
+b(alues.)56 b(The)35 b(iteratorCol.fptr)g(and)0 5262
+y(iteratorCol.coln)m(um)c(structure)g(elemen)m(ts)g(can)h(b)s(e)f(used)
+f(if)h(the)g(w)m(ork)h(function)e(needs)h(to)h(read)f(or)g(write)g(the)
+0 5375 y(v)-5 b(alues)30 b(of)h(other)g(k)m(eyw)m(ords)g(in)f(the)h
+(FITS)f(\014le)g(asso)s(ciated)h(with)f(the)h(arra)m(y)-8
+b(.)43 b(This)29 b(should)g(generally)h(only)g(b)s(e)0
+5488 y(done)k(during)d(the)j(initialization)d(step)i(or)h(during)e(the)
+i(clean)f(up)g(step)h(after)g(the)g(last)g(set)g(of)g(data)g(has)g(b)s
+(een)0 5601 y(pro)s(cessed.)40 b(Extra)29 b(FITS)f(\014le)g(I/O)h
+(during)d(the)j(main)f(pro)s(cessing)g(lo)s(op)g(of)h(the)g(w)m(ork)g
+(function)f(can)h(seriously)0 5714 y(degrade)i(the)f(sp)s(eed)g(of)g
+(the)h(program.)p eop
+%%Page: 68 76
+68 75 bop 0 299 a Fj(68)1455 b Fh(CHAPTER)30 b(6.)112
+b(THE)30 b(CFITSIO)e(ITERA)-8 b(TOR)30 b(FUNCTION)0 555
+y Fj(If)i(v)-5 b(ariable-length)32 b(arra)m(y)h(columns)f(are)h(b)s
+(eing)e(pro)s(cessed,)i(then)g(the)g(iterator)g(will)d(op)s(erate)k(on)
+f(one)g(ro)m(w)g(of)0 668 y(the)j(table)f(at)h(a)g(time.)56
+b(In)34 b(this)h(case)h(the)g(the)f(rep)s(eat)h(elemen)m(t)g(in)e(the)i
+(in)m(teratorCol)f(structure)g(will)e(b)s(e)h(set)0 781
+y(equal)c(to)h(the)g(n)m(um)m(b)s(er)e(of)h(elemen)m(ts)h(in)e(the)i
+(curren)m(t)f(ro)m(w)g(that)h(is)f(b)s(eing)f(pro)s(cessed.)0
+941 y(One)k(imp)s(ortan)m(t)f(feature)i(of)f(the)h(iterator)g(is)e
+(that)i(the)f(\014rst)g(elemen)m(t)h(in)e(eac)m(h)i(arra)m(y)g(that)g
+(is)e(passed)h(to)h(the)0 1054 y(w)m(ork)f(function)f(giv)m(es)h(the)g
+(v)-5 b(alue)32 b(that)i(is)e(used)g(to)h(represen)m(t)g(n)m(ull)e(or)i
+(unde\014ned)d(v)-5 b(alues)33 b(in)e(the)i(arra)m(y)-8
+b(.)49 b(The)0 1167 y(real)40 b(data)h(then)g(b)s(egins)e(with)g(the)h
+(second)h(elemen)m(t)g(of)g(the)f(arra)m(y)h(\(i.e.,)j(arra)m(y[1],)h
+(not)c(arra)m(y[0]\).)73 b(If)40 b(the)0 1280 y(\014rst)e(arra)m(y)h
+(elemen)m(t)g(is)f(equal)g(to)h(zero,)j(then)c(this)f(indicates)h(that)
+h(all)f(the)g(arra)m(y)h(elemen)m(ts)g(ha)m(v)m(e)h(de\014ned)0
+1393 y(v)-5 b(alues)32 b(and)g(there)h(are)g(no)g(unde\014ned)d(v)-5
+b(alues.)47 b(If)33 b(arra)m(y[0])h(is)e(not)h(equal)f(to)h(zero,)i
+(then)d(this)g(indicates)f(that)0 1506 y(some)j(of)g(the)g(data)h(v)-5
+b(alues)33 b(are)h(unde\014ned)d(and)j(this)e(v)-5 b(alue)34
+b(\(arra)m(y[0]\))i(is)c(used)h(to)i(represen)m(t)f(them.)51
+b(In)33 b(the)0 1619 y(case)i(of)e(output)g(arra)m(ys)h(\(i.e.,)h
+(those)f(arra)m(ys)g(that)g(will)d(b)s(e)i(written)f(bac)m(k)i(to)h
+(the)e(FITS)g(\014le)f(b)m(y)i(the)g(iterator)0 1732
+y(function)g(after)j(the)f(w)m(ork)f(function)g(exits\))h(the)g(w)m
+(ork)g(function)e(m)m(ust)i(set)g(the)g(\014rst)f(arra)m(y)h(elemen)m
+(t)g(to)h(the)0 1844 y(desired)f(n)m(ull)f(v)-5 b(alue)36
+b(if)g(necessary)-8 b(,)40 b(otherwise)d(the)g(\014rst)g(elemen)m(t)g
+(should)e(b)s(e)i(set)g(to)h(zero)g(to)g(indicate)e(that)0
+1957 y(there)30 b(are)h(no)e(n)m(ull)f(v)-5 b(alues)30
+b(in)e(the)i(output)g(arra)m(y)-8 b(.)42 b(CFITSIO)28
+b(de\014nes)h(2)h(v)-5 b(alues,)30 b(FLO)m(A)-8 b(TNULL)e(V)g(ALUE)31
+b(and)0 2070 y(DOUBLENULL)-10 b(V)g(ALUE,)37 b(that)f(can)h(b)s(e)e
+(used)g(as)i(default)e(n)m(ull)f(v)-5 b(alues)35 b(for)h(\015oat)h(and)
+e(double)g(data)i(t)m(yp)s(es,)0 2183 y(resp)s(ectiv)m(ely)-8
+b(.)58 b(In)35 b(the)i(case)g(of)f(c)m(haracter)i(string)d(data)i(t)m
+(yp)s(es,)h(a)e(n)m(ull)f(string)g(is)g(alw)m(a)m(ys)i(used)e(to)i
+(represen)m(t)0 2296 y(unde\014ned)28 b(strings.)0 2456
+y(In)33 b(some)h(applications)d(it)i(ma)m(y)h(b)s(e)f(necessary)h(to)g
+(recursiv)m(ely)e(call)h(the)h(iterator)g(function.)49
+b(An)33 b(example)g(of)0 2569 y(this)26 b(is)g(giv)m(en)h(b)m(y)g(one)h
+(of)f(the)h(example)e(programs)h(that)h(is)e(distributed)e(with)i
+(CFITSIO:)g(it)h(\014rst)f(calls)g(a)i(w)m(ork)0 2682
+y(function)37 b(that)h(writes)g(out)g(a)g(2D)h(histogram)f(image.)64
+b(That)38 b(w)m(ork)g(function)f(in)f(turn)h(calls)h(another)g(w)m(ork)
+0 2795 y(function)28 b(that)i(reads)g(the)f(`X')i(and)e(`Y')h(columns)e
+(in)g(a)i(table)g(to)g(calculate)g(the)f(v)-5 b(alue)30
+b(of)f(eac)m(h)i(2D)f(histogram)0 2908 y(image)h(pixel.)39
+b(Graphically)-8 b(,)29 b(the)h(program)g(structure)g(can)h(b)s(e)f
+(describ)s(ed)e(as:)48 3153 y Fe(driver)46 b(-->)h(iterator)e(-->)i
+(work1_fn)f(-->)h(iterator)e(-->)i(work2_fn)0 3399 y
+Fj(Finally)-8 b(,)39 b(it)f(should)e(b)s(e)i(noted)g(that)h(the)g
+(table)f(columns)f(or)h(image)h(arra)m(ys)g(that)g(are)f(passed)g(to)h
+(the)g(w)m(ork)0 3512 y(function)34 b(do)i(not)g(all)e(ha)m(v)m(e)j(to)
+f(come)h(from)e(the)h(same)g(FITS)f(\014le)f(and)h(instead)g(ma)m(y)h
+(come)h(from)e(an)m(y)h(com-)0 3625 y(bination)31 b(of)i(sources)g(as)h
+(long)e(as)i(they)f(ha)m(v)m(e)h(the)f(same)h(length.)48
+b(The)32 b(length)h(of)g(the)g(\014rst)f(table)h(column)f(or)0
+3738 y(image)f(arra)m(y)g(is)e(used)g(b)m(y)i(the)f(iterator)h(if)e
+(they)i(do)f(not)h(all)e(ha)m(v)m(e)j(the)e(same)h(length.)0
+4069 y Ff(6.4)135 b(Complete)47 b(List)e(of)g(Iterator)i(Routines)0
+4319 y Fj(All)34 b(of)h(the)g(iterator)g(routines)f(are)h(listed)f(b)s
+(elo)m(w.)53 b(Most)36 b(of)f(these)h(routines)d(do)i(not)g(ha)m(v)m(e)
+i(a)e(corresp)s(onding)0 4432 y(short)30 b(function)f(name.)0
+4678 y Fi(1)81 b Fj(Iterator)32 b(`constructor')h(functions)d(that)j
+(set)f(the)g(v)-5 b(alue)31 b(of)h(elemen)m(ts)g(in)f(the)h
+(iteratorCol)f(structure)g(that)227 4791 y(de\014ne)k(the)h(columns)e
+(or)i(arra)m(ys.)56 b(These)36 b(set)g(the)g(\014ts\014le)e(p)s(oin)m
+(ter,)i(column)e(name,)k(column)c(n)m(um)m(b)s(er,)227
+4904 y(datat)m(yp)s(e,)28 b(and)e(iot)m(yp)s(e,)h(resp)s(ectiv)m(ely)-8
+b(.)39 b(The)25 b(last)h(2)h(routines)e(allo)m(w)g(all)g(the)h
+(parameters)h(to)f(b)s(e)g(set)g(with)227 5017 y(one)31
+b(function)e(call)h(\(one)h(supplies)c(the)k(column)e(name,)i(the)f
+(other)h(the)f(column)f(n)m(um)m(b)s(er\).)95 5262 y
+Fe(int)47 b(fits_iter_set_file\(iterato)o(rCo)o(l)42
+b(*col,)k(fitsfile)g(*fptr\);)95 5488 y(int)h
+(fits_iter_set_colname\(iter)o(ato)o(rCol)41 b(*col,)46
+b(char)h(*colname\);)95 5714 y(int)g(fits_iter_set_colnum\(itera)o(tor)
+o(Col)41 b(*col,)47 b(int)g(colnum\);)p eop
+%%Page: 69 77
+69 76 bop 0 299 a Fh(6.4.)72 b(COMPLETE)29 b(LIST)g(OF)i(ITERA)-8
+b(TOR)29 b(R)m(OUTINES)1638 b Fj(69)95 668 y Fe(int)47
+b(fits_iter_set_datatype\(ite)o(rat)o(orCo)o(l)42 b(*col,)k(int)h
+(datatype\);)95 894 y(int)g(fits_iter_set_iotype\(itera)o(tor)o(Col)41
+b(*col,)47 b(int)g(iotype\);)95 1120 y(int)g
+(fits_iter_set_by_name\(iter)o(ato)o(rCol)41 b(*col,)46
+b(fitsfile)g(*fptr,)477 1233 y(char)h(*colname,)e(int)i(datatype,)93
+b(int)47 b(iotype\);)95 1458 y(int)g(fits_iter_set_by_num\(itera)o(tor)
+o(Col)41 b(*col,)47 b(fitsfile)e(*fptr,)477 1571 y(int)i(colnum,)f(int)
+h(datatype,)93 b(int)47 b(iotype\);)0 1820 y Fi(2)81
+b Fj(Iterator)38 b(`accessor')h(functions)d(that)h(return)g(the)g(v)-5
+b(alue)37 b(of)g(the)g(elemen)m(t)h(in)e(the)h(iteratorCol)g(structure)
+227 1933 y(that)31 b(describ)s(es)e(a)i(particular)d(data)j(column)f
+(or)g(arra)m(y)95 2181 y Fe(fitsfile)46 b(*)h
+(fits_iter_get_file\(iterato)o(rCol)41 b(*col\);)95 2407
+y(char)47 b(*)h(fits_iter_get_colname\(i)o(ter)o(ator)o(Col)41
+b(*col\);)95 2633 y(int)47 b(fits_iter_get_colnum\(itera)o(tor)o(Col)41
+b(*col\);)95 2858 y(int)47 b(fits_iter_get_datatype\(ite)o(rat)o(orCo)o
+(l)42 b(*col\);)95 3084 y(int)47 b(fits_iter_get_iotype\(itera)o(tor)o
+(Col)41 b(*col\);)95 3310 y(void)47 b(*)h(fits_iter_get_array\(ite)o
+(rat)o(orCo)o(l)42 b(*col\);)95 3536 y(long)47 b
+(fits_iter_get_tlmin\(itera)o(tor)o(Col)41 b(*col\);)95
+3762 y(long)47 b(fits_iter_get_tlmax\(itera)o(tor)o(Col)41
+b(*col\);)95 3987 y(long)47 b(fits_iter_get_repeat\(iter)o(ato)o(rCol)
+41 b(*col\);)95 4213 y(char)47 b(*)h(fits_iter_get_tunit\(ite)o(rat)o
+(orCo)o(l)42 b(*col\);)95 4439 y(char)47 b(*)h
+(fits_iter_get_tdisp\(ite)o(rat)o(orCo)o(l)42 b(*col\);)0
+4687 y Fi(3)81 b Fj(The)29 b(CFITSIO)g(iterator)i(function)95
+4936 y Fe(int)47 b(fits_iterate_data\(int)42 b(narrays,)94
+b(iteratorCol)44 b(*data,)i(long)h(offset,)573 5049 y(long)f(nPerLoop,)
+573 5161 y(int)h(\(*workFn\)\()e(long)h(totaln,)g(long)h(offset,)f
+(long)g(firstn,)1289 5274 y(long)g(nvalues,)g(int)h(narrays,)e
+(iteratorCol)g(*data,)1289 5387 y(void)h(*userPointer\),)573
+5500 y(void)g(*userPointer,)573 5613 y(int)h(*status\);)p
+eop
+%%Page: 70 78
+70 77 bop 0 299 a Fj(70)1455 b Fh(CHAPTER)30 b(6.)112
+b(THE)30 b(CFITSIO)e(ITERA)-8 b(TOR)30 b(FUNCTION)p eop
+%%Page: 71 79
+71 78 bop 0 1225 a Fg(Chapter)65 b(7)0 1687 y Fm(Celestial)76
+b(Co)6 b(ordinate)78 b(System)f(Routines)0 2180 y Fj(The)36
+b(FITS)g(comm)m(unit)m(y)g(has)g(adopted)h(a)g(set)g(of)g(k)m(eyw)m
+(ord)g(con)m(v)m(en)m(tions)g(that)g(de\014ne)f(the)h(transformations)0
+2293 y(needed)30 b(to)i(con)m(v)m(ert)g(b)s(et)m(w)m(een)f(pixel)e(lo)s
+(cations)h(in)f(an)i(image)g(and)f(the)g(corresp)s(onding)f(celestial)h
+(co)s(ordinates)0 2406 y(on)25 b(the)h(sky)-8 b(,)27
+b(or)e(more)g(generally)-8 b(,)27 b(that)f(de\014ne)e(w)m(orld)g(co)s
+(ordinates)i(that)f(are)h(to)g(b)s(e)f(asso)s(ciated)h(with)e(an)m(y)i
+(pixel)0 2518 y(lo)s(cation)34 b(in)f(an)i(n-dimensional)c(FITS)j(arra)
+m(y)-8 b(.)54 b(CFITSIO)33 b(is)g(distributed)f(with)h(a)i(couple)e(of)
+i(self-con)m(tained)0 2631 y(W)-8 b(orld)27 b(Co)s(ordinate)f(System)g
+(\(W)m(CS\))i(routines,)f(ho)m(w)m(ev)m(er,)i(these)f(routines)e(DO)h
+(NOT)f(supp)s(ort)f(all)h(the)h(latest)0 2744 y(W)m(CS)38
+b(con)m(v)m(en)m(tions,)j(so)e(it)f(is)f(STR)m(ONGL)-8
+b(Y)38 b(RECOMMENDED)h(that)f(soft)m(w)m(are)i(dev)m(elop)s(ers)d(use)h
+(a)h(more)0 2857 y(robust)30 b(external)g(W)m(CS)g(library)-8
+b(.)39 b(Sev)m(eral)30 b(recommended)g(libraries)e(are:)95
+3094 y Fe(WCSLIB)47 b(-)95 b(supported)45 b(by)i(Mark)g(Calabretta)95
+3207 y(WCSTools)f(-)h(supported)f(by)h(Doug)g(Mink)95
+3320 y(AST)g(library)f(-)i(developed)d(by)i(the)g(U.K.)g(Starlink)e
+(project)0 3556 y Fj(More)30 b(information)d(ab)s(out)i(the)g(W)m(CS)g
+(k)m(eyw)m(ord)h(con)m(v)m(en)m(tions)g(and)e(links)f(to)j(all)e(of)h
+(these)g(W)m(CS)g(libraries)e(can)0 3669 y(b)s(e)j(found)f(on)h(the)h
+(FITS)e(Supp)s(ort)g(O\016ce)h(w)m(eb)g(site)h(at)g(h)m
+(ttp://\014ts.gsfc.nasa.go)m(v)j(under)29 b(the)h(W)m(CS)h(link.)0
+3829 y(The)i(functions)g(pro)m(vided)g(in)f(these)j(external)e(W)m(CS)h
+(libraries)e(will)f(need)j(access)h(to)g(the)f(W)m(CS)g(information)0
+3942 y(con)m(tained)g(in)e(the)i(FITS)f(\014le)g(headers.)51
+b(One)33 b(con)m(v)m(enien)m(t)i(w)m(a)m(y)g(to)f(pass)g(this)e
+(information)g(to)j(the)f(extermal)0 4055 y(library)29
+b(is)g(to)j(use)f(the)g(\014ts)p 942 4055 28 4 v 32 w(hdr2str)f
+(routine)g(in)g(CFITSIO)f(\(de\014ned)h(b)s(elo)m(w\))g(to)i(cop)m(y)g
+(the)f(header)g(k)m(eyw)m(ords)0 4168 y(in)m(to)j(one)f(long)h(string,)
+f(and)g(then)g(pass)g(this)g(string)f(to)j(an)e(in)m(terface)h(routine)
+f(in)f(the)i(external)f(library)e(that)0 4281 y(will)i(extract)j(the)g
+(necessary)f(W)m(CS)g(information)f(\(e.g.,)k(see)e(the)f(astFitsChan)g
+(and)f(astPutCards)h(routines)0 4394 y(in)29 b(the)i(Starlink)d(AST)h
+(library\).)0 4631 y Fi(1)81 b Fj(Concatenate)38 b(the)f(header)f(k)m
+(eyw)m(ords)h(in)e(the)h(CHDU)h(in)m(to)g(a)g(single)e(long)h(string)f
+(of)i(c)m(haracters.)60 b(Eac)m(h)227 4744 y(80-c)m(haracter)28
+b(\014xed-length)23 b(k)m(eyw)m(ord)i(record)g(is)f(app)s(ended)e(to)k
+(the)f(output)f(c)m(haracter)i(string,)f(in)e(order,)227
+4856 y(with)h(no)g(in)m(terv)m(ening)g(separator)h(or)g(terminating)f
+(c)m(haracters.)40 b(The)24 b(last)h(header)f(record)h(is)e(terminated)
+227 4969 y(with)32 b(a)h(NULL)f(c)m(haracter.)49 b(This)31
+b(routine)h(allo)s(cates)h(memory)f(for)h(the)g(returned)e(c)m
+(haracter)j(arra)m(y)-8 b(,)35 b(so)227 5082 y(the)c(calling)e(program)
+h(m)m(ust)g(free)h(the)f(memory)g(when)g(\014nished.)227
+5229 y(Selected)f(k)m(eyw)m(ords)f(ma)m(y)h(b)s(e)e(excluded)g(from)h
+(the)g(returned)f(c)m(haracter)j(string.)39 b(If)27 b(the)i(second)f
+(param-)227 5342 y(eter)h(\(no)s(commen)m(ts\))g(is)e(TR)m(UE)h
+(\(nonzero\))h(then)e(an)m(y)i(COMMENT,)f(HISTOR)-8 b(Y,)27
+b(or)h(blank)f(k)m(eyw)m(ords)227 5455 y(in)i(the)i(header)f(will)e
+(not)i(b)s(e)g(copied)g(to)h(the)g(output)f(string.)227
+5601 y(The)25 b('exclist')h(parameter)g(ma)m(y)g(b)s(e)f(used)g(to)h
+(supply)d(a)j(list)f(of)g(k)m(eyw)m(ords)h(that)h(are)f(to)g(b)s(e)f
+(excluded)f(from)227 5714 y(the)29 b(output)g(c)m(haracter)h(string.)40
+b(Wild)27 b(card)i(c)m(haracters)h(\(*,)g(?,)f(and)g(#\))g(ma)m(y)g(b)s
+(e)f(used)g(in)g(the)h(excluded)1905 5942 y(71)p eop
+%%Page: 72 80
+72 79 bop 0 299 a Fj(72)1003 b Fh(CHAPTER)30 b(7.)112
+b(CELESTIAL)28 b(COORDINA)-8 b(TE)30 b(SYSTEM)f(R)m(OUTINES)227
+555 y Fj(k)m(eyw)m(ord)h(names.)41 b(If)29 b(no)g(additional)f(k)m(eyw)
+m(ords)i(are)g(to)g(b)s(e)f(excluded,)g(then)g(set)h(nexc)g(=)f(0)h
+(and)f(sp)s(ecify)227 668 y(NULL)i(for)f(the)g(the)h(**header)g
+(parameter.)95 890 y Fe(int)47 b(fits_hdr2str)286 1003
+y(\(fitsfile)f(*fptr,)g(int)h(nocomments,)d(char)j(**exclist,)e(int)i
+(nexc,)286 1116 y(>)h(char)e(**header,)g(int)h(*nkeys,)e(int)i
+(*status\))0 1444 y Ff(7.1)180 b(Self-con)l(tained)46
+b(W)l(CS)f(Routines)0 1694 y Fj(The)21 b(follo)m(wing)f(routines)g(DO)h
+(NOT)g(supp)s(ort)f(the)h(more)h(recen)m(t)g(W)m(CS)f(con)m(v)m(en)m
+(tions)i(that)e(ha)m(v)m(e)i(b)s(een)e(appro)m(v)m(ed)0
+1807 y(as)34 b(part)g(of)g(the)g(FITS)f(standard.)50
+b(Consequen)m(tly)-8 b(,)34 b(the)g(follo)m(wing)f(routines)f(ARE)i(NO)
+m(W)h(DEPRECA)-8 b(TED.)0 1920 y(It)30 b(is)f(STR)m(ONGL)-8
+b(Y)30 b(RECOMMENDED)h(that)g(soft)m(w)m(are)g(dev)m(elop)s(ers)e(not)i
+(use)f(these)g(routines,)f(and)h(instead)0 2033 y(use)g(an)g(external)h
+(W)m(CS)f(library)-8 b(,)29 b(as)h(describ)s(ed)e(in)i(the)g(previous)f
+(section.)0 2193 y(These)21 b(routines)f(are)h(included)d(mainly)h(for)
+i(bac)m(kw)m(ard)g(compatibilit)m(y)f(with)f(existing)h(soft)m(w)m
+(are.)39 b(They)21 b(supp)s(ort)0 2306 y(the)30 b(follo)m(wing)f
+(standard)g(map)g(pro)5 b(jections:)40 b(-SIN,)30 b(-T)-8
+b(AN,)31 b(-AR)m(C,)g(-NCP)-8 b(,)30 b(-GLS,)g(-MER,)h(and)e(-AIT)h
+(\(these)0 2419 y(are)f(the)g(legal)f(v)-5 b(alues)28
+b(for)g(the)h(co)s(ordt)m(yp)s(e)f(parameter\).)41 b(These)28
+b(routines)g(are)h(based)f(on)g(similar)e(functions)h(in)0
+2532 y(Classic)i(AIPS.)h(All)f(the)i(angular)e(quan)m(tities)h(are)h
+(giv)m(en)f(in)f(units)g(of)h(degrees.)0 2754 y Fi(1)81
+b Fj(Get)41 b(the)f(v)-5 b(alues)40 b(of)h(the)f(basic)g(set)h(of)f
+(standard)g(FITS)f(celestial)h(co)s(ordinate)g(system)h(k)m(eyw)m(ords)
+f(from)227 2867 y(the)33 b(header)f(of)h(a)f(FITS)g(image)h(\(i.e.,)g
+(the)g(primary)e(arra)m(y)h(or)h(an)f(IMA)m(GE)i(extension\).)46
+b(These)33 b(v)-5 b(alues)227 2980 y(ma)m(y)35 b(then)f(b)s(e)g(passed)
+f(to)i(the)g(\014ts)p 1462 2980 28 4 v 32 w(pix)p 1619
+2980 V 31 w(to)p 1730 2980 V 34 w(w)m(orld)e(and)h(\014ts)p
+2321 2980 V 32 w(w)m(orld)p 2574 2980 V 32 w(to)p 2686
+2980 V 33 w(pix)f(routines)g(that)i(p)s(erform)e(the)227
+3093 y(co)s(ordinate)e(transformations.)41 b(If)30 b(an)m(y)h(or)f(all)
+g(of)h(the)g(W)m(CS)f(k)m(eyw)m(ords)h(are)g(not)g(presen)m(t,)g(then)g
+(default)227 3206 y(v)-5 b(alues)25 b(will)d(b)s(e)i(returned.)38
+b(If)24 b(the)i(\014rst)e(co)s(ordinate)h(axis)f(is)g(the)h
+(declination-lik)m(e)e(co)s(ordinate,)j(then)f(this)227
+3319 y(routine)30 b(will)d(sw)m(ap)k(them)f(so)h(that)g(the)f
+(longitudinal-lik)m(e)d(co)s(ordinate)j(is)f(returned)h(as)g(the)h
+(\014rst)e(axis.)227 3463 y(If)35 b(the)h(\014le)e(uses)h(the)g(new)m
+(er)h('CDj)p 1454 3463 V 32 w(i')f(W)m(CS)g(transformation)g(matrix)g
+(k)m(eyw)m(ords)g(instead)g(of)g(old)g(st)m(yle)227 3576
+y('CDEL)-8 b(Tn')37 b(and)f('CR)m(OT)-8 b(A2')38 b(k)m(eyw)m(ords,)h
+(then)e(this)e(routine)h(will)e(calculate)k(and)e(return)g(the)h(v)-5
+b(alues)227 3689 y(of)33 b(the)g(equiv)-5 b(alen)m(t)33
+b(old-st)m(yle)f(k)m(eyw)m(ords.)49 b(Note)34 b(that)g(the)f(con)m(v)m
+(ersion)g(from)f(the)i(new-st)m(yle)f(k)m(eyw)m(ords)227
+3801 y(to)f(the)f(old-st)m(yle)f(v)-5 b(alues)30 b(is)g(sometimes)g
+(only)g(an)h(appro)m(ximation,)f(so)g(if)g(the)h(appro)m(ximation)f(is)
+f(larger)227 3914 y(than)37 b(an)h(in)m(ternally)d(de\014ned)h
+(threshold)g(lev)m(el,)j(then)e(CFITSIO)f(will)f(still)g(return)h(the)i
+(appro)m(ximate)227 4027 y(W)m(CS)32 b(k)m(eyw)m(ord)h(v)-5
+b(alues,)32 b(but)f(will)e(also)j(return)f(with)g(status)h(=)f(APPR)m
+(O)m(X)p 2908 4027 V 34 w(W)m(CS)p 3149 4027 V 33 w(KEY,)g(to)i(w)m
+(arn)f(the)227 4140 y(calling)h(program)h(that)h(appro)m(ximations)e
+(ha)m(v)m(e)i(b)s(een)f(made.)52 b(It)35 b(is)e(then)h(up)f(to)i(the)f
+(calling)f(program)227 4253 y(to)d(decide)f(whether)f(the)h(appro)m
+(ximations)f(are)i(su\016cien)m(tly)d(accurate)k(for)e(the)g
+(particular)e(application,)227 4366 y(or)46 b(whether)e(more)i(precise)
+f(W)m(CS)g(transformations)g(m)m(ust)g(b)s(e)g(p)s(erformed)f(using)f
+(new-st)m(yle)j(W)m(CS)227 4479 y(k)m(eyw)m(ords)31 b(directly)-8
+b(.)95 4701 y Fe(int)47 b(fits_read_img_coord)c(/)k(ffgics)286
+4814 y(\(fitsfile)f(*fptr,)g(>)h(double)f(*xrefval,)g(double)g
+(*yrefval,)334 4927 y(double)g(*xrefpix,)f(double)i(*yrefpix,)e(double)
+h(*xinc,)g(double)g(*yinc,)334 5040 y(double)g(*rot,)h(char)f
+(*coordtype,)f(int)i(*status\))0 5262 y Fi(2)81 b Fj(Get)30
+b(the)f(v)-5 b(alues)29 b(of)g(the)h(standard)e(FITS)h(celestial)g(co)s
+(ordinate)g(system)g(k)m(eyw)m(ords)h(from)f(the)g(header)g(of)h(a)227
+5375 y(FITS)23 b(table)h(where)f(the)h(X)g(and)g(Y)g(\(or)g(RA)g(and)f
+(DEC\))h(co)s(ordinates)g(are)g(stored)g(in)e(2)i(separate)h(columns)
+227 5488 y(of)30 b(the)f(table)g(\(as)h(in)e(the)i(Ev)m(en)m(t)g(List)f
+(table)g(format)g(that)h(is)f(often)g(used)g(b)m(y)g(high)f(energy)h
+(astroph)m(ysics)227 5601 y(missions\).)69 b(These)40
+b(v)-5 b(alues)39 b(ma)m(y)i(then)f(b)s(e)f(passed)h(to)h(the)f(\014ts)
+p 2511 5601 V 33 w(pix)p 2669 5601 V 31 w(to)p 2780 5601
+V 34 w(w)m(orld)f(and)h(\014ts)p 3383 5601 V 32 w(w)m(orld)p
+3636 5601 V 32 w(to)p 3748 5601 V 33 w(pix)227 5714 y(routines)30
+b(that)g(p)s(erform)f(the)i(co)s(ordinate)f(transformations.)p
+eop
+%%Page: 73 81
+73 80 bop 0 299 a Fh(7.1.)113 b(SELF-CONT)-8 b(AINED)30
+b(W)m(CS)g(R)m(OUTINES)1984 b Fj(73)95 555 y Fe(int)47
+b(fits_read_tbl_coord)c(/)k(ffgtcs)286 668 y(\(fitsfile)f(*fptr,)g(int)
+h(xcol,)f(int)h(ycol,)f(>)i(double)e(*xrefval,)334 781
+y(double)g(*yrefval,)f(double)i(*xrefpix,)e(double)h(*yrefpix,)f
+(double)h(*xinc,)334 894 y(double)g(*yinc,)g(double)g(*rot,)h(char)f
+(*coordtype,)f(int)i(*status\))0 1154 y Fi(3)81 b Fj(Calculate)40
+b(the)i(celestial)e(co)s(ordinate)h(corresp)s(onding)e(to)j(the)f
+(input)e(X)i(and)g(Y)g(pixel)e(lo)s(cation)i(in)f(the)227
+1267 y(image.)95 1526 y Fe(int)47 b(fits_pix_to_world)c(/)48
+b(ffwldp)286 1639 y(\(double)e(xpix,)h(double)f(ypix,)g(double)g
+(xrefval,)g(double)g(yrefval,)334 1752 y(double)g(xrefpix,)g(double)g
+(yrefpix,)f(double)h(xinc,)h(double)f(yinc,)334 1865
+y(double)g(rot,)h(char)f(*coordtype,)f(>)j(double)e(*xpos,)g(double)g
+(*ypos,)334 1978 y(int)h(*status\))0 2238 y Fi(4)81 b
+Fj(Calculate)40 b(the)i(X)f(and)f(Y)h(pixel)f(lo)s(cation)g(corresp)s
+(onding)f(to)j(the)f(input)e(celestial)i(co)s(ordinate)g(in)f(the)227
+2351 y(image.)95 2611 y Fe(int)47 b(fits_world_to_pix)c(/)48
+b(ffxypx)286 2723 y(\(double)e(xpos,)h(double)f(ypos,)g(double)g
+(xrefval,)g(double)g(yrefval,)334 2836 y(double)g(xrefpix,)g(double)g
+(yrefpix,)f(double)h(xinc,)h(double)f(yinc,)334 2949
+y(double)g(rot,)h(char)f(*coordtype,)f(>)j(double)e(*xpix,)g(double)g
+(*ypix,)334 3062 y(int)h(*status\))p eop
+%%Page: 74 82
+74 81 bop 0 299 a Fj(74)1003 b Fh(CHAPTER)30 b(7.)112
+b(CELESTIAL)28 b(COORDINA)-8 b(TE)30 b(SYSTEM)f(R)m(OUTINES)p
+eop
+%%Page: 75 83
+75 82 bop 0 1225 a Fg(Chapter)65 b(8)0 1687 y Fm(Hierarc)-6
+b(hical)76 b(Grouping)h(Routines)0 2180 y Fj(These)34
+b(functions)g(allo)m(w)g(for)g(the)h(creation)g(and)f(manipulation)e
+(of)j(FITS)f(HDU)h(Groups,)h(as)f(de\014ned)e(in)g("A)0
+2293 y(Hierarc)m(hical)22 b(Grouping)g(Con)m(v)m(en)m(tion)h(for)g
+(FITS")f(b)m(y)h(Jennings,)g(P)m(ence,)i(F)-8 b(olk)24
+b(and)e(Sc)m(hlesinger)g(\()h(h)m(ttp:)37 b(//ad-)0 2406
+y(fwww.gsfc.nasa.go)m(v/other/con)m(v)m(ert/group.h)m(tml)27
+b(\).)38 b(A)23 b(group)g(is)e(a)j(collection)e(of)h(HDUs)h(whose)e
+(asso)s(ciation)0 2518 y(is)33 b(de\014ned)f(b)m(y)h(a)h
+Fa(gr)-5 b(ouping)37 b(table)p Fj(.)50 b(HDUs)35 b(whic)m(h)d(are)i
+(part)f(of)h(a)g(group)f(are)h(referred)f(to)h(as)g Fa(memb)-5
+b(er)36 b(HDUs)0 2631 y Fj(or)i(simply)d(as)i Fa(memb)-5
+b(ers)p Fj(.)63 b(Grouping)37 b(table)g(mem)m(b)s(er)g(HDUs)h(ma)m(y)g
+(themselv)m(es)g(b)s(e)f(grouping)f(tables,)j(th)m(us)0
+2744 y(allo)m(wing)29 b(for)h(the)h(construction)f(of)g(op)s(en-ended)g
+(hierarc)m(hies)f(of)h(HDUs.)0 2904 y(Grouping)25 b(tables)i(con)m
+(tain)g(one)g(ro)m(w)g(for)f(eac)m(h)i(mem)m(b)s(er)e(HDU.)i(The)e
+(grouping)f(table)i(columns)e(pro)m(vide)h(iden-)0 3017
+y(ti\014cation)h(information)f(that)i(allo)m(ws)f(applications)e(to)j
+(reference)g(or)g("p)s(oin)m(t)f(to")h(the)g(mem)m(b)s(er)f(HDUs.)40
+b(Mem-)0 3130 y(b)s(er)27 b(HDUs)h(are)g(exp)s(ected,)h(but)e(not)h
+(required,)e(to)j(con)m(tain)f(a)g(set)g(of)g(GRPIDn/GRPLCn)f(k)m(eyw)m
+(ords)h(in)e(their)0 3243 y(headers)k(for)h(eac)m(h)g(grouping)f(table)
+g(that)h(they)g(are)g(referenced)g(b)m(y)-8 b(.)41 b(In)30
+b(this)g(sense,)h(the)g(GRPIDn/GRPLCn)0 3356 y(k)m(eyw)m(ords)d("link")
+e(the)i(mem)m(b)s(er)f(HDU)h(bac)m(k)g(to)g(its)f(Grouping)f(table.)40
+b(Note)29 b(that)f(a)f(mem)m(b)s(er)g(HDU)h(need)g(not)0
+3469 y(reside)h(in)g(the)h(same)g(FITS)f(\014le)h(as)g(its)f(grouping)g
+(table,)h(and)f(that)i(a)f(giv)m(en)g(HDU)h(ma)m(y)g(b)s(e)e
+(referenced)h(b)m(y)g(up)0 3582 y(to)h(999)h(grouping)d(tables)h(sim)m
+(ultaneously)-8 b(.)0 3742 y(Grouping)21 b(tables)i(are)g(implemen)m
+(ted)e(as)i(FITS)f(binary)f(tables)h(with)g(up)f(to)j(six)d
+(pre-de\014ned)h(column)f(TTYPEn)0 3855 y(v)-5 b(alues:)35
+b('MEMBER)p 752 3855 28 4 v 34 w(XTENSION',)20 b('MEMBER)p
+1789 3855 V 33 w(NAME',)h('MEMBER)p 2620 3855 V 34 w(VERSION',)f
+('MEMBER)p 3590 3855 V 34 w(POSITION',)0 3968 y('MEMBER)p
+451 3968 V 34 w(URI)p 653 3968 V 32 w(TYPE')g(and)g('MEMBER)p
+1601 3968 V 34 w(LOCA)-8 b(TION'.)20 b(The)f(\014rst)h(three)g(columns)
+f(allo)m(w)h(mem)m(b)s(er)g(HDUs)0 4081 y(to)28 b(b)s(e)f(iden)m
+(ti\014ed)e(b)m(y)i(reference)h(to)g(their)e(XTENSION,)h(EXTNAME)g(and)
+g(EXTVER)g(k)m(eyw)m(ord)g(v)-5 b(alues.)39 b(The)0 4194
+y(fourth)29 b(column)g(allo)m(ws)h(mem)m(b)s(er)f(HDUs)i(to)g(b)s(e)f
+(iden)m(ti\014ed)e(b)m(y)i(HDU)h(p)s(osition)d(within)g(their)h(FITS)h
+(\014le.)39 b(The)0 4307 y(last)f(t)m(w)m(o)h(columns)d(iden)m(tify)g
+(the)i(FITS)f(\014le)g(in)f(whic)m(h)h(the)h(mem)m(b)s(er)f(HDU)h
+(resides,)h(if)d(di\013eren)m(t)i(from)f(the)0 4419 y(grouping)29
+b(table)h(FITS)g(\014le.)0 4580 y(Additional)22 b(user)i(de\014ned)f
+("auxiliary")g(columns)g(ma)m(y)i(also)f(b)s(e)g(included)e(with)h(an)m
+(y)i(grouping)e(table.)38 b(When)25 b(a)0 4693 y(grouping)h(table)i(is)
+f(copied)g(or)g(mo)s(di\014ed)f(the)i(presence)g(of)f(auxiliary)f
+(columns)g(is)h(alw)m(a)m(ys)h(tak)m(en)h(in)m(to)e(accoun)m(t)0
+4805 y(b)m(y)k(the)g(grouping)f(supp)s(ort)g(functions;)g(ho)m(w)m(ev)m
+(er,)j(the)e(grouping)f(supp)s(ort)g(functions)f(cannot)j(directly)e
+(mak)m(e)0 4918 y(use)g(of)h(this)e(data.)0 5079 y(If)44
+b(a)h(grouping)e(table)h(column)f(is)h(de\014ned)f(but)h(the)g(corresp)
+s(onding)f(mem)m(b)s(er)g(HDU)j(information)c(is)i(un-)0
+5191 y(a)m(v)-5 b(ailable)38 b(then)f(a)i(n)m(ull)d(v)-5
+b(alue)38 b(of)g(the)g(appropriate)g(data)g(t)m(yp)s(e)h(is)e(inserted)
+g(in)g(the)h(column)f(\014eld.)63 b(In)m(teger)0 5304
+y(columns)25 b(\(MEMBER)p 811 5304 V 34 w(POSITION,)g(MEMBER)p
+1771 5304 V 34 w(VERSION\))h(are)h(de\014ned)f(with)f(a)i(TNULLn)f(v)-5
+b(alue)26 b(of)h(zero)0 5417 y(\(0\).)41 b(Character)27
+b(\014eld)e(columns)h(\(MEMBER)p 1607 5417 V 34 w(XTENSION,)g(MEMBER)p
+2600 5417 V 33 w(NAME,)i(MEMBER)p 3388 5417 V 34 w(URI)p
+3590 5417 V 32 w(TYPE,)0 5530 y(MEMBER)p 426 5530 V 33
+w(LOCA)-8 b(TION\))30 b(utilize)f(an)h(ASCI)s(I)f(n)m(ull)f(c)m
+(haracter)k(to)f(denote)g(a)g(n)m(ull)d(\014eld)h(v)-5
+b(alue.)0 5690 y(The)23 b(grouping)f(supp)s(ort)g(functions)g(b)s
+(elong)h(to)h(t)m(w)m(o)h(basic)e(categories:)39 b(those)24
+b(that)h(w)m(ork)e(with)g(grouping)f(table)1905 5942
+y(75)p eop
+%%Page: 76 84
+76 83 bop 0 299 a Fj(76)1338 b Fh(CHAPTER)29 b(8.)112
+b(HIERAR)m(CHICAL)30 b(GR)m(OUPING)h(R)m(OUTINES)0 555
+y Fj(HDUs)26 b(\(\013gt**\))j(and)c(those)h(that)h(w)m(ork)f(with)e
+(mem)m(b)s(er)i(HDUs)g(\(\013gm**\).)41 b(Tw)m(o)26 b(functions,)g
+(\014ts)p 3360 555 28 4 v 32 w(cop)m(y)p 3573 555 V 34
+w(group\(\))0 668 y(and)40 b(\014ts)p 314 668 V 33 w(remo)m(v)m(e)p
+626 668 V 34 w(group\(\),)k(ha)m(v)m(e)e(the)f(option)f(to)i(recursiv)m
+(ely)d(cop)m(y/delete)k(en)m(tire)e(groups.)71 b(Care)41
+b(should)0 781 y(b)s(e)33 b(tak)m(en)h(when)f(emplo)m(ying)f(these)i
+(functions)e(in)g(recursiv)m(e)h(mo)s(de)g(as)g(p)s(o)s(orly)f
+(de\014ned)g(groups)h(could)f(cause)0 894 y(unpredictable)23
+b(results.)38 b(The)25 b(problem)f(of)i(a)g(grouping)e(table)i
+(directly)e(or)i(indirectly)d(referencing)i(itself)f(\(th)m(us)0
+1007 y(creating)40 b(an)g(in\014nite)d(lo)s(op\))j(is)e(protected)j
+(against;)k(in)38 b(fact,)44 b(neither)38 b(function)h(will)e(attempt)k
+(to)f(cop)m(y)h(or)0 1120 y(delete)31 b(an)f(HDU)h(t)m(wice.)0
+1453 y Ff(8.1)135 b(Grouping)45 b(T)-11 b(able)45 b(Routines)0
+1693 y Fi(1)81 b Fj(Create)34 b(\(app)s(end\))f(a)h(grouping)e(table)i
+(at)g(the)g(end)f(of)h(the)g(curren)m(t)f(FITS)g(\014le)g(p)s(oin)m
+(ted)g(to)h(b)m(y)g(fptr.)49 b(The)227 1806 y(grpname)28
+b(parameter)h(pro)m(vides)f(the)h(grouping)e(table)h(name)h(\(GRPNAME)g
+(k)m(eyw)m(ord)g(v)-5 b(alue\))28 b(and)g(ma)m(y)227
+1919 y(b)s(e)42 b(set)h(to)g(NULL)f(if)f(no)h(group)g(name)g(is)g(to)h
+(b)s(e)e(sp)s(eci\014ed.)75 b(The)42 b(groupt)m(yp)s(e)g(parameter)g
+(sp)s(eci\014es)227 2032 y(the)c(desired)f(structure)g(of)h(the)g
+(grouping)e(table)i(and)f(ma)m(y)i(tak)m(e)g(on)f(the)g(v)-5
+b(alues:)55 b(GT)p 3355 2032 V 33 w(ID)p 3490 2032 V
+33 w(ALL)p 3705 2032 V 32 w(URI)227 2145 y(\(all)33 b(columns)f
+(created\),)k(GT)p 1274 2145 V 33 w(ID)p 1409 2145 V
+33 w(REF)d(\(ID)h(b)m(y)g(reference)g(columns\),)f(GT)p
+2904 2145 V 33 w(ID)p 3039 2145 V 33 w(POS)f(\(ID)i(b)m(y)g(p)s
+(osition)227 2258 y(columns\),)47 b(GT)p 801 2258 V 32
+w(ID)p 935 2258 V 33 w(ALL)d(\(ID)g(b)m(y)f(reference)i(and)e(p)s
+(osition)e(columns\),)47 b(GT)p 3028 2258 V 32 w(ID)p
+3162 2258 V 33 w(REF)p 3383 2258 V 33 w(URI)d(\(ID)g(b)m(y)227
+2371 y(reference)35 b(and)e(FITS)g(\014le)h(URI)f(columns\),)i(and)e
+(GT)p 2129 2371 V 33 w(ID)p 2264 2371 V 33 w(POS)p 2481
+2371 V 32 w(URI)h(\(ID)g(b)m(y)g(p)s(osition)e(and)i(FITS)f(\014le)227
+2484 y(URI)e(columns\).)95 2742 y Fe(int)47 b(fits_create_group)c(/)48
+b(ffgtcr)286 2855 y(\(fitsfile)e(*fptr,)g(char)g(*grpname,)g(int)h
+(grouptype,)e(>)i(int)g(*status\))0 3113 y Fi(2)81 b
+Fj(Create)26 b(\(insert\))f(a)g(grouping)f(table)h(just)g(after)h(the)f
+(CHDU)h(of)g(the)f(curren)m(t)g(FITS)g(\014le)f(p)s(oin)m(ted)g(to)i(b)
+m(y)g(fptr.)227 3226 y(All)i(HDUs)h(b)s(elo)m(w)f(the)h(the)g
+(insertion)e(p)s(oin)m(t)g(will)g(b)s(e)h(shifted)f(do)m(wn)m(w)m(ards)
+h(to)i(mak)m(e)g(ro)s(om)e(for)g(the)h(new)227 3339 y(HDU.)23
+b(The)e(grpname)h(parameter)g(pro)m(vides)e(the)i(grouping)f(table)g
+(name)h(\(GRPNAME)h(k)m(eyw)m(ord)f(v)-5 b(alue\))227
+3451 y(and)25 b(ma)m(y)i(b)s(e)e(set)h(to)h(NULL)e(if)g(no)h(group)f
+(name)h(is)f(to)h(b)s(e)f(sp)s(eci\014ed.)38 b(The)25
+b(groupt)m(yp)s(e)h(parameter)g(sp)s(eci-)227 3564 y(\014es)g(the)h
+(desired)e(structure)h(of)h(the)f(grouping)f(table)i(and)f(ma)m(y)h
+(tak)m(e)h(on)e(the)h(v)-5 b(alues:)38 b(GT)p 3355 3564
+V 33 w(ID)p 3490 3564 V 33 w(ALL)p 3705 3564 V 32 w(URI)227
+3677 y(\(all)33 b(columns)f(created\),)k(GT)p 1274 3677
+V 33 w(ID)p 1409 3677 V 33 w(REF)d(\(ID)h(b)m(y)g(reference)g
+(columns\),)f(GT)p 2904 3677 V 33 w(ID)p 3039 3677 V
+33 w(POS)f(\(ID)i(b)m(y)g(p)s(osition)227 3790 y(columns\),)28
+b(GT)p 782 3790 V 33 w(ID)p 917 3790 V 33 w(ALL)g(\(ID)g(b)m(y)g
+(reference)h(and)e(p)s(osition)f(columns\),)i(GT)p 2897
+3790 V 33 w(ID)p 3032 3790 V 33 w(REF)p 3253 3790 V 32
+w(URI)g(\(ID)h(b)m(y)f(ref-)227 3903 y(erence)g(and)e(FITS)h(\014le)f
+(URI)h(columns\),)g(and)f(GT)p 1976 3903 V 33 w(ID)p
+2111 3903 V 33 w(POS)p 2328 3903 V 32 w(URI)h(\(ID)g(b)m(y)g(p)s
+(osition)e(and)i(FITS)f(\014le)g(URI)227 4016 y(columns\))k(.)95
+4274 y Fe(int)47 b(fits_insert_group)c(/)48 b(ffgtis)286
+4387 y(\(fitsfile)e(*fptr,)g(char)g(*grpname,)g(int)h(grouptype,)e(>)i
+(int)g(*status\))0 4645 y Fi(3)81 b Fj(Change)20 b(the)h(structure)f
+(of)h(an)g(existing)e(grouping)h(table)g(p)s(oin)m(ted)g(to)h(b)m(y)g
+(gfptr.)37 b(The)20 b(groupt)m(yp)s(e)g(parameter)227
+4758 y(\(see)27 b(\014ts)p 532 4758 V 32 w(create)p 800
+4758 V 35 w(group\(\))e(for)h(v)-5 b(alid)24 b(parameter)i(v)-5
+b(alues\))25 b(sp)s(eci\014es)g(the)g(new)g(structure)h(of)f(the)h
+(grouping)227 4871 y(table.)43 b(This)29 b(function)h(only)g(adds)h(or)
+g(remo)m(v)m(es)h(grouping)e(table)h(columns,)f(it)h(do)s(es)g(not)g
+(add)g(or)g(delete)227 4984 y(group)26 b(mem)m(b)s(ers)f(\(i.e.,)j
+(table)e(ro)m(ws\).)40 b(If)26 b(the)g(grouping)f(table)h(already)g
+(has)g(the)h(desired)d(structure)i(then)227 5097 y(no)35
+b(op)s(erations)e(are)i(p)s(erformed)e(and)h(function)f(simply)g
+(returns)g(with)g(a)i(\(0\))g(success)g(status)g(co)s(de.)53
+b(If)227 5210 y(the)32 b(requested)g(structure)g(c)m(hange)h(creates)g
+(new)f(grouping)f(table)h(columns,)f(then)h(the)g(column)f(v)-5
+b(alues)227 5323 y(for)30 b(all)g(existing)f(mem)m(b)s(ers)h(will)d(b)s
+(e)j(\014lled)e(with)h(the)i(n)m(ull)d(v)-5 b(alues)30
+b(appropriate)f(to)i(the)g(column)e(t)m(yp)s(e.)95 5581
+y Fe(int)47 b(fits_change_group)c(/)48 b(ffgtch)286 5694
+y(\(fitsfile)e(*gfptr,)f(int)i(grouptype,)e(>)j(int)f(*status\))p
+eop
+%%Page: 77 85
+77 84 bop 0 299 a Fh(8.1.)72 b(GR)m(OUPING)31 b(T)-8
+b(ABLE)31 b(R)m(OUTINES)2235 b Fj(77)0 555 y Fi(4)81
+b Fj(Remo)m(v)m(e)41 b(the)e(group)g(de\014ned)f(b)m(y)h(the)h
+(grouping)e(table)h(p)s(oin)m(ted)f(to)i(b)m(y)g(gfptr,)h(and)e
+(optionally)f(all)g(the)227 668 y(group)29 b(mem)m(b)s(er)f(HDUs.)41
+b(The)28 b(rmopt)h(parameter)g(sp)s(eci\014es)f(the)h(action)g(to)h(b)s
+(e)e(tak)m(en)i(for)f(all)f(mem)m(b)s(ers)227 781 y(of)f(the)g(group)g
+(de\014ned)e(b)m(y)i(the)g(grouping)f(table.)39 b(V)-8
+b(alid)26 b(v)-5 b(alues)26 b(are:)40 b(OPT)p 2848 781
+28 4 v 32 w(RM)p 3030 781 V 33 w(GPT)26 b(\(delete)i(only)e(the)227
+894 y(grouping)32 b(table\))i(and)f(OPT)p 1259 894 V
+32 w(RM)p 1441 894 V 33 w(ALL)g(\(recursiv)m(ely)f(delete)i(all)e(HDUs)
+i(that)g(b)s(elong)e(to)i(the)g(group\).)227 1007 y(An)m(y)d(groups)g
+(con)m(taining)g(the)g(grouping)f(table)h(gfptr)f(as)i(a)f(mem)m(b)s
+(er)g(are)g(up)s(dated,)f(and)h(if)f(rmopt)h(==)227 1120
+y(OPT)p 431 1120 V 32 w(RM)p 613 1120 V 33 w(GPT)21 b(all)f(mem)m(b)s
+(ers)h(ha)m(v)m(e)h(their)e(GRPIDn)h(and)g(GRPLCn)f(k)m(eyw)m(ords)h
+(up)s(dated)f(accordingly)-8 b(.)227 1233 y(If)36 b(rmopt)g(==)g(OPT)p
+985 1233 V 32 w(RM)p 1167 1233 V 33 w(ALL,)g(then)g(other)h(groups)e
+(that)i(con)m(tain)g(the)f(deleted)g(mem)m(b)s(ers)g(of)g(gfptr)227
+1346 y(are)31 b(up)s(dated)e(to)i(re\015ect)g(the)g(deletion)e
+(accordingly)-8 b(.)95 1582 y Fe(int)47 b(fits_remove_group)c(/)48
+b(ffgtrm)286 1695 y(\(fitsfile)e(*gfptr,)f(int)i(rmopt,)f(>)i(int)f
+(*status\))0 1932 y Fi(5)81 b Fj(Cop)m(y)28 b(\(app)s(end\))g(the)h
+(group)f(de\014ned)g(b)m(y)h(the)f(grouping)g(table)h(p)s(oin)m(ted)e
+(to)j(b)m(y)e(infptr,)g(and)g(optionally)f(all)227 2045
+y(group)j(mem)m(b)s(er)h(HDUs,)g(to)h(the)f(FITS)f(\014le)f(p)s(oin)m
+(ted)h(to)i(b)m(y)e(outfptr.)41 b(The)31 b(cp)s(opt)f(parameter)h(sp)s
+(eci\014es)227 2158 y(the)c(action)g(to)g(b)s(e)f(tak)m(en)h(for)g(all)
+e(mem)m(b)s(ers)h(of)g(the)h(group)f(infptr.)37 b(V)-8
+b(alid)26 b(v)-5 b(alues)25 b(are:)40 b(OPT)p 3443 2158
+V 32 w(GCP)p 3674 2158 V 32 w(GPT)227 2271 y(\(cop)m(y)d(only)f(the)g
+(grouping)f(table\))h(and)f(OPT)p 1887 2271 V 32 w(GCP)p
+2118 2271 V 33 w(ALL)h(\(recursiv)m(ely)f(cop)m(y)i(ALL)e(the)i(HDUs)f
+(that)227 2384 y(b)s(elong)23 b(to)h(the)g(group)f(de\014ned)g(b)m(y)g
+(infptr\).)37 b(If)23 b(the)h(cp)s(opt)g(==)f(OPT)p 2618
+2384 V 32 w(GCP)p 2849 2384 V 32 w(GPT)h(then)f(the)h(mem)m(b)s(ers)f
+(of)227 2497 y(infptr)h(ha)m(v)m(e)i(their)f(GRPIDn)g(and)g(GRPLCn)g(k)
+m(eyw)m(ords)h(up)s(dated)e(to)i(re\015ect)g(the)g(existence)g(of)g
+(the)f(new)227 2610 y(grouping)e(table)g(outfptr,)i(since)e(they)h(no)m
+(w)g(b)s(elong)f(to)h(the)g(new)g(group.)38 b(If)23 b(cp)s(opt)h(==)f
+(OPT)p 3460 2610 V 32 w(GCP)p 3691 2610 V 32 w(ALL)227
+2723 y(then)29 b(the)g(new)g(grouping)f(table)h(outfptr)f(only)g(con)m
+(tains)i(p)s(oin)m(ters)e(to)i(the)f(copied)f(mem)m(b)s(er)h(HDUs)h
+(and)227 2836 y(not)38 b(the)g(original)d(mem)m(b)s(er)i(HDUs)h(of)g
+(infptr.)60 b(Note)39 b(that,)h(when)d(cp)s(opt)g(==)g(OPT)p
+3301 2836 V 32 w(GCP)p 3532 2836 V 33 w(ALL,)g(all)227
+2949 y(mem)m(b)s(ers)h(of)h(the)f(group)g(de\014ned)f(b)m(y)i(infptr)d
+(will)g(b)s(e)h(copied)h(to)h(a)g(single)e(FITS)h(\014le)g(p)s(oin)m
+(ted)f(to)i(b)m(y)227 3061 y(outfptr)30 b(regardless)g(of)g(their)g
+(\014le)f(distribution)e(in)i(the)i(original)d(group.)95
+3298 y Fe(int)47 b(fits_copy_group)d(/)j(ffgtcp)286 3411
+y(\(fitsfile)f(*infptr,)f(fitsfile)h(*outfptr,)f(int)i(cpopt,)f(>)h
+(int)g(*status\))0 3648 y Fi(6)81 b Fj(Merge)40 b(the)f(t)m(w)m(o)h
+(groups)e(de\014ned)g(b)m(y)h(the)g(grouping)f(table)g(HDUs)i(infptr)d
+(and)h(outfptr)h(b)m(y)f(com)m(bining)227 3761 y(their)29
+b(mem)m(b)s(ers)g(in)m(to)h(a)g(single)e(grouping)g(table.)41
+b(All)28 b(mem)m(b)s(er)h(HDUs)h(\(ro)m(ws\))h(are)f(copied)f(from)g
+(infptr)227 3874 y(to)f(outfptr.)39 b(If)26 b(mgopt)i(==)e(OPT)p
+1419 3874 V 32 w(MR)m(G)p 1669 3874 V 34 w(COPY)g(then)g(infptr)f(con)m
+(tin)m(ues)i(to)h(exist)f(unaltered)e(after)j(the)227
+3987 y(merge.)57 b(If)36 b(the)f(mgopt)i(==)e(OPT)p 1474
+3987 V 31 w(MR)m(G)p 1723 3987 V 34 w(MO)m(V)i(then)e(infptr)e(is)i
+(deleted)h(after)g(the)g(merge.)57 b(In)35 b(b)s(oth)227
+4100 y(cases,)d(the)e(GRPIDn)h(and)e(GRPLCn)h(k)m(eyw)m(ords)g(of)h
+(the)g(mem)m(b)s(er)e(HDUs)i(are)g(up)s(dated)e(accordingly)-8
+b(.)95 4337 y Fe(int)47 b(fits_merge_groups)c(/)48 b(ffgtmg)286
+4450 y(\(fitsfile)e(*infptr,)f(fitsfile)h(*outfptr,)f(int)i(mgopt,)f(>)
+h(int)g(*status\))0 4687 y Fi(7)81 b Fj("Compact")24
+b(the)f(group)g(de\014ned)f(b)m(y)h(grouping)e(table)i(p)s(oin)m(ted)f
+(to)i(b)m(y)f(gfptr.)38 b(The)23 b(compaction)g(is)f(ac)m(hiev)m(ed)227
+4799 y(b)m(y)37 b(merging)g(\(via)g(\014ts)p 1034 4799
+V 32 w(merge)p 1303 4799 V 34 w(groups\(\)\))g(all)f(direct)h(mem)m(b)s
+(er)g(HDUs)g(of)h(gfptr)e(that)i(are)g(themselv)m(es)227
+4912 y(grouping)h(tables.)69 b(The)40 b(cmopt)g(parameter)h(de\014nes)e
+(whether)g(the)i(merged)f(grouping)e(table)i(HDUs)227
+5025 y(remain)j(after)i(merging)e(\(cmopt)i(==)f(OPT)p
+1852 5025 V 32 w(CMT)p 2099 5025 V 32 w(MBR\))h(or)f(if)f(they)i(are)f
+(deleted)g(after)h(merging)227 5138 y(\(cmopt)31 b(==)f(OPT)p
+916 5138 V 32 w(CMT)p 1163 5138 V 32 w(MBR)p 1409 5138
+V 34 w(DEL\).)g(If)g(the)h(grouping)d(table)j(con)m(tains)f(no)g
+(direct)g(mem)m(b)s(er)f(HDUs)227 5251 y(that)i(are)f(themselv)m(es)g
+(grouping)e(tables)i(then)f(this)g(function)f(do)s(es)i(nothing.)39
+b(Note)31 b(that)g(this)d(function)227 5364 y(is)i(not)g(recursiv)m(e,)
+g(i.e.,)h(only)f(the)g(direct)g(mem)m(b)s(er)g(HDUs)h(of)f(gfptr)g(are)
+h(considered)e(for)h(merging.)95 5601 y Fe(int)47 b(fits_compact_group)
+c(/)48 b(ffgtcm)286 5714 y(\(fitsfile)e(*gfptr,)f(int)i(cmopt,)f(>)i
+(int)f(*status\))p eop
+%%Page: 78 86
+78 85 bop 0 299 a Fj(78)1338 b Fh(CHAPTER)29 b(8.)112
+b(HIERAR)m(CHICAL)30 b(GR)m(OUPING)h(R)m(OUTINES)0 555
+y Fi(8)81 b Fj(V)-8 b(erify)20 b(the)i(in)m(tegrit)m(y)f(of)g(the)g
+(grouping)f(table)h(p)s(oin)m(ted)f(to)i(b)m(y)f(gfptr)g(to)h(mak)m(e)g
+(sure)e(that)i(all)e(group)h(mem)m(b)s(ers)227 668 y(are)31
+b(accessible)g(and)f(that)h(all)e(links)g(to)i(other)g(grouping)e
+(tables)i(are)g(v)-5 b(alid.)40 b(The)30 b(\014rstfailed)e(parameter)
+227 781 y(returns)e(the)i(mem)m(b)s(er)e(ID)h(\(ro)m(w)h(n)m(um)m(b)s
+(er\))e(of)i(the)f(\014rst)f(mem)m(b)s(er)h(HDU)h(to)g(fail)e(v)m
+(eri\014cation)g(\(if)h(p)s(ositiv)m(e)227 894 y(v)-5
+b(alue\))35 b(or)f(the)h(\014rst)e(group)h(link)e(to)k(fail)d(\(if)g
+(negativ)m(e)j(v)-5 b(alue\).)53 b(If)34 b(gfptr)g(is)f(successfully)g
+(v)m(eri\014ed)g(then)227 1007 y(\014rstfailed)c(con)m(tains)h(a)h
+(return)e(v)-5 b(alue)30 b(of)h(0.)95 1284 y Fe(int)47
+b(fits_verify_group)c(/)48 b(ffgtvf)286 1397 y(\(fitsfile)e(*gfptr,)f
+(>)j(long)f(*firstfailed,)d(int)j(*status\))0 1674 y
+Fi(9)81 b Fj(Op)s(en)23 b(a)j(grouping)e(table)h(that)h(con)m(tains)f
+(the)h(mem)m(b)s(er)e(HDU)i(p)s(oin)m(ted)e(to)i(b)m(y)f(mfptr.)38
+b(The)25 b(grouping)f(table)227 1787 y(to)39 b(op)s(en)e(is)g
+(de\014ned)g(b)m(y)h(the)g(grpid)e(parameter,)k(whic)m(h)d(con)m(tains)
+h(the)g(k)m(eyw)m(ord)h(index)d(v)-5 b(alue)38 b(of)g(the)227
+1900 y(GRPIDn/GRPLCn)d(k)m(eyw)m(ord\(s\))g(that)h(link)d(the)i(mem)m
+(b)s(er)f(HDU)h(mfptr)f(to)i(the)f(grouping)e(table.)54
+b(If)227 2013 y(the)30 b(grouping)e(table)h(resides)f(in)h(a)g(\014le)g
+(other)g(than)h(the)f(mem)m(b)s(er)g(HDUs)h(\014le)e(then)h(an)h
+(attempt)g(is)f(\014rst)227 2126 y(made)g(to)h(op)s(en)e(the)h(\014le)f
+(readwrite,)h(and)f(failing)f(that)j(readonly)-8 b(.)39
+b(A)29 b(p)s(oin)m(ter)f(to)i(the)f(op)s(ened)f(grouping)227
+2238 y(table)j(HDU)g(is)e(returned)g(in)g(gfptr.)227
+2397 y(Note)35 b(that)g(it)e(is)g(p)s(ossible,)f(although)i(unlik)m
+(ely)d(and)i(undesirable,)f(for)i(the)g(GRPIDn/GRPLCn)f(k)m(ey-)227
+2510 y(w)m(ords)k(in)f(a)h(mem)m(b)s(er)g(HDU)h(header)f(to)h(b)s(e)e
+(non-con)m(tin)m(uous,)j(e.g.,)h(GRPID1,)g(GRPID2,)g(GRPID5,)227
+2623 y(GRPID6.)i(In)29 b(suc)m(h)g(cases,)i(the)f(grpid)e(index)g(v)-5
+b(alue)30 b(sp)s(eci\014ed)e(in)g(the)i(function)e(call)i(shall)e(iden)
+m(tify)g(the)227 2736 y(\(grpid\)th)35 b(GRPID)g(v)-5
+b(alue.)56 b(In)34 b(the)i(ab)s(o)m(v)m(e)h(example,)f(if)f(grpid)e(==)
+i(3,)j(then)d(the)g(group)g(sp)s(eci\014ed)f(b)m(y)227
+2849 y(GRPID5)d(w)m(ould)f(b)s(e)f(op)s(ened.)95 3126
+y Fe(int)47 b(fits_open_group)d(/)j(ffgtop)286 3239 y(\(fitsfile)f
+(*mfptr,)f(int)i(group,)f(>)i(fitsfile)d(**gfptr,)h(int)h(*status\))0
+3516 y Fi(10)f Fj(Add)38 b(a)h(mem)m(b)s(er)f(HDU)i(to)f(an)g(existing)
+e(grouping)h(table)h(p)s(oin)m(ted)e(to)j(b)m(y)e(gfptr.)66
+b(The)38 b(mem)m(b)s(er)g(HDU)227 3629 y(ma)m(y)30 b(either)f(b)s(e)g
+(p)s(oin)m(ted)f(to)i(mfptr)f(\(whic)m(h)f(m)m(ust)i(b)s(e)e(p)s
+(ositioned)g(to)i(the)f(mem)m(b)s(er)g(HDU\))i(or,)f(if)e(mfptr)227
+3742 y(==)36 b(NULL,)g(iden)m(ti\014ed)e(b)m(y)i(the)g(hdup)s(os)e
+(parameter)i(\(the)h(HDU)g(p)s(osition)d(n)m(um)m(b)s(er,)i(Primary)e
+(arra)m(y)227 3855 y(==)g(1\))i(if)e(b)s(oth)g(the)h(grouping)f(table)g
+(and)h(the)g(mem)m(b)s(er)f(HDU)h(reside)f(in)g(the)h(same)g(FITS)f
+(\014le.)53 b(The)227 3968 y(new)27 b(mem)m(b)s(er)f(HDU)h(shall)e(ha)m
+(v)m(e)j(the)f(appropriate)f(GRPIDn)g(and)g(GRPLCn)g(k)m(eyw)m(ords)h
+(created)h(in)e(its)227 4081 y(header.)44 b(Note)33 b(that)f(if)f(the)h
+(mem)m(b)s(er)e(HDU)j(is)d(already)h(a)h(mem)m(b)s(er)f(of)h(the)g
+(group)f(then)g(it)g(will)e(not)j(b)s(e)227 4194 y(added)e(a)h(second)f
+(time.)95 4471 y Fe(int)47 b(fits_add_group_member)42
+b(/)48 b(ffgtam)286 4584 y(\(fitsfile)e(*gfptr,)f(fitsfile)h(*mfptr,)g
+(int)h(hdupos,)f(>)h(int)g(*status\))0 4938 y Ff(8.2)135
+b(Group)45 b(Mem)l(b)t(er)f(Routines)0 5191 y Fi(1)81
+b Fj(Return)29 b(the)h(n)m(um)m(b)s(er)f(of)i(mem)m(b)s(er)e(HDUs)i(in)
+e(a)i(grouping)d(table)j(gfptr.)40 b(The)30 b(n)m(um)m(b)s(er)e(mem)m
+(b)s(er)i(HDUs)h(is)227 5304 y(just)f(the)h(NAXIS2)f(v)-5
+b(alue)30 b(\(n)m(um)m(b)s(er)g(of)g(ro)m(ws\))h(of)f(the)h(grouping)e
+(table.)95 5581 y Fe(int)47 b(fits_get_num_members)c(/)k(ffgtnm)286
+5694 y(\(fitsfile)f(*gfptr,)f(>)j(long)f(*nmembers,)e(int)h(*status\))p
+eop
+%%Page: 79 87
+79 86 bop 0 299 a Fh(8.2.)72 b(GR)m(OUP)31 b(MEMBER)g(R)m(OUTINES)2295
+b Fj(79)0 555 y Fi(2)81 b Fj(Return)34 b(the)h(n)m(um)m(b)s(er)f(of)i
+(groups)e(to)i(whic)m(h)e(the)h(HDU)h(p)s(oin)m(ted)e(to)i(b)m(y)f
+(mfptr)f(is)h(link)m(ed,)g(as)g(de\014ned)f(b)m(y)227
+668 y(the)27 b(n)m(um)m(b)s(er)f(of)h(GRPIDn/GRPLCn)f(k)m(eyw)m(ord)i
+(records)e(that)i(app)s(ear)e(in)f(its)i(header.)39 b(Note)28
+b(that)g(eac)m(h)227 781 y(time)36 b(this)g(function)f(is)g(called,)j
+(the)e(indices)f(of)i(the)f(GRPIDn/GRPLCn)g(k)m(eyw)m(ords)h(are)g(c)m
+(hec)m(k)m(ed)h(to)227 894 y(mak)m(e)29 b(sure)e(they)g(are)h(con)m
+(tin)m(uous)f(\(ie)h(no)f(gaps\))h(and)f(are)h(re-en)m(umerated)g(to)h
+(eliminate)d(gaps)i(if)e(found.)95 1228 y Fe(int)47 b
+(fits_get_num_groups)c(/)k(ffgmng)286 1341 y(\(fitsfile)f(*mfptr,)f(>)j
+(long)f(*nmembers,)e(int)h(*status\))0 1563 y Fi(3)81
+b Fj(Op)s(en)26 b(a)i(mem)m(b)s(er)f(of)h(the)f(grouping)g(table)g(p)s
+(oin)m(ted)g(to)h(b)m(y)g(gfptr.)39 b(The)27 b(mem)m(b)s(er)g(to)i(op)s
+(en)e(is)f(iden)m(ti\014ed)g(b)m(y)227 1676 y(its)j(ro)m(w)h(n)m(um)m
+(b)s(er)e(within)f(the)i(grouping)g(table)g(as)h(giv)m(en)f(b)m(y)h
+(the)f(parameter)h('mem)m(b)s(er')f(\(\014rst)h(mem)m(b)s(er)227
+1788 y(==)g(1\))g(.)41 b(A)30 b(\014ts\014le)e(p)s(oin)m(ter)h(to)i
+(the)f(op)s(ened)f(mem)m(b)s(er)g(HDU)i(is)e(returned)g(as)h(mfptr.)39
+b(Note)31 b(that)g(if)e(the)227 1901 y(mem)m(b)s(er)f(HDU)h(resides)f
+(in)f(a)i(FITS)f(\014le)f(di\013eren)m(t)h(from)g(the)h(grouping)e
+(table)h(HDU)i(then)e(the)h(mem)m(b)s(er)227 2014 y(\014le)h(is)f
+(\014rst)h(op)s(ened)f(readwrite)h(and,)g(failing)e(this,)i(op)s(ened)f
+(readonly)-8 b(.)95 2236 y Fe(int)47 b(fits_open_member)d(/)j(ffgmop)
+286 2349 y(\(fitsfile)f(*gfptr,)f(long)i(member,)f(>)h(fitsfile)f
+(**mfptr,)f(int)i(*status\))0 2570 y Fi(4)81 b Fj(Cop)m(y)27
+b(\(app)s(end\))f(a)i(mem)m(b)s(er)f(HDU)h(of)f(the)h(grouping)d(table)
+j(p)s(oin)m(ted)e(to)i(b)m(y)f(gfptr.)39 b(The)27 b(mem)m(b)s(er)g(HDU)
+h(is)227 2683 y(iden)m(ti\014ed)j(b)m(y)i(its)g(ro)m(w)g(n)m(um)m(b)s
+(er)e(within)g(the)i(grouping)f(table)g(as)i(giv)m(en)f(b)m(y)f(the)i
+(parameter)f('mem)m(b)s(er')227 2796 y(\(\014rst)j(mem)m(b)s(er)f(==)g
+(1\).)58 b(The)35 b(cop)m(y)i(of)f(the)g(group)f(mem)m(b)s(er)g(HDU)i
+(will)c(b)s(e)i(app)s(ended)f(to)j(the)f(FITS)227 2909
+y(\014le)28 b(p)s(oin)m(ted)g(to)h(b)m(y)f(mfptr,)h(and)f(up)s(on)f
+(return)g(mfptr)h(shall)f(p)s(oin)m(t)g(to)j(the)f(copied)f(mem)m(b)s
+(er)g(HDU.)h(The)227 3022 y(cp)s(opt)e(parameter)h(ma)m(y)g(tak)m(e)h
+(on)e(the)g(follo)m(wing)f(v)-5 b(alues:)39 b(OPT)p 2465
+3022 28 4 v 32 w(MCP)p 2708 3022 V 32 w(ADD)29 b(whic)m(h)d(adds)g(a)i
+(new)f(en)m(try)227 3135 y(in)c(gfptr)h(for)f(the)i(copied)e(mem)m(b)s
+(er)h(HDU,)h(OPT)p 1907 3135 V 31 w(MCP)p 2149 3135 V
+33 w(NADD)g(whic)m(h)e(do)s(es)h(not)g(add)f(an)h(en)m(try)h(in)d
+(gfptr)227 3247 y(for)j(the)h(copied)e(mem)m(b)s(er,)i(and)f(OPT)p
+1536 3247 V 32 w(MCP)p 1779 3247 V 32 w(REPL)g(whic)m(h)f(replaces)h
+(the)g(original)e(mem)m(b)s(er)i(en)m(try)g(with)227
+3360 y(the)31 b(copied)f(mem)m(b)s(er)f(en)m(try)-8 b(.)95
+3582 y Fe(int)47 b(fits_copy_member)d(/)j(ffgmcp)286
+3695 y(\(fitsfile)f(*gfptr,)f(fitsfile)h(*mfptr,)g(long)g(member,)g
+(int)h(cpopt,)f(>)i(int)f(*status\))0 3916 y Fi(5)81
+b Fj(T)-8 b(ransfer)34 b(a)i(group)f(mem)m(b)s(er)f(HDU)i(from)f(the)h
+(grouping)e(table)h(p)s(oin)m(ted)f(to)i(b)m(y)f(infptr)f(to)i(the)f
+(grouping)227 4029 y(table)h(p)s(oin)m(ted)f(to)i(b)m(y)f(outfptr.)58
+b(The)35 b(mem)m(b)s(er)h(HDU)h(to)f(transfer)g(is)f(iden)m(ti\014ed)f
+(b)m(y)i(its)g(ro)m(w)g(n)m(um)m(b)s(er)227 4142 y(within)k(infptr)g
+(as)j(sp)s(eci\014ed)e(b)m(y)h(the)h(parameter)g('mem)m(b)s(er')f
+(\(\014rst)g(mem)m(b)s(er)g(==)f(1\).)78 b(If)42 b(tfopt)h(==)227
+4255 y(OPT)p 431 4255 V 32 w(MCP)p 674 4255 V 33 w(ADD)26
+b(then)f(the)h(mem)m(b)s(er)e(HDU)i(is)f(made)g(a)h(mem)m(b)s(er)f(of)g
+(outfptr)g(and)g(remains)f(a)i(mem)m(b)s(er)227 4368
+y(of)34 b(infptr.)50 b(If)34 b(tfopt)g(==)g(OPT)p 1339
+4368 V 32 w(MCP)p 1582 4368 V 32 w(MO)m(V)h(then)f(the)g(mem)m(b)s(er)f
+(HDU)i(is)e(deleted)h(from)f(infptr)f(after)227 4481
+y(the)f(transfer)f(to)h(outfptr.)95 4702 y Fe(int)47
+b(fits_transfer_member)c(/)k(ffgmtf)286 4815 y(\(fitsfile)f(*infptr,)f
+(fitsfile)h(*outfptr,)f(long)i(member,)e(int)i(tfopt,)334
+4928 y(>)h(int)e(*status\))0 5149 y Fi(6)81 b Fj(Remo)m(v)m(e)31
+b(a)e(mem)m(b)s(er)g(HDU)h(from)f(the)h(grouping)e(table)h(p)s(oin)m
+(ted)f(to)i(b)m(y)g(gfptr.)40 b(The)29 b(mem)m(b)s(er)f(HDU)i(to)h(b)s
+(e)227 5262 y(deleted)36 b(is)e(iden)m(ti\014ed)g(b)m(y)h(its)g(ro)m(w)
+h(n)m(um)m(b)s(er)f(in)f(the)i(grouping)e(table)h(as)h(sp)s(eci\014ed)e
+(b)m(y)i(the)f(parameter)227 5375 y('mem)m(b)s(er')41
+b(\(\014rst)g(mem)m(b)s(er)g(==)f(1\).)74 b(The)41 b(rmopt)g(parameter)
+h(ma)m(y)f(tak)m(e)i(on)e(the)h(follo)m(wing)d(v)-5 b(alues:)227
+5488 y(OPT)p 431 5488 V 32 w(RM)p 613 5488 V 33 w(ENTR)d(Y)34
+b(whic)m(h)d(remo)m(v)m(es)k(the)e(mem)m(b)s(er)g(HDU)h(en)m(try)f
+(from)g(the)g(grouping)f(table)h(and)g(up-)227 5601 y(dates)40
+b(the)f(mem)m(b)s(er's)f(GRPIDn/GRPLCn)g(k)m(eyw)m(ords,)k(and)c(OPT)p
+2687 5601 V 32 w(RM)p 2869 5601 V 33 w(MBR)h(whic)m(h)f(remo)m(v)m(es)i
+(the)227 5714 y(mem)m(b)s(er)30 b(HDU)h(en)m(try)g(from)f(the)g
+(grouping)f(table)i(and)e(deletes)i(the)f(mem)m(b)s(er)g(HDU)h(itself.)
+p eop
+%%Page: 80 88
+80 87 bop 0 299 a Fj(80)1338 b Fh(CHAPTER)29 b(8.)112
+b(HIERAR)m(CHICAL)30 b(GR)m(OUPING)h(R)m(OUTINES)95 555
+y Fe(int)47 b(fits_remove_member)c(/)48 b(ffgmrm)286
+668 y(\(fitsfile)e(*fptr,)g(long)g(member,)g(int)h(rmopt,)f(>)i(int)f
+(*status\))p eop
+%%Page: 81 89
+81 88 bop 0 1225 a Fg(Chapter)65 b(9)0 1687 y Fm(Sp)6
+b(ecialized)77 b(CFITSIO)f(In)-6 b(terface)0 1937 y(Routines)0
+2429 y Fj(The)28 b(basic)g(in)m(terface)i(routines)e(describ)s(ed)e
+(previously)h(are)i(recommended)f(for)h(most)g(uses,)g(but)f(the)h
+(routines)0 2542 y(describ)s(ed)g(in)g(this)h(c)m(hapter)h(are)h(also)e
+(a)m(v)-5 b(ailable)31 b(if)e(necessary)-8 b(.)43 b(Some)31
+b(of)g(these)g(routines)f(p)s(erform)f(more)i(sp)s(e-)0
+2655 y(cialized)26 b(function)f(that)j(cannot)f(easily)f(b)s(e)g(done)h
+(with)e(the)i(basic)g(in)m(terface)g(routines)f(while)e(others)j
+(duplicate)0 2767 y(the)j(functionalit)m(y)f(of)h(the)g(basic)g
+(routines)f(but)g(ha)m(v)m(e)i(a)g(sligh)m(tly)d(di\013eren)m(t)i
+(calling)e(sequence.)41 b(See)31 b(App)s(endix)0 2880
+y(B)g(for)f(the)g(de\014nition)e(of)j(eac)m(h)h(function)d(parameter.)0
+3210 y Ff(9.1)135 b(FITS)44 b(File)i(Access)e(Routines)0
+3446 y Fi(1)81 b Fj(Op)s(en)37 b(an)i(existing)g(FITS)f(\014le)g
+(residing)f(in)h(core)i(computer)f(memory)-8 b(.)68 b(This)37
+b(routine)h(is)h(analogous)g(to)227 3559 y(\014ts)p 354
+3559 28 4 v 33 w(op)s(en)p 577 3559 V 32 w(\014le.)54
+b(The)35 b('\014lename')f(is)g(curren)m(tly)h(ignored)f(b)m(y)h(this)f
+(routine)g(and)h(ma)m(y)g(b)s(e)g(an)m(y)g(arbitrary)227
+3672 y(string.)77 b(In)42 b(general,)k(the)d(application)e(m)m(ust)i
+(ha)m(v)m(e)h(preallo)s(cated)e(an)g(initial)e(blo)s(c)m(k)j(of)g
+(memory)f(to)227 3785 y(hold)h(the)i(FITS)f(\014le)g(prior)f(to)i
+(calling)e(this)g(routine:)69 b('memptr')44 b(p)s(oin)m(ts)f(to)j(the)e
+(starting)h(address)227 3898 y(and)39 b('memsize')h(giv)m(es)g(the)g
+(initial)d(size)i(of)h(the)g(blo)s(c)m(k)f(of)h(memory)-8
+b(.)69 b('mem)p 2958 3898 V 33 w(reallo)s(c')39 b(is)g(a)h(p)s(oin)m
+(ter)e(to)227 4011 y(an)d(optional)g(function)e(that)j(CFITSIO)e(can)h
+(call)f(to)i(allo)s(cate)g(additional)d(memory)-8 b(,)37
+b(if)d(needed)g(\(only)227 4124 y(if)40 b(mo)s(de)f(=)h(READ)m
+(WRITE\),)i(and)e(is)f(mo)s(deled)g(after)i(the)f(standard)g(C)g
+('reallo)s(c')g(function;)k(a)d(n)m(ull)227 4237 y(p)s(oin)m(ter)f(ma)m
+(y)h(b)s(e)f(giv)m(en)h(if)e(the)i(initial)d(allo)s(cation)i(of)h
+(memory)f(is)g(all)f(that)i(will)d(b)s(e)i(required)f(\(e.g.,)227
+4350 y(if)34 b(the)h(\014le)f(is)g(op)s(ened)g(with)g(mo)s(de)g(=)h
+(READONL)-8 b(Y\).)36 b(The)e('deltasize')h(parameter)g(ma)m(y)h(b)s(e)
+e(used)g(to)227 4463 y(suggest)g(a)f(minim)m(um)d(amoun)m(t)j(of)g
+(additional)e(memory)i(that)g(should)e(b)s(e)h(allo)s(cated)h(during)e
+(eac)m(h)j(call)227 4575 y(to)d(the)f(memory)f(reallo)s(cation)g
+(function.)39 b(By)30 b(default,)f(CFITSIO)f(will)f(reallo)s(cate)k
+(enough)e(additional)227 4688 y(space)44 b(to)g(hold)e(the)i(en)m(tire)
+f(curren)m(tly)f(de\014ned)h(FITS)f(\014le)h(\(as)g(giv)m(en)h(b)m(y)f
+(the)h(NAXISn)e(k)m(eyw)m(ords\))227 4801 y(or)g(1)f(FITS)g(blo)s(c)m
+(k)g(\(=)g(2880)i(b)m(ytes\),)i(whic)m(h)c(ev)m(er)h(is)e(larger.)73
+b(V)-8 b(alues)42 b(of)f(deltasize)g(less)g(than)g(2880)227
+4914 y(will)28 b(b)s(e)i(ignored.)41 b(Since)30 b(the)h(memory)g
+(reallo)s(cation)f(op)s(eration)g(can)h(b)s(e)f(computationally)f(exp)s
+(ensiv)m(e,)227 5027 y(allo)s(cating)24 b(a)h(larger)f(initial)e(blo)s
+(c)m(k)i(of)h(memory)-8 b(,)26 b(and/or)f(sp)s(ecifying)d(a)j(larger)g
+(deltasize)f(v)-5 b(alue)24 b(ma)m(y)h(help)227 5140
+y(to)31 b(reduce)g(the)f(n)m(um)m(b)s(er)f(of)i(reallo)s(cation)e
+(calls)h(and)g(mak)m(e)h(the)g(application)d(program)i(run)f(faster.)95
+5375 y Fe(int)47 b(fits_open_memfile)c(/)48 b(ffomem)286
+5488 y(\(fitsfile)e(**fptr,)f(const)i(char)f(*filename,)f(int)i(mode,)g
+(void)f(**memptr,)334 5601 y(size_t)g(*memsize,)f(size_t)i(deltasize,)
+334 5714 y(void)g(*\(*mem_realloc\)\(void)42 b(*p,)47
+b(size_t)f(newsize\),)f(int)i(*status\))1905 5942 y Fj(81)p
+eop
+%%Page: 82 90
+82 89 bop 0 299 a Fj(82)1003 b Fh(CHAPTER)30 b(9.)112
+b(SPECIALIZED)28 b(CFITSIO)h(INTERF)-10 b(A)m(CE)30 b(R)m(OUTINES)0
+555 y Fi(2)81 b Fj(Create)49 b(a)g(new)f(FITS)g(\014le)g(residing)e(in)
+i(core)h(computer)g(memory)-8 b(.)96 b(This)47 b(routine)g(is)h
+(analogous)h(to)227 668 y(\014ts)p 354 668 28 4 v 33
+w(create)p 623 668 V 34 w(\014le.)39 b(In)29 b(general,)h(the)f
+(application)e(m)m(ust)i(ha)m(v)m(e)i(preallo)s(cated)e(an)g(initial)d
+(blo)s(c)m(k)j(of)g(memory)227 781 y(to)38 b(hold)d(the)i(FITS)f
+(\014le)g(prior)f(to)i(calling)f(this)f(routine:)53 b('memptr')36
+b(p)s(oin)m(ts)g(to)h(the)g(starting)g(address)227 894
+y(and)i('memsize')h(giv)m(es)g(the)g(initial)d(size)i(of)h(the)g(blo)s
+(c)m(k)f(of)h(memory)-8 b(.)69 b('mem)p 2958 894 V 33
+w(reallo)s(c')39 b(is)g(a)h(p)s(oin)m(ter)e(to)227 1007
+y(an)g(optional)e(function)g(that)i(CFITSIO)e(can)i(call)f(to)h(allo)s
+(cate)g(additional)d(memory)-8 b(,)40 b(if)c(needed,)k(and)227
+1120 y(is)33 b(mo)s(deled)f(after)i(the)g(standard)f(C)g('reallo)s(c')g
+(function;)h(a)g(n)m(ull)d(p)s(oin)m(ter)i(ma)m(y)h(b)s(e)f(giv)m(en)g
+(if)g(the)h(initial)227 1233 y(allo)s(cation)f(of)g(memory)g(is)g(all)f
+(that)i(will)c(b)s(e)j(required.)47 b(The)33 b('deltasize')h(parameter)
+f(ma)m(y)h(b)s(e)f(used)f(to)227 1346 y(suggest)i(a)f(minim)m(um)d
+(amoun)m(t)j(of)g(additional)e(memory)i(that)g(should)e(b)s(e)h(allo)s
+(cated)h(during)e(eac)m(h)j(call)227 1458 y(to)d(the)f(memory)f(reallo)
+s(cation)g(function.)39 b(By)30 b(default,)f(CFITSIO)f(will)f(reallo)s
+(cate)k(enough)e(additional)227 1571 y(space)k(to)g(hold)e(1)h(FITS)g
+(blo)s(c)m(k)f(\(=)h(2880)i(b)m(ytes\))f(and)f(v)-5 b(alues)31
+b(of)i(deltasize)f(less)f(than)h(2880)i(will)29 b(b)s(e)j(ig-)227
+1684 y(nored.)39 b(Since)24 b(the)i(memory)f(reallo)s(cation)f(op)s
+(eration)h(can)h(b)s(e)f(computationally)f(exp)s(ensiv)m(e,)i(allo)s
+(cating)227 1797 y(a)h(larger)f(initial)d(blo)s(c)m(k)j(of)g(memory)-8
+b(,)28 b(and/or)e(sp)s(ecifying)e(a)i(larger)g(deltasize)g(v)-5
+b(alue)26 b(ma)m(y)h(help)d(to)j(reduce)227 1910 y(the)k(n)m(um)m(b)s
+(er)e(of)h(reallo)s(cation)g(calls)g(and)f(mak)m(e)j(the)e(application)
+f(program)h(run)f(faster.)95 2147 y Fe(int)47 b(fits_create_memfile)c
+(/)k(ffimem)286 2260 y(\(fitsfile)f(**fptr,)f(void)i(**memptr,)334
+2373 y(size_t)f(*memsize,)f(size_t)i(deltasize,)334 2486
+y(void)g(*\(*mem_realloc\)\(void)42 b(*p,)47 b(size_t)f(newsize\),)f
+(int)i(*status\))0 2723 y Fi(3)81 b Fj(Reop)s(en)34 b(a)i(FITS)e
+(\014le)g(that)i(w)m(as)f(previously)e(op)s(ened)i(with)e(\014ts)p
+2414 2723 V 33 w(op)s(en)p 2637 2723 V 32 w(\014le)h(or)h(\014ts)p
+3058 2723 V 33 w(create)p 3327 2723 V 34 w(\014le.)54
+b(The)34 b(new)227 2836 y(\014ts\014le)h(p)s(oin)m(ter)h(ma)m(y)h(then)
+f(b)s(e)f(treated)j(as)e(a)h(separate)g(\014le,)g(and)f(one)h(ma)m(y)g
+(sim)m(ultaneously)d(read)i(or)227 2949 y(write)d(to)i(2)f(\(or)g
+(more\))g(di\013eren)m(t)f(extensions)g(in)g(the)h(same)g(\014le.)50
+b(The)33 b(\014ts)p 2886 2949 V 32 w(op)s(en)p 3108 2949
+V 32 w(\014le)g(routine)g(\(ab)s(o)m(v)m(e\))227 3061
+y(automatically)i(detects)i(cases)f(where)e(a)i(previously)d(op)s(ened)
+h(\014le)h(is)f(b)s(eing)g(op)s(ened)g(again,)j(and)d(then)227
+3174 y(in)m(ternally)29 b(call)g(\014ts)p 930 3174 V
+33 w(reop)s(en)p 1229 3174 V 32 w(\014le,)h(so)g(programs)g(should)f
+(rarely)g(need)h(to)h(explicitly)d(call)i(this)f(routine.)95
+3411 y Fe(int)47 b(fits_reopen_file)d(/)j(ffreopen)286
+3524 y(\(fitsfile)f(*openfptr,)f(fitsfile)g(**newfptr,)g(>)j(int)f
+(*status\))0 3761 y Fi(4)81 b Fj(Create)24 b(a)g(new)f(FITS)g(\014le,)h
+(using)e(a)i(template)g(\014le)e(to)j(de\014ne)d(its)h(initial)e(size)j
+(and)f(structure.)37 b(The)24 b(template)227 3874 y(ma)m(y)i(b)s(e)f
+(another)g(FITS)g(HDU)h(or)f(an)g(ASCI)s(I)f(template)i(\014le.)38
+b(If)25 b(the)g(input)f(template)h(\014le)g(name)g(p)s(oin)m(ter)227
+3987 y(is)i(n)m(ull,)g(then)g(this)g(routine)f(b)s(eha)m(v)m(es)j(the)f
+(same)g(as)g(\014ts)p 2160 3987 V 32 w(create)p 2428
+3987 V 35 w(\014le.)39 b(The)27 b(curren)m(tly)g(supp)s(orted)f(format)
+227 4100 y(of)33 b(the)g(ASCI)s(I)e(template)i(\014le)e(is)h(describ)s
+(ed)e(under)h(the)i(\014ts)p 2350 4100 V 33 w(parse)p
+2591 4100 V 32 w(template)g(routine)f(\(in)f(the)i(general)227
+4213 y(Utilities)c(section\))95 4450 y Fe(int)47 b
+(fits_create_template)c(/)k(fftplt)286 4563 y(\(fitsfile)f(**fptr,)f
+(char)i(*filename,)e(char)i(*tpltfile)e(>)i(int)g(*status\))0
+4799 y Fi(5)81 b Fj(P)m(arse)28 b(the)f(input)f(\014lename)g(or)i(URL)f
+(in)m(to)g(its)g(comp)s(onen)m(t)h(parts:)39 b(the)27
+b(\014le)g(t)m(yp)s(e)h(\(\014le://,)g(ftp://,)h(h)m(ttp://,)227
+4912 y(etc\),)34 b(the)e(base)g(input)d(\014le)i(name,)h(the)g(name)g
+(of)g(the)g(output)f(\014le)g(that)h(the)g(input)e(\014le)g(is)h(to)h
+(b)s(e)f(copied)227 5025 y(to)38 b(prior)d(to)i(op)s(ening,)g(the)g
+(HDU)g(or)f(extension)h(sp)s(eci\014cation,)g(the)g(\014ltering)d(sp)s
+(eci\014er,)j(the)g(binning)227 5138 y(sp)s(eci\014er,)27
+b(and)h(the)g(column)f(sp)s(eci\014er.)38 b(Null)26 b(strings)h(will)e
+(b)s(e)j(returned)f(for)g(an)m(y)i(comp)s(onen)m(ts)f(that)h(are)227
+5251 y(not)i(presen)m(t)f(in)f(the)i(input)d(\014le)i(name.)95
+5488 y Fe(int)47 b(fits_parse_input_url)c(/)k(ffiurl)286
+5601 y(\(char)g(*filename,)e(>)i(char)g(*filetype,)e(char)h(*infile,)g
+(char)h(*outfile,)e(char)334 5714 y(*extspec,)g(char)i(*filter,)f(char)
+g(*binspec,)f(char)i(*colspec,)e(int)i(*status\))p eop
+%%Page: 83 91
+83 90 bop 0 299 a Fh(9.1.)72 b(FITS)30 b(FILE)g(A)m(CCESS)f(R)m
+(OUTINES)2244 b Fj(83)0 555 y Fi(6)81 b Fj(P)m(arse)33
+b(the)f(input)f(\014lename)h(and)f(return)h(the)h(HDU)g(n)m(um)m(b)s
+(er)e(that)i(w)m(ould)e(b)s(e)h(mo)m(v)m(ed)i(to)f(if)e(the)i(\014le)e
+(w)m(ere)227 668 y(op)s(ened)i(with)f(\014ts)p 878 668
+28 4 v 32 w(op)s(en)p 1100 668 V 32 w(\014le.)48 b(The)33
+b(returned)f(HDU)i(n)m(um)m(b)s(er)e(b)s(egins)g(with)g(1)h(for)g(the)g
+(primary)f(arra)m(y)-8 b(,)227 781 y(so)40 b(for)f(example,)j(if)c(the)
+i(input)d(\014lename)i(=)g(`m)m(y\014le.\014ts[2]')h(then)f(hdun)m(um)e
+(=)i(3)h(will)d(b)s(e)i(returned.)227 894 y(CFITSIO)j(do)s(es)i(not)g
+(op)s(en)f(the)g(\014le)g(to)i(c)m(hec)m(k)g(if)d(the)i(extension)g
+(actually)f(exists)g(if)g(an)g(extension)227 1007 y(n)m(um)m(b)s(er)e
+(is)h(sp)s(eci\014ed.)74 b(If)42 b(an)g(extension)g(name)g(is)g
+(included)d(in)i(the)i(\014le)e(name)h(sp)s(eci\014cation)f(\(e.g.)227
+1120 y(`m)m(y\014le.\014ts[EVENTS]')j(then)f(this)g(routine)g(will)f
+(ha)m(v)m(e)j(to)f(op)s(en)g(the)g(FITS)f(\014le)g(and)g(lo)s(ok)h(for)
+g(the)227 1233 y(p)s(osition)29 b(of)h(the)h(named)f(extension,)h(then)
+f(close)h(\014le)e(again.)41 b(This)29 b(is)g(not)i(p)s(ossible)d(if)i
+(the)g(\014le)g(is)f(b)s(eing)227 1346 y(read)34 b(from)f(the)h(stdin)e
+(stream,)j(and)f(an)f(error)g(will)f(b)s(e)h(returned)f(in)h(this)f
+(case.)52 b(If)33 b(the)h(\014lename)f(do)s(es)227 1458
+y(not)42 b(sp)s(ecify)f(an)h(explicit)e(extension)i(\(e.g.)76
+b('m)m(y\014le.\014ts'\))42 b(then)g(hdun)m(um)e(=)h(-99)i(will)d(b)s
+(e)h(returned,)227 1571 y(whic)m(h)34 b(is)g(functionally)f(equiv)-5
+b(alen)m(t)34 b(to)i(hdun)m(um)d(=)h(1.)55 b(This)33
+b(routine)h(is)g(mainly)g(used)g(for)g(bac)m(kw)m(ard)227
+1684 y(compatibilit)m(y)h(in)h(the)g(fto)s(ols)h(soft)m(w)m(are)h(pac)m
+(k)-5 b(age)39 b(and)d(is)f(not)i(recommended)g(for)f(general)h(use.)59
+b(It)37 b(is)227 1797 y(generally)i(b)s(etter)g(and)g(more)g(e\016cien)
+m(t)h(to)g(\014rst)e(op)s(en)h(the)g(FITS)g(\014le)f(with)g(\014ts)p
+3125 1797 V 32 w(op)s(en)p 3347 1797 V 33 w(\014le,)i(then)f(use)227
+1910 y(\014ts)p 354 1910 V 33 w(get)p 507 1910 V 34 w(hdu)p
+694 1910 V 31 w(n)m(um)c(to)i(determine)f(whic)m(h)f(HDU)i(in)e(the)i
+(\014le)e(has)h(b)s(een)g(op)s(ened,)h(rather)f(than)g(calling)227
+2023 y(\014ts)p 354 2023 V 33 w(parse)p 595 2023 V 32
+w(input)p 841 2023 V 31 w(url)29 b(follo)m(w)m(ed)h(b)m(y)g(a)h(call)e
+(to)j(\014ts)p 1967 2023 V 32 w(op)s(en)p 2189 2023 V
+32 w(\014le.)143 2280 y Fe(int)47 b(fits_parse_extnum)c(/)48
+b(ffextn)334 2393 y(\(char)e(*filename,)f(>)j(int)f(*hdunum,)e(int)i
+(*status\))0 2650 y Fi(7)81 b Fj(P)m(arse)45 b(the)g(input)d(\014le)i
+(name)h(and)f(return)f(the)i(ro)s(ot)g(\014le)f(name.)83
+b(The)44 b(ro)s(ot)h(name)g(includes)d(the)j(\014le)227
+2763 y(t)m(yp)s(e)35 b(if)f(sp)s(eci\014ed,)h(\(e.g.)56
+b('ftp://')37 b(or)e('h)m(ttp://'\))i(and)d(the)h(full)e(path)i(name,)h
+(to)g(the)f(exten)m(t)i(that)e(it)g(is)227 2875 y(sp)s(eci\014ed)25
+b(in)f(the)j(input)d(\014lename.)38 b(It)26 b(do)s(es)g(not)g(include)e
+(the)i(HDU)h(name)f(or)g(n)m(um)m(b)s(er,)g(or)g(an)m(y)h(\014ltering)
+227 2988 y(sp)s(eci\014cations.)143 3245 y Fe(int)47
+b(fits_parse_rootname)c(/)k(ffrtnm)334 3358 y(\(char)f(*filename,)f(>)j
+(char)f(*rootname,)e(int)h(*status\);)0 3615 y Fi(8)81
+b Fj(T)-8 b(est)37 b(if)e(the)i(input)e(\014le)h(or)g(a)h(compressed)g
+(v)m(ersion)f(of)h(the)g(\014le)e(\(with)h(a)h(.gz,)j(.Z,)c(.z,)j(or)e
+(.zip)f(extension\))227 3728 y(exists)i(on)g(disk.)62
+b(The)37 b(returned)g(v)-5 b(alue)37 b(of)h(the)h('exists')f(parameter)
+g(will)d(ha)m(v)m(e)40 b(1)e(of)g(the)g(4)g(follo)m(wing)227
+3841 y(v)-5 b(alues:)370 4087 y Fe(2:)95 b(the)47 b(file)g(does)g(not)f
+(exist,)h(but)f(a)i(compressed)d(version)h(does)g(exist)370
+4200 y(1:)95 b(the)47 b(disk)g(file)g(does)f(exist)370
+4313 y(0:)95 b(neither)46 b(the)h(file)g(nor)g(a)g(compressed)e
+(version)h(of)h(the)g(file)g(exist)323 4426 y(-1:)94
+b(the)47 b(input)g(file)f(name)h(is)g(not)g(a)g(disk)g(file)g(\(could)f
+(be)h(a)g(ftp,)g(http,)561 4539 y(smem,)g(or)g(mem)g(file,)f(or)h(a)h
+(file)e(piped)h(in)g(on)g(the)g(STDIN)f(stream\))143
+4892 y(int)h(fits_file_exists)c(/)48 b(ffexist)334 5005
+y(\(char)e(*filename,)f(>)j(int)f(*exists,)e(int)i(*status\);)0
+5262 y Fi(9)81 b Fj(Flush)35 b(an)m(y)j(in)m(ternal)e(bu\013ers)g(of)i
+(data)g(to)g(the)f(output)g(FITS)g(\014le.)61 b(These)37
+b(routines)f(rarely)g(need)h(to)i(b)s(e)227 5375 y(called,)g(but)d(can)
+i(b)s(e)f(useful)e(in)h(cases)j(where)d(other)i(pro)s(cesses)f(need)g
+(to)h(access)h(the)f(same)f(FITS)g(\014le)227 5488 y(in)i(real)i(time,)
+h(either)e(on)h(disk)e(or)h(in)f(memory)-8 b(.)71 b(These)41
+b(routines)e(also)h(help)f(to)j(ensure)d(that)i(if)f(the)227
+5601 y(application)34 b(program)g(subsequen)m(tly)g(ab)s(orts)g(then)h
+(the)g(FITS)f(\014le)g(will)e(ha)m(v)m(e)37 b(b)s(een)d(closed)g(prop)s
+(erly)-8 b(.)227 5714 y(The)43 b(\014rst)g(routine,)j(\014ts)p
+1110 5714 V 33 w(\015ush)p 1332 5714 V 31 w(\014le)c(is)h(more)g
+(rigorous)g(and)g(completely)g(closes,)k(then)d(reop)s(ens,)i(the)p
+eop
+%%Page: 84 92
+84 91 bop 0 299 a Fj(84)1003 b Fh(CHAPTER)30 b(9.)112
+b(SPECIALIZED)28 b(CFITSIO)h(INTERF)-10 b(A)m(CE)30 b(R)m(OUTINES)227
+555 y Fj(curren)m(t)h(HDU,)h(b)s(efore)e(\015ushing)f(the)i(in)m
+(ternal)e(bu\013ers,)h(th)m(us)h(ensuring)e(that)i(the)g(output)g(FITS)
+f(\014le)g(is)227 668 y(iden)m(tical)35 b(to)h(what)f(w)m(ould)g(b)s(e)
+g(pro)s(duced)f(if)g(the)i(FITS)f(w)m(as)h(closed)f(at)h(that)g(p)s
+(oin)m(t)f(\(i.e.,)i(with)e(a)h(call)227 781 y(to)g(\014ts)p
+470 781 28 4 v 33 w(close)p 690 781 V 33 w(\014le\).)55
+b(The)35 b(second)g(routine,)h(\014ts)p 1912 781 V 33
+w(\015ush)p 2134 781 V 31 w(bu\013er)e(simply)f(\015ushes)h(the)h(in)m
+(ternal)f(CFITSIO)227 894 y(bu\013ers)28 b(of)h(data)h(to)f(the)h
+(output)e(FITS)g(\014le,)h(without)f(up)s(dating)f(and)h(closing)g(the)
+h(curren)m(t)g(HDU.)h(This)227 1007 y(is)36 b(m)m(uc)m(h)h(faster,)i
+(but)e(there)g(ma)m(y)g(b)s(e)f(circumstances)h(where)f(the)h
+(\015ushed)f(\014le)g(do)s(es)g(not)h(completely)227
+1120 y(re\015ect)31 b(the)g(\014nal)e(state)j(of)e(the)h(\014le)e(as)i
+(it)f(will)d(exist)k(when)e(the)h(\014le)g(is)f(actually)h(closed.)227
+1266 y(A)h(t)m(ypical)f(use)g(of)h(these)g(routines)e(w)m(ould)g(b)s(e)
+h(to)h(\015ush)e(the)h(state)i(of)f(a)g(FITS)e(table)i(to)g(disk)e
+(after)i(eac)m(h)227 1379 y(ro)m(w)36 b(of)f(the)h(table)f(is)f
+(written.)54 b(It)36 b(is)e(recommend)h(that)h(\014ts)p
+2392 1379 V 32 w(\015ush)p 2613 1379 V 32 w(\014le)e(b)s(e)h(called)f
+(after)i(the)f(\014rst)g(ro)m(w)227 1492 y(is)j(written,)i(then)e
+(\014ts)p 1023 1492 V 32 w(\015ush)p 1244 1492 V 31 w(bu\013er)g(ma)m
+(y)h(b)s(e)f(called)f(after)i(eac)m(h)h(subsequen)m(t)e(ro)m(w)g(is)g
+(written.)64 b(Note)227 1605 y(that)40 b(this)e(latter)h(routine)f
+(will)e(not)j(automatically)g(up)s(date)f(the)h(NAXIS2)g(k)m(eyw)m(ord)
+h(whic)m(h)d(records)227 1718 y(the)d(n)m(um)m(b)s(er)d(of)i(ro)m(ws)h
+(of)f(data)g(in)f(the)h(table,)h(so)g(this)e(k)m(eyw)m(ord)h(m)m(ust)g
+(b)s(e)f(explicitly)f(up)s(dated)h(b)m(y)h(the)227 1831
+y(application)c(program)h(after)h(eac)m(h)h(ro)m(w)e(is)f(written.)95
+2067 y Fe(int)47 b(fits_flush_file)d(/)j(ffflus)286 2180
+y(\(fitsfile)f(*fptr,)g(>)h(int)g(*status\))95 2406 y(int)g
+(fits_flush_buffer)c(/)48 b(ffflsh)286 2519 y(\(fitsfile)e(*fptr,)g(0,)
+h(>)g(int)g(*status\))286 2745 y(\(Note:)94 b(The)47
+b(second)f(argument)g(must)g(be)i(0\).)0 3075 y Ff(9.2)135
+b(HDU)46 b(Access)e(Routines)0 3311 y Fi(1)81 b Fj(Get)28
+b(the)f(b)m(yte)h(o\013sets)g(in)e(the)h(FITS)f(\014le)h(to)g(the)h
+(start)g(of)f(the)g(header)g(and)g(the)g(start)h(and)e(end)h(of)g(the)g
+(data)227 3424 y(in)33 b(the)h(CHDU.)g(The)f(di\013erence)g(b)s(et)m(w)
+m(een)i(headstart)f(and)f(dataend)h(equals)f(the)h(size)f(of)h(the)g
+(CHDU.)227 3537 y(If)e(the)h(CHDU)f(is)g(the)g(last)g(HDU)h(in)e(the)i
+(\014le,)f(then)g(dataend)g(is)f(also)i(equal)e(to)i(the)g(size)f(of)h
+(the)f(en)m(tire)227 3650 y(FITS)25 b(\014le.)38 b(Null)24
+b(p)s(oin)m(ters)g(ma)m(y)i(b)s(e)f(input)e(for)j(an)m(y)f(of)h(the)g
+(address)e(parameters)i(if)f(their)f(v)-5 b(alues)25
+b(are)h(not)227 3763 y(needed.)54 b(The)34 b(\014ts)p
+897 3763 V 32 w(get)p 1049 3763 V 34 w(hduaddr)e(routine)i(is)g
+(obsolete)h(and)f(should)f(no)i(longer)f(b)s(e)g(used.)53
+b(The)34 b(new)m(er)227 3876 y(\014ts)p 354 3876 V 33
+w(get)p 507 3876 V 34 w(hduo\013)24 b(routine)h(uses)g(the)h('o\013)p
+1588 3876 V 33 w(t')g(data)h(t)m(yp)s(e)f(whic)m(h)e(can)i(supp)s(ort)e
+(o\013sets)i(in)e(large)i(\014les)f(greater)227 3988
+y(than)30 b(2.1GB)j(in)c(size.)95 4225 y Fe(int)47 b(fits_get_hduoff)d
+(/)j(ffghof)334 4338 y(\(fitsfile)e(*fptr,)h(>)i(off_t)e(*headstart,)f
+(off_t)h(*datastart,)f(off_t)h(*dataend,)382 4451 y(int)h(*status\))95
+4676 y(int)g(fits_get_hduaddr)d(/)j(ffghad)94 b(\(OBSOLETE)45
+b(routine\))334 4789 y(\(fitsfile)g(*fptr,)h(>)i(long)f(*headstart,)d
+(long)j(*datastart,)e(long)h(*dataend,)382 4902 y(int)h(*status\))0
+5139 y Fi(2)81 b Fj(Create)31 b(\(app)s(end\))f(a)i(new)e(empt)m(y)i
+(HDU)f(at)h(the)f(end)f(of)i(the)f(FITS)f(\014le.)41
+b(This)30 b(is)g(no)m(w)h(the)g(CHDU)g(but)f(it)227 5252
+y(is)h(completely)f(empt)m(y)i(and)f(has)g(no)g(header)g(k)m(eyw)m
+(ords.)43 b(It)32 b(is)e(recommended)h(that)h(\014ts)p
+3344 5252 V 32 w(create)p 3612 5252 V 34 w(img)f(or)227
+5365 y(\014ts)p 354 5365 V 33 w(create)p 623 5365 V 34
+w(tbl)e(b)s(e)h(used)g(instead)f(of)i(this)e(routine.)95
+5601 y Fe(int)47 b(fits_create_hdu)d(/)j(ffcrhd)286 5714
+y(\(fitsfile)f(*fptr,)g(>)h(int)g(*status\))p eop
+%%Page: 85 93
+85 92 bop 0 299 a Fh(9.2.)72 b(HDU)31 b(A)m(CCESS)e(R)m(OUTINES)2488
+b Fj(85)0 555 y Fi(3)81 b Fj(Insert)22 b(a)h(new)g(IMA)m(GE)h
+(extension)e(immediately)g(follo)m(wing)f(the)i(CHDU,)h(or)f(insert)f
+(a)h(new)f(Primary)g(Arra)m(y)227 668 y(at)30 b(the)e(b)s(eginning)e
+(of)j(the)g(\014le.)39 b(An)m(y)29 b(follo)m(wing)e(extensions)h(in)g
+(the)g(\014le)g(will)e(b)s(e)i(shifted)f(do)m(wn)i(to)g(mak)m(e)227
+781 y(ro)s(om)36 b(for)h(the)f(new)g(extension.)58 b(If)36
+b(the)h(CHDU)g(is)e(the)i(last)f(HDU)h(in)e(the)i(\014le)e(then)h(the)h
+(new)f(image)227 894 y(extension)30 b(will)e(simply)f(b)s(e)j(app)s
+(ended)e(to)j(the)f(end)g(of)g(the)g(\014le.)40 b(One)30
+b(can)g(force)h(a)g(new)e(primary)f(arra)m(y)227 1007
+y(to)35 b(b)s(e)d(inserted)h(at)h(the)g(b)s(eginning)d(of)i(the)h(FITS)
+f(\014le)f(b)m(y)i(setting)g(status)f(=)h(PREPEND)p 3432
+1007 28 4 v 32 w(PRIMAR)-8 b(Y)227 1120 y(prior)24 b(to)h(calling)f
+(the)h(routine.)37 b(In)25 b(this)e(case)j(the)f(old)f(primary)f(arra)m
+(y)j(will)c(b)s(e)i(con)m(v)m(erted)j(to)e(an)g(IMA)m(GE)227
+1233 y(extension.)48 b(The)32 b(new)g(extension)h(\(or)g(primary)e
+(arra)m(y\))i(will)e(b)s(ecome)i(the)g(CHDU.)g(Refer)g(to)h(Chapter)227
+1346 y(9)d(for)f(a)h(list)e(of)h(pre-de\014ned)f(bitpix)g(v)-5
+b(alues.)95 1605 y Fe(int)47 b(fits_insert_img)d(/)j(ffiimg)286
+1718 y(\(fitsfile)f(*fptr,)g(int)h(bitpix,)e(int)i(naxis,)f(long)h
+(*naxes,)f(>)h(int)g(*status\))0 1978 y Fi(4)81 b Fj(Insert)30
+b(a)g(new)g(ASCI)s(I)f(or)i(binary)e(table)h(extension)g(immediately)f
+(follo)m(wing)g(the)i(CHDU.)g(An)m(y)f(follo)m(wing)227
+2091 y(extensions)35 b(will)e(b)s(e)i(shifted)f(do)m(wn)h(to)h(mak)m(e)
+g(ro)s(om)g(for)f(the)g(new)g(extension.)56 b(If)35 b(there)h(are)f(no)
+h(other)227 2204 y(follo)m(wing)29 b(extensions)i(then)f(the)h(new)f
+(table)g(extension)h(will)d(simply)g(b)s(e)i(app)s(ended)f(to)i(the)g
+(end)f(of)h(the)227 2317 y(\014le.)41 b(If)30 b(the)h(FITS)f(\014le)f
+(is)h(curren)m(tly)g(empt)m(y)h(then)f(this)f(routine)h(will)e(create)k
+(a)f(dumm)m(y)f(primary)e(arra)m(y)227 2430 y(b)s(efore)j(app)s(ending)
+e(the)j(table)g(to)g(it.)43 b(The)31 b(new)g(extension)h(will)c(b)s
+(ecome)k(the)g(CHDU.)g(The)f(tunit)g(and)227 2543 y(extname)39
+b(parameters)g(are)f(optional)g(and)g(a)g(n)m(ull)e(p)s(oin)m(ter)i(ma)
+m(y)g(b)s(e)g(giv)m(en)g(if)f(they)i(are)f(not)h(de\014ned.)227
+2656 y(When)32 b(inserting)e(an)i(ASCI)s(I)f(table)h(with)e(\014ts)p
+1847 2656 V 33 w(insert)p 2104 2656 V 32 w(atbl,)i(a)g(n)m(ull)e(p)s
+(oin)m(ter)h(ma)m(y)i(giv)m(en)f(for)g(the)g(*tb)s(col)227
+2769 y(parameter)23 b(in)e(whic)m(h)h(case)h(eac)m(h)h(column)d(of)i
+(the)g(table)f(will)e(b)s(e)i(separated)h(b)m(y)f(a)h(single)e(space)i
+(c)m(haracter.)227 2882 y(Similarly)-8 b(,)25 b(if)g(the)i(input)e(v)-5
+b(alue)26 b(of)h(ro)m(wlen)f(is)f(0,)j(then)f(CFITSIO)e(will)f
+(calculate)j(the)g(default)e(ro)m(wlength)227 2994 y(based)40
+b(on)h(the)g(tb)s(col)e(and)h(tt)m(yp)s(e)h(v)-5 b(alues.)71
+b(When)40 b(inserting)f(a)i(binary)d(table)j(with)e(\014ts)p
+3430 2994 V 32 w(insert)p 3686 2994 V 32 w(btbl,)227
+3107 y(if)g(there)i(are)f(follo)m(wing)f(extensions)h(in)f(the)h
+(\014le)f(and)h(if)f(the)h(table)g(con)m(tains)h(v)-5
+b(ariable)39 b(length)g(arra)m(y)227 3220 y(columns)28
+b(then)h(p)s(coun)m(t)g(m)m(ust)g(sp)s(ecify)f(the)i(exp)s(ected)g
+(\014nal)e(size)h(of)g(the)h(data)g(heap,)g(otherwise)e(p)s(coun)m(t)
+227 3333 y(m)m(ust)j(=)f(0.)95 3593 y Fe(int)47 b(fits_insert_atbl)d(/)
+j(ffitab)286 3706 y(\(fitsfile)f(*fptr,)g(long)g(rowlen,)g(long)h
+(nrows,)f(int)h(tfields,)e(char)i(*ttype[],)334 3819
+y(long)g(*tbcol,)f(char)g(*tform[],)f(char)i(*tunit[],)e(char)i
+(*extname,)e(>)j(int)f(*status\))95 4045 y(int)g(fits_insert_btbl)d(/)j
+(ffibin)286 4158 y(\(fitsfile)f(*fptr,)g(long)g(nrows,)g(int)h
+(tfields,)f(char)h(**ttype,)286 4271 y(char)g(**tform,)f(char)g
+(**tunit,)g(char)g(*extname,)g(long)g(pcount,)g(>)i(int)e(*status\))0
+4530 y Fi(5)81 b Fj(Mo)s(dify)26 b(the)i(size,)g(dimensions,)e(and/or)h
+(data)i(t)m(yp)s(e)f(of)f(the)h(curren)m(t)g(primary)d(arra)m(y)j(or)g
+(image)g(extension.)227 4643 y(If)39 b(the)h(new)e(image,)43
+b(as)c(sp)s(eci\014ed)f(b)m(y)h(the)g(input)f(argumen)m(ts,)k(is)c
+(larger)h(than)g(the)h(curren)m(t)f(existing)227 4756
+y(image)29 b(in)e(the)h(FITS)g(\014le)f(then)h(zero)h(\014ll)d(data)j
+(will)d(b)s(e)i(inserted)f(at)i(the)f(end)g(of)g(the)h(curren)m(t)f
+(image)h(and)227 4869 y(an)m(y)35 b(follo)m(wing)e(extensions)h(will)e
+(b)s(e)i(mo)m(v)m(ed)i(further)d(bac)m(k)i(in)f(the)g(\014le.)53
+b(Similarly)-8 b(,)32 b(if)i(the)h(new)f(image)227 4982
+y(is)i(smaller)f(than)i(the)f(curren)m(t)h(image)g(then)f(an)m(y)h
+(follo)m(wing)e(extensions)h(will)e(b)s(e)i(shifted)g(up)f(to)m(w)m
+(ards)227 5095 y(the)h(b)s(eginning)d(of)j(the)g(FITS)f(\014le)g(and)g
+(the)h(image)g(data)g(will)e(b)s(e)h(truncated)g(to)i(the)f(new)f
+(size.)57 b(This)227 5208 y(routine)26 b(rewrites)g(the)i(BITPIX,)f
+(NAXIS,)g(and)f(NAXISn)g(k)m(eyw)m(ords)i(with)e(the)h(appropriate)f(v)
+-5 b(alues)26 b(for)227 5321 y(the)31 b(new)f(image.)95
+5581 y Fe(int)47 b(fits_resize_img)d(/)j(ffrsim)286 5694
+y(\(fitsfile)f(*fptr,)g(int)h(bitpix,)e(int)i(naxis,)f(long)h(*naxes,)f
+(>)h(int)g(*status\))p eop
+%%Page: 86 94
+86 93 bop 0 299 a Fj(86)1003 b Fh(CHAPTER)30 b(9.)112
+b(SPECIALIZED)28 b(CFITSIO)h(INTERF)-10 b(A)m(CE)30 b(R)m(OUTINES)0
+555 y Fi(6)81 b Fj(Cop)m(y)43 b(the)h(data)h(\(and)e(not)h(the)g
+(header\))g(from)f(the)h(CHDU)g(asso)s(ciated)g(with)f(infptr)e(to)k
+(the)f(CHDU)227 668 y(asso)s(ciated)33 b(with)e(outfptr.)47
+b(This)31 b(will)e(o)m(v)m(erwrite)k(an)m(y)g(data)g(previously)e(in)g
+(the)i(output)f(CHDU.)h(This)227 781 y(lo)m(w)38 b(lev)m(el)g(routine)f
+(is)g(used)g(b)m(y)h(\014ts)p 1510 781 28 4 v 33 w(cop)m(y)p
+1724 781 V 33 w(hdu,)h(but)e(it)h(ma)m(y)g(also)g(b)s(e)g(useful)e(in)h
+(certain)h(application)227 894 y(programs)30 b(that)h(w)m(an)m(t)g(to)g
+(cop)m(y)g(the)f(data)h(from)f(one)h(FITS)e(\014le)h(to)h(another)f
+(but)f(also)i(w)m(an)m(t)g(to)g(mo)s(dify)227 1007 y(the)h(header)g(k)m
+(eyw)m(ords.)46 b(The)32 b(required)e(FITS)h(header)h(k)m(eyw)m(ords)g
+(whic)m(h)f(de\014ne)g(the)h(structure)g(of)g(the)227
+1120 y(HDU)f(m)m(ust)g(b)s(e)e(written)h(to)h(the)f(output)g(CHDU)h(b)s
+(efore)f(calling)f(this)g(routine.)95 1369 y Fe(int)47
+b(fits_copy_data)d(/)k(ffcpdt)286 1482 y(\(fitsfile)e(*infptr,)f
+(fitsfile)h(*outfptr,)f(>)i(int)g(*status\))0 1732 y
+Fi(7)81 b Fj(This)33 b(routine)g(forces)i(CFITSIO)f(to)h(rescan)g(the)g
+(curren)m(t)g(header)f(k)m(eyw)m(ords)h(that)g(de\014ne)f(the)h
+(structure)227 1845 y(of)f(the)f(HDU)h(\(suc)m(h)g(as)f(the)h(NAXIS)f
+(and)g(BITPIX)g(k)m(eyw)m(ords\))h(so)f(that)h(it)f(reinitializes)e
+(the)i(in)m(ternal)227 1958 y(bu\013ers)26 b(that)h(describ)s(e)f(the)h
+(HDU)g(structure.)39 b(This)25 b(routine)h(is)g(useful)f(for)h
+(reinitializing)d(the)k(structure)227 2071 y(of)34 b(an)f(HDU)h(if)e
+(an)m(y)i(of)g(the)f(required)f(k)m(eyw)m(ords)h(\(e.g.,)j(NAXISn\))d
+(ha)m(v)m(e)i(b)s(een)e(mo)s(di\014ed.)47 b(In)33 b(practice)227
+2184 y(it)d(should)e(rarely)h(b)s(e)g(necessary)h(to)h(call)e(this)g
+(routine)g(b)s(ecause)g(CFITSIO)g(in)m(ternally)f(calls)h(it)g(in)g
+(most)227 2297 y(situations.)95 2546 y Fe(int)47 b(fits_set_hdustruc)c
+(/)48 b(ffrdef)286 2659 y(\(fitsfile)e(*fptr,)g(>)h(int)g(*status\))141
+b(\(DEPRECATED\))0 2991 y Ff(9.3)135 b(Sp)t(ecialized)46
+b(Header)g(Keyw)l(ord)f(Routines)0 3245 y Fd(9.3.1)112
+b(Header)38 b(Information)f(Routines)0 3452 y Fi(1)81
+b Fj(Reserv)m(e)29 b(space)g(in)d(the)j(CHU)f(for)g(MOREKEYS)f(more)h
+(header)g(k)m(eyw)m(ords.)41 b(This)26 b(routine)h(ma)m(y)i(b)s(e)f
+(called)227 3565 y(to)34 b(allo)s(cate)f(space)g(for)f(additional)f(k)m
+(eyw)m(ords)i(at)g(the)g(time)f(the)h(header)f(is)g(created)h(\(prior)f
+(to)h(writing)227 3678 y(an)m(y)h(data\).)51 b(CFITSIO)32
+b(can)i(dynamically)d(add)i(more)g(space)h(to)g(the)g(header)f(when)f
+(needed,)j(ho)m(w)m(ev)m(er)227 3791 y(it)30 b(is)g(more)g(e\016cien)m
+(t)h(to)g(preallo)s(cate)f(the)h(required)e(space)i(if)e(the)h(size)h
+(is)e(kno)m(wn)h(in)f(adv)-5 b(ance.)95 4041 y Fe(int)47
+b(fits_set_hdrsize)d(/)j(ffhdef)286 4153 y(\(fitsfile)f(*fptr,)g(int)h
+(morekeys,)e(>)i(int)g(*status\))0 4403 y Fi(2)81 b Fj(Return)26
+b(the)h(n)m(um)m(b)s(er)e(of)j(k)m(eyw)m(ords)f(in)e(the)i(header)g
+(\(not)h(coun)m(ting)f(the)g(END)g(k)m(eyw)m(ord\))h(and)e(the)h
+(curren)m(t)227 4516 y(p)s(osition)32 b(in)h(the)h(header.)50
+b(The)34 b(p)s(osition)d(is)i(the)h(n)m(um)m(b)s(er)f(of)h(the)g(k)m
+(eyw)m(ord)g(record)f(that)i(will)c(b)s(e)i(read)227
+4629 y(next)k(\(or)g(one)f(greater)i(than)e(the)h(p)s(osition)d(of)j
+(the)g(last)f(k)m(eyw)m(ord)h(that)g(w)m(as)g(read\).)59
+b(A)37 b(v)-5 b(alue)35 b(of)i(1)g(is)227 4742 y(returned)29
+b(if)h(the)g(p)s(oin)m(ter)g(is)f(p)s(ositioned)g(at)i(the)f(b)s
+(eginning)e(of)i(the)h(header.)95 4992 y Fe(int)47 b(fits_get_hdrpos)d
+(/)j(ffghps)286 5105 y(\(fitsfile)f(*fptr,)g(>)h(int)g(*keysexist,)e
+(int)i(*keynum,)e(int)i(*status\))0 5394 y Fd(9.3.2)112
+b(Read)38 b(and)h(W)-9 b(rite)35 b(the)i(Required)g(Keyw)m(ords)0
+5601 y Fi(1)81 b Fj(W)-8 b(rite)20 b(the)h(primary)d(header)i(or)g(IMA)
+m(GE)i(extension)e(k)m(eyw)m(ords)g(in)m(to)g(the)h(CHU.)f(The)g
+(simpler)e(\014ts)p 3535 5601 V 32 w(write)p 3770 5601
+V 32 w(imghdr)227 5714 y(routine)32 b(is)h(equiv)-5 b(alen)m(t)32
+b(to)i(calling)e(\014ts)p 1604 5714 V 32 w(write)p 1839
+5714 V 32 w(grphdr)f(with)h(the)i(default)e(v)-5 b(alues)32
+b(of)i(simple)d(=)i(TR)m(UE,)p eop
+%%Page: 87 95
+87 94 bop 0 299 a Fh(9.3.)72 b(SPECIALIZED)29 b(HEADER)i(KEYW)m(ORD)g
+(R)m(OUTINES)1510 b Fj(87)227 555 y(p)s(coun)m(t)39 b(=)g(0,)j(gcoun)m
+(t)e(=)f(1,)j(and)c(extend)h(=)g(TR)m(UE.)g(The)g(PCOUNT,)g(GCOUNT)f
+(and)h(EXTEND)227 668 y(k)m(eyw)m(ords)32 b(are)f(not)g(required)f(in)f
+(the)i(primary)f(header)g(and)h(are)g(only)f(written)g(if)g(p)s(coun)m
+(t)h(is)f(not)h(equal)227 781 y(to)26 b(zero,)h(gcoun)m(t)f(is)e(not)i
+(equal)e(to)i(zero)g(or)f(one,)h(and)f(if)f(extend)h(is)f(TR)m(UE,)h
+(resp)s(ectiv)m(ely)-8 b(.)39 b(When)25 b(writing)227
+894 y(to)37 b(an)f(IMA)m(GE)h(extension,)h(the)e(SIMPLE)f(and)h(EXTEND)
+g(parameters)g(are)h(ignored.)57 b(It)36 b(is)f(recom-)227
+1007 y(mended)27 b(that)i(\014ts)p 885 1007 28 4 v 33
+w(create)p 1154 1007 V 34 w(image)g(or)f(\014ts)p 1680
+1007 V 32 w(create)p 1948 1007 V 35 w(tbl)f(b)s(e)g(used)h(instead)f
+(of)i(these)f(routines)f(to)i(write)f(the)227 1120 y(required)h(header)
+h(k)m(eyw)m(ords.)95 1374 y Fe(int)47 b(fits_write_imghdr)c(/)48
+b(ffphps)286 1487 y(\(fitsfile)e(*fptr,)g(int)h(bitpix,)e(int)i(naxis,)
+f(long)h(*naxes,)f(>)h(int)g(*status\))95 1713 y(int)g
+(fits_write_grphdr)c(/)48 b(ffphpr)286 1826 y(\(fitsfile)e(*fptr,)g
+(int)h(simple,)e(int)i(bitpix,)f(int)h(naxis,)f(long)h(*naxes,)334
+1939 y(long)g(pcount,)f(long)g(gcount,)g(int)h(extend,)f(>)h(int)g
+(*status\))0 2194 y Fi(2)81 b Fj(W)-8 b(rite)29 b(the)h(ASCI)s(I)d
+(table)j(header)f(k)m(eyw)m(ords)g(in)m(to)h(the)f(CHU.)h(The)e
+(optional)h(TUNITn)f(and)h(EXTNAME)227 2307 y(k)m(eyw)m(ords)f(are)h
+(written)d(only)h(if)g(the)h(input)e(p)s(oin)m(ters)h(are)h(not)g(n)m
+(ull.)38 b(A)27 b(n)m(ull)f(p)s(oin)m(ter)h(ma)m(y)h(giv)m(en)g(for)g
+(the)227 2419 y(*tb)s(col)36 b(parameter)h(in)e(whic)m(h)g(case)j(a)e
+(single)f(space)i(will)d(b)s(e)i(inserted)f(b)s(et)m(w)m(een)i(eac)m(h)
+g(column)e(of)i(the)227 2532 y(table.)56 b(Similarly)-8
+b(,)33 b(if)i(ro)m(wlen)f(is)h(giv)m(en)g(=)g(0,)i(then)e(CFITSIO)f
+(will)f(calculate)i(the)h(default)e(ro)m(wlength)227
+2645 y(based)c(on)h(the)f(tb)s(col)g(and)g(tt)m(yp)s(e)h(v)-5
+b(alues.)95 2900 y Fe(int)47 b(fits_write_atblhdr)c(/)48
+b(ffphtb)286 3013 y(\(fitsfile)e(*fptr,)g(long)g(rowlen,)g(long)h
+(nrows,)f(int)h(tfields,)e(char)i(**ttype,)334 3126 y(long)g(*tbcol,)f
+(char)g(**tform,)g(char)g(**tunit,)g(char)h(*extname,)e(>)i(int)g
+(*status\))0 3380 y Fi(3)81 b Fj(W)-8 b(rite)29 b(the)g(binary)f(table)
+h(header)f(k)m(eyw)m(ords)i(in)m(to)f(the)g(CHU.)g(The)g(optional)f
+(TUNITn)g(and)h(EXTNAME)227 3493 y(k)m(eyw)m(ords)35
+b(are)g(written)f(only)g(if)f(the)i(input)e(p)s(oin)m(ters)g(are)i(not)
+g(n)m(ull.)51 b(The)35 b(p)s(coun)m(t)f(parameter,)i(whic)m(h)227
+3606 y(sp)s(eci\014es)g(the)h(size)f(of)h(the)g(v)-5
+b(ariable)36 b(length)g(arra)m(y)h(heap,)h(should)d(initially)e(=)k(0;)
+j(CFITSIO)c(will)e(au-)227 3719 y(tomatically)d(up)s(date)g(the)g
+(PCOUNT)f(k)m(eyw)m(ord)i(v)-5 b(alue)31 b(if)f(an)m(y)h(v)-5
+b(ariable)30 b(length)h(arra)m(y)h(data)g(is)e(written)227
+3832 y(to)h(the)e(heap.)41 b(The)29 b(TF)m(ORM)g(k)m(eyw)m(ord)h(v)-5
+b(alue)29 b(for)h(v)-5 b(ariable)28 b(length)h(v)m(ector)i(columns)d
+(should)g(ha)m(v)m(e)j(the)227 3945 y(form)c('Pt\(len\)')i(or)e
+('1Pt\(len\)')i(where)e(`t')h(is)f(the)h(data)g(t)m(yp)s(e)g(co)s(de)f
+(letter)h(\(A,I,J,E,D,)h(etc.\))42 b(and)27 b(`len')g(is)227
+4058 y(an)h(in)m(teger)h(sp)s(ecifying)d(the)i(maxim)m(um)f(length)g
+(of)i(the)f(v)m(ectors)h(in)e(that)i(column)e(\(len)g(m)m(ust)h(b)s(e)g
+(greater)227 4171 y(than)36 b(or)g(equal)g(to)h(the)f(longest)h(v)m
+(ector)g(in)e(the)i(column\).)57 b(If)36 b(`len')f(is)h(not)g(sp)s
+(eci\014ed)f(when)g(the)h(table)227 4284 y(is)31 b(created)h(\(e.g.,)h
+(the)f(input)d(TF)m(ORMn)i(v)-5 b(alue)31 b(is)f(just)h('1Pt'\))i(then)
+e(CFITSIO)f(will)e(scan)k(the)f(column)227 4397 y(when)f(the)h(table)g
+(is)f(\014rst)g(closed)g(and)h(will)d(app)s(end)h(the)i(maxim)m(um)f
+(length)g(to)h(the)g(TF)m(ORM)g(k)m(eyw)m(ord)227 4509
+y(v)-5 b(alue.)40 b(Note)30 b(that)f(if)e(the)i(table)f(is)g(subsequen)
+m(tly)f(mo)s(di\014ed)f(to)k(increase)e(the)h(maxim)m(um)e(length)h(of)
+h(the)227 4622 y(v)m(ectors)39 b(then)e(the)g(mo)s(difying)e(program)i
+(is)f(resp)s(onsible)f(for)i(also)g(up)s(dating)e(the)j(TF)m(ORM)f(k)m
+(eyw)m(ord)227 4735 y(v)-5 b(alue.)95 4990 y Fe(int)47
+b(fits_write_btblhdr)c(/)48 b(ffphbn)286 5103 y(\(fitsfile)e(*fptr,)g
+(long)g(nrows,)g(int)h(tfields,)f(char)h(**ttype,)334
+5216 y(char)g(**tform,)e(char)i(**tunit,)e(char)i(*extname,)e(long)i
+(pcount,)f(>)h(int)g(*status\))0 5470 y Fi(4)81 b Fj(Read)30
+b(the)h(required)d(k)m(eyw)m(ords)j(from)f(the)h(CHDU)f(\(image)i(or)e
+(table\).)41 b(When)30 b(reading)g(from)g(an)g(IMA)m(GE)227
+5583 y(extension)23 b(the)h(SIMPLE)e(and)h(EXTEND)g(parameters)h(are)f
+(ignored.)38 b(A)23 b(n)m(ull)e(p)s(oin)m(ter)i(ma)m(y)h(b)s(e)e
+(supplied)227 5696 y(for)30 b(an)m(y)h(of)g(the)f(returned)f
+(parameters)i(that)g(are)g(not)f(needed.)p eop
+%%Page: 88 96
+88 95 bop 0 299 a Fj(88)1003 b Fh(CHAPTER)30 b(9.)112
+b(SPECIALIZED)28 b(CFITSIO)h(INTERF)-10 b(A)m(CE)30 b(R)m(OUTINES)95
+555 y Fe(int)47 b(fits_read_imghdr)d(/)j(ffghpr)286 668
+y(\(fitsfile)f(*fptr,)g(int)h(maxdim,)e(>)j(int)f(*simple,)e(int)i
+(*bitpix,)f(int)h(*naxis,)334 781 y(long)g(*naxes,)f(long)g(*pcount,)g
+(long)g(*gcount,)g(int)h(*extend,)e(int)i(*status\))95
+1007 y(int)g(fits_read_atblhdr)c(/)48 b(ffghtb)286 1120
+y(\(fitsfile)e(*fptr,int)f(maxdim,)h(>)h(long)g(*rowlen,)e(long)i
+(*nrows,)334 1233 y(int)g(*tfields,)e(char)i(**ttype,)e(long)i(*tbcol,)
+f(char)h(**tform,)e(char)i(**tunit,)334 1346 y(char)g(*extname,)93
+b(int)47 b(*status\))95 1571 y(int)g(fits_read_btblhdr)c(/)48
+b(ffghbn)286 1684 y(\(fitsfile)e(*fptr,)g(int)h(maxdim,)e(>)j(long)f
+(*nrows,)e(int)i(*tfields,)334 1797 y(char)g(**ttype,)e(char)i
+(**tform,)e(char)i(**tunit,)f(char)g(*extname,)334 1910
+y(long)h(*pcount,)e(int)i(*status\))0 2197 y Fd(9.3.3)112
+b(W)-9 b(rite)36 b(Keyw)m(ord)h(Routines)0 2416 y Fj(These)32
+b(routines)g(simply)e(app)s(end)h(a)h(new)g(k)m(eyw)m(ord)h(to)h(the)e
+(header)h(and)f(do)g(not)h(c)m(hec)m(k)h(to)f(see)g(if)f(a)g(k)m(eyw)m
+(ord)0 2528 y(with)c(the)h(same)h(name)f(already)g(exists.)40
+b(In)28 b(general)h(it)g(is)f(preferable)g(to)i(use)f(the)h(\014ts)p
+3009 2528 28 4 v 32 w(up)s(date)p 3317 2528 V 32 w(k)m(ey)g(routine)e
+(to)0 2641 y(ensure)34 b(that)h(the)g(same)g(k)m(eyw)m(ord)g(is)e(not)i
+(written)f(more)h(than)f(once)h(to)h(the)e(header.)54
+b(See)34 b(App)s(endix)e(B)j(for)0 2754 y(the)c(de\014nition)d(of)i
+(the)h(parameters)f(used)g(in)f(these)i(routines.)0 2988
+y Fi(1)81 b Fj(W)-8 b(rite)29 b(\(app)s(end\))g(a)g(new)g(k)m(eyw)m
+(ord)h(of)g(the)f(appropriate)f(data)i(t)m(yp)s(e)g(in)m(to)f(the)h
+(CHU.)f(A)h(n)m(ull)d(p)s(oin)m(ter)h(ma)m(y)227 3101
+y(b)s(e)35 b(en)m(tered)h(for)f(the)h(commen)m(t)h(parameter,)g(whic)m
+(h)d(will)f(cause)j(the)g(commen)m(t)g(\014eld)e(of)i(the)f(k)m(eyw)m
+(ord)227 3214 y(to)43 b(b)s(e)e(left)h(blank.)75 b(The)41
+b(\015t,)k(dbl,)e(cmp,)i(and)d(dblcmp)e(v)m(ersions)h(of)h(this)f
+(routine)g(ha)m(v)m(e)i(the)g(added)227 3327 y(feature)33
+b(that)g(if)f(the)g('decimals')g(parameter)h(is)f(negativ)m(e,)i(then)e
+(the)h('G')g(displa)m(y)e(format)i(rather)f(then)227
+3440 y(the)i('E')f(format)h(will)c(b)s(e)j(used)f(when)g(constructing)h
+(the)h(k)m(eyw)m(ord)f(v)-5 b(alue,)34 b(taking)f(the)h(absolute)e(v)-5
+b(alue)227 3553 y(of)34 b('decimals')f(for)g(the)h(precision.)49
+b(This)32 b(will)f(suppress)g(trailing)h(zeros,)j(and)e(will)e(use)j(a)
+g(\014xed)f(format)227 3666 y(rather)e(than)f(an)g(exp)s(onen)m(tial)f
+(format,)i(dep)s(ending)d(on)i(the)h(magnitude)e(of)i(the)g(v)-5
+b(alue.)95 3899 y Fe(int)47 b(fits_write_key_str)c(/)48
+b(ffpkys)286 4012 y(\(fitsfile)e(*fptr,)g(char)g(*keyname,)g(char)g
+(*value,)g(char)h(*comment,)334 4125 y(>)h(int)e(*status\))95
+4351 y(int)h(fits_write_key_[log,)c(lng])j(/)95 b(ffpky[lj])286
+4464 y(\(fitsfile)46 b(*fptr,)g(char)g(*keyname,)g(DTYPE)g(numval,)g
+(char)g(*comment,)334 4577 y(>)i(int)e(*status\))95 4803
+y(int)h(fits_write_key_[flt,)c(dbl,)j(fixflg,)g(fixdbl])g(/)h
+(ffpky[edfg])286 4916 y(\(fitsfile)f(*fptr,)g(char)g(*keyname,)g(DTYPE)
+g(numval,)g(int)h(decimals,)286 5028 y(char)g(*comment,)e(>)j(int)f
+(*status\))95 5254 y(int)g(fits_write_key_[cmp,)c(dblcmp,)i(fixcmp,)h
+(fixdblcmp])f(/)j(ffpk[yc,ym,fc,fm])286 5367 y(\(fitsfile)e(*fptr,)g
+(char)g(*keyname,)g(DTYPE)g(*numval,)g(int)g(decimals,)286
+5480 y(char)h(*comment,)e(>)j(int)f(*status\))0 5714
+y Fi(2)81 b Fj(W)-8 b(rite)29 b(\(app)s(end\))f(a)i(string)e(v)-5
+b(alued)28 b(k)m(eyw)m(ord)i(in)m(to)f(the)g(CHU)h(whic)m(h)d(ma)m(y)j
+(b)s(e)f(longer)g(than)f(68)i(c)m(haracters)p eop
+%%Page: 89 97
+89 96 bop 0 299 a Fh(9.3.)72 b(SPECIALIZED)29 b(HEADER)i(KEYW)m(ORD)g
+(R)m(OUTINES)1510 b Fj(89)227 555 y(in)42 b(length.)79
+b(This)41 b(uses)i(the)g(Long)h(String)d(Keyw)m(ord)i(con)m(v)m(en)m
+(tion)i(that)e(is)g(describ)s(ed)e(in)h(the`Lo)s(cal)227
+668 y(FITS)c(Con)m(v)m(en)m(tions')h(section)g(in)f(Chapter)g(4.)66
+b(Since)37 b(this)h(uses)g(a)h(non-standard)f(FITS)g(con)m(v)m(en)m
+(tion)227 781 y(to)45 b(enco)s(de)f(the)g(long)g(k)m(eyw)m(ord)g
+(string,)j(programs)c(whic)m(h)g(use)h(this)f(routine)g(should)f(also)h
+(call)h(the)227 894 y(\014ts)p 354 894 28 4 v 33 w(write)p
+590 894 V 32 w(k)m(ey)p 755 894 V 33 w(longw)m(arn)25
+b(routine)f(to)i(add)f(some)h(COMMENT)f(k)m(eyw)m(ords)g(to)h(w)m(arn)f
+(users)g(of)g(the)h(FITS)227 1007 y(\014le)42 b(that)i(this)d(con)m(v)m
+(en)m(tion)j(is)e(b)s(eing)f(used.)78 b(The)42 b(\014ts)p
+2220 1007 V 32 w(write)p 2455 1007 V 32 w(k)m(ey)p 2620
+1007 V 34 w(longw)m(arn)g(routine)g(also)h(writes)f(a)227
+1120 y(k)m(eyw)m(ord)29 b(called)e(LONGSTRN)g(to)i(record)f(the)g(v)m
+(ersion)g(of)g(the)g(longstring)f(con)m(v)m(en)m(tion)i(that)g(has)f(b)
+s(een)227 1233 y(used,)35 b(in)e(case)j(a)f(new)e(con)m(v)m(en)m(tion)j
+(is)e(adopted)g(at)h(some)g(p)s(oin)m(t)e(in)h(the)g(future.)52
+b(If)34 b(the)h(LONGSTRN)227 1346 y(k)m(eyw)m(ord)43
+b(is)f(already)g(presen)m(t)h(in)f(the)g(header,)k(then)d(\014ts)p
+2332 1346 V 32 w(write)p 2567 1346 V 32 w(k)m(ey)p 2732
+1346 V 34 w(longw)m(arn)f(will)e(simply)g(return)227
+1458 y(without)30 b(doing)f(an)m(ything.)95 1700 y Fe(int)47
+b(fits_write_key_longstr)42 b(/)48 b(ffpkls)286 1813
+y(\(fitsfile)e(*fptr,)g(char)g(*keyname,)g(char)g(*longstr,)g(char)g
+(*comment,)334 1926 y(>)i(int)e(*status\))95 2151 y(int)h
+(fits_write_key_longwarn)42 b(/)47 b(ffplsw)286 2264
+y(\(fitsfile)f(*fptr,)g(>)h(int)g(*status\))0 2506 y
+Fi(3)81 b Fj(W)-8 b(rite)37 b(\(app)s(end\))e(a)i(n)m(um)m(b)s(ered)e
+(sequence)i(of)g(k)m(eyw)m(ords)g(in)m(to)f(the)h(CHU.)g(The)f
+(starting)g(index)f(n)m(um)m(b)s(er)227 2619 y(\(nstart\))30
+b(m)m(ust)e(b)s(e)g(greater)i(than)f(0.)40 b(One)28 b(ma)m(y)i(app)s
+(end)d(the)h(same)i(commen)m(t)f(to)h(ev)m(ery)f(k)m(eyw)m(ord)g(\(and)
+227 2732 y(eliminate)j(the)i(need)f(to)h(ha)m(v)m(e)g(an)f(arra)m(y)h
+(of)f(iden)m(tical)g(commen)m(t)h(strings,)f(one)g(for)h(eac)m(h)g(k)m
+(eyw)m(ord\))g(b)m(y)227 2844 y(including)21 b(the)k(amp)s(ersand)e(c)m
+(haracter)j(as)e(the)h(last)f(non-blank)f(c)m(haracter)j(in)d(the)h
+(\(\014rst\))h(COMMENTS)227 2957 y(string)d(parameter.)38
+b(This)21 b(same)i(string)e(will)f(then)i(b)s(e)g(used)f(for)h(the)h
+(commen)m(t)g(\014eld)e(in)g(all)h(the)g(k)m(eyw)m(ords.)227
+3070 y(One)32 b(ma)m(y)h(also)f(en)m(ter)g(a)h(n)m(ull)d(p)s(oin)m(ter)
+h(for)h(the)g(commen)m(t)h(parameter)g(to)f(lea)m(v)m(e)i(the)e(commen)
+m(t)h(\014eld)e(of)227 3183 y(the)g(k)m(eyw)m(ord)g(blank.)95
+3425 y Fe(int)47 b(fits_write_keys_str)c(/)k(ffpkns)286
+3537 y(\(fitsfile)f(*fptr,)g(char)g(*keyroot,)g(int)h(nstart,)e(int)i
+(nkeys,)334 3650 y(char)g(**value,)e(char)i(**comment,)e(>)i(int)g
+(*status\))95 3876 y(int)g(fits_write_keys_[log,)42 b(lng])47
+b(/)g(ffpkn[lj])286 3989 y(\(fitsfile)f(*fptr,)g(char)g(*keyroot,)g
+(int)h(nstart,)e(int)i(nkeys,)334 4102 y(DTYPE)f(*numval,)g(char)h
+(**comment,)e(int)i(*status\))95 4328 y(int)g(fits_write_keys_[flt,)42
+b(dbl,)47 b(fixflg,)f(fixdbl])g(/)h(ffpkne[edfg])286
+4441 y(\(fitsfile)f(*fptr,)g(char)g(*keyroot,)g(int)h(nstart,)e(int)i
+(nkey,)334 4554 y(DTYPE)f(*numval,)g(int)h(decimals,)e(char)i
+(**comment,)e(>)i(int)g(*status\))0 4795 y Fi(4)81 b
+Fj(Cop)m(y)21 b(an)h(indexed)e(k)m(eyw)m(ord)j(from)e(one)h(HDU)h(to)f
+(another,)i(mo)s(difying)c(the)i(index)e(n)m(um)m(b)s(er)g(of)i(the)g
+(k)m(eyw)m(ord)227 4908 y(name)37 b(in)e(the)h(pro)s(cess.)58
+b(F)-8 b(or)37 b(example,)h(this)d(routine)h(could)f(read)h(the)h
+(TLMIN3)f(k)m(eyw)m(ord)h(from)f(the)227 5021 y(input)29
+b(HDU)i(\(b)m(y)g(giving)f(k)m(eyro)s(ot)h(=)g(`TLMIN')g(and)f(inn)m
+(um)e(=)i(3\))i(and)e(write)g(it)g(to)h(the)g(output)f(HDU)227
+5134 y(with)35 b(the)h(k)m(eyw)m(ord)h(name)f(TLMIN4)g(\(b)m(y)g
+(setting)h(outn)m(um)e(=)h(4\).)58 b(If)36 b(the)g(input)e(k)m(eyw)m
+(ord)j(do)s(es)f(not)227 5247 y(exist,)31 b(then)f(this)f(routine)g
+(simply)f(returns)h(without)h(indicating)e(an)i(error.)95
+5488 y Fe(int)47 b(fits_copy_key)e(/)i(ffcpky)286 5601
+y(\(fitsfile)f(*infptr,)f(fitsfile)h(*outfptr,)f(int)i(innum,)f(int)h
+(outnum,)334 5714 y(char)g(*keyroot,)e(>)i(int)g(*status\))p
+eop
+%%Page: 90 98
+90 97 bop 0 299 a Fj(90)1003 b Fh(CHAPTER)30 b(9.)112
+b(SPECIALIZED)28 b(CFITSIO)h(INTERF)-10 b(A)m(CE)30 b(R)m(OUTINES)0
+555 y Fi(5)81 b Fj(W)-8 b(rite)29 b(\(app)s(end\))g(a)h(`triple)d
+(precision')h(k)m(eyw)m(ord)i(in)m(to)f(the)h(CHU)f(in)f(F28.16)k
+(format.)41 b(The)29 b(\015oating)g(p)s(oin)m(t)227 668
+y(k)m(eyw)m(ord)h(v)-5 b(alue)29 b(is)f(constructed)i(b)m(y)f
+(concatenating)i(the)e(input)f(in)m(teger)i(v)-5 b(alue)28
+b(with)g(the)i(input)d(double)227 781 y(precision)33
+b(fraction)g(v)-5 b(alue)34 b(\(whic)m(h)f(m)m(ust)h(ha)m(v)m(e)i(a)e
+(v)-5 b(alue)34 b(b)s(et)m(w)m(een)g(0.0)i(and)d(1.0\).)53
+b(The)34 b(\013gkyt)h(routine)227 894 y(should)c(b)s(e)i(used)f(to)i
+(read)f(this)f(k)m(eyw)m(ord)i(v)-5 b(alue,)34 b(b)s(ecause)f(the)g
+(other)h(k)m(eyw)m(ord)f(reading)g(routines)f(will)227
+1007 y(not)f(preserv)m(e)f(the)h(full)d(precision)h(of)h(the)h(v)-5
+b(alue.)95 1268 y Fe(int)47 b(fits_write_key_triple)42
+b(/)48 b(ffpkyt)286 1380 y(\(fitsfile)e(*fptr,)g(char)g(*keyname,)g
+(long)g(intval,)g(double)g(frac,)334 1493 y(char)h(*comment,)e(>)i(int)
+g(*status\))0 1754 y Fi(6)81 b Fj(W)-8 b(rite)36 b(k)m(eyw)m(ords)g(to)
+h(the)f(CHDU)g(that)h(are)f(de\014ned)f(in)g(an)h(ASCI)s(I)e(template)i
+(\014le.)57 b(The)35 b(format)i(of)f(the)227 1867 y(template)31
+b(\014le)f(is)f(describ)s(ed)f(under)h(the)i(\014ts)p
+1788 1867 28 4 v 32 w(parse)p 2028 1867 V 33 w(template)f(routine.)95
+2128 y Fe(int)47 b(fits_write_key_template)42 b(/)47
+b(ffpktp)286 2241 y(\(fitsfile)f(*fptr,)g(const)g(char)h(*filename,)e
+(>)i(int)g(*status\))0 2532 y Fd(9.3.4)112 b(Insert)38
+b(Keyw)m(ord)f(Routines)0 2752 y Fj(These)42 b(insert)g(routines)f(are)
+i(somewhat)g(less)e(e\016cien)m(t)i(than)g(the)f(`up)s(date')g(or)h
+(`write')f(k)m(eyw)m(ord)h(routines)0 2864 y(b)s(ecause)30
+b(the)g(follo)m(wing)f(k)m(eyw)m(ords)h(in)f(the)h(header)g(m)m(ust)g
+(b)s(e)f(shifted)g(do)m(wn)g(to)i(mak)m(e)g(ro)s(om)f(for)g(the)g
+(inserted)0 2977 y(k)m(eyw)m(ord.)41 b(See)31 b(App)s(endix)c(B)k(for)f
+(the)h(de\014nition)d(of)i(the)h(parameters)g(used)e(in)g(these)i
+(routines.)0 3238 y Fi(1)81 b Fj(Insert)26 b(a)h(new)f(k)m(eyw)m(ord)h
+(record)g(in)m(to)f(the)h(CHU)g(at)g(the)g(sp)s(eci\014ed)e(p)s
+(osition)g(\(i.e.,)j(immediately)d(preceding)227 3351
+y(the)31 b(\(k)m(eyn)m(um\)th)g(k)m(eyw)m(ord)g(in)e(the)h(header.\))95
+3612 y Fe(int)47 b(fits_insert_record)c(/)48 b(ffirec)286
+3725 y(\(fitsfile)e(*fptr,)g(int)h(keynum,)e(char)i(*card,)f(>)i(int)f
+(*status\))0 3985 y Fi(2)81 b Fj(Insert)24 b(a)h(new)g(k)m(eyw)m(ord)g
+(in)m(to)g(the)g(CHU.)g(The)g(new)f(k)m(eyw)m(ord)i(is)e(inserted)f
+(immediately)h(follo)m(wing)f(the)i(last)227 4098 y(k)m(eyw)m(ord)i
+(that)f(has)f(b)s(een)h(read)f(from)h(the)g(header.)39
+b(The)25 b(`longstr')h(v)m(ersion)f(has)g(the)h(same)g(functionalit)m
+(y)227 4211 y(as)33 b(the)g(`str')f(v)m(ersion)g(except)i(that)f(it)f
+(also)g(supp)s(orts)f(the)h(lo)s(cal)g(long)g(string)g(k)m(eyw)m(ord)h
+(con)m(v)m(en)m(tion)g(for)227 4324 y(strings)28 b(longer)g(than)h(68)h
+(c)m(haracters.)41 b(A)29 b(n)m(ull)e(p)s(oin)m(ter)h(ma)m(y)h(b)s(e)g
+(en)m(tered)g(for)g(the)g(commen)m(t)g(parameter)227
+4437 y(whic)m(h)c(will)d(cause)k(the)g(commen)m(t)h(\014eld)d(to)i(b)s
+(e)f(left)g(blank.)38 b(The)25 b(\015t,)h(dbl,)f(cmp,)i(and)e(dblcmp)e
+(v)m(ersions)i(of)227 4550 y(this)k(routine)g(ha)m(v)m(e)i(the)e(added)
+g(feature)i(that)f(if)f(the)h('decimals')f(parameter)h(is)f(negativ)m
+(e,)i(then)e(the)h('G')227 4663 y(displa)m(y)e(format)i(rather)f(then)g
+(the)h('E')f(format)h(will)d(b)s(e)i(used)f(when)h(constructing)g(the)g
+(k)m(eyw)m(ord)h(v)-5 b(alue,)227 4776 y(taking)26 b(the)h(absolute)f
+(v)-5 b(alue)25 b(of)i('decimals')e(for)h(the)h(precision.)37
+b(This)25 b(will)e(suppress)h(trailing)h(zeros,)j(and)227
+4889 y(will)34 b(use)j(a)g(\014xed)f(format)h(rather)g(than)f(an)h(exp)
+s(onen)m(tial)e(format,)k(dep)s(ending)34 b(on)j(the)g(magnitude)f(of)
+227 5002 y(the)31 b(v)-5 b(alue.)95 5262 y Fe(int)47
+b(fits_insert_card)d(/)j(ffikey)286 5375 y(\(fitsfile)f(*fptr,)g(char)g
+(*card,)g(>)i(&status\))95 5601 y(int)f(fits_insert_key_[str,)42
+b(longstr])k(/)h(ffi[kys,)f(kls])286 5714 y(\(fitsfile)g(*fptr,)g(char)
+g(*keyname,)g(char)g(*value,)g(char)h(*comment,)p eop
+%%Page: 91 99
+91 98 bop 0 299 a Fh(9.3.)72 b(SPECIALIZED)29 b(HEADER)i(KEYW)m(ORD)g
+(R)m(OUTINES)1510 b Fj(91)334 555 y Fe(>)48 b(int)e(*status\))95
+781 y(int)h(fits_insert_key_[log,)42 b(lng])47 b(/)g(ffiky[lj])286
+894 y(\(fitsfile)f(*fptr,)g(char)g(*keyname,)g(DTYPE)g(numval,)g(char)g
+(*comment,)334 1007 y(>)i(int)e(*status\))95 1233 y(int)h
+(fits_insert_key_[flt,)42 b(fixflt,)k(dbl,)h(fixdbl])f(/)h(ffiky[edfg])
+286 1346 y(\(fitsfile)f(*fptr,)g(char)g(*keyname,)g(DTYPE)g(numval,)g
+(int)h(decimals,)334 1458 y(char)g(*comment,)e(>)i(int)g(*status\))95
+1684 y(int)g(fits_insert_key_[cmp,)42 b(dblcmp,)k(fixcmp,)g(fixdblcmp])
+f(/)i(ffik[yc,ym,fc,fm])286 1797 y(\(fitsfile)f(*fptr,)g(char)g
+(*keyname,)g(DTYPE)g(*numval,)g(int)g(decimals,)334 1910
+y(char)h(*comment,)e(>)i(int)g(*status\))0 2169 y Fi(3)81
+b Fj(Insert)32 b(a)i(new)f(k)m(eyw)m(ord)h(with)e(an)h(unde\014ned,)g
+(or)g(n)m(ull,)f(v)-5 b(alue)33 b(in)m(to)h(the)f(CHU.)h(The)f(v)-5
+b(alue)33 b(string)f(of)i(the)227 2282 y(k)m(eyw)m(ord)d(is)f(left)g
+(blank)f(in)g(this)g(case.)95 2541 y Fe(int)47 b(fits_insert_key_null)c
+(/)k(ffikyu)286 2654 y(\(fitsfile)f(*fptr,)g(char)g(*keyname,)g(char)g
+(*comment,)g(>)h(int)g(*status\))0 2945 y Fd(9.3.5)112
+b(Read)38 b(Keyw)m(ord)g(Routines)0 3163 y Fj(Wild)29
+b(card)h(c)m(haracters)i(ma)m(y)f(b)s(e)f(used)f(when)h(sp)s(ecifying)e
+(the)i(name)h(of)f(the)h(k)m(eyw)m(ord)g(to)g(b)s(e)f(read.)0
+3422 y Fi(1)81 b Fj(Read)43 b(a)h(k)m(eyw)m(ord)g(v)-5
+b(alue)42 b(\(with)h(the)g(appropriate)g(data)h(t)m(yp)s(e\))g(and)e
+(commen)m(t)j(from)e(the)g(CHU.)h(If)f(a)227 3535 y(NULL)32
+b(commen)m(t)h(p)s(oin)m(ter)e(is)h(giv)m(en)g(on)g(input,)e(then)i
+(the)g(commen)m(t)i(string)d(will)e(not)j(b)s(e)g(returned.)44
+b(If)227 3648 y(the)32 b(v)-5 b(alue)32 b(of)g(the)g(k)m(eyw)m(ord)g
+(is)f(not)i(de\014ned)d(\(i.e.,)j(the)f(v)-5 b(alue)32
+b(\014eld)e(is)h(blank\))g(then)h(an)g(error)f(status)h(=)227
+3761 y(V)-10 b(ALUE)p 545 3761 28 4 v 33 w(UNDEFINED)29
+b(will)c(b)s(e)j(returned)e(and)h(the)h(input)e(v)-5
+b(alue)27 b(will)f(not)i(b)s(e)f(c)m(hanged)h(\(except)h(that)227
+3874 y(\013gkys)i(will)d(reset)j(the)f(v)-5 b(alue)30
+b(to)h(a)g(n)m(ull)d(string\).)95 4133 y Fe(int)47 b(fits_read_key_str)
+c(/)48 b(ffgkys)286 4246 y(\(fitsfile)e(*fptr,)g(char)g(*keyname,)g(>)h
+(char)g(*value,)f(char)g(*comment,)334 4359 y(int)h(*status\);)95
+4585 y(NOTE:)g(after)f(calling)g(the)h(following)e(routine,)h(programs)
+f(must)i(explicitly)e(free)382 4698 y(the)i(memory)f(allocated)f(for)i
+('longstr')e(after)i(it)g(is)g(no)g(longer)f(needed.)95
+4924 y(int)h(fits_read_key_longstr)42 b(/)48 b(ffgkls)286
+5036 y(\(fitsfile)e(*fptr,)g(char)g(*keyname,)g(>)h(char)g(**longstr,)e
+(char)h(*comment,)620 5149 y(int)h(*status\))95 5375
+y(int)g(fits_read_key_[log,)c(lng,)k(flt,)f(dbl,)h(cmp,)f(dblcmp])g(/)i
+(ffgky[ljedcm])286 5488 y(\(fitsfile)e(*fptr,)g(char)g(*keyname,)g(>)h
+(DTYPE)f(*numval,)g(char)h(*comment,)334 5601 y(int)g(*status\))p
+eop
+%%Page: 92 100
+92 99 bop 0 299 a Fj(92)1003 b Fh(CHAPTER)30 b(9.)112
+b(SPECIALIZED)28 b(CFITSIO)h(INTERF)-10 b(A)m(CE)30 b(R)m(OUTINES)0
+555 y Fi(2)81 b Fj(Read)36 b(a)h(sequence)f(of)h(indexed)d(k)m(eyw)m
+(ord)j(v)-5 b(alues)36 b(\(e.g.,)j(NAXIS1,)g(NAXIS2,)f(...\).)59
+b(The)36 b(input)e(starting)227 668 y(index)j(n)m(um)m(b)s(er)f
+(\(nstart\))j(m)m(ust)f(b)s(e)f(greater)i(than)e(0.)64
+b(If)37 b(the)h(v)-5 b(alue)37 b(of)h(an)m(y)h(of)f(the)g(k)m(eyw)m
+(ords)g(is)f(not)227 781 y(de\014ned)d(\(i.e.,)i(the)f(v)-5
+b(alue)34 b(\014eld)f(is)h(blank\))g(then)g(an)g(error)h(status)g(=)f
+(V)-10 b(ALUE)p 3009 781 28 4 v 33 w(UNDEFINED)36 b(will)c(b)s(e)227
+894 y(returned)21 b(and)h(the)h(input)d(v)-5 b(alue)22
+b(for)g(the)g(unde\014ned)e(k)m(eyw)m(ord\(s\))k(will)19
+b(not)k(b)s(e)e(c)m(hanged.)39 b(These)22 b(routines)227
+1007 y(do)j(not)h(supp)s(ort)d(wild)g(card)i(c)m(haracters)i(in)d(the)i
+(ro)s(ot)f(name.)39 b(If)25 b(there)h(are)f(no)g(indexed)f(k)m(eyw)m
+(ords)i(in)e(the)227 1120 y(header)35 b(with)e(the)i(input)d(ro)s(ot)j
+(name)g(then)f(these)h(routines)f(do)g(not)h(return)e(a)i(non-zero)h
+(status)e(v)-5 b(alue)227 1233 y(and)30 b(instead)g(simply)e(return)h
+(nfound)f(=)i(0.)95 1489 y Fe(int)47 b(fits_read_keys_str)c(/)48
+b(ffgkns)286 1602 y(\(fitsfile)e(*fptr,)g(char)g(*keyname,)g(int)h
+(nstart,)e(int)i(nkeys,)334 1715 y(>)h(char)e(**value,)g(int)h
+(*nfound,)93 b(int)47 b(*status\))95 1941 y(int)g(fits_read_keys_[log,)
+c(lng,)j(flt,)h(dbl])g(/)g(ffgkn[ljed])286 2054 y(\(fitsfile)f(*fptr,)g
+(char)g(*keyname,)g(int)h(nstart,)e(int)i(nkeys,)334
+2167 y(>)h(DTYPE)e(*numval,)f(int)i(*nfound,)f(int)h(*status\))0
+2423 y Fi(3)81 b Fj(Read)37 b(the)h(v)-5 b(alue)37 b(of)h(a)g
+(\015oating)f(p)s(oin)m(t)g(k)m(eyw)m(ord,)j(returning)c(the)i(in)m
+(teger)g(and)f(fractional)g(parts)g(of)h(the)227 2536
+y(v)-5 b(alue)34 b(in)e(separate)j(routine)e(argumen)m(ts.)52
+b(This)32 b(routine)h(ma)m(y)h(b)s(e)f(used)h(to)g(read)g(an)m(y)g(k)m
+(eyw)m(ord)h(but)e(is)227 2649 y(esp)s(ecially)c(useful)f(for)j
+(reading)e(the)i('triple)e(precision')f(k)m(eyw)m(ords)j(written)f(b)m
+(y)g(\013pkyt.)95 2906 y Fe(int)47 b(fits_read_key_triple)c(/)k(ffgkyt)
+286 3019 y(\(fitsfile)f(*fptr,)g(char)g(*keyname,)g(>)h(long)g
+(*intval,)e(double)h(*frac,)334 3132 y(char)h(*comment,)e(int)i
+(*status\))0 3422 y Fd(9.3.6)112 b(Mo)s(dify)38 b(Keyw)m(ord)f
+(Routines)0 3641 y Fj(These)31 b(routines)g(mo)s(dify)f(the)i(v)-5
+b(alue)31 b(of)h(an)g(existing)e(k)m(eyw)m(ord.)46 b(An)31
+b(error)g(is)g(returned)f(if)h(the)h(k)m(eyw)m(ord)g(do)s(es)0
+3753 y(not)43 b(exist.)76 b(Wild)41 b(card)i(c)m(haracters)h(ma)m(y)f
+(b)s(e)f(used)f(when)h(sp)s(ecifying)e(the)j(name)f(of)h(the)f(k)m(eyw)
+m(ord)h(to)h(b)s(e)0 3866 y(mo)s(di\014ed.)39 b(See)30
+b(App)s(endix)e(B)j(for)f(the)g(de\014nition)e(of)j(the)f(parameters)h
+(used)f(in)f(these)i(routines.)0 4123 y Fi(1)81 b Fj(Mo)s(dify)29
+b(\(o)m(v)m(erwrite\))i(the)g(n)m(th)f(80-c)m(haracter)j(header)d
+(record)h(in)e(the)h(CHU.)95 4380 y Fe(int)47 b(fits_modify_record)c(/)
+48 b(ffmrec)286 4492 y(\(fitsfile)e(*fptr,)g(int)h(keynum,)e(char)i
+(*card,)f(>)i(int)f(*status\))0 4749 y Fi(2)81 b Fj(Mo)s(dify)36
+b(\(o)m(v)m(erwrite\))j(the)f(80-c)m(haracter)j(header)c(record)h(for)f
+(the)h(named)f(k)m(eyw)m(ord)h(in)f(the)h(CHU.)g(This)227
+4862 y(can)31 b(b)s(e)f(used)f(to)i(o)m(v)m(erwrite)g(the)g(name)f(of)h
+(the)f(k)m(eyw)m(ord)h(as)g(w)m(ell)e(as)i(its)f(v)-5
+b(alue)29 b(and)h(commen)m(t)i(\014elds.)95 5119 y Fe(int)47
+b(fits_modify_card)d(/)j(ffmcrd)286 5231 y(\(fitsfile)f(*fptr,)g(char)g
+(*keyname,)g(char)g(*card,)g(>)i(int)f(*status\))0 5488
+y Fi(5)81 b Fj(Mo)s(dify)29 b(the)h(v)-5 b(alue)30 b(and)f(commen)m(t)i
+(\014elds)e(of)h(an)g(existing)f(k)m(eyw)m(ord)i(in)e(the)h(CHU.)h(The)
+e(`longstr')h(v)m(ersion)227 5601 y(has)41 b(the)h(same)f(functionalit)
+m(y)f(as)h(the)h(`str')f(v)m(ersion)g(except)h(that)g(it)f(also)g(supp)
+s(orts)e(the)j(lo)s(cal)e(long)227 5714 y(string)28 b(k)m(eyw)m(ord)i
+(con)m(v)m(en)m(tion)g(for)f(strings)e(longer)i(than)g(68)h(c)m
+(haracters.)41 b(Optionally)-8 b(,)28 b(one)h(ma)m(y)h(mo)s(dify)p
+eop
+%%Page: 93 101
+93 100 bop 0 299 a Fh(9.3.)72 b(SPECIALIZED)29 b(HEADER)i(KEYW)m(ORD)g
+(R)m(OUTINES)1510 b Fj(93)227 555 y(only)27 b(the)h(v)-5
+b(alue)27 b(\014eld)g(and)g(lea)m(v)m(e)i(the)f(commen)m(t)h(\014eld)d
+(unc)m(hanged)i(b)m(y)g(setting)f(the)h(input)e(COMMENT)227
+668 y(parameter)d(equal)g(to)g(the)g(amp)s(ersand)e(c)m(haracter)j
+(\(&\))f(or)g(b)m(y)g(en)m(tering)f(a)h(n)m(ull)e(p)s(oin)m(ter)h(for)g
+(the)h(commen)m(t)227 781 y(parameter.)40 b(The)24 b(\015t,)i(dbl,)f
+(cmp,)g(and)g(dblcmp)d(v)m(ersions)j(of)g(this)f(routine)g(ha)m(v)m(e)i
+(the)f(added)f(feature)h(that)227 894 y(if)g(the)i('decimals')e
+(parameter)i(is)e(negativ)m(e,)k(then)d(the)g('G')h(displa)m(y)d
+(format)j(rather)f(then)g(the)g('E')h(format)227 1007
+y(will)f(b)s(e)i(used)f(when)h(constructing)g(the)g(k)m(eyw)m(ord)h(v)
+-5 b(alue,)29 b(taking)f(the)h(absolute)f(v)-5 b(alue)28
+b(of)g('decimals')g(for)227 1120 y(the)37 b(precision.)58
+b(This)34 b(will)g(suppress)h(trailing)f(zeros,)39 b(and)d(will)e(use)j
+(a)g(\014xed)e(format)i(rather)g(than)f(an)227 1233 y(exp)s(onen)m
+(tial)30 b(format,)h(dep)s(ending)c(on)k(the)f(magnitude)g(of)g(the)h
+(v)-5 b(alue.)95 1468 y Fe(int)47 b(fits_modify_key_[str,)42
+b(longstr])k(/)h(ffm[kys,)f(kls])286 1581 y(\(fitsfile)g(*fptr,)g(char)
+g(*keyname,)g(char)g(*value,)g(char)h(*comment,)334 1694
+y(>)h(int)e(*status\);)95 1920 y(int)h(fits_modify_key_[log,)42
+b(lng])47 b(/)g(ffmky[lj])286 2032 y(\(fitsfile)f(*fptr,)g(char)g
+(*keyname,)g(DTYPE)g(numval,)g(char)g(*comment,)334 2145
+y(>)i(int)e(*status\))95 2371 y(int)h(fits_modify_key_[flt,)42
+b(dbl,)47 b(fixflt,)f(fixdbl])g(/)h(ffmky[edfg])286 2484
+y(\(fitsfile)f(*fptr,)g(char)g(*keyname,)g(DTYPE)g(numval,)g(int)h
+(decimals,)334 2597 y(char)g(*comment,)e(>)i(int)g(*status\))95
+2823 y(int)g(fits_modify_key_[cmp,)42 b(dblcmp,)k(fixcmp,)g(fixdblcmp])
+f(/)i(ffmk[yc,ym,fc,fm])286 2936 y(\(fitsfile)f(*fptr,)g(char)g
+(*keyname,)g(DTYPE)g(*numval,)g(int)g(decimals,)334 3049
+y(char)h(*comment,)e(>)i(int)g(*status\))0 3284 y Fi(6)81
+b Fj(Mo)s(dify)21 b(the)h(v)-5 b(alue)22 b(of)g(an)g(existing)g(k)m
+(eyw)m(ord)g(to)h(b)s(e)f(unde\014ned,)g(or)g(n)m(ull.)36
+b(The)22 b(v)-5 b(alue)21 b(string)h(of)g(the)g(k)m(eyw)m(ord)227
+3397 y(is)29 b(set)i(to)g(blank.)39 b(Optionally)-8 b(,)28
+b(one)i(ma)m(y)h(lea)m(v)m(e)g(the)g(commen)m(t)g(\014eld)d(unc)m
+(hanged)i(b)m(y)g(setting)g(the)g(input)227 3510 y(COMMENT)f(parameter)
+g(equal)f(to)h(the)g(amp)s(ersand)e(c)m(haracter)k(\(&\))e(or)f(b)m(y)h
+(en)m(tering)f(a)h(n)m(ull)e(p)s(oin)m(ter.)95 3745 y
+Fe(int)47 b(fits_modify_key_null)c(/)k(ffmkyu)286 3858
+y(\(fitsfile)f(*fptr,)g(char)g(*keyname,)g(char)g(*comment,)g(>)h(int)g
+(*status\))0 4145 y Fd(9.3.7)112 b(Up)s(date)39 b(Keyw)m(ord)e
+(Routines)0 4350 y Fi(1)81 b Fj(These)29 b(up)s(date)g(routines)g(mo)s
+(dify)f(the)h(v)-5 b(alue,)30 b(and)f(optionally)f(the)i(commen)m(t)h
+(\014eld,)e(of)h(the)g(k)m(eyw)m(ord)g(if)e(it)227 4462
+y(already)33 b(exists,)g(otherwise)f(the)h(new)f(k)m(eyw)m(ord)h(is)e
+(app)s(ended)g(to)j(the)f(header.)47 b(A)33 b(separate)g(routine)f(is)
+227 4575 y(pro)m(vided)c(for)h(eac)m(h)h(k)m(eyw)m(ord)f(data)h(t)m(yp)
+s(e.)41 b(The)28 b(`longstr')h(v)m(ersion)g(has)f(the)i(same)f
+(functionalit)m(y)e(as)j(the)227 4688 y(`str')h(v)m(ersion)f(except)i
+(that)g(it)e(also)h(supp)s(orts)d(the)j(lo)s(cal)f(long)h(string)e(k)m
+(eyw)m(ord)j(con)m(v)m(en)m(tion)g(for)e(strings)227
+4801 y(longer)h(than)g(68)h(c)m(haracters.)45 b(A)31
+b(n)m(ull)e(p)s(oin)m(ter)i(ma)m(y)g(b)s(e)g(en)m(tered)h(for)f(the)g
+(commen)m(t)i(parameter)e(whic)m(h)227 4914 y(will)f(lea)m(v)m(e)j(the)
+g(commen)m(t)g(\014eld)e(unc)m(hanged)h(or)g(blank.)45
+b(The)31 b(\015t,)i(dbl,)e(cmp,)i(and)e(dblcmp)f(v)m(ersions)i(of)227
+5027 y(this)d(routine)g(ha)m(v)m(e)i(the)e(added)g(feature)i(that)f(if)
+f(the)h('decimals')f(parameter)h(is)f(negativ)m(e,)i(then)e(the)h('G')
+227 5140 y(displa)m(y)e(format)i(rather)f(then)g(the)h('E')f(format)h
+(will)d(b)s(e)i(used)f(when)h(constructing)g(the)g(k)m(eyw)m(ord)h(v)-5
+b(alue,)227 5253 y(taking)26 b(the)h(absolute)f(v)-5
+b(alue)25 b(of)i('decimals')e(for)h(the)h(precision.)37
+b(This)25 b(will)e(suppress)h(trailing)h(zeros,)j(and)227
+5366 y(will)34 b(use)j(a)g(\014xed)f(format)h(rather)g(than)f(an)h(exp)
+s(onen)m(tial)e(format,)k(dep)s(ending)34 b(on)j(the)g(magnitude)f(of)
+227 5479 y(the)31 b(v)-5 b(alue.)95 5714 y Fe(int)47
+b(fits_update_key_[str,)42 b(longstr])k(/)h(ffu[kys,)f(kls])p
+eop
+%%Page: 94 102
+94 101 bop 0 299 a Fj(94)1003 b Fh(CHAPTER)30 b(9.)112
+b(SPECIALIZED)28 b(CFITSIO)h(INTERF)-10 b(A)m(CE)30 b(R)m(OUTINES)286
+555 y Fe(\(fitsfile)46 b(*fptr,)g(char)g(*keyname,)g(char)g(*value,)g
+(char)h(*comment,)334 668 y(>)h(int)e(*status\))95 894
+y(int)h(fits_update_key_[log,)42 b(lng])47 b(/)g(ffuky[lj])286
+1007 y(\(fitsfile)f(*fptr,)g(char)g(*keyname,)g(DTYPE)g(numval,)g(char)
+g(*comment,)334 1120 y(>)i(int)e(*status\))95 1346 y(int)h
+(fits_update_key_[flt,)42 b(dbl,)47 b(fixflt,)f(fixdbl])g(/)h
+(ffuky[edfg])286 1458 y(\(fitsfile)f(*fptr,)g(char)g(*keyname,)g(DTYPE)
+g(numval,)g(int)h(decimals,)334 1571 y(char)g(*comment,)e(>)i(int)g
+(*status\))95 1797 y(int)g(fits_update_key_[cmp,)42 b(dblcmp,)k
+(fixcmp,)g(fixdblcmp])f(/)i(ffuk[yc,ym,fc,fm])286 1910
+y(\(fitsfile)f(*fptr,)g(char)g(*keyname,)g(DTYPE)g(*numval,)g(int)g
+(decimals,)334 2023 y(char)h(*comment,)e(>)i(int)g(*status\))0
+2363 y Ff(9.4)135 b(De\014ne)45 b(Data)h(Scaling)g(and)e(Unde\014ned)h
+(Pixel)h(P)l(arameters)0 2614 y Fj(These)37 b(routines)f(set)i(or)f(mo)
+s(dify)f(the)h(in)m(ternal)f(parameters)i(used)e(b)m(y)i(CFITSIO)d(to)j
+(either)f(scale)h(the)f(data)0 2727 y(or)f(to)h(represen)m(t)f
+(unde\014ned)d(pixels.)56 b(Generally)35 b(CFITSIO)f(will)g(scale)i
+(the)g(data)h(according)f(to)g(the)h(v)-5 b(alues)0 2840
+y(of)35 b(the)f(BSCALE)g(and)g(BZER)m(O)h(\(or)g(TSCALn)d(and)i(TZER)m
+(On\))g(k)m(eyw)m(ords,)i(ho)m(w)m(ev)m(er)g(these)f(routines)e(ma)m(y)
+0 2953 y(b)s(e)f(used)h(to)h(o)m(v)m(erride)f(the)g(k)m(eyw)m(ord)h(v)
+-5 b(alues.)48 b(This)31 b(ma)m(y)j(b)s(e)f(useful)e(when)h(one)i(w)m
+(an)m(ts)f(to)h(read)f(or)g(write)g(the)0 3066 y(ra)m(w)f(unscaled)f(v)
+-5 b(alues)32 b(in)f(the)h(FITS)f(\014le.)46 b(Similarly)-8
+b(,)29 b(CFITSIO)i(generally)g(uses)h(the)g(v)-5 b(alue)32
+b(of)g(the)h(BLANK)0 3179 y(or)40 b(TNULLn)f(k)m(eyw)m(ord)h(to)h
+(signify)c(an)j(unde\014ned)e(pixel,)j(but)e(these)h(routines)f(ma)m(y)
+h(b)s(e)f(used)g(to)i(o)m(v)m(erride)0 3292 y(this)31
+b(v)-5 b(alue.)47 b(These)32 b(routines)f(do)i(not)f(create)i(or)f(mo)s
+(dify)d(the)j(corresp)s(onding)d(header)j(k)m(eyw)m(ord)f(v)-5
+b(alues.)47 b(See)0 3405 y(App)s(endix)28 b(B)i(for)h(the)f
+(de\014nition)e(of)j(the)f(parameters)h(used)e(in)h(these)g(routines.)0
+3669 y Fi(1)81 b Fj(Reset)26 b(the)g(scaling)e(factors)i(in)e(the)i
+(primary)e(arra)m(y)i(or)f(image)h(extension;)h(do)s(es)e(not)g(c)m
+(hange)i(the)f(BSCALE)227 3782 y(and)i(BZER)m(O)g(k)m(eyw)m(ord)h(v)-5
+b(alues)27 b(and)h(only)f(a\013ects)j(the)e(automatic)i(scaling)d(p)s
+(erformed)g(when)g(the)h(data)227 3895 y(elemen)m(ts)e(are)g
+(written/read)f(to/from)h(the)g(FITS)f(\014le.)38 b(When)25
+b(reading)g(from)g(a)h(FITS)f(\014le)f(the)i(returned)227
+4008 y(data)i(v)-5 b(alue)27 b(=)g(\(the)h(v)-5 b(alue)27
+b(giv)m(en)h(in)e(the)h(FITS)g(arra)m(y\))h(*)g(BSCALE)f(+)g(BZER)m(O.)
+g(The)g(in)m(v)m(erse)h(form)m(ula)227 4121 y(is)i(used)f(when)h
+(writing)e(data)j(v)-5 b(alues)30 b(to)h(the)f(FITS)g(\014le.)95
+4386 y Fe(int)47 b(fits_set_bscale)d(/)j(ffpscl)286 4499
+y(\(fitsfile)f(*fptr,)g(double)g(scale,)g(double)g(zero,)g(>)i(int)f
+(*status\))0 4764 y Fi(2)81 b Fj(Reset)39 b(the)f(scaling)g(parameters)
+g(for)h(a)f(table)g(column;)k(do)s(es)c(not)g(c)m(hange)i(the)e(TSCALn)
+f(or)h(TZER)m(On)227 4877 y(k)m(eyw)m(ord)29 b(v)-5 b(alues)28
+b(and)f(only)h(a\013ects)h(the)g(automatic)g(scaling)e(p)s(erformed)g
+(when)g(the)i(data)g(elemen)m(ts)g(are)227 4990 y(written/read)i
+(to/from)h(the)g(FITS)f(\014le.)43 b(When)31 b(reading)f(from)h(a)h
+(FITS)f(\014le)f(the)i(returned)e(data)i(v)-5 b(alue)227
+5103 y(=)25 b(\(the)i(v)-5 b(alue)25 b(giv)m(en)g(in)f(the)i(FITS)f
+(arra)m(y\))h(*)g(TSCAL)e(+)i(TZER)m(O.)e(The)h(in)m(v)m(erse)h(form)m
+(ula)f(is)f(used)h(when)227 5216 y(writing)k(data)i(v)-5
+b(alues)29 b(to)j(the)e(FITS)g(\014le.)95 5480 y Fe(int)47
+b(fits_set_tscale)d(/)j(fftscl)286 5593 y(\(fitsfile)f(*fptr,)g(int)h
+(colnum,)e(double)i(scale,)f(double)g(zero,)334 5706
+y(>)i(int)e(*status\))p eop
+%%Page: 95 103
+95 102 bop 0 299 a Fh(9.5.)72 b(SPECIALIZED)29 b(FITS)g(PRIMAR)-8
+b(Y)31 b(ARRA)-8 b(Y)32 b(OR)d(IMA)m(GE)j(EXTENSION)d(I/O)h(R)m
+(OUTINES)125 b Fj(95)0 555 y Fi(3)81 b Fj(De\014ne)36
+b(the)g(in)m(teger)h(v)-5 b(alue)35 b(to)i(b)s(e)e(used)h(to)h(signify)
+d(unde\014ned)g(pixels)g(in)h(the)h(primary)e(arra)m(y)j(or)f(image)227
+668 y(extension.)53 b(This)33 b(is)g(only)h(used)g(if)f(BITPIX)h(=)h
+(8,)h(16,)g(or)f(32.)54 b(This)33 b(do)s(es)h(not)h(create)h(or)e(c)m
+(hange)i(the)227 781 y(v)-5 b(alue)30 b(of)h(the)f(BLANK)h(k)m(eyw)m
+(ord)g(in)e(the)h(header.)95 1038 y Fe(int)47 b(fits_set_imgnull)d(/)j
+(ffpnul)286 1150 y(\(fitsfile)f(*fptr,)g(long)g(nulval,)g(>)i(int)f
+(*status\))0 1407 y Fi(4)81 b Fj(De\014ne)36 b(the)g(string)f(to)h(b)s
+(e)f(used)g(to)i(signify)d(unde\014ned)g(pixels)g(in)g(a)i(column)f(in)
+g(an)g(ASCI)s(I)g(table.)57 b(This)227 1520 y(do)s(es)30
+b(not)h(create)h(or)e(c)m(hange)i(the)e(v)-5 b(alue)30
+b(of)h(the)f(TNULLn)g(k)m(eyw)m(ord.)95 1777 y Fe(int)47
+b(fits_set_atblnull)c(/)48 b(ffsnul)286 1889 y(\(fitsfile)e(*fptr,)g
+(int)h(colnum,)e(char)i(*nulstr,)f(>)h(int)g(*status\))0
+2146 y Fi(5)81 b Fj(De\014ne)34 b(the)h(v)-5 b(alue)33
+b(to)i(b)s(e)f(used)g(to)h(signify)d(unde\014ned)g(pixels)h(in)g(an)h
+(in)m(teger)h(column)e(in)g(a)h(binary)f(table)227 2259
+y(\(where)c(TF)m(ORMn)f(=)g('B',)i('I',)f(or)f('J'\).)i(This)c(do)s(es)
+j(not)f(create)j(or)d(c)m(hange)i(the)e(v)-5 b(alue)28
+b(of)h(the)g(TNULLn)227 2372 y(k)m(eyw)m(ord.)95 2628
+y Fe(int)47 b(fits_set_btblnull)c(/)48 b(fftnul)286 2741
+y(\(fitsfile)e(*fptr,)g(int)h(colnum,)e(long)i(nulval,)f(>)h(int)g
+(*status\))0 3074 y Ff(9.5)135 b(Sp)t(ecialized)61 b(FITS)e(Primary)i
+(Arra)l(y)f(or)h(IMA)l(GE)e(Extension)j(I/O)306 3224
+y(Routines)0 3474 y Fj(These)27 b(routines)g(read)g(or)h(write)f(data)h
+(v)-5 b(alues)27 b(in)g(the)g(primary)f(data)i(arra)m(y)h(\(i.e.,)f
+(the)g(\014rst)f(HDU)i(in)d(the)i(FITS)0 3587 y(\014le\))36
+b(or)h(an)f(IMA)m(GE)h(extension.)59 b(Automatic)38 b(data)f(t)m(yp)s
+(e)g(con)m(v)m(ersion)f(is)g(p)s(erformed)f(for)h(if)g(the)h(data)g(t)m
+(yp)s(e)0 3700 y(of)c(the)g(FITS)f(arra)m(y)h(\(as)g(de\014ned)f(b)m(y)
+g(the)h(BITPIX)g(k)m(eyw)m(ord\))g(di\013ers)f(from)g(the)h(data)g(t)m
+(yp)s(e)g(of)g(the)g(arra)m(y)g(in)0 3813 y(the)c(calling)f(routine.)39
+b(The)28 b(data)i(v)-5 b(alues)28 b(are)i(automatically)f(scaled)f(b)m
+(y)h(the)h(BSCALE)e(and)g(BZER)m(O)h(header)0 3926 y(v)-5
+b(alues)24 b(as)i(they)f(are)g(b)s(eing)f(written)g(or)h(read)f(from)h
+(the)g(FITS)f(arra)m(y)-8 b(.)40 b(Unlik)m(e)24 b(the)h(basic)g
+(routines)e(describ)s(ed)g(in)0 4039 y(the)31 b(previous)f(c)m(hapter,)
+j(most)e(of)h(these)g(routines)e(sp)s(eci\014cally)f(supp)s(ort)g(the)j
+(FITS)e(random)h(groups)f(format.)0 4152 y(See)h(App)s(endix)c(B)k(for)
+f(the)h(de\014nition)d(of)i(the)h(parameters)g(used)e(in)g(these)i
+(routines.)0 4312 y(The)24 b(more)h(primitiv)m(e)e(reading)h(and)g
+(writing)f(routines)g(\(i.)39 b(e.,)26 b(\013ppr)p 2364
+4312 28 4 v 32 w(,)g(\013ppn)p 2653 4312 V 31 w(,)g(\013ppn,)f(\013gp)m
+(v)p 3185 4312 V 33 w(,)h(or)f(\013gpf)p 3552 4312 V
+32 w(\))g(simply)0 4425 y(treat)g(the)g(primary)d(arra)m(y)j(as)f(a)h
+(long)f(1-dimensional)e(arra)m(y)j(of)f(pixels,)g(ignoring)f(the)h(in)m
+(trinsic)e(dimensionalit)m(y)0 4538 y(of)30 b(the)g(arra)m(y)-8
+b(.)42 b(When)30 b(dealing)f(with)f(a)j(2D)g(image,)f(for)g(example,)g
+(the)g(application)f(program)h(m)m(ust)g(calculate)0
+4650 y(the)i(pixel)e(o\013set)i(in)e(the)i(1-D)h(arra)m(y)f(that)g
+(corresp)s(onds)e(to)i(an)m(y)g(particular)e(X,)i(Y)f(co)s(ordinate)h
+(in)e(the)h(image.)0 4763 y(C)25 b(programmers)h(should)e(note)i(that)g
+(the)h(ordering)d(of)i(arra)m(ys)g(in)f(FITS)g(\014les,)h(and)f(hence)h
+(in)f(all)f(the)i(CFITSIO)0 4876 y(calls,)38 b(is)e(more)h(similar)e
+(to)i(the)h(dimensionalit)m(y)c(of)j(arra)m(ys)g(in)f(F)-8
+b(ortran)38 b(rather)f(than)f(C.)h(F)-8 b(or)38 b(instance)f(if)f(a)0
+4989 y(FITS)28 b(image)h(has)f(NAXIS1)h(=)f(100)i(and)e(NAXIS2)h(=)f
+(50,)i(then)e(a)h(2-D)h(arra)m(y)f(just)f(large)h(enough)f(to)i(hold)d
+(the)0 5102 y(image)k(should)d(b)s(e)i(declared)g(as)g(arra)m
+(y[50][100])k(and)c(not)h(as)f(arra)m(y[100][50].)0 5262
+y(F)-8 b(or)36 b(con)m(v)m(enience,)h(higher-lev)m(el)d(routines)g(are)
+h(also)g(pro)m(vided)f(to)h(sp)s(eci\014cly)e(deal)i(with)f(2D)h
+(images)g(\(\013p2d)p 3872 5262 V 0 5375 a(and)26 b(\013g2d)p
+372 5375 V 33 w(\))h(and)f(3D)i(data)f(cub)s(es)f(\(\013p3d)p
+1467 5375 V 59 w(and)g(\013g3d)p 1893 5375 V 33 w(\).)40
+b(The)26 b(dimensionalit)m(y)e(of)j(the)g(FITS)f(image)h(is)e(passed)0
+5488 y(b)m(y)36 b(the)h(naxis1,)g(naxis2,)h(and)e(naxis3)g(parameters)g
+(and)g(the)h(declared)e(dimensions)f(of)j(the)f(program)g(arra)m(y)0
+5601 y(are)30 b(passed)g(in)e(the)i(dim1)f(and)g(dim2)g(parameters.)41
+b(Note)31 b(that)f(the)g(dimensions)d(of)j(the)g(program)g(arra)m(y)g
+(ma)m(y)0 5714 y(b)s(e)35 b(larger)g(than)g(the)h(dimensions)d(of)j
+(the)g(FITS)e(arra)m(y)-8 b(.)58 b(F)-8 b(or)36 b(example)f(if)g(a)h
+(FITS)e(image)i(with)e(NAXIS1)i(=)p eop
+%%Page: 96 104
+96 103 bop 0 299 a Fj(96)1003 b Fh(CHAPTER)30 b(9.)112
+b(SPECIALIZED)28 b(CFITSIO)h(INTERF)-10 b(A)m(CE)30 b(R)m(OUTINES)0
+555 y Fj(NAXIS2)36 b(=)g(400)h(is)e(read)h(in)m(to)g(a)h(program)f
+(arra)m(y)g(whic)m(h)f(is)g(dimensioned)e(as)k(512)g(x)f(512)h(pixels,)
+f(then)g(the)0 668 y(image)f(will)d(just)i(\014ll)e(the)j(lo)m(w)m(er)g
+(left)f(corner)g(of)h(the)g(arra)m(y)g(with)e(pixels)g(in)g(the)i
+(range)g(1)g(-)g(400)g(in)f(the)g(X)h(an)0 781 y(Y)g(directions.)52
+b(This)33 b(has)i(the)g(e\013ect)h(of)f(taking)f(a)i(con)m(tiguous)e
+(set)i(of)f(pixel)e(v)-5 b(alue)34 b(in)f(the)i(FITS)f(arra)m(y)i(and)0
+894 y(writing)28 b(them)i(to)h(a)f(non-con)m(tiguous)g(arra)m(y)h(in)d
+(program)i(memory)g(\(i.e.,)h(there)f(are)h(no)m(w)f(some)g(blank)f
+(pixels)0 1007 y(around)g(the)i(edge)g(of)g(the)f(image)h(in)e(the)h
+(program)g(arra)m(y\).)0 1167 y(The)k(most)i(general)e(set)i(of)f
+(routines)e(\(\013pss)p 1560 1167 28 4 v 33 w(,)j(\013gsv)p
+1836 1167 V 33 w(,)g(and)e(\013gsf)p 2273 1167 V 33 w(\))h(ma)m(y)h(b)s
+(e)e(used)g(to)h(transfer)g(a)g(rectangular)0 1280 y(subset)27
+b(of)h(the)g(pixels)d(in)i(a)h(FITS)f(N-dimensional)e(image)j(to)g(or)g
+(from)f(an)g(arra)m(y)i(whic)m(h)d(has)h(b)s(een)g(declared)g(in)0
+1393 y(the)i(calling)e(program.)40 b(The)28 b(fpixel)f(and)h(lpixel)e
+(parameters)j(are)g(in)m(teger)g(arra)m(ys)g(whic)m(h)e(sp)s(ecify)g
+(the)i(starting)0 1506 y(and)k(ending)e(pixel)h(co)s(ordinate)h(in)f
+(eac)m(h)i(dimension)d(\(starting)i(with)f(1,)i(not)g(0\))g(of)f(the)g
+(FITS)g(image)g(that)h(is)0 1619 y(to)f(b)s(e)e(read)g(or)h(written.)44
+b(It)32 b(is)f(imp)s(ortan)m(t)g(to)i(note)f(that)h(these)f(are)g(the)g
+(starting)g(and)f(ending)f(pixels)g(in)h(the)0 1732 y(FITS)j(image,)j
+(not)e(in)e(the)i(declared)g(arra)m(y)g(in)e(the)i(program.)54
+b(The)35 b(arra)m(y)g(parameter)g(in)f(these)h(routines)f(is)0
+1844 y(treated)g(simply)c(as)j(a)f(large)h(one-dimensional)e(arra)m(y)i
+(of)f(the)h(appropriate)f(data)h(t)m(yp)s(e)g(con)m(taining)f(the)h
+(pixel)0 1957 y(v)-5 b(alues;)36 b(The)e(pixel)f(v)-5
+b(alues)34 b(in)g(the)g(FITS)g(arra)m(y)h(are)g(read/written)f(from/to)
+i(this)d(program)i(arra)m(y)g(in)e(strict)0 2070 y(sequence)e(without)e
+(an)m(y)i(gaps;)g(it)f(is)f(up)g(to)j(the)e(calling)f(routine)g(to)j
+(correctly)e(in)m(terpret)g(the)h(dimensionalit)m(y)0
+2183 y(of)d(this)e(arra)m(y)-8 b(.)41 b(The)27 b(t)m(w)m(o)i(FITS)e
+(reading)g(routines)f(\(\013gsv)p 2018 2183 V 61 w(and)h(\013gsf)p
+2415 2183 V 61 w(\))h(also)f(ha)m(v)m(e)i(an)f(`inc')f(parameter)h
+(whic)m(h)0 2296 y(de\014nes)33 b(the)h(data)h(sampling)d(in)m(terv)-5
+b(al)34 b(in)e(eac)m(h)k(dimension)31 b(of)j(the)h(FITS)e(arra)m(y)-8
+b(.)53 b(F)-8 b(or)35 b(example,)g(if)e(inc[0]=2)0 2409
+y(and)j(inc[1]=3)i(when)e(reading)g(a)h(2-dimensional)e(FITS)h(image,)k
+(then)c(only)g(ev)m(ery)i(other)f(pixel)f(in)f(the)j(\014rst)0
+2522 y(dimension)28 b(and)i(ev)m(ery)h(3rd)f(pixel)e(in)h(the)i(second)
+f(dimension)e(will)g(b)s(e)i(returned)f(to)i(the)f('arra)m(y')i
+(parameter.)0 2682 y(Tw)m(o)d(t)m(yp)s(es)h(of)f(routines)f(are)i(pro)m
+(vided)d(to)j(read)f(the)h(data)g(arra)m(y)f(whic)m(h)f(di\013er)g(in)g
+(the)i(w)m(a)m(y)g(unde\014ned)d(pixels)0 2795 y(are)38
+b(handled.)59 b(The)37 b(\014rst)g(t)m(yp)s(e)g(of)g(routines)g
+(\(e.g.,)j(\013gp)m(v)p 2059 2795 V 34 w(\))d(simply)e(return)h(an)h
+(arra)m(y)h(of)g(data)g(elemen)m(ts)f(in)0 2908 y(whic)m(h)29
+b(unde\014ned)g(pixels)f(are)j(set)g(equal)f(to)i(a)f(v)-5
+b(alue)30 b(sp)s(eci\014ed)e(b)m(y)j(the)g(user)e(in)h(the)g(`n)m(ulv)
+-5 b(al')30 b(parameter.)41 b(An)0 3021 y(additional)27
+b(feature)i(of)g(these)h(routines)d(is)h(that)i(if)e(the)h(user)f(sets)
+h(n)m(ulv)-5 b(al)27 b(=)i(0,)h(then)e(no)h(c)m(hec)m(ks)h(for)f
+(unde\014ned)0 3134 y(pixels)23 b(will)f(b)s(e)j(p)s(erformed,)f(th)m
+(us)h(reducing)e(the)i(amoun)m(t)h(of)f(CPU)f(pro)s(cessing.)38
+b(The)24 b(second)h(t)m(yp)s(e)g(of)g(routines)0 3247
+y(\(e.g.,)36 b(\013gpf)p 413 3247 V 32 w(\))e(returns)e(the)i(data)g
+(elemen)m(t)f(arra)m(y)h(and,)g(in)e(addition,)g(a)i(c)m(har)g(arra)m
+(y)f(that)h(indicates)f(whether)0 3360 y(the)h(v)-5 b(alue)33
+b(of)h(the)f(corresp)s(onding)f(data)i(pixel)e(is)h(unde\014ned)e(\(=)j
+(1\))g(or)g(de\014ned)e(\(=)i(0\).)51 b(The)33 b(latter)h(t)m(yp)s(e)g
+(of)0 3472 y(routines)c(ma)m(y)i(b)s(e)e(more)i(con)m(v)m(enien)m(t)g
+(to)g(use)f(in)f(some)h(circumstances,)h(ho)m(w)m(ev)m(er,)h(it)d
+(requires)g(an)h(additional)0 3585 y(arra)m(y)g(of)f(logical)g(v)-5
+b(alues)30 b(whic)m(h)f(can)i(b)s(e)e(un)m(wieldy)f(when)i(w)m(orking)f
+(with)g(large)i(data)g(arra)m(ys.)0 3859 y Fi(1)81 b
+Fj(W)-8 b(rite)30 b(elemen)m(ts)h(in)m(to)f(the)h(FITS)f(data)h(arra)m
+(y)-8 b(.)95 4133 y Fe(int)47 b(fits_write_img)d(/)k(ffppr)286
+4246 y(\(fitsfile)e(*fptr,)g(int)h(datatype,)e(long)i(firstelem,)e
+(long)h(nelements,)334 4359 y(DTYPE)g(*array,)g(int)h(*status\);)95
+4585 y(int)g(fits_write_img_[byt,)c(sht,)j(usht,)h(int,)f(uint,)h(lng,)
+f(ulng,)h(lnglng,)e(flt,)i(dbl])g(/)286 4698 y
+(ffppr[b,i,ui,k,uk,j,uj,jj,)o(e,d)o(])286 4811 y(\(fitsfile)f(*fptr,)g
+(long)g(group,)g(long)h(firstelem,)e(long)i(nelements,)334
+4924 y(DTYPE)f(*array,)g(>)i(int)f(*status\);)95 5149
+y(int)g(fits_write_imgnull)c(/)48 b(ffppn)286 5262 y(\(fitsfile)e
+(*fptr,)g(int)h(datatype,)e(long)i(firstelem,)e(long)h(nelements,)334
+5375 y(DTYPE)g(*array,)g(DTYPE)h(*nulval,)e(>)j(int)f(*status\);)95
+5601 y(int)g(fits_write_imgnull_[byt,)42 b(sht,)k(usht,)h(int,)f(uint,)
+h(lng,)f(ulng,)h(lnglng,)e(flt,)i(dbl])g(/)286 5714 y
+(ffppn[b,i,ui,k,uk,j,uj,jj,)o(e,d)o(])p eop
+%%Page: 97 105
+97 104 bop 0 299 a Fh(9.5.)72 b(SPECIALIZED)29 b(FITS)g(PRIMAR)-8
+b(Y)31 b(ARRA)-8 b(Y)32 b(OR)d(IMA)m(GE)j(EXTENSION)d(I/O)h(R)m
+(OUTINES)125 b Fj(97)286 555 y Fe(\(fitsfile)46 b(*fptr,)g(long)g
+(group,)g(long)h(firstelem,)525 668 y(long)g(nelements,)e(DTYPE)h
+(*array,)g(DTYPE)g(nulval,)g(>)h(int)g(*status\);)0 924
+y Fi(2)81 b Fj(Set)30 b(data)h(arra)m(y)g(elemen)m(ts)g(as)f
+(unde\014ned.)95 1180 y Fe(int)47 b(fits_write_img_null)c(/)k(ffppru)
+286 1293 y(\(fitsfile)f(*fptr,)g(long)g(group,)g(long)h(firstelem,)e
+(long)i(nelements,)334 1406 y(>)h(int)e(*status\))0 1662
+y Fi(3)81 b Fj(W)-8 b(rite)31 b(v)-5 b(alues)29 b(in)m(to)i(group)f
+(parameters.)42 b(This)29 b(routine)g(only)h(applies)f(to)i(the)g
+(`Random)f(Group)s(ed')g(FITS)227 1775 y(format)22 b(whic)m(h)e(has)h
+(b)s(een)f(used)h(for)g(applications)e(in)h(radio)h(in)m(terferometry)
+-8 b(,)24 b(but)c(is)g(o\016cially)g(deprecated)227 1888
+y(for)30 b(future)g(use.)95 2144 y Fe(int)47 b(fits_write_grppar_[byt,)
+42 b(sht,)k(usht,)h(int,)f(uint,)h(lng,)f(ulng,)h(lnglng,)f(flt,)g
+(dbl])h(/)286 2257 y(ffpgp[b,i,ui,k,uk,j,uj,jj,)o(e,d)o(])286
+2370 y(\(fitsfile)f(*fptr,)g(long)g(group,)g(long)h(firstelem,)e(long)i
+(nelements,)334 2483 y(>)h(DTYPE)e(*array,)g(int)h(*status\))0
+2739 y Fi(4)81 b Fj(W)-8 b(rite)30 b(a)h(2-D)h(or)e(3-D)h(image)g(in)m
+(to)f(the)h(data)g(arra)m(y)-8 b(.)95 2996 y Fe(int)47
+b(fits_write_2d_[byt,)c(sht,)k(usht,)f(int,)h(uint,)f(lng,)h(ulng,)f
+(lnglng,)g(flt,)g(dbl])h(/)286 3108 y(ffp2d[b,i,ui,k,uk,j,uj,jj,)o(e,d)
+o(])286 3221 y(\(fitsfile)f(*fptr,)g(long)g(group,)g(long)h(dim1,)f
+(long)h(naxis1,)334 3334 y(long)g(naxis2,)f(DTYPE)g(*array,)g(>)h(int)g
+(*status\))95 3560 y(int)g(fits_write_3d_[byt,)c(sht,)k(usht,)f(int,)h
+(uint,)f(lng,)h(ulng,)f(lnglng,)g(flt,)g(dbl])h(/)286
+3673 y(ffp3d[b,i,ui,k,uk,j,uj,jj,)o(e,d)o(])286 3786
+y(\(fitsfile)f(*fptr,)g(long)g(group,)g(long)h(dim1,)f(long)h(dim2,)334
+3899 y(long)g(naxis1,)f(long)g(naxis2,)g(long)h(naxis3,)e(DTYPE)i
+(*array,)f(>)h(int)g(*status\))0 4155 y Fi(5)81 b Fj(W)-8
+b(rite)30 b(an)h(arbitrary)e(data)i(subsection)e(in)m(to)i(the)f(data)h
+(arra)m(y)-8 b(.)95 4411 y Fe(int)47 b(fits_write_subset_[byt,)42
+b(sht,)k(usht,)h(int,)f(uint,)h(lng,)f(ulng,)h(lnglng,)f(flt,)g(dbl])h
+(/)286 4524 y(ffpss[b,i,ui,k,uk,j,uj,jj,)o(e,d)o(])286
+4637 y(\(fitsfile)f(*fptr,)g(long)g(group,)g(long)h(naxis,)f(long)h
+(*naxes,)334 4750 y(long)g(*fpixel,)e(long)i(*lpixel,)e(DTYPE)i
+(*array,)f(>)h(int)g(*status\))0 5006 y Fi(6)81 b Fj(Read)30
+b(elemen)m(ts)h(from)f(the)g(FITS)g(data)h(arra)m(y)-8
+b(.)95 5262 y Fe(int)47 b(fits_read_img)e(/)i(ffgpv)286
+5375 y(\(fitsfile)f(*fptr,)g(int)94 b(datatype,)46 b(long)g(firstelem,)
+f(long)i(nelements,)334 5488 y(DTYPE)f(*nulval,)g(>)h(DTYPE)g(*array,)f
+(int)h(*anynul,)e(int)i(*status\))95 5714 y(int)g(fits_read_img_[byt,)c
+(sht,)k(usht,)f(int,)h(uint,)f(lng,)h(ulng,)f(lnglng,)g(flt,)g(dbl])h
+(/)p eop
+%%Page: 98 106
+98 105 bop 0 299 a Fj(98)1003 b Fh(CHAPTER)30 b(9.)112
+b(SPECIALIZED)28 b(CFITSIO)h(INTERF)-10 b(A)m(CE)30 b(R)m(OUTINES)286
+555 y Fe(ffgpv[b,i,ui,k,uk,j,uj,jj,)o(e,d)o(])286 668
+y(\(fitsfile)46 b(*fptr,)g(long)g(group,)g(long)h(firstelem,)e(long)i
+(nelements,)334 781 y(DTYPE)f(nulval,)g(>)i(DTYPE)e(*array,)g(int)h
+(*anynul,)e(int)i(*status\))95 1007 y(int)g(fits_read_imgnull)c(/)48
+b(ffgpf)286 1120 y(\(fitsfile)e(*fptr,)g(int)94 b(datatype,)46
+b(long)g(firstelem,)f(long)i(nelements,)334 1233 y(>)h(DTYPE)e(*array,)
+g(char)g(*nullarray,)f(int)i(*anynul,)f(int)g(*status\))95
+1458 y(int)95 b(fits_read_imgnull_[byt,)42 b(sht,)k(usht,)h(int,)f
+(uint,)h(lng,)f(ulng,)h(flt,)f(dbl])h(/)334 1571 y
+(ffgpf[b,i,ui,k,uk,j,uj,jj)o(,e,)o(d])334 1684 y(\(fitsfile)e(*fptr,)h
+(long)h(group,)f(long)h(firstelem,)e(long)h(nelements,)334
+1797 y(>)i(DTYPE)e(*array,)g(char)g(*nullarray,)f(int)i(*anynul,)f(int)
+g(*status\))0 2055 y Fi(7)81 b Fj(Read)29 b(v)-5 b(alues)30
+b(from)f(group)g(parameters.)41 b(This)28 b(routine)g(only)h(applies)f
+(to)j(the)e(`Random)h(Group)s(ed')f(FITS)227 2168 y(format)22
+b(whic)m(h)e(has)h(b)s(een)f(used)h(for)g(applications)e(in)h(radio)h
+(in)m(terferometry)-8 b(,)24 b(but)c(is)g(o\016cially)g(deprecated)227
+2281 y(for)30 b(future)g(use.)95 2538 y Fe(int)95 b
+(fits_read_grppar_[byt,)42 b(sht,)k(usht,)h(int,)f(uint,)h(lng,)f
+(ulng,)h(lnglng,)f(flt,)g(dbl])h(/)334 2651 y
+(ffggp[b,i,ui,k,uk,j,uj,jj)o(,e,)o(d])334 2764 y(\(fitsfile)e(*fptr,)h
+(long)h(group,)f(long)h(firstelem,)e(long)h(nelements,)334
+2877 y(>)i(DTYPE)e(*array,)g(int)h(*status\))0 3135 y
+Fi(8)81 b Fj(Read)37 b(2-D)h(or)g(3-D)g(image)f(from)g(the)g(data)h
+(arra)m(y)-8 b(.)62 b(Unde\014ned)36 b(pixels)g(in)f(the)j(arra)m(y)g
+(will)c(b)s(e)j(set)g(equal)227 3247 y(to)32 b(the)g(v)-5
+b(alue)30 b(of)i('n)m(ulv)-5 b(al',)30 b(unless)g(n)m(ulv)-5
+b(al=0)29 b(in)h(whic)m(h)g(case)i(no)f(testing)h(for)f(unde\014ned)e
+(pixels)g(will)g(b)s(e)227 3360 y(p)s(erformed.)95 3618
+y Fe(int)95 b(fits_read_2d_[byt,)43 b(sht,)k(usht,)f(int,)h(uint,)f
+(lng,)h(ulng,)f(lnglng,)g(flt,)g(dbl])h(/)334 3731 y
+(ffg2d[b,i,ui,k,uk,j,uj,jj)o(,e,)o(d])334 3844 y(\(fitsfile)e(*fptr,)h
+(long)h(group,)f(DTYPE)h(nulval,)e(long)i(dim1,)f(long)h(naxis1,)334
+3957 y(long)g(naxis2,)f(>)h(DTYPE)f(*array,)g(int)h(*anynul,)f(int)h
+(*status\))95 4183 y(int)95 b(fits_read_3d_[byt,)43 b(sht,)k(usht,)f
+(int,)h(uint,)f(lng,)h(ulng,)f(lnglng,)g(flt,)g(dbl])h(/)334
+4295 y(ffg3d[b,i,ui,k,uk,j,uj,jj)o(,e,)o(d])334 4408
+y(\(fitsfile)e(*fptr,)h(long)h(group,)f(DTYPE)h(nulval,)e(long)i(dim1,)
+334 4521 y(long)g(dim2,)f(long)h(naxis1,)f(long)g(naxis2,)g(long)h
+(naxis3,)334 4634 y(>)h(DTYPE)e(*array,)g(int)h(*anynul,)e(int)i
+(*status\))0 4892 y Fi(9)81 b Fj(Read)30 b(an)g(arbitrary)g(data)h
+(subsection)e(from)h(the)g(data)i(arra)m(y)-8 b(.)95
+5149 y Fe(int)95 b(fits_read_subset_[byt,)42 b(sht,)k(usht,)h(int,)f
+(uint,)h(lng,)f(ulng,)h(lnglng,)f(flt,)g(dbl])h(/)334
+5262 y(ffgsv[b,i,ui,k,uk,j,uj,jj)o(,e,)o(d])334 5375
+y(\(fitsfile)e(*fptr,)h(int)h(group,)f(int)h(naxis,)f(long)h(*naxes,)
+334 5488 y(long)g(*fpixel,)e(long)i(*lpixel,)e(long)i(*inc,)f(DTYPE)h
+(nulval,)334 5601 y(>)h(DTYPE)e(*array,)g(int)h(*anynul,)e(int)i
+(*status\))p eop
+%%Page: 99 107
+99 106 bop 0 299 a Fh(9.6.)72 b(SPECIALIZED)29 b(FITS)g(ASCI)s(I)g(AND)
+i(BINAR)-8 b(Y)32 b(T)-8 b(ABLE)30 b(R)m(OUTINES)978
+b Fj(99)95 555 y Fe(int)95 b(fits_read_subsetnull_[byt)o(,)42
+b(sht,)k(usht,)h(int,)f(uint,)h(lng,)f(ulng,)h(lnglng,)f(flt,)g(dbl])h
+(/)334 668 y(ffgsf[b,i,ui,k,uk,j,uj,jj)o(,e,)o(d])334
+781 y(\(fitsfile)e(*fptr,)h(int)h(group,)f(int)h(naxis,)f(long)h
+(*naxes,)334 894 y(long)g(*fpixel,)e(long)i(*lpixel,)e(long)i(*inc,)f
+(>)i(DTYPE)e(*array,)334 1007 y(char)h(*nullarray,)d(int)j(*anynul,)f
+(int)h(*status\))0 1338 y Ff(9.6)135 b(Sp)t(ecialized)46
+b(FITS)e(ASCI)t(I)g(and)g(Binary)h(T)-11 b(able)45 b(Routines)0
+1591 y Fd(9.6.1)112 b(General)38 b(Column)e(Routines)0
+1797 y Fi(1)81 b Fj(Get)31 b(information)d(ab)s(out)i(an)g(existing)f
+(ASCI)s(I)f(or)i(binary)e(table)i(column.)40 b(A)30 b(n)m(ull)e(p)s
+(oin)m(ter)h(ma)m(y)i(b)s(e)e(giv)m(en)227 1910 y(for)40
+b(an)m(y)h(of)f(the)h(output)f(parameters)g(that)h(are)g(not)f(needed.)
+70 b(D)m(A)-8 b(T)g(A)g(TYPE)42 b(is)d(a)i(c)m(haracter)h(string)227
+2023 y(whic)m(h)c(returns)f(the)i(data)g(t)m(yp)s(e)g(of)g(the)f
+(column)g(as)h(de\014ned)e(b)m(y)i(the)f(TF)m(ORMn)h(k)m(eyw)m(ord)g
+(\(e.g.,)j('I',)227 2136 y('J','E',)28 b('D',)g(etc.\).)41
+b(In)27 b(the)g(case)g(of)g(an)g(ASCI)s(I)f(c)m(haracter)i(column,)f(t)
+m(yp)s(eco)s(de)g(will)d(ha)m(v)m(e)k(a)f(v)-5 b(alue)27
+b(of)g(the)227 2249 y(form)g('An')g(where)f('n')h(is)f(an)h(in)m(teger)
+h(expressing)d(the)i(width)f(of)h(the)g(\014eld)f(in)f(c)m(haracters.)
+41 b(F)-8 b(or)28 b(example,)227 2362 y(if)f(TF)m(ORM)i(=)e('160A8')k
+(then)d(\013gb)s(cl)f(will)e(return)i(t)m(yp)s(ec)m(har='A8')j(and)d
+(rep)s(eat=20.)41 b(All)27 b(the)h(returned)227 2475
+y(parameters)j(are)g(scalar)f(quan)m(tities.)95 2716
+y Fe(int)47 b(fits_get_acolparms)c(/)48 b(ffgacl)191
+2829 y(\(fitsfile)d(*fptr,)h(int)h(colnum,)f(>)h(char)g(*ttype,)f(long)
+h(*tbcol,)239 2942 y(char)f(*tunit,)g(char)h(*tform,)f(double)g
+(*scale,)f(double)i(*zero,)239 3055 y(char)f(*nulstr,)g(char)g(*tdisp,)
+g(int)h(*status\))95 3280 y(int)g(fits_get_bcolparms)c(/)48
+b(ffgbcl)286 3393 y(\(fitsfile)e(*fptr,)g(int)h(colnum,)e(>)j(char)f
+(*ttype,)e(char)i(*tunit,)334 3506 y(char)g(*typechar,)e(long)h
+(*repeat,)g(double)g(*scale,)g(double)g(*zero,)334 3619
+y(long)h(*nulval,)e(char)i(*tdisp,)f(int)94 b(*status\))0
+3861 y Fi(2)81 b Fj(Return)27 b(optimal)g(n)m(um)m(b)s(er)g(of)h(ro)m
+(ws)g(to)h(read)f(or)g(write)f(at)i(one)f(time)g(for)g(maxim)m(um)f
+(I/O)g(e\016ciency)-8 b(.)41 b(Refer)227 3973 y(to)25
+b(the)g(\\Optimizing)d(Co)s(de")i(section)h(in)e(Chapter)h(5)g(for)g
+(more)h(discussion)d(on)i(ho)m(w)g(to)h(use)f(this)g(routine.)95
+4328 y Fe(int)47 b(fits_get_rowsize)d(/)j(ffgrsz)286
+4441 y(\(fitsfile)f(*fptr,)g(long)g(*nrows,)g(*status\))0
+4682 y Fi(3)81 b Fj(De\014ne)22 b(the)g(zero)i(indexed)c(b)m(yte)j
+(o\013set)g(of)g(the)f('heap')h(measured)e(from)h(the)h(start)g(of)f
+(the)g(binary)f(table)h(data.)227 4795 y(By)30 b(default)f(the)g(heap)h
+(is)e(assumed)h(to)h(start)g(immediately)e(follo)m(wing)g(the)i
+(regular)e(table)i(data,)g(i.e.,)g(at)227 4908 y(lo)s(cation)36
+b(NAXIS1)h(x)g(NAXIS2.)59 b(This)35 b(routine)g(is)h(only)f(relev)-5
+b(an)m(t)37 b(for)f(binary)f(tables)h(whic)m(h)g(con)m(tain)227
+5021 y(v)-5 b(ariable)23 b(length)h(arra)m(y)h(columns)e(\(with)g(TF)m
+(ORMn)h(=)g('Pt'\).)40 b(This)22 b(routine)i(also)g(automatically)g
+(writes)227 5134 y(the)35 b(v)-5 b(alue)34 b(of)h(theap)f(to)h(a)g(k)m
+(eyw)m(ord)g(in)f(the)g(extension)g(header.)53 b(This)33
+b(routine)g(m)m(ust)i(b)s(e)f(called)f(after)227 5247
+y(the)e(required)d(k)m(eyw)m(ords)i(ha)m(v)m(e)i(b)s(een)d(written)g
+(\(with)g(\013ph)m(bn\))g(but)h(b)s(efore)f(an)m(y)i(data)g(is)e
+(written)g(to)i(the)227 5360 y(table.)95 5601 y Fe(int)47
+b(fits_write_theap)d(/)j(ffpthp)286 5714 y(\(fitsfile)f(*fptr,)g(long)g
+(theap,)g(>)i(int)f(*status\))p eop
+%%Page: 100 108
+100 107 bop 0 299 a Fj(100)958 b Fh(CHAPTER)30 b(9.)112
+b(SPECIALIZED)28 b(CFITSIO)h(INTERF)-10 b(A)m(CE)30 b(R)m(OUTINES)0
+555 y Fi(4)81 b Fj(T)-8 b(est)37 b(the)f(con)m(ten)m(ts)i(of)f(the)g
+(binary)d(table)j(v)-5 b(ariable)35 b(arra)m(y)i(heap,)h(returning)d
+(the)h(size)g(of)h(the)g(heap,)h(the)227 668 y(n)m(um)m(b)s(er)30
+b(of)h(un)m(used)e(b)m(ytes)j(that)f(are)g(not)g(curren)m(tly)f(p)s
+(oin)m(ted)g(to)i(b)m(y)e(an)m(y)i(of)f(the)g(descriptors,)f(and)g(the)
+227 781 y(n)m(um)m(b)s(er)d(of)h(b)m(ytes)h(whic)m(h)e(are)h(p)s(oin)m
+(ted)f(to)i(b)m(y)f(m)m(ultiple)e(descriptors.)39 b(It)28
+b(also)g(returns)f(v)-5 b(alid)27 b(=)g(F)-10 b(ALSE)227
+894 y(if)30 b(an)m(y)g(of)h(the)f(descriptors)g(p)s(oin)m(t)f(to)i(in)m
+(v)-5 b(alid)28 b(addresses)i(out)g(of)h(range)g(of)f(the)h(heap.)95
+1153 y Fe(int)47 b(fits_test_heap)d(/)k(fftheap)286 1266
+y(\(fitsfile)e(*fptr,)g(>)h(long)g(*heapsize,)e(long)h(*unused,)g(long)
+h(*overlap,)334 1379 y(int)g(*validheap,)e(int)i(*status\))0
+1637 y Fi(5)81 b Fj(Re-pac)m(k)33 b(the)f(v)m(ectors)h(in)d(the)i
+(binary)e(table)i(v)-5 b(ariable)30 b(arra)m(y)i(heap)g(to)g(reco)m(v)m
+(er)i(an)m(y)e(un)m(used)e(space.)45 b(Nor-)227 1750
+y(mally)-8 b(,)38 b(when)f(a)g(v)m(ector)i(in)d(a)h(v)-5
+b(ariable)36 b(length)h(arra)m(y)g(column)f(is)g(rewritten)h(the)g
+(previously)e(written)227 1863 y(arra)m(y)f(remains)d(in)h(the)h(heap)f
+(as)h(w)m(asted)h(un)m(used)d(space.)49 b(This)31 b(routine)g(will)g
+(repac)m(k)i(the)g(arra)m(ys)g(that)227 1976 y(are)h(still)d(in)h(use,)
+i(th)m(us)f(eliminating)d(an)m(y)k(b)m(ytes)g(in)e(the)h(heap)g(that)h
+(are)g(no)f(longer)g(in)f(use.)49 b(Note)34 b(that)227
+2089 y(if)e(sev)m(eral)h(v)m(ectors)h(p)s(oin)m(t)d(to)j(the)e(same)h
+(b)m(ytes)g(in)f(the)g(heap,)i(then)e(this)f(routine)h(will)e(mak)m(e)j
+(duplicate)227 2202 y(copies)d(of)h(the)g(b)m(ytes)f(for)h(eac)m(h)g(v)
+m(ector,)h(whic)m(h)d(will)f(actually)i(expand)g(the)g(size)h(of)f(the)
+h(heap.)95 2461 y Fe(int)47 b(fits_compress_heap)c(/)48
+b(ffcmph)286 2574 y(\(fitsfile)e(*fptr,)g(>)h(int)g(*status\))0
+2864 y Fd(9.6.2)112 b(Lo)m(w-Lev)m(el)38 b(T)-9 b(able)37
+b(Access)g(Routines)0 3083 y Fj(The)g(follo)m(wing)g(2)h(routines)e
+(pro)m(vide)h(lo)m(w-lev)m(el)h(access)h(to)g(the)f(data)g(in)f(ASCI)s
+(I)f(or)i(binary)e(tables)h(and)h(are)0 3196 y(mainly)27
+b(useful)g(as)j(an)f(e\016cien)m(t)g(w)m(a)m(y)h(to)g(cop)m(y)g(all)e
+(or)h(part)g(of)g(a)g(table)g(from)g(one)g(lo)s(cation)g(to)h(another.)
+40 b(These)0 3309 y(routines)23 b(simply)f(read)i(or)h(write)e(the)i
+(sp)s(eci\014ed)d(n)m(um)m(b)s(er)h(of)i(consecutiv)m(e)g(b)m(ytes)g
+(in)e(an)h(ASCI)s(I)f(or)h(binary)f(table,)0 3422 y(without)g(regard)h
+(for)f(column)g(b)s(oundaries)e(or)j(the)g(ro)m(w)g(length)f(in)f(the)i
+(table.)39 b(These)23 b(routines)g(do)g(not)h(p)s(erform)0
+3535 y(an)m(y)36 b(mac)m(hine)g(dep)s(enden)m(t)f(data)i(con)m(v)m
+(ersion)f(or)h(b)m(yte)f(sw)m(apping.)57 b(See)36 b(App)s(endix)d(B)k
+(for)f(the)g(de\014nition)e(of)0 3648 y(the)d(parameters)f(used)g(in)f
+(these)i(routines.)0 3906 y Fi(1)81 b Fj(Read)30 b(or)h(write)e(a)i
+(consecutiv)m(e)g(arra)m(y)g(of)g(b)m(ytes)f(from)g(an)h(ASCI)s(I)d(or)
+j(binary)d(table)95 4165 y Fe(int)47 b(fits_read_tblbytes)c(/)48
+b(ffgtbb)286 4278 y(\(fitsfile)e(*fptr,)g(long)g(firstrow,)g(long)g
+(firstchar,)f(long)i(nchars,)334 4391 y(>)h(unsigned)d(char)i(*values,)
+e(int)i(*status\))95 4617 y(int)g(fits_write_tblbytes)c(/)k(ffptbb)286
+4730 y(\(fitsfile)f(*fptr,)g(long)g(firstrow,)g(long)g(firstchar,)f
+(long)i(nchars,)334 4843 y(unsigned)f(char)g(*values,)g(>)h(int)g
+(*status\))0 5133 y Fd(9.6.3)112 b(W)-9 b(rite)36 b(Column)g(Data)i
+(Routines)0 5342 y Fi(1)81 b Fj(W)-8 b(rite)27 b(elemen)m(ts)h(in)m(to)
+f(an)h(ASCI)s(I)d(or)j(binary)d(table)j(column)e(\(in)g(the)i(CDU\).)g
+(The)f(data)h(t)m(yp)s(e)f(of)h(the)f(arra)m(y)227 5455
+y(is)j(implied)d(b)m(y)j(the)h(su\016x)e(of)i(the)f(routine)g(name.)95
+5714 y Fe(int)47 b(fits_write_col_str)c(/)48 b(ffpcls)p
+eop
+%%Page: 101 109
+101 108 bop 0 299 a Fh(9.6.)72 b(SPECIALIZED)29 b(FITS)g(ASCI)s(I)g
+(AND)i(BINAR)-8 b(Y)32 b(T)-8 b(ABLE)30 b(R)m(OUTINES)933
+b Fj(101)286 555 y Fe(\(fitsfile)46 b(*fptr,)g(int)h(colnum,)e(long)i
+(firstrow,)e(long)i(firstelem,)334 668 y(long)g(nelements,)e(char)h
+(**array,)g(>)h(int)g(*status\))95 894 y(int)g
+(fits_write_col_[log,byt,sh)o(t,u)o(sht,)o(int,)o(uin)o(t,ln)o(g,ul)o
+(ng,)o(lngl)o(ng,f)o(lt,)o(dbl,)o(cmp,)o(dbl)o(cmp])41
+b(/)286 1007 y(ffpcl[l,b,i,ui,k,uk,j,uj,j)o(j,e)o(,d,c)o(,m])286
+1120 y(\(fitsfile)46 b(*fptr,)g(int)h(colnum,)e(long)i(firstrow,)525
+1233 y(long)g(firstelem,)e(long)h(nelements,)f(DTYPE)i(*array,)e(>)j
+(int)f(*status\))0 1487 y Fi(2)81 b Fj(W)-8 b(rite)35
+b(elemen)m(ts)h(in)m(to)g(an)f(ASCI)s(I)f(or)i(binary)d(table)j(column)
+e(substituting)f(the)j(appropriate)e(FITS)h(n)m(ull)227
+1600 y(v)-5 b(alue)37 b(for)h(an)m(y)g(elemen)m(ts)g(that)g(are)g
+(equal)f(to)i(the)f(n)m(ulv)-5 b(al)36 b(parameter.)63
+b(This)36 b(routines)g(m)m(ust)i(not)g(b)s(e)227 1713
+y(used)30 b(to)h(write)f(to)h(v)-5 b(ariable)29 b(length)h(arra)m(y)g
+(columns.)95 1967 y Fe(int)47 b(fits_write_colnull_[log,)42
+b(byt,)k(sht,)h(usht,)f(int,)h(uint,)f(lng,)h(ulng,)f(lnglng,)g(flt,)h
+(dbl])f(/)286 2080 y(ffpcn[l,b,i,ui,k,uk,j,uj,j)o(j,e)o(,d])286
+2193 y(\(fitsfile)g(*fptr,)g(int)h(colnum,)e(long)i(firstrow,)e(long)i
+(firstelem,)334 2306 y(long)g(nelements,)e(DTYPE)h(*array,)g(DTYPE)g
+(nulval,)g(>)i(int)e(*status\))0 2560 y Fi(3)81 b Fj(W)-8
+b(rite)26 b(string)g(elemen)m(ts)h(in)m(to)f(a)h(binary)e(table)h
+(column)f(\(in)h(the)g(CDU\))i(substituting)c(the)i(FITS)g(n)m(ull)e(v)
+-5 b(alue)227 2673 y(for)28 b(an)m(y)f(elemen)m(ts)h(that)g(are)g
+(equal)f(to)i(the)e(n)m(ulstr)f(string.)39 b(This)26
+b(routine)g(m)m(ust)i(NOT)f(b)s(e)g(used)f(to)j(write)227
+2786 y(to)i(v)-5 b(ariable)30 b(length)f(arra)m(y)i(columns.)95
+3040 y Fe(int)47 b(fits_write_colnull_str)42 b(/)48 b(ffpcns)286
+3153 y(\(fitsfile)e(*fptr,)g(int)h(colnum,)e(long)i(firstrow,)e(long)i
+(firstelem,)334 3266 y(long)g(nelements,)e(char)h(**array,)g(char)h
+(*nulstr,)e(>)j(int)e(*status\))0 3520 y Fi(4)81 b Fj(W)-8
+b(rite)33 b(bit)f(v)-5 b(alues)32 b(in)m(to)h(a)h(binary)d(b)m(yte)i
+(\('B'\))i(or)e(bit)f(\('X'\))i(table)f(column)f(\(in)g(the)h(CDU\).)h
+(Larra)m(y)f(is)f(an)227 3633 y(arra)m(y)25 b(of)g(c)m(haracters)h
+(corresp)s(onding)d(to)i(the)g(sequence)g(of)f(bits)g(to)h(b)s(e)f
+(written.)38 b(If)24 b(an)g(elemen)m(t)h(of)g(larra)m(y)227
+3746 y(is)j(true)h(\(not)h(equal)e(to)i(zero\))g(then)f(the)g(corresp)s
+(onding)e(bit)h(in)g(the)h(FITS)f(table)h(is)f(set)i(to)g(1,)g
+(otherwise)227 3859 y(the)37 b(bit)f(is)g(set)h(to)g(0.)60
+b(The)37 b('X')g(column)e(in)h(a)h(FITS)f(table)g(is)g(alw)m(a)m(ys)h
+(padded)f(out)h(to)g(a)g(m)m(ultiple)e(of)227 3972 y(8)i(bits)e(where)h
+(the)g(bit)g(arra)m(y)g(starts)h(with)e(the)i(most)f(signi\014can)m(t)f
+(bit)h(of)g(the)h(b)m(yte)g(and)e(w)m(orks)h(do)m(wn)227
+4085 y(to)m(w)m(ards)h(the)g(1's)f(bit.)58 b(F)-8 b(or)37
+b(example,)h(a)e('4X')h(arra)m(y)-8 b(,)39 b(with)c(the)i(\014rst)e
+(bit)h(=)f(1)i(and)f(the)g(remaining)f(3)227 4197 y(bits)30
+b(=)h(0)h(is)e(equiv)-5 b(alen)m(t)31 b(to)h(the)g(8-bit)f(unsigned)e
+(b)m(yte)j(decimal)e(v)-5 b(alue)31 b(of)h(128)g(\('1000)i(0000B'\).)g
+(In)d(the)227 4310 y(case)h(of)f('X')g(columns,)f(CFITSIO)g(can)h
+(write)f(to)h(all)f(8)h(bits)f(of)h(eac)m(h)h(b)m(yte)f(whether)f(they)
+h(are)g(formally)227 4423 y(v)-5 b(alid)32 b(or)h(not.)50
+b(Th)m(us)32 b(if)h(the)g(column)f(is)h(de\014ned)f(as)h('4X',)i(and)e
+(one)g(calls)g(\013p)s(clx)f(with)g(\014rstbit=1)g(and)227
+4536 y(n)m(bits=8,)i(then)g(all)e(8)j(bits)d(will)f(b)s(e)j(written)f
+(in)m(to)g(the)h(\014rst)f(b)m(yte)i(\(as)f(opp)s(osed)f(to)i(writing)c
+(the)j(\014rst)g(4)227 4649 y(bits)27 b(in)m(to)h(the)f(\014rst)g(ro)m
+(w)h(and)f(then)h(the)g(next)g(4)g(bits)e(in)m(to)i(the)g(next)g(ro)m
+(w\),)h(ev)m(en)f(though)f(the)h(last)g(4)g(bits)227
+4762 y(of)j(eac)m(h)g(b)m(yte)g(are)f(formally)f(not)h(de\014ned)f(and)
+h(should)e(all)h(b)s(e)g(set)i(=)f(0.)41 b(It)30 b(should)e(also)j(b)s
+(e)e(noted)h(that)227 4875 y(it)j(is)e(more)i(e\016cien)m(t)h(to)f
+(write)f('X')i(columns)d(an)i(en)m(tire)g(b)m(yte)g(at)h(a)f(time,)g
+(instead)f(of)h(bit)f(b)m(y)h(bit.)47 b(An)m(y)227 4988
+y(of)31 b(the)g(CFITSIO)e(routines)g(that)j(write)e(to)h(columns)e
+(\(e.g.)43 b(\014ts)p 2481 4988 28 4 v 33 w(write)p 2717
+4988 V 32 w(col)p 2860 4988 V 32 w(b)m(yt\))32 b(ma)m(y)f(b)s(e)f(used)
+g(for)g(this)227 5101 y(purp)s(ose.)60 b(These)36 b(routines)h(will)d
+(in)m(terpret)j('X')g(columns)f(as)h(though)g(they)h(w)m(ere)f('B')h
+(columns)e(\(e.g.,)227 5214 y('1X')c(through)d('8X')j(is)d(equiv)-5
+b(alen)m(t)30 b(to)h('1B',)h(and)e('9X')h(through)f('16X')i(is)d(equiv)
+-5 b(alen)m(t)30 b(to)h('2B'\).)95 5468 y Fe(int)47 b
+(fits_write_col_bit)c(/)48 b(ffpclx)286 5581 y(\(fitsfile)e(*fptr,)g
+(int)h(colnum,)e(long)i(firstrow,)e(long)i(firstbit,)334
+5694 y(long)g(nbits,)f(char)g(*larray,)g(>)h(int)g(*status\))p
+eop
+%%Page: 102 110
+102 109 bop 0 299 a Fj(102)958 b Fh(CHAPTER)30 b(9.)112
+b(SPECIALIZED)28 b(CFITSIO)h(INTERF)-10 b(A)m(CE)30 b(R)m(OUTINES)0
+555 y Fi(5)81 b Fj(W)-8 b(rite)34 b(the)g(descriptor)f(for)g(a)h(v)-5
+b(ariable)33 b(length)g(column)g(in)f(a)j(binary)d(table.)51
+b(This)32 b(routine)g(can)j(b)s(e)e(used)227 668 y(in)g(conjunction)g
+(with)f(\013gdes)i(to)h(enable)e(2)h(or)g(more)g(arra)m(ys)h(to)f(p)s
+(oin)m(t)f(to)i(the)f(same)g(storage)h(lo)s(cation)227
+781 y(to)c(sa)m(v)m(e)h(storage)g(space)f(if)e(the)i(arra)m(ys)g(are)g
+(iden)m(tical.)191 1045 y Fe(int)47 b(fits_write_descript)42
+b(/)48 b(ffpdes)382 1158 y(\(fitsfile)d(*fptr,)h(int)h(colnum,)f(long)h
+(rownum,)e(long)i(repeat,)430 1271 y(long)f(offset,)g(>)h(int)g
+(*status\))0 1567 y Fd(9.6.4)112 b(Read)38 b(Column)f(Data)h(Routines)0
+1787 y Fj(Tw)m(o)28 b(t)m(yp)s(es)f(of)h(routines)e(are)i(pro)m(vided)e
+(to)i(get)h(the)e(column)g(data)h(whic)m(h)e(di\013er)g(in)g(the)i(w)m
+(a)m(y)h(unde\014ned)c(pixels)0 1900 y(are)40 b(handled.)65
+b(The)39 b(\014rst)g(set)h(of)f(routines)f(\(\013gcv\))j(simply)c
+(return)h(an)h(arra)m(y)h(of)g(data)g(elemen)m(ts)f(in)f(whic)m(h)0
+2013 y(unde\014ned)28 b(pixels)h(are)i(set)g(equal)f(to)h(a)g(v)-5
+b(alue)30 b(sp)s(eci\014ed)f(b)m(y)i(the)f(user)g(in)f(the)i('n)m(ullv)
+-5 b(al')29 b(parameter.)41 b(If)30 b(n)m(ullv)-5 b(al)0
+2126 y(=)22 b(0,)j(then)d(no)g(c)m(hec)m(ks)i(for)e(unde\014ned)e
+(pixels)h(will)f(b)s(e)i(p)s(erformed,)g(th)m(us)g(increasing)g(the)g
+(sp)s(eed)g(of)g(the)h(program.)0 2239 y(The)36 b(second)g(set)g(of)h
+(routines)d(\(\013gcf)7 b(\))38 b(returns)d(the)h(data)h(elemen)m(t)f
+(arra)m(y)h(and)e(in)g(addition)f(a)j(logical)e(arra)m(y)0
+2351 y(of)e(\015ags)f(whic)m(h)f(de\014nes)h(whether)g(the)g(corresp)s
+(onding)f(data)i(pixel)d(is)i(unde\014ned.)44 b(See)33
+b(App)s(endix)d(B)j(for)f(the)0 2464 y(de\014nition)c(of)j(the)f
+(parameters)h(used)e(in)g(these)i(routines.)0 2625 y(An)m(y)39
+b(column,)g(regardless)f(of)h(it's)f(in)m(trinsic)e(data)k(t)m(yp)s(e,)
+h(ma)m(y)e(b)s(e)f(read)g(as)h(a)g(string.)65 b(It)38
+b(should)f(b)s(e)h(noted)0 2737 y(ho)m(w)m(ev)m(er)32
+b(that)f(reading)e(a)i(n)m(umeric)e(column)g(as)i(a)f(string)g(is)f(10)
+i(-)g(100)g(times)f(slo)m(w)m(er)h(than)f(reading)f(the)i(same)0
+2850 y(column)f(as)i(a)g(n)m(um)m(b)s(er)e(due)h(to)h(the)g(large)g(o)m
+(v)m(erhead)g(in)f(constructing)g(the)h(formatted)g(strings.)43
+b(The)31 b(displa)m(y)0 2963 y(format)26 b(of)g(the)h(returned)d
+(strings)h(will)e(b)s(e)j(determined)e(b)m(y)i(the)g(TDISPn)f(k)m(eyw)m
+(ord,)j(if)c(it)i(exists,)h(otherwise)e(b)m(y)0 3076
+y(the)i(data)g(t)m(yp)s(e)f(of)h(the)f(column.)38 b(The)26
+b(length)g(of)h(the)f(returned)f(strings)g(\(not)i(including)c(the)k(n)
+m(ull)d(terminating)0 3189 y(c)m(haracter\))38 b(can)e(b)s(e)g
+(determined)e(with)h(the)h(\014ts)p 1722 3189 28 4 v
+33 w(get)p 1875 3189 V 34 w(col)p 2020 3189 V 32 w(displa)m(y)p
+2332 3189 V 31 w(width)f(routine.)56 b(The)36 b(follo)m(wing)e(TDISPn)0
+3302 y(displa)m(y)29 b(formats)h(are)h(curren)m(tly)e(supp)s(orted:)191
+3566 y Fe(Iw.m)142 b(Integer)191 3679 y(Ow.m)g(Octal)46
+b(integer)191 3792 y(Zw.m)142 b(Hexadecimal)45 b(integer)191
+3905 y(Fw.d)142 b(Fixed)46 b(floating)g(point)191 4018
+y(Ew.d)142 b(Exponential)45 b(floating)g(point)191 4131
+y(Dw.d)142 b(Exponential)45 b(floating)g(point)191 4244
+y(Gw.d)142 b(General;)46 b(uses)g(Fw.d)h(if)g(significance)d(not)j
+(lost,)g(else)f(Ew.d)0 4508 y Fj(where)37 b(w)h(is)f(the)h(width)e(in)h
+(c)m(haracters)i(of)f(the)h(displa)m(y)m(ed)d(v)-5 b(alues,)40
+b(m)d(is)g(the)h(minim)m(um)e(n)m(um)m(b)s(er)g(of)i(digits)0
+4621 y(displa)m(y)m(ed,)29 b(and)h(d)g(is)f(the)i(n)m(um)m(b)s(er)e(of)
+h(digits)f(to)i(the)g(righ)m(t)f(of)h(the)f(decimal.)40
+b(The)30 b(.m)g(\014eld)f(is)g(optional.)0 4885 y Fi(1)81
+b Fj(Read)29 b(elemen)m(ts)h(from)f(an)g(ASCI)s(I)f(or)i(binary)e
+(table)h(column)f(\(in)h(the)g(CDU\).)i(These)e(routines)f(return)h
+(the)227 4998 y(v)-5 b(alues)29 b(of)h(the)g(table)g(column)f(arra)m(y)
+h(elemen)m(ts.)41 b(Unde\014ned)28 b(arra)m(y)j(elemen)m(ts)f(will)d(b)
+s(e)i(returned)g(with)g(a)227 5111 y(v)-5 b(alue)29 b(=)f(n)m(ulv)-5
+b(al,)28 b(unless)f(n)m(ulv)-5 b(al)27 b(=)h(0)i(\(or)f(=)f(')h(')g
+(for)g(\013gcvs\))g(in)f(whic)m(h)f(case)j(no)f(c)m(hec)m(king)h(for)e
+(unde\014ned)227 5224 y(v)-5 b(alues)27 b(will)e(b)s(e)i(p)s(erformed.)
+39 b(The)27 b(ANYF)h(parameter)g(is)f(set)h(to)g(true)g(if)f(an)m(y)g
+(of)h(the)g(returned)f(elemen)m(ts)227 5337 y(are)k(unde\014ned.)95
+5601 y Fe(int)47 b(fits_read_col_str)c(/)48 b(ffgcvs)286
+5714 y(\(fitsfile)e(*fptr,)g(int)h(colnum,)e(long)i(firstrow,)e(long)i
+(firstelem,)p eop
+%%Page: 103 111
+103 110 bop 0 299 a Fh(9.6.)72 b(SPECIALIZED)29 b(FITS)g(ASCI)s(I)g
+(AND)i(BINAR)-8 b(Y)32 b(T)-8 b(ABLE)30 b(R)m(OUTINES)933
+b Fj(103)334 555 y Fe(long)47 b(nelements,)e(char)h(*nulstr,)g(>)h
+(char)g(**array,)f(int)g(*anynul,)334 668 y(int)h(*status\))95
+894 y(int)g(fits_read_col_[log,byt,sht)o(,us)o(ht,i)o(nt,u)o(int)o
+(,lng)o(,uln)o(g,)41 b(lnglng,)46 b(flt,)h(dbl,)g(cmp,)f(dblcmp])g(/)
+286 1007 y(ffgcv[l,b,i,ui,k,uk,j,uj,j)o(j,e)o(,d,c)o(,m])286
+1120 y(\(fitsfile)g(*fptr,)g(int)h(colnum,)e(long)i(firstrow,)e(long)i
+(firstelem,)334 1233 y(long)g(nelements,)e(DTYPE)h(nulval,)g(>)h(DTYPE)
+g(*array,)f(int)g(*anynul,)334 1346 y(int)h(*status\))0
+1632 y Fi(2)81 b Fj(Read)39 b(elemen)m(ts)h(and)f(n)m(ull)f(\015ags)i
+(from)f(an)g(ASCI)s(I)g(or)g(binary)f(table)i(column)e(\(in)h(the)h
+(CHDU\).)g(These)227 1745 y(routines)28 b(return)f(the)i(v)-5
+b(alues)28 b(of)h(the)g(table)g(column)e(arra)m(y)j(elemen)m(ts.)40
+b(An)m(y)29 b(unde\014ned)d(arra)m(y)k(elemen)m(ts)227
+1858 y(will)h(ha)m(v)m(e)k(the)f(corresp)s(onding)d(n)m(ullarra)m(y)h
+(elemen)m(t)i(set)g(equal)f(to)h(TR)m(UE.)g(The)f(an)m(yn)m(ul)g
+(parameter)h(is)227 1971 y(set)d(to)g(true)f(if)g(an)m(y)h(of)f(the)h
+(returned)e(elemen)m(ts)i(are)f(unde\014ned.)95 2257
+y Fe(int)47 b(fits_read_colnull_str)42 b(/)48 b(ffgcfs)286
+2370 y(\(fitsfile)e(*fptr,)g(int)h(colnum,)e(long)i(firstrow,)e(long)i
+(firstelem,)334 2483 y(long)g(nelements,)e(>)i(char)g(**array,)e(char)i
+(*nullarray,)e(int)i(*anynul,)334 2596 y(int)g(*status\))95
+2822 y(int)g(fits_read_colnull_[log,byt)o(,sh)o(t,us)o(ht,i)o(nt,)o
+(uint)o(,lng)o(,ul)o(ng,l)o(ngln)o(g,f)o(lt,d)o(bl,c)o(mp,)o(dblc)o
+(mp])41 b(/)286 2935 y(ffgcf[l,b,i,ui,k,uk,j,uj,j)o(j,e)o(,d,c)o(,m])
+286 3048 y(\(fitsfile)46 b(*fptr,)g(int)h(colnum,)e(long)i(firstrow,)
+334 3161 y(long)g(firstelem,)e(long)h(nelements,)f(>)j(DTYPE)e(*array,)
+334 3274 y(char)h(*nullarray,)d(int)j(*anynul,)f(int)h(*status\))0
+3560 y Fi(3)81 b Fj(Read)24 b(an)g(arbitrary)f(data)i(subsection)e
+(from)h(an)g(N-dimensional)e(arra)m(y)j(in)e(a)h(binary)f(table)h(v)m
+(ector)i(column.)227 3673 y(Unde\014ned)21 b(pixels)g(in)g(the)i(arra)m
+(y)g(will)d(b)s(e)i(set)h(equal)g(to)g(the)g(v)-5 b(alue)22
+b(of)h('n)m(ulv)-5 b(al',)23 b(unless)e(n)m(ulv)-5 b(al=0)21
+b(in)g(whic)m(h)227 3786 y(case)37 b(no)e(testing)g(for)g(unde\014ned)e
+(pixels)g(will)g(b)s(e)i(p)s(erformed.)53 b(The)35 b(\014rst)g(and)f
+(last)h(ro)m(ws)h(in)e(the)h(table)227 3899 y(to)30 b(b)s(e)e(read)h
+(are)g(sp)s(eci\014ed)f(b)m(y)h(fpixel\(naxis+1\))d(and)j
+(lpixel\(naxis+1\),)e(and)h(hence)h(are)h(treated)g(as)f(the)227
+4012 y(next)38 b(higher)e(dimension)f(of)j(the)f(FITS)g(N-dimensional)e
+(arra)m(y)-8 b(.)63 b(The)37 b(INC)h(parameter)g(sp)s(eci\014es)e(the)
+227 4125 y(sampling)29 b(in)m(terv)-5 b(al)29 b(in)g(eac)m(h)j
+(dimension)c(b)s(et)m(w)m(een)j(the)f(data)h(elemen)m(ts)g(that)g(will)
+d(b)s(e)h(returned.)95 4411 y Fe(int)47 b(fits_read_subset_[byt,)42
+b(sht,)47 b(usht,)f(int,)h(uint,)f(lng,)h(ulng,)f(lnglng,)g(flt,)h
+(dbl])f(/)286 4524 y(ffgsv[b,i,ui,k,uk,j,uj,jj,)o(e,d)o(])286
+4637 y(\(fitsfile)g(*fptr,)g(int)h(colnum,)e(int)i(naxis,)f(long)h
+(*naxes,)f(long)h(*fpixel,)334 4750 y(long)g(*lpixel,)e(long)i(*inc,)f
+(DTYPE)h(nulval,)e(>)j(DTYPE)e(*array,)g(int)h(*anynul,)334
+4863 y(int)g(*status\))0 5149 y Fi(4)81 b Fj(Read)24
+b(an)g(arbitrary)f(data)i(subsection)e(from)h(an)g(N-dimensional)e
+(arra)m(y)j(in)e(a)h(binary)f(table)h(v)m(ector)i(column.)227
+5262 y(An)m(y)34 b(Unde\014ned)e(pixels)g(in)h(the)g(arra)m(y)i(will)c
+(ha)m(v)m(e)k(the)f(corresp)s(onding)d('n)m(ullarra)m(y')i(elemen)m(t)h
+(set)g(equal)227 5375 y(to)40 b(TR)m(UE.)e(The)h(\014rst)e(and)h(last)h
+(ro)m(ws)f(in)g(the)g(table)h(to)g(b)s(e)f(read)h(are)g(sp)s(eci\014ed)
+d(b)m(y)j(fpixel\(naxis+1\))227 5488 y(and)i(lpixel\(naxis+1\),)i(and)e
+(hence)h(are)g(treated)g(as)g(the)g(next)g(higher)f(dimension)e(of)j
+(the)g(FITS)f(N-)227 5601 y(dimensional)f(arra)m(y)-8
+b(.)78 b(The)41 b(INC)h(parameter)h(sp)s(eci\014es)e(the)i(sampling)d
+(in)m(terv)-5 b(al)42 b(in)f(eac)m(h)j(dimension)227
+5714 y(b)s(et)m(w)m(een)31 b(the)g(data)g(elemen)m(ts)g(that)g(will)c
+(b)s(e)j(returned.)p eop
+%%Page: 104 112
+104 111 bop 0 299 a Fj(104)958 b Fh(CHAPTER)30 b(9.)112
+b(SPECIALIZED)28 b(CFITSIO)h(INTERF)-10 b(A)m(CE)30 b(R)m(OUTINES)95
+555 y Fe(int)47 b(fits_read_subsetnull_[byt,)41 b(sht,)47
+b(usht,)f(int,)h(uint,)f(lng,)h(ulng,)f(lnglng,)g(flt,)g(dbl])h(/)286
+668 y(ffgsf[b,i,ui,k,uk,j,uj,jj,)o(e,d)o(])286 781 y(\(fitsfile)f
+(*fptr,)g(int)h(colnum,)e(int)i(naxis,)f(long)h(*naxes,)334
+894 y(long)g(*fpixel,)e(long)i(*lpixel,)e(long)i(*inc,)f(>)i(DTYPE)e
+(*array,)334 1007 y(char)h(*nullarray,)d(int)j(*anynul,)f(int)h
+(*status\))0 1227 y Fi(5)81 b Fj(Read)35 b(bit)f(v)-5
+b(alues)34 b(from)h(a)g(b)m(yte)h(\('B'\))g(or)f(bit)f(\(`X`\))i(table)
+f(column)f(\(in)g(the)h(CDU\).)h(Larra)m(y)g(is)e(an)g(arra)m(y)227
+1340 y(of)g(logical)f(v)-5 b(alues)33 b(corresp)s(onding)f(to)i(the)g
+(sequence)g(of)g(bits)f(to)h(b)s(e)f(read.)51 b(If)33
+b(larra)m(y)g(is)g(true)g(then)h(the)227 1453 y(corresp)s(onding)h(bit)
+h(w)m(as)h(set)h(to)f(1,)j(otherwise)c(the)h(bit)f(w)m(as)h(set)h(to)f
+(0.)61 b(The)37 b('X')g(column)f(in)f(a)j(FITS)227 1566
+y(table)d(is)e(alw)m(a)m(ys)i(padded)f(out)h(to)g(a)g(m)m(ultiple)d(of)
+j(8)g(bits)e(where)h(the)h(bit)f(arra)m(y)h(starts)g(with)e(the)i(most)
+227 1678 y(signi\014can)m(t)h(bit)f(of)i(the)g(b)m(yte)g(and)f(w)m
+(orks)g(do)m(wn)h(to)m(w)m(ards)g(the)g(1's)g(bit.)58
+b(F)-8 b(or)37 b(example,)h(a)f('4X')h(arra)m(y)-8 b(,)227
+1791 y(with)32 b(the)i(\014rst)e(bit)h(=)g(1)h(and)e(the)i(remaining)d
+(3)j(bits)e(=)h(0)h(is)e(equiv)-5 b(alen)m(t)33 b(to)h(the)g(8-bit)f
+(unsigned)e(b)m(yte)227 1904 y(v)-5 b(alue)30 b(of)g(128.)42
+b(Note)31 b(that)g(in)d(the)j(case)g(of)f('X')g(columns,)f(CFITSIO)g
+(can)h(read)g(all)f(8)h(bits)f(of)h(eac)m(h)h(b)m(yte)227
+2017 y(whether)h(they)h(are)g(formally)e(v)-5 b(alid)31
+b(or)h(not.)48 b(Th)m(us)31 b(if)h(the)g(column)g(is)f(de\014ned)g(as)i
+('4X',)h(and)e(one)h(calls)227 2130 y(\013gcx)d(with)e(\014rstbit=1)f
+(and)i(n)m(bits=8,)f(then)h(all)f(8)h(bits)f(will)e(b)s(e)j(read)g
+(from)f(the)h(\014rst)g(b)m(yte)g(\(as)h(opp)s(osed)227
+2243 y(to)39 b(reading)e(the)h(\014rst)g(4)g(bits)f(from)h(the)g
+(\014rst)f(ro)m(w)h(and)g(then)f(the)i(\014rst)e(4)h(bits)f(from)h(the)
+g(next)g(ro)m(w\),)227 2356 y(ev)m(en)g(though)f(the)g(last)h(4)f(bits)
+f(of)i(eac)m(h)g(b)m(yte)g(are)f(formally)f(not)i(de\014ned.)60
+b(It)37 b(should)e(also)i(b)s(e)g(noted)227 2469 y(that)f(it)e(is)h
+(more)g(e\016cien)m(t)g(to)h(read)f('X')h(columns)d(an)i(en)m(tire)g(b)
+m(yte)h(at)g(a)f(time,)h(instead)e(of)i(bit)e(b)m(y)h(bit.)227
+2582 y(An)m(y)29 b(of)g(the)h(CFITSIO)d(routines)h(that)h(read)g
+(columns)f(\(e.g.)42 b(\014ts)p 2520 2582 28 4 v 32 w(read)p
+2724 2582 V 33 w(col)p 2868 2582 V 33 w(b)m(yt\))29 b(ma)m(y)h(b)s(e)e
+(used)g(for)h(this)227 2695 y(purp)s(ose.)60 b(These)36
+b(routines)h(will)d(in)m(terpret)j('X')g(columns)f(as)h(though)g(they)h
+(w)m(ere)f('B')h(columns)e(\(e.g.,)227 2808 y('8X')c(is)d(equiv)-5
+b(alen)m(t)30 b(to)h('1B',)h(and)e('16X')i(is)d(equiv)-5
+b(alen)m(t)30 b(to)h('2B'\).)95 3027 y Fe(int)47 b(fits_read_col_bit)c
+(/)48 b(ffgcx)286 3140 y(\(fitsfile)e(*fptr,)g(int)h(colnum,)e(long)i
+(firstrow,)e(long)i(firstbit,)334 3253 y(long)g(nbits,)f(>)h(char)g
+(*larray,)e(int)i(*status\))0 3473 y Fi(6)81 b Fj(Read)31
+b(an)m(y)h(consecutiv)m(e)h(set)f(of)g(bits)e(from)i(an)f('X')h(or)g
+('B')h(column)d(and)h(in)m(terpret)g(them)h(as)f(an)h(unsigned)227
+3586 y(n-bit)g(in)m(teger.)47 b(n)m(bits)32 b(m)m(ust)g(b)s(e)g(less)g
+(than)h(16)g(or)g(32)g(in)e(\013gcxui)i(and)e(\013gcxuk,)j(resp)s
+(ectiv)m(ely)-8 b(.)47 b(If)32 b(nro)m(ws)227 3699 y(is)27
+b(greater)i(than)f(1,)h(then)e(the)h(same)h(set)f(of)g(bits)f(will)e(b)
+s(e)i(read)h(from)f(eac)m(h)i(ro)m(w,)g(starting)f(with)e(\014rstro)m
+(w.)227 3812 y(The)k(bits)f(are)i(n)m(um)m(b)s(ered)e(with)g(1)i(=)f
+(the)h(most)f(signi\014can)m(t)g(bit)f(of)i(the)f(\014rst)g(elemen)m(t)
+h(of)f(the)h(column.)95 4032 y Fe(int)47 b(fits_read_col_bit_[usht,)42
+b(uint])k(/)h(ffgcx[ui,uk])286 4145 y(\(fitsfile)f(*fptr,)g(int)h
+(colnum,)e(long)i(firstrow,)e(long,)i(nrows,)334 4258
+y(long)g(firstbit,)e(long)i(nbits,)f(>)h(DTYPE)g(*array,)e(int)i
+(*status\))0 4478 y Fi(7)81 b Fj(Return)27 b(the)i(descriptor)e(for)i
+(a)g(v)-5 b(ariable)27 b(length)h(column)f(in)h(a)h(binary)d(table.)40
+b(The)28 b(descriptor)g(consists)g(of)227 4591 y(2)k(in)m(teger)f
+(parameters:)42 b(the)31 b(n)m(um)m(b)s(er)f(of)h(elemen)m(ts)h(in)d
+(the)i(arra)m(y)h(and)e(the)h(starting)g(o\013set)h(relativ)m(e)f(to)
+227 4704 y(the)d(start)f(of)g(the)h(heap.)39 b(The)27
+b(\014rst)f(routine)g(returns)g(a)h(single)f(descriptor)g(whereas)h
+(the)g(second)g(routine)227 4816 y(returns)i(the)i(descriptors)e(for)h
+(a)h(range)g(of)f(ro)m(ws)h(in)e(the)h(table.)95 5036
+y Fe(int)47 b(fits_read_descript)c(/)48 b(ffgdes)286
+5149 y(\(fitsfile)e(*fptr,)g(int)h(colnum,)e(long)i(rownum,)f(>)h(long)
+g(*repeat,)525 5262 y(long)g(*offset,)e(int)i(*status\))95
+5488 y(int)g(fits_read_descripts)c(/)k(ffgdess)286 5601
+y(\(fitsfile)f(*fptr,)g(int)h(colnum,)e(long)i(firstrow,)e(long)i
+(nrows)f(>)i(long)e(*repeat,)525 5714 y(long)h(*offset,)e(int)i
+(*status\))p eop
+%%Page: 105 113
+105 112 bop 0 1225 a Fg(Chapter)65 b(10)0 1687 y Fm(Extended)77
+b(File)g(Name)g(Syn)-6 b(tax)0 2216 y Ff(10.1)136 b(Ov)l(erview)0
+2466 y Fj(CFITSIO)30 b(supp)s(orts)f(an)j(extended)f(syn)m(tax)h(when)f
+(sp)s(ecifying)e(the)j(name)f(of)h(the)g(data)g(\014le)e(to)i(b)s(e)f
+(op)s(ened)g(or)0 2579 y(created)g(that)g(includes)d(the)j(follo)m
+(wing)e(features:)136 2813 y Fc(\017)46 b Fj(CFITSIO)40
+b(can)i(read)f(IRAF)h(format)g(images)f(whic)m(h)f(ha)m(v)m(e)j(header)
+e(\014le)g(names)g(that)h(end)f(with)f(the)227 2926 y('.imh')d
+(extension,)i(as)f(w)m(ell)e(as)i(reading)e(and)h(writing)e(FITS)i
+(\014les,)h(This)e(feature)i(is)e(implemen)m(ted)g(in)227
+3039 y(CFITSIO)29 b(b)m(y)i(\014rst)e(con)m(v)m(erting)j(the)e(IRAF)h
+(image)g(in)m(to)f(a)h(temp)s(orary)f(FITS)g(format)h(\014le)e(in)g
+(memory)-8 b(,)227 3152 y(then)35 b(op)s(ening)e(the)i(FITS)f(\014le.)
+53 b(An)m(y)35 b(of)g(the)g(usual)e(CFITSIO)h(routines)f(then)i(ma)m(y)
+g(b)s(e)f(used)g(to)i(read)227 3265 y(the)31 b(image)f(header)g(or)h
+(data.)41 b(Similarly)-8 b(,)27 b(ra)m(w)j(binary)f(data)i(arra)m(ys)f
+(can)h(b)s(e)f(read)g(b)m(y)g(con)m(v)m(erting)h(them)227
+3378 y(on)g(the)f(\015y)g(in)m(to)g(virtual)f(FITS)h(images.)136
+3557 y Fc(\017)46 b Fj(FITS)37 b(\014les)g(on)g(the)h(in)m(ternet)g
+(can)g(b)s(e)f(read)g(\(and)g(sometimes)h(written\))f(using)f(the)i
+(FTP)-8 b(,)38 b(HTTP)-8 b(,)38 b(or)227 3670 y(R)m(OOT)30
+b(proto)s(cols.)136 3849 y Fc(\017)46 b Fj(FITS)30 b(\014les)f(can)i(b)
+s(e)f(pip)s(ed)e(b)s(et)m(w)m(een)j(tasks)f(on)h(the)f(stdin)f(and)h
+(stdout)g(streams.)136 4028 y Fc(\017)46 b Fj(FITS)36
+b(\014les)g(can)h(b)s(e)f(read)h(and)f(written)g(in)g(shared)g(memory)
+-8 b(.)60 b(This)35 b(can)i(p)s(oten)m(tially)f(ac)m(hiev)m(e)i(b)s
+(etter)227 4141 y(data)26 b(I/O)e(p)s(erformance)g(compared)h(to)h
+(reading)e(and)g(writing)e(the)j(same)h(FITS)e(\014les)f(on)i(magnetic)
+g(disk.)136 4320 y Fc(\017)46 b Fj(Compressed)30 b(FITS)f(\014les)h(in)
+f(gzip)h(or)g(Unix)f(COMPRESS)g(format)h(can)h(b)s(e)f(directly)f
+(read.)136 4499 y Fc(\017)46 b Fj(Output)28 b(FITS)h(\014les)f(can)h(b)
+s(e)g(written)f(directly)g(in)f(compressed)i(gzip)g(format,)h(th)m(us)e
+(sa)m(ving)h(disk)f(space.)136 4678 y Fc(\017)46 b Fj(FITS)26
+b(table)g(columns)f(can)i(b)s(e)f(created,)i(mo)s(di\014ed,)e(or)g
+(deleted)g('on-the-\015y')h(as)g(the)g(table)f(is)f(op)s(ened)h(b)m(y)
+227 4791 y(CFITSIO.)32 b(This)g(creates)j(a)e(virtual)f(FITS)h(\014le)f
+(con)m(taining)h(the)h(mo)s(di\014cations)d(that)j(is)f(then)g(op)s
+(ened)227 4904 y(b)m(y)e(the)f(application)f(program.)136
+5083 y Fc(\017)46 b Fj(T)-8 b(able)28 b(ro)m(ws)f(ma)m(y)i(b)s(e)e
+(selected,)i(or)f(\014ltered)f(out,)h(on)g(the)g(\015y)f(when)g(the)h
+(table)g(is)f(op)s(ened)g(b)m(y)g(CFITSIO,)227 5196 y(based)22
+b(on)f(an)g(user-sp)s(eci\014ed)f(expression.)37 b(Only)20
+b(ro)m(ws)h(for)g(whic)m(h)g(the)h(expression)e(ev)-5
+b(aluates)22 b(to)g('TR)m(UE')227 5309 y(are)31 b(retained)f(in)f(the)h
+(cop)m(y)i(of)e(the)h(table)f(that)h(is)e(op)s(ened)h(b)m(y)g(the)h
+(application)d(program.)136 5488 y Fc(\017)46 b Fj(Histogram)27
+b(images)g(ma)m(y)g(b)s(e)f(created)h(on)f(the)h(\015y)f(b)m(y)g
+(binning)e(the)i(v)-5 b(alues)26 b(in)f(table)i(columns,)f(resulting)
+227 5601 y(in)35 b(a)h(virtual)f(N-dimensional)e(FITS)j(image.)58
+b(The)35 b(application)f(program)i(then)g(only)f(sees)h(the)h(FITS)227
+5714 y(image)31 b(\(in)e(the)i(primary)d(arra)m(y\))k(instead)d(of)i
+(the)f(original)f(FITS)g(table.)1882 5942 y(105)p eop
+%%Page: 106 114
+106 113 bop 0 299 a Fj(106)1528 b Fh(CHAPTER)29 b(10.)113
+b(EXTENDED)30 b(FILE)h(NAME)f(SYNT)-8 b(AX)0 555 y Fj(The)39
+b(latter)h(3)g(table)g(\014ltering)e(features)i(in)e(particular)g(add)h
+(v)m(ery)h(p)s(o)m(w)m(erful)e(data)j(pro)s(cessing)d(capabilities)0
+668 y(directly)31 b(in)m(to)h(CFITSIO,)f(and)h(hence)h(in)m(to)f(ev)m
+(ery)h(task)g(that)g(uses)f(CFITSIO)f(to)i(read)f(or)h(write)e(FITS)h
+(\014les.)0 781 y(F)-8 b(or)29 b(example,)f(these)g(features)h
+(transform)e(a)h(v)m(ery)g(simple)e(program)i(that)g(just)g(copies)f
+(an)h(input)e(FITS)h(\014le)g(to)0 894 y(a)d(new)f(output)h(\014le)f
+(\(lik)m(e)g(the)h(`\014tscop)m(y')h(program)e(that)i(is)d(distributed)
+f(with)i(CFITSIO\))f(in)m(to)i(a)g(m)m(ultipurp)s(ose)0
+1007 y(FITS)33 b(\014le)f(pro)s(cessing)g(to)s(ol.)50
+b(By)33 b(app)s(ending)e(fairly)h(simple)f(quali\014ers)g(on)m(to)j
+(the)g(name)f(of)h(the)f(input)f(FITS)0 1120 y(\014le,)44
+b(the)e(user)f(can)h(p)s(erform)e(quite)h(complex)h(table)f(editing)g
+(op)s(erations)g(\(e.g.,)46 b(create)d(new)e(columns,)j(or)0
+1233 y(\014lter)31 b(out)i(ro)m(ws)f(in)f(a)h(table\))h(or)f(create)i
+(FITS)d(images)i(b)m(y)f(binning)d(or)j(histogramming)f(the)i(v)-5
+b(alues)31 b(in)g(table)0 1346 y(columns.)46 b(In)32
+b(addition,)f(these)i(functions)e(ha)m(v)m(e)j(b)s(een)e(co)s(ded)g
+(using)f(new)h(state-of-the)j(art)e(algorithms)e(that)0
+1458 y(are,)g(in)e(some)i(cases,)g(10)h(-)e(100)i(times)e(faster)h
+(than)f(previous)f(widely)f(used)h(implemen)m(tations.)0
+1619 y(Before)34 b(describing)d(the)j(complete)g(syn)m(tax)g(for)f(the)
+h(extended)f(FITS)g(\014le)f(names)h(in)f(the)i(next)g(section,)g(here)
+0 1732 y(are)d(a)g(few)f(examples)g(of)g(FITS)g(\014le)f(names)i(that)f
+(giv)m(e)h(a)g(quic)m(k)f(o)m(v)m(erview)h(of)g(the)f(allo)m(w)m(ed)g
+(syn)m(tax:)136 1984 y Fc(\017)46 b Fe(myfile.fits)p
+Fj(:)38 b(the)30 b(simplest)f(case)i(of)g(a)g(FITS)e(\014le)h(on)g
+(disk)f(in)g(the)i(curren)m(t)f(directory)-8 b(.)136
+2169 y Fc(\017)46 b Fe(myfile.imh)p Fj(:)i(op)s(ens)34
+b(an)h(IRAF)g(format)g(image)h(\014le)e(and)g(con)m(v)m(erts)j(it)d(on)
+h(the)g(\015y)g(in)m(to)g(a)g(temp)s(orary)227 2282 y(FITS)30
+b(format)h(image)f(in)f(memory)i(whic)m(h)e(can)h(then)g(b)s(e)g(read)g
+(with)f(an)m(y)i(other)g(CFITSIO)e(routine.)136 2467
+y Fc(\017)46 b Fe(rawfile.dat[i512,512])p Fj(:)35 b(op)s(ens)30
+b(a)g(ra)m(w)h(binary)d(data)j(arra)m(y)g(\(a)g(512)g(x)f(512)i(short)e
+(in)m(teger)g(arra)m(y)h(in)227 2580 y(this)h(case\))j(and)d(con)m(v)m
+(erts)j(it)d(on)h(the)g(\015y)g(in)m(to)g(a)g(temp)s(orary)g(FITS)f
+(format)h(image)h(in)d(memory)i(whic)m(h)227 2693 y(can)e(then)f(b)s(e)
+g(read)g(with)f(an)m(y)i(other)f(CFITSIO)f(routine.)136
+2878 y Fc(\017)46 b Fe(myfile.fits.gz)p Fj(:)d(if)32
+b(this)g(is)g(the)h(name)g(of)h(a)f(new)g(output)g(\014le,)g(the)g
+('.gz')i(su\016x)d(will)e(cause)k(it)f(to)h(b)s(e)227
+2991 y(compressed)c(in)f(gzip)h(format)h(when)e(it)h(is)g(written)f(to)
+i(disk.)136 3176 y Fc(\017)46 b Fe(myfile.fits.gz[events,)c(2])p
+Fj(:)35 b(op)s(ens)20 b(and)f(uncompresses)g(the)i(gzipp)s(ed)e(\014le)
+g(m)m(y\014le.\014ts)h(then)g(mo)m(v)m(es)227 3289 y(to)31
+b(the)g(extension)f(with)f(the)i(k)m(eyw)m(ords)f(EXTNAME)h(=)f
+('EVENTS')g(and)g(EXTVER)g(=)g(2.)136 3474 y Fc(\017)46
+b Fe(-)p Fj(:)40 b(a)30 b(dash)f(\(min)m(us)f(sign\))h(signi\014es)f
+(that)i(the)g(input)e(\014le)g(is)h(to)h(b)s(e)f(read)h(from)f(the)h
+(stdin)e(\014le)h(stream,)h(or)227 3587 y(that)h(the)g(output)f(\014le)
+f(is)h(to)h(b)s(e)f(written)f(to)i(the)g(stdout)f(stream.)136
+3772 y Fc(\017)46 b Fe(ftp://legacy.gsfc.nasa.go)o(v/te)o(st/v)o(ela)o
+(.fit)o(s)p Fj(:)k(FITS)37 b(\014les)g(in)g(an)m(y)i(ftp)e(arc)m(hiv)m
+(e)i(site)f(on)g(the)227 3885 y(in)m(ternet)30 b(ma)m(y)h(b)s(e)f
+(directly)f(op)s(ened)h(with)f(read-only)h(access.)136
+4070 y Fc(\017)46 b Fe(http://legacy.gsfc.nasa.g)o(ov/s)o(oftw)o(are)o
+(/tes)o(t.fi)o(ts)p Fj(:)33 b(an)m(y)27 b(v)-5 b(alid)26
+b(URL)h(to)h(a)g(FITS)e(\014le)h(on)g(the)227 4183 y(W)-8
+b(eb)31 b(ma)m(y)g(b)s(e)f(op)s(ened)g(with)f(read-only)g(access.)136
+4368 y Fc(\017)46 b Fe(root://legacy.gsfc.nasa.g)o(ov/t)o(est/)o(vel)o
+(a.fi)o(ts)p Fj(:)e(similar)33 b(to)j(ftp)f(access)i(except)f(that)g
+(it)f(pro-)227 4481 y(vides)29 b(write)h(as)g(w)m(ell)f(as)i(read)f
+(access)h(to)g(the)f(\014les)g(across)g(the)h(net)m(w)m(ork.)41
+b(This)28 b(uses)i(the)h(ro)s(ot)f(proto)s(col)227 4594
+y(dev)m(elop)s(ed)g(at)h(CERN.)136 4779 y Fc(\017)46
+b Fe(shmem://h2[events])p Fj(:)j(op)s(ens)36 b(the)i(FITS)e(\014le)g
+(in)g(a)h(shared)f(memory)h(segmen)m(t)h(and)f(mo)m(v)m(es)h(to)g(the)
+227 4892 y(EVENTS)30 b(extension.)136 5077 y Fc(\017)46
+b Fe(mem://)p Fj(:)65 b(creates)44 b(a)g(scratc)m(h)g(output)f(\014le)f
+(in)g(core)i(computer)f(memory)-8 b(.)79 b(The)43 b(resulting)e
+('\014le')i(will)227 5190 y(disapp)s(ear)24 b(when)g(the)i(program)f
+(exits,)h(so)g(this)e(is)h(mainly)e(useful)h(for)h(testing)h(purp)s
+(oses)d(when)i(one)g(do)s(es)227 5303 y(not)31 b(w)m(an)m(t)g(a)g(p)s
+(ermanen)m(t)f(cop)m(y)h(of)f(the)h(output)f(\014le.)136
+5488 y Fc(\017)46 b Fe(myfile.fits[3;)e(Images\(10\)])p
+Fj(:)c(op)s(ens)30 b(a)i(cop)m(y)g(of)g(the)g(image)f(con)m(tained)h
+(in)e(the)i(10th)g(ro)m(w)f(of)h(the)227 5601 y('Images')38
+b(column)e(in)g(the)h(binary)e(table)i(in)e(the)i(3th)g(extension)g(of)
+g(the)g(FITS)f(\014le.)59 b(The)37 b(virtual)e(\014le)227
+5714 y(that)c(is)f(op)s(ened)f(b)m(y)i(the)f(application)f(just)h(con)m
+(tains)g(this)f(single)g(image)i(in)e(the)i(primary)d(arra)m(y)-8
+b(.)p eop
+%%Page: 107 115
+107 114 bop 0 299 a Fh(10.1.)73 b(O)m(VER)-10 b(VIEW)2995
+b Fj(107)136 555 y Fc(\017)46 b Fe(myfile.fits[1:512:2,)d(1:512:2])p
+Fj(:)c(op)s(ens)30 b(a)h(section)g(of)h(the)f(input)e(image)i(ranging)f
+(from)g(the)h(1st)227 668 y(to)k(the)f(512th)h(pixel)d(in)h(X)h(and)g
+(Y,)g(and)f(selects)i(ev)m(ery)f(second)g(pixel)f(in)f(b)s(oth)h
+(dimensions,)g(resulting)227 781 y(in)c(a)i(256)h(x)e(256)i(pixel)c
+(input)h(image)h(in)g(this)f(case.)136 981 y Fc(\017)46
+b Fe(myfile.fits[EVENTS][col)c(Rad)47 b(=)g(sqrt\(X**2)e(+)j(Y**2\)])p
+Fj(:)36 b(creates)27 b(and)d(op)s(ens)h(a)g(virtual)f(\014le)g(on)227
+1094 y(the)i(\015y)f(that)i(is)e(iden)m(tical)f(to)j(m)m
+(y\014le.\014ts)e(except)h(that)h(it)e(will)e(con)m(tain)j(a)g(new)g
+(column)e(in)h(the)h(EVENTS)227 1207 y(extension)40 b(called)g('Rad')h
+(whose)f(v)-5 b(alue)40 b(is)g(computed)g(using)g(the)g(indicated)f
+(expression)h(whic)m(h)f(is)h(a)227 1320 y(function)29
+b(of)i(the)f(v)-5 b(alues)30 b(in)f(the)i(X)f(and)g(Y)h(columns.)136
+1520 y Fc(\017)46 b Fe(myfile.fits[EVENTS][PHA)c(>)47
+b(5])p Fj(:)41 b(creates)33 b(and)d(op)s(ens)g(a)i(virtual)d(FITS)h
+(\014les)g(that)h(is)f(iden)m(tical)g(to)227 1633 y('m)m
+(y\014le.\014ts')39 b(except)i(that)f(the)f(EVENTS)g(table)g(will)e
+(only)h(con)m(tain)i(the)f(ro)m(ws)h(that)g(ha)m(v)m(e)g(v)-5
+b(alues)39 b(of)227 1746 y(the)34 b(PHA)g(column)f(greater)i(than)e(5.)
+52 b(In)33 b(general,)i(an)m(y)f(arbitrary)f(b)s(o)s(olean)f
+(expression)h(using)f(a)j(C)e(or)227 1859 y(F)-8 b(ortran-lik)m(e)29
+b(syn)m(tax,)g(whic)m(h)e(ma)m(y)i(com)m(bine)f(AND)h(and)f(OR)f(op)s
+(erators,)i(ma)m(y)g(b)s(e)f(used)f(to)i(select)g(ro)m(ws)227
+1972 y(from)h(a)h(table.)136 2172 y Fc(\017)46 b Fe
+(myfile.fits[EVENTS][bin)c(\(X,Y\)=1,2048,4])p Fj(:)34
+b(creates)26 b(a)g(temp)s(orary)f(FITS)g(primary)e(arra)m(y)j(im-)227
+2285 y(age)38 b(whic)m(h)d(is)h(computed)g(on)g(the)h(\015y)f(b)m(y)g
+(binning)d(\(i.e,)39 b(computing)c(the)i(2-dimensional)d(histogram\))
+227 2398 y(of)g(the)f(v)-5 b(alues)33 b(in)f(the)i(X)g(and)e(Y)i
+(columns)e(of)i(the)f(EVENTS)g(extension.)49 b(In)33
+b(this)f(case)j(the)e(X)h(and)f(Y)227 2511 y(co)s(ordinates)g(range)h
+(from)f(1)h(to)g(2048)h(and)e(the)h(image)f(pixel)f(size)h(is)g(4)g
+(units)f(in)g(b)s(oth)h(dimensions,)f(so)227 2624 y(the)f(resulting)d
+(image)j(is)e(512)j(x)e(512)i(pixels)d(in)g(size.)136
+2824 y Fc(\017)46 b Fj(The)31 b(\014nal)f(example)i(com)m(bines)f(man)m
+(y)g(of)h(these)g(feature)g(in)m(to)f(one)h(complex)f(expression)f
+(\(it)i(is)e(brok)m(en)227 2937 y(in)m(to)h(sev)m(eral)f(lines)f(for)h
+(clarit)m(y\):)370 3206 y Fe(ftp://legacy.gsfc.nasa.gov)o(/dat)o(a/s)o
+(ampl)o(e.fi)o(ts.)o(gz[E)o(VENT)o(S])370 3319 y([col)47
+b(phacorr)f(=)h(pha)g(*)h(1.1)f(-)g(0.3][phacorr)e(>=)i(5.0)g(&&)g
+(phacorr)f(<=)h(14.0])370 3432 y([bin)g(\(X,Y\)=32])227
+3701 y Fj(In)37 b(this)g(case,)k(CFITSIO)36 b(\(1\))j(copies)f(and)f
+(uncompresses)g(the)h(FITS)f(\014le)g(from)g(the)h(ftp)f(site)h(on)g
+(the)227 3814 y(legacy)f(mac)m(hine,)h(\(2\))f(mo)m(v)m(es)g(to)g(the)g
+('EVENTS')f(extension,)h(\(3\))g(calculates)g(a)f(new)g(column)f
+(called)227 3927 y('phacorr',)30 b(\(4\))f(selects)g(the)g(ro)m(ws)g
+(in)e(the)i(table)g(that)g(ha)m(v)m(e)h(phacorr)e(in)f(the)i(range)g(5)
+g(to)h(14,)g(and)e(\014nally)227 4040 y(\(5\))35 b(bins)c(the)i
+(remaining)e(ro)m(ws)i(on)h(the)f(X)g(and)g(Y)g(column)f(co)s
+(ordinates,)i(using)d(a)j(pixel)d(size)i(=)g(32)h(to)227
+4153 y(create)d(a)f(2D)g(image.)41 b(All)28 b(this)g(pro)s(cessing)g
+(is)h(completely)g(transparen)m(t)g(to)i(the)e(application)f(program,)
+227 4266 y(whic)m(h)h(simply)f(sees)j(the)g(\014nal)e(2-D)i(image)g(in)
+e(the)h(primary)f(arra)m(y)i(of)f(the)h(op)s(ened)f(\014le.)0
+4538 y(The)c(full)f(extended)i(CFITSIO)e(FITS)h(\014le)g(name)h(can)g
+(con)m(tain)g(sev)m(eral)g(di\013eren)m(t)g(comp)s(onen)m(ts)g(dep)s
+(ending)d(on)0 4651 y(the)31 b(con)m(text.)42 b(These)30
+b(comp)s(onen)m(ts)h(are)g(describ)s(ed)d(in)h(the)h(follo)m(wing)f
+(sections:)0 4924 y Fe(When)47 b(creating)e(a)j(new)f(file:)143
+5036 y(filetype://BaseFilename\(t)o(empl)o(ate)o(Name)o(\)[co)o(mpr)o
+(ess])0 5262 y(When)g(opening)e(an)j(existing)d(primary)h(array)g(or)i
+(image)e(HDU:)143 5375 y(filetype://BaseFilename\(o)o(utNa)o(me\))o
+([HDU)o(loca)o(tio)o(n][I)o(mage)o(Sec)o(tion)o(])0 5601
+y(When)h(opening)e(an)j(existing)d(table)i(HDU:)143 5714
+y(filetype://BaseFilename\(o)o(utNa)o(me\))o([HDU)o(loca)o(tio)o(n][c)o
+(olFi)o(lte)o(r][r)o(owFi)o(lte)o(r][b)o(inSp)o(ec])p
+eop
+%%Page: 108 116
+108 115 bop 0 299 a Fj(108)1528 b Fh(CHAPTER)29 b(10.)113
+b(EXTENDED)30 b(FILE)h(NAME)f(SYNT)-8 b(AX)0 555 y Fj(The)41
+b(\014let)m(yp)s(e,)j(BaseFilename,)h(outName,)g(HDUlo)s(cation,)g(and)
+c(ImageSection)h(comp)s(onen)m(ts,)j(if)c(presen)m(t,)0
+668 y(m)m(ust)30 b(b)s(e)g(giv)m(en)h(in)e(that)i(order,)g(but)f(the)g
+(colFilter,)g(ro)m(wFilter,)h(and)e(binSp)s(ec)g(sp)s(eci\014ers)f(ma)m
+(y)k(follo)m(w)d(in)h(an)m(y)0 781 y(order.)39 b(Regardless)28
+b(of)h(the)f(order,)g(ho)m(w)m(ev)m(er,)i(the)f(colFilter)e(sp)s
+(eci\014er,)g(if)g(presen)m(t,)i(will)d(b)s(e)h(pro)s(cessed)h(\014rst)
+f(b)m(y)0 894 y(CFITSIO,)i(follo)m(w)m(ed)h(b)m(y)g(the)h(ro)m(wFilter)
+f(sp)s(eci\014er,)f(and)g(\014nally)g(b)m(y)h(the)g(binSp)s(ec)e(sp)s
+(eci\014er.)0 1221 y Ff(10.2)136 b(Filet)l(yp)t(e)0 1471
+y Fj(The)37 b(t)m(yp)s(e)g(of)g(\014le)f(determines)g(the)h(medium)e
+(on)i(whic)m(h)f(the)h(\014le)f(is)h(lo)s(cated)g(\(e.g.,)j(disk)c(or)h
+(net)m(w)m(ork\))h(and,)0 1584 y(hence,)f(whic)m(h)d(in)m(ternal)g
+(device)h(driv)m(er)f(is)g(used)g(b)m(y)h(CFITSIO)f(to)i(read)f(and/or)
+g(write)f(the)h(\014le.)55 b(Curren)m(tly)0 1697 y(supp)s(orted)29
+b(t)m(yp)s(es)h(are)382 1913 y Fe(file://)93 b(-)48 b(file)e(on)i
+(local)e(magnetic)g(disk)g(\(default\))382 2026 y(ftp://)141
+b(-)48 b(a)f(readonly)f(file)g(accessed)g(with)h(the)g(anonymous)e(FTP)
+i(protocol.)907 2139 y(It)g(also)g(supports)93 b
+(ftp://username:password@)o(host)o(nam)o(e/..)o(.)907
+2252 y(for)47 b(accessing)e(password-protected)e(ftp)k(sites.)382
+2365 y(http://)93 b(-)48 b(a)f(readonly)f(file)g(accessed)g(with)h(the)
+g(HTTP)f(protocol.)93 b(It)907 2478 y(does)46 b(not)95
+b(support)46 b(username:password)d(like)k(the)g(ftp)f(driver.)907
+2591 y(Proxy)g(HTTP)h(survers)f(are)h(supported)e(using)h(the)h
+(http_proxy)907 2704 y(environment)e(variable.)382 2817
+y(root://)93 b(-)48 b(uses)e(the)h(CERN)g(root)g(protocol)e(for)i
+(writing)f(as)h(well)g(as)907 2930 y(reading)f(files)g(over)h(the)g
+(network.)382 3042 y(shmem://)e(-)j(opens)e(or)h(creates)f(a)i(file)e
+(which)h(persists)e(in)i(the)g(computer's)907 3155 y(shared)f(memory.)
+382 3268 y(mem://)141 b(-)48 b(opens)e(a)i(temporary)d(file)i(in)g
+(core)f(memory.)94 b(The)47 b(file)907 3381 y(disappears)e(when)h(the)h
+(program)f(exits)h(so)g(this)f(is)i(mainly)907 3494 y(useful)e(for)h
+(test)f(purposes)g(when)h(a)g(permanent)e(output)h(file)907
+3607 y(is)h(not)g(desired.)0 3824 y Fj(If)35 b(the)h(\014let)m(yp)s(e)f
+(is)f(not)i(sp)s(eci\014ed,)g(then)f(t)m(yp)s(e)h(\014le://)g(is)e
+(assumed.)56 b(The)35 b(double)f(slashes)h('//')i(are)f(optional)0
+3937 y(and)30 b(ma)m(y)h(b)s(e)e(omitted)i(in)e(most)i(cases.)0
+4220 y Fd(10.2.1)113 b(Notes)36 b(ab)s(out)j(HTTP)d(pro)m(xy)i(serv)m
+(ers)0 4439 y Fj(A)32 b(pro)m(xy)g(HTTP)f(serv)m(er)h(ma)m(y)h(b)s(e)e
+(used)g(b)m(y)h(de\014ning)e(the)i(address)f(\(URL\))i(and)e(p)s(ort)g
+(n)m(um)m(b)s(er)g(of)h(the)g(pro)m(xy)0 4552 y(serv)m(er)f(with)e(the)
+h(h)m(ttp)p 801 4552 28 4 v 33 w(pro)m(xy)g(en)m(vironmen)m(t)g(v)-5
+b(ariable.)40 b(F)-8 b(or)31 b(example)191 4769 y Fe(setenv)46
+b(http_proxy)f(http://heasarc.gsfc.nasa)o(.gov)o(:312)o(8)0
+4985 y Fj(will)35 b(cause)j(CFITSIO)f(to)h(use)g(p)s(ort)f(3128)i(on)f
+(the)g(heasarc)g(pro)m(xy)g(serv)m(er)g(whenev)m(er)g(reading)f(a)h
+(FITS)f(\014le)0 5098 y(with)29 b(HTTP)-8 b(.)0 5382
+y Fd(10.2.2)113 b(Notes)36 b(ab)s(out)j(the)e(ro)s(ot)g(\014let)m(yp)s
+(e)0 5601 y Fj(The)20 b(original)g(ro)s(otd)g(serv)m(er)h(can)h(b)s(e)e
+(obtained)g(from:)36 b Fe(ftp://root.cern.ch/root)o(/roo)o(td.t)o(ar.)o
+(gz)15 b Fj(but,)22 b(for)0 5714 y(it)32 b(to)i(w)m(ork)f(correctly)g
+(with)e(CFITSIO)h(one)h(has)f(to)i(use)e(a)i(mo)s(di\014ed)c(v)m
+(ersion)j(whic)m(h)e(supp)s(orts)g(a)i(command)p eop
+%%Page: 109 117
+109 116 bop 0 299 a Fh(10.2.)73 b(FILETYPE)3037 b Fj(109)0
+555 y(to)41 b(return)d(the)j(length)e(of)h(the)g(\014le.)69
+b(This)38 b(mo)s(di\014ed)f(v)m(ersion)j(is)f(a)m(v)-5
+b(ailable)39 b(in)g(ro)s(otd)g(sub)s(directory)f(in)h(the)0
+668 y(CFITSIO)29 b(ftp)h(area)h(at)286 928 y Fe
+(ftp://legacy.gsfc.nasa.gov)o(/so)o(ftwa)o(re/f)o(its)o(io/c)o(/roo)o
+(t/r)o(ootd)o(.tar)o(.gz)o(.)0 1187 y Fj(This)i(small)f(serv)m(er)j(is)
+f(started)g(either)g(b)m(y)h(inetd)e(when)g(a)i(clien)m(t)f(requests)g
+(a)h(connection)g(to)g(a)f(ro)s(otd)h(serv)m(er)0 1300
+y(or)30 b(b)m(y)g(hand)f(\(i.e.)41 b(from)30 b(the)g(command)g(line\).)
+40 b(The)29 b(ro)s(otd)h(serv)m(er)h(w)m(orks)f(with)f(the)h(R)m(OOT)g
+(TNetFile)g(class.)0 1413 y(It)g(allo)m(ws)e(remote)j(access)f(to)h(R)m
+(OOT)e(database)h(\014les)e(in)g(either)h(read)h(or)f(write)g(mo)s(de.)
+40 b(By)30 b(default)e(TNetFile)0 1526 y(assumes)38 b(p)s(ort)g(432)h
+(\(whic)m(h)e(requires)g(ro)s(otd)h(to)h(b)s(e)f(started)h(as)f(ro)s
+(ot\).)65 b(T)-8 b(o)39 b(run)e(ro)s(otd)h(via)g(inetd)f(add)h(the)0
+1639 y(follo)m(wing)29 b(line)g(to)i(/etc/services:)95
+1898 y Fe(rootd)238 b(432/tcp)0 2158 y Fj(and)30 b(to)h
+(/etc/inetd.conf,)h(add)e(the)g(follo)m(wing)f(line:)95
+2417 y Fe(rootd)47 b(stream)f(tcp)h(nowait)f(root)h
+(/user/rdm/root/bin/root)o(d)42 b(rootd)k(-i)0 2677 y
+Fj(F)-8 b(orce)30 b(inetd)d(to)i(reread)f(its)g(conf)g(\014le)f(with)g
+Fe(kill)47 b(-HUP)g(<pid)f(inetd>)p Fj(.)39 b(Y)-8 b(ou)28
+b(can)h(also)f(start)h(ro)s(otd)f(b)m(y)g(hand)0 2790
+y(running)34 b(directly)h(under)f(y)m(our)j(priv)-5 b(ate)36
+b(accoun)m(t)h(\(no)g(ro)s(ot)g(system)f(privileges)e(needed\).)59
+b(F)-8 b(or)37 b(example)f(to)0 2903 y(start)f(ro)s(otd)g(listening)d
+(on)j(p)s(ort)f(5151)j(just)d(t)m(yp)s(e:)49 b Fe(rootd)e(-p)g(5151)33
+b Fj(Notice)j(that)g(no)e(&)h(is)e(needed.)54 b(Ro)s(otd)0
+3016 y(will)28 b(go)j(in)m(to)f(bac)m(kground)g(b)m(y)h(itself.)95
+3275 y Fe(Rootd)47 b(arguments:)191 3388 y(-i)763 b(says)47
+b(we)g(were)f(started)g(by)h(inetd)191 3501 y(-p)g(port#)476
+b(specifies)45 b(a)j(different)d(port)i(to)g(listen)f(on)191
+3614 y(-d)h(level)476 b(level)46 b(of)i(debug)e(info)h(written)e(to)j
+(syslog)1050 3727 y(0)f(=)h(no)f(debug)f(\(default\))1050
+3840 y(1)h(=)h(minimum)1050 3953 y(2)f(=)h(medium)1050
+4066 y(3)f(=)h(maximum)0 4325 y Fj(Ro)s(otd)29 b(can)f(also)g(b)s(e)g
+(con\014gured)g(for)g(anon)m(ymous)g(usage)h(\(lik)m(e)f(anon)m(ymous)g
+(ftp\).)40 b(T)-8 b(o)29 b(setup)f(ro)s(otd)g(to)h(accept)0
+4438 y(anon)m(ymous)h(logins)f(do)i(the)f(follo)m(wing)f(\(while)g(b)s
+(eing)g(logged)i(in)e(as)h(ro)s(ot\):)143 4698 y Fe(-)48
+b(Add)f(the)f(following)g(line)g(to)i(/etc/passwd:)239
+4924 y(rootd:*:71:72:Anonymous)41 b(rootd:/var/spool/rootd:/b)o(in/)o
+(fals)o(e)239 5149 y(where)46 b(you)h(may)g(modify)f(the)h(uid,)f(gid)h
+(\(71,)g(72\))g(and)g(the)g(home)f(directory)239 5262
+y(to)h(suite)f(your)h(system.)143 5488 y(-)h(Add)f(the)f(following)g
+(line)g(to)i(/etc/group:)239 5714 y(rootd:*:72:rootd)p
+eop
+%%Page: 110 118
+110 117 bop 0 299 a Fj(110)1528 b Fh(CHAPTER)29 b(10.)113
+b(EXTENDED)30 b(FILE)h(NAME)f(SYNT)-8 b(AX)239 668 y
+Fe(where)46 b(the)h(gid)g(must)f(match)h(the)g(gid)g(in)g(/etc/passwd.)
+143 894 y(-)h(Create)e(the)h(directories:)239 1120 y(mkdir)f
+(/var/spool/rootd)239 1233 y(mkdir)g(/var/spool/rootd/tmp)239
+1346 y(chmod)g(777)h(/var/spool/rootd/tmp)239 1571 y(Where)f
+(/var/spool/rootd)d(must)k(match)f(the)h(rootd)g(home)f(directory)g(as)
+239 1684 y(specified)f(in)i(the)g(rootd)f(/etc/passwd)f(entry.)143
+1910 y(-)j(To)f(make)f(writeable)g(directories)e(for)j(anonymous)f(do,)
+h(for)f(example:)239 2136 y(mkdir)g(/var/spool/rootd/pub)239
+2249 y(chown)g(rootd:rootd)f(/var/spool/rootd/pub)0 2492
+y Fj(That's)d(all.)74 b(Sev)m(eral)42 b(additional)e(remarks:)64
+b(y)m(ou)42 b(can)g(login)f(to)i(an)f(anon)m(ymous)f(serv)m(er)i
+(either)e(with)g(the)0 2605 y(names)31 b("anon)m(ymous")h(or)f("ro)s
+(otd".)43 b(The)31 b(passw)m(ord)f(should)f(b)s(e)i(of)g(t)m(yp)s(e)g
+(user@host.do.main.)42 b(Only)29 b(the)i(@)0 2718 y(is)d(enforced)g
+(for)h(the)f(time)h(b)s(eing.)38 b(In)28 b(anon)m(ymous)h(mo)s(de)f
+(the)g(top)h(of)g(the)g(\014le)e(tree)j(is)d(set)i(to)h(the)e(ro)s(otd)
+h(home)0 2831 y(directory)-8 b(,)38 b(therefore)f(only)e(\014les)h(b)s
+(elo)m(w)f(the)i(home)f(directory)g(can)g(b)s(e)g(accessed.)60
+b(Anon)m(ymous)36 b(mo)s(de)g(only)0 2944 y(w)m(orks)30
+b(when)g(the)g(serv)m(er)h(is)e(started)i(via)f(inetd.)0
+3232 y Fd(10.2.3)113 b(Notes)36 b(ab)s(out)j(the)e(shmem)g(\014let)m
+(yp)s(e:)0 3451 y Fj(Shared)d(memory)h(\014les)f(are)h(curren)m(tly)f
+(supp)s(orted)f(on)i(most)h(Unix)e(platforms,)h(where)g(the)g(shared)f
+(memory)0 3564 y(segmen)m(ts)d(are)g(managed)g(b)m(y)f(the)g(op)s
+(erating)g(system)h(k)m(ernel)e(and)h(`liv)m(e')g(indep)s(enden)m(tly)d
+(of)k(pro)s(cesses.)40 b(They)0 3677 y(are)34 b(not)g(deleted)g(\(b)m
+(y)g(default\))f(when)g(the)h(pro)s(cess)f(whic)m(h)g(created)i(them)f
+(terminates,)g(although)g(they)g(will)0 3790 y(disapp)s(ear)d(if)h(the)
+i(system)f(is)f(reb)s(o)s(oted.)49 b(Applications)31
+b(can)j(create)h(shared)d(memory)h(\014les)f(in)g(CFITSIO)g(b)m(y)0
+3903 y(calling:)143 4146 y Fe(fit_create_file\(&fitsfile)o(ptr,)41
+b("shmem://h2",)j(&status\);)0 4389 y Fj(where)25 b(the)g(ro)s(ot)h
+(`\014le')e(names)i(are)f(curren)m(tly)f(restricted)h(to)h(b)s(e)f
+('h0',)i('h1',)g('h2',)g('h3',)f(etc.,)i(up)d(to)g(a)h(maxim)m(um)0
+4502 y(n)m(um)m(b)s(er)20 b(de\014ned)f(b)m(y)i(the)g(the)g(v)-5
+b(alue)21 b(of)g(SHARED)p 1746 4502 28 4 v 33 w(MAXSEG)g(\(equal)g(to)g
+(16)h(b)m(y)f(default\).)37 b(This)19 b(is)h(a)h(protot)m(yp)s(e)0
+4615 y(implemen)m(tation)27 b(of)i(the)g(shared)f(memory)g(in)m
+(terface)h(and)f(a)h(more)g(robust)f(in)m(terface,)i(whic)m(h)d(will)f
+(ha)m(v)m(e)k(few)m(er)0 4728 y(restrictions)f(on)h(the)h(n)m(um)m(b)s
+(er)e(of)i(\014les)e(and)h(on)g(their)f(names,)i(ma)m(y)g(b)s(e)f(dev)m
+(elop)s(ed)f(in)g(the)i(future.)0 4888 y(When)23 b(op)s(ening)g(an)g
+(already)g(existing)g(FITS)g(\014le)g(in)f(shared)h(memory)h(one)g
+(calls)e(the)i(usual)f(CFITSIO)f(routine:)143 5132 y
+Fe(fits_open_file\(&fitsfilep)o(tr,)41 b("shmem://h7",)j(mode,)j
+(&status\))0 5375 y Fj(The)26 b(\014le)g(mo)s(de)h(can)g(b)s(e)f(READ)m
+(WRITE)h(or)g(READONL)-8 b(Y)28 b(just)e(as)h(with)e(disk)h(\014les.)38
+b(More)28 b(than)e(one)h(pro)s(cess)0 5488 y(can)35 b(op)s(erate)g(on)f
+(READONL)-8 b(Y)35 b(mo)s(de)f(\014les)g(at)h(the)f(same)h(time.)53
+b(CFITSIO)33 b(supp)s(orts)f(prop)s(er)h(\014le)h(lo)s(c)m(king)0
+5601 y(\(b)s(oth)27 b(in)g(READONL)-8 b(Y)29 b(and)e(READ)m(WRITE)h(mo)
+s(des\),)h(so)f(calls)f(to)h(\014ts)p 2572 5601 V 33
+w(op)s(en)p 2795 5601 V 32 w(\014le)f(ma)m(y)h(b)s(e)f(lo)s(c)m(k)m(ed)
+i(out)f(un)m(til)0 5714 y(another)j(other)f(pro)s(cess)g(closes)h(the)f
+(\014le.)p eop
+%%Page: 111 119
+111 118 bop 0 299 a Fh(10.3.)73 b(BASE)30 b(FILENAME)2739
+b Fj(111)0 555 y(When)30 b(an)g(application)f(is)g(\014nished)f
+(accessing)j(a)f(FITS)g(\014le)f(in)g(a)i(shared)e(memory)h(segmen)m
+(t,)i(it)e(ma)m(y)h(close)f(it)0 668 y(\(and)k(the)g(\014le)f(will)e
+(remain)h(in)h(the)h(system\))g(with)f(\014ts)p 1955
+668 28 4 v 32 w(close)p 2174 668 V 33 w(\014le,)h(or)g(delete)g(it)g
+(with)e(\014ts)p 3191 668 V 33 w(delete)p 3456 668 V
+33 w(\014le.)50 b(Ph)m(ys-)0 781 y(ical)34 b(deletion)g(is)g(p)s(ostp)s
+(oned)f(un)m(til)h(the)h(last)f(pro)s(cess)h(calls)f
+(\013clos/\013delt.)54 b(\014ts)p 2801 781 V 32 w(delete)p
+3065 781 V 33 w(\014le)34 b(tries)h(to)g(obtain)g(a)0
+894 y(READ)m(WRITE)f(lo)s(c)m(k)f(on)g(the)g(\014le)g(to)h(b)s(e)e
+(deleted,)i(th)m(us)f(it)g(can)g(b)s(e)g(blo)s(c)m(k)m(ed)g(if)f(the)i
+(ob)5 b(ject)34 b(w)m(as)f(not)h(op)s(ened)0 1007 y(in)29
+b(READ)m(WRITE)i(mo)s(de.)0 1167 y(A)i(shared)f(memory)h(managemen)m(t)
+h(utilit)m(y)d(program)i(called)f(`smem',)h(is)f(included)e(with)i(the)
+h(CFITSIO)e(dis-)0 1280 y(tribution.)37 b(It)27 b(can)g(b)s(e)f(built)f
+(b)m(y)i(t)m(yping)f(`mak)m(e)i(smem';)g(then)f(t)m(yp)s(e)g(`smem)f
+(-h')h(to)h(get)g(a)f(list)e(of)i(v)-5 b(alid)25 b(options.)0
+1393 y(Executing)36 b(smem)g(without)f(an)m(y)i(options)f(causes)g(it)g
+(to)h(list)e(all)g(the)i(shared)e(memory)i(segmen)m(ts)g(curren)m(tly)0
+1506 y(residing)31 b(in)h(the)h(system)h(and)e(managed)i(b)m(y)f(the)h
+(shared)e(memory)h(driv)m(er.)48 b(T)-8 b(o)34 b(get)g(a)g(list)e(of)h
+(all)f(the)i(shared)0 1619 y(memory)c(ob)5 b(jects,)32
+b(run)d(the)h(system)h(utilit)m(y)d(program)i(`ip)s(cs)g([-a]'.)0
+1978 y Ff(10.3)136 b(Base)45 b(Filename)0 2233 y Fj(The)31
+b(base)g(\014lename)g(is)f(the)i(name)f(of)h(the)f(\014le)g(optionally)
+e(including)f(the)k(director/sub)s(directory)d(path,)j(and)0
+2346 y(in)d(the)i(case)g(of)g(`ftp',)f(`h)m(ttp',)i(and)d(`ro)s(ot')j
+(\014let)m(yp)s(es,)d(the)i(mac)m(hine)f(iden)m(ti\014er.)39
+b(Examples:)191 2628 y Fe(myfile.fits)191 2741 y(!data.fits)191
+2854 y(/data/myfile.fits)191 2967 y(fits.gsfc.nasa.gov/ftp/s)o(ampl)o
+(eda)o(ta/m)o(yfil)o(e.f)o(its.)o(gz)0 3248 y Fj(When)29
+b(creating)g(a)g(new)f(output)h(\014le)f(on)h(magnetic)g(disk)e(\(of)j
+(t)m(yp)s(e)f(\014le://\))g(if)f(the)h(base)g(\014lename)f(b)s(egins)f
+(with)0 3361 y(an)34 b(exclamation)h(p)s(oin)m(t)e(\(!\))54
+b(then)34 b(an)m(y)g(existing)g(\014le)f(with)g(that)i(same)g(basename)
+g(will)d(b)s(e)h(deleted)h(prior)f(to)0 3474 y(creating)h(the)g(new)g
+(FITS)f(\014le.)50 b(Otherwise)33 b(if)g(the)h(\014le)f(to)h(b)s(e)g
+(created)h(already)e(exists,)i(then)e(CFITSIO)g(will)0
+3587 y(return)g(an)h(error)f(and)g(will)f(not)i(o)m(v)m(erwrite)g(the)g
+(existing)f(\014le.)51 b(Note)35 b(that)g(the)f(exclamation)g(p)s(oin)m
+(t,)g(')10 b(!',)36 b(is)d(a)0 3700 y(sp)s(ecial)26 b(UNIX)i(c)m
+(haracter,)j(so)d(if)e(it)i(is)f(used)g(on)g(the)h(command)g(line)e
+(rather)i(than)f(en)m(tered)h(at)h(a)f(task)h(prompt,)0
+3813 y(it)i(m)m(ust)g(b)s(e)g(preceded)g(b)m(y)h(a)g(bac)m(kslash)f(to)
+h(force)g(the)g(UNIX)g(shell)d(to)j(pass)f(it)h(v)m(erbatim)f(to)h(the)
+g(application)0 3926 y(program.)0 4086 y(If)24 b(the)i(output)e(disk)g
+(\014le)g(name)h(ends)f(with)f(the)i(su\016x)f('.gz',)k(then)d(CFITSIO)
+e(will)f(compress)j(the)g(\014le)f(using)g(the)0 4199
+y(gzip)g(compression)f(algorithm)g(b)s(efore)h(writing)e(it)i(to)h
+(disk.)37 b(This)22 b(can)j(reduce)f(the)g(amoun)m(t)h(of)f(disk)f
+(space)i(used)0 4312 y(b)m(y)34 b(the)h(\014le.)52 b(Note)36
+b(that)f(this)f(feature)h(requires)e(that)i(the)f(uncompressed)g
+(\014le)f(b)s(e)h(constructed)h(in)e(memory)0 4425 y(b)s(efore)d(it)g
+(is)f(compressed)h(and)g(written)g(to)h(disk,)e(so)h(it)g(can)h(fail)e
+(if)g(there)i(is)e(insu\016cien)m(t)g(a)m(v)-5 b(ailable)30
+b(memory)-8 b(.)0 4585 y(An)45 b(input)f(FITS)g(\014le)h(ma)m(y)h(b)s
+(e)f(compressed)g(with)g(the)g(gzip)g(or)h(Unix)e(compress)i
+(algorithms,)i(in)c(whic)m(h)0 4698 y(case)38 b(CFITSIO)e(will)f
+(uncompress)h(the)i(\014le)f(on)g(the)h(\015y)e(in)m(to)i(a)g(temp)s
+(orary)f(\014le)f(\(in)h(memory)g(or)g(on)h(disk\).)0
+4811 y(Compressed)32 b(\014les)h(ma)m(y)h(only)e(b)s(e)h(op)s(ened)f
+(with)g(read-only)h(p)s(ermission.)47 b(When)33 b(sp)s(ecifying)e(the)j
+(name)f(of)h(a)0 4924 y(compressed)h(FITS)g(\014le)g(it)g(is)g(not)h
+(necessary)g(to)g(app)s(end)e(the)i(\014le)f(su\016x)f(\(e.g.,)39
+b(`.gz')e(or)f(`.Z'\).)g(If)f(CFITSIO)0 5036 y(cannot)24
+b(\014nd)e(the)h(input)e(\014le)i(name)g(without)f(the)h(su\016x,)h
+(then)f(it)g(will)e(automatically)i(searc)m(h)h(for)f(a)g(compressed)0
+5149 y(\014le)35 b(with)f(the)i(same)g(ro)s(ot)g(name.)57
+b(In)35 b(the)h(case)h(of)f(reading)f(ftp)g(and)g(h)m(ttp)h(t)m(yp)s(e)
+g(\014les,)g(CFITSIO)f(generally)0 5262 y(lo)s(oks)i(for)h(a)g
+(compressed)g(v)m(ersion)f(of)h(the)g(\014le)f(\014rst,)i(b)s(efore)e
+(trying)g(to)i(op)s(en)e(the)h(uncompressed)e(\014le.)63
+b(By)0 5375 y(default,)36 b(CFITSIO)f(copies)g(\(and)h(uncompressed)e
+(if)h(necessary\))h(the)g(ftp)f(or)h(h)m(ttp)g(FITS)f(\014le)f(in)m(to)
+i(memory)0 5488 y(on)g(the)g(lo)s(cal)f(mac)m(hine)g(b)s(efore)h(op)s
+(ening)e(it.)57 b(This)34 b(will)f(fail)h(if)h(the)h(lo)s(cal)f(mac)m
+(hine)h(do)s(es)f(not)h(ha)m(v)m(e)h(enough)0 5601 y(memory)g(to)h
+(hold)e(the)h(whole)g(FITS)f(\014le,)j(so)e(in)f(this)g(case,)41
+b(the)c(output)g(\014lename)f(sp)s(eci\014er)g(\(see)i(the)g(next)0
+5714 y(section\))31 b(can)g(b)s(e)e(used)h(to)h(further)e(con)m(trol)i
+(ho)m(w)f(CFITSIO)f(reads)h(ftp)g(and)g(h)m(ttp)g(\014les.)p
+eop
+%%Page: 112 120
+112 119 bop 0 299 a Fj(112)1528 b Fh(CHAPTER)29 b(10.)113
+b(EXTENDED)30 b(FILE)h(NAME)f(SYNT)-8 b(AX)0 555 y Fj(If)32
+b(the)h(input)e(\014le)h(is)g(an)h(IRAF)g(image)g(\014le)f(\(*.imh)g
+(\014le\))h(then)f(CFITSIO)f(will)g(automatically)h(con)m(v)m(ert)j(it)
+d(on)0 668 y(the)27 b(\015y)g(in)m(to)g(a)h(virtual)d(FITS)h(image)i(b)
+s(efore)f(it)f(is)g(op)s(ened)h(b)m(y)g(the)g(application)f(program.)39
+b(IRAF)27 b(images)h(can)0 781 y(only)h(b)s(e)h(op)s(ened)g(with)f
+(READONL)-8 b(Y)31 b(\014le)e(access.)0 941 y(Similarly)-8
+b(,)28 b(if)i(the)h(input)e(\014le)i(is)f(a)h(ra)m(w)g(binary)e(data)j
+(arra)m(y)-8 b(,)33 b(then)d(CFITSIO)g(will)e(con)m(v)m(ert)33
+b(it)d(on)h(the)h(\015y)e(in)m(to)0 1054 y(a)38 b(virtual)e(FITS)i
+(image)g(with)e(the)i(basic)g(set)g(of)g(required)e(header)i(k)m(eyw)m
+(ords)g(b)s(efore)g(it)f(is)g(op)s(ened)g(b)m(y)h(the)0
+1167 y(application)29 b(program)i(\(with)f(READONL)-8
+b(Y)31 b(access\).)44 b(In)30 b(this)g(case)i(the)f(data)g(t)m(yp)s(e)g
+(and)g(dimensions)d(of)j(the)0 1280 y(image)c(m)m(ust)g(b)s(e)f(sp)s
+(eci\014ed)f(in)h(square)h(brac)m(k)m(ets)h(follo)m(wing)d(the)i
+(\014lename)f(\(e.g.)41 b(ra)m(w\014le.dat[ib512,512]\).)h(The)0
+1393 y(\014rst)30 b(c)m(haracter)i(\(case)f(insensitiv)m(e\))e
+(de\014nes)h(the)g(data)h(t)m(yp)s(e)g(of)f(the)h(arra)m(y:)239
+1671 y Fe(b)429 b(8-bit)46 b(unsigned)g(byte)239 1784
+y(i)381 b(16-bit)46 b(signed)g(integer)239 1897 y(u)381
+b(16-bit)46 b(unsigned)g(integer)239 2010 y(j)381 b(32-bit)46
+b(signed)g(integer)239 2123 y(r)h(or)g(f)143 b(32-bit)46
+b(floating)g(point)239 2235 y(d)381 b(64-bit)46 b(floating)g(point)0
+2514 y Fj(An)40 b(optional)f(second)h(c)m(haracter)i(sp)s(eci\014es)d
+(the)i(b)m(yte)f(order)g(of)g(the)h(arra)m(y)g(v)-5 b(alues:)59
+b(b)40 b(or)g(B)h(indicates)e(big)0 2626 y(endian)29
+b(\(as)h(in)f(FITS)g(\014les)g(and)g(the)h(nativ)m(e)h(format)f(of)g
+(SUN)g(UNIX)g(w)m(orkstations)g(and)g(Mac)h(PCs\))e(and)h(l)f(or)0
+2739 y(L)e(indicates)g(little)f(endian)g(\(nativ)m(e)j(format)e(of)h
+(DEC)g(OSF)f(w)m(orkstations)g(and)g(IBM)h(PCs\).)40
+b(If)27 b(this)f(c)m(haracter)0 2852 y(is)f(omitted)g(then)g(the)h
+(arra)m(y)g(is)f(assumed)g(to)h(ha)m(v)m(e)h(the)f(nativ)m(e)f(b)m(yte)
+i(order)e(of)g(the)h(lo)s(cal)f(mac)m(hine.)39 b(These)25
+b(data)0 2965 y(t)m(yp)s(e)35 b(c)m(haracters)h(are)g(then)e(follo)m(w)
+m(ed)h(b)m(y)f(a)i(series)e(of)h(one)g(or)g(more)g(in)m(teger)g(v)-5
+b(alues)34 b(separated)i(b)m(y)e(commas)0 3078 y(whic)m(h)40
+b(de\014ne)g(the)h(size)g(of)g(eac)m(h)h(dimension)d(of)i(the)g(ra)m(w)
+g(arra)m(y)-8 b(.)74 b(Arra)m(ys)41 b(with)e(up)h(to)i(5)f(dimensions)e
+(are)0 3191 y(curren)m(tly)30 b(supp)s(orted.)41 b(Finally)-8
+b(,)30 b(a)h(b)m(yte)h(o\013set)g(to)g(the)f(p)s(osition)f(of)h(the)g
+(\014rst)f(pixel)g(in)g(the)h(data)h(\014le)e(ma)m(y)i(b)s(e)0
+3304 y(sp)s(eci\014ed)g(b)m(y)h(separating)h(it)f(with)f(a)i(':')48
+b(from)33 b(the)h(last)f(dimension)e(v)-5 b(alue.)50
+b(If)33 b(omitted,)i(it)e(is)f(assumed)h(that)0 3417
+y(the)i(o\013set)h(=)f(0.)54 b(This)34 b(parameter)h(ma)m(y)h(b)s(e)e
+(used)g(to)i(skip)d(o)m(v)m(er)j(an)m(y)g(header)e(information)g(in)f
+(the)i(\014le)f(that)0 3530 y(precedes)c(the)h(binary)e(data.)41
+b(F)-8 b(urther)30 b(examples:)95 3808 y Fe(raw.dat[b10000])521
+b(1-dimensional)45 b(10000)h(pixel)g(byte)h(array)95
+3921 y(raw.dat[rb400,400,12])233 b(3-dimensional)45 b(floating)g(point)
+h(big-endian)f(array)95 4034 y(img.fits[ib512,512:2880])89
+b(reads)47 b(the)g(512)g(x)g(512)g(short)f(integer)g(array)g(in)1336
+4147 y(a)i(FITS)e(file,)h(skipping)e(over)i(the)g(2880)g(byte)f(header)
+0 4425 y Fj(One)25 b(sp)s(ecial)e(case)j(of)f(input)e(\014le)h(is)g
+(where)h(the)g(\014lename)f(=)h(`-')h(\(a)f(dash)g(or)g(min)m(us)e
+(sign\))h(or)h('stdin')f(or)h('stdout',)0 4538 y(whic)m(h)c
+(signi\014es)g(that)j(the)f(input)d(\014le)i(is)g(to)i(b)s(e)e(read)g
+(from)h(the)g(stdin)e(stream,)k(or)e(written)e(to)j(the)f(stdout)g
+(stream)0 4650 y(if)33 b(a)h(new)g(output)f(\014le)g(is)g(b)s(eing)g
+(created.)52 b(In)33 b(the)h(case)h(of)f(reading)g(from)f(stdin,)g
+(CFITSIO)g(\014rst)g(copies)h(the)0 4763 y(whole)g(stream)i(in)m(to)f
+(a)g(temp)s(orary)g(FITS)f(\014le)h(\(in)f(memory)h(or)g(on)g(disk\),)g
+(and)g(subsequen)m(t)f(reading)g(of)i(the)0 4876 y(FITS)c(\014le)g(o)s
+(ccurs)h(in)e(this)h(cop)m(y)-8 b(.)49 b(When)33 b(writing)e(to)i
+(stdout,)h(CFITSIO)d(\014rst)h(constructs)h(the)g(whole)f(\014le)g(in)0
+4989 y(memory)i(\(since)h(random)e(access)j(is)d(required\),)i(then)f
+(\015ushes)f(it)h(out)h(to)g(the)f(stdout)h(stream)g(when)e(the)i
+(\014le)0 5102 y(is)29 b(closed.)41 b(In)29 b(addition,)g(if)g(the)h
+(output)g(\014lename)f(=)h('-.gz')i(or)e('stdout.gz')h(then)f(it)g
+(will)d(b)s(e)j(gzip)f(compressed)0 5215 y(b)s(efore)h(b)s(eing)f
+(written)g(to)i(stdout.)0 5375 y(This)24 b(abilit)m(y)h(to)h(read)g
+(and)f(write)g(on)h(the)g(stdin)f(and)g(stdout)h(steams)g(allo)m(ws)g
+(FITS)f(\014les)g(to)h(b)s(e)g(pip)s(ed)d(b)s(et)m(w)m(een)0
+5488 y(tasks)42 b(in)e(memory)h(rather)g(than)h(ha)m(ving)f(to)h
+(create)h(temp)s(orary)e(in)m(termediate)g(FITS)f(\014les)h(on)g(disk.)
+72 b(F)-8 b(or)0 5601 y(example)27 b(if)e(task1)j(creates)h(an)e
+(output)f(FITS)g(\014le,)h(and)g(task2)g(reads)g(an)g(input)e(FITS)h
+(\014le,)h(the)g(FITS)f(\014le)g(ma)m(y)0 5714 y(b)s(e)k(pip)s(ed)e(b)s
+(et)m(w)m(een)j(the)f(2)h(tasks)g(b)m(y)f(sp)s(ecifying)p
+eop
+%%Page: 113 121
+113 120 bop 0 299 a Fh(10.4.)73 b(OUTPUT)29 b(FILE)h(NAME)h(WHEN)g
+(OPENING)f(AN)h(EXISTING)f(FILE)876 b Fj(113)143 555
+y Fe(task1)47 b(-)g(|)g(task2)g(-)0 783 y Fj(where)30
+b(the)h(v)m(ertical)g(bar)g(is)e(the)i(Unix)f(piping)e(sym)m(b)s(ol.)41
+b(This)29 b(assumes)h(that)i(the)f(2)g(tasks)g(read)g(the)g(name)g(of)0
+896 y(the)g(FITS)e(\014le)h(o\013)g(of)h(the)g(command)f(line.)0
+1224 y Ff(10.4)136 b(Output)44 b(File)i(Name)f(when)g(Op)t(ening)g(an)g
+(Existing)h(File)0 1474 y Fj(An)36 b(optional)g(output)g(\014lename)g
+(ma)m(y)i(b)s(e)e(sp)s(eci\014ed)f(in)g(paren)m(theses)i(immediately)e
+(follo)m(wing)g(the)i(base)g(\014le)0 1587 y(name)28
+b(to)h(b)s(e)f(op)s(ened.)39 b(This)27 b(is)g(mainly)f(useful)h(in)g
+(those)h(cases)i(where)d(CFITSIO)g(creates)j(a)e(temp)s(orary)g(cop)m
+(y)0 1700 y(of)i(the)f(input)f(FITS)g(\014le)h(b)s(efore)g(it)g(is)f
+(op)s(ened)h(and)f(passed)h(to)h(the)g(application)e(program.)40
+b(This)27 b(happ)s(ens)h(b)m(y)0 1813 y(default)h(when)h(op)s(ening)f
+(a)h(net)m(w)m(ork)h(FTP)g(or)f(HTTP-t)m(yp)s(e)g(\014le,)g(when)f
+(reading)g(a)i(compressed)f(FITS)g(\014le)f(on)0 1926
+y(a)36 b(lo)s(cal)f(disk,)h(when)f(reading)g(from)h(the)g(stdin)e
+(stream,)k(or)d(when)g(a)i(column)d(\014lter,)j(ro)m(w)f(\014lter,)g
+(or)g(binning)0 2039 y(sp)s(eci\014er)28 b(is)g(included)f(as)j(part)f
+(of)g(the)h(input)e(\014le)g(sp)s(eci\014cation.)39 b(By)30
+b(default)f(this)f(temp)s(orary)h(\014le)f(is)h(created)0
+2152 y(in)g(memory)-8 b(.)41 b(If)29 b(there)h(is)f(not)h(enough)g
+(memory)g(to)h(create)g(the)g(\014le)e(cop)m(y)-8 b(,)31
+b(then)f(CFITSIO)e(will)f(exit)j(with)f(an)0 2265 y(error.)45
+b(In)32 b(these)g(cases)h(one)g(can)f(force)h(a)f(p)s(ermanen)m(t)g
+(\014le)f(to)i(b)s(e)e(created)i(on)f(disk,)f(instead)h(of)g(a)g(temp)s
+(orary)0 2378 y(\014le)37 b(in)f(memory)-8 b(,)40 b(b)m(y)d(supplying)d
+(the)k(name)g(in)e(paren)m(theses)i(immediately)e(follo)m(wing)g(the)h
+(base)h(\014le)f(name.)0 2490 y(The)30 b(output)g(\014lename)f(can)i
+(include)d(the)j(')10 b(!')41 b(clobb)s(er)29 b(\015ag.)0
+2651 y(Th)m(us,)48 b(if)c(the)h(input)e(\014lename)h(to)h(CFITSIO)f
+(is:)69 b Fe(file1.fits.gz\(file2.fit)o(s\))39 b Fj(then)44
+b(CFITSIO)g(will)0 2764 y(uncompress)39 b(`\014le1.\014ts.gz')i(in)m
+(to)f(the)g(lo)s(cal)f(disk)f(\014le)h(`\014le2.\014ts')h(b)s(efore)g
+(op)s(ening)e(it.)69 b(CFITSIO)38 b(do)s(es)i(not)0 2876
+y(automatically)30 b(delete)h(the)f(output)g(\014le,)g(so)h(it)f(will)d
+(still)i(exist)h(after)h(the)f(application)f(program)h(exits.)0
+3037 y(The)i(output)h(\014lename)f("mem://")j(is)d(also)h(allo)m(w)m
+(ed,)h(whic)m(h)d(will)g(write)h(the)h(output)f(\014le)g(in)m(to)h
+(memory)-8 b(,)35 b(and)0 3150 y(also)27 b(allo)m(w)f(write)g(access)i
+(to)g(the)f(\014le.)38 b(This)25 b('\014le')i(will)d(disapp)s(ear)h
+(when)h(it)g(is)g(closed,)h(but)f(this)g(ma)m(y)i(b)s(e)e(useful)0
+3262 y(for)k(some)h(applications)d(whic)m(h)i(only)f(need)h(to)h(mo)s
+(dify)e(a)i(temp)s(orary)f(cop)m(y)h(of)f(the)h(\014le.)0
+3423 y(In)k(some)i(cases,)h(sev)m(eral)e(di\013eren)m(t)g(temp)s(orary)
+f(FITS)h(\014les)f(will)e(b)s(e)i(created)i(in)e(sequence,)j(for)e
+(instance,)h(if)0 3535 y(one)g(op)s(ens)g(a)g(remote)h(\014le)e(using)g
+(FTP)-8 b(,)37 b(then)g(\014lters)f(ro)m(ws)h(in)f(a)i(binary)d(table)i
+(extension,)i(then)d(create)j(an)0 3648 y(image)e(b)m(y)g(binning)d(a)j
+(pair)f(of)h(columns.)59 b(In)36 b(this)g(case,)k(the)d(remote)h
+(\014le)e(will)e(b)s(e)i(copied)g(to)i(a)f(temp)s(orary)0
+3761 y(lo)s(cal)h(\014le,)i(then)e(a)h(second)f(temp)s(orary)h(\014le)e
+(will)f(b)s(e)i(created)i(con)m(taining)e(the)g(\014ltered)g(ro)m(ws)g
+(of)h(the)g(table,)0 3874 y(and)c(\014nally)e(a)j(third)d(temp)s(orary)
+i(\014le)g(con)m(taining)f(the)i(binned)d(image)i(will)e(b)s(e)i
+(created.)57 b(In)34 b(cases)i(lik)m(e)f(this)0 3987
+y(where)28 b(m)m(ultiple)e(\014les)h(are)i(created,)h(the)e(out\014le)g
+(sp)s(eci\014er)f(will)e(b)s(e)j(in)m(terpreted)g(the)g(name)g(of)h
+(the)f(\014nal)f(\014le)h(as)0 4100 y(describ)s(ed)g(b)s(elo)m(w,)i(in)
+f(descending)g(priorit)m(y:)136 4327 y Fc(\017)46 b Fj(as)29
+b(the)g(name)g(of)g(the)g(\014nal)e(image)i(\014le)f(if)f(an)i(image)g
+(within)d(a)j(single)e(binary)g(table)i(cell)f(is)f(op)s(ened)h(or)h
+(if)227 4440 y(an)i(image)f(is)g(created)h(b)m(y)f(binning)e(a)i(table)
+h(column.)136 4617 y Fc(\017)46 b Fj(as)33 b(the)f(name)h(of)f(the)h
+(\014le)e(con)m(taining)h(the)g(\014ltered)f(table)i(if)e(a)i(column)e
+(\014lter)g(and/or)h(a)h(ro)m(w)f(\014lter)g(are)227
+4730 y(sp)s(eci\014ed.)136 4907 y Fc(\017)46 b Fj(as)31
+b(the)f(name)h(of)f(the)h(lo)s(cal)f(cop)m(y)h(of)f(the)h(remote)g(FTP)
+f(or)h(HTTP)e(\014le.)136 5084 y Fc(\017)46 b Fj(as)31
+b(the)g(name)g(of)g(the)f(uncompressed)g(v)m(ersion)g(of)h(the)f(FITS)g
+(\014le,)g(if)g(a)h(compressed)f(FITS)g(\014le)g(on)h(lo)s(cal)227
+5197 y(disk)e(has)h(b)s(een)g(op)s(ened.)136 5374 y Fc(\017)46
+b Fj(otherwise,)30 b(the)h(output)f(\014lename)f(is)h(ignored.)0
+5601 y(The)f(output)f(\014le)g(sp)s(eci\014er)g(is)g(useful)f(when)h
+(reading)g(FTP)h(or)g(HTTP-t)m(yp)s(e)g(FITS)f(\014les)g(since)g(it)h
+(can)g(b)s(e)g(used)0 5714 y(to)34 b(create)i(a)e(lo)s(cal)f(disk)f
+(cop)m(y)j(of)f(the)g(\014le)e(that)j(can)f(b)s(e)f(reused)g(in)f(the)i
+(future.)50 b(If)33 b(the)h(output)g(\014le)e(name)i(=)p
+eop
+%%Page: 114 122
+114 121 bop 0 299 a Fj(114)1528 b Fh(CHAPTER)29 b(10.)113
+b(EXTENDED)30 b(FILE)h(NAME)f(SYNT)-8 b(AX)0 555 y Fj(`*')36
+b(then)f(a)g(lo)s(cal)f(\014le)g(with)g(the)h(same)g(name)g(as)g(the)h
+(net)m(w)m(ork)f(\014le)f(will)f(b)s(e)h(created.)56
+b(Note)36 b(that)f(CFITSIO)0 668 y(will)27 b(b)s(eha)m(v)m(e)j
+(di\013eren)m(tly)f(dep)s(ending)e(on)j(whether)f(the)h(remote)g
+(\014le)f(is)g(compressed)g(or)h(not)g(as)g(sho)m(wn)f(b)m(y)h(the)0
+781 y(follo)m(wing)f(examples:)136 1005 y Fc(\017)46
+b Fe(ftp://remote.machine/tmp/)o(myfi)o(le.f)o(its)o(.gz\()o(*\))28
+b Fj(-)35 b(the)g(remote)h(compressed)e(\014le)g(is)g(copied)g(to)227
+1117 y(the)e(lo)s(cal)f(compressed)h(\014le)f(`m)m(y\014le.\014ts.gz',)
+i(whic)m(h)d(is)h(then)h(uncompressed)e(in)h(lo)s(cal)g(memory)g(b)s
+(efore)227 1230 y(b)s(eing)e(op)s(ened)h(and)g(passed)f(to)j(the)e
+(application)f(program.)136 1414 y Fc(\017)46 b Fe
+(ftp://remote.machine/tmp/)o(myfi)o(le.f)o(its)o(.gz\()o(myfi)o(le.)o
+(fits)o(\))33 b Fj(-)39 b(the)g(remote)h(compressed)f(\014le)227
+1526 y(is)c(copied)g(and)g(uncompressed)g(in)m(to)g(the)h(lo)s(cal)f
+(\014le)g(`m)m(y\014le.\014ts'.)56 b(This)34 b(example)h(requires)g
+(less)g(lo)s(cal)227 1639 y(memory)21 b(than)g(the)g(previous)e
+(example)i(since)f(the)h(\014le)f(is)g(uncompressed)f(on)i(disk)f
+(instead)g(of)h(in)e(memory)-8 b(.)136 1822 y Fc(\017)46
+b Fe(ftp://remote.machine/tmp/)o(myfi)o(le.f)o(its)o(\(myf)o(ile.)o
+(fit)o(s.gz)o(\))24 b Fj(-)30 b(this)f(will)e(usually)h(pro)s(duce)h
+(an)227 1935 y(error)h(since)g(CFITSIO)f(itself)g(cannot)i(compress)f
+(\014les.)0 2159 y(The)36 b(exact)i(b)s(eha)m(vior)d(of)i(CFITSIO)e(in)
+g(the)i(latter)f(case)i(dep)s(ends)c(on)j(the)f(t)m(yp)s(e)h(of)g(ftp)f
+(serv)m(er)g(running)e(on)0 2272 y(the)d(remote)g(mac)m(hine)f(and)g
+(ho)m(w)g(it)g(is)f(con\014gured.)40 b(In)30 b(some)h(cases,)g(if)e
+(the)i(\014le)e(`m)m(y\014le.\014ts.gz')j(exists)e(on)g(the)0
+2385 y(remote)38 b(mac)m(hine,)g(then)f(the)g(serv)m(er)g(will)e(cop)m
+(y)i(it)g(to)g(the)h(lo)s(cal)e(mac)m(hine.)60 b(In)36
+b(other)h(cases)h(the)f(ftp)g(serv)m(er)0 2498 y(will)c(automatically)j
+(create)h(and)f(transmit)f(a)h(compressed)g(v)m(ersion)f(of)h(the)g
+(\014le)f(if)g(only)g(the)h(uncompressed)0 2611 y(v)m(ersion)26
+b(exists.)40 b(This)25 b(can)i(get)h(rather)f(confusing,)g(so)g(users)f
+(should)f(use)i(a)g(certain)g(amoun)m(t)h(of)f(caution)g(when)0
+2723 y(using)33 b(the)i(output)f(\014le)g(sp)s(eci\014er)f(with)h(FTP)g
+(or)h(HTTP)f(\014le)g(t)m(yp)s(es,)i(to)f(mak)m(e)h(sure)e(they)h(get)h
+(the)f(b)s(eha)m(vior)0 2836 y(that)c(they)g(exp)s(ect.)0
+3168 y Ff(10.5)136 b(T)-11 b(emplate)45 b(File)h(Name)g(when)e
+(Creating)j(a)e(New)g(File)0 3418 y Fj(When)38 b(a)h(new)f(FITS)g
+(\014le)g(is)g(created)h(with)f(a)g(call)g(to)i(\014ts)p
+2101 3418 28 4 v 32 w(create)p 2369 3418 V 35 w(\014le,)f(the)g(name)g
+(of)g(a)g(template)g(\014le)e(ma)m(y)0 3531 y(b)s(e)i(supplied)e(in)i
+(paren)m(theses)h(immediately)e(follo)m(wing)g(the)j(name)f(of)g(the)g
+(new)f(\014le)g(to)i(b)s(e)e(created.)71 b(This)0 3644
+y(template)26 b(is)e(used)h(to)h(de\014ne)f(the)h(structure)f(of)h(one)
+f(or)h(more)g(HDUs)g(in)e(the)i(new)f(\014le.)38 b(The)25
+b(template)h(\014le)e(ma)m(y)0 3757 y(b)s(e)32 b(another)h(FITS)f
+(\014le,)h(in)f(whic)m(h)f(case)j(the)f(newly)f(created)i(\014le)e
+(will)e(ha)m(v)m(e)k(exactly)g(the)f(same)g(k)m(eyw)m(ords)g(in)0
+3870 y(eac)m(h)25 b(HDU)g(as)g(in)e(the)h(template)h(FITS)e(\014le,)i
+(but)e(all)h(the)g(data)h(units)d(will)g(b)s(e)i(\014lled)e(with)g
+(zeros.)40 b(The)24 b(template)0 3983 y(\014le)h(ma)m(y)i(also)f(b)s(e)
+f(an)h(ASCI)s(I)e(text)j(\014le,)f(where)g(eac)m(h)h(line)d(\(in)h
+(general\))i(describ)s(es)d(one)i(FITS)f(k)m(eyw)m(ord)i(record.)0
+4096 y(The)j(format)h(of)f(the)h(ASCI)s(I)e(template)h(\014le)g(is)f
+(describ)s(ed)f(in)i(the)g(follo)m(wing)f(T)-8 b(emplate)30
+b(Files)g(c)m(hapter.)0 4427 y Ff(10.6)136 b(Image)46
+b(Tile-Compression)g(Sp)t(eci\014cation)0 4677 y Fj(When)28
+b(sp)s(ecifying)e(the)j(name)g(of)f(the)h(output)f(FITS)g(\014le)f(to)i
+(b)s(e)f(created,)i(the)f(user)f(can)g(indicate)g(that)h(images)0
+4790 y(should)c(b)s(e)i(written)f(in)g(tile-compressed)g(format)i
+(\(see)g(section)f(5.5,)i(\\Primary)d(Arra)m(y)i(or)f(IMA)m(GE)h
+(Extension)0 4903 y(I/O)f(Routines"\))h(b)m(y)f(enclosing)f(the)i
+(compression)e(parameters)i(in)e(square)h(brac)m(k)m(ets)i(follo)m
+(wing)d(the)i(ro)s(ot)f(disk)0 5016 y(\014le)i(name.)41
+b(Here)31 b(are)g(some)g(examples)f(of)g(the)h(syn)m(tax)g(for)f(sp)s
+(ecifying)e(tile-compressed)i(output)g(images:)191 5262
+y Fe(myfile.fit[compress])185 b(-)48 b(use)f(Rice)f(algorithm)g(and)h
+(default)e(tile)i(size)191 5488 y(myfile.fit[compress)42
+b(GZIP])47 b(-)g(use)g(the)g(specified)e(compression)g(algorithm;)191
+5601 y(myfile.fit[compress)d(Rice])238 b(only)46 b(the)h(first)g
+(letter)f(of)h(the)g(algorithm)191 5714 y(myfile.fit[compress)42
+b(PLIO])238 b(name)46 b(is)i(required.)p eop
+%%Page: 115 123
+115 122 bop 0 299 a Fh(10.7.)73 b(HDU)31 b(LOCA)-8 b(TION)29
+b(SPECIFICA)-8 b(TION)2019 b Fj(115)191 668 y Fe(myfile.fit[compress)42
+b(Rice)47 b(100,100])141 b(-)48 b(use)e(100)h(x)h(100)f(pixel)f(tile)h
+(size)191 781 y(myfile.fit[compress)42 b(Rice)47 b(100,100;2])e(-)j(as)
+f(above,)f(and)h(use)g(noisebits)e(=)i(2)0 1114 y Ff(10.7)136
+b(HDU)45 b(Lo)t(cation)g(Sp)t(eci\014cation)0 1364 y
+Fj(The)c(optional)f(HDU)j(lo)s(cation)e(sp)s(eci\014er)e(de\014nes)i
+(whic)m(h)f(HDU)i(\(Header-Data)i(Unit,)g(also)d(kno)m(wn)g(as)h(an)0
+1477 y(`extension'\))35 b(within)c(the)k(FITS)e(\014le)g(to)i
+(initially)c(op)s(en.)51 b(It)34 b(m)m(ust)g(immediately)f(follo)m(w)g
+(the)h(base)h(\014le)e(name)0 1590 y(\(or)h(the)g(output)g(\014le)f
+(name)g(if)g(presen)m(t\).)52 b(If)33 b(it)g(is)g(not)h(sp)s(eci\014ed)
+f(then)g(the)h(\014rst)f(HDU)i(\(the)f(primary)e(arra)m(y\))0
+1703 y(is)g(op)s(ened.)46 b(The)32 b(HDU)h(lo)s(cation)f(sp)s
+(eci\014er)f(is)h(required)f(if)g(the)i(colFilter,)f(ro)m(wFilter,)h
+(or)g(binSp)s(ec)d(sp)s(eci\014ers)0 1816 y(are)g(presen)m(t,)f(b)s
+(ecause)h(the)f(primary)e(arra)m(y)j(is)e(not)i(a)f(v)-5
+b(alid)28 b(HDU)i(for)f(these)g(op)s(erations.)40 b(The)29
+b(HDU)h(ma)m(y)g(b)s(e)0 1929 y(sp)s(eci\014ed)d(either)i(b)m(y)f
+(absolute)h(p)s(osition)e(n)m(um)m(b)s(er,)h(starting)h(with)e(0)j(for)
+e(the)h(primary)e(arra)m(y)-8 b(,)31 b(or)e(b)m(y)f(reference)0
+2042 y(to)h(the)g(HDU)g(name,)g(and)f(optionally)-8 b(,)28
+b(the)h(v)m(ersion)f(n)m(um)m(b)s(er)f(and)h(the)h(HDU)g(t)m(yp)s(e)g
+(of)f(the)h(desired)e(extension.)0 2155 y(The)32 b(lo)s(cation)f(of)h
+(an)g(image)h(within)c(a)k(single)d(cell)i(of)g(a)g(binary)f(table)h
+(ma)m(y)g(also)g(b)s(e)g(sp)s(eci\014ed,)f(as)h(describ)s(ed)0
+2268 y(b)s(elo)m(w.)0 2428 y(The)26 b(absolute)g(p)s(osition)e(of)i
+(the)h(extension)f(is)f(sp)s(eci\014ed)f(either)i(b)m(y)g(enclosed)g
+(the)h(n)m(um)m(b)s(er)e(in)g(square)g(brac)m(k)m(ets)0
+2541 y(\(e.g.,)k(`[1]')g(=)d(the)h(\014rst)f(extension)g(follo)m(wing)g
+(the)h(primary)d(arra)m(y\))k(or)f(b)m(y)f(preceded)h(the)g(n)m(um)m(b)
+s(er)e(with)h(a)h(plus)0 2654 y(sign)36 b(\(`+1'\).)63
+b(T)-8 b(o)38 b(sp)s(ecify)e(the)h(HDU)h(b)m(y)g(name,)h(giv)m(e)f(the)
+f(name)h(of)f(the)h(desired)e(HDU)i(\(the)f(v)-5 b(alue)37
+b(of)h(the)0 2766 y(EXTNAME)e(or)g(HDUNAME)h(k)m(eyw)m(ord\))g(and)f
+(optionally)e(the)i(extension)g(v)m(ersion)f(n)m(um)m(b)s(er)g(\(v)-5
+b(alue)36 b(of)g(the)0 2879 y(EXTVER)27 b(k)m(eyw)m(ord\))i(and)e(the)h
+(extension)g(t)m(yp)s(e)f(\(v)-5 b(alue)28 b(of)g(the)g(XTENSION)f(k)m
+(eyw)m(ord:)40 b(IMA)m(GE,)29 b(ASCI)s(I)d(or)0 2992
+y(T)-8 b(ABLE,)36 b(or)f(BINT)-8 b(ABLE\),)36 b(separated)f(b)m(y)g
+(commas)h(and)e(all)g(enclosed)h(in)f(square)h(brac)m(k)m(ets.)56
+b(If)34 b(the)h(v)-5 b(alue)0 3105 y(of)34 b(EXTVER)f(and)f(XTENSION)h
+(are)h(not)f(sp)s(eci\014ed,)g(then)g(the)h(\014rst)e(extension)i(with)
+e(the)h(correct)i(v)-5 b(alue)33 b(of)0 3218 y(EXTNAME)39
+b(is)f(op)s(ened.)67 b(The)38 b(extension)h(name)g(and)f(t)m(yp)s(e)i
+(are)f(not)h(case)g(sensitiv)m(e,)h(and)d(the)h(extension)0
+3331 y(t)m(yp)s(e)29 b(ma)m(y)g(b)s(e)f(abbreviated)g(to)h(a)g(single)e
+(letter)i(\(e.g.,)i(I)d(=)g(IMA)m(GE)i(extension)e(or)g(primary)f(arra)
+m(y)-8 b(,)30 b(A)f(or)f(T)g(=)0 3444 y(ASCI)s(I)d(table)h(extension,)h
+(and)f(B)h(=)f(binary)f(table)h(BINT)-8 b(ABLE)27 b(extension\).)40
+b(If)26 b(the)g(HDU)h(lo)s(cation)g(sp)s(eci\014er)0
+3557 y(is)i(equal)h(to)h(`[PRIMAR)-8 b(Y]')32 b(or)f(`[P]',)g(then)f
+(the)h(primary)d(arra)m(y)j(\(the)g(\014rst)f(HDU\))h(will)d(b)s(e)i
+(op)s(ened.)0 3717 y(FITS)k(images)h(are)g(most)h(commonly)e(stored)h
+(in)f(the)h(primary)e(arra)m(y)i(or)g(an)g(image)g(extension,)h(but)e
+(images)0 3830 y(can)d(also)g(b)s(e)f(stored)h(as)h(a)f(v)m(ector)h(in)
+e(a)h(single)f(cell)g(of)h(a)h(binary)d(table)i(\(i.e.)42
+b(eac)m(h)32 b(ro)m(w)f(of)g(the)h(v)m(ector)g(column)0
+3943 y(con)m(tains)c(a)h(di\013eren)m(t)e(image\).)41
+b(Suc)m(h)27 b(an)h(image)h(can)f(b)s(e)g(op)s(ened)f(with)g(CFITSIO)f
+(b)m(y)i(sp)s(ecifying)e(the)i(desired)0 4056 y(column)j(name)h(and)f
+(the)h(ro)m(w)g(n)m(um)m(b)s(er)f(after)h(the)g(binary)e(table)i(HDU)h
+(sp)s(eci\014er)d(as)i(sho)m(wn)g(in)e(the)i(follo)m(wing)0
+4169 y(examples.)70 b(The)40 b(column)f(name)i(is)e(separated)i(from)f
+(the)h(HDU)g(sp)s(eci\014er)e(b)m(y)h(a)h(semicolon)e(and)h(the)h(ro)m
+(w)0 4282 y(n)m(um)m(b)s(er)29 b(is)g(enclosed)h(in)e(paren)m(theses.)
+41 b(In)30 b(this)f(case)i(CFITSIO)d(copies)i(the)g(image)h(from)e(the)
+i(table)f(cell)f(in)m(to)0 4394 y(a)j(temp)s(orary)e(primary)g(arra)m
+(y)h(b)s(efore)g(it)g(is)f(op)s(ened.)43 b(The)30 b(application)g
+(program)h(then)g(just)g(sees)g(the)h(image)0 4507 y(in)h(the)i
+(primary)d(arra)m(y)-8 b(,)37 b(without)c(an)m(y)i(extensions.)52
+b(The)34 b(particular)e(ro)m(w)j(to)g(b)s(e)e(op)s(ened)h(ma)m(y)h(b)s
+(e)f(sp)s(eci\014ed)0 4620 y(either)27 b(b)m(y)g(giving)f(an)h
+(absolute)g(in)m(teger)h(ro)m(w)g(n)m(um)m(b)s(er)e(\(starting)h(with)f
+(1)i(for)f(the)g(\014rst)g(ro)m(w\),)i(or)e(b)m(y)g(sp)s(ecifying)0
+4733 y(a)33 b(b)s(o)s(olean)e(expression)g(that)i(ev)-5
+b(aluates)33 b(to)g(TR)m(UE)g(for)f(the)g(desired)f(ro)m(w.)47
+b(The)32 b(\014rst)f(ro)m(w)i(that)g(satis\014es)f(the)0
+4846 y(expression)27 b(will)e(b)s(e)j(used.)39 b(The)28
+b(ro)m(w)g(selection)g(expression)f(has)h(the)g(same)g(syn)m(tax)h(as)f
+(describ)s(ed)e(in)h(the)h(Ro)m(w)0 4959 y(Filter)i(Sp)s(eci\014er)e
+(section,)j(b)s(elo)m(w.)0 5119 y(Examples:)143 5375
+y Fe(myfile.fits[3])44 b(-)k(open)e(the)h(3rd)g(HDU)g(following)e(the)i
+(primary)f(array)143 5488 y(myfile.fits+3)92 b(-)48 b(same)e(as)h
+(above,)f(but)h(using)g(the)g(FTOOLS-style)d(notation)143
+5601 y(myfile.fits[EVENTS])f(-)k(open)g(the)g(extension)e(that)i(has)g
+(EXTNAME)e(=)j('EVENTS')143 5714 y(myfile.fits[EVENTS,)43
+b(2])95 b(-)47 b(same)g(as)g(above,)f(but)h(also)g(requires)e(EXTVER)h
+(=)i(2)p eop
+%%Page: 116 124
+116 123 bop 0 299 a Fj(116)1528 b Fh(CHAPTER)29 b(10.)113
+b(EXTENDED)30 b(FILE)h(NAME)f(SYNT)-8 b(AX)143 555 y
+Fe(myfile.fits[events,2,b])42 b(-)47 b(same,)f(but)h(also)g(requires)f
+(XTENSION)f(=)j('BINTABLE')143 668 y(myfile.fits[3;)c(images\(17\)])h
+(-)i(opens)g(the)g(image)f(in)h(row)g(17)g(of)g(the)g('images')1527
+781 y(column)f(in)i(the)e(3rd)h(extension)f(of)h(the)g(file.)143
+894 y(myfile.fits[3;)d(images\(exposure)g(>)j(100\)])g(-)g(as)g(above,)
+f(but)h(opens)g(the)f(image)907 1007 y(in)h(the)g(first)f(row)h(that)g
+(has)g(an)g('exposure')e(column)h(value)907 1120 y(greater)g(than)g
+(100.)0 1449 y Ff(10.8)136 b(Image)46 b(Section)0 1699
+y Fj(A)41 b(virtual)e(\014le)g(con)m(taining)h(a)h(rectangular)g
+(subsection)e(of)i(an)g(image)f(can)h(b)s(e)f(extracted)i(and)e(op)s
+(ened)g(b)m(y)0 1812 y(sp)s(ecifying)30 b(the)j(range)g(of)g(pixels)e
+(\(start:end\))i(along)g(eac)m(h)h(axis)e(to)h(b)s(e)f(extracted)i
+(from)e(the)h(original)d(image.)0 1925 y(One)g(can)h(also)g(sp)s(ecify)
+e(an)i(optional)f(pixel)f(incremen)m(t)h(\(start:end:step\))i(for)f
+(eac)m(h)h(axis)e(of)h(the)g(input)d(image.)0 2038 y(A)g(pixel)d(step)j
+(=)f(1)h(will)d(b)s(e)i(assumed)f(if)h(it)g(is)f(not)i(sp)s(eci\014ed.)
+38 b(If)27 b(the)h(start)g(pixel)e(is)g(larger)i(then)f(the)h(end)e
+(pixel,)0 2151 y(then)32 b(the)g(image)g(will)d(b)s(e)i(\015ipp)s(ed)e
+(\(pro)s(ducing)h(a)i(mirror)f(image\))h(along)g(that)g(dimension.)43
+b(An)32 b(asterisk,)g('*',)0 2264 y(ma)m(y)39 b(b)s(e)e(used)h(to)h(sp)
+s(ecify)e(the)h(en)m(tire)g(range)h(of)f(an)h(axis,)h(and)d('-*')j
+(will)35 b(\015ip)i(the)h(en)m(tire)g(axis.)64 b(The)38
+b(input)0 2377 y(image)30 b(can)g(b)s(e)f(in)f(the)i(primary)e(arra)m
+(y)-8 b(,)31 b(in)d(an)h(image)h(extension,)g(or)g(con)m(tained)f(in)g
+(a)h(v)m(ector)h(cell)e(of)h(a)g(binary)0 2490 y(table.)39
+b(In)25 b(the)h(later)g(2)g(cases)h(the)f(extension)g(name)g(or)f(n)m
+(um)m(b)s(er)g(m)m(ust)h(b)s(e)f(sp)s(eci\014ed)f(b)s(efore)i(the)g
+(image)g(section)0 2603 y(sp)s(eci\014er.)0 2763 y(Examples:)95
+2996 y Fe(myfile.fits[1:512:2,)43 b(2:512:2])i(-)95 b(open)47
+b(a)h(256x256)d(pixel)i(image)668 3109 y(consisting)e(of)i(the)g(odd)g
+(numbered)f(columns)g(\(1st)g(axis\))h(and)668 3222 y(the)g(even)g
+(numbered)e(rows)i(\(2nd)g(axis\))f(of)h(the)g(image)f(in)i(the)668
+3335 y(primary)e(array)g(of)i(the)e(file.)95 3561 y(myfile.fits[*,)e
+(512:256])i(-)h(open)g(an)g(image)g(consisting)e(of)i(all)g(the)g
+(columns)668 3674 y(in)g(the)g(input)g(image,)f(but)h(only)f(rows)h
+(256)g(through)f(512.)668 3787 y(The)h(image)f(will)h(be)g(flipped)f
+(along)g(the)h(2nd)g(axis)g(since)668 3900 y(the)g(starting)f(pixel)g
+(is)h(greater)f(than)h(the)g(ending)f(pixel.)95 4125
+y(myfile.fits[*:2,)e(512:256:2])h(-)i(same)g(as)g(above)f(but)h
+(keeping)f(only)668 4238 y(every)h(other)f(row)h(and)g(column)f(in)h
+(the)g(input)f(image.)95 4464 y(myfile.fits[-*,)e(*])j(-)h(copy)e(the)h
+(entire)f(image,)g(flipping)g(it)h(along)668 4577 y(the)g(first)f
+(axis.)95 4803 y(myfile.fits[3][1:256,1:256)o(])c(-)47
+b(opens)g(a)g(subsection)e(of)i(the)g(image)g(that)668
+4916 y(is)g(in)h(the)e(3rd)h(extension)f(of)h(the)g(file.)95
+5142 y(myfile.fits[4;)d(images\(12\)][1:10,1:10])e(-)48
+b(open)e(an)h(image)g(consisting)286 5255 y(of)h(the)e(first)h(10)g
+(pixels)f(in)h(both)g(dimensions.)e(The)i(original)286
+5367 y(image)g(resides)f(in)h(the)g(12th)f(row)h(of)g(the)g('images')f
+(vector)286 5480 y(column)g(in)i(the)f(table)f(in)h(the)g(4th)g
+(extension)e(of)i(the)g(file.)0 5714 y Fj(When)23 b(CFITSIO)f(op)s(ens)
+h(an)g(image)g(section)h(it)f(\014rst)g(creates)h(a)g(temp)s(orary)f
+(\014le)g(con)m(taining)g(the)g(image)h(section)p eop
+%%Page: 117 125
+117 124 bop 0 299 a Fh(10.9.)73 b(COLUMN)30 b(AND)h(KEYW)m(ORD)g(FIL)-8
+b(TERING)30 b(SPECIFICA)-8 b(TION)1030 b Fj(117)0 555
+y(plus)31 b(a)j(cop)m(y)g(of)g(an)m(y)g(other)f(HDUs)h(in)e(the)i
+(\014le.)49 b(This)31 b(temp)s(orary)i(\014le)g(is)f(then)h(op)s(ened)g
+(b)m(y)g(the)h(application)0 668 y(program,)28 b(so)g(it)f(is)f(not)i
+(p)s(ossible)d(to)j(write)f(to)h(or)g(mo)s(dify)e(the)h(input)f(\014le)
+g(when)h(sp)s(ecifying)e(an)j(image)g(section.)0 781
+y(Note)39 b(that)f(CFITSIO)e(automatically)h(up)s(dates)g(the)g(w)m
+(orld)g(co)s(ordinate)g(system)h(k)m(eyw)m(ords)f(in)f(the)i(header)0
+894 y(of)33 b(the)h(image)f(section,)h(if)e(they)i(exist,)g(so)f(that)h
+(the)f(co)s(ordinate)g(asso)s(ciated)h(with)e(eac)m(h)i(pixel)d(in)h
+(the)i(image)0 1007 y(section)d(will)c(b)s(e)j(computed)g(correctly)-8
+b(.)0 1360 y Ff(10.9)136 b(Column)45 b(and)f(Keyw)l(ord)i(Filtering)g
+(Sp)t(eci\014cation)0 1615 y Fj(The)27 b(optional)g(column/k)m(eyw)m
+(ord)h(\014ltering)e(sp)s(eci\014er)g(is)h(used)g(to)i(mo)s(dify)d(the)
+i(column)f(structure)g(and/or)h(the)0 1728 y(header)38
+b(k)m(eyw)m(ords)h(in)e(the)i(HDU)g(that)h(w)m(as)f(selected)g(with)e
+(the)i(previous)e(HDU)i(lo)s(cation)f(sp)s(eci\014er.)64
+b(This)0 1840 y(\014ltering)40 b(sp)s(eci\014er)g(m)m(ust)i(b)s(e)f
+(enclosed)h(in)e(square)i(brac)m(k)m(ets)h(and)e(can)h(b)s(e)f
+(distinguished)d(from)k(a)g(general)0 1953 y(ro)m(w)d(\014lter)f(sp)s
+(eci\014er)f(\(describ)s(ed)g(b)s(elo)m(w\))h(b)m(y)h(the)g(fact)h
+(that)f(it)f(b)s(egins)f(with)h(the)h(string)f('col)h(')g(and)f(is)g
+(not)0 2066 y(immediately)27 b(follo)m(w)m(ed)h(b)m(y)g(an)g(equals)g
+(sign.)39 b(The)28 b(original)e(\014le)h(is)h(not)g(c)m(hanged)h(b)m(y)
+f(this)g(\014ltering)e(op)s(eration,)0 2179 y(and)40
+b(instead)g(the)h(mo)s(di\014cations)e(are)i(made)f(on)h(a)g(cop)m(y)g
+(of)g(the)g(input)e(FITS)h(\014le)f(\(usually)g(in)g(memory\),)0
+2292 y(whic)m(h)32 b(also)h(con)m(tains)g(a)g(cop)m(y)h(of)f(all)f(the)
+i(other)f(HDUs)h(in)d(the)i(\014le.)48 b(This)32 b(temp)s(orary)g
+(\014le)g(is)g(passed)h(to)h(the)0 2405 y(application)c(program)i(and)f
+(will)e(p)s(ersist)h(only)h(un)m(til)f(the)i(\014le)f(is)g(closed)h(or)
+g(un)m(til)e(the)i(program)f(exits,)i(unless)0 2518 y(the)e(out\014le)e
+(sp)s(eci\014er)g(\(see)i(ab)s(o)m(v)m(e\))h(is)e(also)g(supplied.)0
+2678 y(The)h(column/k)m(eyw)m(ord)g(\014lter)f(can)h(b)s(e)g(used)f(to)
+i(p)s(erform)e(the)i(follo)m(wing)d(op)s(erations.)43
+b(More)32 b(than)f(one)g(op)s(er-)0 2791 y(ation)f(ma)m(y)h(b)s(e)f(sp)
+s(eci\014ed)f(b)m(y)h(separating)g(them)g(with)g(semi-colons.)136
+3068 y Fc(\017)46 b Fj(Cop)m(y)36 b(only)f(a)h(sp)s(eci\014ed)f(list)f
+(of)i(columns)f(columns)f(to)j(the)f(\014ltered)f(input)f(\014le.)56
+b(The)36 b(list)e(of)i(column)227 3181 y(name)c(should)e(b)s(e)i
+(separated)g(b)m(y)g(semi-colons.)46 b(Wild)30 b(card)i(c)m(haracters)i
+(ma)m(y)e(b)s(e)g(used)f(in)g(the)h(column)227 3294 y(names)37
+b(to)h(matc)m(h)g(m)m(ultiple)d(columns.)60 b(If)37 b(the)g(expression)
+f(con)m(tains)i(b)s(oth)e(a)i(list)d(of)j(columns)e(to)i(b)s(e)227
+3406 y(included)f(and)h(columns)g(to)h(b)s(e)g(deleted,)i(then)d(all)g
+(the)h(columns)f(in)g(the)h(original)e(table)i(except)h(the)227
+3519 y(explicitly)28 b(deleted)i(columns)f(will)e(app)s(ear)j(in)f(the)
+h(\014ltered)f(table)h(\(i.e.,)h(there)f(is)g(no)g(need)f(to)i
+(explicitly)227 3632 y(list)e(the)i(columns)e(to)i(b)s(e)f(included)d
+(if)j(an)m(y)g(columns)f(are)i(b)s(eing)e(deleted\).)136
+3837 y Fc(\017)46 b Fj(Delete)31 b(a)e(column)f(or)h(k)m(eyw)m(ord)h(b)
+m(y)f(listing)e(the)i(name)g(preceded)g(b)m(y)g(a)g(min)m(us)f(sign)g
+(or)h(an)g(exclamation)227 3950 y(mark)c(\(!\),)h(e.g.,)i('-TIME')d
+(will)d(delete)j(the)f(TIME)h(column)e(if)g(it)i(exists,)g(otherwise)f
+(the)h(TIME)f(k)m(eyw)m(ord.)227 4063 y(An)35 b(error)f(is)g(returned)f
+(if)h(neither)f(a)j(column)d(nor)h(k)m(eyw)m(ord)h(with)f(this)f(name)i
+(exists.)53 b(Note)36 b(that)g(the)227 4176 y(exclamation)25
+b(p)s(oin)m(t,)h(')10 b(!',)27 b(is)d(a)h(sp)s(ecial)f(UNIX)h(c)m
+(haracter,)j(so)d(if)f(it)h(is)f(used)g(on)h(the)g(command)g(line)e
+(rather)227 4289 y(than)33 b(en)m(tered)h(at)g(a)g(task)g(prompt,)f(it)
+g(m)m(ust)g(b)s(e)g(preceded)g(b)m(y)g(a)h(bac)m(kslash)f(to)h(force)g
+(the)f(UNIX)h(shell)227 4401 y(to)d(ignore)f(it.)136
+4606 y Fc(\017)46 b Fj(Rename)29 b(an)g(existing)e(column)g(or)i(k)m
+(eyw)m(ord)g(with)e(the)i(syn)m(tax)g('NewName)h(==)e(OldName'.)39
+b(An)28 b(error)227 4719 y(is)i(returned)f(if)g(neither)h(a)g(column)f
+(nor)h(k)m(eyw)m(ord)h(with)e(this)h(name)g(exists.)136
+4924 y Fc(\017)46 b Fj(App)s(end)37 b(a)j(new)f(column)e(or)j(k)m(eyw)m
+(ord)f(to)h(the)f(table.)67 b(T)-8 b(o)40 b(create)g(a)g(column,)g(giv)
+m(e)g(the)f(new)g(name,)227 5036 y(optionally)32 b(follo)m(w)m(ed)g(b)m
+(y)h(the)g(data)h(t)m(yp)s(e)f(in)e(paren)m(theses,)j(follo)m(w)m(ed)f
+(b)m(y)g(a)g(single)f(equals)g(sign)g(and)g(an)227 5149
+y(expression)i(to)i(b)s(e)e(used)g(to)i(compute)f(the)g(v)-5
+b(alue)34 b(\(e.g.,)k('new)m(col\(1J\))e(=)f(0')g(will)e(create)j(a)f
+(new)g(32-bit)227 5262 y(in)m(teger)h(column)d(called)i('new)m(col')g
+(\014lled)e(with)h(zeros\).)55 b(The)35 b(data)g(t)m(yp)s(e)h(is)e(sp)s
+(eci\014ed)f(using)g(the)j(same)227 5375 y(syn)m(tax)j(that)g(is)e
+(allo)m(w)m(ed)h(for)g(the)g(v)-5 b(alue)38 b(of)g(the)g(FITS)f(TF)m
+(ORMn)h(k)m(eyw)m(ord)h(\(e.g.,)j('I',)d('J',)f('E',)h('D',)227
+5488 y(etc.)66 b(for)38 b(binary)e(tables,)41 b(and)c('I8',)k(F12.3',)i
+('E20.12',)g(etc.)65 b(for)38 b(ASCI)s(I)f(tables\).)65
+b(If)37 b(the)i(data)g(t)m(yp)s(e)227 5601 y(is)34 b(not)h(sp)s
+(eci\014ed)e(then)h(an)g(appropriate)g(data)h(t)m(yp)s(e)g(will)d(b)s
+(e)i(c)m(hosen)h(dep)s(ending)d(on)i(the)h(form)f(of)h(the)227
+5714 y(expression)43 b(\(ma)m(y)h(b)s(e)f(a)h(c)m(haracter)i(string,)g
+(logical,)h(bit,)f(long)d(in)m(teger,)48 b(or)43 b(double)g(column\).)
+79 b(An)p eop
+%%Page: 118 126
+118 125 bop 0 299 a Fj(118)1528 b Fh(CHAPTER)29 b(10.)113
+b(EXTENDED)30 b(FILE)h(NAME)f(SYNT)-8 b(AX)227 555 y
+Fj(appropriate)38 b(v)m(ector)j(coun)m(t)e(\(in)f(the)h(case)h(of)f
+(binary)e(tables\))i(will)d(also)j(b)s(e)f(added)g(if)g(not)h
+(explicitly)227 668 y(sp)s(eci\014ed.)227 819 y(When)26
+b(creating)g(a)g(new)f(k)m(eyw)m(ord,)j(the)e(k)m(eyw)m(ord)g(name)g(m)
+m(ust)g(b)s(e)f(preceded)g(b)m(y)h(a)g(p)s(ound)e(sign)g('#',)k(and)227
+932 y(the)h(expression)e(m)m(ust)h(ev)-5 b(aluate)29
+b(to)g(a)g(scalar)f(\(i.e.,)h(cannot)g(ha)m(v)m(e)h(a)f(column)e(name)h
+(in)f(the)i(expression\).)227 1045 y(The)j(commen)m(t)i(string)e(for)g
+(the)h(k)m(eyw)m(ord)h(ma)m(y)f(b)s(e)f(sp)s(eci\014ed)f(in)g(paren)m
+(theses)i(immediately)e(follo)m(wing)227 1158 y(the)c(k)m(eyw)m(ord)g
+(name)f(\(instead)g(of)h(supplying)c(a)k(data)g(t)m(yp)s(e)g(as)f(in)f
+(the)i(case)g(of)g(creating)g(a)g(new)f(column\).)136
+1348 y Fc(\017)46 b Fj(Recompute)f(\(o)m(v)m(erwrite\))h(the)e(v)-5
+b(alues)43 b(in)g(an)h(existing)g(column)f(or)h(k)m(eyw)m(ord)g(b)m(y)g
+(giving)g(the)g(name)227 1461 y(follo)m(w)m(ed)30 b(b)m(y)h(an)f
+(equals)g(sign)f(and)h(an)g(arithmetic)g(expression.)0
+1722 y(The)23 b(expression)f(that)j(is)d(used)h(when)g(app)s(ending)e
+(or)i(recomputing)g(columns)f(or)i(k)m(eyw)m(ords)g(can)g(b)s(e)f
+(arbitrarily)0 1835 y(complex)35 b(and)h(ma)m(y)g(b)s(e)f(a)h(function)
+f(of)h(other)g(header)g(k)m(eyw)m(ord)g(v)-5 b(alues)35
+b(and)g(other)h(columns)f(\(in)g(the)h(same)0 1948 y(ro)m(w\).)63
+b(The)37 b(full)e(syn)m(tax)k(and)e(a)m(v)-5 b(ailable)37
+b(functions)f(for)h(the)h(expression)e(are)i(describ)s(ed)e(b)s(elo)m
+(w)h(in)f(the)i(ro)m(w)0 2061 y(\014lter)29 b(sp)s(eci\014cation)h
+(section.)0 2221 y(F)-8 b(or)30 b(complex)g(or)f(commonly)g(used)g(op)s
+(erations,)h(one)f(can)h(also)g(place)g(the)f(op)s(erations)g(in)m(to)h
+(an)f(external)h(text)0 2334 y(\014le)g(and)g(imp)s(ort)f(it)h(in)m(to)
+h(the)g(column)f(\014lter)f(using)h(the)h(syn)m(tax)g('[col)g
+(@\014lename.txt]'.)42 b(The)31 b(op)s(erations)f(can)0
+2447 y(extend)c(o)m(v)m(er)i(m)m(ultiple)c(lines)h(of)h(the)h(\014le,)g
+(but)e(m)m(ultiple)f(op)s(erations)i(m)m(ust)g(still)f(b)s(e)g
+(separated)i(b)m(y)g(semicolons.)0 2560 y(An)m(y)h(lines)f(in)g(the)h
+(external)h(text)g(\014le)e(that)i(b)s(egin)e(with)g(2)i(slash)e(c)m
+(haracters)j(\('//'\))g(will)c(b)s(e)h(ignored)h(and)f(ma)m(y)0
+2673 y(b)s(e)j(used)f(to)i(add)f(commen)m(ts)h(in)m(to)g(the)f(\014le.)
+0 2833 y(Examples:)143 3095 y Fe([col)47 b(Time;rate])713
+b(-)47 b(only)g(the)g(Time)g(and)g(rate)f(columns)g(will)1670
+3208 y(appear)h(in)g(the)g(filtered)e(input)i(file.)143
+3434 y([col)g(Time;*raw])713 b(-)47 b(include)f(the)h(Time)g(column)f
+(and)h(any)g(other)1670 3546 y(columns)f(whose)h(name)f(ends)h(with)g
+('raw'.)143 3772 y([col)g(-TIME;)f(Good)h(==)g(STATUS])141
+b(-)47 b(deletes)f(the)h(TIME)g(column)f(and)1670 3885
+y(renames)g(the)h(status)f(column)g(to)i('Good')143 4111
+y([col)f(PI=PHA)f(*)h(1.1)g(+)h(0.2])285 b(-)47 b(creates)f(new)h(PI)g
+(column)f(from)h(PHA)g(values)143 4337 y([col)g(rate)f(=)i
+(rate/exposure])139 b(-)48 b(recomputes)d(the)i(rate)f(column)g(by)i
+(dividing)1670 4450 y(it)g(by)f(the)g(EXPOSURE)e(keyword)h(value.)0
+4786 y Ff(10.10)136 b(Ro)l(w)46 b(Filtering)g(Sp)t(eci\014cation)0
+5036 y Fj(When)29 b(en)m(tering)g(the)g(name)g(of)g(a)g(FITS)f(table)h
+(that)h(is)d(to)j(b)s(e)e(op)s(ened)h(b)m(y)f(a)i(program,)f(an)g
+(optional)f(ro)m(w)h(\014lter)0 5149 y(ma)m(y)i(b)s(e)g(sp)s(eci\014ed)
+e(to)i(select)g(a)h(subset)e(of)h(the)g(ro)m(ws)f(in)g(the)h(table.)42
+b(A)31 b(temp)s(orary)f(new)g(FITS)g(\014le)g(is)g(created)0
+5262 y(on)25 b(the)h(\015y)e(whic)m(h)g(con)m(tains)h(only)g(those)h
+(ro)m(ws)f(for)g(whic)m(h)f(the)h(ro)m(w)g(\014lter)g(expression)f(ev)
+-5 b(aluates)25 b(to)h(true.)39 b(\(The)0 5375 y(primary)25
+b(arra)m(y)i(and)f(an)m(y)g(other)h(extensions)f(in)f(the)i(input)e
+(\014le)g(are)i(also)g(copied)f(to)h(the)f(temp)s(orary)h(\014le\).)38
+b(The)0 5488 y(original)27 b(FITS)i(\014le)f(is)g(closed)h(and)f(the)i
+(new)e(virtual)g(\014le)g(is)g(op)s(ened)g(b)m(y)h(the)h(application)d
+(program.)40 b(The)29 b(ro)m(w)0 5601 y(\014lter)36 b(expression)g(is)h
+(enclosed)g(in)f(square)h(brac)m(k)m(ets)i(follo)m(wing)d(the)h(\014le)
+g(name)g(and)g(extension)g(name)g(\(e.g.,)0 5714 y('\014le.\014ts[ev)m
+(en)m(ts][GRADE==50]')28 b(selects)d(only)f(those)i(ro)m(ws)f(where)f
+(the)h(GRADE)h(column)e(v)-5 b(alue)24 b(equals)g(50\).)p
+eop
+%%Page: 119 127
+119 126 bop 0 299 a Fh(10.10.)73 b(R)m(O)m(W)31 b(FIL)-8
+b(TERING)31 b(SPECIFICA)-8 b(TION)1936 b Fj(119)0 555
+y(When)33 b(dealing)f(with)g(tables)g(where)h(eac)m(h)h(ro)m(w)f(has)g
+(an)g(asso)s(ciated)h(time)f(and/or)g(2D)g(spatial)g(p)s(osition,)f
+(the)0 668 y(ro)m(w)g(\014lter)g(expression)e(can)j(also)f(b)s(e)g
+(used)f(to)i(select)g(ro)m(ws)f(based)g(on)g(the)g(times)g(in)f(a)h(Go)
+s(o)s(d)g(Time)f(In)m(terv)-5 b(als)0 781 y(\(GTI\))31
+b(extension,)f(or)g(on)h(spatial)e(p)s(osition)g(as)h(giv)m(en)h(in)e
+(a)h(SA)m(O-st)m(yle)h(region)f(\014le.)0 1090 y Fd(10.10.1)113
+b(General)37 b(Syn)m(tax)0 1313 y Fj(The)32 b(ro)m(w)h(\014ltering)e
+(expression)h(can)h(b)s(e)f(an)h(arbitrarily)d(complex)i(series)g(of)h
+(op)s(erations)f(p)s(erformed)g(on)g(con-)0 1426 y(stan)m(ts,)39
+b(k)m(eyw)m(ord)e(v)-5 b(alues,)37 b(and)f(column)f(data)j(tak)m(en)f
+(from)f(the)h(sp)s(eci\014ed)d(FITS)i(T)-8 b(ABLE)37
+b(extension.)58 b(The)0 1539 y(expression)36 b(m)m(ust)i(ev)-5
+b(aluate)38 b(to)h(a)f(b)s(o)s(olean)f(v)-5 b(alue)37
+b(for)g(eac)m(h)i(ro)m(w)f(of)g(the)f(table,)j(where)d(a)h(v)-5
+b(alue)38 b(of)f(F)-10 b(ALSE)0 1652 y(means)30 b(that)h(the)g(ro)m(w)f
+(will)e(b)s(e)i(excluded.)0 1812 y(F)-8 b(or)34 b(complex)f(or)h
+(commonly)e(used)h(\014lters,)g(one)h(can)g(place)f(the)h(expression)e
+(in)m(to)h(a)h(text)g(\014le)f(and)g(imp)s(ort)e(it)0
+1925 y(in)m(to)37 b(the)f(ro)m(w)h(\014lter)f(using)f(the)i(syn)m(tax)g
+('[@\014lename.txt]'.)60 b(The)36 b(expression)g(can)g(b)s(e)g
+(arbitrarily)e(complex)0 2038 y(and)27 b(extend)i(o)m(v)m(er)g(m)m
+(ultiple)d(lines)g(of)i(the)h(\014le.)39 b(An)m(y)28
+b(lines)e(in)h(the)h(external)g(text)h(\014le)e(that)i(b)s(egin)e(with)
+g(2)h(slash)0 2151 y(c)m(haracters)k(\('//'\))g(will)c(b)s(e)i(ignored)
+f(and)h(ma)m(y)h(b)s(e)f(used)f(to)i(add)f(commen)m(ts)h(in)m(to)g(the)
+f(\014le.)0 2311 y(Keyw)m(ord)37 b(and)f(column)f(data)j(are)f
+(referenced)g(b)m(y)g(name.)60 b(An)m(y)37 b(string)e(of)i(c)m
+(haracters)i(not)e(surrounded)d(b)m(y)0 2424 y(quotes)41
+b(\(ie,)i(a)e(constan)m(t)h(string\))e(or)g(follo)m(w)m(ed)g(b)m(y)h
+(an)f(op)s(en)g(paren)m(theses)h(\(ie,)i(a)e(function)e(name\))i(will)d
+(b)s(e)0 2537 y(initially)33 b(in)m(terpreted)i(as)i(a)g(column)e(name)
+h(and)g(its)g(con)m(ten)m(ts)i(for)e(the)h(curren)m(t)f(ro)m(w)g
+(inserted)f(in)m(to)i(the)f(ex-)0 2650 y(pression.)j(If)28
+b(no)h(suc)m(h)g(column)f(exists,)h(a)h(k)m(eyw)m(ord)f(of)h(that)f
+(name)g(will)e(b)s(e)h(searc)m(hed)i(for)f(and)f(its)h(v)-5
+b(alue)28 b(used,)0 2763 y(if)35 b(found.)55 b(T)-8 b(o)36
+b(force)g(the)g(name)g(to)h(b)s(e)e(in)m(terpreted)g(as)h(a)g(k)m(eyw)m
+(ord)g(\(in)f(case)h(there)g(is)f(b)s(oth)g(a)h(column)f(and)0
+2875 y(k)m(eyw)m(ord)41 b(with)d(the)j(same)f(name\),)j(precede)d(the)h
+(k)m(eyw)m(ord)f(name)g(with)f(a)i(single)d(p)s(ound)g(sign,)k('#',)h
+(as)d(in)0 2988 y('#NAXIS2'.)g(Due)27 b(to)g(the)f(generalities)g(of)g
+(FITS)g(column)f(and)h(k)m(eyw)m(ord)h(names,)g(if)e(the)i(column)e(or)
+h(k)m(eyw)m(ord)0 3101 y(name)34 b(con)m(tains)g(a)g(space)h(or)e(a)i
+(c)m(haracter)g(whic)m(h)e(migh)m(t)g(app)s(ear)g(as)i(an)e(arithmetic)
+g(term)h(then)g(inclose)f(the)0 3214 y(name)d(in)f('$')j(c)m(haracters)
+g(as)e(in)f($MAX)j(PHA$)f(or)f(#$MAX-PHA$.)43 b(Names)31
+b(are)f(case)i(insensitiv)m(e.)0 3374 y(T)-8 b(o)32 b(access)g(a)g
+(table)f(en)m(try)h(in)e(a)i(ro)m(w)f(other)h(than)f(the)g(curren)m(t)g
+(one,)h(follo)m(w)f(the)g(column's)g(name)g(with)f(a)i(ro)m(w)0
+3487 y(o\013set)37 b(within)c(curly)h(braces.)57 b(F)-8
+b(or)36 b(example,)h('PHA)p Fc(f)p Fj(-3)p Fc(g)p Fj(')h(will)33
+b(ev)-5 b(aluate)37 b(to)f(the)g(v)-5 b(alue)35 b(of)h(column)e(PHA,)j
+(3)0 3600 y(ro)m(ws)28 b(ab)s(o)m(v)m(e)i(the)e(ro)m(w)h(curren)m(tly)e
+(b)s(eing)g(pro)s(cessed.)40 b(One)28 b(cannot)h(sp)s(ecify)e(an)h
+(absolute)g(ro)m(w)g(n)m(um)m(b)s(er,)g(only)g(a)0 3713
+y(relativ)m(e)i(o\013set.)42 b(Ro)m(ws)31 b(that)g(fall)e(outside)h
+(the)g(table)g(will)e(b)s(e)i(treated)h(as)g(unde\014ned,)d(or)j
+(NULLs.)0 3873 y(Bo)s(olean)g(op)s(erators)g(can)g(b)s(e)f(used)f(in)h
+(the)g(expression)g(in)f(either)h(their)g(F)-8 b(ortran)31
+b(or)f(C)h(forms.)40 b(The)30 b(follo)m(wing)0 3986 y(b)s(o)s(olean)f
+(op)s(erators)i(are)g(a)m(v)-5 b(ailable:)191 4262 y
+Fe("equal")428 b(.eq.)46 b(.EQ.)h(==)95 b("not)46 b(equal")476
+b(.ne.)94 b(.NE.)h(!=)191 4375 y("less)46 b(than")238
+b(.lt.)46 b(.LT.)h(<)143 b("less)46 b(than/equal")188
+b(.le.)94 b(.LE.)h(<=)47 b(=<)191 4488 y("greater)e(than")95
+b(.gt.)46 b(.GT.)h(>)143 b("greater)45 b(than/equal")g(.ge.)94
+b(.GE.)h(>=)47 b(=>)191 4601 y("or")572 b(.or.)46 b(.OR.)h(||)95
+b("and")762 b(.and.)46 b(.AND.)h(&&)191 4713 y("negation")236
+b(.not.)46 b(.NOT.)h(!)95 b("approx.)45 b(equal\(1e-7\)")92
+b(~)0 4989 y Fj(Note)32 b(that)g(the)f(exclamation)g(p)s(oin)m(t,)f(')
+10 b(!',)33 b(is)d(a)h(sp)s(ecial)e(UNIX)j(c)m(haracter,)h(so)e(if)f
+(it)g(is)g(used)g(on)h(the)g(command)0 5102 y(line)g(rather)h(than)h
+(en)m(tered)g(at)g(a)g(task)g(prompt,)g(it)f(m)m(ust)g(b)s(e)g
+(preceded)h(b)m(y)f(a)h(bac)m(kslash)f(to)i(force)f(the)g(UNIX)0
+5215 y(shell)c(to)i(ignore)f(it.)0 5375 y(The)i(expression)f(ma)m(y)j
+(also)e(include)e(arithmetic)i(op)s(erators)h(and)f(functions.)46
+b(T)-8 b(rigonometric)32 b(functions)f(use)0 5488 y(radians,)22
+b(not)h(degrees.)38 b(The)22 b(follo)m(wing)e(arithmetic)h(op)s
+(erators)i(and)e(functions)f(can)j(b)s(e)e(used)g(in)g(the)h
+(expression)0 5601 y(\(function)37 b(names)g(are)h(case)g(insensitiv)m
+(e\).)61 b(A)37 b(n)m(ull)f(v)-5 b(alue)37 b(will)d(b)s(e)j(returned)g
+(in)f(case)i(of)g(illegal)e(op)s(erations)0 5714 y(suc)m(h)30
+b(as)h(divide)d(b)m(y)i(zero,)i(sqrt\(negativ)m(e\))g(log\(negativ)m
+(e\),)g(log10\(negativ)m(e\),)i(arccos\(.gt.)43 b(1\),)32
+b(arcsin\(.gt.)41 b(1\).)p eop
+%%Page: 120 128
+120 127 bop 0 299 a Fj(120)1528 b Fh(CHAPTER)29 b(10.)113
+b(EXTENDED)30 b(FILE)h(NAME)f(SYNT)-8 b(AX)191 555 y
+Fe("addition")474 b(+)j("subtraction")d(-)191 668 y("multiplication")
+186 b(*)477 b("division")618 b(/)191 781 y("negation")474
+b(-)j("exponentiation")330 b(**)143 b(^)191 894 y("absolute)45
+b(value")189 b(abs\(x\))237 b("cosine")762 b(cos\(x\))191
+1007 y("sine")666 b(sin\(x\))237 b("tangent")714 b(tan\(x\))191
+1120 y("arc)47 b(cosine")379 b(arccos\(x\))93 b("arc)47
+b(sine")667 b(arcsin\(x\))191 1233 y("arc)47 b(tangent")331
+b(arctan\(x\))93 b("arc)47 b(tangent")523 b(arctan2\(x,y\))191
+1346 y("hyperbolic)45 b(cos")189 b(cosh\(x\))g("hyperbolic)45
+b(sin")381 b(sinh\(x\))191 1458 y("hyperbolic)45 b(tan")189
+b(tanh\(x\))g("round)47 b(to)g(nearest)f(int")94 b(round\(x\))191
+1571 y("round)46 b(down)h(to)g(int")f(floor\(x\))141
+b("round)47 b(up)g(to)g(int")333 b(ceil\(x\))191 1684
+y("exponential")d(exp\(x\))237 b("square)46 b(root")524
+b(sqrt\(x\))191 1797 y("natural)45 b(log")333 b(log\(x\))237
+b("common)46 b(log")572 b(log10\(x\))191 1910 y("modulus")522
+b(i)48 b(\045)f(j)286 b("random)46 b(#)i([0.0,1.0\)")188
+b(random\(\))191 2023 y("minimum")522 b(min\(x,y\))141
+b("maximum")714 b(max\(x,y\))191 2136 y("cumulative)45
+b(sum")189 b(accum\(x\))141 b("sequential)45 b(difference")g
+(seqdiff\(x\))191 2249 y("if-then-else")282 b(b?x:y)0
+2484 y Fj(An)31 b(alternate)h(syn)m(tax)g(for)f(the)g(min)f(and)h(max)g
+(functions)f(has)h(only)f(a)i(single)e(argumen)m(t)i(whic)m(h)e(should)
+f(b)s(e)i(a)0 2597 y(v)m(ector)g(v)-5 b(alue)29 b(\(see)h(b)s(elo)m
+(w\).)40 b(The)29 b(result)f(will)f(b)s(e)h(the)i(minim)m(um/maxim)m
+(um)c(elemen)m(t)j(con)m(tained)h(within)d(the)0 2710
+y(v)m(ector.)0 2870 y(The)35 b(accum\(x\))i(function)e(forms)g(the)h
+(cum)m(ulativ)m(e)g(sum)f(of)h(x,)h(elemen)m(t)g(b)m(y)f(elemen)m(t.)57
+b(V)-8 b(ector)38 b(columns)d(are)0 2983 y(supp)s(orted)i(simply)f(b)m
+(y)i(p)s(erforming)e(the)j(summation)f(pro)s(cess)g(through)f(all)h
+(the)h(v)-5 b(alues.)64 b(Null)37 b(v)-5 b(alues)38 b(are)0
+3096 y(treated)30 b(as)f(0.)41 b(The)29 b(seqdi\013\(x\))g(function)e
+(forms)i(the)g(sequen)m(tial)g(di\013erence)f(of)i(x,)f(elemen)m(t)h(b)
+m(y)f(elemen)m(t.)40 b(The)0 3209 y(\014rst)c(v)-5 b(alue)37
+b(of)g(seqdi\013)f(is)g(the)h(\014rst)g(v)-5 b(alue)36
+b(of)h(x.)61 b(A)37 b(single)f(n)m(ull)f(v)-5 b(alue)37
+b(in)e(x)i(causes)h(a)f(pair)f(of)h(n)m(ulls)e(in)h(the)0
+3322 y(output.)55 b(The)35 b(seqdi\013)f(and)h(accum)g(functions)f(are)
+i(functional)d(in)m(v)m(erses,)k(i.e.,)g(seqdi\013\(accum\(x\)\))f(==)f
+(x)g(as)0 3435 y(long)30 b(as)h(no)f(n)m(ull)e(v)-5 b(alues)30
+b(are)h(presen)m(t.)0 3595 y(The)38 b(follo)m(wing)f(t)m(yp)s(e)i
+(casting)g(op)s(erators)g(are)g(a)m(v)-5 b(ailable,)41
+b(where)d(the)h(inclosing)e(paren)m(theses)i(are)g(required)0
+3708 y(and)30 b(tak)m(en)h(from)f(the)h(C)f(language)g(usage.)42
+b(Also,)30 b(the)h(in)m(teger)f(to)i(real)e(casts)h(v)-5
+b(alues)29 b(to)j(double)d(precision:)764 3944 y Fe("real)46
+b(to)h(integer")189 b(\(int\))46 b(x)239 b(\(INT\))46
+b(x)764 4057 y("integer)f(to)i(real")190 b(\(float\))46
+b(i)143 b(\(FLOAT\))45 b(i)0 4292 y Fj(In)30 b(addition,)e(sev)m(eral)j
+(constan)m(ts)h(are)f(built)d(in)h(for)h(use)g(in)f(n)m(umerical)g
+(expressions:)382 4528 y Fe(#pi)667 b(3.1415...)284 b(#e)620
+b(2.7182...)382 4641 y(#deg)f(#pi/180)380 b(#row)524
+b(current)46 b(row)h(number)382 4754 y(#null)428 b(undefined)45
+b(value)142 b(#snull)428 b(undefined)45 b(string)0 4989
+y Fj(A)40 b(string)e(constan)m(t)j(m)m(ust)e(b)s(e)g(enclosed)g(in)g
+(quotes)h(as)f(in)g('Crab'.)67 b(The)39 b("n)m(ull")g(constan)m(ts)h
+(are)g(useful)e(for)0 5102 y(conditionally)d(setting)j(table)g(v)-5
+b(alues)37 b(to)h(a)g(NULL,)g(or)g(unde\014ned,)f(v)-5
+b(alue)38 b(\(eg.,)j("col1==-99)e(?)62 b(#NULL)38 b(:)0
+5215 y(col1"\).)0 5375 y(There)27 b(is)f(also)i(a)f(function)f(for)i
+(testing)f(if)f(t)m(w)m(o)j(v)-5 b(alues)27 b(are)h(close)f(to)i(eac)m
+(h)f(other,)h(i.e.,)f(if)e(they)i(are)g("near")g(eac)m(h)0
+5488 y(other)c(to)h(within)c(a)j(user)g(sp)s(eci\014ed)e(tolerance.)39
+b(The)24 b(argumen)m(ts,)h(v)-5 b(alue)p 2503 5488 28
+4 v 33 w(1)24 b(and)f(v)-5 b(alue)p 2980 5488 V 32 w(2)25
+b(can)f(b)s(e)f(in)m(teger)h(or)g(real)0 5601 y(and)32
+b(represen)m(t)h(the)g(t)m(w)m(o)h(v)-5 b(alues)32 b(who's)g(pro)m
+(ximit)m(y)g(is)g(b)s(eing)f(tested)i(to)h(b)s(e)e(within)e(the)j(sp)s
+(eci\014ed)e(tolerance,)0 5714 y(also)f(an)h(in)m(teger)f(or)h(real:)p
+eop
+%%Page: 121 129
+121 128 bop 0 299 a Fh(10.10.)73 b(R)m(O)m(W)31 b(FIL)-8
+b(TERING)31 b(SPECIFICA)-8 b(TION)1936 b Fj(121)955 555
+y Fe(near\(value_1,)44 b(value_2,)h(tolerance\))0 781
+y Fj(When)24 b(a)i(NULL,)e(or)h(unde\014ned,)f(v)-5 b(alue)24
+b(is)g(encoun)m(tered)h(in)f(the)g(FITS)g(table,)i(the)f(expression)f
+(will)e(ev)-5 b(aluate)25 b(to)0 894 y(NULL)31 b(unless)e(the)i
+(unde\014ned)e(v)-5 b(alue)30 b(is)g(not)h(actually)f(required)f(for)i
+(ev)-5 b(aluation,)31 b(e.g.)43 b("TR)m(UE)31 b(.or.)43
+b(NULL")0 1006 y(ev)-5 b(aluates)31 b(to)g(TR)m(UE.)g(The)f(follo)m
+(wing)e(t)m(w)m(o)k(functions)d(allo)m(w)h(some)h(NULL)f(detection)h
+(and)f(handling:)430 1232 y Fe("a)47 b(null)f(value?")667
+b(ISNULL\(x\))430 1345 y("define)45 b(a)j(value)e(for)h(null")190
+b(DEFNULL\(x,y\))0 1570 y Fj(The)36 b(former)h(returns)e(a)i(b)s(o)s
+(olean)f(v)-5 b(alue)36 b(of)h(TR)m(UE)g(if)f(the)h(argumen)m(t)g(x)g
+(is)f(NULL.)h(The)f(later)h("de\014nes")g(a)0 1683 y(v)-5
+b(alue)34 b(to)h(b)s(e)e(substituted)g(for)h(NULL)g(v)-5
+b(alues;)36 b(it)e(returns)f(the)h(v)-5 b(alue)34 b(of)g(x)g(if)f(x)i
+(is)e(not)h(NULL,)h(otherwise)e(it)0 1796 y(returns)c(the)i(v)-5
+b(alue)30 b(of)g(y)-8 b(.)0 2081 y Fd(10.10.2)113 b(Bit)35
+b(Masks)0 2300 y Fj(Bit)g(masks)g(can)h(b)s(e)f(used)f(to)i(select)g
+(out)f(ro)m(ws)h(from)e(bit)h(columns)f(\(TF)m(ORMn)h(=)g(#X\))h(in)e
+(FITS)g(\014les.)54 b(T)-8 b(o)0 2413 y(represen)m(t)30
+b(the)h(mask,)g(binary)-8 b(,)29 b(o)s(ctal,)i(and)f(hex)g(formats)g
+(are)h(allo)m(w)m(ed:)811 2638 y Fe(binary:)142 b
+(b0110xx1010000101xxxx00)o(01)811 2751 y(octal:)190 b(o720x1)46
+b(->)h(\(b111010000xxx001\))811 2864 y(hex:)286 b(h0FxD)94
+b(->)47 b(\(b00001111xxxx1101\))0 3090 y Fj(In)22 b(all)g(the)h
+(represen)m(tations,)i(an)d(x)h(or)g(X)g(is)f(allo)m(w)m(ed)h(in)e(the)
+i(mask)g(as)g(a)h(wild)c(card.)38 b(Note)25 b(that)e(the)g(x)g
+(represen)m(ts)0 3203 y(a)k(di\013eren)m(t)g(n)m(um)m(b)s(er)f(of)h
+(wild)d(card)j(bits)f(in)g(eac)m(h)i(represen)m(tation.)40
+b(All)25 b(represen)m(tations)i(are)h(case)g(insensitiv)m(e.)0
+3363 y(T)-8 b(o)28 b(construct)g(the)g(b)s(o)s(olean)e(expression)h
+(using)f(the)i(mask)f(as)h(the)g(b)s(o)s(olean)e(equal)h(op)s(erator)h
+(describ)s(ed)e(ab)s(o)m(v)m(e)0 3476 y(on)34 b(a)h(bit)f(table)h
+(column.)52 b(F)-8 b(or)35 b(example,)h(if)d(y)m(ou)i(had)f(a)h(7)g
+(bit)f(column)f(named)h(\015ags)h(in)e(a)i(FITS)f(table)h(and)0
+3589 y(w)m(an)m(ted)c(all)e(ro)m(ws)i(ha)m(ving)f(the)g(bit)g(pattern)g
+(0010011,)k(the)c(selection)h(expression)e(w)m(ould)g(b)s(e:)1336
+3814 y Fe(flags)47 b(==)g(b0010011)191 3927 y(or)1336
+4040 y(flags)g(.eq.)f(b10011)0 4265 y Fj(It)35 b(is)f(also)h(p)s
+(ossible)d(to)k(test)g(if)e(a)h(range)g(of)g(bits)f(is)g(less)g(than,)i
+(less)e(than)h(equal,)h(greater)g(than)e(and)h(greater)0
+4378 y(than)30 b(equal)g(to)h(a)g(particular)e(b)s(o)s(olean)g(v)-5
+b(alue:)1336 4604 y Fe(flags)47 b(<=)g(bxxx010xx)1336
+4717 y(flags)g(.gt.)f(bxxx100xx)1336 4829 y(flags)h(.le.)f(b1xxxxxxx)0
+5055 y Fj(Notice)31 b(the)g(use)f(of)h(the)f(x)g(bit)g(v)-5
+b(alue)30 b(to)h(limit)d(the)i(range)h(of)g(bits)e(b)s(eing)g
+(compared.)0 5215 y(It)j(is)g(not)g(necessary)h(to)g(sp)s(ecify)e(the)i
+(leading)e(\(most)i(signi\014can)m(t\))f(zero)h(\(0\))g(bits)e(in)g
+(the)i(mask,)g(as)g(sho)m(wn)e(in)0 5328 y(the)g(second)f(expression)f
+(ab)s(o)m(v)m(e.)0 5488 y(Bit)43 b(wise)f(AND,)i(OR)e(and)g(NOT)h(op)s
+(erations)f(are)h(also)g(p)s(ossible)d(on)j(t)m(w)m(o)h(or)f(more)g
+(bit)f(\014elds)f(using)h(the)0 5601 y('&'\(AND\),)35
+b(')p Fc(j)p Fj('\(OR\),)g(and)e(the)h(')10 b(!'\(NOT\))34
+b(op)s(erators.)51 b(All)32 b(of)h(these)h(op)s(erators)g(result)e(in)h
+(a)h(bit)e(\014eld)g(whic)m(h)0 5714 y(can)f(then)f(b)s(e)f(used)h
+(with)f(the)i(equal)f(op)s(erator.)41 b(F)-8 b(or)31
+b(example:)p eop
+%%Page: 122 130
+122 129 bop 0 299 a Fj(122)1528 b Fh(CHAPTER)29 b(10.)113
+b(EXTENDED)30 b(FILE)h(NAME)f(SYNT)-8 b(AX)1241 555 y
+Fe(\(!flags\))45 b(==)j(b1101100)1241 668 y(\(flags)e(&)h(b1000001\))f
+(==)h(bx000001)0 928 y Fj(Bit)34 b(\014elds)f(can)h(b)s(e)f(app)s
+(ended)g(as)h(w)m(ell)f(using)g(the)h('+')g(op)s(erator.)53
+b(Strings)32 b(can)j(b)s(e)e(concatenated)j(this)d(w)m(a)m(y)-8
+b(,)0 1041 y(to)s(o.)0 1331 y Fd(10.10.3)113 b(V)-9 b(ector)36
+b(Columns)0 1550 y Fj(V)-8 b(ector)37 b(columns)d(can)i(also)f(b)s(e)g
+(used)f(in)g(building)e(the)j(expression.)55 b(No)36
+b(sp)s(ecial)e(syn)m(tax)h(is)g(required)e(if)i(one)0
+1663 y(w)m(an)m(ts)46 b(to)f(op)s(erate)h(on)f(all)f(elemen)m(ts)h(of)g
+(the)h(v)m(ector.)86 b(Simply)42 b(use)j(the)g(column)f(name)h(as)g
+(for)g(a)g(scalar)0 1776 y(column.)c(V)-8 b(ector)32
+b(columns)e(can)h(b)s(e)f(freely)g(in)m(termixed)g(with)f(scalar)i
+(columns)e(or)i(constan)m(ts)h(in)e(virtually)e(all)0
+1889 y(expressions.)39 b(The)29 b(result)f(will)e(b)s(e)j(of)g(the)g
+(same)h(dimension)c(as)k(the)f(v)m(ector.)42 b(Tw)m(o)29
+b(v)m(ectors)i(in)d(an)h(expression,)0 2002 y(though,)f(need)e(to)i(ha)
+m(v)m(e)g(the)f(same)g(n)m(um)m(b)s(er)f(of)h(elemen)m(ts)g(and)f(ha)m
+(v)m(e)j(the)e(same)g(dimensions.)37 b(The)26 b(only)g(places)0
+2115 y(a)35 b(v)m(ector)h(column)d(cannot)i(b)s(e)f(used)f(\(for)i(no)m
+(w,)g(an)m(yw)m(a)m(y\))h(are)f(the)g(SA)m(O)f(region)g(functions)f
+(and)g(the)i(NEAR)0 2228 y(b)s(o)s(olean)29 b(function.)0
+2388 y(Arithmetic)22 b(and)g(logical)h(op)s(erations)f(are)i(all)e(p)s
+(erformed)f(on)i(an)g(elemen)m(t)g(b)m(y)g(elemen)m(t)h(basis.)37
+b(Comparing)22 b(t)m(w)m(o)0 2501 y(v)m(ector)32 b(columns,)d(eg)i
+("COL1)f(==)g(COL2",)g(th)m(us)g(results)f(in)g(another)h(v)m(ector)i
+(of)e(b)s(o)s(olean)g(v)-5 b(alues)29 b(indicating)0
+2614 y(whic)m(h)g(elemen)m(ts)i(of)f(the)h(t)m(w)m(o)h(v)m(ectors)f
+(are)g(equal.)0 2774 y(Eigh)m(t)f(functions)f(are)i(a)m(v)-5
+b(ailable)30 b(that)h(op)s(erate)g(on)f(a)h(v)m(ector)h(and)d(return)h
+(a)g(scalar)h(result:)191 3034 y Fe("minimum")284 b(MIN\(V\))475
+b("maximum")714 b(MAX\(V\))191 3147 y("average")284 b(AVERAGE\(V\))f
+("median")762 b(MEDIAN\(V\))191 3259 y("sumation")236
+b(SUM\(V\))475 b("standard)46 b(deviation")188 b(STDDEV\(V\))191
+3372 y("#)47 b(of)g(values")94 b(NELEM\(V\))379 b("#)48
+b(of)f(non-null)e(values")94 b(NVALID\(V\))0 3632 y Fj(where)40
+b(V)h(represen)m(ts)g(the)g(name)g(of)h(a)f(v)m(ector)h(column)e(or)h
+(a)h(man)m(ually)d(constructed)i(v)m(ector)i(using)c(curly)0
+3745 y(brac)m(k)m(ets)27 b(as)f(describ)s(ed)d(b)s(elo)m(w.)38
+b(The)25 b(\014rst)g(6)h(of)g(these)g(functions)e(ignore)h(an)m(y)h(n)m
+(ull)d(v)-5 b(alues)25 b(in)f(the)i(v)m(ector)h(when)0
+3858 y(computing)i(the)i(result.)0 4018 y(The)g(SUM)h(function)e
+(literally)g(sums)h(all)f(the)i(elemen)m(ts)g(in)f(x,)h(returning)e(a)i
+(scalar)g(v)-5 b(alue.)44 b(If)31 b(V)h(is)f(a)h(b)s(o)s(olean)0
+4131 y(v)m(ector,)40 b(SUM)c(returns)f(the)h(n)m(um)m(b)s(er)f(of)i(TR)
+m(UE)f(elemen)m(ts.)59 b(The)36 b(NELEM)g(function)f(returns)g(the)h(n)
+m(um)m(b)s(er)0 4244 y(of)h(elemen)m(ts)f(in)g(v)m(ector)i(V)e(whereas)
+h(NV)-10 b(ALID)36 b(return)g(the)h(n)m(um)m(b)s(er)e(of)h(non-n)m(ull)
+e(elemen)m(ts)j(in)e(the)i(v)m(ector.)0 4357 y(\(NELEM)28
+b(also)g(op)s(erates)g(on)g(bit)e(and)h(string)g(columns,)g(returning)f
+(their)h(column)f(widths.\))39 b(As)27 b(an)h(example,)0
+4470 y(to)42 b(test)g(whether)f(all)f(elemen)m(ts)i(of)g(t)m(w)m(o)g(v)
+m(ectors)h(satisfy)e(a)h(giv)m(en)f(logical)g(comparison,)i(one)f(can)g
+(use)f(the)0 4583 y(expression)668 4842 y Fe(SUM\()47
+b(COL1)f(>)i(COL2)f(\))g(==)g(NELEM\()f(COL1)h(\))0 5102
+y Fj(whic)m(h)31 b(will)e(return)i(TR)m(UE)h(if)f(all)g(elemen)m(ts)h
+(of)g(COL1)g(are)g(greater)h(than)f(their)f(corresp)s(onding)f(elemen)m
+(ts)i(in)0 5215 y(COL2.)0 5375 y(T)-8 b(o)32 b(sp)s(ecify)e(a)j(single)
+d(elemen)m(t)i(of)g(a)g(v)m(ector,)i(giv)m(e)e(the)g(column)e(name)i
+(follo)m(w)m(ed)f(b)m(y)h(a)g(comma-separated)h(list)0
+5488 y(of)c(co)s(ordinates)f(enclosed)h(in)e(square)i(brac)m(k)m(ets.)
+41 b(F)-8 b(or)30 b(example,)f(if)e(a)i(v)m(ector)i(column)c(named)i
+(PHAS)f(exists)g(in)0 5601 y(the)f(table)f(as)h(a)g(one)g(dimensional,)
+e(256)j(comp)s(onen)m(t)f(list)e(of)i(n)m(um)m(b)s(ers)e(from)h(whic)m
+(h)g(y)m(ou)h(w)m(an)m(ted)g(to)g(select)h(the)0 5714
+y(57th)k(comp)s(onen)m(t)g(for)f(use)g(in)f(the)i(expression,)e(then)i
+(PHAS[57])g(w)m(ould)e(do)i(the)f(tric)m(k.)44 b(Higher)31
+b(dimensional)p eop
+%%Page: 123 131
+123 130 bop 0 299 a Fh(10.10.)73 b(R)m(O)m(W)31 b(FIL)-8
+b(TERING)31 b(SPECIFICA)-8 b(TION)1936 b Fj(123)0 555
+y(arra)m(ys)41 b(of)h(data)f(ma)m(y)h(app)s(ear)f(in)e(a)j(column.)72
+b(But)41 b(in)f(order)g(to)i(in)m(terpret)e(them,)k(the)e(TDIMn)e(k)m
+(eyw)m(ord)0 668 y(m)m(ust)34 b(app)s(ear)g(in)f(the)h(header.)52
+b(Assuming)33 b(that)i(a)f(\(4,4,4,4\))k(arra)m(y)c(is)g(pac)m(k)m(ed)h
+(in)m(to)f(eac)m(h)i(ro)m(w)e(of)g(a)h(column)0 781 y(named)26
+b(ARRA)-8 b(Y4D,)28 b(the)f(\(1,2,3,4\))i(comp)s(onen)m(t)e(elemen)m(t)
+f(of)h(eac)m(h)g(ro)m(w)g(is)e(accessed)j(b)m(y)e(ARRA)-8
+b(Y4D[1,2,3,4].)0 894 y(Arra)m(ys)33 b(up)e(to)j(dimension)c(5)j(are)f
+(curren)m(tly)g(supp)s(orted.)46 b(Eac)m(h)33 b(v)m(ector)h(index)d
+(can)i(itself)e(b)s(e)h(an)h(expression,)0 1007 y(although)38
+b(it)g(m)m(ust)h(ev)-5 b(aluate)39 b(to)g(an)g(in)m(teger)g(v)-5
+b(alue)38 b(within)e(the)j(b)s(ounds)d(of)j(the)g(v)m(ector.)67
+b(V)-8 b(ector)40 b(columns)0 1120 y(whic)m(h)30 b(con)m(tain)h(spaces)
+h(or)f(arithmetic)f(op)s(erators)i(m)m(ust)f(ha)m(v)m(e)h(their)e
+(names)h(enclosed)g(in)f("$")i(c)m(haracters)h(as)0 1233
+y(with)c($ARRA)-8 b(Y-4D$[1,2,3,4].)0 1393 y(A)45 b(more)f(C-lik)m(e)g
+(syn)m(tax)i(for)e(sp)s(ecifying)e(v)m(ector)47 b(indices)42
+b(is)i(also)h(a)m(v)-5 b(ailable.)82 b(The)45 b(elemen)m(t)g(used)e(in)
+h(the)0 1506 y(preceding)27 b(example)h(alternativ)m(ely)g(could)f(b)s
+(e)h(sp)s(eci\014ed)f(with)f(the)j(syn)m(tax)g(ARRA)-8
+b(Y4D[4][3][2][1].)45 b(Note)30 b(the)0 1619 y(rev)m(erse)40
+b(order)f(of)h(indices)d(\(as)j(in)e(C\),)i(as)f(w)m(ell)g(as)g(the)h
+(fact)g(that)g(the)g(v)-5 b(alues)39 b(are)g(still)f(ones-based)h(\(as)
+h(in)0 1732 y(F)-8 b(ortran)39 b({)g(adopted)g(to)g(a)m(v)m(oid)g(am)m
+(biguit)m(y)f(for)h(1D)g(v)m(ectors\).)67 b(With)38 b(this)g(syn)m
+(tax,)j(one)e(do)s(es)f(not)h(need)f(to)0 1844 y(sp)s(ecify)29
+b(all)g(of)i(the)f(indices.)39 b(T)-8 b(o)31 b(extract)h(a)f(3D)g
+(slice)e(of)i(this)e(4D)i(arra)m(y)-8 b(,)32 b(use)e(ARRA)-8
+b(Y4D[4].)0 2005 y(V)g(ariable-length)30 b(v)m(ector)i(columns)d(are)h
+(not)h(supp)s(orted.)0 2165 y(V)-8 b(ectors)24 b(can)e(b)s(e)f(man)m
+(ually)f(constructed)j(within)c(the)j(expression)f(using)f(a)i
+(comma-separated)i(list)d(of)h(elemen)m(ts)0 2278 y(surrounded)35
+b(b)m(y)j(curly)f(braces)i(\(')p Fc(fg)p Fj('\).)66 b(F)-8
+b(or)38 b(example,)i(')p Fc(f)p Fj(1,3,6,1)p Fc(g)p Fj(')i(is)c(a)g
+(4-elemen)m(t)h(v)m(ector)h(con)m(taining)e(the)0 2391
+y(v)-5 b(alues)25 b(1,)i(3,)g(6,)g(and)e(1.)40 b(The)25
+b(v)m(ector)i(can)f(con)m(tain)g(only)f(b)s(o)s(olean,)g(in)m(teger,)j
+(and)d(real)g(v)-5 b(alues)25 b(\(or)h(expressions\).)0
+2503 y(The)c(elemen)m(ts)h(will)d(b)s(e)i(promoted)h(to)g(the)g
+(highest)f(data)h(t)m(yp)s(e)g(presen)m(t.)38 b(An)m(y)22
+b(elemen)m(ts)h(whic)m(h)f(are)h(themselv)m(es)0 2616
+y(v)m(ectors,)40 b(will)34 b(b)s(e)i(expanded)g(out)h(with)f(eac)m(h)h
+(of)g(its)f(elemen)m(ts)i(b)s(ecoming)d(an)i(elemen)m(t)g(in)f(the)h
+(constructed)0 2729 y(v)m(ector.)0 3032 y Fd(10.10.4)113
+b(Go)s(o)s(d)38 b(Time)e(In)m(terv)-6 b(al)36 b(Filtering)0
+3254 y Fj(A)44 b(common)g(\014ltering)f(metho)s(d)g(in)m(v)m(olv)m(es)h
+(selecting)g(ro)m(ws)g(whic)m(h)e(ha)m(v)m(e)k(a)e(time)g(v)-5
+b(alue)43 b(whic)m(h)g(lies)f(within)0 3367 y(what)37
+b(is)f(called)h(a)h(Go)s(o)s(d)f(Time)f(In)m(terv)-5
+b(al)37 b(or)g(GTI.)g(The)g(time)g(in)m(terv)-5 b(als)36
+b(are)i(de\014ned)e(in)g(a)h(separate)i(FITS)0 3480 y(table)h
+(extension)g(whic)m(h)e(con)m(tains)i(2)h(columns)e(giving)f(the)j
+(start)f(and)g(stop)g(time)f(of)h(eac)m(h)i(go)s(o)s(d)e(in)m(terv)-5
+b(al.)0 3592 y(The)34 b(\014ltering)f(op)s(eration)i(accepts)h(only)d
+(those)j(ro)m(ws)e(of)h(the)g(input)e(table)i(whic)m(h)e(ha)m(v)m(e)j
+(an)f(asso)s(ciated)g(time)0 3705 y(whic)m(h)f(falls)h(within)e(one)j
+(of)g(the)g(time)f(in)m(terv)-5 b(als)35 b(de\014ned)g(in)f(the)i(GTI)g
+(extension.)56 b(A)36 b(high)f(lev)m(el)g(function,)0
+3818 y(gti\014lter\(a,b,c,d\),)42 b(is)d(a)m(v)-5 b(ailable)39
+b(whic)m(h)f(ev)-5 b(aluates)40 b(eac)m(h)h(ro)m(w)e(of)h(the)f(input)f
+(table)h(and)g(returns)f(TR)m(UE)i(or)0 3931 y(F)-10
+b(ALSE)30 b(dep)s(ending)e(whether)i(the)g(ro)m(w)h(is)e(inside)f(or)i
+(outside)g(the)h(go)s(o)s(d)f(time)g(in)m(terv)-5 b(al.)40
+b(The)30 b(syn)m(tax)h(is)286 4202 y Fe(gtifilter\()45
+b([)j("gtifile")d([,)i(expr)g([,)g("STARTCOL",)e("STOPCOL")g(])j(])f(])
+g(\))191 4314 y(or)286 4427 y(gtifilter\()e([)j('gtifile')d([,)i(expr)g
+([,)g('STARTCOL',)e('STOPCOL')g(])j(])f(])g(\))0 4698
+y Fj(where)20 b(eac)m(h)h("[]")h(demarks)e(optional)f(parameters.)38
+b(Note)21 b(that)g(the)g(quotes)f(around)g(the)g(gti\014le)g(and)f(ST)
+-8 b(AR)g(T/STOP)0 4811 y(column)32 b(are)i(required.)49
+b(Either)33 b(single)f(or)i(double)e(quotes)i(ma)m(y)g(b)s(e)f(used.)50
+b(In)33 b(cases)h(where)g(this)e(expression)0 4924 y(is)d(en)m(tered)h
+(on)g(the)g(Unix)f(command)h(line,)e(enclose)i(the)g(en)m(tire)g
+(expression)f(in)f(double)h(quotes,)h(and)g(then)f(use)0
+5036 y(single)23 b(quotes)i(within)c(the)k(expression)e(to)i(enclose)f
+(the)h('gti\014le')f(and)f(other)i(terms.)38 b(It)25
+b(is)e(also)h(usually)e(p)s(ossible)0 5149 y(to)38 b(do)e(the)h(rev)m
+(erse,)j(and)c(enclose)h(the)g(whole)f(expression)g(in)f(single)h
+(quotes)h(and)f(then)h(use)f(double)f(quotes)0 5262 y(within)c(the)i
+(expression.)49 b(The)33 b(gti\014le,)g(if)g(sp)s(eci\014ed,)f(can)i(b)
+s(e)f(blank)f(\(""\))j(whic)m(h)d(will)e(mean)k(to)g(use)f(the)h
+(\014rst)0 5375 y(extension)f(with)g(the)g(name)h("*GTI*")h(in)e(the)g
+(curren)m(t)h(\014le,)g(a)g(plain)d(extension)i(sp)s(eci\014er)f(\(eg,)
+k("+2",)g("[2]",)0 5488 y(or)30 b("[STDGTI]"\))i(whic)m(h)d(will)f(b)s
+(e)i(used)f(to)j(select)f(an)f(extension)g(in)f(the)i(curren)m(t)f
+(\014le,)g(or)g(a)h(regular)f(\014lename)0 5601 y(with)f(or)i(without)e
+(an)i(extension)f(sp)s(eci\014er)f(whic)m(h)g(in)g(the)i(latter)g(case)
+g(will)d(mean)i(to)i(use)e(the)h(\014rst)e(extension)0
+5714 y(with)36 b(an)h(extension)f(name)i("*GTI*".)62
+b(Expr)36 b(can)h(b)s(e)g(an)m(y)g(arithmetic)g(expression,)g
+(including)d(simply)h(the)p eop
+%%Page: 124 132
+124 131 bop 0 299 a Fj(124)1528 b Fh(CHAPTER)29 b(10.)113
+b(EXTENDED)30 b(FILE)h(NAME)f(SYNT)-8 b(AX)0 555 y Fj(time)35
+b(column)g(name.)57 b(A)36 b(v)m(ector)h(time)f(expression)e(will)f
+(pro)s(duce)i(a)h(v)m(ector)h(b)s(o)s(olean)e(result.)56
+b(ST)-8 b(AR)g(TCOL)0 668 y(and)27 b(STOPCOL)f(are)i(the)g(names)g(of)g
+(the)g(ST)-8 b(AR)g(T/STOP)26 b(columns)h(in)f(the)i(GTI)g(extension.)
+40 b(If)27 b(one)h(of)g(them)0 781 y(is)h(sp)s(eci\014ed,)g(they)i(b)s
+(oth)f(m)m(ust)g(b)s(e.)0 941 y(In)21 b(its)g(simplest)f(form,)k(no)d
+(parameters)h(need)g(to)h(b)s(e)e(pro)m(vided)f({)i(default)f(v)-5
+b(alues)21 b(will)f(b)s(e)h(used.)37 b(The)21 b(expression)0
+1054 y("gti\014lter\(\)")31 b(is)f(equiv)-5 b(alen)m(t)29
+b(to)334 1322 y Fe(gtifilter\()45 b("",)i(TIME,)f("*START*",)f
+("*STOP*")h(\))0 1590 y Fj(This)30 b(will)e(searc)m(h)k(the)g(curren)m
+(t)f(\014le)f(for)h(a)h(GTI)f(extension,)g(\014lter)g(the)g(TIME)g
+(column)f(in)g(the)i(curren)m(t)f(table,)0 1703 y(using)i(ST)-8
+b(AR)g(T/STOP)34 b(times)h(tak)m(en)g(from)g(columns)e(in)h(the)h(GTI)g
+(extension)f(with)g(names)g(con)m(taining)h(the)0 1816
+y(strings)c("ST)-8 b(AR)g(T")33 b(and)e("STOP".)46 b(The)32
+b(wildcards)d(\('*'\))34 b(allo)m(w)e(sligh)m(t)f(v)-5
+b(ariations)31 b(in)g(naming)g(con)m(v)m(en)m(tions)0
+1929 y(suc)m(h)38 b(as)g("TST)-8 b(AR)g(T")39 b(or)f("ST)-8
+b(AR)g(TTIME".)65 b(The)37 b(same)i(default)f(v)-5 b(alues)37
+b(apply)g(for)h(unsp)s(eci\014ed)e(parame-)0 2042 y(ters)g(when)f(the)h
+(\014rst)f(one)i(or)f(t)m(w)m(o)h(parameters)f(are)h(sp)s(eci\014ed.)55
+b(The)36 b(function)e(automatically)i(searc)m(hes)h(for)0
+2154 y(TIMEZER)m(O/I/F)g(k)m(eyw)m(ords)f(in)f(the)i(curren)m(t)f(and)g
+(GTI)g(extensions,)h(applying)e(a)h(relativ)m(e)h(time)f(o\013set,)j
+(if)0 2267 y(necessary)-8 b(.)0 2568 y Fd(10.10.5)113
+b(Spatial)36 b(Region)h(Filtering)0 2788 y Fj(Another)h(common)g
+(\014ltering)e(metho)s(d)h(selects)h(ro)m(ws)g(based)g(on)f(whether)h
+(the)g(spatial)f(p)s(osition)e(asso)s(ciated)0 2901 y(with)c(eac)m(h)j
+(ro)m(w)e(is)g(lo)s(cated)h(within)d(a)j(giv)m(en)f(2-dimensional)e
+(region.)47 b(The)32 b(syn)m(tax)h(for)f(this)g(high-lev)m(el)f
+(\014lter)0 3014 y(is)334 3282 y Fe(regfilter\()45 b("regfilename")f([)
+k(,)f(Xexpr,)f(Yexpr)h([)g(,)h("wcs)e(cols")h(])g(])g(\))0
+3550 y Fj(where)22 b(eac)m(h)i("[]")g(demarks)e(optional)g(parameters.)
+38 b(The)22 b(region)g(\014le)g(name)g(is)g(required)f(and)h(m)m(ust)g
+(b)s(e)g(enclosed)0 3663 y(in)38 b(quotes.)70 b(The)39
+b(remaining)f(parameters)i(are)g(optional.)68 b(The)39
+b(region)g(\014le)g(is)g(an)g(ASCI)s(I)g(text)h(\014le)f(whic)m(h)0
+3776 y(con)m(tains)30 b(a)f(list)f(of)i(one)f(or)h(more)f(geometric)i
+(shap)s(es)d(\(circle,)i(ellipse,)d(b)s(o)m(x,)j(etc.\))42
+b(whic)m(h)28 b(de\014nes)g(a)i(region)f(on)0 3889 y(the)i(celestial)f
+(sphere)g(or)h(an)g(area)g(within)d(a)j(particular)f(2D)h(image.)42
+b(The)30 b(region)h(\014le)f(is)f(t)m(ypically)h(generated)0
+4002 y(using)21 b(an)i(image)g(displa)m(y)e(program)i(suc)m(h)f(as)h
+(fv/PO)m(W)h(\(distribute)c(b)m(y)j(the)g(HEASAR)m(C\),)g(or)g(ds9)g
+(\(distributed)0 4115 y(b)m(y)k(the)g(Smithsonian)d(Astroph)m(ysical)i
+(Observ)-5 b(atory\).)39 b(Users)27 b(should)e(refer)h(to)i(the)f(do)s
+(cumen)m(tation)f(pro)m(vided)0 4228 y(with)j(these)i(programs)f(for)g
+(more)h(details)e(on)h(the)h(syn)m(tax)g(used)e(in)g(the)i(region)f
+(\014les.)0 4388 y(In)44 b(its)g(simpliest)e(form,)47
+b(\(e.g.,)j(reg\014lter\("region.reg"\))c(\))f(the)g(co)s(ordinates)f
+(in)f(the)i(default)e('X')i(and)f('Y')0 4501 y(columns)32
+b(will)e(b)s(e)i(used)g(to)i(determine)e(if)f(eac)m(h)j(ro)m(w)f(is)f
+(inside)f(or)i(outside)f(the)h(area)h(sp)s(eci\014ed)d(in)g(the)i
+(region)0 4613 y(\014le.)40 b(Alternate)31 b(p)s(osition)d(column)h
+(names,)i(or)f(expressions,)f(ma)m(y)i(b)s(e)f(en)m(tered)h(if)e
+(needed,)i(as)f(in)382 4881 y Fe(regfilter\("region.reg",)41
+b(XPOS,)47 b(YPOS\))0 5149 y Fj(Region)36 b(\014ltering)e(can)i(b)s(e)f
+(applied)e(most)j(unam)m(biguously)d(if)i(the)h(p)s(ositions)e(in)g
+(the)i(region)f(\014le)g(and)g(in)g(the)0 5262 y(table)g(to)h(b)s(e)e
+(\014ltered)g(are)i(b)s(oth)e(giv)m(e)i(in)e(terms)h(of)g(absolute)g
+(celestial)g(co)s(ordinate)g(units.)53 b(In)35 b(this)f(case)i(the)0
+5375 y(lo)s(cations)24 b(and)f(sizes)h(of)h(the)f(geometric)h(shap)s
+(es)f(in)f(the)h(region)g(\014le)f(are)i(sp)s(eci\014ed)e(in)g(angular)
+g(units)g(on)h(the)g(sky)0 5488 y(\(e.g.,)32 b(p)s(ositions)c(giv)m(en)
+j(in)e(R.A.)h(and)g(Dec.)42 b(and)30 b(sizes)g(in)f(arcseconds)h(or)h
+(arcmin)m(utes\).)40 b(Similarly)-8 b(,)27 b(eac)m(h)32
+b(ro)m(w)0 5601 y(of)h(the)h(\014ltered)e(table)h(will)d(ha)m(v)m(e)35
+b(a)e(celestial)g(co)s(ordinate)g(asso)s(ciated)g(with)f(it.)49
+b(This)31 b(asso)s(ciation)i(is)f(usually)0 5714 y(implemen)m(ted)37
+b(using)f(a)j(set)g(of)f(so-called)g('W)-8 b(orld)38
+b(Co)s(ordinate)g(System')g(\(or)h(W)m(CS\))f(FITS)g(k)m(eyw)m(ords)g
+(that)p eop
+%%Page: 125 133
+125 132 bop 0 299 a Fh(10.10.)73 b(R)m(O)m(W)31 b(FIL)-8
+b(TERING)31 b(SPECIFICA)-8 b(TION)1936 b Fj(125)0 555
+y(de\014ne)27 b(the)g(co)s(ordinate)g(transformation)g(that)h(m)m(ust)f
+(b)s(e)f(applied)f(to)j(the)g(v)-5 b(alues)26 b(in)g(the)i('X')g(and)e
+('Y')i(columns)0 668 y(to)j(calculate)g(the)f(co)s(ordinate.)0
+828 y(Alternativ)m(ely)-8 b(,)27 b(one)g(can)g(p)s(erform)e(spatial)h
+(\014ltering)e(using)h(unitless)g('pixel')g(co)s(ordinates)i(for)f(the)
+h(regions)f(and)0 941 y(ro)m(w)33 b(p)s(ositions.)47
+b(In)33 b(this)f(case)i(the)f(user)g(m)m(ust)g(b)s(e)f(careful)g(to)i
+(ensure)f(that)g(the)h(p)s(ositions)d(in)h(the)h(2)g(\014les)g(are)0
+1054 y(self-consisten)m(t.)52 b(A)34 b(t)m(ypical)g(problem)e(is)h
+(that)i(the)f(region)g(\014le)f(ma)m(y)i(b)s(e)e(generated)j(using)c(a)
+j(binned)c(image,)0 1167 y(but)h(the)h(un)m(binned)d(co)s(ordinates)i
+(are)h(giv)m(en)g(in)e(the)i(ev)m(en)m(t)i(table.)47
+b(The)32 b(R)m(OSA)-8 b(T)33 b(ev)m(en)m(ts)h(\014les,)f(for)f
+(example,)0 1280 y(ha)m(v)m(e)f(X)f(and)f(Y)g(pixel)f(co)s(ordinates)h
+(that)i(range)f(from)f(1)h(-)g(15360.)42 b(These)30 b(co)s(ordinates)f
+(are)h(t)m(ypically)e(binned)0 1393 y(b)m(y)33 b(a)h(factor)g(of)f(32)h
+(to)g(pro)s(duce)e(a)i(480x480)i(pixel)31 b(image.)50
+b(If)32 b(one)i(then)f(uses)g(a)g(region)g(\014le)f(generated)i(from)0
+1506 y(this)29 b(image)i(\(in)f(image)g(pixel)f(units\))h(to)h
+(\014lter)e(the)i(R)m(OSA)-8 b(T)30 b(ev)m(en)m(ts)i(\014le,)e(then)g
+(the)h(X)g(and)f(Y)g(column)g(v)-5 b(alues)0 1619 y(m)m(ust)30
+b(b)s(e)g(con)m(v)m(erted)i(to)f(corresp)s(onding)d(pixel)h(units)g(as)
+h(in:)382 1885 y Fe(regfilter\("rosat.reg",)42 b(X/32.+.5,)j
+(Y/32.+.5\))0 2151 y Fj(Note)h(that)f(this)e(binning)e(con)m(v)m
+(ersion)k(is)e(not)i(necessary)g(if)e(the)i(region)f(\014le)f(is)h(sp)s
+(eci\014ed)e(using)h(celestial)0 2264 y(co)s(ordinate)h(units)f
+(instead)g(of)h(pixel)f(units)g(b)s(ecause)h(CFITSIO)e(is)i(then)f
+(able)h(to)h(directly)e(compare)i(the)0 2377 y(celestial)27
+b(co)s(ordinate)h(of)f(eac)m(h)i(ro)m(w)f(in)e(the)i(table)f(with)g
+(the)g(celestial)h(co)s(ordinates)f(in)f(the)i(region)f(\014le)g
+(without)0 2490 y(ha)m(ving)j(to)h(kno)m(w)f(an)m(ything)g(ab)s(out)g
+(ho)m(w)h(the)f(image)h(ma)m(y)g(ha)m(v)m(e)g(b)s(een)f(binned.)0
+2650 y(The)f(last)g("w)m(cs)h(cols")g(parameter)g(should)d(rarely)h(b)s
+(e)h(needed.)40 b(If)29 b(supplied,)d(this)j(string)f(con)m(tains)i
+(the)f(names)0 2763 y(of)37 b(the)g(2)h(columns)e(\(space)i(or)f(comma)
+g(separated\))h(whic)m(h)e(ha)m(v)m(e)i(the)g(asso)s(ciated)f(W)m(CS)g
+(k)m(eyw)m(ords.)61 b(If)37 b(not)0 2876 y(supplied,)d(the)i(\014lter)f
+(will)f(scan)i(the)g(X)g(and)f(Y)h(expressions)f(for)h(column)e(names.)
+58 b(If)35 b(only)g(one)i(is)e(found)f(in)0 2989 y(eac)m(h)e
+(expression,)d(those)i(columns)e(will)f(b)s(e)h(used,)h(otherwise)g(an)
+g(error)g(will)e(b)s(e)i(returned.)0 3149 y(These)g(region)g(shap)s(es)
+g(are)g(supp)s(orted)f(\(names)h(are)h(case)h(insensitiv)m(e\):)334
+3415 y Fe(Point)428 b(\()48 b(X1,)f(Y1)g(\))715 b(<-)48
+b(One)f(pixel)f(square)g(region)334 3528 y(Line)476 b(\()48
+b(X1,)f(Y1,)g(X2,)f(Y2)i(\))333 b(<-)48 b(One)f(pixel)f(wide)h(region)
+334 3641 y(Polygon)332 b(\()48 b(X1,)f(Y1,)g(X2,)f(Y2,)h(...)g(\))95
+b(<-)48 b(Rest)e(are)h(interiors)e(with)334 3754 y(Rectangle)236
+b(\()48 b(X1,)f(Y1,)g(X2,)f(Y2,)h(A)h(\))334 b(|)47 b(boundaries)e
+(considered)334 3867 y(Box)524 b(\()48 b(Xc,)f(Yc,)g(Wdth,)f(Hght,)g(A)
+i(\))143 b(V)47 b(within)f(the)h(region)334 3980 y(Diamond)332
+b(\()48 b(Xc,)f(Yc,)g(Wdth,)f(Hght,)g(A)i(\))334 4093
+y(Circle)380 b(\()48 b(Xc,)f(Yc,)g(R)g(\))334 4206 y(Annulus)332
+b(\()48 b(Xc,)f(Yc,)g(Rin,)f(Rout)h(\))334 4319 y(Ellipse)332
+b(\()48 b(Xc,)f(Yc,)g(Rx,)f(Ry,)h(A)h(\))334 4431 y(Elliptannulus)c(\()
+k(Xc,)f(Yc,)g(Rinx,)f(Riny,)g(Routx,)g(Routy,)g(Ain,)h(Aout)g(\))334
+4544 y(Sector)380 b(\()48 b(Xc,)f(Yc,)g(Amin,)f(Amax)h(\))0
+4811 y Fj(where)28 b(\(Xc,Yc\))j(is)c(the)i(co)s(ordinate)g(of)f(the)h
+(shap)s(e's)f(cen)m(ter;)j(\(X#,Y#\))e(are)g(the)g(co)s(ordinates)f(of)
+h(the)g(shap)s(e's)0 4924 y(edges;)39 b(Rxxx)c(are)g(the)h(shap)s(es')f
+(v)-5 b(arious)34 b(Radii)g(or)h(semima)5 b(jor/minor)34
+b(axes;)k(and)d(Axxx)g(are)h(the)g(angles)f(of)0 5036
+y(rotation)d(\(or)f(b)s(ounding)e(angles)i(for)g(Sector\))h(in)e
+(degrees.)44 b(F)-8 b(or)32 b(rotated)h(shap)s(es,)e(the)g(rotation)h
+(angle)f(can)h(b)s(e)0 5149 y(left)f(o\013,)i(indicating)c(no)i
+(rotation.)45 b(Common)31 b(alternate)h(names)f(for)h(the)f(regions)g
+(can)h(also)g(b)s(e)e(used:)43 b(rotb)s(o)m(x)0 5262
+y(=)29 b(b)s(o)m(x;)g(rotrectangle)h(=)f(rectangle;)h(\(rot\)rhom)m
+(bus)f(=)f(\(rot\)diamond;)i(and)e(pie)g(=)g(sector.)42
+b(When)28 b(a)i(shap)s(e's)0 5375 y(name)e(is)f(preceded)g(b)m(y)h(a)g
+(min)m(us)f(sign,)g('-',)j(the)e(de\014ned)e(region)i(is)f(instead)g
+(the)h(area)h(*outside*)f(its)f(b)s(oundary)0 5488 y(\(ie,)35
+b(the)f(region)g(is)f(in)m(v)m(erted\).)52 b(All)32 b(the)i(shap)s(es)f
+(within)f(a)i(single)f(region)g(\014le)h(are)g(OR'd)f(together)j(to)e
+(create)0 5601 y(the)29 b(region,)h(and)e(the)i(order)f(is)f
+(signi\014can)m(t.)39 b(The)29 b(o)m(v)m(erall)g(w)m(a)m(y)i(of)e(lo)s
+(oking)f(at)i(region)f(\014les)f(is)g(that)i(if)e(the)i(\014rst)0
+5714 y(region)e(is)g(an)h(excluded)f(region)g(then)g(a)i(dumm)m(y)d
+(included)f(region)j(of)g(the)g(whole)f(detector)i(is)e(inserted)f(in)h
+(the)p eop
+%%Page: 126 134
+126 133 bop 0 299 a Fj(126)1528 b Fh(CHAPTER)29 b(10.)113
+b(EXTENDED)30 b(FILE)h(NAME)f(SYNT)-8 b(AX)0 555 y Fj(fron)m(t.)40
+b(Then)25 b(eac)m(h)j(region)e(sp)s(eci\014cation)g(as)h(it)f(is)g(pro)
+s(cessed)g(o)m(v)m(errides)g(an)m(y)h(selections)g(inside)d(of)j(that)g
+(region)0 668 y(sp)s(eci\014ed)35 b(b)m(y)h(previous)f(regions.)58
+b(Another)37 b(w)m(a)m(y)g(of)g(thinking)d(ab)s(out)i(this)f(is)h(that)
+h(if)e(a)i(previous)e(excluded)0 781 y(region)30 b(is)f(completely)h
+(inside)f(of)h(a)h(subsequen)m(t)e(included)f(region)i(the)h(excluded)e
+(region)h(is)f(ignored.)0 941 y(The)44 b(p)s(ositional)f(co)s
+(ordinates)i(ma)m(y)g(b)s(e)g(giv)m(en)g(either)f(in)g(pixel)f(units,)k
+(decimal)d(degrees)i(or)f(hh:mm:ss.s,)0 1054 y(dd:mm:ss.s)25
+b(units.)37 b(The)26 b(shap)s(e)f(sizes)h(ma)m(y)g(b)s(e)g(giv)m(en)g
+(in)e(pixels,)i(degrees,)h(arcmin)m(utes,)g(or)f(arcseconds.)40
+b(Lo)s(ok)0 1167 y(at)31 b(examples)f(of)g(region)g(\014le)g(pro)s
+(duced)e(b)m(y)i(fv/PO)m(W)h(or)g(ds9)f(for)g(further)f(details)g(of)i
+(the)f(region)g(\014le)f(format.)0 1327 y(There)37 b(are)g(three)g
+(functions)f(that)h(are)h(primarily)c(for)i(use)h(with)f(SA)m(O)h
+(region)f(\014les)g(and)h(the)g(FSA)m(OI)g(task,)0 1440
+y(but)e(they)h(can)h(b)s(e)e(used)g(directly)-8 b(.)57
+b(They)36 b(return)f(a)h(b)s(o)s(olean)f(true)h(or)g(false)f(dep)s
+(ending)f(on)i(whether)f(a)i(t)m(w)m(o)0 1553 y(dimensional)28
+b(p)s(oin)m(t)h(is)g(in)g(the)i(region)f(or)g(not:)191
+1815 y Fe("point)46 b(in)h(a)h(circular)d(region")477
+1927 y(circle\(xcntr,ycntr,radius)o(,Xco)o(lumn)o(,Yc)o(olum)o(n\))191
+2153 y("point)h(in)h(an)g(elliptical)e(region")430 2266
+y(ellipse\(xcntr,ycntr,xhl)o(f_w)o(dth,)o(yhlf)o(_wd)o(th,r)o(otat)o
+(ion)o(,Xco)o(lumn)o(,Yc)o(olum)o(n\))191 2492 y("point)h(in)h(a)h
+(rectangular)c(region")620 2605 y(box\(xcntr,ycntr,xfll_wdth,)o(yfll)o
+(_wd)o(th,r)o(otat)o(ion)o(,Xco)o(lumn)o(,Yc)o(olum)o(n\))191
+2831 y(where)334 2944 y(\(xcntr,ycntr\))g(are)j(the)g(\(x,y\))f
+(position)g(of)h(the)g(center)f(of)h(the)g(region)334
+3057 y(\(xhlf_wdth,yhlf_wdth\))42 b(are)47 b(the)g(\(x,y\))f(half)h
+(widths)f(of)h(the)g(region)334 3169 y(\(xfll_wdth,yfll_wdth\))42
+b(are)47 b(the)g(\(x,y\))f(full)h(widths)f(of)h(the)g(region)334
+3282 y(\(radius\))f(is)h(half)f(the)h(diameter)f(of)h(the)g(circle)334
+3395 y(\(rotation\))e(is)i(the)g(angle\(degrees\))d(that)j(the)g
+(region)f(is)h(rotated)f(with)620 3508 y(respect)g(to)h
+(\(xcntr,ycntr\))334 3621 y(\(Xcoord,Ycoord\))d(are)j(the)g(\(x,y\))f
+(coordinates)f(to)i(test,)f(usually)g(column)620 3734
+y(names)334 3847 y(NOTE:)g(each)h(parameter)e(can)i(itself)f(be)i(an)f
+(expression,)d(not)j(merely)f(a)620 3960 y(column)h(name)f(or)h
+(constant.)0 4253 y Fd(10.10.6)113 b(Example)36 b(Ro)m(w)h(Filters)191
+4472 y Fe([)47 b(binary)f(&&)i(mag)f(<=)g(5.0])380 b(-)48
+b(Extract)e(all)h(binary)f(stars)g(brighter)1766 4585
+y(than)94 b(fifth)47 b(magnitude)e(\(note)h(that)1766
+4698 y(the)h(initial)f(space)g(is)h(necessary)e(to)1766
+4811 y(prevent)h(it)h(from)g(being)f(treated)g(as)h(a)1766
+4924 y(binning)f(specification\))191 5149 y([#row)g(>=)h(125)g(&&)h
+(#row)e(<=)h(175])142 b(-)48 b(Extract)e(row)h(numbers)e(125)i(through)
+f(175)191 5375 y([IMAGE[4,5])f(.gt.)h(100])476 b(-)48
+b(Extract)e(all)h(rows)f(that)h(have)g(the)1766 5488
+y(\(4,5\))f(component)g(of)h(the)g(IMAGE)f(column)1766
+5601 y(greater)g(than)g(100)p eop
+%%Page: 127 135
+127 134 bop 0 299 a Fh(10.11.)113 b(BINNING)32 b(OR)e(HISTOGRAMMING)g
+(SPECIFICA)-8 b(TION)1223 b Fj(127)191 555 y Fe([abs\(sin\(theta)44
+b(*)j(#deg\)\))f(<)i(0.5])e(-)i(Extract)e(all)h(rows)f(having)g(the)
+1766 668 y(absolute)f(value)i(of)g(the)g(sine)g(of)g(theta)1766
+781 y(less)94 b(than)47 b(a)g(half)g(where)f(the)h(angles)1766
+894 y(are)g(tabulated)e(in)i(degrees)191 1120 y([SUM\()f(SPEC)h(>)g
+(3*BACKGRND)e(\)>=1])94 b(-)48 b(Extract)e(all)h(rows)f(containing)f(a)
+1766 1233 y(spectrum,)g(held)i(in)g(vector)f(column)1766
+1346 y(SPEC,)g(with)h(at)g(least)f(one)h(value)g(3)1766
+1458 y(times)f(greater)g(than)h(the)g(background)1766
+1571 y(level)f(held)h(in)g(a)h(keyword,)d(BACKGRND)191
+1797 y([VCOL=={1,4,2}])759 b(-)48 b(Extract)e(all)h(rows)f(whose)h
+(vector)f(column)1766 1910 y(VCOL)h(contains)e(the)i(3-elements)e(1,)i
+(4,)g(and)1766 2023 y(2.)191 2249 y([@rowFilter.txt])711
+b(-)48 b(Extract)e(rows)g(using)h(the)g(expression)1766
+2362 y(contained)e(within)h(the)h(text)g(file)1766 2475
+y(rowFilter.txt)191 2700 y([gtifilter\(\)])855 b(-)48
+b(Search)e(the)h(current)f(file)g(for)h(a)h(GTI)239 2813
+y(extension,)92 b(filter)i(the)47 b(TIME)239 2926 y(column)f(in)h(the)g
+(current)f(table,)g(using)239 3039 y(START/STOP)f(times)h(taken)g(from)
+239 3152 y(columns)f(in)j(the)f(GTI)94 b(extension)191
+3378 y([regfilter\("pow.reg"\)])423 b(-)48 b(Extract)e(rows)g(which)h
+(have)f(a)i(coordinate)1766 3491 y(\(as)f(given)f(in)h(the)g(X)h(and)f
+(Y)g(columns\))1766 3604 y(within)f(the)h(spatial)f(region)g(specified)
+1766 3717 y(in)h(the)g(pow.reg)f(region)g(file.)191 3942
+y([regfilter\("pow.reg",)c(Xs,)47 b(Ys\)])f(-)i(Same)f(as)g(above,)f
+(except)g(that)h(the)1766 4055 y(Xs)g(and)g(Ys)g(columns)f(will)h(be)g
+(used)f(to)1766 4168 y(determine)f(the)i(coordinate)e(of)i(each)1766
+4281 y(row)g(in)g(the)g(table.)0 4664 y Ff(10.11)181
+b(Binning)44 b(or)h(Histogramming)i(Sp)t(eci\014cation)0
+4924 y Fj(The)22 b(optional)g(binning)e(sp)s(eci\014er)h(is)h(enclosed)
+h(in)f(square)g(brac)m(k)m(ets)j(and)d(can)h(b)s(e)f(distinguished)d
+(from)k(a)g(general)0 5036 y(ro)m(w)32 b(\014lter)g(sp)s(eci\014cation)
+f(b)m(y)h(the)h(fact)g(that)g(it)f(b)s(egins)f(with)g(the)h(k)m(eyw)m
+(ord)h('bin')e(not)i(immediately)d(follo)m(w)m(ed)0 5149
+y(b)m(y)41 b(an)f(equals)h(sign.)71 b(When)41 b(binning)c(is)j(sp)s
+(eci\014ed,)i(a)f(temp)s(orary)g(N-dimensional)d(FITS)i(primary)f(arra)
+m(y)0 5262 y(is)j(created)i(b)m(y)f(computing)g(the)g(histogram)g(of)g
+(the)g(v)-5 b(alues)43 b(in)e(the)j(sp)s(eci\014ed)d(columns)h(of)h(a)h
+(FITS)e(table)0 5375 y(extension.)e(After)30 b(the)f(histogram)g(is)g
+(computed)g(the)h(input)d(FITS)i(\014le)g(con)m(taining)g(the)g(table)h
+(is)e(then)h(closed)0 5488 y(and)34 b(the)h(temp)s(orary)f(FITS)g
+(primary)f(arra)m(y)i(is)f(op)s(ened)g(and)g(passed)g(to)h(the)g
+(application)e(program.)54 b(Th)m(us,)0 5601 y(the)39
+b(application)e(program)i(nev)m(er)g(sees)g(the)g(original)e(FITS)h
+(table)h(and)f(only)g(sees)i(the)f(image)g(in)e(the)i(new)0
+5714 y(temp)s(orary)32 b(\014le)g(\(whic)m(h)g(has)g(no)h(additional)d
+(extensions\).)48 b(Ob)m(viously)-8 b(,)32 b(the)h(application)e
+(program)h(m)m(ust)h(b)s(e)p eop
+%%Page: 128 136
+128 135 bop 0 299 a Fj(128)1528 b Fh(CHAPTER)29 b(10.)113
+b(EXTENDED)30 b(FILE)h(NAME)f(SYNT)-8 b(AX)0 555 y Fj(exp)s(ecting)30
+b(to)h(op)s(en)f(a)h(FITS)e(image)i(and)f(not)g(a)h(FITS)f(table)g(in)f
+(this)g(case.)0 715 y(The)h(data)h(t)m(yp)s(e)f(of)h(the)f(FITS)g
+(histogram)f(image)i(ma)m(y)g(b)s(e)f(sp)s(eci\014ed)e(b)m(y)i(app)s
+(ending)e('b')i(\(for)h(8-bit)f(b)m(yte\),)h('i')0 828
+y(\(for)g(16-bit)f(in)m(tegers\),)h('j')g(\(for)g(32-bit)f(in)m
+(teger\),)i('r')e(\(for)h(32-bit)f(\015oating)h(p)s(oin)m(ts\),)e(or)i
+('d')f(\(for)h(64-bit)f(double)0 941 y(precision)i(\015oating)j(p)s
+(oin)m(t\))e(to)i(the)g('bin')e(k)m(eyw)m(ord)i(\(e.g.)54
+b('[binr)32 b(X]')j(creates)h(a)f(real)f(\015oating)g(p)s(oin)m(t)f
+(image\).)0 1054 y(If)h(the)i(data)f(t)m(yp)s(e)g(is)f(not)i
+(explicitly)c(sp)s(eci\014ed)h(then)i(a)g(32-bit)h(in)m(teger)f(image)g
+(will)d(b)s(e)j(created)h(b)m(y)e(default,)0 1167 y(unless)23
+b(the)j(w)m(eigh)m(ting)e(option)h(is)f(also)h(sp)s(eci\014ed)e(in)h
+(whic)m(h)g(case)i(the)f(image)h(will)c(ha)m(v)m(e)k(a)g(32-bit)f
+(\015oating)g(p)s(oin)m(t)0 1280 y(data)31 b(t)m(yp)s(e)g(b)m(y)f
+(default.)0 1440 y(The)24 b(histogram)f(image)i(ma)m(y)g(ha)m(v)m(e)g
+(from)f(1)g(to)h(4)g(dimensions)c(\(axes\),)27 b(dep)s(ending)22
+b(on)i(the)g(n)m(um)m(b)s(er)f(of)h(columns)0 1553 y(that)31
+b(are)g(sp)s(eci\014ed.)39 b(The)30 b(general)g(form)g(of)g(the)h
+(binning)c(sp)s(eci\014cation)i(is:)48 1767 y Fe([bin{bijrd})92
+b(Xcol=min:max:binsize,)42 b(Ycol=)47 b(...,)f(Zcol=...,)f(Tcol=...;)h
+(weight])0 1982 y Fj(in)38 b(whic)m(h)g(up)g(to)i(4)g(columns,)g(eac)m
+(h)g(corresp)s(onding)d(to)j(an)g(axis)e(of)i(the)f(image,)j(are)e
+(listed.)65 b(The)39 b(column)0 2095 y(names)27 b(are)h(case)h
+(insensitiv)m(e,)d(and)h(the)h(column)e(n)m(um)m(b)s(er)g(ma)m(y)i(b)s
+(e)f(giv)m(en)g(instead)g(of)h(the)g(name,)g(preceded)f(b)m(y)0
+2208 y(a)32 b(p)s(ound)e(sign)h(\(e.g.,)j([bin)c(#4=1:512]\).)47
+b(If)31 b(the)h(column)f(name)h(is)e(not)i(sp)s(eci\014ed,)f(then)g
+(CFITSIO)g(will)e(\014rst)0 2321 y(try)37 b(to)h(use)f(the)g
+('preferred)f(column')h(as)g(sp)s(eci\014ed)f(b)m(y)h(the)g(CPREF)g(k)m
+(eyw)m(ord)h(if)e(it)g(exists)h(\(e.g.,)k('CPREF)0 2433
+y(=)i('DETX,DETY'\),)h(otherwise)f(column)f(names)h('X',)h('Y',)g('Z',)
+f(and)f('T')i(will)c(b)s(e)i(assumed)h(for)g(eac)m(h)h(of)0
+2546 y(the)37 b(4)h(axes,)i(resp)s(ectiv)m(ely)-8 b(.)60
+b(In)37 b(cases)h(where)e(the)i(column)e(name)h(could)f(b)s(e)g
+(confused)h(with)f(an)h(arithmetic)0 2659 y(expression,)29
+b(enclose)i(the)g(column)e(name)h(in)f(paren)m(theses)i(to)g(force)g
+(the)f(name)h(to)g(b)s(e)f(in)m(terpreted)f(literally)-8
+b(.)0 2819 y(Eac)m(h)33 b(column)e(name)h(ma)m(y)h(b)s(e)f(follo)m(w)m
+(ed)f(b)m(y)i(an)f(equals)f(sign)h(and)f(then)h(the)g(lo)m(w)m(er)h
+(and)f(upp)s(er)e(range)i(of)h(the)0 2932 y(histogram,)e(and)f(the)h
+(size)g(of)g(the)g(histogram)g(bins,)e(separated)i(b)m(y)g(colons.)42
+b(Spaces)31 b(are)g(allo)m(w)m(ed)g(b)s(efore)g(and)0
+3045 y(after)e(the)g(equals)f(sign)f(but)h(not)h(within)d(the)j
+('min:max:binsize')d(string.)39 b(The)29 b(min,)e(max)i(and)f(binsize)f
+(v)-5 b(alues)0 3158 y(ma)m(y)32 b(b)s(e)e(in)m(teger)h(or)g
+(\015oating)g(p)s(oin)m(t)f(n)m(um)m(b)s(ers,)g(or)h(they)g(ma)m(y)g(b)
+s(e)g(the)g(names)g(of)g(k)m(eyw)m(ords)g(in)f(the)h(header)g(of)0
+3271 y(the)g(table.)40 b(If)30 b(the)h(latter,)g(then)f(the)g(v)-5
+b(alue)30 b(of)h(that)g(k)m(eyw)m(ord)f(is)g(substituted)f(in)m(to)h
+(the)h(expression.)0 3431 y(Default)36 b(v)-5 b(alues)35
+b(for)h(the)g(min,)g(max)g(and)g(binsize)e(quan)m(tities)h(will)e(b)s
+(e)i(used)h(if)e(not)j(explicitly)c(giv)m(en)j(in)f(the)0
+3544 y(binning)27 b(expression)i(as)i(sho)m(wn)f(in)f(these)i
+(examples:)191 3759 y Fe([bin)47 b(x)g(=)g(:512:2])94
+b(-)47 b(use)g(default)f(minimum)g(value)191 3871 y([bin)h(x)g(=)g
+(1::2])190 b(-)47 b(use)g(default)f(maximum)g(value)191
+3984 y([bin)h(x)g(=)g(1:512])142 b(-)47 b(use)g(default)f(bin)h(size)
+191 4097 y([bin)g(x)g(=)g(1:])286 b(-)47 b(use)g(default)f(maximum)g
+(value)g(and)h(bin)g(size)191 4210 y([bin)g(x)g(=)g(:512])190
+b(-)47 b(use)g(default)f(minimum)g(value)g(and)h(bin)g(size)191
+4323 y([bin)g(x)g(=)g(2])334 b(-)47 b(use)g(default)f(minimum)g(and)h
+(maximum)f(values)191 4436 y([bin)h(x])524 b(-)47 b(use)g(default)f
+(minimum,)g(maximum)g(and)g(bin)h(size)191 4549 y([bin)g(4])524
+b(-)47 b(default)f(2-D)h(image,)f(bin)h(size)g(=)g(4)h(in)f(both)g
+(axes)191 4662 y([bin])619 b(-)47 b(default)f(2-D)h(image)0
+4876 y Fj(CFITSIO)31 b(will)f(use)i(the)h(v)-5 b(alue)32
+b(of)h(the)g(TLMINn,)f(TLMAXn,)h(and)f(TDBINn)h(k)m(eyw)m(ords,)h(if)d
+(they)i(exist,)g(for)0 4989 y(the)k(default)e(min,)i(max,)h(and)e
+(binsize,)g(resp)s(ectiv)m(ely)-8 b(.)59 b(If)36 b(they)h(do)f(not)h
+(exist)f(then)g(CFITSIO)f(will)f(use)i(the)0 5102 y(actual)c(minim)m
+(um)d(and)j(maxim)m(um)f(v)-5 b(alues)31 b(in)g(the)h(column)e(for)i
+(the)g(histogram)g(min)e(and)i(max)g(v)-5 b(alues.)44
+b(The)0 5215 y(default)33 b(binsize)e(will)g(b)s(e)i(set)h(to)h(1,)g
+(or)e(\(max)h(-)g(min\))e(/)i(10.,)i(whic)m(hev)m(er)d(is)g(smaller,)g
+(so)g(that)i(the)e(histogram)0 5328 y(will)28 b(ha)m(v)m(e)j(at)g
+(least)g(10)g(bins)e(along)h(eac)m(h)i(axis.)0 5488 y(A)41
+b(shortcut)g(notation)g(is)f(allo)m(w)m(ed)h(if)f(all)g(the)h
+(columns/axes)g(ha)m(v)m(e)h(the)f(same)g(binning)d(sp)s
+(eci\014cation.)72 b(In)0 5601 y(this)32 b(case)h(all)f(the)h(column)e
+(names)i(ma)m(y)g(b)s(e)f(listed)f(within)f(paren)m(theses,)k(follo)m
+(w)m(ed)f(b)m(y)f(the)h(\(single\))f(binning)0 5714 y(sp)s
+(eci\014cation,)d(as)i(in:)p eop
+%%Page: 129 137
+129 136 bop 0 299 a Fh(10.11.)113 b(BINNING)32 b(OR)e(HISTOGRAMMING)g
+(SPECIFICA)-8 b(TION)1223 b Fj(129)191 555 y Fe([bin)47
+b(\(X,Y\)=1:512:2])191 668 y([bin)g(\(X,Y\))f(=)h(5])0
+888 y Fj(The)31 b(optional)g(w)m(eigh)m(ting)h(factor)g(is)f(the)h
+(last)f(item)h(in)e(the)i(binning)d(sp)s(eci\014er)h(and,)i(if)e
+(presen)m(t,)j(is)d(separated)0 1001 y(from)38 b(the)g(list)f(of)h
+(columns)f(b)m(y)h(a)h(semi-colon.)63 b(As)39 b(the)f(histogram)g(is)f
+(accum)m(ulated,)k(this)c(w)m(eigh)m(t)i(is)e(used)0
+1114 y(to)e(incremen)m(ted)e(the)h(v)-5 b(alue)34 b(of)g(the)g
+(appropriated)e(bin)h(in)f(the)i(histogram.)51 b(If)34
+b(the)g(w)m(eigh)m(ting)g(factor)h(is)e(not)0 1227 y(sp)s(eci\014ed,)23
+b(then)g(the)g(default)f(w)m(eigh)m(t)i(=)e(1)i(is)e(assumed.)37
+b(The)23 b(w)m(eigh)m(ting)g(factor)h(ma)m(y)f(b)s(e)g(a)g(constan)m(t)
+i(in)m(teger)e(or)0 1340 y(\015oating)29 b(p)s(oin)m(t)f(n)m(um)m(b)s
+(er,)g(or)h(the)g(name)g(of)g(a)g(k)m(eyw)m(ord)h(con)m(taining)e(the)i
+(w)m(eigh)m(ting)e(v)-5 b(alue.)40 b(Or)28 b(the)h(w)m(eigh)m(ting)0
+1453 y(factor)g(ma)m(y)g(b)s(e)e(the)h(name)g(of)h(a)f(table)g(column)f
+(in)g(whic)m(h)f(case)k(the)e(v)-5 b(alue)27 b(in)g(that)i(column,)e
+(on)h(a)h(ro)m(w)f(b)m(y)g(ro)m(w)0 1566 y(basis,)h(will)f(b)s(e)i
+(used.)0 1726 y(In)35 b(some)h(cases,)i(the)d(column)g(or)g(k)m(eyw)m
+(ord)h(ma)m(y)g(giv)m(e)g(the)g(recipro)s(cal)e(of)i(the)g(actual)g(w)m
+(eigh)m(t)g(v)-5 b(alue)35 b(that)h(is)0 1839 y(needed.)49
+b(In)32 b(this)g(case,)j(precede)e(the)h(w)m(eigh)m(t)f(k)m(eyw)m(ord)h
+(or)f(column)f(name)h(b)m(y)g(a)g(slash)f('/')i(to)g(tell)e(CFITSIO)0
+1952 y(to)f(use)f(the)h(recipro)s(cal)e(of)h(the)h(v)-5
+b(alue)30 b(when)f(constructing)h(the)h(histogram.)0
+2112 y(F)-8 b(or)25 b(complex)f(or)g(commonly)f(used)h(histograms,)h
+(one)f(can)h(also)f(place)g(its)f(description)f(in)m(to)i(a)h(text)g
+(\014le)e(and)h(im-)0 2225 y(p)s(ort)e(it)f(in)m(to)h(the)h(binning)c
+(sp)s(eci\014cation)i(using)f(the)j(syn)m(tax)f([bin)f
+(@\014lename.txt].)38 b(The)22 b(\014le's)f(con)m(ten)m(ts)j(can)e(ex-)
+0 2338 y(tend)h(o)m(v)m(er)i(m)m(ultiple)c(lines,)i(although)g(it)g(m)m
+(ust)g(still)e(conform)i(to)h(the)g(no-spaces)g(rule)e(for)h(the)h
+(min:max:binsize)0 2451 y(syn)m(tax)35 b(and)f(eac)m(h)h(axis)f(sp)s
+(eci\014cation)g(m)m(ust)g(still)e(b)s(e)i(comma-separated.)55
+b(An)m(y)34 b(lines)f(in)g(the)i(external)f(text)0 2564
+y(\014le)26 b(that)h(b)s(egin)f(with)f(2)j(slash)d(c)m(haracters)k
+(\('//'\))g(will)24 b(b)s(e)i(ignored)g(and)g(ma)m(y)i(b)s(e)e(used)g
+(to)i(add)e(commen)m(ts)i(in)m(to)0 2676 y(the)j(\014le.)0
+2837 y(Examples:)191 3057 y Fe([bini)46 b(detx,)h(dety])762
+b(-)47 b(2-D,)g(16-bit)f(integer)g(histogram)1861 3170
+y(of)i(DETX)e(and)h(DETY)g(columns,)e(using)1861 3283
+y(default)h(values)g(for)h(the)g(histogram)1861 3396
+y(range)g(and)g(binsize)191 3621 y([bin)g(\(detx,)f(dety\)=16;)f
+(/exposure])g(-)i(2-D,)g(32-bit)f(real)h(histogram)e(of)i(DETX)1861
+3734 y(and)g(DETY)g(columns)f(with)g(a)i(bin)f(size)f(=)i(16)1861
+3847 y(in)g(both)e(axes.)h(The)f(histogram)g(values)1861
+3960 y(are)h(divided)f(by)h(the)g(EXPOSURE)f(keyword)1861
+4073 y(value.)191 4299 y([bin)h(time=TSTART:TSTOP:0.1])280
+b(-)47 b(1-D)g(lightcurve,)e(range)h(determined)f(by)1861
+4412 y(the)i(TSTART)f(and)h(TSTOP)g(keywords,)1861 4525
+y(with)g(0.1)g(unit)g(size)f(bins.)191 4751 y([bin)h(pha,)f
+(time=8000.:8100.:0.1])90 b(-)47 b(2-D)g(image)g(using)f(default)g
+(binning)1861 4863 y(of)i(the)e(PHA)h(column)f(for)h(the)g(X)h(axis,)
+1861 4976 y(and)f(1000)g(bins)g(in)g(the)g(range)1861
+5089 y(8000.)g(to)g(8100.)f(for)h(the)g(Y)h(axis.)191
+5315 y([bin)f(@binFilter.txt])616 b(-)47 b(Use)g(the)g(contents)f(of)h
+(the)g(text)f(file)1861 5428 y(binFilter.txt)f(for)h(the)h(binning)1861
+5541 y(specifications.)p eop
+%%Page: 130 138
+130 137 bop 0 299 a Fj(130)1528 b Fh(CHAPTER)29 b(10.)113
+b(EXTENDED)30 b(FILE)h(NAME)f(SYNT)-8 b(AX)p eop
+%%Page: 131 139
+131 138 bop 0 1225 a Fg(Chapter)65 b(11)0 1687 y Fm(T)-19
+b(emplate)76 b(Files)0 2180 y Fj(When)38 b(a)h(new)f(FITS)g(\014le)g
+(is)g(created)h(with)f(a)g(call)g(to)i(\014ts)p 2101
+2180 28 4 v 32 w(create)p 2369 2180 V 35 w(\014le,)f(the)g(name)g(of)g
+(a)g(template)g(\014le)e(ma)m(y)0 2293 y(b)s(e)i(supplied)e(in)i(paren)
+m(theses)h(immediately)e(follo)m(wing)g(the)j(name)f(of)g(the)g(new)f
+(\014le)g(to)i(b)s(e)e(created.)71 b(This)0 2406 y(template)26
+b(is)e(used)h(to)h(de\014ne)f(the)h(structure)f(of)h(one)f(or)h(more)g
+(HDUs)g(in)e(the)i(new)f(\014le.)38 b(The)25 b(template)h(\014le)e(ma)m
+(y)0 2518 y(b)s(e)32 b(another)h(FITS)f(\014le,)h(in)f(whic)m(h)f(case)
+j(the)f(newly)f(created)i(\014le)e(will)e(ha)m(v)m(e)k(exactly)g(the)f
+(same)g(k)m(eyw)m(ords)g(in)0 2631 y(eac)m(h)25 b(HDU)g(as)g(in)e(the)h
+(template)h(FITS)e(\014le,)i(but)e(all)h(the)g(data)h(units)d(will)g(b)
+s(e)i(\014lled)e(with)g(zeros.)40 b(The)24 b(template)0
+2744 y(\014le)h(ma)m(y)i(also)f(b)s(e)f(an)h(ASCI)s(I)e(text)j(\014le,)
+f(where)g(eac)m(h)h(line)d(\(in)h(general\))i(describ)s(es)d(one)i
+(FITS)f(k)m(eyw)m(ord)i(record.)0 2857 y(The)j(format)h(of)f(the)h
+(ASCI)s(I)e(template)h(\014le)g(is)f(describ)s(ed)f(in)i(the)g(follo)m
+(wing)f(sections.)0 3188 y Ff(11.1)136 b(Detailed)46
+b(T)-11 b(emplate)46 b(Line)f(F)-11 b(ormat)0 3438 y
+Fj(The)30 b(format)h(of)f(eac)m(h)i(ASCI)s(I)c(template)j(line)e
+(closely)h(follo)m(ws)f(the)i(format)g(of)f(a)h(FITS)f(k)m(eyw)m(ord)g
+(record:)95 3682 y Fe(KEYWORD)46 b(=)i(KEYVALUE)d(/)j(COMMENT)0
+3926 y Fj(except)22 b(that)g(free)g(format)f(ma)m(y)h(b)s(e)f(used)f
+(\(e.g.,)25 b(the)d(equals)e(sign)h(ma)m(y)g(app)s(ear)g(at)h(an)m(y)g
+(p)s(osition)d(in)h(the)i(line\))e(and)0 4039 y(T)-8
+b(AB)34 b(c)m(haracters)g(are)g(allo)m(w)m(ed)f(and)g(are)g(treated)h
+(the)g(same)f(as)h(space)f(c)m(haracters.)51 b(The)33
+b(KEYV)-10 b(ALUE)33 b(and)0 4152 y(COMMENT)d(\014elds)f(are)i
+(optional.)41 b(The)30 b(equals)g(sign)f(c)m(haracter)k(is)c(also)i
+(optional,)f(but)g(it)g(is)f(recommended)0 4264 y(that)42
+b(it)e(b)s(e)h(included)d(for)j(clarit)m(y)-8 b(.)73
+b(An)m(y)41 b(template)h(line)d(that)j(b)s(egins)e(with)f(the)j(p)s
+(ound)d('#')i(c)m(haracter)i(is)0 4377 y(ignored)29 b(b)m(y)i(the)f
+(template)h(parser)f(and)g(ma)m(y)h(b)s(e)e(use)h(to)h(insert)f(commen)
+m(ts)h(in)m(to)f(the)h(template)g(\014le)e(itself.)0
+4538 y(The)d(KEYW)m(ORD)g(name)g(\014eld)f(is)g(limited)f(to)j(8)f(c)m
+(haracters)h(in)e(length)h(and)f(only)g(the)h(letters)h(A-Z,)f(digits)f
+(0-9,)0 4650 y(and)j(the)g(h)m(yphen)f(and)h(underscore)g(c)m
+(haracters)h(ma)m(y)g(b)s(e)f(used,)g(without)g(an)m(y)g(em)m(b)s
+(edded)g(spaces.)40 b(Lo)m(w)m(ercase)0 4763 y(letters)21
+b(in)f(the)i(template)f(k)m(eyw)m(ord)h(name)f(will)d(b)s(e)j(con)m(v)m
+(erted)i(to)f(upp)s(ercase.)36 b(Leading)21 b(spaces)g(in)f(the)i
+(template)0 4876 y(line)i(preceding)h(the)g(k)m(eyw)m(ord)h(name)g(are)
+g(generally)f(ignored,)h(except)g(if)f(the)h(\014rst)f(8)h(c)m
+(haracters)h(of)f(a)g(template)0 4989 y(line)d(are)j(all)e(blank,)h
+(then)g(the)g(en)m(tire)g(line)f(is)g(treated)i(as)f(a)h(FITS)e(commen)
+m(t)i(k)m(eyw)m(ord)g(\(with)e(a)i(blank)d(k)m(eyw)m(ord)0
+5102 y(name\))31 b(and)f(is)f(copied)h(v)m(erbatim)g(in)m(to)g(the)h
+(FITS)e(header.)0 5262 y(The)37 b(KEYV)-10 b(ALUE)37
+b(\014eld)f(ma)m(y)i(ha)m(v)m(e)g(an)m(y)g(allo)m(w)m(ed)f(FITS)g(data)
+h(t)m(yp)s(e:)54 b(c)m(haracter)39 b(string,)g(logical,)f(in)m(teger,)0
+5375 y(real,)33 b(complex)f(in)m(teger,)i(or)e(complex)h(real.)46
+b(The)32 b(c)m(haracter)j(string)c(v)-5 b(alues)32 b(need)g(not)h(b)s
+(e)f(enclosed)g(in)f(single)0 5488 y(quote)e(c)m(haracters)h(unless)d
+(they)h(are)h(necessary)g(to)g(distinguish)24 b(the)29
+b(string)e(from)h(a)h(di\013eren)m(t)f(data)h(t)m(yp)s(e)f(\(e.g.)0
+5601 y(2.0)h(is)d(a)i(real)g(but)f('2.0')i(is)e(a)h(string\).)39
+b(The)27 b(k)m(eyw)m(ord)h(has)f(an)h(unde\014ned)d(\(n)m(ull\))h(v)-5
+b(alue)28 b(if)e(the)i(template)g(record)0 5714 y(only)h(con)m(tains)i
+(blanks)e(follo)m(wing)g(the)h("=")h(or)g(b)s(et)m(w)m(een)g(the)f("=")
+h(and)f(the)g("/")i(commen)m(t)g(\014eld)c(delimiter.)1882
+5942 y(131)p eop
+%%Page: 132 140
+132 139 bop 0 299 a Fj(132)2250 b Fh(CHAPTER)29 b(11.)72
+b(TEMPLA)-8 b(TE)30 b(FILES)0 555 y Fj(String)25 b(k)m(eyw)m(ord)i(v)-5
+b(alues)26 b(longer)g(than)g(68)h(c)m(haracters)h(\(the)f(maxim)m(um)e
+(length)h(that)h(will)d(\014t)i(in)f(a)i(single)e(FITS)0
+668 y(k)m(eyw)m(ord)41 b(record\))g(are)g(p)s(ermitted)e(using)g(the)i
+(CFITSIO)e(long)h(string)g(con)m(v)m(en)m(tion.)73 b(They)40
+b(can)h(either)f(b)s(e)0 781 y(sp)s(eci\014ed)27 b(as)j(a)f(single)f
+(long)g(line)g(in)f(the)j(template,)g(or)f(b)m(y)f(using)g(m)m(ultiple)
+f(lines)g(where)h(the)i(con)m(tin)m(uing)e(lines)0 894
+y(con)m(tain)j(the)f('CONTINUE')g(k)m(eyw)m(ord,)h(as)g(in)e(this)g
+(example:)95 1139 y Fe(LONGKEY)46 b(=)i('This)e(is)h(a)h(long)e(string)
+g(value)h(that)f(is)i(contin&')95 1252 y(CONTINUE)94
+b('ued)46 b(over)h(2)g(records')f(/)h(comment)f(field)h(goes)f(here)0
+1497 y Fj(The)29 b(format)h(of)g(template)g(lines)d(with)i(CONTINUE)f
+(k)m(eyw)m(ord)i(is)f(v)m(ery)h(strict:)40 b(3)30 b(spaces)g(m)m(ust)f
+(follo)m(w)g(CON-)0 1610 y(TINUE)h(and)g(the)g(rest)h(of)f(the)h(line)e
+(is)g(copied)h(v)m(erbatim)g(to)h(the)g(FITS)e(\014le.)0
+1771 y(The)i(start)h(of)g(the)f(optional)g(COMMENT)g(\014eld)f(m)m(ust)
+i(b)s(e)e(preceded)i(b)m(y)f("/",)i(whic)m(h)d(is)h(used)g(to)h
+(separate)g(it)0 1883 y(from)e(the)g(k)m(eyw)m(ord)h(v)-5
+b(alue)29 b(\014eld.)40 b(Exceptions)29 b(are)i(if)e(the)i(KEYW)m(ORD)g
+(name)f(\014eld)f(con)m(tains)h(COMMENT,)0 1996 y(HISTOR)-8
+b(Y,)30 b(CONTINUE,)g(or)g(if)f(the)i(\014rst)f(8)g(c)m(haracters)i(of)
+f(the)f(template)h(line)e(are)i(blanks.)0 2157 y(More)c(than)f(one)h
+(Header-Data)i(Unit)d(\(HDU\))h(ma)m(y)g(b)s(e)f(de\014ned)f(in)g(the)i
+(template)g(\014le.)38 b(The)26 b(start)h(of)g(an)f(HDU)0
+2269 y(de\014nition)i(is)h(denoted)i(with)e(a)i(SIMPLE)e(or)i(XTENSION)
+e(template)i(line:)0 2430 y(1\))j(SIMPLE)f(b)s(egins)f(a)i(Primary)f
+(HDU)h(de\014nition.)48 b(SIMPLE)33 b(ma)m(y)h(only)f(app)s(ear)g(as)h
+(the)g(\014rst)f(k)m(eyw)m(ord)h(in)0 2543 y(the)e(template)h(\014le.)
+44 b(If)32 b(the)g(template)h(\014le)e(b)s(egins)f(with)h(XTENSION)g
+(instead)g(of)h(SIMPLE,)g(then)f(a)i(default)0 2655 y(empt)m(y)d
+(Primary)d(HDU)j(is)f(created,)i(and)d(the)i(template)g(is)e(then)h
+(assumed)f(to)i(de\014ne)f(the)h(k)m(eyw)m(ords)f(starting)0
+2768 y(with)g(the)i(\014rst)e(extension)h(follo)m(wing)f(the)i(Primary)
+e(HDU.)0 2928 y(2\))35 b(XTENSION)e(marks)g(the)i(b)s(eginning)c(of)j
+(a)h(new)e(extension)h(HDU)g(de\014nition.)50 b(The)33
+b(previous)g(HDU)i(will)0 3041 y(b)s(e)30 b(closed)g(at)h(this)e(p)s
+(oin)m(t)h(and)f(pro)s(cessing)h(of)g(the)h(next)f(extension)g(b)s
+(egins.)0 3373 y Ff(11.2)136 b(Auto-indexing)45 b(of)g(Keyw)l(ords)0
+3623 y Fj(If)31 b(a)h(template)f(k)m(eyw)m(ord)h(name)f(ends)g(with)f
+(a)h("#")h(c)m(haracter,)i(it)d(is)f(said)g(to)i(b)s(e)f
+('auto-indexed'.)43 b(Eac)m(h)32 b("#")0 3736 y(c)m(haracter)i(will)c
+(b)s(e)i(replaced)h(b)m(y)f(the)h(curren)m(t)g(in)m(teger)g(index)e(v)
+-5 b(alue,)33 b(whic)m(h)f(gets)h(reset)h(=)e(1)h(at)h(the)e(start)i
+(of)0 3849 y(eac)m(h)h(new)f(HDU)g(in)f(the)h(\014le)f(\(or)h(7)h(in)d
+(the)i(sp)s(ecial)f(case)i(of)f(a)g(GR)m(OUP)h(de\014nition\).)49
+b(The)33 b(FIRST)g(indexed)0 3962 y(k)m(eyw)m(ord)c(in)e(eac)m(h)i
+(template)g(HDU)g(de\014nition)d(is)h(used)g(as)i(the)f('incremen)m
+(tor';)i(eac)m(h)f(subsequen)m(t)f(o)s(ccurrence)0 4075
+y(of)k(this)e(SAME)h(k)m(eyw)m(ord)h(will)d(cause)j(the)g(index)e(v)-5
+b(alue)31 b(to)h(b)s(e)f(incremen)m(ted.)43 b(This)30
+b(b)s(eha)m(vior)g(can)i(b)s(e)f(rather)0 4188 y(subtle,)c(as)h
+(illustrated)e(in)g(the)i(follo)m(wing)e(examples)h(in)f(whic)m(h)h
+(the)h(TTYPE)e(k)m(eyw)m(ord)i(is)f(the)h(incremen)m(tor)f(in)0
+4300 y(b)s(oth)j(cases:)95 4546 y Fe(TTYPE#)47 b(=)g(TIME)95
+4659 y(TFORM#)g(=)g(1D)95 4772 y(TTYPE#)g(=)g(RATE)95
+4884 y(TFORM#)g(=)g(1E)0 5130 y Fj(will)23 b(create)28
+b(TTYPE1,)e(TF)m(ORM1,)i(TTYPE2,)f(and)e(TF)m(ORM2)i(k)m(eyw)m(ords.)40
+b(But)26 b(if)f(the)h(template)g(lo)s(oks)f(lik)m(e,)95
+5375 y Fe(TTYPE#)47 b(=)g(TIME)95 5488 y(TTYPE#)g(=)g(RATE)95
+5601 y(TFORM#)g(=)g(1D)95 5714 y(TFORM#)g(=)g(1E)p eop
+%%Page: 133 141
+133 140 bop 0 299 a Fh(11.3.)73 b(TEMPLA)-8 b(TE)30 b(P)-8
+b(ARSER)30 b(DIRECTIVES)1982 b Fj(133)0 555 y(this)30
+b(results)f(in)h(a)h(FITS)f(\014les)g(with)f(TTYPE1,)i(TTYPE2,)g(TF)m
+(ORM2,)h(and)e(TF)m(ORM2,)i(whic)m(h)e(is)g(probably)0
+668 y(not)h(what)f(w)m(as)h(in)m(tended!)0 1000 y Ff(11.3)136
+b(T)-11 b(emplate)45 b(P)l(arser)h(Directiv)l(es)0 1251
+y Fj(In)29 b(addition)g(to)h(the)g(template)h(lines)d(whic)m(h)h
+(de\014ne)g(individual)d(k)m(eyw)m(ords,)k(the)g(template)h(parser)e
+(recognizes)0 1363 y(3)h(sp)s(ecial)f(directiv)m(es)g(whic)m(h)g(are)h
+(eac)m(h)h(preceded)f(b)m(y)f(the)h(bac)m(kslash)g(c)m(haracter:)90
+b Fe(\\include,)45 b(\\group)p Fj(,)29 b(and)48 1476
+y Fe(\\end)p Fj(.)0 1637 y(The)37 b('include')f(directiv)m(e)i(m)m(ust)
+f(b)s(e)h(follo)m(w)m(ed)f(b)m(y)h(a)g(\014lename.)62
+b(It)38 b(forces)g(the)g(parser)f(to)i(temp)s(orarily)d(stop)0
+1749 y(reading)e(the)h(curren)m(t)g(template)g(\014le)f(and)g(b)s(egin)
+g(reading)g(the)h(include)d(\014le.)54 b(Once)35 b(the)g(parser)f(reac)
+m(hes)i(the)0 1862 y(end)f(of)h(the)g(include)d(\014le)i(it)g(con)m
+(tin)m(ues)g(parsing)g(the)g(curren)m(t)h(template)g(\014le.)55
+b(Include)34 b(\014les)h(can)h(b)s(e)f(nested,)0 1975
+y(and)30 b(HDU)h(de\014nitions)d(can)i(span)g(m)m(ultiple)e(template)j
+(\014les.)0 2135 y(The)g(start)h(of)g(a)g(GR)m(OUP)h(de\014nition)c(is)
+i(denoted)h(with)e(the)i('group')g(directiv)m(e,)f(and)h(the)f(end)h
+(of)f(a)i(GR)m(OUP)0 2248 y(de\014nition)i(is)i(denoted)g(with)f(the)i
+('end')f(directiv)m(e.)61 b(Eac)m(h)39 b(GR)m(OUP)e(con)m(tains)h(0)g
+(or)f(more)h(mem)m(b)s(er)f(blo)s(c)m(ks)0 2361 y(\(HDUs)44
+b(or)f(GR)m(OUPs\).)79 b(Mem)m(b)s(er)42 b(blo)s(c)m(ks)h(of)g(t)m(yp)s
+(e)g(GR)m(OUP)g(can)g(con)m(tain)g(their)f(o)m(wn)h(mem)m(b)s(er)f(blo)
+s(c)m(ks.)0 2474 y(The)32 b(GR)m(OUP)g(de\014nition)e(itself)h(o)s
+(ccupies)h(one)g(FITS)g(\014le)f(HDU)i(of)f(sp)s(ecial)f(t)m(yp)s(e)h
+(\(GR)m(OUP)h(HDU\),)h(so)e(if)g(a)0 2587 y(template)f(sp)s(eci\014es)e
+(1)i(group)e(with)g(1)i(mem)m(b)s(er)f(HDU)h(lik)m(e:)0
+2838 y Fe(\\group)0 2951 y(grpdescr)46 b(=)h('demo')0
+3064 y(xtension)f(bintable)0 3177 y(#)h(this)g(bintable)f(has)h(0)g
+(cols,)f(0)i(rows)0 3290 y(\\end)0 3541 y Fj(then)30
+b(the)h(parser)e(creates)j(a)f(FITS)f(\014le)f(with)g(3)i(HDUs)g(:)0
+3792 y Fe(1\))47 b(dummy)g(PHDU)0 3905 y(2\))g(GROUP)g(HDU)f(\(has)h(1)
+h(member,)d(which)i(is)g(bintable)e(in)j(HDU)f(number)f(3\))0
+4018 y(3\))h(bintable)f(\(member)g(of)h(GROUP)f(in)h(HDU)g(number)f
+(2\))0 4269 y Fj(T)-8 b(ec)m(hnically)29 b(sp)s(eaking,)g(the)g(GR)m
+(OUP)i(HDU)f(is)f(a)h(BINT)-8 b(ABLE)30 b(with)f(6)h(columns.)39
+b(Applications)28 b(can)i(de\014ne)0 4382 y(additional)20
+b(columns)h(in)f(a)j(GR)m(OUP)f(HDU)h(using)e(TF)m(ORMn)g(and)h(TTYPEn)
+f(\(where)g(n)h(is)f(7,)j(8,)h(....\))39 b(k)m(eyw)m(ords)0
+4494 y(or)30 b(their)g(auto-indexing)f(equiv)-5 b(alen)m(ts.)0
+4655 y(F)d(or)26 b(a)f(more)g(complicated)f(example)g(of)h(a)h
+(template)f(\014le)f(using)f(the)i(group)f(directiv)m(es,)i(lo)s(ok)e
+(at)h(the)g(sample.tpl)0 4767 y(\014le)k(that)i(is)f(included)d(in)j
+(the)g(CFITSIO)f(distribution.)0 5100 y Ff(11.4)136 b(F)-11
+b(ormal)45 b(T)-11 b(emplate)46 b(Syn)l(tax)0 5350 y
+Fj(The)30 b(template)h(syn)m(tax)g(can)f(formally)f(b)s(e)h(de\014ned)f
+(as)i(follo)m(ws:)191 5601 y Fe(TEMPLATE)45 b(=)j(BLOCK)e([)i(BLOCK)e
+(...)h(])p eop
+%%Page: 134 142
+134 141 bop 0 299 a Fj(134)2250 b Fh(CHAPTER)29 b(11.)72
+b(TEMPLA)-8 b(TE)30 b(FILES)334 555 y Fe(BLOCK)46 b(=)i({)f(HDU)g(|)h
+(GROUP)e(})334 781 y(GROUP)g(=)i(\\GROUP)e([)h(BLOCK)g(...)g(])g(\\END)
+430 1007 y(HDU)f(=)i(XTENSION)d([)j(LINE)f(...)f(])i({)f(XTENSION)f(|)h
+(\\GROUP)f(|)i(\\END)f(|)g(EOF)g(})382 1233 y(LINE)f(=)i([)f(KEYWORD)f
+([)i(=)f(])h(])f([)g(VALUE)g(])g([)h(/)f(COMMENT)f(])191
+1458 y(X)h(...)238 b(-)48 b(X)f(can)g(be)g(present)f(1)h(or)h(more)e
+(times)191 1571 y({)h(X)h(|)f(Y)h(})f(-)h(X)f(or)g(Y)191
+1684 y([)g(X)h(])238 b(-)48 b(X)f(is)g(optional)0 1937
+y Fj(A)m(t)34 b(the)f(topmost)g(lev)m(el,)g(the)g(template)h(de\014nes)
+d(1)j(or)e(more)h(template)g(blo)s(c)m(ks.)48 b(Blo)s(c)m(ks)33
+b(can)g(b)s(e)f(either)g(HDU)0 2050 y(\(Header)27 b(Data)h(Unit\))f(or)
+f(a)h(GR)m(OUP)-8 b(.)28 b(F)-8 b(or)27 b(eac)m(h)g(blo)s(c)m(k)f(the)h
+(parser)f(creates)i(1)f(\(or)g(more)f(for)h(GR)m(OUPs\))g(FITS)0
+2163 y(\014le)i(HDUs.)0 2495 y Ff(11.5)136 b(Errors)0
+2745 y Fj(In)24 b(general)g(the)g(\014ts)p 692 2745 28
+4 v 33 w(execute)p 1019 2745 V 34 w(template\(\))h(function)e(tries)h
+(to)h(b)s(e)f(as)g(atomic)h(as)g(p)s(ossible,)e(so)h(either)g(ev)m
+(erything)0 2858 y(is)f(done)h(or)g(nothing)e(is)h(done.)39
+b(If)23 b(an)h(error)f(o)s(ccurs)h(during)e(parsing)g(of)i(the)g
+(template,)i(\014ts)p 3125 2858 V 33 w(execute)p 3452
+2858 V 34 w(template\(\))0 2971 y(will)i(\(try)j(to\))h(delete)f(the)g
+(top)g(lev)m(el)f(BLOCK)g(\(with)g(all)f(its)i(c)m(hildren)d(if)i(an)m
+(y\))h(in)f(whic)m(h)f(the)i(error)f(o)s(ccurred,)0 3084
+y(then)g(it)g(will)e(stop)i(reading)g(the)g(template)h(\014le)e(and)h
+(it)g(will)e(return)h(with)g(an)h(error.)0 3417 y Ff(11.6)136
+b(Examples)0 3667 y Fj(1.)54 b(This)33 b(template)i(\014le)f(will)e
+(create)k(a)f(200)h(x)e(300)i(pixel)d(image,)k(with)c(4-b)m(yte)j(in)m
+(teger)f(pixel)e(v)-5 b(alues,)35 b(in)f(the)0 3780 y(primary)28
+b(HDU:)95 4032 y Fe(SIMPLE)47 b(=)g(T)95 4145 y(BITPIX)g(=)g(32)95
+4258 y(NAXIS)g(=)g(2)239 b(/)47 b(number)f(of)h(dimensions)95
+4371 y(NAXIS1)g(=)g(100)95 b(/)47 b(length)f(of)h(first)g(axis)95
+4484 y(NAXIS2)g(=)g(200)95 b(/)47 b(length)f(of)h(second)f(axis)95
+4597 y(OBJECT)h(=)g(NGC)g(253)g(/)g(name)g(of)g(observed)f(object)0
+4850 y Fj(The)35 b(allo)m(w)m(ed)g(v)-5 b(alues)35 b(of)g(BITPIX)g(are)
+h(8,)h(16,)h(32,)g(-32,)g(or)d(-64,)j(represen)m(ting,)e(resp)s(ectiv)m
+(ely)-8 b(,)37 b(8-bit)e(in)m(teger,)0 4962 y(16-bit)c(in)m(teger,)g
+(32-bit)f(in)m(teger,)h(32-bit)g(\015oating)f(p)s(oin)m(t,)g(or)g(64)h
+(bit)f(\015oating)g(p)s(oin)m(t)f(pixels.)0 5123 y(2.)39
+b(T)-8 b(o)23 b(create)h(a)f(FITS)e(table,)k(the)d(template)h(\014rst)f
+(needs)g(to)i(include)c(XTENSION)i(=)g(T)-8 b(ABLE)23
+b(or)f(BINT)-8 b(ABLE)0 5235 y(to)31 b(de\014ne)e(whether)g(it)g(is)g
+(an)g(ASCI)s(I)g(or)g(binary)f(table,)i(and)g(NAXIS2)g(to)g(de\014ne)f
+(the)h(n)m(um)m(b)s(er)f(of)h(ro)m(ws)f(in)g(the)0 5348
+y(table.)49 b(Tw)m(o)34 b(template)f(lines)f(are)i(then)f(needed)f(to)i
+(de\014ne)f(the)g(name)h(\(TTYPEn\))e(and)h(FITS)g(data)h(format)0
+5461 y(\(TF)m(ORMn\))d(of)f(the)h(columns,)e(as)i(in)e(this)g(example:)
+95 5714 y Fe(xtension)46 b(=)h(bintable)p eop
+%%Page: 135 143
+135 142 bop 0 299 a Fh(11.6.)73 b(EXAMPLES)2993 b Fj(135)95
+555 y Fe(naxis2)47 b(=)g(40)95 668 y(ttype#)g(=)g(Name)95
+781 y(tform#)g(=)g(10a)95 894 y(ttype#)g(=)g(Npoints)95
+1007 y(tform#)g(=)g(j)95 1120 y(ttype#)g(=)g(Rate)95
+1233 y(tunit#)g(=)g(counts/s)95 1346 y(tform#)g(=)g(e)0
+1605 y Fj(The)26 b(ab)s(o)m(v)m(e)j(example)d(de\014nes)g(a)i(n)m(ull)d
+(primary)g(arra)m(y)i(follo)m(w)m(ed)g(b)m(y)g(a)g(40-ro)m(w)h(binary)d
+(table)i(extension)g(with)f(3)0 1718 y(columns)h(called)g('Name',)j
+('Np)s(oin)m(ts',)e(and)g('Rate',)i(with)d(data)i(formats)f(of)g('10A')
+i(\(ASCI)s(I)d(c)m(haracter)i(string\),)0 1831 y('1J')k(\(in)m(teger\))
+h(and)e('1E')i(\(\015oating)e(p)s(oin)m(t\),)h(resp)s(ectiv)m(ely)-8
+b(.)48 b(Note)34 b(that)f(the)g(other)g(required)e(FITS)h(k)m(eyw)m
+(ords)0 1944 y(\(BITPIX,)37 b(NAXIS,)g(NAXIS1,)h(PCOUNT,)e(GCOUNT,)h
+(TFIELDS,)f(and)g(END\))h(do)g(not)g(need)f(to)h(b)s(e)f(ex-)0
+2057 y(plicitly)f(de\014ned)h(in)h(the)g(template)h(b)s(ecause)g(their)
+f(v)-5 b(alues)37 b(can)h(b)s(e)f(inferred)e(from)j(the)f(other)h(k)m
+(eyw)m(ords)g(in)0 2170 y(the)d(template.)54 b(This)33
+b(example)i(also)g(illustrates)d(that)k(the)f(templates)g(are)g
+(generally)f(case-insensitiv)m(e)g(\(the)0 2283 y(k)m(eyw)m(ord)29
+b(names)g(and)g(TF)m(ORMn)f(v)-5 b(alues)29 b(are)g(con)m(v)m(erted)i
+(to)e(upp)s(er-case)g(in)e(the)i(FITS)g(\014le\))f(and)g(that)i(string)
+0 2396 y(k)m(eyw)m(ord)h(v)-5 b(alues)30 b(generally)f(do)h(not)h(need)
+f(to)h(b)s(e)f(enclosed)g(in)f(quotes.)p eop
+%%Page: 136 144
+136 143 bop 0 299 a Fj(136)2250 b Fh(CHAPTER)29 b(11.)72
+b(TEMPLA)-8 b(TE)30 b(FILES)p eop
+%%Page: 137 145
+137 144 bop 0 1225 a Fg(Chapter)65 b(12)0 1687 y Fm(Lo)6
+b(cal)78 b(FITS)e(Con)-6 b(v)g(en)g(tions)0 2180 y Fj(CFITSIO)25
+b(supp)s(orts)g(sev)m(eral)i(lo)s(cal)e(FITS)h(con)m(v)m(en)m(tions)i
+(whic)m(h)d(are)i(not)g(de\014ned)e(in)g(the)i(o\016cial)f(NOST)g(FITS)
+0 2293 y(standard)k(and)g(whic)m(h)g(are)h(not)g(necessarily)e
+(recognized)i(or)g(supp)s(orted)e(b)m(y)i(other)g(FITS)f(soft)m(w)m
+(are)i(pac)m(k)-5 b(ages.)0 2406 y(Programmers)36 b(should)e(b)s(e)h
+(cautious)h(ab)s(out)f(using)g(these)h(features,)i(esp)s(ecially)c(if)h
+(the)h(FITS)f(\014les)g(that)i(are)0 2518 y(pro)s(duced)31
+b(are)i(exp)s(ected)g(to)g(b)s(e)f(pro)s(cessed)g(b)m(y)h(other)f(soft)
+m(w)m(are)i(systems)f(whic)m(h)e(do)i(not)f(use)h(the)f(CFITSIO)0
+2631 y(in)m(terface.)0 3275 y Ff(12.1)136 b(64-Bit)45
+b(Long)g(In)l(tegers)0 3587 y Fj(CFITSIO)38 b(can)i(read)f(and)g(write)
+g(FITS)f(images)i(or)g(table)f(columns)f(con)m(taining)h(64-bit)h(in)m
+(teger)g(data)g(v)-5 b(al-)0 3700 y(ues.)63 b(This)37
+b(data)h(t)m(yp)s(e)g(is)f(not)i(recognized)f(in)f(the)h(o\016cial)f
+(FITS)h(Standard)e(de\014nition)g(do)s(cumen)m(t,)k(but)d(it)0
+3813 y(is)31 b(lik)m(ely)f(that)i(FITS)f(will)e(ev)m(en)m(tually)i
+(supp)s(ort)f(this)h(data)h(t)m(yp)s(e,)g(esp)s(ecially)e(as)i
+(computers)f(that)i(run)d(64-bit)0 3926 y(op)s(erating)25
+b(systems)h(b)s(ecome)f(more)h(common.)40 b(Supp)s(ort)23
+b(for)i(reading)g(and)g(writing)e(64-bit)j(in)m(tegers)g(in)e(CFIT-)0
+4039 y(SIO)32 b(can)i(b)s(e)f(con)m(trolled)g(with)f(the)i(#de\014ne)e
+(statemen)m(t)k(at)e(the)g(b)s(eginning)d(of)i(the)h(\014tsio2.h)f
+(\014le)f(b)m(y)i(setting)0 4152 y(SUPPOR)-8 b(T)p 444
+4152 28 4 v 32 w(64BIT)p 729 4152 V 33 w(INTEGERS)30
+b(to)h(1)g(\(enable\))f(or)h(0)f(\(disable\).)0 4312
+y(Under)k(the)h(con)m(v)m(en)m(tion)h(used)e(b)m(y)h(CFITSIO,)e(FITS)h
+(64-bit)h(images)g(ha)m(v)m(e)h(BITPIX)f(=)f(64,)j(and)e(the)g(64-bit)0
+4425 y(binary)e(table)i(columns)e(ha)m(v)m(e)j(TF)m(ORMn)f(=)f('K'.)i
+(The)e(use)g(of)h(these)h(data)f(t)m(yp)s(es)g(on)g(platforms)e(where)i
+(the)0 4538 y(size)26 b(of)h(a)g('long')f(\(or)h('longlong'\))g(in)m
+(teger)g(=)f(8)h(b)m(ytes)g(is)e(rather)i(in)m(tuitiv)m(e.)38
+b(CFITSIO)25 b(will)e(write)j(64-bit)h('long')0 4650
+y(v)-5 b(ariable)29 b(v)-5 b(alues)30 b(to)g(the)h(FITS)e(\014le)h(and)
+f(read)h(them)g(bac)m(k)h(in)m(to)g('long')f(v)-5 b(ariables)29
+b(just)g(as)i(one)f(w)m(ould)f(exp)s(ect.)0 4763 y(CFITSIO)j(also)h
+(supp)s(orts)f(implicit)e(data)k(t)m(yp)s(e)g(con)m(v)m(ersion)f(b)s
+(et)m(w)m(een)i(64-bit)e(in)m(teger)h(images)f(and)g(columns)0
+4876 y(and)24 b(an)m(y)h(other)f(supp)s(orted)f(data)i(t)m(yp)s(e,)h
+(although)e(some)h(loss)f(of)g(n)m(umerical)f(precision)g(or)i(n)m
+(umerical)e(o)m(v)m(er\015o)m(w)0 4989 y(is)29 b(lik)m(ely)g(in)g(this)
+h(case.)0 5149 y(The)h(situation)f(is)h(more)g(di\016cult)e(on)j
+(32-bit)f(computing)g(platforms)f(that)i(do)f(not)h(supp)s(ort)e(an)h
+(in)m(trinsic)e(64-)0 5262 y(bit)37 b(in)m(teger)i(data)g(t)m(yp)s(e.)
+65 b(In)38 b(this)f(case)i(it)f(is)f(not)i(p)s(ossible)d(to)j(return)e
+(the)i(full)d(64)j(precision)e(of)h(the)h(FITS)0 5375
+y(data)29 b(v)-5 b(alues)27 b(when)g(reading)g(the)i(v)-5
+b(alues)27 b(in)m(to)h(a)g(program)g(v)-5 b(ariable.)39
+b(CFITSIO)26 b(will)g(still)g(con)m(v)m(ert)j(the)g(64-bit)0
+5488 y(in)m(teger)d(v)-5 b(alues)25 b(in)m(to)g(an)m(y)h(other)g(supp)s
+(orted)e(data)i(t)m(yp)s(e;)i(the)d(64-bit)h(double)e(data)j(t)m(yp)s
+(e)e(is)g(probably)f(the)i(most)0 5601 y(useful)33 b(in)g(this)h(case.)
+55 b(It)35 b(only)f(pro)m(vides)f(ab)s(out)i(52-bits)g(of)g(precision)e
+(in)g(the)i(man)m(tissa,)h(ho)m(w)m(ev)m(er,)i(so)d(some)0
+5714 y(lose)30 b(of)h(precision)d(is)i(p)s(ossible.)1882
+5942 y(137)p eop
+%%Page: 138 146
+138 145 bop 0 299 a Fj(138)1741 b Fh(CHAPTER)30 b(12.)112
+b(LOCAL)29 b(FITS)h(CONVENTIONS)0 555 y Ff(12.2)136 b(Long)44
+b(String)i(Keyw)l(ord)f(V)-11 b(alues.)0 805 y Fj(The)43
+b(length)h(of)g(a)g(standard)g(FITS)f(string)g(k)m(eyw)m(ord)h(is)f
+(limited)f(to)j(68)f(c)m(haracters)i(b)s(ecause)e(it)f(m)m(ust)h(\014t)
+0 918 y(en)m(tirely)33 b(within)e(a)j(single)f(FITS)g(header)g(k)m(eyw)
+m(ord)i(record.)50 b(In)33 b(some)i(instances)e(it)g(is)g(necessary)h
+(to)h(enco)s(de)0 1031 y(strings)28 b(longer)i(than)f(this)f(limit,)g
+(so)i(CFITSIO)e(supp)s(orts)g(a)h(lo)s(cal)g(con)m(v)m(en)m(tion)i(in)d
+(whic)m(h)h(the)g(string)g(v)-5 b(alue)29 b(is)0 1144
+y(con)m(tin)m(ued)35 b(o)m(v)m(er)h(m)m(ultiple)c(k)m(eyw)m(ords.)55
+b(This)33 b(con)m(tin)m(uation)h(con)m(v)m(en)m(tion)i(uses)f(an)f(amp)
+s(ersand)g(c)m(haracter)i(at)0 1257 y(the)26 b(end)f(of)h(eac)m(h)g
+(substring)e(to)i(indicate)f(that)h(it)g(is)e(con)m(tin)m(ued)i(on)f
+(the)h(next)g(k)m(eyw)m(ord,)h(and)e(the)h(con)m(tin)m(uation)0
+1370 y(k)m(eyw)m(ords)40 b(all)f(ha)m(v)m(e)i(the)f(name)g(CONTINUE)f
+(without)g(an)h(equal)f(sign)g(in)g(column)g(9.)69 b(The)40
+b(string)e(v)-5 b(alue)0 1483 y(ma)m(y)33 b(b)s(e)f(con)m(tin)m(ued)g
+(in)g(this)f(w)m(a)m(y)i(o)m(v)m(er)h(as)f(man)m(y)g(additional)d
+(CONTINUE)i(k)m(eyw)m(ords)h(as)f(is)g(required.)45 b(The)0
+1596 y(follo)m(wing)34 b(lines)f(illustrate)g(this)h(con)m(tin)m
+(uation)h(con)m(v)m(en)m(tion)i(whic)m(h)c(is)i(used)f(in)g(the)h(v)-5
+b(alue)35 b(of)g(the)g(STRKEY)0 1709 y(k)m(eyw)m(ord:)0
+1939 y Fe(LONGSTRN=)45 b('OGIP)i(1.0')189 b(/)48 b(The)f(OGIP)f(Long)h
+(String)f(Convention)f(may)i(be)g(used.)0 2051 y(STRKEY)94
+b(=)47 b('This)g(is)g(a)g(very)g(long)g(string)f(keyword&')93
+b(/)47 b(Optional)f(Comment)0 2164 y(CONTINUE)93 b(')48
+b(value)e(that)h(is)g(continued)e(over)i(3)g(keywords)f(in)h(the)g(&)95
+b(')0 2277 y(CONTINUE)e('FITS)47 b(header.')e(/)j(This)e(is)h(another)f
+(optional)g(comment.)0 2507 y Fj(It)29 b(is)f(recommended)g(that)h(the)
+g(LONGSTRN)f(k)m(eyw)m(ord,)i(as)f(sho)m(wn)f(here,)h(alw)m(a)m(ys)h(b)
+s(e)e(included)e(in)h(an)m(y)i(HDU)0 2620 y(that)i(uses)f(this)f
+(longstring)g(con)m(v)m(en)m(tion)j(as)f(a)f(w)m(arning)g(to)h(an)m(y)g
+(soft)m(w)m(are)g(that)g(m)m(ust)g(read)f(the)h(k)m(eyw)m(ords.)41
+b(A)0 2733 y(routine)c(called)f(\014ts)p 712 2733 28
+4 v 33 w(write)p 948 2733 V 32 w(k)m(ey)p 1113 2733 V
+33 w(longw)m(arn)h(has)g(b)s(een)g(pro)m(vided)f(in)h(CFITSIO)e(to)k
+(write)d(this)h(k)m(eyw)m(ord)h(if)e(it)0 2846 y(do)s(es)30
+b(not)h(already)f(exist.)0 3006 y(This)f(long)h(string)f(con)m(v)m(en)m
+(tion)i(is)f(supp)s(orted)e(b)m(y)j(the)f(follo)m(wing)f(CFITSIO)g
+(routines:)191 3236 y Fe(fits_write_key_longstr)89 b(-)48
+b(write)e(a)i(long)e(string)g(keyword)g(value)191 3349
+y(fits_insert_key_longstr)41 b(-)48 b(insert)e(a)h(long)g(string)f
+(keyword)g(value)191 3462 y(fits_modify_key_longstr)41
+b(-)48 b(modify)e(a)h(long)g(string)f(keyword)g(value)191
+3575 y(fits_update_key_longstr)41 b(-)48 b(modify)e(a)h(long)g(string)f
+(keyword)g(value)191 3688 y(fits_read_key_longstr)137
+b(-)48 b(read)94 b(a)48 b(long)e(string)g(keyword)g(value)191
+3801 y(fits_delete_key)425 b(-)48 b(delete)e(a)h(keyword)0
+4030 y Fj(The)36 b(\014ts)p 320 4030 V 32 w(read)p 524
+4030 V 33 w(k)m(ey)p 690 4030 V 34 w(longstr)f(routine)h(is)f(unique)f
+(among)j(all)f(the)g(CFITSIO)f(routines)g(in)g(that)i(it)f(in)m
+(ternally)0 4143 y(allo)s(cates)e(memory)f(for)h(the)f(long)g(string)g
+(v)-5 b(alue;)35 b(all)d(the)i(other)g(CFITSIO)e(routines)g(that)i
+(deal)f(with)g(arra)m(ys)0 4256 y(require)38 b(that)i(the)g(calling)e
+(program)h(pre-allo)s(cate)h(adequate)g(space)g(to)g(hold)e(the)i(arra)
+m(y)g(of)f(data.)69 b(Conse-)0 4369 y(quen)m(tly)-8 b(,)30
+b(programs)g(whic)m(h)f(use)h(the)g(\014ts)p 1443 4369
+V 32 w(read)p 1647 4369 V 33 w(k)m(ey)p 1813 4369 V 34
+w(longstr)f(routine)g(m)m(ust)h(b)s(e)g(careful)f(to)i(free)g(the)f
+(allo)s(cated)0 4482 y(memory)g(for)g(the)h(string)e(when)h(it)g(is)f
+(no)h(longer)g(needed.)0 4642 y(The)g(follo)m(wing)f(2)h(routines)g
+(also)g(ha)m(v)m(e)i(limited)c(supp)s(ort)g(for)i(this)g(long)g(string)
+f(con)m(v)m(en)m(tion,)286 4872 y Fe(fits_modify_key_str)43
+b(-)k(modify)f(an)i(existing)d(string)h(keyword)g(value)286
+4985 y(fits_update_key_str)d(-)k(update)f(a)i(string)e(keyword)g(value)
+0 5215 y Fj(in)23 b(that)i(they)f(will)e(correctly)i(o)m(v)m(erwrite)h
+(an)f(existing)f(long)h(string)f(v)-5 b(alue,)26 b(but)d(the)h(new)g
+(string)f(v)-5 b(alue)24 b(is)f(limited)0 5328 y(to)31
+b(a)g(maxim)m(um)e(of)i(68)g(c)m(haracters)h(in)d(length.)0
+5488 y(The)g(more)h(commonly)g(used)f(CFITSIO)f(routines)h(to)h(write)f
+(string)g(v)-5 b(alued)29 b(k)m(eyw)m(ords)h(\(\014ts)p
+3254 5488 V 33 w(up)s(date)p 3563 5488 V 32 w(k)m(ey)h(and)0
+5601 y(\014ts)p 127 5601 V 32 w(write)p 362 5601 V 32
+w(k)m(ey\))j(do)e(not)h(supp)s(ort)d(this)h(long)h(string)g(con)m(v)m
+(en)m(tion)h(and)f(only)f(supp)s(ort)g(strings)g(up)g(to)i(68)g(c)m
+(har-)0 5714 y(acters)g(in)e(length.)47 b(This)30 b(has)i(b)s(een)g
+(done)g(delib)s(erately)e(to)j(prev)m(en)m(t)g(programs)f(from)g(inadv)
+m(erten)m(tly)g(writing)p eop
+%%Page: 139 147
+139 146 bop 0 299 a Fh(12.3.)73 b(ARRA)-8 b(YS)30 b(OF)h(FIXED-LENGTH)g
+(STRINGS)e(IN)h(BINAR)-8 b(Y)32 b(T)-8 b(ABLES)871 b
+Fj(139)0 555 y(k)m(eyw)m(ords)25 b(using)e(this)h(non-standard)f(con)m
+(v)m(en)m(tion)j(without)e(the)h(explicit)e(in)m(ten)m(t)i(of)g(the)f
+(programmer)h(or)f(user.)0 668 y(The)36 b(\014ts)p 320
+668 28 4 v 32 w(write)p 555 668 V 32 w(k)m(ey)p 720 668
+V 34 w(longstr)g(routine)f(m)m(ust)i(b)s(e)f(called)g(instead)f(to)j
+(write)d(long)h(strings.)58 b(This)35 b(routine)h(can)0
+781 y(also)30 b(b)s(e)g(used)g(to)h(write)e(ordinary)g(string)g(v)-5
+b(alues)30 b(less)g(than)g(68)h(c)m(haracters)h(in)d(length.)0
+1128 y Ff(12.3)136 b(Arra)l(ys)45 b(of)g(Fixed-Length)g(Strings)g(in)g
+(Binary)f(T)-11 b(ables)0 1381 y Fj(The)29 b(de\014nition)e(of)j(the)f
+(FITS)g(binary)e(table)j(extension)f(format)g(do)s(es)h(not)f(pro)m
+(vide)g(a)g(simple)f(w)m(a)m(y)i(to)g(sp)s(ecify)0 1494
+y(that)24 b(a)f(c)m(haracter)i(column)d(con)m(tains)h(an)g(arra)m(y)h
+(of)f(\014xed-length)f(strings.)37 b(T)-8 b(o)24 b(supp)s(ort)d(this)h
+(feature,)j(CFITSIO)0 1607 y(uses)31 b(a)h(lo)s(cal)f(con)m(v)m(en)m
+(tion)h(for)f(the)h(format)g(of)g(the)f(TF)m(ORMn)g(k)m(eyw)m(ord)h(v)
+-5 b(alue)31 b(of)h(the)g(form)f('rAw')g(where)g('r')0
+1720 y(is)c(an)g(in)m(teger)h(sp)s(ecifying)d(the)j(total)g(width)e(in)
+g(c)m(haracters)j(of)f(the)g(column,)f(and)g('w')g(is)g(an)g(in)m
+(teger)h(sp)s(ecifying)0 1833 y(the)c(\(\014xed\))g(length)g(of)g(an)g
+(individual)19 b(unit)k(string)g(within)e(the)j(v)m(ector.)41
+b(F)-8 b(or)24 b(example,)i(TF)m(ORM1)e(=)g('120A10')0
+1946 y(w)m(ould)k(indicate)g(that)h(the)h(binary)d(table)i(column)f(is)
+g(120)i(c)m(haracters)g(wide)e(and)h(consists)f(of)h(12)h(10-c)m
+(haracter)0 2059 y(length)c(strings.)38 b(This)24 b(con)m(v)m(en)m
+(tion)k(is)d(recognized)i(b)m(y)f(the)g(CFITSIO)f(routines)g(that)i
+(read)f(or)h(write)e(strings)g(in)0 2171 y(binary)30
+b(tables.)44 b(The)31 b(Binary)g(T)-8 b(able)31 b(de\014nition)e(do)s
+(cumen)m(t)i(sp)s(eci\014es)g(that)h(other)g(optional)e(c)m(haracters)j
+(ma)m(y)0 2284 y(follo)m(w)f(the)h(data)g(t)m(yp)s(e)g(co)s(de)g(in)e
+(the)i(TF)m(ORM)g(k)m(eyw)m(ord,)h(so)f(this)e(lo)s(cal)h(con)m(v)m(en)
+m(tion)i(is)e(in)f(compliance)h(with)0 2397 y(the)f(FITS)e(standard)h
+(although)g(other)g(FITS)g(readers)g(ma)m(y)h(not)g(recognize)g(this)e
+(con)m(v)m(en)m(tion.)0 2557 y(The)c(Binary)g(T)-8 b(able)26
+b(de\014nition)d(do)s(cumen)m(t)j(that)h(w)m(as)f(appro)m(v)m(ed)g(b)m
+(y)g(the)g(IA)m(U)g(in)f(1994)j(con)m(tains)e(an)f(app)s(endix)0
+2670 y(describing)20 b(an)j(alternate)g(con)m(v)m(en)m(tion)h(for)f(sp)
+s(ecifying)d(arra)m(ys)j(of)g(\014xed)f(or)h(v)-5 b(ariable)22
+b(length)g(strings)f(in)h(a)h(binary)0 2783 y(table)34
+b(c)m(haracter)h(column)e(\(with)g(the)i(form)e('rA:SSTRw/nnn\)'.)50
+b(This)32 b(app)s(endix)f(w)m(as)k(not)f(o\016cially)f(v)m(oted)0
+2896 y(on)d(b)m(y)h(the)f(IA)m(U)h(and)f(hence)g(is)g(still)e(pro)m
+(visional.)39 b(CFITSIO)29 b(do)s(es)h(not)g(curren)m(tly)g(supp)s(ort)
+e(this)i(prop)s(osal.)0 3243 y Ff(12.4)136 b(Keyw)l(ord)45
+b(Units)h(Strings)0 3496 y Fj(One)37 b(limitation)f(of)h(the)h(curren)m
+(t)g(FITS)e(Standard)h(is)g(that)h(it)f(do)s(es)g(not)h(de\014ne)f(a)h
+(sp)s(eci\014c)e(con)m(v)m(en)m(tion)j(for)0 3609 y(recording)29
+b(the)h(ph)m(ysical)f(units)g(of)h(a)g(k)m(eyw)m(ord)h(v)-5
+b(alue.)40 b(The)30 b(TUNITn)f(k)m(eyw)m(ord)h(can)g(b)s(e)g(used)f(to)
+i(sp)s(ecify)e(the)0 3722 y(ph)m(ysical)34 b(units)g(of)h(the)h(v)-5
+b(alues)35 b(in)f(a)h(table)h(column,)f(but)g(there)g(is)g(no)g
+(analogous)h(con)m(v)m(en)m(tion)g(for)f(k)m(eyw)m(ord)0
+3835 y(v)-5 b(alues.)41 b(The)30 b(commen)m(t)h(\014eld)f(of)g(the)h(k)
+m(eyw)m(ord)g(is)f(often)h(used)f(for)g(this)f(purp)s(ose,)h(but)f(the)
+i(units)e(are)i(usually)0 3948 y(not)g(sp)s(eci\014ed)d(in)h(a)i(w)m
+(ell)e(de\014ned)h(format)g(that)h(FITS)f(readers)g(can)h(easily)e
+(recognize)i(and)f(extract.)0 4108 y(T)-8 b(o)27 b(solv)m(e)h(this)d
+(problem,)i(CFITSIO)e(uses)i(a)g(lo)s(cal)f(con)m(v)m(en)m(tion)i(in)e
+(whic)m(h)f(the)j(k)m(eyw)m(ord)f(units)e(are)j(enclosed)e(in)0
+4221 y(square)20 b(brac)m(k)m(ets)j(as)e(the)f(\014rst)g(tok)m(en)i(in)
+e(the)g(k)m(eyw)m(ord)i(commen)m(t)f(\014eld;)i(more)e(sp)s
+(eci\014cally)-8 b(,)21 b(the)g(op)s(ening)e(square)0
+4334 y(brac)m(k)m(et)28 b(immediately)d(follo)m(ws)g(the)i(slash)e('/')
+i(commen)m(t)h(\014eld)d(delimiter)f(and)i(a)g(single)f(space)i(c)m
+(haracter.)41 b(The)0 4447 y(follo)m(wing)29 b(examples)h(illustrate)e
+(k)m(eyw)m(ords)j(that)g(use)f(this)f(con)m(v)m(en)m(tion:)0
+4718 y Fe(EXPOSURE=)713 b(1800.0)47 b(/)g([s])g(elapsed)f(exposure)f
+(time)0 4831 y(V_HELIO)h(=)763 b(16.23)47 b(/)g([km)g(s**\(-1\)])e
+(heliocentric)g(velocity)0 4944 y(LAMBDA)94 b(=)763 b(5400.)47
+b(/)g([angstrom])e(central)h(wavelength)0 5057 y(FLUX)190
+b(=)47 b(4.9033487787637465E-30)42 b(/)47 b([J/cm**2/s])e(average)h
+(flux)0 5328 y Fj(In)28 b(general,)g(the)h(units)d(named)i(in)f(the)i
+(IA)m(U\(1988\))i(St)m(yle)d(Guide)f(are)i(recommended,)f(with)f(the)i
+(main)e(excep-)0 5441 y(tion)j(that)h(the)f(preferred)g(unit)e(for)j
+(angle)f(is)f('deg')j(for)e(degrees.)0 5601 y(The)38
+b(\014ts)p 322 5601 V 33 w(read)p 527 5601 V 33 w(k)m(ey)p
+693 5601 V 33 w(unit)g(and)g(\014ts)p 1234 5601 V 32
+w(write)p 1469 5601 V 32 w(k)m(ey)p 1634 5601 V 34 w(unit)f(routines)h
+(in)g(CFITSIO)f(read)i(and)f(write,)j(resp)s(ectiv)m(ely)-8
+b(,)0 5714 y(the)31 b(k)m(eyw)m(ord)f(unit)f(strings)h(in)f(an)h
+(existing)f(k)m(eyw)m(ord.)p eop
+%%Page: 140 148
+140 147 bop 0 299 a Fj(140)1741 b Fh(CHAPTER)30 b(12.)112
+b(LOCAL)29 b(FITS)h(CONVENTIONS)0 555 y Ff(12.5)136 b(HIERAR)l(CH)46
+b(Con)l(v)l(en)l(tion)g(for)f(Extended)h(Keyw)l(ord)f(Names)0
+805 y Fj(CFITSIO)c(supp)s(orts)g(the)i(HIERAR)m(CH)g(k)m(eyw)m(ord)g
+(con)m(v)m(en)m(tion)h(whic)m(h)e(allo)m(ws)g(k)m(eyw)m(ord)h(names)g
+(that)h(are)0 918 y(longer)33 b(then)f(8)i(c)m(haracters)g(and)f(ma)m
+(y)h(con)m(tain)f(the)g(full)e(range)i(of)h(prin)m(table)d(ASCI)s(I)g
+(text)j(c)m(haracters.)51 b(This)0 1031 y(con)m(v)m(en)m(tion)38
+b(w)m(as)g(dev)m(elop)s(ed)e(at)i(the)f(Europ)s(ean)f(Southern)g
+(Observ)-5 b(atory)37 b(\(ESO\))f(to)i(supp)s(ort)d(hierarc)m(hical)0
+1144 y(FITS)30 b(k)m(eyw)m(ord)g(suc)m(h)h(as:)0 1395
+y Fe(HIERARCH)46 b(ESO)g(INS)h(FOCU)g(POS)g(=)g(-0.00002500)e(/)j
+(Focus)e(position)0 1646 y Fj(Basically)-8 b(,)52 b(this)46
+b(con)m(v)m(en)m(tion)j(uses)e(the)h(FITS)f(k)m(eyw)m(ord)h('HIERAR)m
+(CH')h(to)f(indicate)f(that)h(this)e(con)m(v)m(en-)0
+1759 y(tion)e(is)f(b)s(eing)g(used,)k(then)d(the)g(actual)h(k)m(eyw)m
+(ord)f(name)h(\()p Fe('ESO)i(INS)f(FOCU)h(POS')c Fj(in)g(this)g
+(example\))h(b)s(e-)0 1872 y(gins)39 b(in)f(column)g(10)j(and)e(can)h
+(con)m(tain)f(an)m(y)h(prin)m(table)e(ASCI)s(I)g(text)j(c)m(haracters,)
+i(including)37 b(spaces.)68 b(The)0 1985 y(equals)43
+b(sign)h(marks)f(the)h(end)g(of)g(the)g(k)m(eyw)m(ord)h(name)f(and)f
+(is)h(follo)m(w)m(ed)f(b)m(y)h(the)g(usual)f(v)-5 b(alue)44
+b(and)f(com-)0 2098 y(men)m(t)31 b(\014elds)e(just)h(as)h(in)e
+(standard)h(FITS)g(k)m(eyw)m(ords.)41 b(F)-8 b(urther)30
+b(details)g(of)h(this)e(con)m(v)m(en)m(tion)j(are)f(describ)s(ed)d(at)0
+2211 y(h)m(ttp://arcdev.hq.eso.org/dicb/dicd/dic-1-1.4.h)m(tml)33
+b(\(searc)m(h)f(for)e(HIERAR)m(CH\).)0 2371 y(This)42
+b(con)m(v)m(en)m(tion)k(allo)m(ws)e(a)g(m)m(uc)m(h)h(broader)e(range)i
+(of)f(k)m(eyw)m(ord)h(names)f(than)h(is)e(allo)m(w)m(ed)h(b)m(y)g(the)h
+(FITS)0 2484 y(Standard.)40 b(Here)30 b(are)h(more)g(examples)f(of)g
+(suc)m(h)g(k)m(eyw)m(ords:)0 2735 y Fe(HIERARCH)46 b(LongKeyword)e(=)k
+(47.5)e(/)i(Keyword)e(has)h(>)g(8)g(characters,)e(and)i(mixed)f(case)0
+2848 y(HIERARCH)g(XTE$TEMP)f(=)j(98.6)e(/)i(Keyword)d(contains)h(the)h
+('$')g(character)0 2961 y(HIERARCH)f(Earth)g(is)h(a)h(star)e(=)i(F)f(/)
+h(Keyword)d(contains)h(embedded)f(spaces)0 3212 y Fj(CFITSIO)40
+b(will)f(transparen)m(tly)i(read)h(and)f(write)f(these)j(k)m(eyw)m
+(ords,)i(so)d(application)e(programs)h(do)g(not)h(in)0
+3325 y(general)32 b(need)g(to)h(kno)m(w)f(an)m(ything)g(ab)s(out)g(the)
+g(sp)s(eci\014c)f(implemen)m(tation)g(details)g(of)i(the)f(HIERAR)m(CH)
+g(con-)0 3438 y(v)m(en)m(tion.)49 b(In)32 b(particular,)h(application)e
+(programs)h(do)h(not)h(need)e(to)i(sp)s(ecify)e(the)h(`HIERAR)m(CH')h
+(part)f(of)g(the)0 3551 y(k)m(eyw)m(ord)g(name)f(when)g(reading)f(or)h
+(writing)f(k)m(eyw)m(ords)h(\(although)g(it)g(ma)m(y)h(b)s(e)f
+(included)d(if)j(desired\).)45 b(When)0 3664 y(writing)33
+b(a)i(k)m(eyw)m(ord,)h(CFITSIO)d(\014rst)h(c)m(hec)m(ks)i(to)f(see)g
+(if)f(the)h(k)m(eyw)m(ord)g(name)f(is)g(legal)g(as)h(a)g(standard)f
+(FITS)0 3776 y(k)m(eyw)m(ord)k(\(no)g(more)f(than)h(8)g(c)m(haracters)h
+(long)e(and)g(con)m(taining)g(only)f(letters,)k(digits,)e(or)g(a)g(min)
+m(us)d(sign)i(or)0 3889 y(underscore\).)68 b(If)39 b(so)h(it)f(writes)g
+(it)g(as)g(a)h(standard)f(FITS)g(k)m(eyw)m(ord,)k(otherwise)c(it)g
+(uses)g(the)h(hierarc)m(h)e(con-)0 4002 y(v)m(en)m(tion)33
+b(to)g(write)f(the)g(k)m(eyw)m(ord.)48 b(The)32 b(maxim)m(um)f(k)m(eyw)
+m(ord)i(name)f(length)g(is)g(67)h(c)m(haracters,)i(whic)m(h)c(lea)m(v)m
+(es)0 4115 y(only)c(1)i(space)g(for)f(the)h(v)-5 b(alue)28
+b(\014eld.)38 b(A)29 b(more)f(practical)g(limit)e(is)i(ab)s(out)g(40)h
+(c)m(haracters,)i(whic)m(h)c(lea)m(v)m(es)i(enough)0
+4228 y(ro)s(om)f(for)h(most)f(k)m(eyw)m(ord)h(v)-5 b(alues.)40
+b(CFITSIO)27 b(returns)g(an)h(error)h(if)e(there)i(is)e(not)i(enough)f
+(ro)s(om)h(for)f(b)s(oth)g(the)0 4341 y(k)m(eyw)m(ord)k(name)f(and)f
+(the)i(k)m(eyw)m(ord)f(v)-5 b(alue)31 b(on)g(the)h(80-c)m(haracter)h
+(card,)f(except)g(for)f(string-v)-5 b(alued)30 b(k)m(eyw)m(ords)0
+4454 y(whic)m(h)i(are)h(simply)d(truncated)j(so)g(that)h(the)f(closing)
+f(quote)i(c)m(haracter)g(falls)d(in)h(column)g(80.)49
+b(In)32 b(the)h(curren)m(t)0 4567 y(implemen)m(tation,)28
+b(CFITSIO)f(preserv)m(es)i(the)g(case)h(of)f(the)g(letters)g(when)f
+(writing)f(the)i(k)m(eyw)m(ord)g(name,)g(but)f(it)0 4680
+y(is)c(case-insensitiv)m(e)g(when)g(reading)g(or)h(searc)m(hing)g(for)g
+(a)g(k)m(eyw)m(ord.)40 b(The)24 b(curren)m(t)h(implemen)m(tation)e
+(allo)m(ws)i(an)m(y)0 4793 y(ASCI)s(I)k(text)j(c)m(haracter)h(\(ASCI)s
+(I)c(32)j(to)f(ASCI)s(I)f(126\))i(in)e(the)h(k)m(eyw)m(ord)g(name)g
+(except)h(for)e(the)h('=')g(c)m(haracter.)0 4906 y(A)f(space)h(is)f
+(also)g(required)f(on)h(either)g(side)f(of)i(the)f(equal)g(sign.)0
+5238 y Ff(12.6)136 b(Tile-Compressed)46 b(Image)g(F)-11
+b(ormat)0 5488 y Fj(CFITSIO)36 b(supp)s(orts)f(a)j(con)m(v)m(en)m(tion)
+h(for)e(compressing)g(n-dimensional)d(images)j(and)g(storing)g(the)h
+(resulting)0 5601 y(b)m(yte)i(stream)g(in)e(a)i(v)-5
+b(ariable-length)38 b(column)g(in)g(a)i(FITS)f(binary)e(table.)68
+b(The)39 b(general)h(principle)c(used)i(in)0 5714 y(this)33
+b(con)m(v)m(en)m(tion)j(is)d(to)i(\014rst)f(divide)e(the)j
+(n-dimensional)c(image)k(in)m(to)f(a)h(rectangular)f(grid)f(of)i
+(subimages)e(or)p eop
+%%Page: 141 149
+141 148 bop 0 299 a Fh(12.6.)73 b(TILE-COMPRESSED)28
+b(IMA)m(GE)j(F)m(ORMA)-8 b(T)1838 b Fj(141)0 555 y(`tiles'.)55
+b(Eac)m(h)35 b(tile)g(is)f(then)h(compressed)g(as)g(a)h(con)m(tin)m
+(uous)f(blo)s(c)m(k)f(of)i(data,)h(and)e(the)g(resulting)e(compressed)0
+668 y(b)m(yte)k(stream)h(is)e(stored)h(in)e(a)i(ro)m(w)g(of)g(a)h(v)-5
+b(ariable)35 b(length)h(column)g(in)g(a)h(FITS)f(binary)f(table.)60
+b(By)37 b(dividing)0 781 y(the)j(image)f(in)m(to)g(tiles)g(it)g(is)f
+(generally)h(p)s(ossible)e(to)j(extract)h(and)d(uncompress)g
+(subsections)h(of)g(the)h(image)0 894 y(without)c(ha)m(ving)h(to)h
+(uncompress)e(the)h(whole)f(image.)61 b(The)37 b(default)f(tiling)f
+(pattern)j(treats)g(eac)m(h)g(ro)m(w)f(of)h(a)0 1007
+y(2-dimensional)33 b(image)i(\(or)g(higher)e(dimensional)f(cub)s(e\))j
+(as)g(a)g(tile,)h(suc)m(h)e(that)i(eac)m(h)g(tile)e(con)m(tains)h
+(NAXIS1)0 1120 y(pixels.)57 b(An)m(y)36 b(other)h(rectangular)f(tiling)
+f(pattern)h(ma)m(y)h(also)f(b)s(e)g(de\014ned.)58 b(In)35
+b(the)i(case)g(of)g(relativ)m(ely)e(small)0 1233 y(images)j(it)g(ma)m
+(y)h(b)s(e)f(su\016cien)m(t)f(to)i(compress)f(the)h(en)m(tire)f(image)g
+(as)h(a)f(single)f(tile,)j(resulting)c(in)h(an)h(output)0
+1346 y(binary)28 b(table)i(with)f(1)h(ro)m(w.)41 b(In)29
+b(the)h(case)h(of)f(3-dimensional)e(data)j(cub)s(es,)e(it)h(ma)m(y)g(b)
+s(e)f(adv)-5 b(an)m(tageous)32 b(to)f(treat)0 1458 y(eac)m(h)i(plane)e
+(of)h(the)g(cub)s(e)f(as)h(a)g(separate)h(tile)e(if)g(application)f
+(soft)m(w)m(are)k(t)m(ypically)c(needs)i(to)g(access)i(the)e(cub)s(e)0
+1571 y(on)e(a)h(plane)e(b)m(y)i(plane)e(basis.)0 1732
+y(See)41 b(section)f(5.6)i(\\Image)f(Compression")e(for)h(more)h
+(information)e(on)h(using)f(this)g(tile-compressed)h(image)0
+1844 y(format.)p eop
+%%Page: 142 150
+142 149 bop 0 299 a Fj(142)1741 b Fh(CHAPTER)30 b(12.)112
+b(LOCAL)29 b(FITS)h(CONVENTIONS)p eop
+%%Page: 143 151
+143 150 bop 0 1225 a Fg(Chapter)65 b(13)0 1687 y Fm(Optimizing)76
+b(Programs)0 2180 y Fj(CFITSIO)22 b(has)h(b)s(een)f(carefully)g
+(designed)g(to)i(obtain)f(the)g(highest)g(p)s(ossible)d(sp)s(eed)j
+(when)f(reading)g(and)h(writing)0 2293 y(FITS)33 b(\014les.)50
+b(In)33 b(order)h(to)g(ac)m(hiev)m(e)h(the)f(b)s(est)g(p)s(erformance,)
+g(ho)m(w)m(ev)m(er,)i(application)d(programmers)g(m)m(ust)h(b)s(e)0
+2406 y(careful)23 b(to)i(call)e(the)h(CFITSIO)f(routines)f
+(appropriately)h(and)g(in)g(an)g(e\016cien)m(t)i(sequence;)i
+(inappropriate)21 b(usage)0 2518 y(of)31 b(CFITSIO)d(routines)i(can)g
+(greatly)h(slo)m(w)f(do)m(wn)g(the)h(execution)f(sp)s(eed)g(of)g(a)h
+(program.)0 2679 y(The)f(maxim)m(um)g(p)s(ossible)e(I/O)j(sp)s(eed)f
+(of)h(CFITSIO)e(dep)s(ends)g(of)i(course)g(on)f(the)h(t)m(yp)s(e)g(of)g
+(computer)g(system)0 2791 y(that)g(it)e(is)g(running)e(on.)41
+b(As)30 b(a)g(rough)g(guide,)f(the)h(curren)m(t)g(generation)g(of)g(w)m
+(orkstations)g(can)h(ac)m(hiev)m(e)g(sp)s(eeds)0 2904
+y(of)k(2)g({)g(10)g(MB/s)h(when)e(reading)g(or)g(writing)f(FITS)h
+(images)h(and)f(similar,)f(or)i(sligh)m(tly)e(slo)m(w)m(er)i(sp)s(eeds)
+e(with)0 3017 y(FITS)c(binary)g(tables.)40 b(Reading)30
+b(of)g(FITS)g(\014les)f(can)i(o)s(ccur)f(at)h(ev)m(en)f(higher)f(rates)
+i(\(30MB/s)i(or)d(more\))h(if)e(the)0 3130 y(FITS)d(\014le)g(is)f
+(still)g(cac)m(hed)j(in)d(system)i(memory)f(follo)m(wing)g(a)h
+(previous)e(read)h(or)h(write)f(op)s(eration)g(on)h(the)g(same)0
+3243 y(\014le.)43 b(T)-8 b(o)32 b(more)g(accurately)g(predict)e(the)i
+(b)s(est)f(p)s(erformance)g(that)h(is)e(p)s(ossible)f(on)j(an)m(y)g
+(particular)d(system,)k(a)0 3356 y(diagnostic)f(program)h(called)f
+(\\sp)s(eed.c")h(is)f(included)e(with)i(the)h(CFITSIO)e(distribution)e
+(whic)m(h)j(can)h(b)s(e)f(run)0 3469 y(to)f(appro)m(ximately)f(measure)
+g(the)h(maxim)m(um)e(p)s(ossible)f(sp)s(eed)h(of)i(writing)d(and)i
+(reading)g(a)g(test)i(FITS)d(\014le.)0 3629 y(The)k(follo)m(wing)e(2)j
+(sections)f(pro)m(vide)g(some)g(bac)m(kground)g(on)h(ho)m(w)f(CFITSIO)f
+(in)m(ternally)f(manages)j(the)f(data)0 3742 y(I/O)g(and)g(describ)s
+(es)e(some)j(strategies)g(that)g(ma)m(y)g(b)s(e)e(used)h(to)h(optimize)
+e(the)i(pro)s(cessing)e(sp)s(eed)g(of)h(soft)m(w)m(are)0
+3855 y(that)e(uses)f(CFITSIO.)0 4271 y Ff(13.1)136 b(Ho)l(w)45
+b(CFITSIO)f(Manages)i(Data)g(I/O)0 4538 y Fj(Man)m(y)22
+b(CFITSIO)e(op)s(erations)h(in)m(v)m(olv)m(e)h(transferring)e(only)h(a)
+h(small)e(n)m(um)m(b)s(er)h(of)h(b)m(ytes)g(to)g(or)g(from)f(the)h
+(FITS)f(\014le)0 4650 y(\(e.g,)31 b(reading)d(a)h(k)m(eyw)m(ord,)h(or)f
+(writing)e(a)i(ro)m(w)g(in)e(a)i(table\);)h(it)f(w)m(ould)e(b)s(e)h(v)m
+(ery)i(ine\016cien)m(t)e(to)h(ph)m(ysically)e(read)0
+4763 y(or)32 b(write)g(suc)m(h)g(small)e(blo)s(c)m(ks)i(of)g(data)h
+(directly)e(in)g(the)h(FITS)g(\014le)f(on)h(disk,)g(therefore)g
+(CFITSIO)f(main)m(tains)0 4876 y(a)38 b(set)g(of)g(in)m(ternal)f
+(Input{Output)e(\(IO\))j(bu\013ers)f(in)f(RAM)i(memory)g(that)g(eac)m
+(h)h(con)m(tain)f(one)g(FITS)f(blo)s(c)m(k)0 4989 y(\(2880)27
+b(b)m(ytes\))f(of)f(data.)40 b(Whenev)m(er)25 b(CFITSIO)f(needs)g(to)i
+(access)g(data)g(in)e(the)h(FITS)f(\014le,)i(it)e(\014rst)g(transfers)h
+(the)0 5102 y(FITS)30 b(blo)s(c)m(k)g(con)m(taining)g(those)h(b)m(ytes)
+g(in)m(to)f(one)h(of)f(the)h(IO)f(bu\013ers)f(in)g(memory)-8
+b(.)42 b(The)30 b(next)g(time)g(CFITSIO)0 5215 y(needs)36
+b(to)g(access)i(b)m(ytes)e(in)f(the)h(same)h(blo)s(c)m(k)e(it)h(can)g
+(then)g(go)h(to)f(the)h(fast)f(IO)f(bu\013er)g(rather)h(than)g(using)f
+(a)0 5328 y(m)m(uc)m(h)d(slo)m(w)m(er)h(system)f(disk)f(access)i
+(routine.)45 b(The)32 b(n)m(um)m(b)s(er)f(of)h(a)m(v)-5
+b(ailable)32 b(IO)g(bu\013ers)f(is)g(determined)g(b)m(y)h(the)0
+5441 y(NIOBUF)f(parameter)g(\(in)e(\014tsio2.h\))h(and)g(is)g(curren)m
+(tly)f(set)i(to)g(40)g(b)m(y)g(default.)0 5601 y(Whenev)m(er)24
+b(CFITSIO)f(reads)g(or)h(writes)f(data)h(it)g(\014rst)f(c)m(hec)m(ks)i
+(to)g(see)f(if)f(that)h(blo)s(c)m(k)g(of)g(the)g(FITS)f(\014le)f(is)h
+(already)0 5714 y(loaded)32 b(in)m(to)g(one)g(of)g(the)g(IO)g
+(bu\013ers.)44 b(If)32 b(not,)h(and)e(if)g(there)h(is)f(an)h(empt)m(y)h
+(IO)e(bu\013er)g(a)m(v)-5 b(ailable,)32 b(then)g(it)g(will)1882
+5942 y(143)p eop
+%%Page: 144 152
+144 151 bop 0 299 a Fj(144)1876 b Fh(CHAPTER)30 b(13.)112
+b(OPTIMIZING)29 b(PR)m(OGRAMS)0 555 y Fj(load)j(that)i(blo)s(c)m(k)e
+(in)m(to)g(the)h(IO)g(bu\013er)e(\(when)h(reading)g(a)h(FITS)f
+(\014le\))g(or)h(will)d(initialize)g(a)j(new)f(blo)s(c)m(k)h(\(when)0
+668 y(writing)i(to)j(a)g(FITS)f(\014le\).)61 b(If)37
+b(all)f(the)i(IO)e(bu\013ers)h(are)g(already)g(full,)g(it)g(m)m(ust)h
+(decide)e(whic)m(h)g(one)i(to)g(reuse)0 781 y(\(generally)32
+b(the)h(one)g(that)g(has)f(b)s(een)g(accessed)i(least)e(recen)m(tly\),)
+i(and)e(\015ush)f(the)i(con)m(ten)m(ts)h(bac)m(k)g(to)f(disk)e(if)g(it)
+0 894 y(has)f(b)s(een)g(mo)s(di\014ed)e(b)s(efore)i(loading)f(the)i
+(new)f(blo)s(c)m(k.)0 1054 y(The)g(one)g(ma)5 b(jor)30
+b(exception)h(to)g(the)f(ab)s(o)m(v)m(e)h(pro)s(cess)f(o)s(ccurs)g
+(whenev)m(er)g(a)g(large)h(con)m(tiguous)f(set)h(of)f(b)m(ytes)h(are)0
+1167 y(accessed,)37 b(as)d(migh)m(t)h(o)s(ccur)f(when)f(reading)h(or)g
+(writing)e(a)j(FITS)f(image.)53 b(In)34 b(this)f(case)i(CFITSIO)e(b)m
+(ypasses)0 1280 y(the)i(in)m(ternal)f(IO)h(bu\013ers)f(and)g(simply)f
+(reads)i(or)g(writes)g(the)g(desired)f(b)m(ytes)h(directly)f(in)g(the)h
+(disk)f(\014le)g(with)0 1393 y(a)j(single)e(call)g(to)i(a)g(lo)m(w-lev)
+m(el)f(\014le)f(read)h(or)h(write)e(routine.)57 b(The)36
+b(minim)m(um)e(threshold)g(for)i(the)h(n)m(um)m(b)s(er)e(of)0
+1506 y(b)m(ytes)40 b(to)g(read)f(or)g(write)f(this)h(w)m(a)m(y)h(is)e
+(set)i(b)m(y)f(the)g(MINDIRECT)g(parameter)h(and)e(is)h(curren)m(tly)f
+(set)i(to)g(3)0 1619 y(FITS)28 b(blo)s(c)m(ks)f(=)h(8640)i(b)m(ytes.)41
+b(This)27 b(is)g(the)h(most)h(e\016cien)m(t)g(w)m(a)m(y)g(to)g(read)g
+(or)f(write)g(large)g(c)m(h)m(unks)g(of)g(data)i(and)0
+1732 y(can)37 b(ac)m(hiev)m(e)h(IO)e(transfer)g(rates)h(of)g(5)g({)g
+(10MB/s)i(or)d(greater.)61 b(Note)38 b(that)f(this)f(fast)h(direct)f
+(IO)g(pro)s(cess)g(is)0 1844 y(not)29 b(applicable)d(when)h(accessing)i
+(columns)f(of)g(data)h(in)e(a)i(FITS)f(table)g(b)s(ecause)h(the)f(b)m
+(ytes)h(are)g(generally)f(not)0 1957 y(con)m(tiguous)h(since)f(they)h
+(are)h(in)m(terlea)m(v)m(ed)f(b)m(y)g(the)g(other)g(columns)f(of)h
+(data)g(in)f(the)h(table.)40 b(This)27 b(explains)g(wh)m(y)0
+2070 y(the)k(sp)s(eed)e(for)h(accessing)h(FITS)f(tables)g(is)f
+(generally)h(slo)m(w)m(er)g(than)h(accessing)f(FITS)g(images.)0
+2230 y(Giv)m(en)h(this)g(bac)m(kground)g(information,)f(the)i(general)f
+(strategy)i(for)e(e\016cien)m(tly)g(accessing)h(FITS)f(\014les)f
+(should)0 2343 y(b)s(e)f(apparen)m(t:)41 b(when)28 b(dealing)h(with)f
+(FITS)h(images,)h(read)f(or)h(write)f(large)g(c)m(h)m(unks)h(of)g(data)
+g(at)g(a)g(time)f(so)h(that)0 2456 y(the)25 b(direct)f(IO)g(mec)m
+(hanism)f(will)f(b)s(e)i(in)m(v)m(ok)m(ed;)j(when)d(accessing)h(FITS)f
+(headers)g(or)g(FITS)g(tables,)i(on)e(the)h(other)0 2569
+y(hand,)35 b(once)g(a)g(particular)e(FITS)h(blo)s(c)m(k)h(has)f(b)s
+(een)g(loading)g(in)m(to)g(one)h(of)g(the)g(IO)f(bu\013ers,)h(try)g(to)
+g(access)h(all)0 2682 y(the)30 b(needed)g(information)e(in)h(that)h
+(blo)s(c)m(k)g(b)s(efore)g(it)f(gets)i(\015ushed)d(out)j(of)f(the)g(IO)
+f(bu\013er.)40 b(It)30 b(is)f(imp)s(ortan)m(t)g(to)0
+2795 y(a)m(v)m(oid)e(the)g(situation)e(where)h(the)h(same)g(FITS)e(blo)
+s(c)m(k)h(is)g(b)s(eing)f(read)h(then)g(\015ushed)f(from)h(a)h(IO)f
+(bu\013er)f(m)m(ultiple)0 2908 y(times.)0 3068 y(The)30
+b(follo)m(wing)f(section)h(giv)m(es)h(more)f(sp)s(eci\014c)g
+(suggestions)g(for)g(optimizing)f(the)h(use)g(of)h(CFITSIO.)0
+3481 y Ff(13.2)136 b(Optimization)46 b(Strategies)0 3747
+y Fj(1.)54 b(When)34 b(dealing)f(with)h(a)h(FITS)e(primary)g(arra)m(y)i
+(or)g(IMA)m(GE)g(extension,)h(it)e(is)f(more)i(e\016cien)m(t)g(to)g
+(read)g(or)0 3860 y(write)30 b(large)g(c)m(h)m(unks)g(of)g(the)h(image)
+f(at)i(a)e(time)g(\(at)i(least)e(3)h(FITS)f(blo)s(c)m(ks)f(=)h(8640)i
+(b)m(ytes\))f(so)g(that)g(the)f(direct)0 3973 y(IO)j(mec)m(hanism)g
+(will)d(b)s(e)j(used)g(as)g(describ)s(ed)f(in)g(the)h(previous)f
+(section.)50 b(Smaller)32 b(c)m(h)m(unks)h(of)g(data)h(are)g(read)0
+4086 y(or)d(written)f(via)h(the)g(IO)f(bu\013ers,)g(whic)m(h)g(is)g
+(somewhat)h(less)f(e\016cien)m(t)i(b)s(ecause)f(of)g(the)g(extra)h(cop)
+m(y)f(op)s(eration)0 4199 y(and)26 b(additional)e(b)s(o)s(okk)m(eeping)
+i(steps)h(that)g(are)g(required.)38 b(In)26 b(principle)d(it)j(is)g
+(more)g(e\016cien)m(t)h(to)h(read)e(or)h(write)0 4312
+y(as)i(big)f(an)h(arra)m(y)h(of)f(image)g(pixels)e(at)j(one)f(time)f
+(as)i(p)s(ossible,)d(ho)m(w)m(ev)m(er,)j(if)e(the)i(arra)m(y)f(b)s
+(ecomes)g(so)g(large)g(that)0 4425 y(the)j(op)s(erating)f(system)g
+(cannot)h(store)g(it)f(all)g(in)f(RAM,)i(then)f(the)h(p)s(erformance)f
+(ma)m(y)h(b)s(e)f(degraded)g(b)s(ecause)0 4538 y(of)g(the)f(increased)g
+(sw)m(apping)f(of)h(virtual)f(memory)h(to)h(disk.)0 4698
+y(2.)51 b(When)33 b(dealing)g(with)f(FITS)h(tables,)i(the)f(most)g(imp)
+s(ortan)m(t)f(e\016ciency)g(factor)i(in)d(the)i(soft)m(w)m(are)h
+(design)e(is)0 4811 y(to)k(read)f(or)g(write)f(the)h(data)h(in)e(the)h
+(FITS)g(\014le)f(in)g(a)h(single)f(pass)h(through)f(the)h(\014le.)57
+b(An)36 b(example)g(of)g(p)s(o)s(or)0 4924 y(program)g(design)g(w)m
+(ould)f(b)s(e)h(to)h(read)g(a)f(large,)j(3-column)d(table)g(b)m(y)h
+(sequen)m(tially)e(reading)h(the)g(en)m(tire)h(\014rst)0
+5036 y(column,)24 b(then)g(going)g(bac)m(k)g(to)h(read)e(the)h(2nd)g
+(column,)g(and)f(\014nally)f(the)i(3rd)f(column;)i(this)e(ob)m(viously)
+f(requires)0 5149 y(3)27 b(passes)g(through)g(the)g(\014le)f(whic)m(h)g
+(could)g(triple)f(the)j(execution)f(time)g(of)g(an)g(IO)f(limited)f
+(program.)40 b(F)-8 b(or)27 b(small)0 5262 y(tables)j(this)f(is)h(not)g
+(imp)s(ortan)m(t,)g(but)g(when)f(reading)g(m)m(ulti-megab)m(yte)i
+(sized)f(tables)g(these)h(ine\016ciencies)e(can)0 5375
+y(b)s(ecome)g(signi\014can)m(t.)39 b(The)28 b(more)h(e\016cien)m(t)g
+(pro)s(cedure)e(in)h(this)f(case)j(is)d(to)j(read)e(or)h(write)f(only)f
+(as)i(man)m(y)g(ro)m(ws)0 5488 y(of)j(the)g(table)f(as)h(will)d(\014t)j
+(in)m(to)f(the)h(a)m(v)-5 b(ailable)31 b(in)m(ternal)f(IO)h(bu\013ers,)
+h(then)f(access)i(all)d(the)i(necessary)g(columns)0 5601
+y(of)f(data)h(within)c(that)k(range)f(of)g(ro)m(ws.)43
+b(Then)29 b(after)j(the)f(program)g(is)f(completely)g(\014nished)f
+(with)g(the)j(data)f(in)0 5714 y(those)i(ro)m(ws)e(it)h(can)g(mo)m(v)m
+(e)i(on)e(to)g(the)h(next)f(range)g(of)g(ro)m(ws)g(that)h(will)c(\014t)
+j(in)f(the)h(bu\013ers,)f(con)m(tin)m(uing)g(in)g(this)p
+eop
+%%Page: 145 153
+145 152 bop 0 299 a Fh(13.2.)73 b(OPTIMIZA)-8 b(TION)29
+b(STRA)-8 b(TEGIES)2186 b Fj(145)0 555 y(w)m(a)m(y)28
+b(un)m(til)d(the)h(en)m(tire)h(\014le)f(has)g(b)s(een)g(pro)s(cessed.)
+39 b(By)27 b(using)e(this)h(pro)s(cedure)f(of)i(accessing)g(all)f(the)g
+(columns)g(of)0 668 y(a)k(table)f(in)f(parallel)f(rather)i(than)g
+(sequen)m(tially)-8 b(,)29 b(eac)m(h)h(blo)s(c)m(k)f(of)h(the)f(FITS)g
+(\014le)f(will)e(only)j(b)s(e)f(read)i(or)f(written)0
+781 y(once.)0 941 y(The)g(optimal)f(n)m(um)m(b)s(er)g(of)i(ro)m(ws)f
+(to)i(read)e(or)g(write)g(at)h(one)g(time)f(in)f(a)i(giv)m(en)f(table)h
+(dep)s(ends)d(on)j(the)f(width)f(of)0 1054 y(the)j(table)g(ro)m(w,)g
+(on)g(the)g(n)m(um)m(b)s(er)f(of)h(IO)g(bu\013ers)e(that)j(ha)m(v)m(e)g
+(b)s(een)e(allo)s(cated)h(in)f(CFITSIO,)g(and)g(also)h(on)g(the)0
+1167 y(n)m(um)m(b)s(er)f(of)h(other)g(FITS)f(\014les)g(that)i(are)f(op)
+s(en)f(at)i(the)f(same)g(time)g(\(since)g(one)g(IO)f(bu\013er)g(is)g
+(alw)m(a)m(ys)i(reserv)m(ed)0 1280 y(for)i(eac)m(h)h(op)s(en)e(FITS)g
+(\014le\).)50 b(The)34 b(CFITSIO)e(Iterator)j(routine)e(will)e
+(automatically)j(use)f(the)h(optimal-sized)0 1393 y(bu\013er,)43
+b(but)c(there)i(is)f(also)h(a)g(CFITSIO)e(routine)h(that)h(will)d
+(return)i(the)h(optimal)e(n)m(um)m(b)s(er)h(of)g(ro)m(ws)h(for)g(a)0
+1506 y(giv)m(en)36 b(table:)52 b(\014ts)p 644 1506 28
+4 v 32 w(get)p 796 1506 V 34 w(ro)m(wsize.)57 b(It)37
+b(is)d(not)j(critical)d(to)j(use)f(exactly)g(the)h(v)-5
+b(alue)35 b(of)h(nro)m(ws)f(returned)g(b)m(y)h(this)0
+1619 y(routine,)30 b(as)h(long)f(as)h(one)g(do)s(es)f(not)h(exceed)g
+(it.)41 b(Using)30 b(a)h(v)m(ery)g(small)e(v)-5 b(alue)30
+b(ho)m(w)m(ev)m(er)i(can)f(also)f(lead)h(to)g(p)s(o)s(or)0
+1732 y(p)s(erformance)f(b)s(ecause)g(of)h(the)f(o)m(v)m(erhead)i(from)e
+(the)g(larger)g(n)m(um)m(b)s(er)f(of)i(subroutine)d(calls.)0
+1892 y(The)36 b(optimal)f(n)m(um)m(b)s(er)g(of)h(ro)m(ws)g(returned)f
+(b)m(y)i(\014ts)p 1829 1892 V 32 w(get)p 1981 1892 V
+34 w(ro)m(wsize)f(is)g(v)-5 b(alid)34 b(only)h(as)i(long)f(as)g(the)h
+(application)0 2005 y(program)27 b(is)f(only)g(reading)h(or)g(writing)e
+(data)j(in)e(the)h(sp)s(eci\014ed)e(table.)40 b(An)m(y)27
+b(other)g(calls)g(to)h(access)g(data)g(in)e(the)0 2118
+y(table)31 b(header)g(or)g(in)e(an)m(y)j(other)f(FITS)f(\014le)g(w)m
+(ould)g(cause)h(additional)e(blo)s(c)m(ks)i(of)g(data)g(to)h(b)s(e)e
+(loaded)h(in)m(to)g(the)0 2230 y(IO)c(bu\013ers)g(displacing)f(data)i
+(from)g(the)g(original)e(table,)j(and)e(should)f(b)s(e)i(a)m(v)m(oided)
+g(during)e(the)i(critical)f(p)s(erio)s(d)0 2343 y(while)h(the)j(table)f
+(is)g(b)s(eing)f(read)h(or)g(written.)0 2503 y(Occasionally)f(it)g(is)f
+(necessary)i(to)h(sim)m(ultaneously)c(access)k(more)f(than)f(one)h
+(FITS)f(table,)h(for)g(example)f(when)0 2616 y(transferring)41
+b(v)-5 b(alues)42 b(from)g(an)h(input)d(table)j(to)g(an)g(output)f
+(table.)78 b(In)42 b(cases)h(lik)m(e)f(this,)j(one)e(should)e(call)0
+2729 y(\014ts)p 127 2729 V 32 w(get)p 279 2729 V 34 w(ro)m(wsize)24
+b(to)g(get)h(the)f(optimal)e(n)m(um)m(b)s(er)g(of)i(ro)m(ws)g(for)f
+(eac)m(h)i(table)e(separately)-8 b(,)26 b(than)d(reduce)h(the)f(n)m(um)
+m(b)s(er)0 2842 y(of)31 b(ro)m(ws)h(prop)s(ortionally)-8
+b(.)41 b(F)-8 b(or)32 b(example,)f(if)f(the)i(optimal)e(n)m(um)m(b)s
+(er)g(of)h(ro)m(ws)g(in)f(the)i(input)d(table)i(is)g(3600)i(and)0
+2955 y(is)f(1400)i(in)e(the)h(output)f(table,)h(then)g(these)g(v)-5
+b(alues)32 b(should)f(b)s(e)h(cut)h(in)e(half)h(to)h(1800)i(and)d(700,)
+j(resp)s(ectiv)m(ely)-8 b(,)0 3068 y(if)29 b(b)s(oth)h(tables)g(are)h
+(going)f(to)h(b)s(e)f(accessed)i(at)f(the)f(same)h(time.)0
+3228 y(3.)39 b(Use)25 b(the)g(CFITSIO)e(Iterator)j(routine.)38
+b(This)23 b(routine)h(pro)m(vides)f(a)j(more)e(`ob)5
+b(ject)26 b(orien)m(ted')f(w)m(a)m(y)h(of)f(reading)0
+3341 y(and)34 b(writing)e(FITS)i(\014les)f(whic)m(h)h(automatically)g
+(uses)g(the)g(most)h(appropriate)f(data)h(bu\013er)e(size)h(to)i(ac)m
+(hiev)m(e)0 3454 y(the)31 b(maxim)m(um)e(I/O)h(throughput.)0
+3614 y(4.)39 b(Use)24 b(binary)e(table)h(extensions)g(rather)g(than)h
+(ASCI)s(I)e(table)h(extensions)g(for)g(b)s(etter)h(e\016ciency)g(when)e
+(dealing)0 3727 y(with)36 b(tabular)h(data.)62 b(The)37
+b(I/O)g(to)h(ASCI)s(I)e(tables)h(is)g(slo)m(w)m(er)g(b)s(ecause)h(of)f
+(the)h(o)m(v)m(erhead)h(in)d(formatting)h(or)0 3840 y(parsing)31
+b(the)h(ASCI)s(I)f(data)i(\014elds)e(and)h(b)s(ecause)g(ASCI)s(I)f
+(tables)h(are)h(ab)s(out)f(t)m(wice)h(as)g(large)f(as)h(binary)d
+(tables)0 3953 y(with)f(the)i(same)f(information)f(con)m(ten)m(t.)0
+4113 y(5.)64 b(Design)38 b(soft)m(w)m(are)h(so)g(that)f(it)g(reads)g
+(the)g(FITS)f(header)h(k)m(eyw)m(ords)g(in)f(the)h(same)h(order)e(in)g
+(whic)m(h)g(they)0 4226 y(o)s(ccur)28 b(in)g(the)h(\014le.)39
+b(When)28 b(reading)g(k)m(eyw)m(ords,)i(CFITSIO)d(searc)m(hes)i(forw)m
+(ard)g(starting)f(from)g(the)h(p)s(osition)e(of)0 4339
+y(the)i(last)h(k)m(eyw)m(ord)f(that)h(w)m(as)g(read.)40
+b(If)29 b(it)f(reac)m(hes)j(the)e(end)g(of)g(the)h(header)f(without)f
+(\014nding)f(the)i(k)m(eyw)m(ord,)h(it)0 4452 y(then)j(go)s(es)h(bac)m
+(k)g(to)h(the)e(start)h(of)g(the)g(header)f(and)g(con)m(tin)m(ues)g
+(the)h(searc)m(h)g(do)m(wn)f(to)h(the)g(p)s(osition)d(where)i(it)0
+4565 y(started.)41 b(In)30 b(practice,)h(as)f(long)g(as)h(the)f(en)m
+(tire)h(FITS)e(header)h(can)h(\014t)f(at)h(one)g(time)f(in)f(the)h(a)m
+(v)-5 b(ailable)30 b(in)m(ternal)0 4678 y(IO)36 b(bu\013ers,)h(then)f
+(the)g(header)g(k)m(eyw)m(ord)h(access)g(will)d(b)s(e)i(v)m(ery)g(fast)
+h(and)f(it)f(mak)m(es)i(little)e(di\013erence)h(whic)m(h)0
+4791 y(order)30 b(they)g(are)h(accessed.)0 4951 y(6.)40
+b(Av)m(oid)28 b(the)f(use)h(of)f(scaling)g(\(b)m(y)h(using)e(the)i
+(BSCALE)e(and)h(BZER)m(O)h(or)f(TSCAL)g(and)g(TZER)m(O)f(k)m(eyw)m
+(ords\))0 5064 y(in)34 b(FITS)g(\014les)f(since)i(the)g(scaling)f(op)s
+(erations)g(add)g(to)i(the)f(pro)s(cessing)e(time)i(needed)f(to)i(read)
+f(or)g(write)f(the)0 5176 y(data.)39 b(In)24 b(some)h(cases)h(it)e(ma)m
+(y)h(b)s(e)f(more)g(e\016cien)m(t)h(to)h(temp)s(orarily)c(turn)i(o\013)
+h(the)f(scaling)g(\(using)f(\014ts)p 3490 5176 V 33 w(set)p
+3634 5176 V 33 w(bscale)0 5289 y(or)30 b(\014ts)p 238
+5289 V 33 w(set)p 382 5289 V 33 w(tscale\))i(and)d(then)h(read)h(or)f
+(write)g(the)g(ra)m(w)h(unscaled)e(v)-5 b(alues)30 b(in)f(the)h(FITS)g
+(\014le.)0 5450 y(7.)77 b(Av)m(oid)42 b(using)f(the)i(`implicit)c(data)
+44 b(t)m(yp)s(e)e(con)m(v)m(ersion')h(capabilit)m(y)e(in)g(CFITSIO.)g
+(F)-8 b(or)44 b(instance,)h(when)0 5562 y(reading)27
+b(a)h(FITS)f(image)h(with)e(BITPIX)i(=)f(-32)i(\(32-bit)f(\015oating)g
+(p)s(oin)m(t)f(pixels\),)g(read)g(the)h(data)g(in)m(to)g(a)g(single)0
+5675 y(precision)38 b(\015oating)i(p)s(oin)m(t)f(data)i(arra)m(y)f(in)f
+(the)h(program.)69 b(F)-8 b(orcing)40 b(CFITSIO)f(to)i(con)m(v)m(ert)g
+(the)f(data)h(to)g(a)p eop
+%%Page: 146 154
+146 153 bop 0 299 a Fj(146)1876 b Fh(CHAPTER)30 b(13.)112
+b(OPTIMIZING)29 b(PR)m(OGRAMS)0 555 y Fj(di\013eren)m(t)h(data)h(t)m
+(yp)s(e)f(can)h(slo)m(w)f(the)h(program.)0 715 y(8.)57
+b(Where)36 b(feasible,)g(design)f(FITS)g(binary)f(tables)h(using)f(v)m
+(ector)k(column)c(elemen)m(ts)i(so)g(that)g(the)g(data)h(are)0
+828 y(written)29 b(as)h(a)g(con)m(tiguous)g(set)g(of)g(b)m(ytes,)g
+(rather)g(than)f(as)h(single)e(elemen)m(ts)i(in)f(m)m(ultiple)e(ro)m
+(ws.)41 b(F)-8 b(or)30 b(example,)0 941 y(it)35 b(is)g(faster)h(to)g
+(access)h(the)f(data)h(in)d(a)i(table)g(that)g(con)m(tains)g(a)g
+(single)e(ro)m(w)i(and)f(2)h(columns)e(with)h(TF)m(ORM)0
+1054 y(k)m(eyw)m(ords)e(equal)g(to)h('10000E')h(and)e('10000J',)j(than)
+d(it)f(is)g(to)i(access)g(the)g(same)f(amoun)m(t)h(of)f(data)h(in)e(a)h
+(table)0 1167 y(with)39 b(10000)k(ro)m(ws)d(whic)m(h)g(has)g(columns)f
+(with)g(the)i(TF)m(ORM)g(k)m(eyw)m(ords)g(equal)f(to)h('1E')h(and)e
+('1J'.)h(In)f(the)0 1280 y(former)27 b(case)i(the)f(10000)i(\015oating)
+e(p)s(oin)m(t)f(v)-5 b(alues)27 b(in)g(the)h(\014rst)f(column)g(are)h
+(all)f(written)g(in)f(a)i(con)m(tiguous)g(blo)s(c)m(k)0
+1393 y(of)e(the)f(\014le)g(whic)m(h)f(can)i(b)s(e)f(read)g(or)g
+(written)g(quic)m(kly)-8 b(,)26 b(whereas)f(in)f(the)i(second)f(case)i
+(eac)m(h)g(\015oating)e(p)s(oin)m(t)f(v)-5 b(alue)0 1506
+y(in)33 b(the)h(\014rst)f(column)f(is)h(in)m(terlea)m(v)m(ed)i(with)d
+(the)i(in)m(teger)h(v)-5 b(alue)33 b(in)g(the)h(second)g(column)e(of)i
+(the)g(same)h(ro)m(w)f(so)0 1619 y(CFITSIO)29 b(has)h(to)h(explicitly)d
+(mo)m(v)m(e)k(to)f(the)g(p)s(osition)d(of)j(eac)m(h)g(elemen)m(t)g(to)g
+(b)s(e)f(read)g(or)g(written.)0 1779 y(9.)52 b(Av)m(oid)34
+b(the)h(use)e(of)i(v)-5 b(ariable)32 b(length)i(v)m(ector)i(columns)c
+(in)h(binary)g(tables,)i(since)e(an)m(y)i(reading)e(or)h(writing)0
+1892 y(of)f(these)g(data)g(requires)e(that)i(CFITSIO)f(\014rst)f(lo)s
+(ok)i(up)e(or)i(compute)g(the)f(starting)h(address)f(of)g(eac)m(h)i(ro)
+m(w)f(of)0 2005 y(data)e(in)e(the)i(heap.)0 2165 y(10.)73
+b(When)40 b(cop)m(ying)h(data)h(from)e(one)h(FITS)f(table)h(to)g
+(another,)j(it)d(is)e(faster)j(to)f(transfer)g(the)f(ra)m(w)h(b)m(ytes)
+0 2278 y(instead)27 b(of)i(reading)e(then)h(writing)e(eac)m(h)j(column)
+e(of)h(the)g(table.)40 b(The)28 b(CFITSIO)e(routines)h(\014ts)p
+3349 2278 28 4 v 33 w(read)p 3554 2278 V 32 w(tblb)m(ytes)0
+2391 y(and)36 b(\014ts)p 310 2391 V 32 w(write)p 545
+2391 V 32 w(tblb)m(ytes)h(will)d(p)s(erform)h(lo)m(w-lev)m(el)h(reads)h
+(or)f(writes)g(of)h(an)m(y)g(con)m(tiguous)f(range)h(of)g(b)m(ytes)g
+(in)0 2503 y(a)d(table)f(extension.)50 b(These)33 b(routines)g(can)g(b)
+s(e)g(used)g(to)h(read)f(or)h(write)f(a)g(whole)g(ro)m(w)h(\(or)g(m)m
+(ultiple)d(ro)m(ws)i(for)0 2616 y(ev)m(en)e(greater)h(e\016ciency\))g
+(of)f(a)g(table)g(with)e(a)i(single)f(function)f(call.)41
+b(These)31 b(routines)f(are)h(fast)g(b)s(ecause)g(they)0
+2729 y(b)m(ypass)36 b(all)f(the)i(usual)e(data)i(scaling,)g(error)f(c)m
+(hec)m(king)h(and)f(mac)m(hine)g(dep)s(enden)m(t)f(data)i(con)m(v)m
+(ersion)g(that)g(is)0 2842 y(normally)e(done)i(b)m(y)f(CFITSIO,)g(and)g
+(they)h(allo)m(w)f(the)i(program)e(to)i(write)e(the)h(data)g(to)h(the)f
+(output)f(\014le)g(in)0 2955 y(exactly)29 b(the)f(same)h(b)m(yte)g
+(order.)40 b(F)-8 b(or)29 b(these)f(same)h(reasons,)g(these)g(routines)
+e(can)h(corrupt)g(the)g(FITS)g(data)h(\014le)0 3068 y(if)35
+b(used)f(incorrectly)h(b)s(ecause)h(no)f(v)-5 b(alidation)34
+b(or)i(mac)m(hine)f(dep)s(enden)m(t)f(con)m(v)m(ersion)i(is)f(p)s
+(erformed)f(b)m(y)h(these)0 3181 y(routines.)54 b(These)35
+b(routines)f(are)i(only)e(recommended)h(for)g(optimizing)e(critical)h
+(pieces)h(of)h(co)s(de)f(and)g(should)0 3294 y(only)d(b)s(e)h(used)g(b)
+m(y)g(programmers)g(who)g(thoroughly)f(understand)f(the)j(in)m(ternal)e
+(format)i(of)f(the)h(FITS)e(tables)0 3407 y(they)f(are)f(reading)g(or)g
+(writing.)0 3567 y(11.)41 b(Another)30 b(strategy)g(for)g(impro)m(ving)
+d(the)j(sp)s(eed)e(of)i(writing)e(a)h(FITS)g(table,)h(similar)d(to)j
+(the)f(previous)f(one,)0 3680 y(is)j(to)h(directly)f(construct)h(the)f
+(en)m(tire)h(b)m(yte)g(stream)g(for)g(a)g(whole)f(table)g(ro)m(w)h
+(\(or)g(m)m(ultiple)e(ro)m(ws\))i(within)d(the)0 3793
+y(application)f(program)h(and)g(then)h(write)f(it)g(to)h(the)g(FITS)f
+(\014le)g(with)f(\014ts)p 2520 3793 V 32 w(write)p 2755
+3793 V 32 w(tblb)m(ytes.)40 b(This)28 b(a)m(v)m(oids)i(all)f(the)0
+3906 y(o)m(v)m(erhead)h(normally)e(presen)m(t)h(in)f(the)i
+(column-orien)m(ted)e(CFITSIO)g(write)g(routines.)39
+b(This)28 b(tec)m(hnique)h(should)0 4019 y(only)34 b(b)s(e)f(used)h
+(for)g(critical)f(applications)g(b)s(ecause)h(it)g(mak)m(es)i(the)e(co)
+s(de)h(more)f(di\016cult)f(to)i(understand)e(and)0 4131
+y(main)m(tain,)j(and)f(it)g(mak)m(es)h(the)g(co)s(de)f(more)h(system)g
+(dep)s(enden)m(t)e(\(e.g.,)39 b(do)c(the)h(b)m(ytes)g(need)f(to)h(b)s
+(e)f(sw)m(app)s(ed)0 4244 y(b)s(efore)30 b(writing)e(to)j(the)g(FITS)f
+(\014le?\).)0 4405 y(12.)53 b(Finally)-8 b(,)34 b(external)g(factors)i
+(suc)m(h)e(as)g(the)h(t)m(yp)s(e)f(of)h(magnetic)f(disk)f(con)m
+(troller)h(\(SCSI)f(or)i(IDE\),)g(the)f(size)0 4517 y(of)h(the)g(disk)f
+(cac)m(he,)k(the)d(a)m(v)m(erage)i(seek)f(sp)s(eed)e(of)h(the)g(disk,)g
+(the)g(amoun)m(t)h(of)f(disk)e(fragmen)m(tation,)k(and)e(the)0
+4630 y(amoun)m(t)29 b(of)g(RAM)f(a)m(v)-5 b(ailable)28
+b(on)h(the)f(system)h(can)g(all)e(ha)m(v)m(e)j(a)f(signi\014can)m(t)e
+(impact)i(on)f(o)m(v)m(erall)h(I/O)f(e\016ciency)-8 b(.)0
+4743 y(F)g(or)36 b(critical)e(applications,)g(a)i(system)f
+(administrator)e(should)g(review)h(the)i(prop)s(osed)d(system)j(hardw)m
+(are)e(to)0 4856 y(iden)m(tify)29 b(an)m(y)i(p)s(oten)m(tial)e(I/O)i(b)
+s(ottlenec)m(ks.)p eop
+%%Page: 147 155
+147 154 bop 0 1225 a Fg(App)5 b(endix)65 b(A)0 1687 y
+Fm(Index)77 b(of)h(Routines)50 2154 y Fj(\014ts)p 177
+2154 28 4 v 32 w(add)p 356 2154 V 32 w(group)p 616 2154
+V 33 w(mem)m(b)s(er)144 b(78)50 2267 y(\014ts)p 177 2267
+V 32 w(ascii)p 382 2267 V 32 w(tform)478 b(59)50 2380
+y(\014ts)p 177 2380 V 32 w(binary)p 466 2380 V 31 w(tform)395
+b(59)50 2493 y(\014ts)p 177 2493 V 32 w(calculator)514
+b(52)50 2606 y(\014ts)p 177 2606 V 32 w(calculator)p
+598 2606 V 33 w(rng)349 b(53)50 2719 y(\014ts)p 177 2719
+V 32 w(calc)p 360 2719 V 34 w(ro)m(ws)538 b(52)50 2832
+y(\014ts)p 177 2832 V 32 w(c)m(hange)p 478 2832 V 34
+w(group)372 b(76)50 2945 y(\014ts)p 177 2945 V 32 w(clear)p
+396 2945 V 33 w(errmark)366 b(30)50 3057 y(\014ts)p 177
+3057 V 32 w(clear)p 396 3057 V 33 w(errmsg)414 b(30)50
+3170 y(\014ts)p 177 3170 V 32 w(close)p 396 3170 V 33
+w(\014le)566 b(33)50 3283 y(\014ts)p 177 3283 V 32 w(compact)p
+541 3283 V 34 w(group)309 b(77)50 3396 y(\014ts)p 177
+3396 V 32 w(compare)p 542 3396 V 34 w(str)429 b(56)50
+3509 y(\014ts)p 177 3509 V 32 w(compress)p 569 3509 V
+33 w(heap)278 b(100)50 3622 y(\014ts)p 177 3622 V 32
+w(cop)m(y)p 390 3622 V 34 w(col)577 b(49)50 3735 y(\014ts)p
+177 3735 V 32 w(cop)m(y)p 390 3735 V 34 w(data)512 b(86)50
+3848 y(\014ts)p 177 3848 V 32 w(cop)m(y)p 390 3848 V
+34 w(\014le)571 b(34)50 3961 y(\014ts)p 177 3961 V 32
+w(cop)m(y)p 390 3961 V 34 w(group)460 b(77)50 4074 y(\014ts)p
+177 4074 V 32 w(cop)m(y)p 390 4074 V 34 w(hdu)535 b(34)50
+4187 y(\014ts)p 177 4187 V 32 w(cop)m(y)p 390 4187 V
+34 w(header)425 b(34)50 4299 y(\014ts)p 177 4299 V 32
+w(cop)m(y)p 390 4299 V 34 w(k)m(ey)555 b(89)50 4412 y(\014ts)p
+177 4412 V 32 w(cop)m(y)p 390 4412 V 34 w(mem)m(b)s(er)369
+b(79)50 4525 y(\014ts)p 177 4525 V 32 w(create)p 445
+4525 V 35 w(disk\014le)354 b(32)50 4638 y(\014ts)p 177
+4638 V 32 w(create)p 445 4638 V 35 w(\014le)515 b(32)50
+4751 y(\014ts)p 177 4751 V 32 w(create)p 445 4751 V 35
+w(group)404 b(76)50 4864 y(\014ts)p 177 4864 V 32 w(create)p
+445 4864 V 35 w(hdu)479 b(84)50 4977 y(\014ts)p 177 4977
+V 32 w(create)p 445 4977 V 35 w(img)485 b(40)50 5090
+y(\014ts)p 177 5090 V 32 w(create)p 445 5090 V 35 w(mem\014le)323
+b(82)50 5203 y(\014ts)p 177 5203 V 32 w(create)p 445
+5203 V 35 w(tbl)520 b(46)50 5316 y(\014ts)p 177 5316
+V 32 w(create)p 445 5316 V 35 w(template)284 b(82)50
+5429 y(\014ts)p 177 5429 V 32 w(date2str)580 b(55)50
+5541 y(\014ts)p 177 5541 V 32 w(deco)s(de)p 479 5541
+V 33 w(c)m(hksum)301 b(54)50 5654 y(\014ts)p 177 5654
+V 32 w(deco)s(de)p 479 5654 V 33 w(tdim)412 b(48)1325
+2154 y(\014ts)p 1452 2154 V 33 w(delete)p 1717 2154 V
+33 w(col)565 b(49)1325 2267 y(\014ts)p 1452 2267 V 33
+w(delete)p 1717 2267 V 33 w(\014le)559 b(33)1325 2380
+y(\014ts)p 1452 2380 V 33 w(delete)p 1717 2380 V 33 w(hdu)523
+b(35)1325 2493 y(\014ts)p 1452 2493 V 33 w(delete)p 1717
+2493 V 33 w(k)m(ey)543 b(39)1325 2606 y(\014ts)p 1452
+2606 V 33 w(delete)p 1717 2606 V 33 w(record)428 b(39)1325
+2719 y(\014ts)p 1452 2719 V 33 w(delete)p 1717 2719 V
+33 w(ro)m(wlist)409 b(48)1325 2832 y(\014ts)p 1452 2832
+V 33 w(delete)p 1717 2832 V 33 w(ro)m(wrange)315 b(48)1325
+2945 y(\014ts)p 1452 2945 V 33 w(delete)p 1717 2945 V
+33 w(ro)m(ws)496 b(48)1325 3057 y(\014ts)p 1452 3057
+V 33 w(enco)s(de)p 1755 3057 V 33 w(c)m(hksum)339 b(54)1325
+3170 y(\014ts)p 1452 3170 V 33 w(\014le)p 1602 3170 V
+32 w(exists)571 b(83)1325 3283 y(\014ts)p 1452 3283 V
+33 w(\014le)p 1602 3283 V 32 w(mo)s(de)577 b(33)1325
+3396 y(\014ts)p 1452 3396 V 33 w(\014le)p 1602 3396 V
+32 w(name)j(33)1325 3509 y(\014ts)p 1452 3509 V 33 w(\014nd)p
+1638 3509 V 31 w(\014rst)p 1827 3509 V 32 w(ro)m(w)423
+b(52)1325 3622 y(\014ts)p 1452 3622 V 33 w(\014nd)p 1638
+3622 V 31 w(nextk)m(ey)450 b(36)1325 3735 y(\014ts)p
+1452 3735 V 33 w(\014nd)p 1638 3735 V 31 w(ro)m(ws)577
+b(52)1325 3848 y(\014ts)p 1452 3848 V 33 w(\015ush)p
+1674 3848 V 31 w(bu\013er)490 b(84)1325 3961 y(\014ts)p
+1452 3961 V 33 w(\015ush)p 1674 3961 V 31 w(\014le)604
+b(84)1325 4074 y(\014ts)p 1452 4074 V 33 w(get)p 1605
+4074 V 34 w(acolparms)387 b(99)1325 4187 y(\014ts)p 1452
+4187 V 33 w(get)p 1605 4187 V 34 w(b)s(colparms)378 b(99)1325
+4299 y(\014ts)p 1452 4299 V 33 w(get)p 1605 4299 V 34
+w(c)m(hksum)488 b(54)1325 4412 y(\014ts)p 1452 4412 V
+33 w(get)p 1605 4412 V 34 w(col)p 1750 4412 V 32 w(displa)m(y)p
+2062 4412 V 31 w(width)104 b(48)1325 4525 y(\014ts)p
+1452 4525 V 33 w(get)p 1605 4525 V 34 w(colname)464 b(46)1325
+4638 y(\014ts)p 1452 4638 V 33 w(get)p 1605 4638 V 34
+w(coln)m(um)501 b(46)1325 4751 y(\014ts)p 1452 4751 V
+33 w(get)p 1605 4751 V 34 w(colt)m(yp)s(e)h(47)1325 4864
+y(\014ts)p 1452 4864 V 33 w(get)p 1605 4864 V 34 w(compression)p
+2121 4864 V 31 w(t)m(yp)s(e)100 b(44)1325 4977 y(\014ts)p
+1452 4977 V 33 w(get)p 1605 4977 V 34 w(eqcolt)m(yp)s(e)414
+b(47)1325 5090 y(\014ts)p 1452 5090 V 33 w(get)p 1605
+5090 V 34 w(errstatus)437 b(29)1325 5203 y(\014ts)p 1452
+5203 V 33 w(get)p 1605 5203 V 34 w(hdrp)s(os)514 b(86)1325
+5316 y(\014ts)p 1452 5316 V 33 w(get)p 1605 5316 V 34
+w(hdrspace)437 b(35)1325 5429 y(\014ts)p 1452 5429 V
+33 w(get)p 1605 5429 V 34 w(hdu)p 1792 5429 V 31 w(n)m(um)428
+b(34)1325 5541 y(\014ts)p 1452 5541 V 33 w(get)p 1605
+5541 V 34 w(hdu)p 1792 5541 V 31 w(t)m(yp)s(e)h(34)1325
+5654 y(\014ts)p 1452 5654 V 33 w(get)p 1605 5654 V 34
+w(hduaddr)451 b(84)2639 2154 y(\014ts)p 2766 2154 V 33
+w(get)p 2919 2154 V 34 w(hduo\013)560 b(84)2639 2267
+y(\014ts)p 2766 2267 V 33 w(get)p 2919 2267 V 34 w(img)p
+3100 2267 V 32 w(dim)479 b(40)2639 2380 y(\014ts)p 2766
+2380 V 33 w(get)p 2919 2380 V 34 w(img)p 3100 2380 V
+32 w(equivt)m(yp)s(e)245 b(40)2639 2493 y(\014ts)p 2766
+2493 V 33 w(get)p 2919 2493 V 34 w(img)p 3100 2493 V
+32 w(param)379 b(40)2639 2606 y(\014ts)p 2766 2606 V
+33 w(get)p 2919 2606 V 34 w(img)p 3100 2606 V 32 w(size)490
+b(40)2639 2719 y(\014ts)p 2766 2719 V 33 w(get)p 2919
+2719 V 34 w(img)p 3100 2719 V 32 w(t)m(yp)s(e)458 b(40)2639
+2832 y(\014ts)p 2766 2832 V 33 w(get)p 2919 2832 V 34
+w(k)m(eyclass)495 b(58)2639 2945 y(\014ts)p 2766 2945
+V 33 w(get)p 2919 2945 V 34 w(k)m(eyname)466 b(57)2639
+3057 y(\014ts)p 2766 3057 V 33 w(get)p 2919 3057 V 34
+w(k)m(eyt)m(yp)s(e)504 b(58)2639 3170 y(\014ts)p 2766
+3170 V 33 w(get)p 2919 3170 V 34 w(noise)p 3151 3170
+V 32 w(bits)433 b(44)2639 3283 y(\014ts)p 2766 3283 V
+33 w(get)p 2919 3283 V 34 w(n)m(um)p 3128 3283 V 32 w(cols)457
+b(46)2639 3396 y(\014ts)p 2766 3396 V 33 w(get)p 2919
+3396 V 34 w(n)m(um)p 3128 3396 V 32 w(groups)340 b(79)2639
+3509 y(\014ts)p 2766 3509 V 33 w(get)p 2919 3509 V 34
+w(n)m(um)p 3128 3509 V 32 w(hdus)415 b(33)2639 3622 y(\014ts)p
+2766 3622 V 33 w(get)p 2919 3622 V 34 w(n)m(um)p 3128
+3622 V 32 w(mem)m(b)s(ers)249 b(78)2639 3735 y(\014ts)p
+2766 3735 V 33 w(get)p 2919 3735 V 34 w(n)m(um)p 3128
+3735 V 32 w(ro)m(ws)424 b(46)2639 3848 y(\014ts)p 2766
+3848 V 33 w(get)p 2919 3848 V 34 w(ro)m(wsize)525 b(99)2639
+3961 y(\014ts)p 2766 3961 V 33 w(get)p 2919 3961 V 34
+w(system)p 3224 3961 V 33 w(time)330 b(55)2639 4074 y(\014ts)p
+2766 4074 V 33 w(get)p 2919 4074 V 34 w(tile)p 3080 4074
+V 32 w(dim)499 b(44)2639 4187 y(\014ts)p 2766 4187 V
+33 w(get)p 2919 4187 V 34 w(tb)s(col)611 b(59)2639 4299
+y(\014ts)p 2766 4299 V 33 w(get)p 2919 4299 V 34 w(v)m(ersion)532
+b(56)2639 4412 y(\014ts)p 2766 4412 V 33 w(hdr2str)d(37,)31
+b(72)2639 4525 y(\014ts)p 2766 4525 V 33 w(insert)p 3023
+4525 V 31 w(atbl)553 b(85)2639 4638 y(\014ts)p 2766 4638
+V 33 w(insert)p 3023 4638 V 31 w(btbl)547 b(85)2639 4751
+y(\014ts)p 2766 4751 V 33 w(insert)p 3023 4751 V 31 w(col)599
+b(49)2639 4864 y(\014ts)p 2766 4864 V 33 w(insert)p 3023
+4864 V 31 w(cols)563 b(49)2639 4977 y(\014ts)p 2766 4977
+V 33 w(insert)p 3023 4977 V 31 w(group)482 b(76)2639
+5090 y(\014ts)p 2766 5090 V 33 w(insert)p 3023 5090 V
+31 w(img)563 b(85)2639 5203 y(\014ts)p 2766 5203 V 33
+w(insert)p 3023 5203 V 31 w(k)m(ey)p 3187 5203 V 34 w(n)m(ull)392
+b(91)2639 5316 y(\014ts)p 2766 5316 V 33 w(insert)p 3023
+5316 V 31 w(k)m(ey)p 3187 5316 V 34 w(TYP)347 b(90)2639
+5429 y(\014ts)p 2766 5429 V 33 w(insert)p 3023 5429 V
+31 w(record)462 b(90)2639 5541 y(\014ts)p 2766 5541 V
+33 w(insert)p 3023 5541 V 31 w(ro)m(ws)530 b(48)2639
+5654 y(\014ts)p 2766 5654 V 33 w(iterate)p 3056 5654
+V 33 w(data)499 b(69)1882 5942 y(147)p eop
+%%Page: 148 156
+148 155 bop 0 299 a Fj(148)2084 b Fh(APPENDIX)31 b(A.)61
+b(INDEX)31 b(OF)f(R)m(OUTINES)50 599 y Fj(\014ts)p 177
+599 28 4 v 32 w(mak)m(e)p 415 599 V 34 w(k)m(eyn)421
+b(57)50 712 y(\014ts)p 177 712 V 32 w(mak)m(e)p 415 712
+V 34 w(nk)m(ey)g(58)50 825 y(\014ts)p 177 825 V 32 w(merge)p
+446 825 V 34 w(groups)310 b(77)50 938 y(\014ts)p 177
+938 V 32 w(mo)s(dify)p 486 938 V 31 w(card)365 b(92)50
+1051 y(\014ts)p 177 1051 V 32 w(mo)s(dify)p 486 1051
+V 31 w(commen)m(t)177 b(38)50 1164 y(\014ts)p 177 1164
+V 32 w(mo)s(dify)p 486 1164 V 31 w(k)m(ey)p 650 1164
+V 34 w(n)m(ull)219 b(93)50 1277 y(\014ts)p 177 1277 V
+32 w(mo)s(dify)p 486 1277 V 31 w(k)m(ey)p 650 1277 V
+34 w(TYP)174 b(93)50 1390 y(\014ts)p 177 1390 V 32 w(mo)s(dify)p
+486 1390 V 31 w(name)325 b(39)50 1503 y(\014ts)p 177
+1503 V 32 w(mo)s(dify)p 486 1503 V 31 w(record)289 b(92)50
+1616 y(\014ts)p 177 1616 V 32 w(mo)s(dify)p 486 1616
+V 31 w(v)m(ector)p 758 1616 V 35 w(len)144 b(49)50 1728
+y(\014ts)p 177 1728 V 32 w(mo)m(v)-5 b(abs)p 502 1728
+V 33 w(hdu)366 b(33)50 1841 y(\014ts)p 177 1841 V 32
+w(mo)m(vnam)p 547 1841 V 33 w(hdu)321 b(33)50 1954 y(\014ts)p
+177 1954 V 32 w(mo)m(vrel)p 477 1954 V 33 w(hdu)391 b(33)50
+2067 y(\014ts)p 177 2067 V 32 w(n)m(ull)p 360 2067 V
+31 w(c)m(hec)m(k)450 b(57)50 2180 y(\014ts)p 177 2180
+V 32 w(op)s(en)p 399 2180 V 32 w(data)d(30)50 2293 y(\014ts)p
+177 2293 V 32 w(op)s(en)p 399 2293 V 32 w(disk\014le)345
+b(30)50 2406 y(\014ts)p 177 2406 V 32 w(op)s(en)p 399
+2406 V 32 w(\014le)506 b(30)50 2519 y(\014ts)p 177 2519
+V 32 w(op)s(en)p 399 2519 V 32 w(image)391 b(30)50 2632
+y(\014ts)p 177 2632 V 32 w(op)s(en)p 399 2632 V 32 w(table)426
+b(30)50 2745 y(\014ts)p 177 2745 V 32 w(op)s(en)p 399
+2745 V 32 w(group)395 b(78)50 2858 y(\014ts)p 177 2858
+V 32 w(op)s(en)p 399 2858 V 32 w(mem)m(b)s(er)304 b(79)50
+2970 y(\014ts)p 177 2970 V 32 w(op)s(en)p 399 2970 V
+32 w(mem\014le)314 b(81)50 3083 y(\014ts)p 177 3083 V
+32 w(parse)p 417 3083 V 33 w(extn)m(um)306 b(83)50 3196
+y(\014ts)p 177 3196 V 32 w(parse)p 417 3196 V 33 w(input)p
+664 3196 V 31 w(url)246 b(82)50 3309 y(\014ts)p 177 3309
+V 32 w(parse)p 417 3309 V 33 w(range)387 b(61)50 3422
+y(\014ts)p 177 3422 V 32 w(parse)p 417 3422 V 33 w(ro)s(otname)228
+b(83)50 3535 y(\014ts)p 177 3535 V 32 w(parse)p 417 3535
+V 33 w(template)256 b(59)50 3648 y(\014ts)p 177 3648
+V 32 w(parse)p 417 3648 V 33 w(v)-5 b(alue)399 b(57)50
+3761 y(\014ts)p 177 3761 V 32 w(pix)p 334 3761 V 32 w(to)p
+446 3761 V 33 w(w)m(orld)354 b(73)50 3874 y(\014ts)p
+177 3874 V 32 w(read)p 381 3874 V 33 w(2d)p 510 3874
+V 33 w(TYP)315 b(98)50 3987 y(\014ts)p 177 3987 V 32
+w(read)p 381 3987 V 33 w(3d)p 510 3987 V 33 w(TYP)g(98)50
+4100 y(\014ts)p 177 4100 V 32 w(read)p 381 4100 V 33
+w(atblhdr)345 b(87)50 4212 y(\014ts)p 177 4212 V 32 w(read)p
+381 4212 V 33 w(btblhdr)339 b(87)50 4325 y(\014ts)p 177
+4325 V 32 w(read)p 381 4325 V 33 w(card)468 b(36)50 4438
+y(\014ts)p 177 4438 V 32 w(read)p 381 4438 V 33 w(col)529
+b(51)50 4551 y(\014ts)p 177 4551 V 32 w(read)p 381 4551
+V 33 w(col)p 525 4551 V 33 w(bit)p 670 4551 V 338 w(104)50
+4664 y(\014ts)p 177 4664 V 32 w(read)p 381 4664 V 33
+w(col)p 525 4664 V 33 w(TYP)254 b(102)50 4777 y(\014ts)p
+177 4777 V 32 w(read)p 381 4777 V 33 w(coln)m(ull)378
+b(51)50 4890 y(\014ts)p 177 4890 V 32 w(read)p 381 4890
+V 33 w(coln)m(ull)p 676 4890 V 31 w(TYP)105 b(103)50
+5003 y(\014ts)p 177 5003 V 32 w(read)p 381 5003 V 33
+w(descript)279 b(104)50 5116 y(\014ts)p 177 5116 V 32
+w(read)p 381 5116 V 33 w(descripts)243 b(104)50 5229
+y(\014ts)p 177 5229 V 32 w(read)p 381 5229 V 33 w(errmsg)371
+b(30)50 5342 y(\014ts)p 177 5342 V 32 w(read)p 381 5342
+V 33 w(grppar)p 678 5342 V 32 w(TYP)148 b(98)50 5454
+y(\014ts)p 177 5454 V 32 w(read)p 381 5454 V 33 w(img)493
+b(97)50 5567 y(\014ts)p 177 5567 V 32 w(read)p 381 5567
+V 33 w(img)p 561 5567 V 32 w(co)s(ord)241 b(72)50 5680
+y(\014ts)p 177 5680 V 32 w(read)p 381 5680 V 33 w(img)p
+561 5680 V 32 w(TYP)265 b(97)50 5793 y(\014ts)p 177 5793
+V 32 w(read)p 381 5793 V 33 w(imghdr)355 b(87)1260 543
+y(\014ts)p 1387 543 V 32 w(read)p 1591 543 V 33 w(imgn)m(ull)596
+b(97)1260 656 y(\014ts)p 1387 656 V 32 w(read)p 1591
+656 V 33 w(imgn)m(ull)p 1922 656 V 30 w(TYP)370 b(97)1260
+769 y(\014ts)p 1387 769 V 32 w(read)p 1591 769 V 33 w(k)m(ey)761
+b(36)1260 882 y(\014ts)p 1387 882 V 32 w(read)p 1591
+882 V 33 w(k)m(ey)p 1757 882 V 33 w(longstr)454 b(91)1260
+995 y(\014ts)p 1387 995 V 32 w(read)p 1591 995 V 33 w(k)m(ey)p
+1757 995 V 33 w(triple)514 b(92)1260 1107 y(\014ts)p
+1387 1107 V 32 w(read)p 1591 1107 V 33 w(k)m(ey)p 1757
+1107 V 33 w(unit)565 b(37)1260 1220 y(\014ts)p 1387 1220
+V 32 w(read)p 1591 1220 V 33 w(k)m(ey)p 1757 1220 V 33
+w(TYP)532 b(91)1260 1333 y(\014ts)p 1387 1333 V 32 w(read)p
+1591 1333 V 33 w(k)m(eyn)710 b(36)1260 1446 y(\014ts)p
+1387 1446 V 32 w(read)p 1591 1446 V 33 w(k)m(eys)p 1793
+1446 V 33 w(TYP)496 b(92)1260 1559 y(\014ts)p 1387 1559
+V 32 w(read)p 1591 1559 V 33 w(k)m(eyw)m(ord)566 b(36)1260
+1672 y(\014ts)p 1387 1672 V 32 w(read)p 1591 1672 V 33
+w(pix)769 b(42)1260 1785 y(\014ts)p 1387 1785 V 32 w(read)p
+1591 1785 V 33 w(pixn)m(ull)618 b(42)1260 1898 y(\014ts)p
+1387 1898 V 32 w(read)p 1591 1898 V 33 w(record)646 b(36)1260
+2011 y(\014ts)p 1387 2011 V 32 w(read)p 1591 2011 V 33
+w(subset)p 1873 2011 V 32 w(TYP)250 b(98)31 b(103)1260
+2124 y(\014ts)p 1387 2124 V 32 w(read)p 1591 2124 V 33
+w(subsetn)m(ull)p 2024 2124 V 30 w(TYP)101 b(98)31 b(103)1260
+2237 y(\014ts)p 1387 2237 V 32 w(read)p 1591 2237 V 33
+w(tbl)p 1736 2237 V 32 w(co)s(ord)530 b(72)1260 2349
+y(\014ts)p 1387 2349 V 32 w(read)p 1591 2349 V 33 w(tblb)m(ytes)f(100)
+1260 2462 y(\014ts)p 1387 2462 V 32 w(read)p 1591 2462
+V 33 w(tdim)706 b(48)1260 2575 y(\014ts)p 1387 2575 V
+32 w(remo)m(v)m(e)p 1698 2575 V 34 w(group)558 b(77)1260
+2688 y(\014ts)p 1387 2688 V 32 w(remo)m(v)m(e)p 1698
+2688 V 34 w(mem)m(b)s(er)467 b(79)1260 2801 y(\014ts)p
+1387 2801 V 32 w(reop)s(en)p 1685 2801 V 32 w(\014le)684
+b(82)1260 2914 y(\014ts)p 1387 2914 V 32 w(rep)s(ort)p
+1665 2914 V 32 w(error)628 b(30)1260 3027 y(\014ts)p
+1387 3027 V 32 w(resize)p 1637 3027 V 33 w(img)701 b(85)1260
+3140 y(\014ts)p 1387 3140 V 32 w(select)p 1636 3140 V
+33 w(ro)m(ws)669 b(52)1260 3253 y(\014ts)p 1387 3253
+V 32 w(set)p 1530 3253 V 33 w(atbln)m(ull)647 b(95)1260
+3366 y(\014ts)p 1387 3366 V 32 w(set)p 1530 3366 V 33
+w(bscale)717 b(94)1260 3479 y(\014ts)p 1387 3479 V 32
+w(set)p 1530 3479 V 33 w(btbln)m(ull)641 b(95)1260 3591
+y(\014ts)p 1387 3591 V 32 w(set)p 1530 3591 V 33 w(compression)p
+2045 3591 V 32 w(t)m(yp)s(e)267 b(44)1260 3704 y(\014ts)p
+1387 3704 V 32 w(set)p 1530 3704 V 33 w(hdrsize)675 b(86)1260
+3817 y(\014ts)p 1387 3817 V 32 w(set)p 1530 3817 V 33
+w(hdustruc)604 b(86)1260 3930 y(\014ts)p 1387 3930 V
+32 w(set)p 1530 3930 V 33 w(imgn)m(ull)657 b(95)1260
+4043 y(\014ts)p 1387 4043 V 32 w(set)p 1530 4043 V 33
+w(noise)p 1761 4043 V 33 w(bits)576 b(44)1260 4156 y(\014ts)p
+1387 4156 V 32 w(set)p 1530 4156 V 33 w(tile)p 1690 4156
+V 32 w(dim)643 b(44)1260 4269 y(\014ts)p 1387 4269 V
+32 w(set)p 1530 4269 V 33 w(tscale)733 b(94)1260 4382
+y(\014ts)p 1387 4382 V 32 w(split)p 1593 4382 V 31 w(names)646
+b(56)1260 4495 y(\014ts)p 1387 4495 V 32 w(str2date)776
+b(55)1260 4608 y(\014ts)p 1387 4608 V 32 w(str2time)770
+b(55)1260 4721 y(\014ts)p 1387 4721 V 32 w(test)p 1565
+4721 V 34 w(expr)744 b(53)1260 4833 y(\014ts)p 1387 4833
+V 32 w(test)p 1565 4833 V 34 w(heap)686 b(100)1260 4946
+y(\014ts)p 1387 4946 V 32 w(test)p 1565 4946 V 34 w(k)m(eyw)m(ord)591
+b(57)1260 5059 y(\014ts)p 1387 5059 V 32 w(test)p 1565
+5059 V 34 w(record)671 b(57)1260 5172 y(\014ts)p 1387
+5172 V 32 w(time2str)770 b(55)1260 5285 y(\014ts)p 1387
+5285 V 32 w(transfer)p 1726 5285 V 32 w(mem)m(b)s(er)441
+b(79)1260 5398 y(\014ts)p 1387 5398 V 32 w(up)s(date)p
+1695 5398 V 32 w(card)619 b(38)1260 5511 y(\014ts)p 1387
+5511 V 32 w(up)s(date)p 1695 5511 V 32 w(c)m(hksum)492
+b(54)1260 5624 y(\014ts)p 1387 5624 V 32 w(up)s(date)p
+1695 5624 V 32 w(k)m(ey)658 b(37)1260 5737 y(\014ts)p
+1387 5737 V 32 w(up)s(date)p 1695 5737 V 32 w(k)m(ey)p
+1860 5737 V 34 w(n)m(ull)473 b(38)1260 5850 y(\014ts)p
+1387 5850 V 32 w(up)s(date)p 1695 5850 V 32 w(k)m(ey)p
+1860 5850 V 34 w(TYP)428 b(93)2723 543 y(\014ts)p 2850
+543 V 33 w(upp)s(ercase)515 b(56)2723 656 y(\014ts)p
+2850 656 V 33 w(url)p 2996 656 V 31 w(t)m(yp)s(e)590
+b(33)2723 769 y(\014ts)p 2850 769 V 33 w(v)m(erify)p
+3106 769 V 32 w(c)m(hksum)354 b(54)2723 882 y(\014ts)p
+2850 882 V 33 w(v)m(erify)p 3106 882 V 32 w(group)425
+b(78)2723 995 y(\014ts)p 2850 995 V 33 w(w)m(orld)p 3104
+995 V 32 w(to)p 3216 995 V 33 w(pix)417 b(73)2723 1107
+y(\014ts)p 2850 1107 V 33 w(write)p 3086 1107 V 32 w(2d)p
+3214 1107 V 33 w(TYP)348 b(97)2723 1220 y(\014ts)p 2850
+1220 V 33 w(write)p 3086 1220 V 32 w(3d)p 3214 1220 V
+33 w(TYP)g(97)2723 1333 y(\014ts)p 2850 1333 V 33 w(write)p
+3086 1333 V 32 w(atblhdr)378 b(87)2723 1446 y(\014ts)p
+2850 1446 V 33 w(write)p 3086 1446 V 32 w(btblhdr)372
+b(87)2723 1559 y(\014ts)p 2850 1559 V 33 w(write)p 3086
+1559 V 32 w(c)m(hksum)i(53)2723 1672 y(\014ts)p 2850
+1672 V 33 w(write)p 3086 1672 V 32 w(col)562 b(50)2723
+1785 y(\014ts)p 2850 1785 V 33 w(write)p 3086 1785 V
+32 w(col)p 3229 1785 V 33 w(bit)371 b(101)2723 1898 y(\014ts)p
+2850 1898 V 33 w(write)p 3086 1898 V 32 w(col)p 3229
+1898 V 33 w(TYP)287 b(100)2723 2011 y(\014ts)p 2850 2011
+V 33 w(write)p 3086 2011 V 32 w(col)p 3229 2011 V 33
+w(n)m(ull)378 b(50)2723 2124 y(\014ts)p 2850 2124 V 33
+w(write)p 3086 2124 V 32 w(coln)m(ull)411 b(50)2723 2237
+y(\014ts)p 2850 2237 V 33 w(write)p 3086 2237 V 32 w(coln)m(ull)p
+3380 2237 V 31 w(TYP)138 b(101)2723 2349 y(\014ts)p 2850
+2349 V 33 w(write)p 3086 2349 V 32 w(commen)m(t)313 b(38)2723
+2462 y(\014ts)p 2850 2462 V 33 w(write)p 3086 2462 V
+32 w(date)502 b(38)2723 2575 y(\014ts)p 2850 2575 V 33
+w(write)p 3086 2575 V 32 w(descript)312 b(102)2723 2688
+y(\014ts)p 2850 2688 V 33 w(write)p 3086 2688 V 32 w(errmark)356
+b(30)2723 2801 y(\014ts)p 2850 2801 V 33 w(write)p 3086
+2801 V 32 w(errmsg)404 b(56)2723 2914 y(\014ts)p 2850
+2914 V 33 w(write)p 3086 2914 V 32 w(grphdr)f(87)2723
+3027 y(\014ts)p 2850 3027 V 33 w(write)p 3086 3027 V
+32 w(grppar)p 3382 3027 V 32 w(TYP)181 b(97)2723 3140
+y(\014ts)p 2850 3140 V 33 w(write)p 3086 3140 V 32 w(history)396
+b(38)2723 3253 y(\014ts)p 2850 3253 V 33 w(write)p 3086
+3253 V 32 w(img)526 b(96)2723 3366 y(\014ts)p 2850 3366
+V 33 w(write)p 3086 3366 V 32 w(img)p 3265 3366 V 32
+w(n)m(ull)343 b(97)2723 3479 y(\014ts)p 2850 3479 V 33
+w(write)p 3086 3479 V 32 w(img)p 3265 3479 V 32 w(TYP)298
+b(96)2723 3591 y(\014ts)p 2850 3591 V 33 w(write)p 3086
+3591 V 32 w(imghdr)388 b(87)2723 3704 y(\014ts)p 2850
+3704 V 33 w(write)p 3086 3704 V 32 w(imgn)m(ull)375 b(96)2723
+3817 y(\014ts)p 2850 3817 V 33 w(write)p 3086 3817 V
+32 w(imgn)m(ull)p 3416 3817 V 30 w(TYP)149 b(96)2723
+3930 y(\014ts)p 2850 3930 V 33 w(write)p 3086 3930 V
+32 w(k)m(ey)540 b(37)2723 4043 y(\014ts)p 2850 4043 V
+33 w(write)p 3086 4043 V 32 w(k)m(ey)p 3251 4043 V 33
+w(longstr)233 b(89)2723 4156 y(\014ts)p 2850 4156 V 33
+w(write)p 3086 4156 V 32 w(k)m(ey)p 3251 4156 V 33 w(longw)m(arn)145
+b(89)2723 4269 y(\014ts)p 2850 4269 V 33 w(write)p 3086
+4269 V 32 w(k)m(ey)p 3251 4269 V 33 w(n)m(ull)356 b(38)2723
+4382 y(\014ts)p 2850 4382 V 33 w(write)p 3086 4382 V
+32 w(k)m(ey)p 3251 4382 V 33 w(template)159 b(90)2723
+4495 y(\014ts)p 2850 4495 V 33 w(write)p 3086 4495 V
+32 w(k)m(ey)p 3251 4495 V 33 w(triple)293 b(90)2723 4608
+y(\014ts)p 2850 4608 V 33 w(write)p 3086 4608 V 32 w(k)m(ey)p
+3251 4608 V 33 w(unit)344 b(39)2723 4721 y(\014ts)p 2850
+4721 V 33 w(write)p 3086 4721 V 32 w(k)m(ey)p 3251 4721
+V 33 w(TYP)311 b(88)2723 4833 y(\014ts)p 2850 4833 V
+33 w(write)p 3086 4833 V 32 w(k)m(eys)p 3287 4833 V 33
+w(TYP)275 b(89)2723 4946 y(\014ts)p 2850 4946 V 33 w(write)p
+3086 4946 V 32 w(n)m(ull)p 3269 4946 V 31 w(img)344 b(41)2723
+5059 y(\014ts)p 2850 5059 V 33 w(write)p 3086 5059 V
+32 w(pix)548 b(41)2723 5172 y(\014ts)p 2850 5172 V 33
+w(write)p 3086 5172 V 32 w(pixn)m(ull)397 b(41)2723 5285
+y(\014ts)p 2850 5285 V 33 w(write)p 3086 5285 V 32 w(record)425
+b(38)2723 5398 y(\014ts)p 2850 5398 V 33 w(write)p 3086
+5398 V 32 w(subset)f(40)2723 5511 y(\014ts)p 2850 5511
+V 33 w(write)p 3086 5511 V 32 w(subset)p 3367 5511 V
+32 w(TYP)196 b(97)2723 5624 y(\014ts)p 2850 5624 V 33
+w(write)p 3086 5624 V 32 w(tblb)m(ytes)308 b(100)2723
+5737 y(\014ts)p 2850 5737 V 33 w(write)p 3086 5737 V
+32 w(tdim)485 b(48)2723 5850 y(\014ts)p 2850 5850 V 33
+w(write)p 3086 5850 V 32 w(theap)451 b(99)p eop
+%%Page: 149 157
+149 156 bop 3764 299 a Fj(149)50 543 y(\013asfm)276 b(59)50
+656 y(\013bnfm)255 b(59)50 769 y(\013calc)310 b(52)50
+882 y(\013calc)p 259 882 28 4 v 33 w(rng)145 b(53)50
+995 y(\013clos)314 b(33)50 1107 y(\013cmph)197 b(100)50
+1220 y(\013cmps)258 b(56)50 1333 y(\013cmrk)j(30)50 1446
+y(\013cmsg)j(30)50 1559 y(\013cop)m(y)280 b(34)50 1672
+y(\013cp)s(cl)301 b(49)50 1785 y(\013cp)s(dt)281 b(86)50
+1898 y(\013cp\015)319 b(34)50 2011 y(\013cphd)268 b(34)50
+2124 y(\013cpky)274 b(89)50 2237 y(\013crhd)283 b(84)50
+2349 y(\013crim)g(40)50 2462 y(\013cro)m(w)277 b(52)50
+2575 y(\013crtb)299 b(46)50 2688 y(\013dcol)g(49)50 2801
+y(\013delt)309 b(33)50 2914 y(\013dhdu)257 b(35)50 3027
+y(\013dk)m(ey)277 b(39)50 3140 y(\013dkinit)224 b(32)50
+3253 y(\013dk)m(op)s(en)175 b(30)50 3366 y(\013dopn)263
+b(30)50 3479 y(\013drec)294 b(39)50 3591 y(\013dro)m(w)266
+b(48)50 3704 y(\013drrg)293 b(48)50 3817 y(\013drws)272
+b(48)50 3930 y(\013dsum)247 b(54)50 4043 y(\013dt2s)294
+b(55)50 4156 y(\013dtdm)248 b(48)50 4269 y(\013dt)m(yp)279
+b(58)50 4382 y(\013eqt)m(y)293 b(47)50 4495 y(\013esum)258
+b(54)50 4608 y(\013exest)k(83)50 4721 y(\013extn)287
+b(83)50 4833 y(\013\013rw)306 b(52)50 4946 y(\013\015md)283
+b(33)50 5059 y(\013\015nm)g(33)50 5172 y(\013\015sh)323
+b(84)50 5285 y(\013\015us)g(84)50 5398 y(\013fro)m(w)289
+b(52)50 5511 y(\013g2d)p 249 5511 V 320 w(98)50 5624
+y(\013g3d)p 249 5624 V 320 w(98)50 5737 y(\013gab)s(c)277
+b(59)785 543 y(\013gacl)221 b(99)785 656 y(\013gb)s(cl)212
+b(99)785 769 y(\013gcdw)175 b(48)785 882 y(\013gcf)264
+b(51)785 995 y(\013gcf)p 956 995 V 219 w(103)785 1107
+y(\013gc)m(ks)211 b(54)785 1220 y(\013gcnn)190 b(46)785
+1333 y(\013gcno)196 b(46)785 1446 y(\013gcrd)205 b(36)785
+1559 y(\013gcv)244 b(51)785 1672 y(\013gcv)p 976 1672
+V 199 w(102)785 1785 y(\013gcx)199 b(104)785 1898 y(\013gdes)160
+b(104)785 2011 y(\013gdess)124 b(104)785 2124 y(\013gerr)220
+b(29)785 2237 y(\013ggp)p 984 2237 V 236 w(98)785 2349
+y(\013ghad)185 b(84)785 2462 y(\013gh)m(bn)d(87)785 2575
+y(\013ghdn)d(34)785 2688 y(\013ghdt)195 b(34)785 2801
+y(\013ghof)208 b(84)785 2914 y(\013ghpr)194 b(87)785
+3027 y(\013ghps)g(86)785 3140 y(\013ghsp)g(35)785 3253
+y(\013gh)m(tb)k(87)785 3366 y(\013gics)230 b(72)785 3479
+y(\013gidm)179 b(40)785 3591 y(\013gidt)220 b(40)785
+3704 y(\013giet)231 b(40)785 3817 y(\013gipr)219 b(40)785
+3930 y(\013gisz)230 b(40)785 4043 y(\013gk)m(cl)221 b(58)785
+4156 y(\013gk)m(ey)199 b(36)785 4269 y(\013gkls)222 b(91)785
+4382 y(\013gkn)p 987 4382 V 233 w(92)785 4495 y(\013gknm)157
+b(57)785 4608 y(\013gky)236 b(36)785 4721 y(\013gkyn)185
+b(36)785 4833 y(\013gkyt)201 b(92)785 4946 y(\013gky)p
+984 4946 V 236 w(91)785 5059 y(\013gmcp)165 b(79)785
+5172 y(\013gmng)160 b(79)785 5285 y(\013gmop)g(79)785
+5398 y(\013gmrm)144 b(79)785 5511 y(\013gmsg)175 b(30)785
+5624 y(\013gm)m(tf)196 b(79)785 5737 y(\013gncl)215 b(46)1436
+543 y(\013gnrw)283 b(46)1436 656 y(\013gnxk)289 b(36)1436
+769 y(\013gpf)357 b(97)1436 882 y(\013gpf)p 1618 882
+V 357 w(97)1436 995 y(\013gp)m(v)340 b(97)1436 1107 y(\013gp)m(v)p
+1635 1107 V 340 w(97)1436 1220 y(\013gp)m(xv)292 b(42)1436
+1333 y(\013gp)m(xf)312 b(42)1436 1446 y(\013grec)320
+b(36)1436 1559 y(\013grsz)k(99)1436 1672 y(\013gsdt)314
+b(55)1436 1785 y(\013gsf)p 1603 1785 V 205 w(98)32 b(103)1436
+1898 y(\013gstm)289 b(55)1436 2011 y(\013gsv)p 1623 2011
+V 185 w(98)32 b(103)1436 2124 y(\013gtam)280 b(78)1436
+2237 y(\013gtbb)254 b(100)1436 2349 y(\013gtc)m(h)313
+b(76)1436 2462 y(\013gtcl)335 b(47)1436 2575 y(\013gtcm)285
+b(77)1436 2688 y(\013gtcp)310 b(77)1436 2801 y(\013gtcr)325
+b(76)1436 2914 y(\013gtcs)g(72)1436 3027 y(\013gtdm)274
+b(48)1436 3140 y(\013gthd)299 b(59)1436 3253 y(\013gtis)339
+b(76)1436 3366 y(\013gtmg)280 b(77)1436 3479 y(\013gtnm)274
+b(78)1436 3591 y(\013gtop)305 b(78)1436 3704 y(\013gtrm)289
+b(77)1436 3817 y(\013gtvf)325 b(78)1436 3930 y(\013gun)m(t)302
+b(37)1436 4043 y(\013hdef)311 b(86)1436 4156 y(\016bin)330
+b(85)1436 4269 y(\016cls)356 b(49)1436 4382 y(\016col)347
+b(49)1436 4495 y(\016img)311 b(85)1436 4608 y(\016kls)348
+b(90)1436 4721 y(\016kyu)311 b(91)1436 4833 y(\016ky)p
+1613 4833 V 362 w(90)1436 4946 y(\016mem)266 b(82)1436
+5059 y(\016nit)346 b(32)1436 5172 y(\016opn)311 b(30)1436
+5285 y(\016rec)342 b(90)1436 5398 y(\016ro)m(w)314 b(48)1436
+5511 y(\016tab)327 b(85)1436 5624 y(\016ter)347 b(69)1436
+5737 y(\016url)e(82)2191 543 y(\013k)m(eyn)208 b(57)2191
+656 y(\013mahd)169 b(33)2191 769 y(\013mcom)155 b(38)2191
+882 y(\013mcrd)189 b(92)2191 995 y(\013mkls)206 b(93)2191
+1107 y(\013mkyu)169 b(93)2191 1220 y(\013mky)p 2421 1220
+V 220 w(93)2191 1333 y(\013mnam)144 b(39)2191 1446 y(\013mnhd)163
+b(33)2191 1559 y(\013mrec)200 b(92)2191 1672 y(\013mrhd)178
+b(33)2191 1785 y(\013m)m(v)m(ec)194 b(49)2191 1898 y(\013nc)m(hk)205
+b(57)2191 2011 y(\013nk)m(ey)j(58)2191 2124 y(\013omem)155
+b(81)2191 2237 y(\013op)s(en)202 b(30)2191 2349 y(\013p2d)p
+2396 2349 V 245 w(97)2191 2462 y(\013p3d)p 2396 2462
+V 245 w(97)2191 2575 y(\013p)s(c)m(ks)217 b(53)2191 2688
+y(\013p)s(cl)272 b(50)2191 2801 y(\013p)s(cls)191 b(100)2191
+2914 y(\013p)s(cl)p 2369 2914 V 227 w(101)2191 3027 y(\013p)s(clu)221
+b(50)2191 3140 y(\013p)s(cn)247 b(50)2191 3253 y(\013p)s(cn)p
+2394 3253 V 202 w(101)2191 3366 y(\013p)s(com)177 b(38)2191
+3479 y(\013p)s(dat)207 b(38)2191 3591 y(\013p)s(des)166
+b(102)2191 3704 y(\013pgp)p 2396 3704 V 245 w(97)2191
+3817 y(\013ph)m(bn)191 b(87)2191 3930 y(\013phis)228
+b(38)2191 4043 y(\013phpr)203 b(87)2191 4156 y(\013phps)g(87)2191
+4269 y(\013ph)m(tb)k(87)2191 4382 y(\013pkls)231 b(89)2191
+4495 y(\013pkn)p 2399 4495 V 242 w(89)2191 4608 y(\013pktp)207
+b(90)2191 4721 y(\013pky)245 b(37)2191 4833 y(\013pkyt)210
+b(90)2191 4946 y(\013pkyu)194 b(38)2191 5059 y(\013pky)p
+2396 5059 V 245 w(88)2191 5172 y(\013plsw)213 b(89)2191
+5285 y(\013pmrk)181 b(30)2191 5398 y(\013pmsg)j(56)2191
+5511 y(\013pn)m(ul)216 b(95)2191 5624 y(\013ppn)239 b(96)2191
+5737 y(\013ppn)p 2402 5737 V 239 w(96)2857 543 y(\013ppr)273
+b(96)2857 656 y(\013pprn)222 b(41)2857 769 y(\013ppru)g(97)2857
+882 y(\013ppr)p 3053 882 V 273 w(96)2857 995 y(\013pp)m(x)264
+b(41)2857 1107 y(\013pp)m(xn)213 b(41)2857 1220 y(\013prec)244
+b(38)2857 1333 y(\013pscl)258 b(94)2857 1446 y(\013pss)288
+b(40)2857 1559 y(\013pss)p 3038 1559 V 288 w(97)2857
+1672 y(\013psv)m(c)239 b(57)2857 1785 y(\013ptbb)177
+b(100)2857 1898 y(\013ptdm)198 b(48)2857 2011 y(\013pthp)223
+b(99)2857 2124 y(\013pun)m(t)j(39)2857 2237 y(\013rdef)256
+b(86)2857 2349 y(\013reop)s(en)145 b(82)2857 2462 y(\013rprt)253
+b(30)2857 2575 y(\013rsim)237 b(85)2857 2688 y(\013rtnm)213
+b(83)2857 2801 y(\013rwrg)228 b(61)2857 2914 y(\013s2dt)244
+b(55)2857 3027 y(\013s2tm)219 b(55)2857 3140 y(\013sn)m(ul)250
+b(95)2857 3253 y(\013sro)m(w)231 b(52)2857 3366 y(\013texp)237
+b(53)2857 3479 y(\013thdu)223 b(33)2857 3591 y(\013theap)143
+b(100)2857 3704 y(\013tk)m(ey)243 b(57)2857 3817 y(\013tm2s)219
+b(55)2857 3930 y(\013tn)m(ul)251 b(95)2857 4043 y(\013topn)229
+b(30)2857 4156 y(\013tplt)264 b(82)2857 4269 y(\013trec)c(57)2857
+4382 y(\013tscl)274 b(94)2857 4495 y(\013ucrd)233 b(38)2857
+4608 y(\013ukls)250 b(93)2857 4721 y(\013uky)264 b(37)2857
+4833 y(\013ukyu)213 b(38)2857 4946 y(\013uky)p 3062 4946
+V 264 w(93)2857 5059 y(\013up)s(c)m(h)218 b(56)2857 5172
+y(\013up)s(c)m(k)j(54)2857 5285 y(\013urlt)263 b(33)2857
+5398 y(\013v)m(c)m(ks)245 b(54)2857 5511 y(\013v)m(ers)254
+b(56)2857 5624 y(\013wldp)217 b(73)2857 5737 y(\013xyp)m(x)i(73)p
+eop
+%%Page: 150 158
+150 157 bop 0 299 a Fj(150)2084 b Fh(APPENDIX)31 b(A.)61
+b(INDEX)31 b(OF)f(R)m(OUTINES)p eop
+%%Page: 151 159
+151 158 bop 0 1225 a Fg(App)5 b(endix)65 b(B)0 1687 y
+Fm(P)-6 b(arameter)77 b(De\014nitions)0 2180 y Fe(anynul)142
+b(-)47 b(set)g(to)g(TRUE)g(\(=1\))f(if)i(any)e(returned)g(values)g(are)
+h(undefined,)e(else)i(FALSE)0 2293 y(array)190 b(-)47
+b(array)f(of)i(numerical)d(data)h(values)h(to)g(read)f(or)i(write)0
+2406 y(ascii)190 b(-)47 b(encoded)f(checksum)f(string)0
+2518 y(binspec)94 b(-)47 b(the)g(input)f(table)h(binning)e(specifier)0
+2631 y(bitpix)142 b(-)47 b(bits)g(per)g(pixel.)f(The)h(following)e
+(symbolic)g(mnemonics)h(are)h(predefined:)716 2744 y(BYTE_IMG)141
+b(=)i(8)47 b(\(unsigned)f(char\))716 2857 y(SHORT_IMG)93
+b(=)i(16)47 b(\(signed)f(short)g(integer\))716 2970 y(LONG_IMG)141
+b(=)95 b(32)47 b(\(signed)f(long)h(integer\))716 3083
+y(LONGLONG_IMG)d(=)96 b(64)47 b(\(signed)f(long)g(64-bit)g(integer\))
+716 3196 y(FLOAT_IMG)93 b(=)47 b(-32)g(\(float\))716
+3309 y(DOUBLE_IMG)e(=)i(-64)g(\(double\).)525 3422 y(The)g
+(LONGLONG_IMG)d(type)j(is)g(experimental)e(and)i(is)g(not)g(officially)
+525 3535 y(recognized)e(in)i(the)g(FITS)g(Standard)e(document.)525
+3648 y(Two)i(additional)e(values,)h(USHORT_IMG)f(and)i(ULONG_IMG)e(are)
+i(also)f(available)525 3760 y(for)h(creating)e(unsigned)h(integer)g
+(images.)93 b(These)47 b(are)g(equivalent)e(to)525 3873
+y(creating)h(a)h(signed)f(integer)g(image)g(with)h(BZERO)f(offset)g
+(keyword)g(values)525 3986 y(of)h(32768)g(or)g(2147483648,)d
+(respectively,)h(which)h(is)h(the)g(convention)e(that)525
+4099 y(FITS)i(uses)f(to)h(store)g(unsigned)e(integers.)0
+4212 y(card)238 b(-)47 b(header)f(record)g(to)h(be)h(read)e(or)h
+(written)f(\(80)h(char)g(max,)f(null-terminated\))0 4325
+y(casesen)94 b(-)47 b(CASESEN)f(\(=1\))g(for)h(case-sensitive)d(string)
+i(matching,)g(else)g(CASEINSEN)g(\(=0\))0 4438 y(cmopt)190
+b(-)47 b(grouping)f(table)g("compact")f(option)h(parameter.)f(Allowed)h
+(values)g(are:)525 4551 y(OPT_CMT_MBR)f(and)i(OPT_CMT_MBR_DEL.)0
+4664 y(colname)94 b(-)47 b(name)g(of)g(the)g(column)f
+(\(null-terminated\))0 4777 y(colnum)142 b(-)47 b(column)f(number)g
+(\(first)g(column)g(=)i(1\))0 4890 y(colspec)94 b(-)47
+b(the)g(input)f(file)h(column)f(specification;)e(used)j(to)g(delete,)f
+(create,)f(or)j(rename)525 5002 y(table)e(columns)0 5115
+y(comment)94 b(-)47 b(the)g(keyword)f(comment)g(field)g(\(72)h(char)f
+(max,)h(null-terminated\))0 5228 y(complm)142 b(-)47
+b(should)f(the)h(checksum)f(be)h(complemented?)0 5341
+y(comptype)f(-)h(compression)e(algorithm)g(to)i(use:)g(GZIP_1,)f
+(RICE_1,)f(or)j(PLIO_1)0 5454 y(coordtype-)d(type)i(of)g(coordinate)e
+(projection)g(\(-SIN,)h(-TAN,)g(-ARC,)h(-NCP,)525 5567
+y(-GLS,)f(-MER,)h(or)g(-AIT\))0 5680 y(cpopt)190 b(-)47
+b(grouping)f(table)g(copy)h(option)f(parameter.)f(Allowed)g(values)i
+(are:)1882 5942 y Fj(151)p eop
+%%Page: 152 160
+152 159 bop 0 299 a Fj(152)1822 b Fh(APPENDIX)31 b(B.)61
+b(P)-8 b(ARAMETER)30 b(DEFINITIONS)525 555 y Fe(OPT_GCP_GPT,)44
+b(OPT_GCP_MBR,)h(OPT_GCP_ALL,)f(OPT_MCP_ADD,)h(OPT_MCP_NADD,)525
+668 y(OPT_MCP_REPL,)f(amd)j(OPT_MCP_MOV.)0 781 y(create_col-)e(If)i
+(TRUE,)f(then)h(insert)f(a)h(new)g(column)f(in)i(the)f(table,)f
+(otherwise)525 894 y(overwrite)f(the)i(existing)f(column.)0
+1007 y(current)94 b(-)47 b(if)g(TRUE,)g(then)f(the)h(current)f(HDU)h
+(will)f(be)i(copied)0 1120 y(dataok)142 b(-)47 b(was)g(the)g(data)f
+(unit)h(verification)e(successful)g(\(=1\))h(or)525 1233
+y(not)h(\(=)g(-1\).)94 b(Equals)47 b(zero)f(if)h(the)g(DATASUM)f
+(keyword)g(is)h(not)g(present.)0 1346 y(datasum)94 b(-)47
+b(32-bit)f(1's)h(complement)e(checksum)h(for)g(the)h(data)g(unit)0
+1458 y(dataend)94 b(-)47 b(address)f(\(in)h(bytes\))f(of)h(the)g(end)g
+(of)g(the)g(HDU)0 1571 y(datastart-)e(address)h(\(in)h(bytes\))f(of)h
+(the)g(start)f(of)h(the)g(data)g(unit)0 1684 y(datatype)f(-)h
+(specifies)e(the)i(data)g(type)f(of)i(the)f(value.)93
+b(Allowed)46 b(value)h(are:)94 b(TSTRING,)525 1797 y(TLOGICAL,)45
+b(TBYTE,)h(TSBYTE,)g(TSHORT,)g(TUSHORT,)g(TINT,)g(TUINT,)g(TLONG,)g
+(TULONG,)525 1910 y(TFLOAT,)g(TDOUBLE,)f(TCOMPLEX,)h(and)h(TDBLCOMPLEX)
+0 2023 y(datestr)94 b(-)47 b(FITS)g(date/time)e(string:)h
+('YYYY-MM-DDThh:mm:ss.dd)o(d',)41 b('YYYY-MM-dd',)525
+2136 y(or)47 b('dd/mm/yy')0 2249 y(day)286 b(-)47 b(calendar)f(day)g
+(\(UTC\))h(\(1-31\))0 2362 y(decimals)f(-)h(number)f(of)h(decimal)f
+(places)g(to)h(be)h(displayed)0 2475 y(deltasize)d(-)j(increment)d(for)
+i(allocating)e(more)i(memory)0 2588 y(dim1)238 b(-)47
+b(declared)f(size)g(of)h(the)g(first)g(dimension)e(of)i(the)g(image)f
+(or)i(cube)e(array)0 2700 y(dim2)238 b(-)47 b(declared)f(size)g(of)h
+(the)g(second)f(dimension)g(of)h(the)g(data)f(cube)h(array)0
+2813 y(dispwidth)e(-)j(display)e(width)g(of)h(a)h(column)e(=)h(length)f
+(of)h(string)f(that)h(will)g(be)g(read)0 2926 y(dtype)190
+b(-)47 b(data)g(type)f(of)h(the)g(keyword)f(\('C',)h('L',)f('I',)h('F')
+g(or)g('X'\))764 3039 y(C)g(=)h(character)d(string)764
+3152 y(L)i(=)h(logical)764 3265 y(I)f(=)h(integer)764
+3378 y(F)f(=)h(floating)d(point)h(number)764 3491 y(X)h(=)h(complex,)d
+(e.g.,)h("\(1.23,)g(-4.56\)")0 3604 y(err_msg)94 b(-)47
+b(error)f(message)g(on)h(the)g(internal)f(stack)g(\(80)h(chars)f(max\))
+0 3717 y(err_text)g(-)h(error)f(message)g(string)g(corresponding)e(to)k
+(error)e(number)g(\(30)h(chars)f(max\))0 3830 y(exact)190
+b(-)47 b(TRUE)g(\(=1\))f(if)h(the)g(strings)f(match)h(exactly;)525
+3942 y(FALSE)f(\(=0\))h(if)g(wildcards)e(are)i(used)0
+4055 y(exclist)94 b(-)47 b(array)f(of)i(pointers)d(to)i(keyword)f
+(names)g(to)i(be)f(excluded)e(from)i(search)0 4168 y(exists)142
+b(-)47 b(flag)g(indicating)e(whether)g(the)i(file)g(or)g(compressed)e
+(file)i(exists)f(on)h(disk)0 4281 y(expr)238 b(-)47 b(boolean)f(or)h
+(arithmetic)e(expression)0 4394 y(extend)142 b(-)47 b(TRUE)g(\(=1\))f
+(if)h(FITS)g(file)g(may)g(have)f(extensions,)f(else)i(FALSE)f(\(=0\))0
+4507 y(extname)94 b(-)47 b(value)f(of)i(the)e(EXTNAME)g(keyword)g
+(\(null-terminated\))0 4620 y(extspec)94 b(-)47 b(the)g(extension)e(or)
+i(HDU)g(specifier;)e(a)j(number)e(or)h(name,)f(version,)g(and)h(type)0
+4733 y(extver)142 b(-)47 b(value)f(of)i(the)e(EXTVER)h(keyword)e(=)j
+(integer)e(version)f(number)0 4846 y(filename)h(-)h(full)g(name)f(of)h
+(the)g(FITS)g(file,)f(including)g(optional)f(HDU)i(and)g(filtering)e
+(specs)0 4959 y(filetype)h(-)h(type)g(of)g(file)f(\(file://,)g(ftp://,)
+g(http://,)f(etc.\))0 5072 y(filter)142 b(-)47 b(the)g(input)f(file)h
+(filtering)e(specifier)0 5185 y(firstchar-)g(starting)h(byte)g(in)h
+(the)g(row)g(\(first)f(byte)h(of)g(row)g(=)g(1\))0 5297
+y(firstfailed)e(-)i(member)f(HDU)h(ID)g(\(if)g(positive\))f(or)h
+(grouping)e(table)i(GRPIDn)f(index)525 5410 y(value)g(\(if)h
+(negative\))f(that)g(failed)g(grouping)g(table)g(verification.)0
+5523 y(firstelem-)f(first)h(element)g(in)h(a)h(vector)e(\(ignored)f
+(for)i(ASCII)g(tables\))0 5636 y(firstrow)f(-)h(starting)f(row)g
+(number)h(\(first)f(row)h(of)g(table)f(=)i(1\))p eop
+%%Page: 153 161
+153 160 bop 3764 299 a Fj(153)0 555 y Fe(following-)45
+b(if)i(TRUE,)g(any)f(HDUs)h(following)e(the)i(current)f(HDU)h(will)g
+(be)g(copied)0 668 y(fpixel)142 b(-)47 b(coordinate)e(of)i(the)g(first)
+f(pixel)h(to)g(be)g(read)g(or)g(written)f(in)h(the)525
+781 y(FITS)g(array.)93 b(The)47 b(array)g(must)f(be)i(of)f(length)f
+(NAXIS)g(and)h(have)g(values)f(such)525 894 y(that)h(fpixel[0])e(is)i
+(in)g(the)g(range)g(1)g(to)g(NAXIS1,)f(fpixel[1])f(is)i(in)h(the)525
+1007 y(range)e(1)i(to)f(NAXIS2,)f(etc.)0 1120 y(fptr)238
+b(-)47 b(pointer)f(to)h(a)g('fitsfile')e(structure)h(describing)f(the)i
+(FITS)f(file.)0 1233 y(frac)238 b(-)47 b(factional)e(part)i(of)g(the)g
+(keyword)f(value)0 1346 y(gcount)142 b(-)47 b(number)f(of)h(groups)f
+(in)i(the)e(primary)g(array)h(\(usually)e(=)j(1\))0 1458
+y(gfptr)190 b(-)47 b(fitsfile*)e(pointer)h(to)h(a)h(grouping)d(table)i
+(HDU.)0 1571 y(group)190 b(-)47 b(GRPIDn/GRPLCn)d(index)j(value)f
+(identifying)f(a)i(grouping)f(table)g(HDU,)h(or)525 1684
+y(data)g(group)f(number)g(\(=0)h(for)g(non-grouped)e(data\))0
+1797 y(grouptype)g(-)j(Grouping)d(table)i(parameter)e(that)i(specifies)
+e(the)i(columns)f(to)h(be)525 1910 y(created)f(in)h(a)g(grouping)f
+(table)g(HDU.)h(Allowed)f(values)g(are:)h(GT_ID_ALL_URI,)525
+2023 y(GT_ID_REF,)e(GT_ID_POS,)g(GT_ID_ALL,)g(GT_ID_REF_URI,)f(and)j
+(GT_ID_POS_URI.)0 2136 y(grpname)94 b(-)47 b(value)f(to)i(use)e(for)h
+(the)g(GRPNAME)f(keyword)g(value.)0 2249 y(hdunum)142
+b(-)47 b(sequence)f(number)g(of)h(the)g(HDU)g(\(Primary)e(array)i(=)g
+(1\))0 2362 y(hduok)190 b(-)47 b(was)g(the)g(HDU)g(verification)d
+(successful)h(\(=1\))i(or)525 2475 y(not)g(\(=)g(-1\).)94
+b(Equals)47 b(zero)f(if)h(the)g(CHECKSUM)f(keyword)g(is)h(not)g
+(present.)0 2588 y(hdusum)142 b(-)47 b(32)g(bit)g(1's)g(complement)e
+(checksum)h(for)g(the)h(entire)f(CHDU)0 2700 y(hdutype)94
+b(-)47 b(type)g(of)g(HDU:)f(IMAGE_HDU)g(\(=0\),)g(ASCII_TBL)f(\(=1\),)i
+(or)g(BINARY_TBL)e(\(=2\))0 2813 y(header)142 b(-)47
+b(returned)f(character)f(string)h(containing)f(all)i(the)g(keyword)f
+(records)0 2926 y(headstart-)f(starting)h(address)f(\(in)i(bytes\))f
+(of)i(the)e(CHDU)0 3039 y(heapsize)g(-)h(size)g(of)g(the)g(binary)f
+(table)g(heap,)h(in)g(bytes)0 3152 y(history)94 b(-)47
+b(the)g(HISTORY)f(keyword)g(comment)f(string)h(\(70)h(char)g(max,)g
+(null-terminated\))0 3265 y(hour)238 b(-)47 b(hour)g(within)f(day)h
+(\(UTC\))f(\(0)h(-)h(23\))0 3378 y(inc)286 b(-)47 b(sampling)f
+(interval)f(for)i(pixels)f(in)h(each)g(FITS)g(dimension)0
+3491 y(inclist)94 b(-)47 b(array)f(of)i(pointers)d(to)i(matching)f
+(keyword)g(names)0 3604 y(incolnum)g(-)h(input)f(column)g(number;)g
+(range)h(=)g(1)h(to)f(TFIELDS)0 3717 y(infile)142 b(-)47
+b(the)g(input)f(filename,)g(including)f(path)h(if)i(specified)0
+3830 y(infptr)142 b(-)47 b(pointer)f(to)h(a)g('fitsfile')e(structure)h
+(describing)f(the)i(input)f(FITS)h(file.)0 3942 y(intval)142
+b(-)47 b(integer)f(part)g(of)i(the)f(keyword)e(value)0
+4055 y(iomode)142 b(-)47 b(file)g(access)f(mode:)g(either)g(READONLY)g
+(\(=0\))g(or)i(READWRITE)d(\(=1\))0 4168 y(keyname)94
+b(-)47 b(name)g(of)g(a)g(keyword)f(\(8)h(char)g(max,)g
+(null-terminated\))0 4281 y(keynum)142 b(-)47 b(position)f(of)h
+(keyword)f(in)h(header)f(\(1st)g(keyword)g(=)i(1\))0
+4394 y(keyroot)94 b(-)47 b(root)g(string)f(for)h(the)g(keyword)e(name)i
+(\(5)g(char)g(max,)f(null-terminated\))0 4507 y(keysexist-)f(number)h
+(of)h(existing)f(keyword)g(records)f(in)j(the)f(CHU)0
+4620 y(keytype)94 b(-)47 b(header)f(record)g(type:)h(-1=delete;)92
+b(0=append)46 b(or)h(replace;)907 4733 y(1=append;)e(2=this)h(is)h(the)
+g(END)g(keyword)0 4846 y(longstr)94 b(-)47 b(arbitrarily)e(long)h
+(string)g(keyword)g(value)h(\(null-terminated\))0 4959
+y(lpixel)142 b(-)47 b(coordinate)e(of)i(the)g(last)g(pixel)f(to)h(be)g
+(read)g(or)g(written)f(in)h(the)525 5072 y(FITS)g(array.)93
+b(The)47 b(array)g(must)f(be)i(of)f(length)f(NAXIS)g(and)h(have)g
+(values)f(such)525 5185 y(that)h(lpixel[0])e(is)i(in)g(the)g(range)g(1)
+g(to)g(NAXIS1,)f(lpixel[1])f(is)i(in)h(the)525 5297 y(range)e(1)i(to)f
+(NAXIS2,)f(etc.)0 5410 y(match)190 b(-)47 b(TRUE)g(\(=1\))f(if)h(the)g
+(2)h(strings)e(match,)g(else)g(FALSE)h(\(=0\))0 5523
+y(maxdim)142 b(-)47 b(maximum)f(number)g(of)h(values)f(to)h(return)0
+5636 y(member)142 b(-)47 b(row)g(number)f(of)h(a)h(grouping)d(table)i
+(member)f(HDU.)p eop
+%%Page: 154 162
+154 161 bop 0 299 a Fj(154)1822 b Fh(APPENDIX)31 b(B.)61
+b(P)-8 b(ARAMETER)30 b(DEFINITIONS)0 555 y Fe(memptr)142
+b(-)47 b(pointer)f(to)h(the)g(a)g(FITS)g(file)g(in)g(memory)0
+668 y(mem_realloc)e(-)i(pointer)f(to)h(a)h(function)d(for)i
+(reallocating)e(more)h(memory)0 781 y(memsize)94 b(-)47
+b(size)g(of)g(the)g(memory)f(block)g(allocated)f(for)i(the)g(FITS)g
+(file)0 894 y(mfptr)190 b(-)47 b(fitsfile*)e(pointer)h(to)h(a)h
+(grouping)d(table)i(member)f(HDU.)0 1007 y(mgopt)190
+b(-)47 b(grouping)f(table)g(merge)g(option)g(parameter.)f(Allowed)h
+(values)g(are:)525 1120 y(OPT_MRG_COPY,)e(and)j(OPT_MRG_MOV.)0
+1233 y(minute)142 b(-)47 b(minute)f(within)g(hour)h(\(UTC\))f(\(0)h(-)h
+(59\))0 1346 y(month)190 b(-)47 b(calendar)f(month)g(\(UTC\))g(\(1)h(-)
+h(12\))0 1458 y(morekeys)e(-)h(space)f(in)i(the)e(header)h(for)f(this)h
+(many)g(more)f(keywords)0 1571 y(n_good_rows)f(-)i(number)f(of)h(rows)g
+(evaluating)e(to)i(TRUE)0 1684 y(namelist)f(-)h(string)f(containing)f
+(a)j(comma)e(or)h(space)f(delimited)g(list)g(of)i(names)0
+1797 y(naxes)190 b(-)47 b(size)g(of)g(each)f(dimension)g(in)h(the)g
+(FITS)f(array)0 1910 y(naxis)190 b(-)47 b(number)f(of)h(dimensions)e
+(in)i(the)g(FITS)g(array)0 2023 y(naxis1)142 b(-)47 b(length)f(of)h
+(the)g(X/first)f(axis)h(of)g(the)g(FITS)f(array)0 2136
+y(naxis2)142 b(-)47 b(length)f(of)h(the)g(Y/second)f(axis)g(of)i(the)e
+(FITS)h(array)0 2249 y(naxis3)142 b(-)47 b(length)f(of)h(the)g(Z/third)
+f(axis)h(of)g(the)g(FITS)f(array)0 2362 y(nchars)142
+b(-)47 b(number)f(of)h(characters)e(to)i(read)g(or)g(write)0
+2475 y(nelements-)e(number)h(of)h(data)g(elements)e(to)j(read)e(or)h
+(write)0 2588 y(newfptr)94 b(-)47 b(returned)f(pointer)f(to)j(the)e
+(reopened)g(file)0 2700 y(newveclen-)f(new)i(value)f(for)h(the)g
+(column)f(vector)g(repeat)g(parameter)0 2813 y(nexc)238
+b(-)47 b(number)f(of)h(names)g(in)g(the)g(exclusion)e(list)i(\(may)f(=)
+i(0\))0 2926 y(nfound)142 b(-)47 b(number)f(of)h(keywords)f(found)g
+(\(highest)g(keyword)g(number\))0 3039 y(nkeys)190 b(-)47
+b(number)f(of)h(keywords)f(in)h(the)g(sequence)0 3152
+y(ninc)238 b(-)47 b(number)f(of)h(names)g(in)g(the)g(inclusion)e(list)0
+3265 y(nmembers)h(-)h(Number)f(of)h(grouping)f(table)g(members)g
+(\(NAXIS2)g(value\).)0 3378 y(nmove)190 b(-)47 b(number)f(of)h(HDUs)g
+(to)g(move)g(\(+)g(or)g(-\),)g(relative)f(to)h(current)f(position)0
+3491 y(nocomments)f(-)i(if)h(equal)e(to)h(TRUE,)g(then)f(no)h
+(commentary)e(keywords)h(will)h(be)g(copied)0 3604 y(noisebits-)e
+(number)h(of)h(bits)g(to)g(ignore)f(when)h(compressing)e(floating)g
+(point)h(images)0 3717 y(nrows)190 b(-)47 b(number)f(of)h(rows)g(in)g
+(the)g(table)0 3830 y(nstart)142 b(-)47 b(first)f(integer)g(value)0
+3942 y(nullarray-)f(set)i(to)g(TRUE)g(\(=1\))f(if)i(corresponding)c
+(data)i(element)g(is)h(undefined)0 4055 y(nulval)142
+b(-)47 b(numerical)e(value)i(to)g(represent)e(undefined)g(pixels)0
+4168 y(nulstr)142 b(-)47 b(character)e(string)h(used)h(to)g(represent)e
+(undefined)h(values)g(in)h(ASCII)f(table)0 4281 y(numval)142
+b(-)47 b(numerical)e(data)i(value,)f(of)h(the)g(appropriate)e(data)h
+(type)0 4394 y(offset)142 b(-)95 b(byte)46 b(offset)g(in)i(the)f(heap)f
+(to)h(the)g(first)g(element)e(of)j(the)f(vector)0 4507
+y(openfptr)f(-)h(pointer)f(to)h(a)g(currently)f(open)g(FITS)h(file)0
+4620 y(overlap)94 b(-)47 b(number)f(of)h(bytes)g(in)g(the)g(binary)f
+(table)g(heap)h(pointed)f(to)h(by)g(more)g(than)f(1)525
+4733 y(descriptor)0 4846 y(outcolnum-)f(output)h(column)g(number;)g
+(range)g(=)i(1)f(to)g(TFIELDS)f(+)i(1)0 4959 y(outfile)94
+b(-)47 b(and)g(optional)e(output)i(filename;)e(the)i(input)f(file)h
+(will)f(be)i(copied)e(to)h(this)f(prior)525 5072 y(to)h(opening)f(the)h
+(file)0 5185 y(outfptr)94 b(-)47 b(pointer)f(to)h(a)g('fitsfile')e
+(structure)h(describing)f(the)i(output)f(FITS)g(file.)0
+5297 y(pcount)142 b(-)47 b(value)f(of)i(the)e(PCOUNT)h(keyword)e(=)j
+(size)e(of)i(binary)e(table)g(heap)0 5410 y(previous)g(-)h(if)g(TRUE,)g
+(any)f(previous)g(HDUs)h(in)g(the)g(input)f(file)h(will)f(be)i(copied.)
+0 5523 y(repeat)142 b(-)47 b(length)f(of)h(column)f(vector)g(\(e.g.)h
+(12J\);)f(==)h(1)h(for)f(ASCII)f(table)0 5636 y(rmopt)190
+b(-)47 b(grouping)f(table)g(remove)g(option)g(parameter.)f(Allowed)h
+(values)g(are:)p eop
+%%Page: 155 163
+155 162 bop 3764 299 a Fj(155)525 555 y Fe(OPT_RM_GPT,)45
+b(OPT_RM_ENTRY,)f(OPT_RM_MBR,)h(and)i(OPT_RM_ALL.)0 668
+y(rootname)f(-)h(root)g(filename,)e(minus)h(any)h(extension)e(or)j
+(filtering)d(specifications)0 781 y(rot)286 b(-)47 b(celestial)e
+(coordinate)g(rotation)h(angle)g(\(degrees\))0 894 y(rowlen)142
+b(-)47 b(length)f(of)h(a)h(table)e(row,)h(in)g(characters)e(or)i(bytes)
+0 1007 y(rowlist)94 b(-)47 b(sorted)f(list)h(of)g(row)g(numbers)f(to)h
+(be)g(deleted)f(from)g(the)h(table)0 1120 y(rownum)142
+b(-)47 b(number)f(of)h(the)g(row)g(\(first)f(row)h(=)h(1\))0
+1233 y(rowrange)e(-)h(list)g(of)g(rows)f(or)i(row)f(ranges:)e
+('3,6-8,12,56-80')f(or)j('500-')0 1346 y(row_status)e(-)i(array)g(of)g
+(True/False)e(results)h(for)h(each)f(row)h(that)g(was)g(evaluated)0
+1458 y(scale)190 b(-)47 b(linear)f(scaling)g(factor;)g(true)g(value)h
+(=)g(\(FITS)g(value\))f(*)h(scale)f(+)i(zero)0 1571 y(second)142
+b(-)47 b(second)f(within)g(minute)g(\(0)h(-)h(60.9999999999\))c(\(leap)
+i(second!\))0 1684 y(simple)142 b(-)47 b(TRUE)g(\(=1\))f(if)h(FITS)g
+(file)g(conforms)e(to)i(the)g(Standard,)f(else)g(FALSE)h(\(=0\))0
+1797 y(space)190 b(-)47 b(number)f(of)h(blank)g(spaces)f(to)h(leave)f
+(between)g(ASCII)g(table)h(columns)0 1910 y(status)142
+b(-)47 b(returned)f(error)g(status)g(code)h(\(0)g(=)g(OK\))0
+2023 y(sum)286 b(-)47 b(32)g(bit)g(unsigned)f(checksum)f(value)0
+2136 y(tbcol)190 b(-)47 b(byte)g(position)e(in)i(row)g(to)g(start)g(of)
+g(column)f(\(1st)h(col)g(has)g(tbcol)f(=)h(1\))0 2249
+y(tdisp)190 b(-)47 b(Fortran)f(style)g(display)g(format)g(for)h(the)g
+(table)f(column)0 2362 y(tdimstr)94 b(-)47 b(the)g(value)f(of)h(the)g
+(TDIMn)g(keyword)0 2475 y(templt)142 b(-)47 b(template)f(string)g(used)
+g(in)h(comparison)e(\(null-terminated\))0 2588 y(tfields)94
+b(-)47 b(number)f(of)h(fields)f(\(columns\))g(in)h(the)g(table)0
+2700 y(tfopt)190 b(-)47 b(grouping)f(table)g(member)g(transfer)g
+(option)g(parameter.)f(Allowed)g(values)i(are:)525 2813
+y(OPT_MCP_ADD,)d(and)j(OPT_MCP_MOV.)0 2926 y(tform)190
+b(-)47 b(format)f(of)h(the)g(column)f(\(null-terminated\);)d(allowed)j
+(values)g(are:)525 3039 y(ASCII)g(tables:)94 b(Iw,)47
+b(Aw,)g(Fww.dd,)f(Eww.dd,)f(or)j(Dww.dd)525 3152 y(Binary)e(tables:)g
+(rL,)h(rX,)g(rB,)g(rI,)g(rJ,)f(rA,)h(rAw,)g(rE,)g(rD,)g(rC,)g(rM)525
+3265 y(where)f('w'=width)g(of)h(the)g(field,)f('d'=no.)g(of)h
+(decimals,)e('r'=repeat)g(count.)525 3378 y(Variable)h(length)g(array)g
+(columns)g(are)h(denoted)f(by)h(a)g('1P')g(before)f(the)h(data)f(type)
+525 3491 y(character)f(\(e.g.,)h('1PJ'\).)94 b(When)47
+b(creating)e(a)j(binary)e(table,)g(2)h(addition)f(tform)525
+3604 y(data)h(type)f(codes)h(are)g(recognized)e(by)i(CFITSIO:)e('rU')i
+(and)g('rV')f(for)h(unsigned)525 3717 y(16-bit)f(and)h(unsigned)f
+(32-bit)g(integer,)f(respectively.)0 3942 y(theap)190
+b(-)47 b(zero)g(indexed)e(byte)i(offset)f(of)h(starting)f(address)g(of)
+h(the)g(heap)525 4055 y(relative)f(to)h(the)g(beginning)e(of)i(the)g
+(binary)f(table)g(data)0 4168 y(tilesize)g(-)h(array)f(of)i(length)e
+(NAXIS)g(that)h(specifies)e(the)i(dimensions)e(of)525
+4281 y(the)i(image)f(compression)f(tiles)0 4394 y(ttype)190
+b(-)47 b(label)f(or)i(name)e(for)h(table)f(column)h
+(\(null-terminated\))0 4507 y(tunit)190 b(-)47 b(physical)f(unit)g(for)
+h(table)f(column)h(\(null-terminated\))0 4620 y(typechar)f(-)h
+(symbolic)f(code)g(of)h(the)g(table)g(column)f(data)g(type)0
+4733 y(typecode)g(-)h(data)g(type)f(code)h(of)g(the)g(table)f(column.)
+94 b(The)47 b(negative)e(of)525 4846 y(the)i(value)f(indicates)g(a)h
+(variable)f(length)g(array)g(column.)764 4959 y(Datatype)618
+b(typecode)189 b(Mnemonic)764 5072 y(bit,)46 b(X)907
+b(1)381 b(TBIT)764 5185 y(byte,)46 b(B)811 b(11)381 b(TBYTE)764
+5297 y(logical,)45 b(L)668 b(14)381 b(TLOGICAL)764 5410
+y(ASCII)46 b(character,)f(A)286 b(16)381 b(TSTRING)764
+5523 y(short)46 b(integer,)g(I)381 b(21)g(TSHORT)764
+5636 y(integer,)45 b(J)668 b(41)381 b(TINT32BIT)p eop
+%%Page: 156 164
+156 163 bop 0 299 a Fj(156)1822 b Fh(APPENDIX)31 b(B.)61
+b(P)-8 b(ARAMETER)30 b(DEFINITIONS)764 555 y Fe(long)46
+b(long)h(integer,)e(K)191 b(81)381 b(TLONGLONG)764 668
+y(real,)46 b(E)811 b(42)381 b(TFLOAT)764 781 y(double)46
+b(precision,)f(D)238 b(82)381 b(TDOUBLE)764 894 y(complex,)45
+b(C)668 b(83)381 b(TCOMPLEX)764 1007 y(double)46 b(complex,)f(M)286
+b(163)381 b(TDBLCOMPLEX)620 1120 y(The)47 b(TLONGLONG)f(column)g(type)g
+(is)i(experimental)c(and)j(is)g(not)620 1233 y(recognized)e(in)j(the)f
+(official)e(FITS)i(Standard)e(document)0 1346 y(unit)238
+b(-)47 b(the)g(physical)e(unit)i(string)f(\(e.g.,)g('km/s'\))g(for)h(a)
+g(keyword)0 1458 y(unused)142 b(-)47 b(number)f(of)h(unused)f(bytes)h
+(in)g(the)g(binary)f(table)g(heap)0 1571 y(urltype)94
+b(-)47 b(the)g(file)g(type)f(of)h(the)g(FITS)g(file)g(\(file://,)e
+(ftp://,)h(mem://,)f(etc.\))0 1684 y(validheap-)g(returned)h(value)g(=)
+h(FALSE)g(if)g(any)g(of)g(the)g(variable)e(length)i(array)525
+1797 y(address)f(are)h(outside)f(the)g(valid)h(range)f(of)h(addresses)f
+(in)h(the)g(heap)0 1910 y(value)190 b(-)47 b(the)g(keyword)f(value)g
+(string)g(\(70)h(char)g(max,)f(null-terminated\))0 2023
+y(version)94 b(-)47 b(current)f(version)g(number)g(of)h(the)g(CFITSIO)f
+(library)0 2136 y(width)190 b(-)47 b(width)f(of)i(the)e(character)g
+(string)g(field)0 2249 y(xcol)238 b(-)47 b(number)f(of)h(the)g(column)f
+(containing)f(the)i(X)h(coordinate)d(values)0 2362 y(xinc)238
+b(-)47 b(X)g(axis)g(coordinate)e(increment)g(at)j(reference)d(pixel)h
+(\(deg\))0 2475 y(xpix)238 b(-)47 b(X)g(axis)g(pixel)f(location)0
+2588 y(xpos)238 b(-)47 b(X)g(axis)g(celestial)e(coordinate)g(\(usually)
+h(RA\))h(\(deg\))0 2700 y(xrefpix)94 b(-)47 b(X)g(axis)g(reference)e
+(pixel)i(array)f(location)0 2813 y(xrefval)94 b(-)47
+b(X)g(axis)g(coordinate)e(value)h(at)i(the)f(reference)e(pixel)h
+(\(deg\))0 2926 y(ycol)238 b(-)47 b(number)f(of)h(the)g(column)f
+(containing)f(the)i(X)h(coordinate)d(values)0 3039 y(year)238
+b(-)47 b(calendar)f(year)g(\(e.g.)h(1999,)f(2000,)g(etc\))0
+3152 y(yinc)238 b(-)47 b(Y)g(axis)g(coordinate)e(increment)g(at)j
+(reference)d(pixel)h(\(deg\))0 3265 y(ypix)238 b(-)47
+b(y)g(axis)g(pixel)f(location)0 3378 y(ypos)238 b(-)47
+b(y)g(axis)g(celestial)e(coordinate)g(\(usually)h(DEC\))h(\(deg\))0
+3491 y(yrefpix)94 b(-)47 b(Y)g(axis)g(reference)e(pixel)i(array)f
+(location)0 3604 y(yrefval)94 b(-)47 b(Y)g(axis)g(coordinate)e(value)h
+(at)i(the)f(reference)e(pixel)h(\(deg\))0 3717 y(zero)238
+b(-)47 b(scaling)f(offset;)g(true)g(value)h(=)g(\(FITS)f(value\))h(*)g
+(scale)f(+)i(zero)p eop
+%%Page: 157 165
+157 164 bop 0 1225 a Fg(App)5 b(endix)65 b(C)0 1687 y
+Fm(CFITSIO)76 b(Error)h(Status)h(Co)6 b(des)0 2180 y
+Fj(The)28 b(follo)m(wing)e(table)i(lists)f(all)g(the)h(error)g(status)g
+(co)s(des)g(used)f(b)m(y)h(CFITSIO.)f(Programmers)h(are)g(encouraged)0
+2293 y(to)37 b(use)e(the)h(sym)m(b)s(olic)f(mnemonics)f(\(de\014ned)h
+(in)g(the)h(\014le)f(\014tsio.h\))h(rather)f(than)h(the)g(actual)g(in)m
+(teger)h(status)0 2406 y(v)-5 b(alues)30 b(to)h(impro)m(v)m(e)f(the)h
+(readabilit)m(y)d(of)j(their)e(co)s(de.)48 2665 y Fe(Symbolic)45
+b(Const)190 b(Value)237 b(Meaning)48 2778 y(--------------)187
+b(-----)94 b(------------------------)o(----)o(---)o(----)o(----)o(--)
+1002 2891 y(0)191 b(OK,)47 b(no)g(error)48 3004 y(SAME_FILE)427
+b(101)190 b(input)46 b(and)h(output)f(files)h(are)g(the)f(same)48
+3117 y(TOO_MANY_FILES)187 b(103)j(tried)46 b(to)h(open)g(too)g(many)g
+(FITS)f(files)h(at)g(once)48 3230 y(FILE_NOT_OPENED)139
+b(104)190 b(could)46 b(not)h(open)g(the)g(named)f(file)48
+3343 y(FILE_NOT_CREATED)91 b(105)190 b(could)46 b(not)h(create)f(the)h
+(named)g(file)48 3456 y(WRITE_ERROR)331 b(106)190 b(error)46
+b(writing)g(to)h(FITS)g(file)48 3569 y(END_OF_FILE)331
+b(107)190 b(tried)46 b(to)h(move)g(past)g(end)g(of)g(file)48
+3681 y(READ_ERROR)379 b(108)190 b(error)46 b(reading)g(from)h(FITS)f
+(file)48 3794 y(FILE_NOT_CLOSED)139 b(110)190 b(could)46
+b(not)h(close)g(the)f(file)48 3907 y(ARRAY_TOO_BIG)235
+b(111)190 b(array)46 b(dimensions)f(exceed)h(internal)g(limit)48
+4020 y(READONLY_FILE)235 b(112)190 b(Cannot)46 b(write)g(to)i(readonly)
+d(file)48 4133 y(MEMORY_ALLOCATION)e(113)190 b(Could)46
+b(not)h(allocate)f(memory)48 4246 y(BAD_FILEPTR)331 b(114)190
+b(invalid)46 b(fitsfile)f(pointer)48 4359 y(NULL_INPUT_PTR)187
+b(115)j(NULL)47 b(input)f(pointer)g(to)h(routine)48 4472
+y(SEEK_ERROR)379 b(116)190 b(error)46 b(seeking)g(position)g(in)h(file)
+48 4698 y(BAD_URL_PREFIX)235 b(121)142 b(invalid)46 b(URL)h(prefix)f
+(on)h(file)g(name)48 4811 y(TOO_MANY_DRIVERS)139 b(122)j(tried)46
+b(to)h(register)f(too)h(many)g(IO)g(drivers)48 4924 y
+(DRIVER_INIT_FAILED)c(123)142 b(driver)46 b(initialization)e(failed)48
+5036 y(NO_MATCHING_DRIVER)f(124)142 b(matching)45 b(driver)i(is)g(not)g
+(registered)48 5149 y(URL_PARSE_ERROR)187 b(125)142 b(failed)46
+b(to)h(parse)g(input)f(file)h(URL)48 5262 y(RANGE_PARSE_ERROR)91
+b(126)142 b(parse)46 b(error)h(in)g(range)f(list)48 5488
+y(SHARED_BADARG)235 b(151)190 b(bad)47 b(argument)e(in)j(shared)e
+(memory)g(driver)48 5601 y(SHARED_NULPTR)235 b(152)190
+b(null)47 b(pointer)e(passed)h(as)i(an)f(argument)48
+5714 y(SHARED_TABFULL)187 b(153)j(no)47 b(more)g(free)f(shared)g
+(memory)h(handles)1882 5942 y Fj(157)p eop
+%%Page: 158 166
+158 165 bop 0 299 a Fj(158)1589 b Fh(APPENDIX)31 b(C.)61
+b(CFITSIO)29 b(ERR)m(OR)h(ST)-8 b(A)g(TUS)30 b(CODES)48
+555 y Fe(SHARED_NOTINIT)187 b(154)j(shared)46 b(memory)g(driver)g(is)h
+(not)g(initialized)48 668 y(SHARED_IPCERR)235 b(155)190
+b(IPC)47 b(error)f(returned)g(by)h(a)g(system)f(call)48
+781 y(SHARED_NOMEM)283 b(156)190 b(no)47 b(memory)f(in)h(shared)f
+(memory)h(driver)48 894 y(SHARED_AGAIN)283 b(157)190
+b(resource)45 b(deadlock)h(would)g(occur)48 1007 y(SHARED_NOFILE)235
+b(158)190 b(attempt)46 b(to)h(open/create)e(lock)h(file)h(failed)48
+1120 y(SHARED_NORESIZE)139 b(159)190 b(shared)46 b(memory)g(block)g
+(cannot)h(be)g(resized)f(at)h(the)g(moment)48 1346 y(HEADER_NOT_EMPTY)
+91 b(201)190 b(header)46 b(already)g(contains)f(keywords)48
+1458 y(KEY_NO_EXIST)283 b(202)190 b(keyword)46 b(not)h(found)f(in)h
+(header)48 1571 y(KEY_OUT_BOUNDS)187 b(203)j(keyword)46
+b(record)g(number)g(is)h(out)g(of)g(bounds)48 1684 y(VALUE_UNDEFINED)
+139 b(204)190 b(keyword)46 b(value)g(field)g(is)i(blank)48
+1797 y(NO_QUOTE)475 b(205)190 b(string)46 b(is)h(missing)f(the)h
+(closing)f(quote)48 1910 y(BAD_KEYCHAR)331 b(207)190
+b(illegal)46 b(character)f(in)i(keyword)f(name)h(or)g(card)48
+2023 y(BAD_ORDER)427 b(208)190 b(required)45 b(keywords)h(out)h(of)g
+(order)48 2136 y(NOT_POS_INT)331 b(209)190 b(keyword)46
+b(value)g(is)h(not)g(a)h(positive)d(integer)48 2249 y(NO_END)571
+b(210)190 b(couldn't)45 b(find)i(END)g(keyword)48 2362
+y(BAD_BITPIX)379 b(211)190 b(illegal)46 b(BITPIX)g(keyword)g(value)48
+2475 y(BAD_NAXIS)427 b(212)190 b(illegal)46 b(NAXIS)g(keyword)g(value)
+48 2588 y(BAD_NAXES)427 b(213)190 b(illegal)46 b(NAXISn)g(keyword)g
+(value)48 2700 y(BAD_PCOUNT)379 b(214)190 b(illegal)46
+b(PCOUNT)g(keyword)g(value)48 2813 y(BAD_GCOUNT)379 b(215)190
+b(illegal)46 b(GCOUNT)g(keyword)g(value)48 2926 y(BAD_TFIELDS)331
+b(216)190 b(illegal)46 b(TFIELDS)g(keyword)f(value)48
+3039 y(NEG_WIDTH)427 b(217)190 b(negative)45 b(table)i(row)g(size)48
+3152 y(NEG_ROWS)475 b(218)190 b(negative)45 b(number)i(of)g(rows)f(in)i
+(table)48 3265 y(COL_NOT_FOUND)235 b(219)190 b(column)46
+b(with)h(this)f(name)h(not)g(found)f(in)h(table)48 3378
+y(BAD_SIMPLE)379 b(220)190 b(illegal)46 b(value)g(of)h(SIMPLE)f
+(keyword)48 3491 y(NO_SIMPLE)427 b(221)190 b(Primary)46
+b(array)g(doesn't)g(start)g(with)h(SIMPLE)48 3604 y(NO_BITPIX)427
+b(222)190 b(Second)46 b(keyword)g(not)h(BITPIX)48 3717
+y(NO_NAXIS)475 b(223)190 b(Third)46 b(keyword)g(not)h(NAXIS)48
+3830 y(NO_NAXES)475 b(224)190 b(Couldn't)45 b(find)i(all)g(the)g
+(NAXISn)f(keywords)48 3942 y(NO_XTENSION)331 b(225)190
+b(HDU)47 b(doesn't)f(start)g(with)h(XTENSION)e(keyword)48
+4055 y(NOT_ATABLE)379 b(226)190 b(the)47 b(CHDU)f(is)i(not)f(an)g
+(ASCII)f(table)g(extension)48 4168 y(NOT_BTABLE)379 b(227)190
+b(the)47 b(CHDU)f(is)i(not)f(a)g(binary)f(table)g(extension)48
+4281 y(NO_PCOUNT)427 b(228)190 b(couldn't)45 b(find)i(PCOUNT)f(keyword)
+48 4394 y(NO_GCOUNT)427 b(229)190 b(couldn't)45 b(find)i(GCOUNT)f
+(keyword)48 4507 y(NO_TFIELDS)379 b(230)190 b(couldn't)45
+b(find)i(TFIELDS)f(keyword)48 4620 y(NO_TBCOL)475 b(231)190
+b(couldn't)45 b(find)i(TBCOLn)f(keyword)48 4733 y(NO_TFORM)475
+b(232)190 b(couldn't)45 b(find)i(TFORMn)f(keyword)48
+4846 y(NOT_IMAGE)427 b(233)190 b(the)47 b(CHDU)f(is)i(not)f(an)g(IMAGE)
+f(extension)48 4959 y(BAD_TBCOL)427 b(234)190 b(TBCOLn)46
+b(keyword)g(value)g(<)i(0)f(or)g(>)h(rowlength)48 5072
+y(NOT_TABLE)427 b(235)190 b(the)47 b(CHDU)f(is)i(not)f(a)g(table)48
+5185 y(COL_TOO_WIDE)283 b(236)190 b(column)46 b(is)h(too)g(wide)g(to)g
+(fit)g(in)g(table)48 5297 y(COL_NOT_UNIQUE)187 b(237)j(more)47
+b(than)f(1)i(column)e(name)g(matches)g(template)48 5410
+y(BAD_ROW_WIDTH)235 b(241)190 b(sum)47 b(of)g(column)f(widths)g(not)h
+(=)h(NAXIS1)48 5523 y(UNKNOWN_EXT)331 b(251)190 b(unrecognizable)44
+b(FITS)i(extension)g(type)48 5636 y(UNKNOWN_REC)331 b(252)190
+b(unknown)46 b(record;)g(1st)g(keyword)g(not)h(SIMPLE)f(or)h(XTENSION)p
+eop
+%%Page: 159 167
+159 166 bop 3764 299 a Fj(159)48 555 y Fe(END_JUNK)475
+b(253)190 b(END)47 b(keyword)f(is)h(not)g(blank)48 668
+y(BAD_HEADER_FILL)139 b(254)190 b(Header)46 b(fill)h(area)f(contains)g
+(non-blank)f(chars)48 781 y(BAD_DATA_FILL)235 b(255)190
+b(Illegal)46 b(data)g(fill)h(bytes)f(\(not)h(zero)g(or)g(blank\))48
+894 y(BAD_TFORM)427 b(261)190 b(illegal)46 b(TFORM)g(format)g(code)48
+1007 y(BAD_TFORM_DTYPE)139 b(262)190 b(unrecognizable)44
+b(TFORM)i(data)h(type)f(code)48 1120 y(BAD_TDIM)475 b(263)190
+b(illegal)46 b(TDIMn)g(keyword)g(value)48 1233 y(BAD_HEAP_PTR)283
+b(264)190 b(invalid)46 b(BINTABLE)f(heap)i(pointer)f(is)h(out)g(of)g
+(range)48 1458 y(BAD_HDU_NUM)331 b(301)190 b(HDU)47 b(number)f(<)h(1)48
+1571 y(BAD_COL_NUM)331 b(302)190 b(column)46 b(number)g(<)i(1)f(or)g(>)
+h(tfields)48 1684 y(NEG_FILE_POS)283 b(304)190 b(tried)46
+b(to)h(move)g(to)g(negative)f(byte)g(location)g(in)h(file)48
+1797 y(NEG_BYTES)427 b(306)190 b(tried)46 b(to)h(read)g(or)g(write)g
+(negative)e(number)h(of)h(bytes)48 1910 y(BAD_ROW_NUM)331
+b(307)190 b(illegal)46 b(starting)f(row)i(number)f(in)h(table)48
+2023 y(BAD_ELEM_NUM)283 b(308)190 b(illegal)46 b(starting)f(element)h
+(number)g(in)h(vector)48 2136 y(NOT_ASCII_COL)235 b(309)190
+b(this)47 b(is)g(not)g(an)g(ASCII)f(string)g(column)48
+2249 y(NOT_LOGICAL_COL)139 b(310)190 b(this)47 b(is)g(not)g(a)g
+(logical)f(data)h(type)f(column)48 2362 y(BAD_ATABLE_FORMAT)d(311)190
+b(ASCII)46 b(table)h(column)f(has)h(wrong)f(format)48
+2475 y(BAD_BTABLE_FORMAT)d(312)190 b(Binary)46 b(table)g(column)g(has)h
+(wrong)g(format)48 2588 y(NO_NULL)523 b(314)190 b(null)47
+b(value)f(has)h(not)g(been)f(defined)48 2700 y(NOT_VARI_LEN)283
+b(317)190 b(this)47 b(is)g(not)g(a)g(variable)f(length)g(column)48
+2813 y(BAD_DIMEN)427 b(320)190 b(illegal)46 b(number)g(of)h(dimensions)
+e(in)i(array)48 2926 y(BAD_PIX_NUM)331 b(321)190 b(first)46
+b(pixel)h(number)f(greater)g(than)g(last)h(pixel)48 3039
+y(ZERO_SCALE)379 b(322)190 b(illegal)46 b(BSCALE)g(or)h(TSCALn)f
+(keyword)g(=)h(0)48 3152 y(NEG_AXIS)475 b(323)190 b(illegal)46
+b(axis)g(length)g(<)i(1)48 3378 y(NOT_GROUP_TABLE)330
+b(340)142 b(Grouping)46 b(function)f(error)48 3491 y
+(HDU_ALREADY_MEMBER)186 b(341)48 3604 y(MEMBER_NOT_FOUND)282
+b(342)48 3717 y(GROUP_NOT_FOUND)330 b(343)48 3830 y(BAD_GROUP_ID)474
+b(344)48 3942 y(TOO_MANY_HDUS_TRACKED)42 b(345)48 4055
+y(HDU_ALREADY_TRACKED)138 b(346)48 4168 y(BAD_OPTION)570
+b(347)48 4281 y(IDENTICAL_POINTERS)186 b(348)48 4394
+y(BAD_GROUP_ATTACH)282 b(349)48 4507 y(BAD_GROUP_DETACH)g(350)48
+4733 y(NGP_NO_MEMORY)426 b(360)238 b(malloc)46 b(failed)48
+4846 y(NGP_READ_ERR)474 b(361)238 b(read)46 b(error)h(from)f(file)48
+4959 y(NGP_NUL_PTR)522 b(362)238 b(null)46 b(pointer)g(passed)g(as)h
+(an)g(argument.)1575 5072 y(Passing)f(null)g(pointer)g(as)h(a)h(name)f
+(of)1575 5185 y(template)f(file)g(raises)g(this)h(error)48
+5297 y(NGP_EMPTY_CURLINE)234 b(363)k(line)46 b(read)h(seems)f(to)h(be)h
+(empty)e(\(used)1575 5410 y(internally\))48 5523 y
+(NGP_UNREAD_QUEUE_FULL)c(364)238 b(cannot)46 b(unread)g(more)g(then)h
+(1)g(line)g(\(or)g(single)1575 5636 y(line)g(twice\))p
+eop
+%%Page: 160 168
+160 167 bop 0 299 a Fj(160)1589 b Fh(APPENDIX)31 b(C.)61
+b(CFITSIO)29 b(ERR)m(OR)h(ST)-8 b(A)g(TUS)30 b(CODES)48
+555 y Fe(NGP_INC_NESTING)330 b(365)238 b(too)46 b(deep)h(include)f
+(file)h(nesting)e(\(infinite)1575 668 y(loop,)h(template)g(includes)f
+(itself)i(?\))48 781 y(NGP_ERR_FOPEN)426 b(366)238 b(fopen\(\))45
+b(failed,)h(cannot)g(open)h(template)e(file)48 894 y(NGP_EOF)714
+b(367)238 b(end)46 b(of)i(file)e(encountered)f(and)i(not)g(expected)48
+1007 y(NGP_BAD_ARG)522 b(368)238 b(bad)46 b(arguments)g(passed.)g
+(Usually)f(means)1575 1120 y(internal)h(parser)g(error.)g(Should)g(not)
+h(happen)48 1233 y(NGP_TOKEN_NOT_EXPECT)90 b(369)238
+b(token)46 b(not)h(expected)e(here)48 1458 y(BAD_I2C)523
+b(401)190 b(bad)47 b(int)g(to)g(formatted)e(string)h(conversion)48
+1571 y(BAD_F2C)523 b(402)190 b(bad)47 b(float)f(to)h(formatted)f
+(string)g(conversion)48 1684 y(BAD_INTKEY)379 b(403)190
+b(can't)46 b(interpret)g(keyword)f(value)i(as)g(integer)48
+1797 y(BAD_LOGICALKEY)187 b(404)j(can't)46 b(interpret)g(keyword)f
+(value)i(as)g(logical)48 1910 y(BAD_FLOATKEY)283 b(405)190
+b(can't)46 b(interpret)g(keyword)f(value)i(as)g(float)48
+2023 y(BAD_DOUBLEKEY)235 b(406)190 b(can't)46 b(interpret)g(keyword)f
+(value)i(as)g(double)48 2136 y(BAD_C2I)523 b(407)190
+b(bad)47 b(formatted)e(string)h(to)h(int)g(conversion)48
+2249 y(BAD_C2F)523 b(408)190 b(bad)47 b(formatted)e(string)h(to)h
+(float)g(conversion)48 2362 y(BAD_C2D)523 b(409)190 b(bad)47
+b(formatted)e(string)h(to)h(double)f(conversion)48 2475
+y(BAD_DATATYPE)283 b(410)190 b(illegal)46 b(datatype)f(code)i(value)48
+2588 y(BAD_DECIM)427 b(411)190 b(bad)47 b(number)f(of)h(decimal)f
+(places)g(specified)48 2700 y(NUM_OVERFLOW)283 b(412)190
+b(overflow)45 b(during)i(data)f(type)h(conversion)48
+2813 y(DATA_COMPRESSION_ERR)137 b(413)95 b(error)46 b(compressing)f
+(image)48 2926 y(DATA_DECOMPRESSION_ERR)c(414)95 b(error)46
+b(uncompressing)f(image)48 3152 y(BAD_DATE)475 b(420)190
+b(error)46 b(in)h(date)g(or)g(time)g(conversion)48 3378
+y(PARSE_SYNTAX_ERR)91 b(431)190 b(syntax)46 b(error)g(in)i(parser)e
+(expression)48 3491 y(PARSE_BAD_TYPE)187 b(432)j(expression)45
+b(did)i(not)g(evaluate)e(to)i(desired)f(type)48 3604
+y(PARSE_LRG_VECTOR)91 b(433)190 b(vector)46 b(result)g(too)h(large)f
+(to)i(return)e(in)h(array)48 3717 y(PARSE_NO_OUTPUT)139
+b(434)190 b(data)47 b(parser)f(failed)g(not)h(sent)f(an)h(out)g(column)
+48 3830 y(PARSE_BAD_COL)235 b(435)190 b(bad)47 b(data)f(encounter)g
+(while)g(parsing)g(column)48 3942 y(PARSE_BAD_OUTPUT)91
+b(436)190 b(Output)46 b(file)h(not)g(of)g(proper)f(type)48
+4168 y(ANGLE_TOO_BIG)235 b(501)190 b(celestial)45 b(angle)i(too)f
+(large)h(for)g(projection)48 4281 y(BAD_WCS_VAL)331 b(502)190
+b(bad)47 b(celestial)e(coordinate)g(or)i(pixel)g(value)48
+4394 y(WCS_ERROR)427 b(503)190 b(error)46 b(in)h(celestial)f
+(coordinate)f(calculation)48 4507 y(BAD_WCS_PROJ)283
+b(504)190 b(unsupported)45 b(type)h(of)h(celestial)f(projection)48
+4620 y(NO_WCS_KEY)379 b(505)190 b(celestial)45 b(coordinate)g(keywords)
+h(not)h(found)48 4733 y(APPROX_WCS_KEY)187 b(506)j(approximate)45
+b(wcs)i(keyword)e(values)h(were)h(returned)p eop
+%%Trailer
+end
+userdict /end-hook known{end-hook}if
+%%EOF
diff --git a/pkg/tbtables/cfitsio/cfitsio.tex b/pkg/tbtables/cfitsio/cfitsio.tex
new file mode 100644
index 00000000..6375fdbf
--- /dev/null
+++ b/pkg/tbtables/cfitsio/cfitsio.tex
@@ -0,0 +1,9422 @@
+\documentclass[11pt]{book}
+\input{html.sty}
+\htmladdtonavigation
+ {\begin{rawhtml}
+ <A HREF="http://heasarc.gsfc.nasa.gov/docs/software/fitsio/fitsio.html">FITSIO Home</A>
+ \end{rawhtml}}
+\oddsidemargin=0.00in
+\evensidemargin=0.00in
+\textwidth=6.5in
+%\topmargin=0.0in
+\textheight=8.75in
+\parindent=0cm
+\parskip=0.2cm
+\begin{document}
+\pagenumbering{roman}
+
+\begin{titlepage}
+\normalsize
+\vspace*{4.0cm}
+\begin{center}
+{\Huge \bf CFITSIO User's Reference Guide}\\
+\end{center}
+\medskip
+\medskip
+\begin{center}
+{\LARGE \bf An Interface to FITS Format Files}\\
+\end{center}
+\begin{center}
+{\LARGE \bf for C Programmers}\\
+\end{center}
+\medskip
+\medskip
+\begin{center}
+{\Large Version 2.5 \\}
+\end{center}
+\bigskip
+\vskip 2.5cm
+\begin{center}
+{HEASARC\\
+Code 662\\
+Goddard Space Flight Center\\
+Greenbelt, MD 20771\\
+USA}
+\end{center}
+
+\vfill
+\bigskip
+\begin{center}
+{\Large December 2004\\}
+\end{center}
+\vfill
+\end{titlepage}
+
+\clearpage
+
+\tableofcontents
+\chapter{Introduction }
+\pagenumbering{arabic}
+
+
+\section{ A Brief Overview}
+
+CFITSIO is a machine-independent library of routines for reading and
+writing data files in the FITS (Flexible Image Transport System) data
+format. It can also read IRAF format image files and raw binary data
+arrays by converting them on the fly into a virtual FITS format file.
+This library is written in ANSI C and provides a powerful yet simple
+interface for accessing FITS files which will run on most commonly used
+computers and workstations. CFITSIO supports all the features
+described in the official NOST definition of the FITS format and can
+read and write all the currently defined types of extensions, including
+ASCII tables (TABLE), Binary tables (BINTABLE) and IMAGE extensions.
+The CFITSIO routines insulate the programmer from having to deal with
+the complicated formatting details in the FITS file, however, it is
+assumed that users have a general knowledge about the structure and
+usage of FITS files.
+
+CFITSIO also contains a set of Fortran callable wrapper routines which
+allow Fortran programs to call the CFITSIO routines. See the companion
+``FITSIO User's Guide'' for the definition of the Fortran subroutine
+calling sequences. These wrappers replace the older Fortran FITSIO
+library which is no longer supported.
+
+The CFITSIO package was initially developed by the HEASARC (High Energy
+Astrophysics Science Archive Research Center) at the NASA Goddard Space
+Flight Center to convert various existing and newly acquired
+astronomical data sets into FITS format and to further analyze data
+already in FITS format. New features continue to be added to CFITSIO
+in large part due to contributions of ideas or actual code from
+users of the package. The Integral Science Data Center in Switzerland,
+and the XMM/ESTEC project in The Netherlands made especially significant
+contributions that resulted in many of the new features that appeared
+in v2.0 of CFITSIO.
+
+
+\section{Sources of FITS Software and Information}
+
+The latest version of the CFITSIO source code,
+documentation, and example programs are available on the World-Wide
+Web or via anonymous ftp from:
+
+\begin{verbatim}
+ http://heasarc.gsfc.nasa.gov/fitsio
+ ftp://legacy.gsfc.nasa.gov/software/fitsio/c
+\end{verbatim}
+
+Any questions, bug reports, or suggested enhancements related to the CFITSIO
+package should be sent to the primary author:
+
+\begin{verbatim}
+ Dr. William Pence Telephone: (301) 286-4599
+ HEASARC, Code 662 E-mail: pence@tetra.gsfc.nasa.gov
+ NASA/Goddard Space Flight Center
+ Greenbelt, MD 20771, USA
+\end{verbatim}
+This User's Guide assumes that readers already have a general
+understanding of the definition and structure of FITS format files.
+Further information about FITS formats is available from the FITS Support
+Office at {\tt http://fits.gsfc.nasa.gov}. In particular, the
+'NOST FITS Standard' gives the authoritative definition of the FITS data
+format, and the `FITS User's Guide' provides additional historical background
+and practical advice on using FITS files.
+
+The HEASARC also provides a very sophisticated FITS file analysis
+program called `Fv' which can be used to display and edit the contents
+of any FITS file as well as construct new FITS files from scratch. The
+display functions in Fv allow users to interactively adjust the
+brightness and contrast of images, pan, zoom, and blink images, and
+measure the positions and brightnesses of objects within images. FITS
+tables can be displayed like a spread sheet, and then modified using
+powerful calculator and sorting functions. Fv is freely available for
+most Unix platforms, Mac PCs, and Windows PCs.
+CFITSIO users may also be interested in the FTOOLS package of programs
+that can be used to manipulate and analyze FITS format files.
+Fv and FTOOLS are available from their respective Web sites at:
+
+\begin{verbatim}
+ http://fv.gsfc.nasa.gov
+ http://heasarc.gsfc.nasa.gov/ftools
+\end{verbatim}
+
+
+\section{Acknowledgements}
+
+The development of the powerful features in CFITSIO was made
+possible through collaborations with many people or organizations from
+around the world. The following in particular have made especially
+significant contributions:
+
+Programmers from the Integral Science Data Center, Switzerland (namely,
+Jurek Borkowski, Bruce O'Neel, and Don Jennings), designed the concept
+for the plug-in I/O drivers that was introduced with CFITSIO 2.0. The
+use of `drivers' greatly simplified the low-level I/O, which in turn
+made other new features in CFITSIO (e.g., support for compressed FITS
+files and support for IRAF format image files) much easier to
+implement. Jurek Borkowski wrote the Shared Memory driver, and Bruce
+O'Neel wrote the drivers for accessing FITS files over the network
+using the FTP, HTTP, and ROOT protocols.
+
+The ISDC also provided the template parsing routines (written by Jurek
+Borkowski) and the hierarchical grouping routines (written by Don
+Jennings). The ISDC DAL (Data Access Layer) routines are layered on
+top of CFITSIO and make extensive use of these features.
+
+Uwe Lammers (XMM/ESA/ESTEC, The Netherlands) designed the
+high-performance lexical parsing algorithm that is used to do
+on-the-fly filtering of FITS tables. This algorithm essentially
+pre-compiles the user-supplied selection expression into a form that
+can be rapidly evaluated for each row. Peter Wilson (RSTX, NASA/GSFC)
+then wrote the parsing routines used by CFITSIO based on Lammers'
+design, combined with other techniques such as the CFITSIO iterator
+routine to further enhance the data processing throughput. This effort
+also benefited from a much earlier lexical parsing routine that was
+developed by Kent Blackburn (NASA/GSFC). More recently, Craig Markwardt
+(NASA/GSFC) implemented additional functions (median, average, stddev)
+and other enhancements to the lexical parser.
+
+The CFITSIO iterator function is loosely based on similar ideas
+developed for the XMM Data Access Layer.
+
+Peter Wilson (RSTX, NASA/GSFC) wrote the complete set of
+Fortran-callable wrappers for all the CFITSIO routines, which in turn
+rely on the CFORTRAN macro developed by Burkhard Burow.
+
+The syntax used by CFITSIO for filtering or binning input FITS files is
+based on ideas developed for the AXAF Science Center Data Model by
+Jonathan McDowell, Antonella Fruscione, Aneta Siemiginowska and Bill
+Joye. See http://heasarc.gsfc.nasa.gov/docs/journal/axaf7.html for
+further description of the AXAF Data Model.
+
+The file decompression code were taken directly from the gzip (GNU zip)
+program developed by Jean-loup Gailly and others.
+
+The new compressed image data format (where the image is tiled and
+the compressed byte stream from each tile is stored in a binary table)
+was implemented in collaboration with Richard White (STScI), Perry
+Greenfield (STScI) and Doug Tody (NOAO).
+
+Doug Mink (SAO) provided the routines for converting IRAF format
+images into FITS format.
+
+In addition, many other people have made valuable contributions to the
+development of CFITSIO. These include (with apologies to others that may
+have inadvertently been omitted):
+
+Steve Allen, Carl Akerlof, Keith Arnaud, Morten Krabbe Barfoed, Kent
+Blackburn, G Bodammer, Romke Bontekoe, Lucio Chiappetti, Keith Costorf,
+Robin Corbet, John Davis, Richard Fink, Ning Gan, Emily Greene, Gretchen
+Green, Joe Harrington, Cheng Ho, Phil Hodge, Jim Ingham, Yoshitaka
+Ishisaki, Diab Jerius, Mark Levine, Todd Karakaskian, Edward King,
+Scott Koch, Claire Larkin, Rob Managan, Eric Mandel, Richard Mathar,
+John Mattox, Carsten Meyer, Emi Miyata, Stefan Mochnacki, Mike Noble,
+Oliver Oberdorf, Clive Page, Arvind Parmar, Jeff Pedelty, Tim Pearson,
+Philippe Prugniel, Maren Purves, Scott Randall, Chris Rogers, Arnold Rots,
+Barry Schlesinger, Robin Stebbins, Andrew Szymkowiak, Allyn Tennant,
+Peter Teuben, James Theiler, Doug Tody, Shiro Ueno, Steve Walton, Archie
+Warnock, Alan Watson, Dan Whipple, Wim Wimmers, Peter Young, Jianjun Xu,
+and Nelson Zarate.
+
+
+\section{Legal Stuff}
+
+Copyright (Unpublished--all rights reserved under the copyright laws of
+the United States), U.S. Government as represented by the Administrator
+of the National Aeronautics and Space Administration. No copyright is
+claimed in the United States under Title 17, U.S. Code.
+
+Permission to freely use, copy, modify, and distribute this software
+and its documentation without fee is hereby granted, provided that this
+copyright notice and disclaimer of warranty appears in all copies.
+(However, see the restriction on the use of the gzip compression code,
+below).
+
+DISCLAIMER:
+
+THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND,
+EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO,
+ANY WARRANTY THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY
+IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE, AND FREEDOM FROM INFRINGEMENT, AND ANY WARRANTY THAT THE
+DOCUMENTATION WILL CONFORM TO THE SOFTWARE, OR ANY WARRANTY THAT THE
+SOFTWARE WILL BE ERROR FREE. IN NO EVENT SHALL NASA BE LIABLE FOR ANY
+DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, INDIRECT, SPECIAL OR
+CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, OR IN ANY WAY
+CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY,
+CONTRACT, TORT , OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY
+PERSONS OR PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED
+FROM, OR AROSE OUT OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR
+SERVICES PROVIDED HEREUNDER."
+
+The file compress.c contains (slightly modified) source code that
+originally came from gzip-1.2.4, copyright (C) 1992-1993 by Jean-loup
+Gailly. This gzip code is distributed under the GNU General Public
+License and thus requires that any software that uses the CFITSIO
+library (which in turn uses the gzip code) must conform to the
+provisions in the GNU General Public License. A copy of the GNU
+license is included at the beginning of compress.c file.
+
+An alternate version of the compress.c file (called
+compress\_alternate.c) is provided for users who want to use the CFITSIO
+library but are unwilling or unable to publicly release their software
+under the terms of the GNU General Public License. This alternate
+version contains non-functional stubs for the file compression and
+uncompression routines used by CFITSIO. Replace the file `compress.c'
+with `compress\_alternate.c' before compiling the CFITSIO library. This
+will produce a version of CFITSIO which does not support reading or
+writing compressed FITS files but is otherwise identical to the
+standard version.
+
+\chapter{ Creating the CFITSIO Library }
+
+
+\section{Building the Library}
+
+The CFITSIO code is contained in about 40 C source files (*.c) and header
+files (*.h). On VAX/VMS systems 2 assembly-code files (vmsieeed.mar and
+vmsieeer.mar) are also needed.
+
+CFITSIO has currently been tested on the following platforms:
+
+\begin{verbatim}
+ OPERATING SYSTEM COMPILER
+ Sun OS gcc and cc (3.0.1)
+ Sun Solaris gcc and cc
+ Silicon Graphics IRIX gcc and cc
+ Silicon Graphics IRIX64 MIPS
+ Dec Alpha OSF/1 gcc and cc
+ DECstation Ultrix gcc
+ Dec Alpha OpenVMS cc
+ DEC VAX/VMS gcc and cc
+ HP-UX gcc
+ IBM AIX gcc
+ Linux gcc
+ MkLinux DR3
+ Windows 95/98/NT Borland C++ V4.5
+ Windows 95/98/NT/ME/XP Microsoft/Compaq Visual C++ v5.0, v6.0
+ Windows 95/98/NT Cygwin gcc
+ MacOS 7.1 or greater Metrowerks 10.+
+ MacOS-X 10.1 or greater cc (gcc)
+\end{verbatim}
+CFITSIO will probably run on most other Unix platforms. Cray
+supercomputers are currently not supported.
+
+
+\subsection{Unix Systems}
+
+The CFITSIO library is built on Unix systems by typing:
+
+\begin{verbatim}
+ > ./configure [--prefix=/target/installation/path]
+ > make (or 'make shared')
+ > make install (this step is optional)
+\end{verbatim}
+at the operating system prompt. The configure command customizes the
+Makefile for the particular system, then the `make' command compiles the
+source files and builds the library. Type `./configure' and not simply
+`configure' to ensure that the configure script in the current directory
+is run and not some other system-wide configure script. The optional
+'prefix' argument to configure gives the path to the directory where
+the CFITSIO library and include files should be installed via the later
+'make install' command. For example,
+
+\begin{verbatim}
+ > ./configure --prefix=/usr1/local
+\end{verbatim}
+will cause the 'make install' command to copy the CFITSIO libcfitsio file
+to /usr1/local/lib and the necessary include files to /usr1/local/include
+(assuming of course that the process has permission to write to these
+directories).
+
+The 'make shared' option builds a shared or dynamic version of the
+CFITSIO library. When using the shared library the executable code is
+not copied into your program at link time and instead the program
+locates the necessary library code at run time, normally through
+LD\_LIBRARY\_PATH or some other method. The advantages of using a shared
+library are:
+
+\begin{verbatim}
+ 1. Less disk space if you build more than 1 program
+ 2. Less memory if more than one copy of a program using the shared
+ library is running at the same time since the system is smart
+ enough to share copies of the shared library at run time.
+ 3. Possibly easier maintenance since a new version of the shared
+ library can be installed without relinking all the software
+ that uses it (as long as the subroutine names and calling
+ sequences remain unchanged).
+ 4. No run-time penalty.
+\end{verbatim}
+The disadvantages are:
+
+\begin{verbatim}
+ 1. More hassle at runtime. You have to either build the programs
+ specially or have LD_LIBRARY_PATH set right.
+ 2. There may be a slight start up penalty, depending on where you are
+ reading the shared library and the program from and if your CPU is
+ either really slow or really heavily loaded.
+\end{verbatim}
+
+On Mac OS X platforms the 'make shared' command works like on other
+UNIX platforms, but a .dylib file will be created instead of .so. If
+installed in a nonstandard location, add its location to the
+DYLD\_LIBRARY\_PATH environment variable so that the library can be found
+at run time.
+
+On HP/UX systems, the environment variable CFLAGS should be set
+to -Ae before running configure to enable "extended ANSI" features.
+
+By default, a set of Fortran-callable wrapper routines are
+also built and included in the CFITSIO library. If these wrapper
+routines are not needed (i.e., the CFITSIO library will not
+be linked to any Fortran applications which call FITSIO subroutines)
+then they may be omitted from the build by typing 'make all-nofitsio'
+instead of simply typing 'make'. This will reduce the size
+of the CFITSIO library slightly.
+
+Most 32-bit operating systems have only supported disk files up to 2.1GB
+(2**31 bytes) in size. Starting with version 2.1 of CFITSIO, FITS files
+larger than this limit (up to 6 terabytes) can be read and written on
+platforms that support large files (e.g., at least some LINUX platforms
+and Solaris). To enable this
+feature, CFITSIO must be compiled with the '-D\_LARGEFILE\_SOURCE' and
+`-D\_FILE\_OFFSET\_BITS=64'
+compiler flags. Some platforms may also require the `-D\_LARGE\_FILES'
+compiler flag. It appears that in most cases it is not necessary to
+also include these compiler flags when compiling programs that link to
+the CFITSIO library. See the `CFITSIO Size Limitations'
+section in Chapter 4 for further details.
+
+It may not be possible to staticly link programs that use CFITSIO on
+some platforms (namely, on Solaris 2.6) due to the network drivers
+(which provide FTP and HTTP access to FITS files). It is possible to
+make both a dynamic and a static version of the CFITSIO library, but
+network file access will not be possible using the static version.
+
+
+\subsection{VMS}
+
+On VAX/VMS and ALPHA/VMS systems the make\_gfloat.com command file may
+be executed to build the cfitsio.olb object library using the default
+G-floating point option for double variables. The make\_dfloat.com and
+make\_ieee.com files may be used instead to build the library with the
+other floating point options. Note that the getcwd function that is
+used in the group.c module may require that programs using CFITSIO be
+linked with the ALPHA\$LIBRARY:VAXCRTL.OLB library. See the example
+link line in the next section of this document.
+
+
+\subsection{Windows PCs}
+
+A precompiled DLL version of CFITSIO is available for IBM-PC users of
+the Borland or Microsoft Visual C++ compilers in the files
+cfitsiodll\_2xxx\_borland.zip and cfitsiodll\_2xxx\_vcc.zip, where
+'2xxx' represents the current release number. These zip archives also
+contains other files and instructions on how to use the CFITSIO DLL
+library.
+
+The CFITSIO library may also be built from the source code using the
+makefile.bc or makefile.vcc files. Finally, the makepc.bat file gives
+an example of building CFITSIO with the Borland C++ v4.5 compiler
+using older DOS commands.
+
+
+\subsection{Macintosh PCs}
+
+When building on Mac OS-X, users should follow the Unix instructions,
+above.
+
+The classic MacOS version (OS 9 or earlier) of the CFITSIO library can
+be built by (1) un binhex and unstuff cfitsio\_mac.sit.hqx, (2) put
+CFitsioPPC.mcp in the cfitsio directory, and (3) load CFitsioPPC.mcp
+into CodeWarrior Pro 5 and make. This builds the CFITSIO library for
+PPC. There are also targets for both the test program and the speed
+test program.
+
+To use the MacOS port you can add Cfitsio PPC.lib to your CodeWarrior
+Pro 5 project. Note that this only has been tested for the PPC and
+probably won't work on 68k Macs.
+
+
+
+\section{Testing the Library}
+
+The CFITSIO library should be tested by building and running
+the testprog.c program that is included with the release.
+On Unix systems, type:
+
+\begin{verbatim}
+ % make testprog
+ % testprog > testprog.lis
+ % diff testprog.lis testprog.out
+ % cmp testprog.fit testprog.std
+\end{verbatim}
+ On VMS systems,
+(assuming cc is the name of the C compiler command), type:
+
+\begin{verbatim}
+ $ cc testprog.c
+ $ link testprog, cfitsio/lib, alpha$library:vaxcrtl/lib
+ $ run testprog
+\end{verbatim}
+The test program should produce a FITS file called `testprog.fit'
+that is identical to the `testprog.std' FITS file included with this
+release. The diagnostic messages (which were piped to the file
+testprog.lis in the Unix example) should be identical to the listing
+contained in the file testprog.out. The 'diff' and 'cmp' commands
+shown above should not report any differences in the files. (There
+may be some minor format differences, such as the presence or
+absence of leading zeros, or 3 digit exponents in numbers,
+which can be ignored).
+
+The Fortran wrappers in CFITSIO may be tested with the testf77
+program on Unix systems with:
+
+\begin{verbatim}
+ % f77 -o testf77 testf77.f -L. -lcfitsio -lnsl -lsocket
+ or
+ % f77 -f -o testf77 testf77.f -L. -lcfitsio (under SUN O/S)
+ or
+ % f77 -o testf77 testf77.f -Wl,-L. -lcfitsio -lm -lnsl -lsocket (HP/UX)
+
+ % testf77 > testf77.lis
+ % diff testf77.lis testf77.out
+ % cmp testf77.fit testf77.std
+\end{verbatim}
+On machines running SUN O/S, Fortran programs must be compiled with the
+'-f' option to force double precision variables to be aligned on 8-byte
+boundarys to make the fortran-declared variables compatible with C. A
+similar compiler option may be required on other platforms. Failing to
+use this option may cause the program to crash on FITSIO routines that
+read or write double precision variables.
+
+Also note that on some systems, the output listing of the testf77
+program may differ slightly from the testf77.std template, if leading
+zeros are not printed by default before the decimal point when using F
+format.
+
+A few other utility programs are included with CFITSIO; the first four
+of this programs can be compiled an linked by typing `make
+program\_name' where `program\_name' is the actual name of the program:
+
+\begin{verbatim}
+ speed - measures the maximum throughput (in MB per second)
+ for writing and reading FITS files with CFITSIO.
+
+ listhead - lists all the header keywords in any FITS file
+
+ fitscopy - copies any FITS file (especially useful in conjunction
+ with the CFITSIO's extended input filename syntax).
+
+ cookbook - a sample program that performs common read and
+ write operations on a FITS file.
+
+ iter_a, iter_b, iter_c - examples of the CFITSIO iterator routine
+\end{verbatim}
+
+
+\section{Linking Programs with CFITSIO}
+
+When linking applications software with the CFITSIO library, several
+system libraries usually need to be specified on the link command
+line. On Unix systems, the most reliable way to determine what
+libraries are required is to type 'make testprog' and see what
+libraries the configure script has added. The typical libraries that
+need to be added are -lm (the math library) and -lnsl and -lsocket
+(needed only for FTP and HTTP file access). These latter 2 libraries
+are not needed on VMS and Windows platforms, because FTP file access is
+not currently supported on those platforms.
+
+Note that when upgrading to a newer version of CFITSIO it is usually
+necessary to recompile, as well as relink, the programs that use CFITSIO,
+because the definitions in fitsio.h often change.
+
+
+\section{Getting Started with CFITSIO}
+
+In order to effectively use the CFITSIO library it is recommended that
+new users begin by reading the ``CFITSIO Quick Start Guide''. It
+contains all the basic information needed to write programs that
+perform most types of operations on FITS files. The set of example
+FITS utility programs that are available from the CFITSIO web site are
+also very useful for learning how to use CFITSIO. To learn even more
+about the capabilities of the CFITSIO library the following steps are
+recommended:
+
+1. Read the following short `FITS Primer' chapter for an overview of
+the structure of FITS files.
+
+2. Review the Programming Guidelines in Chapter 4 to become familiar
+with the conventions used by the CFITSIO interface.
+
+3. Refer to the cookbook.c, listhead.c, and fitscopy.c programs that
+are included with this release for examples of routines that perform
+various common FITS file operations. Type 'make program\_name' to
+compile and link these programs on Unix systems.
+
+4. Write a simple program to read or write a FITS file using the Basic
+Interface routines described in Chapter 5.
+
+5. Scan through the more specialized routines that are described in
+the following chapters to become familiar with the functionality that
+they provide.
+
+
+\section{Example Program}
+
+The following listing shows an example of how to use the CFITSIO
+routines in a C program. Refer to the cookbook.c program that is
+included with the CFITSIO distribution for other example routines.
+
+This program creates a new FITS file, containing a FITS image. An
+`EXPOSURE' keyword is written to the header, then the image data are
+written to the FITS file before closing the FITS file.
+
+\begin{verbatim}
+#include "fitsio.h" /* required by every program that uses CFITSIO */
+main()
+{
+ fitsfile *fptr; /* pointer to the FITS file; defined in fitsio.h */
+ int status, ii, jj;
+ long fpixel = 1, naxis = 2, nelements, exposure;
+ long naxes[2] = { 300, 200 }; /* image is 300 pixels wide by 200 rows */
+ short array[200][300];
+
+ status = 0; /* initialize status before calling fitsio routines */
+ fits_create_file(&fptr, "testfile.fits", &status); /* create new file */
+
+ /* Create the primary array image (16-bit short integer pixels */
+ fits_create_img(fptr, SHORT_IMG, naxis, naxes, &status);
+
+ /* Write a keyword; must pass the ADDRESS of the value */
+ exposure = 1500.;
+ fits_update_key(fptr, TLONG, "EXPOSURE", &exposure,
+ "Total Exposure Time", &status);
+
+ /* Initialize the values in the image with a linear ramp function */
+ for (jj = 0; jj < naxes[1]; jj++)
+ for (ii = 0; ii < naxes[0]; ii++)
+ array[jj][ii] = ii + jj;
+
+ nelements = naxes[0] * naxes[1]; /* number of pixels to write */
+
+ /* Write the array of integers to the image */
+ fits_write_img(fptr, TSHORT, fpixel, nelements, array[0], &status);
+
+ fits_close_file(fptr, &status); /* close the file */
+
+ fits_report_error(stderr, status); /* print out any error messages */
+ return( status );
+}
+\end{verbatim}
+
+\chapter{ A FITS Primer }
+
+This section gives a brief overview of the structure of FITS files.
+Users should refer to the documentation available from the NOST, as
+described in the introduction, for more detailed information on FITS
+formats.
+
+FITS was first developed in the late 1970's as a standard data
+interchange format between various astronomical observatories. Since
+then FITS has become the standard data format supported by most
+astronomical data analysis software packages.
+
+A FITS file consists of one or more Header + Data Units (HDUs), where
+the first HDU is called the `Primary HDU', or `Primary Array'. The
+primary array contains an N-dimensional array of pixels, such as a 1-D
+spectrum, a 2-D image, or a 3-D data cube. Five different primary
+data types are supported: Unsigned 8-bit bytes, 16 and 32-bit signed
+integers, and 32 and 64-bit floating point reals. FITS also has a
+convention for storing 16 and 32-bit unsigned integers (see the later
+section entitled `Unsigned Integers' for more details). The primary HDU
+may also consist of only a header with a null array containing no
+data pixels.
+
+Any number of additional HDUs may follow the primary array; these
+additional HDUs are called FITS `extensions'. There are currently 3
+types of extensions defined by the FITS standard:
+
+\begin{itemize}
+\item
+ Image Extension - a N-dimensional array of pixels, like in a primary array
+\item
+ ASCII Table Extension - rows and columns of data in ASCII character format
+\item
+ Binary Table Extension - rows and columns of data in binary representation
+\end{itemize}
+
+In each case the HDU consists of an ASCII Header Unit followed by an optional
+Data Unit. For historical reasons, each Header or Data unit must be an
+exact multiple of 2880 8-bit bytes long. Any unused space is padded
+with fill characters (ASCII blanks or zeros).
+
+Each Header Unit consists of any number of 80-character keyword records
+or `card images' which have the
+general form:
+
+\begin{verbatim}
+ KEYNAME = value / comment string
+ NULLKEY = / comment: This keyword has no value
+\end{verbatim}
+The keyword names may be up to 8 characters long and can only contain
+uppercase letters, the digits 0-9, the hyphen, and the underscore
+character. The keyword name is (usually) followed by an equals sign and
+a space character (= ) in columns 9 - 10 of the record, followed by the
+value of the keyword which may be either an integer, a floating point
+number, a character string (enclosed in single quotes), or a boolean
+value (the letter T or F). A keyword may also have a null or undefined
+value if there is no specified value string, as in the second example, above
+
+The last keyword in the header is always the `END' keyword which has no
+value or comment fields. There are many rules governing the exact
+format of a keyword record (see the NOST FITS Standard) so it is better
+to rely on standard interface software like CFITSIO to correctly
+construct or to parse the keyword records rather than try to deal
+directly with the raw FITS formats.
+
+Each Header Unit begins with a series of required keywords which depend
+on the type of HDU. These required keywords specify the size and
+format of the following Data Unit. The header may contain other
+optional keywords to describe other aspects of the data, such as the
+units or scaling values. Other COMMENT or HISTORY keywords are also
+frequently added to further document the data file.
+
+The optional Data Unit immediately follows the last 2880-byte block in
+the Header Unit. Some HDUs do not have a Data Unit and only consist of
+the Header Unit.
+
+If there is more than one HDU in the FITS file, then the Header Unit of
+the next HDU immediately follows the last 2880-byte block of the
+previous Data Unit (or Header Unit if there is no Data Unit).
+
+The main required keywords in FITS primary arrays or image extensions are:
+\begin{itemize}
+\item
+BITPIX -- defines the data type of the array: 8, 16, 32, -32, -64 for
+unsigned 8--bit byte, 16--bit signed integer, 32--bit signed integer,
+32--bit IEEE floating point, and 64--bit IEEE double precision floating
+point, respectively.
+\item
+NAXIS -- the number of dimensions in the array, usually 0, 1, 2, 3, or 4.
+\item
+NAXISn -- (n ranges from 1 to NAXIS) defines the size of each dimension.
+\end{itemize}
+
+FITS tables start with the keyword XTENSION = `TABLE' (for ASCII
+tables) or XTENSION = `BINTABLE' (for binary tables) and have the
+following main keywords:
+\begin{itemize}
+\item
+TFIELDS -- number of fields or columns in the table
+\item
+NAXIS2 -- number of rows in the table
+\item
+TTYPEn -- for each column (n ranges from 1 to TFIELDS) gives the
+name of the column
+\item
+TFORMn -- the data type of the column
+\item
+TUNITn -- the physical units of the column (optional)
+\end{itemize}
+
+Users should refer to the FITS Support Office at {\tt http://fits.gsfc.nasa.gov}
+for futher information about the FITS format and related software
+packages.
+
+
+\chapter{ Programming Guidelines }
+
+
+\section{CFITSIO Definitions}
+
+Any program that uses the CFITSIO interface must include the fitsio.h
+header file with the statement
+
+\begin{verbatim}
+ #include "fitsio.h"
+\end{verbatim}
+This header file contains the prototypes for all the CFITSIO user
+interface routines as well as the definitions of various constants used
+in the interface. It also defines a C structure of type `fitsfile'
+that is used by CFITSIO to store the relevant parameters that define
+the format of a particular FITS file. Application programs must define
+a pointer to this structure for each FITS file that is to be opened.
+This structure is initialized (i.e., memory is allocated for the
+structure) when the FITS file is first opened or created with the
+fits\_open\_file or fits\_create\_file routines. This fitsfile pointer
+is then passed as the first argument to every other CFITSIO routine
+that operates on the FITS file. Application programs must not directly
+read or write elements in this fitsfile structure because the
+definition of the structure may change in future versions of CFITSIO.
+
+A number of symbolic constants are also defined in fitsio.h for the
+convenience of application programmers. Use of these symbolic
+constants rather than the actual numeric value will help to make the
+source code more readable and easier for others to understand.
+
+\begin{verbatim}
+String Lengths, for use when allocating character arrays:
+
+ #define FLEN_FILENAME 1025 /* max length of a filename */
+ #define FLEN_KEYWORD 72 /* max length of a keyword */
+ #define FLEN_CARD 81 /* max length of a FITS header card */
+ #define FLEN_VALUE 71 /* max length of a keyword value string */
+ #define FLEN_COMMENT 73 /* max length of a keyword comment string */
+ #define FLEN_ERRMSG 81 /* max length of a CFITSIO error message */
+ #define FLEN_STATUS 31 /* max length of a CFITSIO status text string */
+
+ Note that FLEN_KEYWORD is longer than the nominal 8-character keyword
+ name length because the HIERARCH convention supports longer keyword names.
+
+Access modes when opening a FITS file:
+
+ #define READONLY 0
+ #define READWRITE 1
+
+BITPIX data type code values for FITS images:
+
+ #define BYTE_IMG 8 /* 8-bit unsigned integers */
+ #define SHORT_IMG 16 /* 16-bit signed integers */
+ #define LONG_IMG 32 /* 32-bit signed integers */
+ #define FLOAT_IMG -32 /* 32-bit single precision floating point */
+ #define DOUBLE_IMG -64 /* 64-bit double precision floating point */
+
+ The following 4 data type codes are also supported by CFITSIO:
+ #define LONGLONG_IMG 64 /* 64-bit long signed integers */
+ #define SBYTE_IMG 10 /* 8-bit signed integers, equivalent to */
+ /* BITPIX = 8, BSCALE = 1, BZERO = -128 */
+ #define USHORT_IMG 20 /* 16-bit unsigned integers, equivalent to */
+ /* BITPIX = 16, BSCALE = 1, BZERO = 32768 */
+ #define ULONG_IMG 40 /* 32-bit unsigned integers, equivalent to */
+ /* BITPIX = 32, BSCALE = 1, BZERO = 2147483648 */
+
+Codes for the data type of binary table columns and/or for the
+data type of variables when reading or writing keywords or data:
+
+ DATATYPE TFORM CODE
+ #define TBIT 1 /* 'X' */
+ #define TBYTE 11 /* 8-bit unsigned byte, 'B' */
+ #define TLOGICAL 14 /* logicals (int for keywords */
+ /* and char for table cols 'L' */
+ #define TSTRING 16 /* ASCII string, 'A' */
+ #define TSHORT 21 /* signed short, 'I' */
+ #define TINT32BIT 41 /* signed 32-bit int, 'J' */
+ #define TLONG 41 /* signed long, */
+ #define TFLOAT 42 /* single precision float, 'E' */
+ #define TDOUBLE 82 /* double precision float, 'D' */
+ #define TCOMPLEX 83 /* complex (pair of floats) 'C' */
+ #define TDBLCOMPLEX 163 /* double complex (2 doubles) 'M' */
+
+ The following data type codes are also supported by CFITSIO:
+ #define TINT 31 /* int */
+ #define TSBYTE 12 /* 8-bit signed byte, 'S' */
+ #define TUINT 30 /* unsigned int 'V' */
+ #define TUSHORT 20 /* unsigned short 'U' */
+ #define TULONG 40 /* unsigned long */
+ #define TLONGLONG 81 /* 64-bit long signed integer 'K' */
+
+HDU type code values (value returned when moving to new HDU):
+
+ #define IMAGE_HDU 0 /* Primary Array or IMAGE HDU */
+ #define ASCII_TBL 1 /* ASCII table HDU */
+ #define BINARY_TBL 2 /* Binary table HDU */
+ #define ANY_HDU -1 /* matches any type of HDU */
+
+Column name and string matching case-sensitivity:
+
+ #define CASESEN 1 /* do case-sensitive string match */
+ #define CASEINSEN 0 /* do case-insensitive string match */
+
+Logical states (if TRUE and FALSE are not already defined):
+
+ #define TRUE 1
+ #define FALSE 0
+
+Values to represent undefined floating point numbers:
+
+ #define FLOATNULLVALUE -9.11912E-36F
+ #define DOUBLENULLVALUE -9.1191291391491E-36
+
+Image compression algorithm definitions
+
+ #define RICE_1 11
+ #define GZIP_1 21
+ #define PLIO_1 31
+\end{verbatim}
+
+
+\section{Current Header Data Unit (CHDU)}
+
+The concept of the Current Header and Data Unit, or CHDU, is
+fundamental to the use of the CFITSIO library. A simple FITS image may
+only contain a single Header and Data unit (HDU), but in general FITS
+files can contain multiple Header Data Units (also known as
+`extensions'), concatenated one after the other in the file. The user
+can specify which HDU should be initially opened at run time by giving
+the HDU name or number after the root file name. For example,
+'myfile.fits[4]' opens the 5th HDU in the file (note that the numbering
+starts with 0), and 'myfile.fits[EVENTS] opens the HDU with the name
+'EVENTS' (as defined by the EXTNAME or HDUNAME keywords). If no HDU is
+specified then CFITSIO opens the first HDU (the primary array) by
+default. The CFITSIO routines which read and write data only operate
+within the opened HDU, Other CFITSIO routines are provided to move to
+and open any other existing HDU within the FITS file or to append or
+insert new HDUs in the FITS file.
+
+
+\section{Function Names and Variable Datatypes}
+
+Most of the CFITSIO routines have both a short name as well as a
+longer descriptive name. The short name is only 5 or 6 characters long
+and is similar to the subroutine name in the Fortran-77 version of
+FITSIO. The longer name is more descriptive and it is recommended that
+it be used instead of the short name to more clearly document the
+source code.
+
+Many of the CFITSIO routines come in families which differ only in the
+data type of the associated parameter(s). The data type of these
+routines is indicated by the suffix of the routine name. The short
+routine names have a 1 or 2 character suffix (e.g., 'j' in 'ffpkyj')
+while the long routine names have a 4 character or longer suffix
+as shown in the following table:
+
+\begin{verbatim}
+ Long Short Data
+ Names Names Type
+ ----- ----- ----
+ _bit x bit
+ _byt b unsigned byte
+ _sbyt sb signed byte
+ _sht i short integer
+ _lng j long integer
+ _lnglng jj 8-byte LONGLONG integer (see note below)
+ _usht ui unsigned short integer
+ _ulng uj unsigned long integer
+ _uint uk unsigned int integer
+ _int k int integer
+ _flt e real exponential floating point (float)
+ _fixflt f real fixed-decimal format floating point (float)
+ _dbl d double precision real floating-point (double)
+ _fixdbl g double precision fixed-format floating point (double)
+ _cmp c complex reals (pairs of float values)
+ _fixcmp fc complex reals, fixed-format floating point
+ _dblcmp m double precision complex (pairs of double values)
+ _fixdblcmp fm double precision complex, fixed-format floating point
+ _log l logical (int)
+ _str s character string
+\end{verbatim}
+
+The logical data type corresponds to `int' for logical keyword values,
+and `byte' for logical binary table columns. In other words, the value
+when writing a logical keyword must be stored in an `int' variable, and
+must be stored in a `char' array when reading or writing to `L' columns
+in a binary table. Inplicit data type conversion is not supported for
+logical table columns, but is for keywords, so a logical keyword may be
+read and cast to any numerical data type; a returned value = 0
+indicates false, and any other value = true.
+
+The `int' data type may be 2 bytes long on some IBM PC compatible
+systems and is usually 4 bytes long on most other systems. Some 64-bit
+machines, however, like the Dec Alpha/OSF, define the `short', `int',
+and `long' integer data types to be 2, 4, and 8 bytes long,
+respectively. The FITS standard only supports 2 and 4 byte integer
+data types, so CFITSIO internally converts between 4 and 8 bytes when
+reading or writing `long' integers on Alpha/OSF systems.
+
+The 8-byte 'LONGLONG' integer data type is supported on most platforms.
+CFITSIO defines the LONGLONG data type to be equivalent to 'long long'
+on most Unix platforms and on Mac OS-X. Since most Windows compilers don't
+support the 'long long' data type, LONGLONG is defined instead to be
+equivalent to '\_\_int64'. If the compiler does not support a 8-byte
+integer data type then LONGLONG is defined to be equivalent to 'long'.
+Note that the C format specifier to print out these long integer values
+is "\%lld" on most unix machines, except on OSF platforms where "\%ld"
+must be used. On Windows platform that have the \_\_int64 data type,
+the format specifier is "\%INT64d".
+
+When dealing with the FITS byte data type it is important to remember
+that the raw values (before any scaling by the BSCALE and BZERO, or
+TSCALn and TZEROn keyword values) in byte arrays (BITPIX = 8) or byte
+columns (TFORMn = 'B') are interpreted as unsigned bytes with values
+ranging from 0 to 255. Some C compilers define a 'char' variable as
+signed, so it is important to explicitly declare a numeric char
+variable as 'unsigned char' to avoid any ambiguity
+
+One feature of the CFITSIO routines is that they can operate on a `X'
+(bit) column in a binary table as though it were a `B' (byte) column.
+For example a `11X' data type column can be interpreted the same as a
+`2B' column (i.e., 2 unsigned 8-bit bytes). In some instances, it can
+be more efficient to read and write whole bytes at a time, rather than
+reading or writing each individual bit.
+
+The complex and double precision complex data types are not directly
+supported in ANSI C so these data types should be interpreted as pairs
+of float or double values, respectively, where the first value in each
+pair is the real part, and the second is the imaginary part.
+
+
+\section{Support for Unsigned Integers and Signed Bytes}
+
+Although FITS does not directly support unsigned integers as one of its
+fundamental data types, FITS can still be used to efficiently store
+unsigned integer data values in images and binary tables. The
+convention used in FITS files is to store the unsigned integers as
+signed integers with an associated offset (specified by the BZERO or
+TZEROn keyword). For example, to store unsigned 16-bit integer values
+in a FITS image the image would be defined as a signed 16-bit integer
+(with BITPIX keyword = SHORT\_IMG = 16) with the keywords BSCALE = 1.0
+and BZERO = 32768. Thus the unsigned values of 0, 32768, and 65535,
+for example, are physically stored in the FITS image as -32768, 0, and
+32767, respectively; CFITSIO automatically adds the BZERO offset to
+these values when they are read. Similarly, in the case of unsigned
+32-bit integers the BITPIX keyword would be equal to LONG\_IMG = 32 and
+BZERO would be equal to 2147483648 (i.e. 2 raised to the 31st power).
+
+The CFITSIO interface routines will efficiently and transparently apply
+the appropriate offset in these cases so in general application
+programs do not need to be concerned with how the unsigned values are
+actually stored in the FITS file. As a convenience for users, CFITSIO
+has several predefined constants for the value of BITPIX (USHORT\_IMG,
+ULONG\_IMG) and for the TFORMn value in the case of binary tables (`U'
+and `V') which programmers can use when creating FITS files containing
+unsigned integer values. The following code fragment illustrates how
+to write a FITS 1-D primary array of unsigned 16-bit integers:
+
+\begin{verbatim}
+ unsigned short uarray[100];
+ int naxis, status;
+ long naxes[10], group, firstelem, nelements;
+ ...
+ status = 0;
+ naxis = 1;
+ naxes[0] = 100;
+ fits_create_img(fptr, USHORT_IMG, naxis, naxes, &status);
+
+ firstelem = 1;
+ nelements = 100;
+ fits_write_img(fptr, TUSHORT, firstelem, nelements,
+ uarray, &status);
+ ...
+\end{verbatim}
+In the above example, the 2nd parameter in fits\_create\_img tells
+CFITSIO to write the header keywords appropriate for an array of 16-bit
+unsigned integers (i.e., BITPIX = 16 and BZERO = 32768). Then the
+fits\_write\_img routine writes the array of unsigned short integers
+(uarray) into the primary array of the FITS file. Similarly, a 32-bit
+unsigned integer image may be created by setting the second parameter
+in fits\_create\_img equal to `ULONG\_IMG' and by calling the
+fits\_write\_img routine with the second parameter = TULONG to write
+the array of unsigned long image pixel values.
+
+An analogous set of routines are available for reading or writing unsigned
+integer values and signed byte values in a FITS binary table extension.
+When specifying the TFORMn keyword value which defines the format of a
+column, CFITSIO recognized 3 additional data type codes besides those
+already defined in the FITS standard: `U' meaning a 16-bit unsigned
+integer column, `V' for a 32-bit unsigned integer column, and 'S'
+for a signed byte column. These non-standard data type codes are not
+actually written into the FITS file but instead are just used internally
+within CFITSIO. The following code fragment illustrates how to use
+these features:
+
+\begin{verbatim}
+ unsigned short uarray[100];
+ unsigned int varray[100];
+
+ int colnum, tfields, status;
+ long nrows, firstrow, firstelem, nelements, pcount;
+
+ char extname[] = "Test_table"; /* extension name */
+
+ /* define the name, data type, and physical units for the 2 columns */
+ char *ttype[] = { "Col_1", "Col_2", "Col_3" };
+ char *tform[] = { "1U", "1V", "1S"}; /* special CFITSIO codes */
+ char *tunit[] = { " ", " ", " " };
+ ...
+
+ /* write the header keywords */
+ status = 0;
+ nrows = 1;
+ tfields = 3
+ pcount = 0;
+ fits_create_tbl(fptr, BINARY_TBL, nrows, tfields, ttype, tform,
+ tunit, extname, &status);
+
+ /* write the unsigned shorts to the 1st column */
+ colnum = 1;
+ firstrow = 1;
+ firstelem = 1;
+ nelements = 100;
+ fits_write_col(fptr, TUSHORT, colnum, firstrow, firstelem,
+ nelements, uarray, &status);
+
+ /* now write the unsigned longs to the 2nd column */
+ colnum = 2;
+ fits_write_col(fptr, TUINT, colnum, firstrow, firstelem,
+ nelements, varray, &status);
+ ...
+\end{verbatim}
+Note that the non-standard TFORM values for the 3 columns, `U' and `V',
+tell CFITSIO to write the keywords appropriate for unsigned 16-bit and
+unsigned 32-bit integers, respectively (i.e., TFORMn = '1I' and TZEROn
+= 32678 for unsigned 16-bit integers, and TFORMn = '1J' and TZEROn =
+2147483648 for unsigned 32-bit integers). The 'S' TFORMn value tells
+CFITSIO to write the keywords appropriate for a signed 8-bit byte column
+with TFORMn = '1B' and TZEROn = -128. The calls to fits\_write\_col
+then write the arrays of unsigned integer values to the columns.
+
+
+\section{Dealing with Character Strings}
+
+The character string values in a FITS header or in an ASCII column in a
+FITS table extension are generally padded out with non-significant
+space characters (ASCII 32) to fill up the header record or the column
+width. When reading a FITS string value, the CFITSIO routines will
+strip off these non-significant trailing spaces and will return a
+null-terminated string value containing only the significant
+characters. Leading spaces in a FITS string are considered
+significant. If the string contains all blanks, then CFITSIO will
+return a single blank character, i.e, the first blank is considered to
+be significant, since it distinguishes the string from a null or
+undefined string, but the remaining trailing spaces are not
+significant.
+
+Similarly, when writing string values to a FITS file the
+CFITSIO routines expect to get a null-terminated string as input;
+CFITSIO will pad the string with blanks if necessary when writing it
+to the FITS file.
+
+When calling CFITSIO routines that return a character string it is
+vital that the size of the char array be large enough to hold the
+entire string of characters, otherwise CFITSIO will overwrite whatever
+memory locations follow the char array, possibly causing the program to
+execute incorrectly. This type of error can be difficult to debug, so
+programmers should always ensure that the char arrays are allocated
+enough space to hold the longest possible string, {\bf including} the
+terminating NULL character. The fitsio.h file contains the following
+defined constants which programmers are strongly encouraged to use
+whenever they are allocating space for char arrays:
+
+\begin{verbatim}
+#define FLEN_FILENAME 1025 /* max length of a filename */
+#define FLEN_KEYWORD 72 /* max length of a keyword */
+#define FLEN_CARD 81 /* length of a FITS header card */
+#define FLEN_VALUE 71 /* max length of a keyword value string */
+#define FLEN_COMMENT 73 /* max length of a keyword comment string */
+#define FLEN_ERRMSG 81 /* max length of a CFITSIO error message */
+#define FLEN_STATUS 31 /* max length of a CFITSIO status text string */
+\end{verbatim}
+For example, when declaring a char array to hold the value string
+of FITS keyword, use the following statement:
+
+\begin{verbatim}
+ char value[FLEN_VALUE];
+\end{verbatim}
+Note that FLEN\_KEYWORD is longer than needed for the nominal 8-character
+keyword name because the HIERARCH convention supports longer keyword names.
+
+
+\section{Implicit Data Type Conversion}
+
+The CFITSIO routines that read and write numerical data can perform
+implicit data type conversion. This means that the data type of the
+variable or array in the program does not need to be the same as the
+data type of the value in the FITS file. Data type conversion is
+supported for numerical and string data types (if the string contains a
+valid number enclosed in quotes) when reading a FITS header keyword
+value and for numeric values when reading or writing values in the
+primary array or a table column. CFITSIO returns status =
+NUM\_OVERFLOW if the converted data value exceeds the range of the
+output data type. Implicit data type conversion is not supported
+within binary tables for string, logical, complex, or double complex
+data types.
+
+In addition, any table column may be read as if it contained string values.
+In the case of numeric columns the returned string will be formatted
+using the TDISPn display format if it exists.
+
+
+\section{Data Scaling}
+
+When reading numerical data values in the primary array or a
+table column, the values will be scaled automatically by the BSCALE and
+BZERO (or TSCALn and TZEROn) header values if they are
+present in the header. The scaled data that is returned to the reading
+program will have
+
+\begin{verbatim}
+ output value = (FITS value) * BSCALE + BZERO
+\end{verbatim}
+(a corresponding formula using TSCALn and TZEROn is used when reading
+from table columns). In the case of integer output values the floating
+point scaled value is truncated to an integer (not rounded to the
+nearest integer). The fits\_set\_bscale and fits\_set\_tscale routines
+(described in the `Advanced' chapter) may be used to override the
+scaling parameters defined in the header (e.g., to turn off the scaling
+so that the program can read the raw unscaled values from the FITS
+file).
+
+When writing numerical data to the primary array or to a table column
+the data values will generally be automatically inversely scaled by the
+value of the BSCALE and BZERO (or TSCALn and TZEROn) keyword values if
+they they exist in the header. These keywords must have been written
+to the header before any data is written for them to have any immediate
+effect. One may also use the fits\_set\_bscale and fits\_set\_tscale
+routines to define or override the scaling keywords in the header
+(e.g., to turn off the scaling so that the program can write the raw
+unscaled values into the FITS file). If scaling is performed, the
+inverse scaled output value that is written into the FITS file will
+have
+
+\begin{verbatim}
+ FITS value = ((input value) - BZERO) / BSCALE
+\end{verbatim}
+(a corresponding formula using TSCALn and TZEROn is used when
+writing to table columns). Rounding to the nearest integer, rather
+than truncation, is performed when writing integer data types to the
+FITS file.
+
+
+\section{Support for IEEE Special Values}
+
+The ANSI/IEEE-754 floating-point number standard defines certain
+special values that are used to represent such quantities as
+Not-a-Number (NaN), denormalized, underflow, overflow, and infinity.
+(See the Appendix in the NOST FITS standard or the NOST FITS User's
+Guide for a list of these values). The CFITSIO routines that read
+floating point data in FITS files recognize these IEEE special values
+and by default interpret the overflow and infinity values as being
+equivalent to a NaN, and convert the underflow and denormalized values
+into zeros. In some cases programmers may want access to the raw IEEE
+values, without any modification by CFITSIO. This can be done by
+calling the fits\_read\_img or fits\_read\_col routines while
+specifying 0.0 as the value of the NULLVAL parameter. This will force
+CFITSIO to simply pass the IEEE values through to the application
+program without any modification. This is not fully supported on
+VAX/VMS machines, however, where there is no easy way to bypass the
+default interpretation of the IEEE special values.
+
+
+\section{Error Status Values and the Error Message Stack}
+
+Nearly all the CFITSIO routines return an error status value
+in 2 ways: as the value of the last parameter in the function call,
+and as the returned value of the function itself. This provides
+some flexibility in the way programmers can test if an error
+occurred, as illustrated in the following 2 code fragments:
+
+\begin{verbatim}
+ if ( fits_write_record(fptr, card, &status) )
+ printf(" Error occurred while writing keyword.");
+
+or,
+
+ fits_write_record(fptr, card, &status);
+ if ( status )
+ printf(" Error occurred while writing keyword.");
+\end{verbatim}
+A listing of all the CFITSIO status code values is given at the end of
+this document. Programmers are encouraged to use the symbolic
+mnemonics (defined in fitsio.h) rather than the actual integer status
+values to improve the readability of their code.
+
+The CFITSIO library uses an `inherited status' convention for the
+status parameter which means that if a routine is called with a
+positive input value of the status parameter as input, then the routine
+will exit immediately without changing the value of the status
+parameter. Thus, if one passes the status value returned from each
+CFITSIO routine as input to the next CFITSIO routine, then whenever an
+error is detected all further CFITSIO processing will cease. This
+convention can simplify the error checking in application programs
+because it is not necessary to check the value of the status parameter
+after every single CFITSIO routine call. If a program contains a
+sequence of several CFITSIO calls, one can just check the status value
+after the last call. Since the returned status values are generally
+distinctive, it should be possible to determine which routine
+originally returned the error status.
+
+CFITSIO also maintains an internal stack of error messages
+(80-character maximum length) which in many cases provide a more
+detailed explanation of the cause of the error than is provided by the
+error status number alone. It is recommended that the error message
+stack be printed out whenever a program detects a CFITSIO error. The
+function fits\_report\_error will print out the entire error message
+stack, or alternatively one may call fits\_read\_errmsg to get the
+error messages one at a time.
+
+
+\section{Variable-Length Arrays in Binary Tables}
+
+CFITSIO provides easy-to-use support for reading and writing data in
+variable length fields of a binary table. The variable length columns
+have TFORMn keyword values of the form `1Pt(len)' where `t' is the
+data type code (e.g., I, J, E, D, etc.) and `len' is an integer
+specifying the maximum length of the vector in the table. If the value
+of `len' is not specified when the table is created (e.g., if the TFORM
+keyword value is simply specified as '1PE' instead of '1PE(400) ), then
+CFITSIO will automatically scan the table when it is closed to
+determine the maximum length of the vector and will append this value
+to the TFORMn value.
+
+The same routines that read and write data in an ordinary fixed length
+binary table extension are also used for variable length fields,
+however, the routine parameters take on a slightly different
+interpretation as described below.
+
+All the data in a variable length field is written into an area called
+the `heap' which follows the main fixed-length FITS binary table. The
+size of the heap, in bytes, is specified by the PCOUNT keyword in the
+FITS header. When creating a new binary table, the initial value of
+PCOUNT should usually be set to zero. CFITSIO will recompute the size
+of the heap as the data is written and will automatically update the
+PCOUNT keyword value when the table is closed. When writing variable
+length data to a table, CFITSIO will automatically extend the size
+of the heap area if necessary, so that any following HDUs do not
+get overwritten.
+
+By default the heap data area starts immediately after the last row of
+the fixed-length table. This default starting location may be
+overridden by the THEAP keyword, but this is not recommended.
+If additional rows of data are added to the table, CFITSIO will
+automatically shift the the heap down to make room for the new
+rows, but it is obviously be more efficient to initially
+create the table with the necessary number of blank rows, so that
+the heap does not needed to be constantly moved.
+
+When writing to a variable length field the entire array of values for
+a given row of the table must be written with a single call to
+fits\_write\_col. The total length of the array is given by nelements
++ firstelem - 1. Additional elements cannot be appended to an existing
+vector at a later time since any attempt to do so will simply overwrite
+all the previously written data. Note also that the new data will be
+written to a new area of the heap and the heap space used by the
+previous write cannot be reclaimed. For this reason each row of a
+variable length field should only be written once. An exception to
+this general rule occurs when setting elements of an array as
+undefined. One must first write a dummy value into the array with
+fits\_write\_col, and then call fits\_write\_col\_nul to flag the
+desired elements as undefined. (Do not use the fits\_write\_colnull
+routines with variable length fields). Note that the rows of a table,
+whether fixed or variable length, do not have to be written
+consecutively and may be written in any order.
+
+When writing to a variable length ASCII character field (e.g., TFORM =
+'1PA') only a single character string can be written. The `firstelem'
+and `nelements' parameter values in the fits\_write\_col routine are
+ignored and the number of characters to write is simply determined by
+the length of the input null-terminated character string.
+
+The fits\_write\_descript routine is useful in situations where
+multiple rows of a variable length column have the identical array of
+values. One can simply write the array once for the first row, and
+then use fits\_write\_descript to write the same descriptor values into
+the other rows; all the rows will then point to the same storage
+location thus saving disk space.
+
+When reading from a variable length array field one can only read as
+many elements as actually exist in that row of the table; reading does
+not automatically continue with the next row of the table as occurs
+when reading an ordinary fixed length table field. Attempts to read
+more than this will cause an error status to be returned. One can
+determine the number of elements in each row of a variable column with
+the fits\_read\_descript routine.
+
+
+\section{Multiple Access to the Same FITS File}
+
+CFITSIO supports simultaneous read and write access to multiple HDUs in
+the same FITS file. Thus, one can open the same FITS file twice within
+a single program and move to 2 different HDUs in the file, and then
+read and write data or keywords to the 2 extensions just as if one were
+accessing 2 completely separate FITS files. Since in general it is
+not possible to physically open the same file twice and then expect to
+be able to simultaneously (or in alternating succession) write to 2
+different locations in the file, CFITSIO recognizes when the file to be
+opened (in the call to fits\_open\_file) has already been opened and
+instead of actually opening the file again, just logically links the
+new file to the old file. (This only applies if the file is opened
+more than once within the same program, and does not prevent the same
+file from being simultaneously opened by more than one program). Then
+before CFITSIO reads or writes to either (logical) file, it makes sure
+that any modifications made to the other file have been completely
+flushed from the internal buffers to the file. Thus, in principle, one
+could open a file twice, in one case pointing to the first extension
+and in the other pointing to the 2nd extension and then write data to
+both extensions, in any order, without danger of corrupting the file,
+There may be some efficiency penalties in doing this however, since
+CFITSIO has to flush all the internal buffers related to one file
+before switching to the other, so it would still be prudent to
+minimize the number of times one switches back and forth between doing
+I/O to different HDUs in the same file.
+
+
+\section{When the Final Size of the FITS HDU is Unknown}
+
+It is not required to know the total size of a FITS data array or table
+before beginning to write the data to the FITS file. In the case of
+the primary array or an image extension, one should initially create
+the array with the size of the highest dimension (largest NAXISn
+keyword) set to a dummy value, such as 1. Then after all the data have
+been written and the true dimensions are known, then the NAXISn value
+should be updated using the fits\_update\_key routine before moving to
+another extension or closing the FITS file.
+
+When writing to FITS tables, CFITSIO automatically keeps track of the
+highest row number that is written to, and will increase the size of
+the table if necessary. CFITSIO will also automatically insert space
+in the FITS file if necessary, to ensure that the data 'heap', if it
+exists, and/or any additional HDUs that follow the table do not get
+overwritten as new rows are written to the table.
+
+As a general rule it is best to specify the initial number of rows = 0
+when the table is created, then let CFITSIO keep track of the number of
+rows that are actually written. The application program should not
+manually update the number of rows in the table (as given by the NAXIS2
+keyword) since CFITSIO does this automatically. If a table is
+initially created with more than zero rows, then this will usually be
+considered as the minimum size of the table, even if fewer rows are
+actually written to the table. Thus, if a table is initially created
+with NAXIS2 = 20, and CFITSIO only writes 10 rows of data before
+closing the table, then NAXIS2 will remain equal to 20. If however, 30
+rows of data are written to this table, then NAXIS2 will be increased
+from 20 to 30. The one exception to this automatic updating of the
+NAXIS2 keyword is if the application program directly modifies the
+value of NAXIS2 (up or down) itself just before closing the table. In this
+case, CFITSIO does not update NAXIS2 again, since it assumes that the
+application program must have had a good reason for changing the value
+directly. This is not recommended, however, and is only provided for
+backward compatibility with software that initially creates a table
+with a large number of rows, than decreases the NAXIS2 value to the
+actual smaller value just before closing the table.
+
+
+\section{CFITSIO Size Limitations}
+
+CFITSIO places very few restrictions on the size of FITS files that it
+reads or writes. There are a few limits, however, that may affect
+some extreme cases:
+
+1. The maximum number of FITS files that may be simultaneously opened
+by CFITSIO is set by NMAXFILES as defined in fitsio2.h. It is currently
+set = 300 by default. CFITSIO will allocate about 80 * NMAXFILES bytes
+of memory for internal use. Note that the underlying C compiler or
+operating system, may have a smaller limit on the number of opened files.
+The C symbolic constant FOPEN\_MAX is intended to define the maximum
+number of files that may open at once (including any other text or
+binary files that may be open, not just FITS files). On some systems it
+has been found that gcc supports a maximum of 255 opened files.
+
+Note that opening and operating on many FITS files simultaneously in
+parallel may be less efficient than operating on smaller groups of files
+in series. CFITSIO only has NIOBUF number of internal buffers (set = 40
+by default) that are used for temporary storage of the most recent data
+records that have been read or written in the FITS files. If the number
+of opened files is greater than NIOBUF, then CFITSIO may waste more time
+flushing and re-reading or re-writing the same records in the FITS files.
+
+2. By default, CFITSIO can handle FITS files up to 2.1 GB in size (2**31
+bytes). This file size limit is often imposed by 32-bit operating
+systems. More recently, as 64-bit operating systems become more common, an
+industry-wide standard (at least on Unix systems) has been developed to
+support larger sized files (see http://ftp.sas.com/standards/large.file/).
+Starting with version 2.1 of CFITSIO, larger FITS files up to 6 terabytes
+in size may be read and written on supported platforms. In order
+to support these larger files, CFITSIO must be compiled with the
+'-D\_LARGEFILE\_SOURCE' and `-D\_FILE\_OFFSET\_BITS=64' compiler flags.
+Some platforms may also require the `-D\_LARGE\_FILES' compiler flag.
+ This causes the compiler to allocate 8-bytes instead of
+4-bytes for the `off\_t' data type that is used to store file offset
+positions. It appears that in most cases it is not necessary to
+also include these compiler flags when compiling programs that link to
+the CFITSIO library.
+
+If CFITSIO is compiled with the -D\_LARGEFILE\_SOURCE
+and -D\_FILE\_OFFSET\_BITS=64 flags on a
+platform that supports large files, then it can read and write FITS
+files that contain up to 2**31 2880-byte FITS records, or approximately
+6 terabytes in size. It is still required that the value of the NAXISn
+and PCOUNT keywords in each extension be within the range of a signed
+4-byte integer (max value = 2,147,483,648). Thus, each dimension of an
+image (given by the NAXISn keywords), the total width of a table
+(NAXIS1 keyword), the number of rows in a table (NAXIS2 keyword), and
+the total size of the variable-length array heap in binary tables
+(PCOUNT keyword) must be less than this limit.
+
+Currently, support for large files within CFITSIO has been tested
+on the Linux, Solaris, and IBM AIX operating systems.
+
+\chapter{Basic CFITSIO Interface Routines }
+
+This chapter describes the basic routines in the CFITSIO user interface
+that provide all the functions normally needed to read and write most
+FITS files. It is recommended that these routines be used for most
+applications and that the more advanced routines described in the
+next chapter only be used in special circumstances when necessary.
+
+The following conventions are used in this chapter in the description
+of each function:
+
+1. Most functions have 2 names: a long descriptive name and a short
+concise name. Both names are listed on the first line of the following
+descriptions, separated by a slash (/) character. Programmers may use
+either name in their programs but the long names are recommended to
+help document the code and make it easier to read.
+
+2. A right arrow symbol ($>$) is used in the function descriptions to
+separate the input parameters from the output parameters in the
+definition of each routine. This symbol is not actually part of the C
+calling sequence.
+
+3. The function parameters are defined in more detail in the
+alphabetical listing in Appendix B.
+
+4. The first argument in almost all the functions is a pointer to a
+structure of type `fitsfile'. Memory for this structure is allocated
+by CFITSIO when the FITS file is first opened or created and is freed
+when the FITS file is closed.
+
+5. The last argument in almost all the functions is the error status
+parameter. It must be equal to 0 on input, otherwise the function will
+immediately exit without doing anything. A non-zero output value
+indicates that an error occurred in the function. In most cases the
+status value is also returned as the value of the function itself.
+
+
+\section{CFITSIO Error Status Routines}
+
+
+\begin{description}
+\item[1 ] Return a descriptive text string (30 char max.) corresponding to
+ a CFITSIO error status code.\label{ffgerr}
+\end{description}
+
+\begin{verbatim}
+ void fits_get_errstatus / ffgerr (int status, > char *err_text)
+\end{verbatim}
+
+\begin{description}
+\item[2 ] Return the top (oldest) 80-character error message from the
+ internal CFITSIO stack of error messages and shift any remaining
+ messages on the stack up one level. Call this routine
+ repeatedly to get each message in sequence. The function returns
+ a value = 0 and a null error message when the error stack is empty.
+\label{ffgmsg}
+\end{description}
+
+\begin{verbatim}
+ int fits_read_errmsg / ffgmsg (char *err_msg)
+\end{verbatim}
+
+\begin{description}
+\item[3 ] Print out the error message corresponding to the input status
+ value and all the error messages on the CFITSIO stack to the specified
+ file stream (normally to stdout or stderr). If the input
+ status value = 0 then this routine does nothing.
+\label{ffrprt}
+\end{description}
+
+\begin{verbatim}
+ void fits_report_error / ffrprt (FILE *stream, > status)
+\end{verbatim}
+
+\begin{description}
+\item[4 ]The fits\_write\_errmark routine puts an invisible marker on the
+ CFITSIO error stack. The fits\_clear\_errmark routine can then be
+ used to delete any more recent error messages on the stack, back to
+ the position of the marker. This preserves any older error messages
+ on the stack. The fits\_clear\_errmsg routine simply clears all the
+ messages (and marks) from the stack. These routines are called
+ without any arguments.
+\label{ffpmrk} \label{ffcmsg}
+\end{description}
+
+\begin{verbatim}
+ void fits_write_errmark / ffpmrk (void)
+ void fits_clear_errmark / ffcmrk (void)
+ void fits_clear_errmsg / ffcmsg (void)
+\end{verbatim}
+
+
+\section{FITS File Access Routines}
+
+
+\begin{description}
+\item[1 ] Open an existing data file. \label{ffopen}
+
+
+\begin{verbatim}
+int fits_open_file / ffopen
+ (fitsfile **fptr, char *filename, int iomode, > int *status)
+
+int fits_open_diskfile / ffdkopen
+ (fitsfile **fptr, char *filename, int iomode, > int *status)
+
+int fits_open_data / ffdopn
+ (fitsfile **fptr, char *filename, int iomode, > int *status)
+
+int fits_open_table / fftopn
+ (fitsfile **fptr, char *filename, int iomode, > int *status)
+
+int fits_open_image / ffiopn
+ (fitsfile **fptr, char *filename, int iomode, > int *status)
+\end{verbatim}
+
+The iomode parameter determines the read/write access allowed in the
+file and can have values of READONLY (0) or READWRITE (1). The filename
+parameter gives the name of the file to be opened, followed by an
+optional argument giving the name or index number of the extension
+within the FITS file that should be moved to and opened (e.g.,
+\verb-myfile.fits+3- or \verb-myfile.fits[3]- moves to the 3rd extension within
+the file, and \verb-myfile.fits[events]- moves to the extension with the
+keyword EXTNAME = 'EVENTS').
+
+The fits\_open\_diskfile routine is similar to the fits\_open\_file routine
+except that it does not support the extended filename syntax in the input
+file name. This routine simply tries to open the specified input file
+on magnetic disk. This routine is mainly for use in cases where the
+filename (or directory path) contains square or curly bracket characters
+that would confuse the extended filename parser.
+
+The fits\_open\_data routine is similar to the fits\_open\_file routine
+except that it will move to the first HDU containing significant data,
+if a HDU name or number to open was not explicitly specified as
+part of the filename. In this case, it will look for the first
+IMAGE HDU with NAXIS > 0, or the first table that does not contain the
+strings `GTI' (Good Time Interval extension) or `OBSTABLE' in the
+EXTNAME keyword value.
+
+The fits\_open\_table and fits\_open\_image routines are similar to
+fits\_open\_data except they will move to the first significant table
+HDU or image HDU in the file, respectively, if a HDU name or
+number is not specified as part of the filename.
+
+IRAF images (.imh format files) and raw binary data arrays may also be
+opened with READONLY access. CFITSIO will automatically test if the
+input file is an IRAF image, and if, so will convert it on the fly into
+a virtual FITS image before it is opened by the application program.
+If the input file is a raw binary data array of numbers, then the data type
+and dimensions of the array must be specified in square brackets
+following the name of the file (e.g. 'rawfile.dat[i512,512]' opens a
+512 x 512 short integer image). See the `Extended File Name Syntax'
+chapter for more details on how to specify the raw file name. The raw
+file is converted on the fly into a virtual FITS image in memory that
+is then opened by the application program with READONLY access.
+
+Programs can read the input file from the 'stdin' file stream if a dash
+character ('-') is given as the filename. Files can also be opened over
+the network using FTP or HTTP protocols by supplying the appropriate URL
+as the filename.
+
+The input file can be modified in various ways to create a virtual file
+(usually stored in memory) that is then opened by the application
+program by supplying a filtering or binning specifier in square brackets
+following the filename. Some of the more common filtering methods are
+illustrated in the following paragraphs, but users should refer to the
+'Extended File Name Syntax' chapter for a complete description of
+the full file filtering syntax.
+
+When opening an image, a rectangular subset of the physical image may be
+opened by listing the first and last pixel in each dimension (and
+optional pixel skipping factor):
+
+\begin{verbatim}
+myimage.fits[101:200,301:400]
+\end{verbatim}
+will create and open a 100x100 pixel virtual image of that section of
+the physical image, and \verb+myimage.fits[*,-*]+ opens a virtual image
+that is the same size as the physical image but has been flipped in
+the vertical direction.
+
+When opening a table, the filtering syntax can be used to add or delete
+columns or keywords in the virtual table:
+\verb-myfile.fits[events][col !time; PI = PHA*1.2]- opens a virtual table in which the TIME column
+has been deleted and a new PI column has been added with a value 1.2
+times that of the PHA column. Similarly, one can filter a table to keep
+only those rows that satisfy a selection criterion:
+\verb-myfile.fits[events][pha > 50]- creates and opens a virtual table
+containing only those rows with a PHA value greater than 50. A large
+number of boolean and mathematical operators can be used in the
+selection expression. One can also filter table rows using 'Good Time
+Interval' extensions, and spatial region filters as in
+\verb-myfile.fits[events][gtifilter()]- and
+\verb-myfile.fits[events][regfilter( "stars.rng")]-.
+
+Finally, table columns may be binned or histogrammed to generate a
+virtual image. For example, \verb-myfile.fits[events][bin (X,Y)=4]- will
+result in a 2-dimensional image calculated by binning the X and Y
+columns in the event table with a bin size of 4 in each dimension. The
+TLMINn and TLMAXn keywords will be used by default to determine the
+range of the image.
+
+A single program can open the same FITS file more than once and then
+treat the resulting fitsfile pointers as though they were completely
+independent FITS files. Using this facility, a program can open a FITS
+file twice, move to 2 different extensions within the file, and then
+ read and write data in those extensions in any order.
+\end{description}
+
+
+\begin{description}
+\item[2 ] Create and open a new empty output FITS file. \label{ffinit}
+
+
+\begin{verbatim}
+int fits_create_file / ffinit
+ (fitsfile **fptr, char *filename, > int *status)
+
+int fits_create_diskfile / ffdkinit
+ (fitsfile **fptr, char *filename, > int *status)
+\end{verbatim}
+
+An error will be returned if the specified file already exists, unless
+the filename is prefixed with an exclamation point (!). In that case
+CFITSIO will overwrite (delete) any existing file with the same name.
+Note that the exclamation point is a special UNIX character so if
+it is used on the command line it must be preceded by a backslash to
+force the UNIX shell to accept the character as part of the filename.
+
+The output file will be written to the 'stdout' file stream if a dash
+character ('-') or the string 'stdout' is given as the filename. Similarly,
+'-.gz' or 'stdout.gz' will cause the file to be gzip compressed before
+it is written out to the stdout stream.
+
+Optionally, the name of a template file that is used to define the
+structure of the new file may be specified in parentheses following the
+output file name. The template file may be another FITS file, in which
+case the new file, at the time it is opened, will be an exact copy of
+the template file except that the data structures (images and tables)
+will be filled with zeros. Alternatively, the template file may be an
+ASCII format text file containing directives that define the keywords to be
+created in each HDU of the file. See the 'Extended File Name Syntax'
+ section for a complete description of the template file syntax.
+
+The fits\_create\_diskfile routine is similar to the fits\_create\_file routine
+except that it does not support the extended filename syntax in the input
+file name. This routine simply tries to create the specified file
+on magnetic disk. This routine is mainly for use in cases where the
+filename (or directory path) contains square or curly bracket characters
+ that would confuse the extended filename parser.
+\end{description}
+
+
+
+\begin{description}
+\item[3 ] Close a previously opened FITS file. The first routine simply
+closes the file, whereas the second one also DELETES THE FILE, which
+can be useful in cases where a FITS file has been partially created,
+but then an error occurs which prevents it from being completed.
+ \label{ffclos} \label{ffdelt}
+\end{description}
+
+\begin{verbatim}
+ int fits_close_file / ffclos (fitsfile *fptr, > int *status)
+
+ int fits_delete_file / ffdelt (fitsfile *fptr, > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[4 ]Return the name, I/O mode (READONLY or READWRITE), and/or the file
+type (e.g. 'file://', 'ftp://') of the opened FITS file. \label{ffflnm}
+ \label{ffflmd} \label{ffurlt}
+\end{description}
+
+\begin{verbatim}
+ int fits_file_name / ffflnm (fitsfile *fptr, > char *filename, int *status)
+
+ int fits_file_mode / ffflmd (fitsfile *fptr, > int *iomode, int *status)
+
+ int fits_url_type / ffurlt (fitsfile *fptr, > char *urltype, int *status)
+\end{verbatim}
+
+\section{HDU Access Routines}
+
+The following functions perform operations on Header-Data Units (HDUs)
+as a whole.
+
+
+\begin{description}
+\item[1 ] Move to a different HDU in the file. The first routine moves to a
+ specified absolute HDU number (starting with 1 for the primary
+ array) in the FITS file, and the second routine moves a relative
+ number HDUs forward or backward from the current HDU. A null
+ pointer may be given for the hdutype parameter if it's value is not
+ needed. The third routine moves to the (first) HDU which has the
+ specified extension type and EXTNAME and EXTVER keyword values (or
+ HDUNAME and HDUVER keywords). The hdutype parameter may have a
+ value of IMAGE\_HDU, ASCII\_TBL, BINARY\_TBL, or ANY\_HDU where
+ ANY\_HDU means that only the extname and extver values will be used
+ to locate the correct extension. If the input value of extver is 0
+ then the EXTVER keyword is ignored and the first HDU with a
+ matching EXTNAME (or HDUNAME) keyword will be found. If no
+ matching HDU is found in the file then the current HDU will remain
+ unchanged and a status = BAD\_HDU\_NUM will be returned.
+ \label{ffmahd} \label{ffmrhd} \label{ffmnhd}
+\end{description}
+
+\begin{verbatim}
+ int fits_movabs_hdu / ffmahd
+ (fitsfile *fptr, int hdunum, > int *hdutype, int *status)
+
+ int fits_movrel_hdu / ffmrhd
+ (fitsfile *fptr, int nmove, > int *hdutype, int *status)
+
+ int fits_movnam_hdu / ffmnhd
+ (fitsfile *fptr, int hdutype, char *extname, int extver, > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[2 ] Return the total number of HDUs in the FITS file.
+ The current HDU remains unchanged. \label{ffthdu}
+\end{description}
+
+\begin{verbatim}
+ int fits_get_num_hdus / ffthdu
+ (fitsfile *fptr, > int *hdunum, int *status)
+\end{verbatim}
+
+\begin{description}
+\item[3 ] Return the number of the current HDU (CHDU) in the FITS file (where
+ the primary array = 1). This function returns the HDU number
+ rather than a status value. \label{ffghdn}
+\end{description}
+
+\begin{verbatim}
+ int fits_get_hdu_num / ffghdn
+ (fitsfile *fptr, > int *hdunum)
+\end{verbatim}
+
+\begin{description}
+\item[4 ] Return the type of the current HDU in the FITS file. The possible
+ values for hdutype are: IMAGE\_HDU, ASCII\_TBL, or BINARY\_TBL. \label{ffghdt}
+\end{description}
+
+\begin{verbatim}
+ int fits_get_hdu_type / ffghdt
+ (fitsfile *fptr, > int *hdutype, int *status)
+\end{verbatim}
+
+\begin{description}
+\item[5 ] Copy all or part of the HDUs in the FITS file associated with infptr
+ and append them to the end of the FITS file associated with
+ outfptr. If 'previous' is true (not 0), then any HDUs preceding
+ the current HDU in the input file will be copied to the output
+ file. Similarly, 'current' and 'following' determine whether the
+ current HDU, and/or any following HDUs in the input file will be
+ copied to the output file. Thus, if all 3 parameters are true, then the
+ entire input file will be copied. On exit, the current HDU in
+ the input file will be unchanged, and the last HDU in the output
+ file will be the current HDU. \label{ffcpfl}
+\end{description}
+
+\begin{verbatim}
+ int fits_copy_file / ffcpfl
+ (fitsfile *infptr, fitsfile *outfptr, int previous, int current,
+ int following, > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[6 ] Copy the current HDU from the FITS file associated with infptr and append it
+ to the end of the FITS file associated with outfptr. Space may be
+ reserved for MOREKEYS additional keywords in the output header. \label{ffcopy}
+\end{description}
+
+\begin{verbatim}
+ int fits_copy_hdu / ffcopy
+ (fitsfile *infptr, fitsfile *outfptr, int morekeys, > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[7 ] Copy the header (and not the data) from the CHDU associated with infptr
+ to the CHDU associated with outfptr. If the current output HDU
+ is not completely empty, then the CHDU will be closed and a new
+ HDU will be appended to the output file. An empty output data unit
+ will be created with all values initially = 0). \label{ffcphd}
+\end{description}
+
+\begin{verbatim}
+ int fits_copy_header / ffcphd
+ (fitsfile *infptr, fitsfile *outfptr, > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[8 ] Delete the CHDU in the FITS file. Any following HDUs will be shifted
+ forward in the file, to fill in the gap created by the deleted
+ HDU. In the case of deleting the primary array (the first HDU in
+ the file) then the current primary array will be replace by a null
+ primary array containing the minimum set of required keywords and
+ no data. If there are more extensions in the file following the
+ one that is deleted, then the the CHDU will be redefined to point
+ to the following extension. If there are no following extensions
+ then the CHDU will be redefined to point to the previous HDU. The
+ output hdutype parameter returns the type of the new CHDU. A null
+ pointer may be given for
+ hdutype if the returned value is not needed. \label{ffdhdu}
+\end{description}
+
+\begin{verbatim}
+ int fits_delete_hdu / ffdhdu
+ (fitsfile *fptr, > int *hdutype, int *status)
+\end{verbatim}
+
+\section{Header Keyword Read/Write Routines}
+
+These routines read or write keywords in the Current Header Unit
+(CHU). Wild card characters (*, ?, or \#) may be used when specifying
+the name of the keyword to be read: a '?' will match any single
+character at that position in the keyword name and a '*' will match any
+length (including zero) string of characters. The '\#' character will
+match any consecutive string of decimal digits (0 - 9). When a wild
+card is used the routine will only search for a match from the current
+header position to the end of the header and will not resume the search
+from the top of the header back to the original header position as is
+done when no wildcards are included in the keyword name. The
+fits\_read\_record routine may be used to set the starting position
+when doing wild card searchs. A status value of KEY\_NO\_EXIST is
+returned if the specified keyword to be read is not found in the
+header.
+
+
+\subsection{Keyword Reading Routines}
+
+
+\begin{description}
+\item[1 ] Return the number of existing keywords (not counting the
+ END keyword) and the amount of space currently available for more
+ keywords. It returns morekeys = -1 if the header has not yet been
+ closed. Note that CFITSIO will dynamically add space if required
+ when writing new keywords to a header so in practice there is no
+ limit to the number of keywords that can be added to a header. A
+ null pointer may be entered for the morekeys parameter if it's
+ value is not needed. \label{ffghsp}
+\end{description}
+
+\begin{verbatim}
+ int fits_get_hdrspace / ffghsp
+ (fitsfile *fptr, > int *keysexist, int *morekeys, int *status)
+\end{verbatim}
+
+\begin{description}
+\item[2 ] Return the specified keyword. In the first routine,
+ the datatype parameter specifies the desired returned data type of the
+ keyword value and can have one of the following symbolic constant
+ values: TSTRING, TLOGICAL (== int), TBYTE, TSHORT, TUSHORT, TINT,
+ TUINT, TLONG, TULONG, TFLOAT, TDOUBLE, TCOMPLEX, and TDBLCOMPLEX.
+ Within the context of this routine, TSTRING corresponds to a
+ 'char*' data type, i.e., a pointer to a character array. Data type
+ conversion will be performed for numeric values if the keyword
+ value does not have the same data type. If the value of the keyword
+ is undefined (i.e., the value field is blank) then an error status
+ = VALUE\_UNDEFINED will be returned.
+
+ The second routine returns the keyword value as a character string
+ (a literal copy of what is in the value field) regardless of the
+ intrinsic data type of the keyword. The third routine returns
+ the entire 80-character header record of the keyword.
+
+ If a NULL comment pointer is supplied then the comment string
+ will not be returned. \label{ffgky} \label{ffgkey} \label{ffgcrd}
+\end{description}
+
+\begin{verbatim}
+ int fits_read_key / ffgky
+ (fitsfile *fptr, int datatype, char *keyname, > DTYPE *value,
+ char *comment, int *status)
+
+ int fits_read_keyword / ffgkey
+ (fitsfile *fptr, char *keyname, > char *value, char *comment,
+ int *status)
+
+ int fits_read_card / ffgcrd
+ (fitsfile *fptr, char *keyname, > char *card, int *status)
+\end{verbatim}
+
+\begin{description}
+\item[3 ] Return the nth header record in the CHU. The first keyword
+ in the header is at keynum = 1; if keynum = 0 then these routines
+ simply reset the internal CFITSIO pointer to the beginning of the header
+ so that subsequent keyword operations will start at the top of the
+ header (e.g., prior to searching for keywords using wild cards in
+ the keyword name). The first routine returns the entire
+ 80-character header record, while the second routine parses the
+ record and returns the name, value, and comment fields as separate
+ character strings. If a NULL comment pointer is given on input,
+ then the comment string will not be
+ returned. \label{ffgrec} \label{ffgkyn}
+\end{description}
+
+\begin{verbatim}
+ int fits_read_record / ffgrec
+ (fitsfile *fptr, int keynum, > char *card, int *status)
+
+ int fits_read_keyn / ffgkyn
+ (fitsfile *fptr, int keynum, > char *keyname, char *value,
+ char *comment, int *status)
+\end{verbatim}
+
+\begin{description}
+\item[4 ] Return the next keyword whose name matches one of the strings in
+ 'inclist' but does not match any of the strings in 'exclist'.
+ The strings in inclist and exclist may contain wild card characters
+ (*, ?, and \#) as described at the beginning of this section.
+ This routine searches from the current header position to the
+ end of the header, only, and does not continue the search from
+ the top of the header back to the original position. The current
+ header position may be reset with the ffgrec routine. Note
+ that nexc may be set = 0 if there are no keywords to be excluded.
+ This routine returns status = KEY\_NO\_EXIST if a matching
+ keyword is not found. \label{ffgnxk}
+\end{description}
+
+\begin{verbatim}
+ int fits_find_nextkey / ffgnxk
+ (fitsfile *fptr, char **inclist, int ninc, char **exclist,
+ int nexc, > char *card, int *status)
+\end{verbatim}
+
+\begin{description}
+\item[5 ] Return the physical units string from an existing keyword. This
+ routine uses a local convention, shown in the following example,
+ in which the keyword units are enclosed in square brackets in the
+ beginning of the keyword comment field. A null string is returned
+ if no units are defined for the keyword. \label{ffgunt}
+\end{description}
+
+\begin{verbatim}
+ VELOCITY= 12.3 / [km/s] orbital speed
+
+ int fits_read_key_unit / ffgunt
+ (fitsfile *fptr, char *keyname, > char *unit, int *status)
+\end{verbatim}
+
+\begin{description}
+\item[6 ] Concatenate the header keywords in the CHDU into a single long
+ string of characters. This provides a convenient way of passing
+ all or part of the header information in a FITS HDU to other subroutines.
+ Each 80-character fixed-length keyword record is appended to the
+ output character string, in order, with no intervening separator or
+ terminating characters. The last header record is terminated with
+ a NULL character. This routine allocates memory for the returned
+ character array, so the calling program must free the memory when
+ finished.
+
+ Selected keywords may be excluded from the returned character string.
+ If the second parameter (nocomments) is TRUE (nonzero) then any
+ COMMENT, HISTORY, or blank keywords in the header will not be copied
+ to the output string.
+
+ The 'exclist' parameter may be used to supply a list of keywords
+ that are to be excluded from the output character string. Wild card
+ characters (*, ?, and \#) may be used in the excluded keyword names.
+ If no additional keywords are to be excluded, then set nexc = 0 and
+ specify NULL for the the **header parameter. \label{ffhdr2str}
+\end{description}
+
+\begin{verbatim}
+ int fits_hdr2str
+ (fitsfile *fptr, int nocomments, char **exclist, int nexc,
+ > char **header, int *nkeys, int *status)
+\end{verbatim}
+
+
+\subsection{Keyword Writing Routines}
+
+
+\begin{description}
+\item[1 ] Write a keyword of the appropriate data type into the
+ CHU. The first routine simply appends a new keyword whereas the
+ second routine will update the value and comment fields of the
+ keyword if it already exists, otherwise it appends a new
+ keyword. Note that the address to the value, and not the value
+ itself, must be entered. The datatype parameter specifies the
+ data type of the keyword value with one of the following values:
+ TSTRING, TLOGICAL (== int), TBYTE, TSHORT, TUSHORT, TINT, TUINT,
+ TLONG, TULONG, TFLOAT, TDOUBLE. Within the context of this
+ routine, TSTRING corresponds to a 'char*' data type, i.e., a pointer
+ to a character array. A null pointer may be entered for the
+ comment parameter in which case the keyword comment
+ field will be unmodified or left blank. \label{ffpky} \label{ffuky}
+\end{description}
+
+\begin{verbatim}
+ int fits_write_key / ffpky
+ (fitsfile *fptr, int datatype, char *keyname, DTYPE *value,
+ char *comment, > int *status)
+
+ int fits_update_key / ffuky
+ (fitsfile *fptr, int datatype, char *keyname, DTYPE *value,
+ char *comment, > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[2 ] Write a keyword with a null or undefined value (i.e., the
+ value field in the keyword is left blank). The first routine
+ simply appends a new keyword whereas the second routine will update
+ the value and comment fields of the keyword if it already exists,
+ otherwise it appends a new keyword. A null pointer may be
+ entered for the comment parameter in which case the keyword
+ comment
+ field will be unmodified or left blank. \label{ffpkyu} \label{ffukyu}
+\end{description}
+
+\begin{verbatim}
+ int fits_write_key_null / ffpkyu
+ (fitsfile *fptr, char *keyname, char *comment, > int *status)
+
+ int fits_update_key_null / ffukyu
+ (fitsfile *fptr, char *keyname, char *comment, > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[3 ] Write (append) a COMMENT or HISTORY keyword to the CHU. The comment or
+ history string will be continued over multiple keywords if it is longer
+ than 70 characters. \label{ffpcom} \label{ffphis}
+\end{description}
+
+\begin{verbatim}
+ int fits_write_comment / ffpcom
+ (fitsfile *fptr, char *comment, > int *status)
+
+ int fits_write_history / ffphis
+ (fitsfile *fptr, char *history, > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[4 ] Write the DATE keyword to the CHU. The keyword value will contain
+ the current system date as a character string in 'yyyy-mm-ddThh:mm:ss'
+ format. If a DATE keyword already exists in the header, then this
+ routine will simply update the keyword value with the current date.
+ \label{ffpdat}
+\end{description}
+
+\begin{verbatim}
+ int fits_write_date / ffpdat
+ (fitsfile *fptr, > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[5 ]Write a user specified keyword record into the CHU. This is
+ a low--level routine which can be used to write any arbitrary
+ record into the header. The record must conform to the all
+ the FITS format requirements. \label{ffprec}
+\end{description}
+
+\begin{verbatim}
+ int fits_write_record / ffprec
+ (fitsfile *fptr, char *card, > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[6 ]Update an 80-character record in the CHU. If a keyword with the input
+ name already exists, then it is overwritten by the value of card. This
+ could modify the keyword name as well as the value and comment fields.
+ If the keyword doesn't already exist then a new keyword card is appended
+ to the header. \label{ffucrd}
+\end{description}
+
+\begin{verbatim}
+ int fits_update_card / ffucrd
+ (fitsfile *fptr, char *keyname, char *card, > int *status)
+\end{verbatim}
+
+
+\begin{description}
+\item[7 ] Modify (overwrite) the comment field of an existing keyword. \label{ffmcom}
+\end{description}
+
+\begin{verbatim}
+ int fits_modify_comment / ffmcom
+ (fitsfile *fptr, char *keyname, char *comment, > int *status)
+\end{verbatim}
+
+
+\begin{description}
+\item[8 ] Write the physical units string into an existing keyword. This
+ routine uses a local convention, shown in the following example,
+ in which the keyword units are enclosed in square brackets in the
+ beginning of the keyword comment field. \label{ffpunt}
+\end{description}
+
+\begin{verbatim}
+ VELOCITY= 12.3 / [km/s] orbital speed
+
+ int fits_write_key_unit / ffpunt
+ (fitsfile *fptr, char *keyname, char *unit, > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[9 ] Rename an existing keyword, preserving the current value
+ and comment fields. \label{ffmnam}
+\end{description}
+
+\begin{verbatim}
+ int fits_modify_name / ffmnam
+ (fitsfile *fptr, char *oldname, char *newname, > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[10] Delete a keyword record. The space occupied by
+ the keyword is reclaimed by moving all the following header records up
+ one row in the header. The first routine deletes a keyword at a
+ specified position in the header (the first keyword is at position 1),
+ whereas the second routine deletes a specifically named keyword.
+ Wild card characters may be used when specifying the name of the keyword
+ to be deleted. \label{ffdrec} \label{ffdkey}
+\end{description}
+
+\begin{verbatim}
+ int fits_delete_record / ffdrec
+ (fitsfile *fptr, int keynum, > int *status)
+
+ int fits_delete_key / ffdkey
+ (fitsfile *fptr, char *keyname, > int *status)
+\end{verbatim}
+
+\section{Primary Array or IMAGE Extension I/O Routines}
+
+These routines read or write data values in the primary data array (i.e.,
+the first HDU in a FITS file) or an IMAGE extension. There are also
+routines to get information about the data type and size of the image.
+Users should also read the following chapter on the CFITSIO iterator
+function which provides a more `object oriented' method of reading and
+writing images. The iterator function is a little more complicated to
+use, but the advantages are that it usually takes less code to perform
+the same operation, and the resulting program oftens runs faster because
+the FITS files are read and written using the most efficient block size.
+
+C programmers should note that the ordering of arrays in FITS files, and
+hence in all the CFITSIO calls, is more similar to the dimensionality
+of arrays in Fortran rather than C. For instance if a FITS image has
+NAXIS1 = 100 and NAXIS2 = 50, then a 2-D array just large enough to hold
+the image should be declared as array[50][100] and not as array[100][50].
+
+The `datatype' parameter specifies the data type of the `nulval' and
+`array' pointers and can have one of the following values: TBYTE,
+TSBYTE, TSHORT, TUSHORT, TINT, TUINT, TLONG, TLONGLONG, TULONG, TFLOAT,
+TDOUBLE. Automatic data type conversion is performed if the data type
+of the FITS array (as defined by the BITPIX keyword) differs from that
+specified by 'datatype'. The data values are also automatically scaled
+by the BSCALE and BZERO keyword values as they are being read or written
+in the FITS array.
+
+
+\begin{description}
+\item[1 ] Get the data type or equivalent data type of the image. The
+ first routine returns the physical data type of the FITS image, as
+ given by the BITPIX keyword, with allowed values of BYTE\_IMG (8),
+ SHORT\_IMG (16), LONG\_IMG (32), FLOAT\_IMG (-32), and DOUBLE\_IMG
+ (-64). The second routine is similar, except that if the image pixel
+ values are scaled, with non-default values for the BZERO and BSCALE
+ keywords, then the routine will return the 'equivalent' data type
+ that is needed to store the scaled values. For example, if BITPIX
+ = 16 and BSCALE = 0.1 then the equivalent data type is FLOAT\_IMG.
+ Similarly if BITPIX = 16, BSCALE = 1, and BZERO = 32768, then the
+ the pixel values span the range of an unsigned short integer and
+ the returned data type will be USHORT\_IMG. \label{ffgidt}
+\end{description}
+
+\begin{verbatim}
+ int fits_get_img_type / ffgidt
+ (fitsfile *fptr, > int *bitpix, int *status)
+
+ int fits_get_img_equivtype / ffgiet
+ (fitsfile *fptr, > int *bitpix, int *status)
+\end{verbatim}
+
+\begin{description}
+\item[2 ] Get the number of dimensions, and/or the size of
+ each dimension in the image . The number of axes in the image is
+ given by naxis, and the size of each dimension is given by the
+ naxes array (a maximum of maxdim dimensions will be returned).
+ \label{ffgidm} \label{ffgisz} \label{ffgipr}
+\end{description}
+
+\begin{verbatim}
+ int fits_get_img_dim / ffgidm
+ (fitsfile *fptr, > int *naxis, int *status)
+
+ int fits_get_img_size / ffgisz
+ (fitsfile *fptr, int maxdim, > long *naxes, int *status)
+
+ int fits_get_img_param / ffgipr
+ (fitsfile *fptr, int maxdim, > int *bitpix, int *naxis, long *naxes,
+ int *status)
+\end{verbatim}
+
+\begin{description}
+\item[3 ]Create a new primary array or IMAGE extension with a specified
+ data type and size. If the FITS file is currently empty then a
+ primary array is created, otherwise a new IMAGE extension is
+ appended to the file. \label{ffcrim}
+\end{description}
+
+\begin{verbatim}
+ int fits_create_img / ffcrim
+ ( fitsfile *fptr, int bitpix, int naxis, long *naxes, > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[4 ] Write a rectangular subimage (or the whole image) to the FITS data
+ array. The fpixel and lpixel arrays give the coordinates of the
+ first (lower left corner) and last (upper right corner) pixels in
+ FITS image to be written to. \label{ffpss}
+\end{description}
+
+\begin{verbatim}
+ int fits_write_subset / ffpss
+ (fitsfile *fptr, int datatype, long *fpixel, long *lpixel,
+ DTYPE *array, > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[5 ] Write pixels into the FITS data array. 'fpixel' is an array of
+ length NAXIS which gives the coordinate of the starting pixel to be
+ written to, such that fpixel[0] is in the range 1 to NAXIS1,
+ fpixel[1] is in the range 1 to NAXIS2, etc. The first routine
+ simply writes the array of pixels to the FITS file (doing data type
+ conversion if necessary) whereas the second routine will substitute
+ the appropriate FITS null value for any elements which are equal to
+ the input value of nulval (note that this parameter gives the
+ address of the null value, not the null value itself). For integer
+ FITS arrays, the FITS null value is defined by the BLANK keyword (an
+ error is returned if the BLANK keyword doesn't exist). For floating
+ point FITS arrays the special IEEE NaN (Not-a-Number) value will be
+ written into the FITS file. If a null pointer is entered for
+ nulval, then the null value is ignored and this routine behaves
+ the same as fits\_write\_pix. \label{ffppx} \label{ffppxn}
+\end{description}
+
+\begin{verbatim}
+ int fits_write_pix / ffppx
+ (fitsfile *fptr, int datatype, long *fpixel, long nelements,
+ DTYPE *array, int *status);
+
+ int fits_write_pixnull / ffppxn
+ (fitsfile *fptr, int datatype, long *fpixel, long nelements,
+ DTYPE *array, DTYPE *nulval, > int *status);
+\end{verbatim}
+
+\begin{description}
+\item[6 ] Set FITS data array elements equal to the appropriate null pixel
+ value. For integer FITS arrays, the FITS null value is defined by
+ the BLANK keyword (an error is returned if the BLANK keyword
+ doesn't exist). For floating point FITS arrays the special IEEE NaN
+ (Not-a-Number) value will be written into the FITS file. Note that
+ 'firstelem' is a scalar giving the offset to the first pixel to be
+ written in the equivalent 1-dimensional array of image pixels. \label{ffpprn}
+\end{description}
+
+\begin{verbatim}
+ int fits_write_null_img / ffpprn
+ (fitsfile *fptr, long firstelem, long nelements, > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[7 ] Read a rectangular subimage (or the whole image) from the FITS
+ data array. The fpixel and lpixel arrays give the coordinates of
+ the first (lower left corner) and last (upper right corner) pixels
+ to be read from the FITS image. Undefined FITS array elements will
+ be returned with a value = *nullval, (note that this parameter
+ gives the address of the null value, not the null value itself)
+ unless nulval = 0 or *nulval = 0, in which case no checks for
+ undefined pixels will be performed. \label{ffgsv}
+\end{description}
+
+\begin{verbatim}
+ int fits_read_subset / ffgsv
+ (fitsfile *fptr, int datatype, long *fpixel, long *lpixel, long *inc,
+ DTYPE *nulval, > DTYPE *array, int *anynul, int *status)
+\end{verbatim}
+
+\begin{description}
+\item[8 ] Read pixels from the FITS data array. 'fpixel' is the starting
+ pixel location and is an array of length NAXIS such that fpixel[0]
+ is in the range 1 to NAXIS1, fpixel[1] is in the range 1 to NAXIS2,
+ etc. The nelements parameter specifies the number of pixels to
+ read. If fpixel is set to the first pixel, and nelements is set
+ equal to the NAXIS1 value, then this routine would read the first
+ row of the image. Alternatively, if nelements is set equal to
+ NAXIS1 * NAXIS2 then it would read an entire 2D image, or the first
+ plane of a 3-D datacube.
+
+ The first routine will return any undefined pixels in the FITS array
+ equal to the value of *nullval (note that this parameter gives the
+ address of the null value, not the null value itself) unless nulval
+ = 0 or *nulval = 0, in which case no checks for undefined pixels
+ will be performed. The second routine is similar except that any
+ undefined pixels will have the corresponding nullarray element set
+ equal to TRUE (= 1). \label{ffgpxv} \label{ffgpxf}
+\end{description}
+
+\begin{verbatim}
+ int fits_read_pix / ffgpxv
+ (fitsfile *fptr, int datatype, long *fpixel, long nelements,
+ DTYPE *nulval, > DTYPE *array, int *anynul, int *status)
+
+ int fits_read_pixnull / ffgpxf
+ (fitsfile *fptr, int datatype, long *fpixel, long nelements,
+ > DTYPE *array, char *nullarray, int *anynul, int *status)
+\end{verbatim}
+
+\section{Image Compression}
+
+CFITSIO now transparently supports 2 types of image compression:
+
+1) The entire FITS file may be externally compressed with the gzip or
+Unix compress algorithm, producing a *.gz or *.Z file, respectively.
+When reading compressed files of this type, CFITSIO first uncompresses
+the entire file into memory before performing the requested read
+operations. Output files can be directly written in the gzip
+compressed format if the user-specified filename ends with `.gz'. In
+this case, CFITSIO initially writes the uncompressed file in memory and
+then compresses it and writes it to disk when the FITS file is closed,
+thus saving user disk space. Read and write access to these compressed
+FITS files is generally quite fast; the main limitation is that there
+must be enough available memory (or swap space) to hold the entire
+uncompressed FITS file.
+
+2) CFITSIO also supports a newer image compression format in which the
+image is divided into a grid of rectangular tiles, and each tile of
+pixels is individually compressed. The compressed tiles are stored in
+rows of a variable length array column in a FITS binary table, but
+CFITSIO recognizes that the binary table extension contains an image
+and treats it as if it were an IMAGE extension. This tile-compressed
+format is especially well suited for compressing very large images
+because a) the FITS header keywords remain uncompressed for rapid read
+access, and because b) it is possible to extract and uncompress
+sections of the image without having to uncompress the entire image.
+This format is also much more effective in compressing floating point
+images (using a lossy compression algorithm) than simply compressing
+the image using gzip or compress.
+
+A detailed description of this format is available at:
+
+\begin{verbatim}
+http://heasarc.gsfc.nasa.gov/docs/software/fitsio/
+ compression/compress_image.html
+\end{verbatim}
+
+The N-dimensional FITS image can be divided into any
+desired rectangular grid of compression tiles. By default the tiles
+are chosen to correspond to the rows of the image, each containing
+NAXIS1 pixels. For example, a 800 x 800 x 4 pixel data cube would be
+divided in to 3200 tiles containing 800 pixels each by default.
+Alternatively, this data cube could be divided into 256 tiles that are each
+100 X 100 X 1 pixels in size, or 4 tiles containing 800 x 800 X 1
+pixels, or a single tile containing the entire data cube. Note that
+the image dimensions are not required to be an integer multiple of the
+tile dimensions, so, for example, this data cube could also be divided
+into 250 X 200 pixel tiles, in which case the last tile in each row
+would only contain 50 X 200 pixels.
+
+Currently, 3 image compression algorithms are supported: Rice, GZIP,
+and PLIO. Rice and GZIP are general purpose algorithms that can be
+used to compress almost any image. The PLIO algorithm, on the other
+hand, is more specialized and was developed for use in IRAF to store
+pixel data quality masks. It is designed to only work on images
+containing positive integers with values up to about 2**24. Other
+image compression algorithms may be supported in the future.
+
+The 3 supported image compression algorithms are all 'loss-less' when
+applied to integer FITS images; the pixel values are preserved exactly
+with no loss of information during the compression and uncompression
+process. Floating point FITS images (which have BITPIX = -32 or -64)
+are first quantized into scaled integer pixel values before being
+compressed. This technique produces much higher compression factors
+than simply using GZIP to compress the image, but it also means that
+the original floating value pixel values may not be precisely returned
+when the image is uncompressed. When done properly, this only discards
+the 'noise' from the floating point values without losing any
+significant information. The amount of noise that is discarded can be
+controlled by the 'noise\_bits' compression parameter.
+
+No special action is required to read tile-compressed images because
+all the CFITSIO routines that read normal uncompressed FITS images can
+also read images in the tile-compressed format; CFITSIO essentially
+treats the binary table that contains the compressed tiles as if
+it were an IMAGE extension.
+
+When creating (writing) a new image with CFITSIO, a normal uncompressed
+FITS primary array or IMAGE extension will be written unless the
+tile-compressed format has been specified in 1 of 2 possible ways:
+
+1) At run time, when specifying the name of the output FITS file to be
+created at run time, the user can indicate that images should be
+written in tile-compressed format by enclosing the compression
+parameters in square brackets following the root disk file name. The
+`imcopy' example program that included with the CFITSIO distribution
+can be used for this purpose to compress or uncompress images. Here
+are some examples of the extended file name syntax for specifying
+tile-compressed output images:
+
+\begin{verbatim}
+ myfile.fit[compress] - use the default compression algorithm (Rice)
+ and the default tile size (row by row)
+
+ myfile.fit[compress GZIP] - use the specified compression algorithm;
+ myfile.fit[compress Rice] only the first letter of the algorithm
+ myfile.fit[compress PLIO] name is required.
+
+ myfile.fit[compress R 100,100] - use Rice compression and
+ 100 x 100 pixel tile size
+
+ myfile.fit[compress R 100,100;2] - as above, and also use noisebits = 2
+\end{verbatim}
+
+2) Before calling the CFITSIO routine to write the image header
+keywords (e.g., fits\_create\_image) the programmer can call the
+routines described below to specify the compression algorithm and the
+tiling pattern that is to be used. There are 3 routines for specifying
+the various compression parameters and 3 corresponding routines to
+return the current values of the parameters:
+\label{ffsetcomp} \label{ffgetcomp}
+
+\begin{verbatim}
+ int fits_set_compression_type(fitsfile *fptr, int comptype, int *status)
+ int fits_set_tile_dim(fitsfile *fptr, int ndim, long *tilesize, int *status)
+ int fits_set_noise_bits(fitsfile *fptr, int noisebits, int *status)
+
+ int fits_get_compression_type(fitsfile *fptr, int *comptype, int *status)
+ int fits_get_tile_dim(fitsfile *fptr, int ndim, long *tilesize, int *status)
+ int fits_get_noise_bits(fitsfile *fptr, int *noisebits, int *status)
+\end{verbatim}
+3 symbolic constants are defined for use as the value of the
+`comptype' parameter: GZIP\_1, RICE\_1, or PLIO\_1. Entering NULL for
+comptype will turn off the tile-compression and cause normal FITS
+images to be written.
+
+The 'noisebits' parameter is only used when compressing floating point
+images. The default value is 4. Decreasing the value of noisebits
+will improve the overall compression efficiency at the expense of
+losing more information.
+
+A small example program called 'imcopy' is included with CFITSIO that
+can be used to compress (or uncompress) any FITS image. This
+program can be used to experiment with the various compression options
+on existing FITS images as shown in these examples:
+
+\begin{verbatim}
+1) imcopy infile.fit 'outfile.fit[compress]'
+
+ This will use the default compression algorithm (Rice) and the
+ default tile size (row by row)
+
+2) imcopy infile.fit 'outfile.fit[compress GZIP]'
+
+ This will use the GZIP compression algorithm and the default
+ tile size (row by row). The allowed compression algorithms are
+ Rice, GZIP, and PLIO. Only the first letter of the algorithm
+ name needs to be specified.
+
+3) imcopy infile.fit 'outfile.fit[compress G 100,100]'
+
+ This will use the GZIP compression algorithm and 100 X 100 pixel
+ tiles.
+
+4) imcopy infile.fit 'outfile.fit[compress R 100,100; 4]'
+
+ This will use the Rice compression algorithm, 100 X 100 pixel
+ tiles, and noise_bits = 4 (assuming the input image has a
+ floating point data type). Decreasing the value of noisebits
+ will improve the overall compression efficiency at the expense
+ of losing more information.
+
+5) imcopy infile.fit outfile.fit
+
+ If the input file is in tile-compressed format, then it will be
+ uncompressed to the output file. Otherwise, it simply copies
+ the input image to the output image.
+
+6) imcopy 'infile.fit[1001:1500,2001:2500]' outfile.fit
+
+ This extracts a 500 X 500 pixel section of the much larger
+ input image (which may be in tile-compressed format). The
+ output is a normal uncompressed FITS image.
+
+7) imcopy 'infile.fit[1001:1500,2001:2500]' outfile.fit.gz
+
+ Same as above, except the output file is externally compressed
+ using the gzip algorithm.
+
+\end{verbatim}
+
+\section{ASCII and Binary Table Routines}
+
+These routines perform read and write operations on columns of data in
+FITS ASCII or Binary tables. Note that in the following discussions,
+the first row and column in a table is at position 1 not 0.
+
+Users should also read the following chapter on the CFITSIO iterator
+function which provides a more `object oriented' method of reading and
+writing table columns. The iterator function is a little more
+complicated to use, but the advantages are that it usually takes less
+code to perform the same operation, and the resulting program oftens
+runs faster because the FITS files are read and written using the most
+efficient block size.
+
+
+\subsection{Create New Table}
+
+
+\begin{description}
+\item[1 ]Create a new ASCII or bintable table extension. If
+ the FITS file is currently empty then a dummy primary array will be
+ created before appending the table extension to it. The tbltype
+ parameter defines the type of table and can have values of
+ ASCII\_TBL or BINARY\_TBL. The naxis2 parameter gives the initial
+ number of rows to be created in the table, and should normally be
+ set = 0. CFITSIO will automatically increase the size of the table
+ as additional rows are written. A non-zero number of rows may be
+ specified to reserve space for that many rows, even if a fewer
+ number of rows will be written. The tunit and extname parameters
+ are optional and a null pointer may be given if they are not
+ defined. The FITS Standard recommends that only letters, digits,
+ and the underscore character be used in column names (the ttype
+ parameter) with no embedded spaces. Trailing blank characters are
+ not significant. It is recommended that all the column names in a
+ given table be unique within the first 8 characters, and strongly
+ recommended that the names be
+ unique within the first 16 characters. \label{ffcrtb}
+\end{description}
+
+\begin{verbatim}
+ int fits_create_tbl / ffcrtb
+ (fitsfile *fptr, int tbltype, long naxis2, int tfields, char *ttype[],
+ char *tform[], char *tunit[], char *extname, int *status)
+\end{verbatim}
+
+\subsection{Column Information Routines}
+
+
+\begin{description}
+\item[1 ] Get the number of rows or columns in the current FITS table.
+ The number of rows is given by the NAXIS2 keyword and the
+ number of columns is given by the TFIELDS keyword in the header
+ of the table. \label{ffgnrw}
+\end{description}
+
+\begin{verbatim}
+ int fits_get_num_rows / ffgnrw
+ (fitsfile *fptr, > long *nrows, int *status);
+
+ int fits_get_num_cols / ffgncl
+ (fitsfile *fptr, > int *ncols, int *status);
+\end{verbatim}
+
+
+\begin{description}
+\item[2 ] Get the table column number (and name) of the column whose name
+matches an input template name. If casesen = CASESEN then the column
+name match will be case-sensitive, whereas if casesen = CASEINSEN then
+the case will be ignored. As a general rule, the column names should
+be treated as case INsensitive.
+
+The input column name template may be either the exact name of the
+column to be searched for, or it may contain wild card characters (*,
+?, or \#), or it may contain the integer number of the desired column
+(with the first column = 1). The `*' wild card character matches any
+sequence of characters (including zero characters) and the `?'
+character matches any single character. The \# wildcard will match any
+consecutive string of decimal digits (0-9). If more than one column
+name in the table matches the template string, then the first match is
+returned and the status value will be set to COL\_NOT\_UNIQUE as a
+warning that a unique match was not found. To find the other cases
+that match the template, call the routine again leaving the input
+status value equal to COL\_NOT\_UNIQUE and the next matching name will
+then be returned. Repeat this process until a status =
+COL\_NOT\_FOUND is returned.
+
+The FITS Standard recommends that only letters, digits, and the
+underscore character be used in column names (with no embedded
+spaces). Trailing blank characters are not significant. It is
+recommended that all the column names in a given table be unique within
+the first 8 characters, and strongly recommended that the names be
+ unique within the first 16 characters. \label{ffgcno} \label{ffgcnn}
+\end{description}
+
+\begin{verbatim}
+ int fits_get_colnum / ffgcno
+ (fitsfile *fptr, int casesen, char *templt, > int *colnum,
+ int *status)
+
+ int fits_get_colname / ffgcnn
+ (fitsfile *fptr, int casesen, char *templt, > char *colname,
+ int *colnum, int *status)
+\end{verbatim}
+
+\begin{description}
+\item[3 ] Return the data type, vector repeat value, and the width in bytes
+ of a column in an ASCII or binary table. Allowed values for the
+ data type in ASCII tables are: TSTRING, TSHORT, TLONG, TFLOAT, and
+ TDOUBLE. Binary tables also support these types: TLOGICAL, TBIT,
+ TBYTE, TCOMPLEX and TDBLCOMPLEX. The negative of the data type code
+ value is returned if it is a variable length array column. Note
+ that in the case of a 'J' 32-bit integer binary table column, this
+ routine will return data type = TINT32BIT (which in fact is
+ equivalent to TLONG). With most current C compilers, a value in a
+ 'J' column has the same size as an 'int' variable, and may not be
+ equivalent to a 'long' variable, which is 64-bits long on an
+ increasing number of compilers.
+
+ The 'repeat' parameter returns the vector repeat count on the binary
+ table TFORMn keyword value. (ASCII table columns always have repeat
+ = 1). The 'width' parameter returns the width in bytes of a single
+ column element (e.g., a '10D' binary table column will have width =
+ 8, an ASCII table 'F12.2' column will have width = 12, and a binary
+ table'60A' character string column will have width = 60); Note that
+ this routine supports the local convention for specifying arrays of
+ fixed length strings within a binary table character column using
+ the syntax TFORM = 'rAw' where 'r' is the total number of characters
+ (= the width of the column) and 'w' is the width of a unit string
+ within the column. Thus if the column has TFORM = '60A12' then this
+ means that each row of the table contains 5 12-character substrings
+ within the 60-character field, and thus in this case this routine will
+ return typecode = TSTRING, repeat = 60, and width = 12. The number
+ of substings in any binary table character string field can be
+ calculated by (repeat/width). A null pointer may be given for any of
+ the output parameters that are not needed.
+
+ The second routine, fit\_get\_eqcoltype is similar except that in
+ the case of scaled integer columns it returns the 'equivalent' data
+ type that is needed to store the scaled values, and not necessarily
+ the physical data type of the unscaled values as stored in the FITS
+ table. For example if a '1I' column in a binary table has TSCALn =
+ 1 and TZEROn = 32768, then this column effectively contains unsigned
+ short integer values, and thus the returned value of typecode will
+ be TUSHORT, not TSHORT. Similarly, if a column has TTYPEn = '1I'
+ and TSCALn = 0.12, then the returned typecode
+ will be TFLOAT. \label{ffgtcl}
+\end{description}
+
+\begin{verbatim}
+ int fits_get_coltype / ffgtcl
+ (fitsfile *fptr, int colnum, > int *typecode, long *repeat,
+ long *width, int *status)
+
+ int fits_get_eqcoltype / ffeqty
+ (fitsfile *fptr, int colnum, > int *typecode, long *repeat,
+ long *width, int *status)
+\end{verbatim}
+
+\begin{description}
+\item[4 ] Return the display width of a column. This is the length
+ of the string that will be returned by the fits\_read\_col routine
+ when reading the column as a formatted string. The display width is
+ determined by the TDISPn keyword, if present, otherwise by the data
+ type of the column. \label{ffgcdw}
+\end{description}
+
+\begin{verbatim}
+ int fits_get_col_display_width / ffgcdw
+ (fitsfile *fptr, int colnum, > int *dispwidth, int *status)
+\end{verbatim}
+
+
+\begin{description}
+\item[5 ] Return the number of and size of the dimensions of a table column in
+ a binary table. Normally this information is given by the TDIMn keyword,
+ but if this keyword is not present then this routine returns naxis = 1
+ and naxes[0] equal to the repeat count in the TFORM keyword. \label{ffgtdm}
+\end{description}
+
+\begin{verbatim}
+ int fits_read_tdim / ffgtdm
+ (fitsfile *fptr, int colnum, int maxdim, > int *naxis,
+ long *naxes, int *status)
+\end{verbatim}
+
+\begin{description}
+\item[6 ] Decode the input TDIMn keyword string (e.g. '(100,200)') and return the
+ number of and size of the dimensions of a binary table column. If the input
+ tdimstr character string is null, then this routine returns naxis = 1
+ and naxes[0] equal to the repeat count in the TFORM keyword. This routine
+ is called by fits\_read\_tdim. \label{ffdtdm}
+\end{description}
+
+\begin{verbatim}
+ int fits_decode_tdim / ffdtdm
+ (fitsfile *fptr, char *tdimstr, int colnum, int maxdim, > int *naxis,
+ long *naxes, int *status)
+\end{verbatim}
+
+\begin{description}
+\item[7 ] Write a TDIMn keyword whose value has the form '(l,m,n...)'
+ where l, m, n... are the dimensions of a multidimension array
+ column in a binary table. \label{ffptdm}
+\end{description}
+
+\begin{verbatim}
+ int fits_write_tdim / ffptdm
+ (fitsfile *fptr, int colnum, int naxis, long *naxes, > int *status)
+\end{verbatim}
+
+
+\subsection{Routines to Edit Rows or Columns}
+
+
+\begin{description}
+\item[1 ] Insert or delete rows in an ASCII or binary table. When inserting rows
+ all the rows following row FROW are shifted down by NROWS rows; if
+ FROW = 0 then the blank rows are inserted at the beginning of the
+ table. The first delete routine deletes NROWS consecutive rows
+ starting with row FIRSTROW. The second delete routine takes an
+ input string that lists the rows or row ranges (e.g.,
+ '5-10,12,20-30'), whereas the third delete routine takes an input
+ integer array that specifies each individual row to be deleted. In
+ both latter cases, the input list of rows to delete must be sorted
+ in ascending order. These routines update the NAXIS2 keyword to
+ reflect the new number of rows in the
+ table. \label{ffirow} \label{ffdrow} \label{ffdrws} \label{ffdrrg}
+\end{description}
+
+\begin{verbatim}
+ int fits_insert_rows / ffirow
+ (fitsfile *fptr, long firstrow, long nrows, > int *status)
+
+ int fits_delete_rows / ffdrow
+ (fitsfile *fptr, long firstrow, long nrows, > int *status)
+
+ int fits_delete_rowrange / ffdrrg
+ (fitsfile *fptr, char *rangelist, > int *status)
+
+ int fits_delete_rowlist / ffdrws
+ (fitsfile *fptr, long *rowlist, long nrows, > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[2 ] Insert or delete column(s) in an ASCII or binary
+ table. When inserting, COLNUM specifies the column number that the
+ (first) new column should occupy in the table. NCOLS specifies how
+ many columns are to be inserted. Any existing columns from this
+ position and higher are shifted over to allow room for the new
+ column(s). The index number on all the following keywords will be
+ incremented or decremented if necessary to reflect the new position
+ of the column(s) in the table: TBCOLn, TFORMn, TTYPEn, TUNITn,
+ TNULLn, TSCALn, TZEROn, TDISPn, TDIMn, TLMINn, TLMAXn, TDMINn,
+ TDMAXn, TCTYPn, TCRPXn, TCRVLn, TCDLTn, TCROTn,
+ and TCUNIn. \label{fficol} \label{fficls} \label{ffdcol}
+\end{description}
+
+\begin{verbatim}
+ int fits_insert_col / fficol
+ (fitsfile *fptr, int colnum, char *ttype, char *tform,
+ > int *status)
+
+ int fits_insert_cols / fficls
+ (fitsfile *fptr, int colnum, int ncols, char **ttype,
+ char **tform, > int *status)
+
+ int fits_delete_col / ffdcol(fitsfile *fptr, int colnum, > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[3 ] Copy a column from one HDU to another (or to the same HDU). If
+ create\_col = TRUE, then a new column will be inserted in the output
+ table, at position `outcolumn', otherwise the existing output column will
+ be overwritten (in which case it must have a compatible data type).
+ If outcolnum is greater than the number of column in the table, then
+ the new column will be appended to the end of the table.
+ Note that the first column in a table is at colnum = 1.
+ The standard indexed keywords that related to the column (e.g., TDISPn,
+ TUNITn, TCRPXn, TCDLTn, etc.) will also be copied. \label{ffcpcl}
+\end{description}
+
+\begin{verbatim}
+ int fits_copy_col / ffcpcl
+ (fitsfile *infptr, fitsfile *outfptr, int incolnum, int outcolnum,
+ int create_col, > int *status);
+\end{verbatim}
+
+\begin{description}
+\item[4 ] Modify the vector length of a binary table column (e.g.,
+ change a column from TFORMn = '1E' to '20E'). The vector
+ length may be increased or decreased from the current value. \label{ffmvec}
+\end{description}
+
+\begin{verbatim}
+ int fits_modify_vector_len / ffmvec
+ (fitsfile *fptr, int colnum, long newveclen, > int *status)
+\end{verbatim}
+
+\subsection{Read and Write Column Data Routines}
+
+The following routines write or read data values in the current ASCII
+or binary table extension. If a write operation extends beyond the
+current size of the table, then the number of rows in the table will
+automatically be increased and the NAXIS2 keyword value will be
+updated. Attempts to read beyond the end of the table will result in
+an error.
+
+Automatic data type conversion is performed for numerical data types
+(only) if the data type of the column (defined by the TFORMn keyword)
+differs from the data type of the calling routine. ASCII and binary
+tables support the following data type values: TSTRING, TBYTE, TSBYTE, TSHORT,
+TUSHORT, TINT, TUINT, TLONG, TLONGLONG, TULONG, TFLOAT, or TDOUBLE.
+Binary tables also support TLOGICAL (internally mapped to the `char'
+data type), TCOMPLEX, and TDBLCOMPLEX.
+
+Note that within the context of these routines, the TSTRING data type
+corresponds to a C 'char**' data type, i.e., a pointer to an array of
+pointers to an array of characters. This is different from the keyword
+reading and writing routines where TSTRING corresponds to a C 'char*'
+data type, i.e., a single pointer to an array of characters. When
+reading strings from a table, the char arrays obviously must have been
+allocated long enough to hold the whole FITS table string.
+
+Numerical data values are automatically scaled by the TSCALn and TZEROn
+keyword values (if they exist).
+
+In the case of binary tables with vector elements, the 'felem'
+parameter defines the starting element (beginning with 1, not 0) within
+the cell (a cell is defined as the intersection of a row and a column
+and may contain a single value or a vector of values). The felem
+parameter is ignored when dealing with ASCII tables. Similarly, in the
+case of binary tables the 'nelements' parameter specifies the total
+number of vector values to be read or written (continuing on subsequent
+rows if required) and not the number of table cells.
+
+
+\begin{description}
+\item[1 ] Write elements into an ASCII or binary table column.
+\end{description}
+ The first routine simply writes the array of values to the FITS file
+ (doing data type conversion if necessary) whereas the second routine
+ will substitute the appropriate FITS null value for all elements
+ which are equal to the input value of nulval (note that this
+ parameter gives the address of nulval, not the null value
+ itself). For integer columns the FITS null value is defined by the
+ TNULLn keyword (an error is returned if the keyword doesn't exist).
+ For floating point columns the special IEEE NaN (Not-a-Number)
+ value will be written into the FITS file. If a null pointer is
+ entered for nulval, then the null value is ignored and this routine
+ behaves the same as the first routine. The second routine must not
+ be used to write to variable length array columns. The third routine
+ simply writes undefined pixel values to the column.
+ \label{ffpcl} \label{ffpcn} \label{ffpclu}
+
+\begin{verbatim}
+ int fits_write_col / ffpcl
+ (fitsfile *fptr, int datatype, int colnum, long firstrow,
+ long firstelem, long nelements, DTYPE *array, > int *status)
+
+ int fits_write_colnull / ffpcn
+ (fitsfile *fptr, int datatype, int colnum, long firstrow,
+ long firstelem, long nelements, DTYPE *array, DTYPE *nulval,
+ > int *status)
+
+ int fits_write_col_null / ffpclu
+ (fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelements, > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[2 ] Read elements from an ASCII or binary table column. The data type
+ parameter specifies the data type of the `nulval' and `array' pointers;
+ Undefined array elements will be returned with a value = *nullval,
+ (note that this parameter gives the address of the null value, not the
+ null value itself) unless nulval = 0 or *nulval = 0, in which case
+ no checking for undefined pixels will be performed. The second
+ routine is similar except that any undefined pixels will have the
+ corresponding nullarray element set equal to TRUE (= 1).
+
+ Any column, regardless of it's intrinsic data type, may be read as a
+ string. It should be noted however that reading a numeric column
+ as a string is 10 - 100 times slower than reading the same column
+ as a number due to the large overhead in constructing the formatted
+ strings. The display format of the returned strings will be
+ determined by the TDISPn keyword, if it exists, otherwise by the
+ data type of the column. The length of the returned strings (not
+ including the null terminating character) can be determined with
+ the fits\_get\_col\_display\_width routine. The following TDISPn
+ display formats are currently supported:
+
+\begin{verbatim}
+ Iw.m Integer
+ Ow.m Octal integer
+ Zw.m Hexadecimal integer
+ Fw.d Fixed floating point
+ Ew.d Exponential floating point
+ Dw.d Exponential floating point
+ Gw.d General; uses Fw.d if significance not lost, else Ew.d
+\end{verbatim}
+ where w is the width in characters of the displayed values, m is the minimum
+ number of digits displayed, and d is the number of digits to the right of the
+ decimal. The .m field is optional.
+ \label{ffgcv} \label{ffgcf}
+\end{description}
+
+\begin{verbatim}
+ int fits_read_col / ffgcv
+ (fitsfile *fptr, int datatype, int colnum, long firstrow, long firstelem,
+ long nelements, DTYPE *nulval, DTYPE *array, int *anynul, int *status)
+
+ int fits_read_colnull / ffgcf
+ (fitsfile *fptr, int datatype, int colnum, long firstrow, long firstelem,
+ long nelements, DTYPE *array, char *nullarray, int *anynul, int *status)
+\end{verbatim}
+
+
+\subsection{Row Selection and Calculator Routines}
+
+These routines all parse and evaluate an input string containing a user
+defined arithmetic expression. The first 3 routines select rows in a
+FITS table, based on whether the expression evaluates to true (not
+equal to zero) or false (zero). The other routines evaluate the
+expression and calculate a value for each row of the table. The
+allowed expression syntax is described in the row filter section in the
+`Extended File Name Syntax' chapter of this document. The expression
+may also be written to a text file, and the name of the file, prepended
+with a '@' character may be supplied for the 'expr' parameter (e.g.
+'@filename.txt'). The expression in the file can be arbitrarily
+complex and extend over multiple lines of the file. Lines that begin
+with 2 slash characters ('//') will be ignored and may be used to add
+comments to the file.
+
+
+\begin{description}
+\item[1 ] Evaluate a boolean expression over the indicated rows, returning an
+ array of flags indicating which rows evaluated to TRUE/FALSE \label{fffrow}
+\end{description}
+
+\begin{verbatim}
+ int fits_find_rows / fffrow
+ (fitsfile *fptr, char *expr, long firstrow, long nrows,
+ > long *n_good_rows, char *row_status, int *status)
+\end{verbatim}
+
+\begin{description}
+\item[2 ] Find the first row which satisfies the input boolean expression \label{ffffrw}
+\end{description}
+
+\begin{verbatim}
+ int fits_find_first_row / ffffrw
+ (fitsfile *fptr, char *expr, > long *rownum, int *status)
+\end{verbatim}
+
+\begin{description}
+\item[3 ]Evaluate an expression on all rows of a table. If the input and output
+files are not the same, copy the TRUE rows to the output file. If the
+files are the same, delete the FALSE rows (preserve the TRUE rows). \label{ffsrow}
+\end{description}
+
+\begin{verbatim}
+ int fits_select_rows / ffsrow
+ (fitsfile *infptr, fitsfile *outfptr, char *expr, > int *status )
+\end{verbatim}
+
+\begin{description}
+\item[4 ] Calculate an expression for the indicated rows of a table, returning
+the results, cast as datatype (TSHORT, TDOUBLE, etc), in array. If
+nulval==NULL, UNDEFs will be zeroed out. For vector results, the number
+of elements returned may be less than nelements if nelements is not an
+even multiple of the result dimension. Call fits\_test\_expr to obtain
+the dimensions of the results. \label{ffcrow}
+\end{description}
+
+\begin{verbatim}
+ int fits_calc_rows / ffcrow
+ (fitsfile *fptr, int datatype, char *expr, long firstrow,
+ long nelements, void *nulval, > void *array, int *anynul, int *status)
+\end{verbatim}
+
+\begin{description}
+\item[5 ]Evaluate an expression and write the result either to a column (if
+the expression is a function of other columns in the table) or to a
+keyword (if the expression evaluates to a constant and is not a
+function of other columns in the table). In the former case, the
+parName parameter is the name of the column (which may or may not already
+exist) into which to write the results, and parInfo contains an
+optional TFORM keyword value if a new column is being created. If a
+TFORM value is not specified then a default format will be used,
+depending on the expression. If the expression evaluates to a constant,
+then the result will be written to the keyword name given by the
+parName parameter, and the parInfo parameter may be used to supply an
+optional comment for the keyword. If the keyword does not already
+exist, then the name of the keyword must be preceded with a '\#' character,
+otherwise the result will be written to a column with that name.
+ \label{ffcalc}
+\end{description}
+
+\begin{verbatim}
+ int fits_calculator / ffcalc
+ (fitsfile *infptr, char *expr, fitsfile *outfptr, char *parName,
+ char *parInfo, > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[6 ] This calculator routine is similar to the previous routine, except
+that the expression is only evaluated over the specified
+row ranges. nranges specifies the number of row ranges, and firstrow
+and lastrow give the starting and ending row number of each range.
+ \label{ffcalcrng}
+\end{description}
+
+\begin{verbatim}
+ int fits_calculator_rng / ffcalc_rng
+ (fitsfile *infptr, char *expr, fitsfile *outfptr, char *parName,
+ char *parInfo, int nranges, long *firstrow, long *lastrow
+ > int *status)
+\end{verbatim}
+
+
+\begin{description}
+\item[7 ]Evaluate the given expression and return information on the result. \label{fftexp}
+\end{description}
+
+\begin{verbatim}
+ int fits_test_expr / fftexp
+ (fitsfile *fptr, char *expr, > int *datatype, long *nelem, int *naxis,
+ long *naxes, int *status)
+\end{verbatim}
+
+
+
+\section{Utility Routines}
+
+
+\subsection{File Checksum Routines}
+
+The following routines either compute or validate the checksums for the
+CHDU. The DATASUM keyword is used to store the numerical value of the
+32-bit, 1's complement checksum for the data unit alone. If there is
+no data unit then the value is set to zero. The numerical value is
+stored as an ASCII string of digits, enclosed in quotes, because the
+value may be too large to represent as a 32-bit signed integer. The
+CHECKSUM keyword is used to store the ASCII encoded COMPLEMENT of the
+checksum for the entire HDU. Storing the complement, rather than the
+actual checksum, forces the checksum for the whole HDU to equal zero.
+If the file has been modified since the checksums were computed, then
+the HDU checksum will usually not equal zero. These checksum keyword
+conventions are based on a paper by Rob Seaman published in the
+proceedings of the ADASS IV conference in Baltimore in November 1994
+and a later revision in June 1995. See Appendix B for the definition
+of the parameters used in these routines.
+
+
+\begin{description}
+\item[1 ] Compute and write the DATASUM and CHECKSUM keyword values for the CHDU
+ into the current header. If the keywords already exist, their values
+ will be updated only if necessary (i.e., if the file
+ has been modified since the original keyword
+ values were computed). \label{ffpcks}
+\end{description}
+
+\begin{verbatim}
+ int fits_write_chksum / ffpcks
+ (fitsfile *fptr, > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[2 ] Update the CHECKSUM keyword value in the CHDU, assuming that the
+ DATASUM keyword exists and already has the correct value. This routine
+ calculates the new checksum for the current header unit, adds it to the
+ data unit checksum, encodes the value into an ASCII string, and writes
+ the string to the CHECKSUM keyword. \label{ffupck}
+\end{description}
+
+\begin{verbatim}
+ int fits_update_chksum / ffupck
+ (fitsfile *fptr, > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[3 ] Verify the CHDU by computing the checksums and comparing
+ them with the keywords. The data unit is verified correctly
+ if the computed checksum equals the value of the DATASUM
+ keyword. The checksum for the entire HDU (header plus data unit) is
+ correct if it equals zero. The output DATAOK and HDUOK parameters
+ in this routine are integers which will have a value = 1
+ if the data or HDU is verified correctly, a value = 0
+ if the DATASUM or CHECKSUM keyword is not present, or value = -1
+ if the computed checksum is not correct. \label{ffvcks}
+\end{description}
+
+\begin{verbatim}
+ int fits_verify_chksum / ffvcks
+ (fitsfile *fptr, > int *dataok, int *hduok, int *status)
+\end{verbatim}
+
+\begin{description}
+\item[4 ] Compute and return the checksum values for the CHDU
+ without creating or modifying the
+ CHECKSUM and DATASUM keywords. This routine is used internally by
+ ffvcks, but may be useful in other situations as well. \label{ffgcks}
+\end{description}
+
+\begin{verbatim}
+ int fits_get_chksum/ /ffgcks
+ (fitsfile *fptr, > unsigned long *datasum, unsigned long *hdusum,
+ int *status)
+\end{verbatim}
+
+\begin{description}
+\item[5 ] Encode a checksum value
+ into a 16-character string. If complm is non-zero (true) then the 32-bit
+ sum value will be complemented before encoding. \label{ffesum}
+\end{description}
+
+\begin{verbatim}
+ int fits_encode_chksum / ffesum
+ (unsigned long sum, int complm, > char *ascii);
+\end{verbatim}
+
+\begin{description}
+\item[6 ] Decode a 16-character checksum string into a unsigned long value.
+ If is non-zero (true). then the 32-bit sum value will be complemented
+ after decoding. The checksum value is also returned as the
+ value of the function. \label{ffdsum}
+\end{description}
+
+\begin{verbatim}
+ unsigned long fits_decode_chksum / ffdsum
+ (char *ascii, int complm, > unsigned long *sum);
+\end{verbatim}
+
+
+\subsection{Date and Time Utility Routines}
+
+The following routines help to construct or parse the FITS date/time
+strings. Starting in the year 2000, the FITS DATE keyword values (and
+the values of other `DATE-' keywords) must have the form 'YYYY-MM-DD'
+(date only) or 'YYYY-MM-DDThh:mm:ss.ddd...' (date and time) where the
+number of decimal places in the seconds value is optional. These times
+are in UTC. The older 'dd/mm/yy' date format may not be used for dates
+after 01 January 2000. See Appendix B for the definition of the
+parameters used in these routines.
+
+
+\begin{description}
+\item[1 ] Get the current system date. C already provides standard
+ library routines for getting the current date and time,
+ but this routine is provided for compatibility with
+ the Fortran FITSIO library. The returned year has 4 digits
+ (1999, 2000, etc.) \label{ffgsdt}
+\end{description}
+
+\begin{verbatim}
+ int fits_get_system_date/ffgsdt
+ ( > int *day, int *month, int *year, int *status )
+\end{verbatim}
+
+
+\begin{description}
+\item[2 ] Get the current system date and time string ('YYYY-MM-DDThh:mm:ss').
+The time will be in UTC/GMT if available, as indicated by a returned timeref
+value = 0. If the returned value of timeref = 1 then this indicates that
+it was not possible to convert the local time to UTC, and thus the local
+time was returned.
+\end{description}
+
+\begin{verbatim}
+ int fits_get_system_time/ffgstm
+ (> char *datestr, int *timeref, int *status)
+\end{verbatim}
+
+
+\begin{description}
+\item[3 ] Construct a date string from the input date values. If the year
+is between 1900 and 1998, inclusive, then the returned date string will
+have the old FITS format ('dd/mm/yy'), otherwise the date string will
+have the new FITS format ('YYYY-MM-DD'). Use fits\_time2str instead
+ to always return a date string using the new FITS format. \label{ffdt2s}
+\end{description}
+
+\begin{verbatim}
+ int fits_date2str/ffdt2s
+ (int year, int month, int day, > char *datestr, int *status)
+\end{verbatim}
+
+
+\begin{description}
+\item[4 ] Construct a new-format date + time string ('YYYY-MM-DDThh:mm:ss.ddd...').
+ If the year, month, and day values all = 0 then only the time is encoded
+ with format 'hh:mm:ss.ddd...'. The decimals parameter specifies how many
+ decimal places of fractional seconds to include in the string. If `decimals'
+ is negative, then only the date will be return ('YYYY-MM-DD').
+\end{description}
+
+\begin{verbatim}
+ int fits_time2str/fftm2s
+ (int year, int month, int day, int hour, int minute, double second,
+ int decimals, > char *datestr, int *status)
+\end{verbatim}
+
+
+\begin{description}
+\item[5 ] Return the date as read from the input string, where the string may be
+in either the old ('dd/mm/yy') or new ('YYYY-MM-DDThh:mm:ss' or
+'YYYY-MM-DD') FITS format. Null pointers may be supplied for any
+ unwanted output date parameters.
+\end{description}
+
+\begin{verbatim}
+ int fits_str2date/ffs2dt
+ (char *datestr, > int *year, int *month, int *day, int *status)
+\end{verbatim}
+
+
+\begin{description}
+\item[6 ] Return the date and time as read from the input string, where the
+string may be in either the old or new FITS format. The returned hours,
+minutes, and seconds values will be set to zero if the input string
+does not include the time ('dd/mm/yy' or 'YYYY-MM-DD') . Similarly,
+the returned year, month, and date values will be set to zero if the
+date is not included in the input string ('hh:mm:ss.ddd...'). Null
+pointers may be supplied for any unwanted output date and time
+parameters.
+\end{description}
+
+\begin{verbatim}
+ int fits_str2time/ffs2tm
+ (char *datestr, > int *year, int *month, int *day, int *hour,
+ int *minute, double *second, int *status)
+\end{verbatim}
+
+
+\subsection{General Utility Routines}
+
+The following utility routines may be useful for certain applications.
+
+
+\begin{description}
+\item[1 ] Return the revision number of the CFITSIO library.
+ The revision number will be incremented with each new
+ release of CFITSIO. \label{ffvers}
+\end{description}
+
+\begin{verbatim}
+ float fits_get_version / ffvers ( > float *version)
+\end{verbatim}
+
+\begin{description}
+\item[2 ] Write an 80-character message to the CFITSIO error stack. Application
+ programs should not normally write to the stack, but there may be
+ some situations where this is desirable. \label{ffpmsg}
+\end{description}
+
+\begin{verbatim}
+ void fits_write_errmsg / ffpmsg (char *err_msg)
+\end{verbatim}
+
+\begin{description}
+\item[3 ] Convert a character string to uppercase (operates in place). \label{ffupch}
+\end{description}
+
+\begin{verbatim}
+ void fits_uppercase / ffupch (char *string)
+\end{verbatim}
+
+\begin{description}
+\item[4 ] Compare the input template string against the reference string
+ to see if they match. The template string may contain wildcard
+ characters: '*' will match any sequence of characters (including
+ zero characters) and '\%' will match any single character in the
+ reference string. If casesen = CASESEN = TRUE then the match will be
+ case sensitive, otherwise the case of the letters will be ignored
+ if casesen = CASEINSEN = FALSE. The returned MATCH parameter will be
+ TRUE if the 2 strings match, and EXACT will be TRUE if the match is
+ exact (i.e., if no wildcard characters were used in the match).
+ Both strings must be 68 characters or less in length. \label{ffcmps}
+\end{description}
+
+\begin{verbatim}
+ void fits_compare_str / ffcmps
+ (char *templt, char *string, int casesen, > int *match, int *exact)
+\end{verbatim}
+
+\begin{description}
+\item[5 ]Split a string containing a list of names (typically file names or column
+ names) into individual name tokens by a sequence of calls to
+ fits\_split\_names. The names in the list must be delimited by a comma
+ and/or spaces. This routine ignores spaces and commas that occur
+ within parentheses, brackets, or curly brackets. It also strips any
+ leading and trailing blanks from the returned name.
+
+ This routine is similar to the ANSI C 'strtok' function:
+
+ The first call to fits\_split\_names has a non-null input string.
+ It finds the first name in the string and terminates it by overwriting
+ the next character of the string with a null terminator and returns a
+ pointer to the name. Each subsequent call, indicated by a NULL value
+ of the input string, returns the next name, searching from just past
+ the end of the previous name. It returns NULL when no further names
+ are found. \label{splitnames}
+\end{description}
+
+\begin{verbatim}
+ char *fits_split_names(char *namelist)
+\end{verbatim}
+ The following example shows how a string would be split into 3 names:
+
+\begin{verbatim}
+ myfile[1][bin (x,y)=4], file2.fits file3.fits
+ ^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^ ^^^^^^^^^^
+ 1st name 2nd name 3rd name
+\end{verbatim}
+
+\begin{description}
+\item[6 ] Test that the keyword name contains only legal characters (A-Z,0-9,
+ hyphen, and underscore) or that the keyword record contains only legal
+ printable ASCII characters \label{fftkey} \label{fftrec}
+\end{description}
+
+\begin{verbatim}
+ int fits_test_keyword / fftkey (char *keyname, > int *status)
+
+ int fits_test_record / fftrec (char *card, > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[7 ] Test whether the current header contains any NULL (ASCII 0) characters.
+ These characters are illegal in the header, but they will go undetected
+ by most of the CFITSIO keyword header routines, because the null is
+ interpreted as the normal end-of-string terminator. This routine returns
+ the position of the first null character in the header, or zero if there
+ are no nulls. For example a returned value of 110 would indicate that
+ the first NULL is located in the 30th character of the second keyword
+ in the header (recall that each header record is 80 characters long).
+ Note that this is one of the few CFITSIO routines in which the returned
+ value is not necessarily equal to the status value).
+ \label{ffnchk}
+\end{description}
+
+\begin{verbatim}
+ int fits_null_check / ffnchk (char *card, > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[8 ] Parse a header keyword record and return the name of the keyword,
+ and the length of the name.
+ The keyword name normally occupies the first 8 characters of the
+ record, except under the HIERARCH convention where the name can
+ be up to 70 characters in length. \label{ffgknm}
+\end{description}
+
+\begin{verbatim}
+ int fits_get_keyname / ffgknm
+ (char *card, > char *keyname, int *keylength, int *status)
+\end{verbatim}
+
+\begin{description}
+\item[9 ] Parse a header keyword record, returning the value (as
+ a literal character string) and comment strings. If the keyword has no
+ value (columns 9-10 not equal to '= '), then a null value string is
+ returned and the comment string is set equal to column 9 - 80 of the
+ input string. \label{ffpsvc}
+\end{description}
+
+\begin{verbatim}
+ int fits_parse_value / ffpsvc
+ (char *card, > char *value, char *comment, int *status)
+\end{verbatim}
+
+\begin{description}
+\item[10] Construct an array indexed keyword name (ROOT + nnn).
+ This routine appends the sequence number to the root string to create
+ a keyword name (e.g., 'NAXIS' + 2 = 'NAXIS2') \label{ffkeyn}
+\end{description}
+
+\begin{verbatim}
+ int fits_make_keyn / ffkeyn
+ (char *keyroot, int value, > char *keyname, int *status)
+\end{verbatim}
+
+\begin{description}
+\item[11] Construct a sequence keyword name (n + ROOT).
+ This routine concatenates the sequence number to the front of the
+ root string to create a keyword name (e.g., 1 + 'CTYP' = '1CTYP') \label{ffnkey}
+\end{description}
+
+\begin{verbatim}
+ int fits_make_nkey / ffnkey
+ (int value, char *keyroot, > char *keyname, int *status)
+\end{verbatim}
+
+\begin{description}
+\item[12] Determine the data type of a keyword value string. This routine
+ parses the keyword value string to determine its data type.
+ Returns 'C', 'L', 'I', 'F' or 'X', for character string, logical,
+ integer, floating point, or complex, respectively. \label{ffdtyp}
+\end{description}
+
+\begin{verbatim}
+ int fits_get_keytype / ffdtyp
+ (char *value, > char *dtype, int *status)
+\end{verbatim}
+
+\begin{description}
+\item[13] Return the class of an input header record. The record is classified
+ into one of the following categories (the class values are
+ defined in fitsio.h). Note that this is one of the few CFITSIO
+ routines that does not return a status value. \label{ffgkcl}
+\end{description}
+
+\begin{verbatim}
+ Class Value Keywords
+ TYP_STRUC_KEY 10 SIMPLE, BITPIX, NAXIS, NAXISn, EXTEND, BLOCKED,
+ GROUPS, PCOUNT, GCOUNT, END
+ XTENSION, TFIELDS, TTYPEn, TBCOLn, TFORMn, THEAP,
+ and the first 4 COMMENT keywords in the primary array
+ that define the FITS format.
+ TYP_CMPRS_KEY 20 The experimental keywords used in the compressed
+ image format ZIMAGE, ZCMPTYPE, ZNAMEn, ZVALn,
+ ZTILEn, ZBITPIX, ZNAXISn, ZSCALE, ZZERO, ZBLANK
+ TYP_SCAL_KEY 30 BSCALE, BZERO, TSCALn, TZEROn
+ TYP_NULL_KEY 40 BLANK, TNULLn
+ TYP_DIM_KEY 50 TDIMn
+ TYP_RANG_KEY 60 TLMINn, TLMAXn, TDMINn, TDMAXn, DATAMIN, DATAMAX
+ TYP_UNIT_KEY 70 BUNIT, TUNITn
+ TYP_DISP_KEY 80 TDISPn
+ TYP_HDUID_KEY 90 EXTNAME, EXTVER, EXTLEVEL, HDUNAME, HDUVER, HDULEVEL
+ TYP_CKSUM_KEY 100 CHECKSUM, DATASUM
+ TYP_WCS_KEY 110 CTYPEn, CUNITn, CRVALn, CRPIXn, CROTAn, CDELTn
+ CDj_is, PVj_ms, LONPOLEs, LATPOLEs
+ TCTYPn, TCTYns, TCUNIn, TCUNns, TCRVLn, TCRVns, TCRPXn,
+ TCRPks, TCDn_k, TCn_ks, TPVn_m, TPn_ms, TCDLTn, TCROTn
+ jCTYPn, jCTYns, jCUNIn, jCUNns, jCRVLn, jCRVns, iCRPXn,
+ iCRPns, jiCDn, jiCDns, jPVn_m, jPn_ms, jCDLTn, jCROTn
+ (i,j,m,n are integers, s is any letter)
+ TYP_REFSYS_KEY 120 EQUINOXs, EPOCH, MJD-OBSs, RADECSYS, RADESYSs
+ TYP_COMM_KEY 130 COMMENT, HISTORY, (blank keyword)
+ TYP_CONT_KEY 140 CONTINUE
+ TYP_USER_KEY 150 all other keywords
+
+ int fits_get_keyclass / ffgkcl (char *card)
+\end{verbatim}
+
+\begin{description}
+\item[14] Parse the 'TFORM' binary table column format string.
+ This routine parses the input TFORM character string and returns the
+ integer data type code, the repeat count of the field, and, in the case
+ of character string fields, the length of the unit string. See Appendix
+ B for the allowed values for the returned typecode parameter. A
+ null pointer may be given for any output parameters that are not needed. \label{ffbnfm}
+\end{description}
+
+\begin{verbatim}
+ int fits_binary_tform / ffbnfm
+ (char *tform, > int *typecode, long *repeat, long *width,
+ int *status)
+\end{verbatim}
+
+\begin{description}
+\item[15] Parse the 'TFORM' keyword value that defines the column format in
+ an ASCII table. This routine parses the input TFORM character
+ string and returns the data type code, the width of the column,
+ and (if it is a floating point column) the number of decimal places
+ to the right of the decimal point. The returned data type codes are
+ the same as for the binary table, with the following
+ additional rules: integer columns that are between 1 and 4 characters
+ wide are defined to be short integers (code = TSHORT). Wider integer
+ columns are defined to be regular integers (code = TLONG). Similarly,
+ Fixed decimal point columns (with TFORM = 'Fw.d') are defined to
+ be single precision reals (code = TFLOAT) if w is between 1 and 7 characters
+ wide, inclusive. Wider 'F' columns will return a double precision
+ data code (= TDOUBLE). 'Ew.d' format columns will have datacode = TFLOAT,
+ and 'Dw.d' format columns will have datacode = TDOUBLE. A null
+ pointer may be given for any output parameters that are not needed. \label{ffasfm}
+\end{description}
+
+\begin{verbatim}
+ int fits_ascii_tform / ffasfm
+ (char *tform, > int *typecode, long *width, int *decimals,
+ int *status)
+\end{verbatim}
+
+\begin{description}
+\item[16] Calculate the starting column positions and total ASCII table width
+ based on the input array of ASCII table TFORM values. The SPACE input
+ parameter defines how many blank spaces to leave between each column
+ (it is recommended to have one space between columns for better human
+ readability). \label{ffgabc}
+\end{description}
+
+\begin{verbatim}
+ int fits_get_tbcol / ffgabc
+ (int tfields, char **tform, int space, > long *rowlen,
+ long *tbcol, int *status)
+\end{verbatim}
+
+\begin{description}
+\item[17] Parse a template header record and return a formatted 80-character string
+ suitable for appending to (or deleting from) a FITS header file.
+ This routine is useful for parsing lines from an ASCII template file
+ and reformatting them into legal FITS header records. The formatted
+ string may then be passed to the fits\_write\_record, ffmcrd, or
+ fits\_delete\_key routines
+ to append or modify a FITS header record. \label{ffgthd}
+\end{description}
+
+\begin{verbatim}
+ int fits_parse_template / ffgthd
+ (char *templt, > char *card, int *keytype, int *status)
+\end{verbatim}
+ The input templt character string generally should contain 3 tokens:
+ (1) the KEYNAME, (2) the VALUE, and (3) the COMMENT string. The
+ TEMPLATE string must adhere to the following format:
+
+
+\begin{description}
+\item[- ] The KEYNAME token must begin in columns 1-8 and be a maximum of 8
+ characters long. A legal FITS keyword name may only
+ contain the characters A-Z, 0-9, and '-' (minus sign) and
+ underscore. This routine will automatically convert any lowercase
+ characters to uppercase in the output string. If the first 8 characters
+ of the template line are
+ blank then the remainder of the line is considered to be a FITS comment
+ (with a blank keyword name).
+\end{description}
+
+
+\begin{description}
+\item[- ] The VALUE token must be separated from the KEYNAME token by one or more
+ spaces and/or an '=' character. The data type of the VALUE token
+ (numeric, logical, or character string) is automatically determined
+ and the output CARD string is formatted accordingly. The value
+ token may be forced to be interpreted as a string (e.g. if it is a
+ string of numeric digits) by enclosing it in single quotes.
+\end{description}
+
+
+\begin{description}
+\item[- ] The COMMENT token is optional, but if present must be separated from
+ the VALUE token by at least one blank space and a '/' character.
+\end{description}
+
+
+\begin{description}
+\item[- ] One exception to the above rules is that if the first non-blank
+ character in the first 8 characters of the template string is a
+ minus sign ('-') followed
+ by a single token, or a single token followed by an equal sign,
+ then it is interpreted as the name of a keyword which is to be
+ deleted from the FITS header.
+\end{description}
+
+
+\begin{description}
+\item[- ] The second exception is that if the template string starts with
+ a minus sign and is followed by 2 tokens (without an equals sign between
+ them) then the second token
+ is interpreted as the new name for the keyword specified by
+ first token. In this case the old keyword name (first token)
+ is returned in characters 1-8 of the returned CARD string, and
+ the new keyword name (the second token) is returned in characters
+ 41-48 of the returned CARD string. These old and new names
+ may then be passed to the ffmnam routine which will change
+ the keyword name.
+\end{description}
+
+ The keytype output parameter indicates how the returned CARD string
+ should be interpreted:
+
+\begin{verbatim}
+ keytype interpretation
+ ------- -------------------------------------------------
+ -2 Rename the keyword with name = the first 8 characters of CARD
+ to the new name given in characters 41 - 48 of CARD.
+
+ -1 delete the keyword with this name from the FITS header.
+
+ 0 append the CARD string to the FITS header if the
+ keyword does not already exist, otherwise update
+ the keyword value and/or comment field if is already exists.
+
+ 1 This is a HISTORY or COMMENT keyword; append it to the header
+
+ 2 END record; do not explicitly write it to the FITS file.
+\end{verbatim}
+ EXAMPLES: The following lines illustrate valid input template strings:
+
+\begin{verbatim}
+ INTVAL 7 / This is an integer keyword
+ RVAL 34.6 / This is a floating point keyword
+ EVAL=-12.45E-03 / This is a floating point keyword in exponential notation
+ lval F / This is a boolean keyword
+ This is a comment keyword with a blank keyword name
+ SVAL1 = 'Hello world' / this is a string keyword
+ SVAL2 '123.5' this is also a string keyword
+ sval3 123+ / this is also a string keyword with the value '123+ '
+ # the following template line deletes the DATE keyword
+ - DATE
+ # the following template line modifies the NAME keyword to OBJECT
+ - NAME OBJECT
+\end{verbatim}
+
+\begin{description}
+\item[18] Parse the input string containing a list of rows or row ranges, and
+ return integer arrays containing the first and last row in each
+ range. For example, if rowlist = "3-5, 6, 8-9" then it will
+ return numranges = 3, rangemin = 3, 6, 8 and rangemax = 5, 6, 9.
+ At most, 'maxranges' number of ranges will be returned. 'maxrows'
+ is the maximum number of rows in the table; any rows or ranges
+ larger than this will be ignored. The rows must be specified in
+ increasing order, and the ranges must not overlap. A minus sign
+ may be use to specify all the rows to the upper or lower bound, so
+ "50-" means all the rows from 50 to the end of the table, and "-"
+ means all the rows in the table, from 1 - maxrows.
+ \label{ffrwrg}
+\end{description}
+
+\begin{verbatim}
+ int fits_parse_range / ffrwrg(char *rowlist, long maxrows, int maxranges, >
+ int *numranges, long *rangemin, long *rangemax, int *status)
+\end{verbatim}
+
+\begin{description}
+\item[19] Check that the Header fill bytes (if any) are all blank. These are the bytes
+ that may follow END keyword and before the beginning of data unit,
+ or the end of the HDU if there is no data unit.
+ \label{ffchfl}
+\end{description}
+
+\begin{verbatim}
+ int ffchfl(fitsfile *fptr, > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[20] Check that the Data fill bytes (if any) are all zero (for IMAGE or
+ BINARY Table HDU) or all blanks (for ASCII table HDU). These file
+ bytes may be located after the last valid data byte in the HDU and
+ before the physical end of the HDU.
+ \label{ffcdfl}
+\end{description}
+
+\begin{verbatim}
+ int ffcdfl(fitsfile *fptr, > int *status)
+\end{verbatim}
+
+\chapter{ The CFITSIO Iterator Function }
+
+The fits\_iterate\_data function in CFITSIO provides a unique method of
+executing an arbitrary user-supplied `work' function that operates on
+rows of data in FITS tables or on pixels in FITS images. Rather than
+explicitly reading and writing the FITS images or columns of data, one
+instead calls the CFITSIO iterator routine, passing to it the name of
+the user's work function that is to be executed along with a list of
+all the table columns or image arrays that are to be passed to the work
+function. The CFITSIO iterator function then does all the work of
+allocating memory for the arrays, reading the input data from the FITS
+file, passing them to the work function, and then writing any output
+data back to the FITS file after the work function exits. Because
+it is often more efficient to process only a subset of the total table
+rows at one time, the iterator function can determine the optimum
+amount of data to pass in each iteration and repeatly call the work
+function until the entire table been processed.
+
+For many applications this single CFITSIO iterator function can
+effectively replace all the other CFITSIO routines for reading or
+writing data in FITS images or tables. Using the iterator has several
+important advantages over the traditional method of reading and writing
+FITS data files:
+
+\begin{itemize}
+\item
+It cleanly separates the data I/O from the routine that operates on
+the data. This leads to a more modular and `object oriented'
+programming style.
+
+\item
+It simplifies the application program by eliminating the need to allocate
+memory for the data arrays and eliminates most of the calls to the CFITSIO
+routines that explicitly read and write the data.
+
+\item
+It ensures that the data are processed as efficiently as possible.
+This is especially important when processing tabular data since
+the iterator function will calculate the most efficient number
+of rows in the table to be passed at one time to the user's work
+function on each iteration.
+
+\item
+Makes it possible for larger projects to develop a library of work
+functions that all have a uniform calling sequence and are all
+independent of the details of the FITS file format.
+
+\end{itemize}
+
+There are basically 2 steps in using the CFITSIO iterator function.
+The first step is to design the work function itself which must have a
+prescribed set of input parameters. One of these parameters is a
+structure containing pointers to the arrays of data; the work function
+can perform any desired operations on these arrays and does not need to
+worry about how the input data were read from the file or how the
+output data get written back to the file.
+
+The second step is to design the driver routine that opens all the
+necessary FITS files and initializes the input parameters to the
+iterator function. The driver program calls the CFITSIO iterator
+function which then reads the data and passes it to the user's work
+function.
+
+The following 2 sections describe these steps in more detail. There
+are also several example programs included with the CFITSIO
+distribution which illustrate how to use the iterator function.
+
+
+\section{The Iterator Work Function}
+
+The user-supplied iterator work function must have the following set of
+input parameters (the function can be given any desired name):
+
+
+\begin{verbatim}
+ int user_fn( long totaln, long offset, long firstn, long nvalues,
+ int narrays, iteratorCol *data, void *userPointer )
+\end{verbatim}
+
+\begin{itemize}
+
+\item
+ totaln -- the total number of table rows or image pixels
+ that will be passed to the work function
+ during 1 or more iterations.
+
+\item
+ offset -- the offset applied to the first table row or image
+ pixel to be passed to the work function. In other
+ words, this is the number of rows or pixels that
+ are skipped over before starting the iterations. If
+ offset = 0, then all the table rows or image pixels
+ will be passed to the work function.
+
+\item
+ firstn -- the number of the first table row or image pixel
+ (starting with 1) that is being passed in this
+ particular call to the work function.
+
+\item
+ nvalues -- the number of table rows or image pixels that are
+ being passed in this particular call to the work
+ function. nvalues will always be less than or
+ equal to totaln and will have the same value on
+ each iteration, except possibly on the last
+ call which may have a smaller value.
+
+\item
+ narrays -- the number of arrays of data that are being passed
+ to the work function. There is one array for each
+ image or table column.
+
+\item
+ *data -- array of structures, one for each
+ column or image. Each structure contains a pointer
+ to the array of data as well as other descriptive
+ parameters about that array.
+
+\item
+ *userPointer -- a user supplied pointer that can be used
+ to pass ancillary information from the driver function
+ to the work function.
+ This pointer is passed to the CFITSIO iterator function
+ which then passes it on to the
+ work function without any modification.
+ It may point to a single number, to an array of values,
+ to a structure containing an arbitrary set of parameters
+ of different types,
+ or it may be a null pointer if it is not needed.
+ The work function must cast this pointer to the
+ appropriate data type before using it it.
+\end{itemize}
+
+The totaln, offset, narrays, data, and userPointer parameters are
+guaranteed to have the same value on each iteration. Only firstn,
+nvalues, and the arrays of data pointed to by the data structures may
+change on each iterative call to the work function.
+
+Note that the iterator treats an image as a long 1-D array of pixels
+regardless of it's intrinsic dimensionality. The total number of
+pixels is just the product of the size of each dimension, and the order
+of the pixels is the same as the order that they are stored in the FITS
+file. If the work function needs to know the number and size of the
+image dimensions then these parameters can be passed via the
+userPointer structure.
+
+The iteratorCol structure is currently defined as follows:
+
+\begin{verbatim}
+typedef struct /* structure for the iterator function column information */
+{
+ /* structure elements required as input to fits_iterate_data: */
+
+ fitsfile *fptr; /* pointer to the HDU containing the column or image */
+ int colnum; /* column number in the table; ignored for images */
+ char colname[70]; /* name (TTYPEn) of the column; null for images */
+ int datatype; /* output data type (converted if necessary) */
+ int iotype; /* type: InputCol, InputOutputCol, or OutputCol */
+
+ /* output structure elements that may be useful for the work function: */
+
+ void *array; /* pointer to the array (and the null value) */
+ long repeat; /* binary table vector repeat value; set */
+ /* equal to 1 for images */
+ long tlmin; /* legal minimum data value, if any */
+ long tlmax; /* legal maximum data value, if any */
+ char unit[70]; /* physical unit string (BUNIT or TUNITn) */
+ char tdisp[70]; /* suggested display format; null if none */
+
+} iteratorCol;
+\end{verbatim}
+
+Instead of directly reading or writing the elements in this structure,
+it is recommended that programmers use the access functions that are
+provided for this purpose.
+
+The first five elements in this structure must be initially defined by
+the driver routine before calling the iterator routine. The CFITSIO
+iterator routine uses this information to determine what column or
+array to pass to the work function, and whether the array is to be
+input to the work function, output from the work function, or both.
+The CFITSIO iterator function fills in the values of the remaining
+structure elements before passing it to the work function.
+
+The array structure element is a pointer to the actual data array and
+it must be cast to the correct data type before it is used. The
+`repeat' structure element give the number of data values in each row
+of the table, so that the total number of data values in the array is
+given by repeat * nvalues. In the case of image arrays and ASCII
+tables, repeat will always be equal to 1. When the data type is a
+character string, the array pointer is actually a pointer to an array
+of string pointers (i.e., char **array). The other output structure
+elements are provided for convenience in case that information is
+needed within the work function. Any other information may be passed
+from the driver routine to the work function via the userPointer
+parameter.
+
+Upon completion, the work routine must return an integer status value,
+with 0 indicating success and any other value indicating an error which
+will cause the iterator function to immediately exit at that point. Return status
+values in the range 1 -- 1000 should be avoided since these are
+reserved for use by CFITSIO. A return status value of -1 may be used to
+force the CFITSIO iterator function to stop at that point and return
+control to the driver routine after writing any output arrays to the
+FITS file. CFITSIO does not considered this to be an error condition,
+so any further processing by the application program will continue normally.
+
+
+\section{The Iterator Driver Function}
+
+The iterator driver function must open the necessary FITS files and
+position them to the correct HDU. It must also initialize the following
+parameters in the iteratorCol structure (defined above) for each
+column or image before calling the CFITSIO iterator function.
+Several `constructor' routines are provided in CFITSIO for this
+purpose.
+
+\begin{itemize}
+\item
+ *fptr -- The fitsfile pointer to the table or image.
+\item
+colnum -- the number of the column in the table. This value is ignored
+ in the case of images. If colnum equals 0, then the column name
+ will be used to identify the column to be passed to the
+ work function.
+
+\item
+colname -- the name (TTYPEn keyword) of the column. This is
+ only required if colnum = 0 and is ignored for images.
+\item
+datatype -- The desired data type of the array to be passed to the
+ work function. For numerical data the data type does
+ not need to be the same as the actual data type in the
+ FITS file, in which case CFITSIO will do the conversion.
+ Allowed values are: TSTRING, TLOGICAL, TBYTE, TSBYTE, TSHORT, TUSHORT,
+ TINT, TLONG, TULONG, TFLOAT, TDOUBLE. If the input
+ value of data type equals 0, then the existing
+ data type of the column or image will be used without
+ any conversion.
+
+\item
+iotype -- defines whether the data array is to be input to the
+ work function (i.e, read from the FITS file), or output
+ from the work function (i.e., written to the FITS file) or
+ both. Allowed values are InputCol, OutputCol, or InputOutputCol.
+ Variable-length array columns are supported as InputCol or
+ InputOutputCol types, but may not be used for an OutputCol type.
+\end{itemize}
+
+After the driver routine has initialized all these parameters, it
+can then call the CFITSIO iterator function:
+
+
+\begin{verbatim}
+ int fits_iterate_data(int narrays, iteratorCol *data, long offset,
+ long nPerLoop, int (*workFn)( ), void *userPointer, int *status);
+\end{verbatim}
+
+\begin{itemize}
+\item
+
+ narrays -- the number of columns or images that are to be passed
+ to the work function.
+\item
+ *data -- pointer to array of structures containing information
+ about each column or image.
+
+\item
+ offset -- if positive, this number of rows at the
+ beginning of the table (or pixels in the image)
+ will be skipped and will not be passed to the work
+ function.
+
+\item
+ nPerLoop - specifies the number of table rows (or number of
+ image pixels) that are to be passed to the work
+ function on each iteration. If nPerLoop = 0
+ then CFITSIO will calculate the optimum number
+ for greatest efficiency.
+ If nPerLoop is negative, then all the rows
+ or pixels will be passed at one time, and the work
+ function will only be called once. If any variable
+ length arrays are being processed, then the nPerLoop
+ value is ignored, and the iterator will always process
+ one row of the table at a time.
+
+\item
+ *workFn - the name (actually the address) of the work function
+ that is to be called by fits\_iterate\_data.
+
+\item
+ *userPointer - this is a user supplied pointer that can be used
+ to pass ancillary information from the driver routine
+ to the work function. It may point to a single number,
+ an array, or to a structure containing an arbitrary set
+ of parameters.
+
+\item
+ *status - The CFITSIO error status. Should = 0 on input;
+ a non-zero output value indicates an error.
+\end{itemize}
+
+When fits\_iterate\_data is called it first allocates memory to hold
+all the requested columns of data or image pixel arrays. It then reads
+the input data from the FITS tables or images into the arrays then
+passes the structure with pointers to these data arrays to the work
+function. After the work function returns, the iterator function
+writes any output columns of data or images back to the FITS files. It
+then repeats this process for any remaining sets of rows or image
+pixels until it has processed the entire table or image or until the
+work function returns a non-zero status value. The iterator then frees
+the memory that it initially allocated and returns control to the
+driver routine that called it.
+
+
+\section{Guidelines for Using the Iterator Function}
+
+The totaln, offset, firstn, and nvalues parameters that are passed to
+the work function are useful for determining how much of the data has
+been processed and how much remains left to do. On the very first call
+to the work function firstn will be equal to offset + 1; the work
+function may need to perform various initialization tasks before
+starting to process the data. Similarly, firstn + nvalues - 1 will be
+equal to totaln on the last iteration, at which point the work function
+may need to perform some clean up operations before exiting for the
+last time. The work function can also force an early termination of
+the iterations by returning a status value = -1.
+
+The narrays and iteratorCol.datatype arguments allow the work function
+to double check that the number of input arrays and their data types
+have the expected values. The iteratorCol.fptr and iteratorCol.colnum
+structure elements can be used if the work function needs to read or
+write the values of other keywords in the FITS file associated with
+the array. This should generally only be done during the
+initialization step or during the clean up step after the last set of
+data has been processed. Extra FITS file I/O during the main
+processing loop of the work function can seriously degrade the speed of
+the program.
+
+If variable-length array columns are being processed, then the iterator
+will operate on one row of the table at a time. In this case the
+the repeat element in the interatorCol structure will be set equal to
+the number of elements in the current row that is being processed.
+
+One important feature of the iterator is that the first element in each
+array that is passed to the work function gives the value that is used
+to represent null or undefined values in the array. The real data then
+begins with the second element of the array (i.e., array[1], not
+array[0]). If the first array element is equal to zero, then this
+indicates that all the array elements have defined values and there are
+no undefined values. If array[0] is not equal to zero, then this
+indicates that some of the data values are undefined and this value
+(array[0]) is used to represent them. In the case of output arrays
+(i.e., those arrays that will be written back to the FITS file by the
+iterator function after the work function exits) the work function must
+set the first array element to the desired null value if necessary,
+otherwise the first element should be set to zero to indicate that
+there are no null values in the output array. CFITSIO defines 2
+values, FLOATNULLVALUE and DOUBLENULLVALUE, that can be used as default
+null values for float and double data types, respectively. In the case
+of character string data types, a null string is always used to
+represent undefined strings.
+
+In some applications it may be necessary to recursively call the iterator
+function. An example of this is given by one of the example programs
+that is distributed with CFITSIO: it first calls a work function that
+writes out a 2D histogram image. That work function in turn calls
+another work function that reads the `X' and `Y' columns in a table to
+calculate the value of each 2D histogram image pixel. Graphically, the
+program structure can be described as:
+
+\begin{verbatim}
+ driver --> iterator --> work1_fn --> iterator --> work2_fn
+\end{verbatim}
+
+Finally, it should be noted that the table columns or image arrays that
+are passed to the work function do not all have to come from the same
+FITS file and instead may come from any combination of sources as long
+as they have the same length. The length of the first table column or
+image array is used by the iterator if they do not all have the same
+length.
+
+
+\section{Complete List of Iterator Routines}
+
+All of the iterator routines are listed below. Most of these routines
+do not have a corresponding short function name.
+
+
+\begin{description}
+\item[1 ] Iterator `constructor' functions that set
+ the value of elements in the iteratorCol structure
+ that define the columns or arrays. These set the fitsfile
+ pointer, column name, column number, datatype, and iotype,
+ respectively. The last 2 routines allow all the parameters
+ to be set with one function call (one supplies the column
+ name, the other the column number). \label{ffiterset}
+\end{description}
+
+
+\begin{verbatim}
+ int fits_iter_set_file(iteratorCol *col, fitsfile *fptr);
+
+ int fits_iter_set_colname(iteratorCol *col, char *colname);
+
+ int fits_iter_set_colnum(iteratorCol *col, int colnum);
+
+ int fits_iter_set_datatype(iteratorCol *col, int datatype);
+
+ int fits_iter_set_iotype(iteratorCol *col, int iotype);
+
+ int fits_iter_set_by_name(iteratorCol *col, fitsfile *fptr,
+ char *colname, int datatype, int iotype);
+
+ int fits_iter_set_by_num(iteratorCol *col, fitsfile *fptr,
+ int colnum, int datatype, int iotype);
+\end{verbatim}
+
+\begin{description}
+\item[2 ] Iterator `accessor' functions that return the value of the
+ element in the iteratorCol structure
+ that describes a particular data column or array \label{ffiterget}
+\end{description}
+
+\begin{verbatim}
+ fitsfile * fits_iter_get_file(iteratorCol *col);
+
+ char * fits_iter_get_colname(iteratorCol *col);
+
+ int fits_iter_get_colnum(iteratorCol *col);
+
+ int fits_iter_get_datatype(iteratorCol *col);
+
+ int fits_iter_get_iotype(iteratorCol *col);
+
+ void * fits_iter_get_array(iteratorCol *col);
+
+ long fits_iter_get_tlmin(iteratorCol *col);
+
+ long fits_iter_get_tlmax(iteratorCol *col);
+
+ long fits_iter_get_repeat(iteratorCol *col);
+
+ char * fits_iter_get_tunit(iteratorCol *col);
+
+ char * fits_iter_get_tdisp(iteratorCol *col);
+\end{verbatim}
+
+\begin{description}
+\item[3 ] The CFITSIO iterator function \label{ffiter}
+\end{description}
+
+\begin{verbatim}
+ int fits_iterate_data(int narrays, iteratorCol *data, long offset,
+ long nPerLoop,
+ int (*workFn)( long totaln, long offset, long firstn,
+ long nvalues, int narrays, iteratorCol *data,
+ void *userPointer),
+ void *userPointer,
+ int *status);
+\end{verbatim}
+
+\chapter{ Celestial Coordinate System Routines }
+
+The FITS community has adopted a set of keyword conventions that define
+the transformations needed to convert between pixel locations in an
+image and the corresponding celestial coordinates on the sky, or more
+generally, that define world coordinates that are to be associated with
+any pixel location in an n-dimensional FITS array. CFITSIO is distributed
+with a couple of self-contained World Coordinate System (WCS) routines,
+however, these routines DO NOT support all the latest WCS conventions,
+so it is STRONGLY RECOMMENDED that software developers use a more robust
+external WCS library. Several recommended libraries are:
+
+
+\begin{verbatim}
+ WCSLIB - supported by Mark Calabretta
+ WCSTools - supported by Doug Mink
+ AST library - developed by the U.K. Starlink project
+\end{verbatim}
+
+More information about the WCS keyword conventions and links to all of
+these WCS libraries can be found on the FITS Support Office web site at
+http://fits.gsfc.nasa.gov under the WCS link.
+
+The functions provided in these external WCS libraries will need
+access to the WCS information contained in the FITS file headers.
+One convenient way to pass this information to the extermal library is
+to use the fits\_hdr2str routine in CFITSIO (defined below) to copy the
+header keywords into one long string, and then pass this string to an
+interface routine in the external library that will extract
+the necessary WCS information (e.g., see the astFitsChan and astPutCards
+routines in the Starlink AST library).
+
+
+\begin{description}
+\item[1 ] Concatenate the header keywords in the CHDU into a single long
+ string of characters. Each 80-character fixed-length keyword
+ record is appended to the output character string, in order, with
+ no intervening separator or terminating characters. The last header
+ record is terminated with a NULL character. This routine allocates
+ memory for the returned character array, so the calling program must
+ free the memory when finished.
+
+ Selected keywords may be excluded from the returned character string.
+ If the second parameter (nocomments) is TRUE (nonzero) then any
+ COMMENT, HISTORY, or blank keywords in the header will not be copied
+ to the output string.
+
+ The 'exclist' parameter may be used to supply a list of keywords
+ that are to be excluded from the output character string. Wild card
+ characters (*, ?, and \#) may be used in the excluded keyword names.
+ If no additional keywords are to be excluded, then set nexc = 0 and
+ specify NULL for the the **header parameter. \label{hdr2str}
+\end{description}
+
+\begin{verbatim}
+ int fits_hdr2str
+ (fitsfile *fptr, int nocomments, char **exclist, int nexc,
+ > char **header, int *nkeys, int *status)
+\end{verbatim}
+
+
+\section{ Self-contained WCS Routines}
+
+The following routines DO NOT support the more recent WCS conventions
+that have been approved as part of the FITS standard. Consequently,
+the following routines ARE NOW DEPRECATED. It is STRONGLY RECOMMENDED
+that software developers not use these routines, and instead use an
+external WCS library, as described in the previous section.
+
+These routines are included mainly for backward compatibility with
+existing software. They support the following standard map
+projections: -SIN, -TAN, -ARC, -NCP, -GLS, -MER, and -AIT (these are the
+legal values for the coordtype parameter). These routines are based
+on similar functions in Classic AIPS. All the angular quantities are
+given in units of degrees.
+
+
+\begin{description}
+\item[1 ] Get the values of the basic set of standard FITS celestial coordinate
+ system keywords from the header of a FITS image (i.e., the primary
+ array or an IMAGE extension). These values may then be passed to
+ the fits\_pix\_to\_world and fits\_world\_to\_pix routines that
+ perform the coordinate transformations. If any or all of the WCS
+ keywords are not present, then default values will be returned. If
+ the first coordinate axis is the declination-like coordinate, then
+ this routine will swap them so that the longitudinal-like coordinate
+ is returned as the first axis.
+
+ If the file uses the newer 'CDj\_i' WCS transformation matrix
+ keywords instead of old style 'CDELTn' and 'CROTA2' keywords, then
+ this routine will calculate and return the values of the equivalent
+ old-style keywords. Note that the conversion from the new-style
+ keywords to the old-style values is sometimes only an
+ approximation, so if the approximation is larger than an internally
+ defined threshold level, then CFITSIO will still return the
+ approximate WCS keyword values, but will also return with status =
+ APPROX\_WCS\_KEY, to warn the calling program that approximations
+ have been made. It is then up to the calling program to decide
+ whether the approximations are sufficiently accurate for the
+ particular application, or whether more precise WCS transformations
+ must be performed using new-style WCS keywords directly. \label{ffgics}
+\end{description}
+
+\begin{verbatim}
+ int fits_read_img_coord / ffgics
+ (fitsfile *fptr, > double *xrefval, double *yrefval,
+ double *xrefpix, double *yrefpix, double *xinc, double *yinc,
+ double *rot, char *coordtype, int *status)
+\end{verbatim}
+
+\begin{description}
+\item[2 ] Get the values of the standard FITS celestial coordinate system
+ keywords from the header of a FITS table where the X and Y (or RA
+ and DEC) coordinates are stored in 2 separate columns of the table
+ (as in the Event List table format that is often used by high energy
+ astrophysics missions). These values may then be passed to the
+ fits\_pix\_to\_world and fits\_world\_to\_pix routines that perform
+ the coordinate transformations. \label{ffgtcs}
+\end{description}
+
+\begin{verbatim}
+ int fits_read_tbl_coord / ffgtcs
+ (fitsfile *fptr, int xcol, int ycol, > double *xrefval,
+ double *yrefval, double *xrefpix, double *yrefpix, double *xinc,
+ double *yinc, double *rot, char *coordtype, int *status)
+\end{verbatim}
+
+\begin{description}
+\item[3 ] Calculate the celestial coordinate corresponding to the input
+ X and Y pixel location in the image. \label{ffwldp}
+\end{description}
+
+\begin{verbatim}
+ int fits_pix_to_world / ffwldp
+ (double xpix, double ypix, double xrefval, double yrefval,
+ double xrefpix, double yrefpix, double xinc, double yinc,
+ double rot, char *coordtype, > double *xpos, double *ypos,
+ int *status)
+\end{verbatim}
+
+\begin{description}
+\item[4 ] Calculate the X and Y pixel location corresponding to the input
+ celestial coordinate in the image. \label{ffxypx}
+\end{description}
+
+\begin{verbatim}
+ int fits_world_to_pix / ffxypx
+ (double xpos, double ypos, double xrefval, double yrefval,
+ double xrefpix, double yrefpix, double xinc, double yinc,
+ double rot, char *coordtype, > double *xpix, double *ypix,
+ int *status)
+\end{verbatim}
+
+
+\chapter{ Hierarchical Grouping Routines }
+
+These functions allow for the creation and manipulation of FITS HDU
+Groups, as defined in "A Hierarchical Grouping Convention for FITS" by
+Jennings, Pence, Folk and Schlesinger ( http:
+//adfwww.gsfc.nasa.gov/other/convert/group.html ). A group is a
+collection of HDUs whose association is defined by a {\it grouping
+table}. HDUs which are part of a group are referred to as {\it member
+HDUs} or simply as {\it members}. Grouping table member HDUs may
+themselves be grouping tables, thus allowing for the construction of
+open-ended hierarchies of HDUs.
+
+Grouping tables contain one row for each member HDU. The grouping table
+columns provide identification information that allows applications to
+reference or "point to" the member HDUs. Member HDUs are expected, but
+not required, to contain a set of GRPIDn/GRPLCn keywords in their
+headers for each grouping table that they are referenced by. In this
+sense, the GRPIDn/GRPLCn keywords "link" the member HDU back to its
+Grouping table. Note that a member HDU need not reside in the same FITS
+file as its grouping table, and that a given HDU may be referenced by
+up to 999 grouping tables simultaneously.
+
+Grouping tables are implemented as FITS binary tables with up to six
+pre-defined column TTYPEn values: 'MEMBER\_XTENSION', 'MEMBER\_NAME',
+'MEMBER\_VERSION', 'MEMBER\_POSITION', 'MEMBER\_URI\_TYPE' and 'MEMBER\_LOCATION'.
+The first three columns allow member HDUs to be identified by reference to
+their XTENSION, EXTNAME and EXTVER keyword values. The fourth column allows
+member HDUs to be identified by HDU position within their FITS file.
+The last two columns identify the FITS file in which the member HDU resides,
+if different from the grouping table FITS file.
+
+Additional user defined "auxiliary" columns may also be included with any
+grouping table. When a grouping table is copied or modified the presence of
+auxiliary columns is always taken into account by the grouping support
+functions; however, the grouping support functions cannot directly
+make use of this data.
+
+If a grouping table column is defined but the corresponding member HDU
+information is unavailable then a null value of the appropriate data type
+is inserted in the column field. Integer columns (MEMBER\_POSITION,
+MEMBER\_VERSION) are defined with a TNULLn value of zero (0). Character field
+columns (MEMBER\_XTENSION, MEMBER\_NAME, MEMBER\_URI\_TYPE, MEMBER\_LOCATION)
+utilize an ASCII null character to denote a null field value.
+
+The grouping support functions belong to two basic categories: those that
+work with grouping table HDUs (ffgt**) and those that work with member HDUs
+(ffgm**). Two functions, fits\_copy\_group() and fits\_remove\_group(), have the
+option to recursively copy/delete entire groups. Care should be taken when
+employing these functions in recursive mode as poorly defined groups could
+cause unpredictable results. The problem of a grouping table directly or
+indirectly referencing itself (thus creating an infinite loop) is protected
+against; in fact, neither function will attempt to copy or delete an HDU
+twice.
+
+
+\section{Grouping Table Routines}
+
+
+\begin{description}
+\item[1 ]Create (append) a grouping table at the end of the current FITS file
+ pointed to by fptr. The grpname parameter provides the grouping table
+ name (GRPNAME keyword value) and may be set to NULL if no group name
+ is to be specified. The grouptype parameter specifies the desired
+ structure of the grouping table and may take on the values:
+ GT\_ID\_ALL\_URI (all columns created), GT\_ID\_REF (ID by reference columns),
+ GT\_ID\_POS (ID by position columns), GT\_ID\_ALL (ID by reference and
+ position columns), GT\_ID\_REF\_URI (ID by reference and FITS file URI
+ columns), and GT\_ID\_POS\_URI (ID by position and FITS file URI columns). \label{ffgtcr}
+\end{description}
+
+\begin{verbatim}
+ int fits_create_group / ffgtcr
+ (fitsfile *fptr, char *grpname, int grouptype, > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[2 ]Create (insert) a grouping table just after the CHDU of the current FITS
+ file pointed to by fptr. All HDUs below the the insertion point will be
+ shifted downwards to make room for the new HDU. The grpname parameter
+ provides the grouping table name (GRPNAME keyword value) and may be set to
+ NULL if no group name is to be specified. The grouptype parameter specifies
+ the desired structure of the grouping table and may take on the values:
+ GT\_ID\_ALL\_URI (all columns created), GT\_ID\_REF (ID by reference columns),
+ GT\_ID\_POS (ID by position columns), GT\_ID\_ALL (ID by reference and
+ position columns), GT\_ID\_REF\_URI (ID by reference and FITS file URI
+ columns), and GT\_ID\_POS\_URI (ID by position and FITS file URI columns) \label{ffgtis}.
+\end{description}
+
+\begin{verbatim}
+ int fits_insert_group / ffgtis
+ (fitsfile *fptr, char *grpname, int grouptype, > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[3 ]Change the structure of an existing grouping table pointed to by
+ gfptr. The grouptype parameter (see fits\_create\_group() for valid
+ parameter values) specifies the new structure of the grouping table. This
+ function only adds or removes grouping table columns, it does not add
+ or delete group members (i.e., table rows). If the grouping table already
+ has the desired structure then no operations are performed and function
+ simply returns with a (0) success status code. If the requested structure
+ change creates new grouping table columns, then the column values for all
+ existing members will be filled with the null values appropriate to the
+ column type. \label{ffgtch}
+\end{description}
+
+\begin{verbatim}
+ int fits_change_group / ffgtch
+ (fitsfile *gfptr, int grouptype, > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[4 ]Remove the group defined by the grouping table pointed to by gfptr, and
+ optionally all the group member HDUs. The rmopt parameter specifies the
+ action to be taken for
+ all members of the group defined by the grouping table. Valid values are:
+ OPT\_RM\_GPT (delete only the grouping table) and OPT\_RM\_ALL (recursively
+ delete all HDUs that belong to the group). Any groups containing the
+ grouping table gfptr as a member are updated, and if rmopt == OPT\_RM\_GPT
+ all members have their GRPIDn and GRPLCn keywords updated accordingly.
+ If rmopt == OPT\_RM\_ALL, then other groups that contain the deleted members
+ of gfptr are updated to reflect the deletion accordingly. \label{ffgtrm}
+\end{description}
+
+\begin{verbatim}
+ int fits_remove_group / ffgtrm
+ (fitsfile *gfptr, int rmopt, > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[5 ]Copy (append) the group defined by the grouping table pointed to by infptr,
+ and optionally all group member HDUs, to the FITS file pointed to by
+ outfptr. The cpopt parameter specifies the action to be taken for all
+ members of the group infptr. Valid values are: OPT\_GCP\_GPT (copy only
+ the grouping table) and OPT\_GCP\_ALL (recursively copy ALL the HDUs that
+ belong to the group defined by infptr). If the cpopt == OPT\_GCP\_GPT then
+ the members of infptr have their GRPIDn and GRPLCn keywords updated to
+ reflect the existence of the new grouping table outfptr, since they now
+ belong to the new group. If cpopt == OPT\_GCP\_ALL then the new
+ grouping table outfptr only contains pointers to the copied member HDUs
+ and not the original member HDUs of infptr. Note that, when
+ cpopt == OPT\_GCP\_ALL, all members of the group defined by infptr will be
+ copied to a single FITS file pointed to by outfptr regardless of their
+ file distribution in the original group. \label{ffgtcp}
+\end{description}
+
+\begin{verbatim}
+ int fits_copy_group / ffgtcp
+ (fitsfile *infptr, fitsfile *outfptr, int cpopt, > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[6 ] Merge the two groups defined by the grouping table HDUs infptr and outfptr
+ by combining their members into a single grouping table. All member HDUs
+ (rows) are copied from infptr to outfptr. If mgopt == OPT\_MRG\_COPY then
+ infptr continues to exist unaltered after the merge. If the mgopt ==
+ OPT\_MRG\_MOV then infptr is deleted after the merge. In both cases,
+ the GRPIDn and GRPLCn keywords of the member HDUs are updated accordingly. \label{ffgtmg}
+\end{description}
+
+\begin{verbatim}
+ int fits_merge_groups / ffgtmg
+ (fitsfile *infptr, fitsfile *outfptr, int mgopt, > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[7 ]"Compact" the group defined by grouping table pointed to by gfptr. The
+ compaction is achieved by merging (via fits\_merge\_groups()) all direct
+ member HDUs of gfptr that are themselves grouping tables. The cmopt
+ parameter defines whether the merged grouping table HDUs remain after
+ merging (cmopt == OPT\_CMT\_MBR) or if they are deleted after merging
+ (cmopt == OPT\_CMT\_MBR\_DEL). If the grouping table contains no direct
+ member HDUs that are themselves grouping tables then this function
+ does nothing. Note that this function is not recursive, i.e., only the
+ direct member HDUs of gfptr are considered for merging. \label{ffgtcm}
+\end{description}
+
+\begin{verbatim}
+ int fits_compact_group / ffgtcm
+ (fitsfile *gfptr, int cmopt, > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[8 ]Verify the integrity of the grouping table pointed to by gfptr to make
+ sure that all group members are accessible and that all links to other
+ grouping tables are valid. The firstfailed parameter returns the member
+ ID (row number) of the first member HDU to fail verification (if positive
+ value) or the first group link to fail (if negative value). If gfptr is
+ successfully verified then firstfailed contains a return value of 0. \label{ffgtvf}
+\end{description}
+
+\begin{verbatim}
+ int fits_verify_group / ffgtvf
+ (fitsfile *gfptr, > long *firstfailed, int *status)
+\end{verbatim}
+
+\begin{description}
+\item[9 ] Open a grouping table that contains the member HDU pointed to by mfptr.
+ The grouping table to open is defined by the grpid parameter, which
+ contains the keyword index value of the GRPIDn/GRPLCn keyword(s) that
+ link the member HDU mfptr to the grouping table. If the grouping table
+ resides in a file other than the member HDUs file then an attempt is
+ first made to open the file readwrite, and failing that readonly. A
+ pointer to the opened grouping table HDU is returned in gfptr.
+
+ Note that it is possible, although unlikely and undesirable, for the
+ GRPIDn/GRPLCn keywords in a member HDU header to be non-continuous, e.g.,
+ GRPID1, GRPID2, GRPID5, GRPID6. In such cases, the grpid index value
+ specified in the function call shall identify the (grpid)th GRPID value.
+ In the above example, if grpid == 3, then the group specified by GRPID5
+ would be opened. \label{ffgtop}
+\end{description}
+
+\begin{verbatim}
+ int fits_open_group / ffgtop
+ (fitsfile *mfptr, int group, > fitsfile **gfptr, int *status)
+\end{verbatim}
+
+\begin{description}
+\item[10] Add a member HDU to an existing grouping table pointed to by gfptr.
+ The member HDU may either be pointed to mfptr (which must be positioned
+ to the member HDU) or, if mfptr == NULL, identified by the hdupos parameter
+ (the HDU position number, Primary array == 1) if both the grouping table
+ and the member HDU reside in the same FITS file. The new member HDU shall
+ have the appropriate GRPIDn and GRPLCn keywords created in its header.
+ Note that if the member HDU is already a member of the group then it will
+ not be added a second time. \label{ffgtam}
+\end{description}
+
+\begin{verbatim}
+ int fits_add_group_member / ffgtam
+ (fitsfile *gfptr, fitsfile *mfptr, int hdupos, > int *status)
+\end{verbatim}
+
+
+\section{Group Member Routines}
+
+
+\begin{description}
+\item[1 ] Return the number of member HDUs in a grouping table gfptr. The number
+ member HDUs is just the NAXIS2 value (number of rows) of the grouping
+ table. \label{ffgtnm}
+\end{description}
+
+\begin{verbatim}
+ int fits_get_num_members / ffgtnm
+ (fitsfile *gfptr, > long *nmembers, int *status)
+\end{verbatim}
+
+\begin{description}
+\item[2 ] Return the number of groups to which the HDU pointed to by mfptr is
+ linked, as defined by the number of GRPIDn/GRPLCn keyword records that
+ appear in its header. Note that each time this function is called, the
+ indices of the GRPIDn/GRPLCn keywords are checked to make sure they
+ are continuous (ie no gaps) and are re-enumerated to eliminate gaps if
+ found. \label{ffgmng}
+\end{description}
+
+\begin{verbatim}
+ int fits_get_num_groups / ffgmng
+ (fitsfile *mfptr, > long *nmembers, int *status)
+\end{verbatim}
+
+\begin{description}
+\item[3 ] Open a member of the grouping table pointed to by gfptr. The member to
+ open is identified by its row number within the grouping table as given
+ by the parameter 'member' (first member == 1) . A fitsfile pointer to
+ the opened member HDU is returned as mfptr. Note that if the member HDU
+ resides in a FITS file different from the grouping table HDU then the
+ member file is first opened readwrite and, failing this, opened readonly. \label{ffgmop}
+\end{description}
+
+\begin{verbatim}
+ int fits_open_member / ffgmop
+ (fitsfile *gfptr, long member, > fitsfile **mfptr, int *status)
+\end{verbatim}
+
+\begin{description}
+\item[4 ]Copy (append) a member HDU of the grouping table pointed to by gfptr.
+ The member HDU is identified by its row number within the grouping table
+ as given by the parameter 'member' (first member == 1). The copy of the
+ group member HDU will be appended to the FITS file pointed to by mfptr,
+ and upon return mfptr shall point to the copied member HDU. The cpopt
+ parameter may take on the following values: OPT\_MCP\_ADD which adds a new
+ entry in gfptr for the copied member HDU, OPT\_MCP\_NADD which does not add
+ an entry in gfptr for the copied member, and OPT\_MCP\_REPL which replaces
+ the original member entry with the copied member entry. \label{ffgmcp}
+\end{description}
+
+\begin{verbatim}
+ int fits_copy_member / ffgmcp
+ (fitsfile *gfptr, fitsfile *mfptr, long member, int cpopt, > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[5 ]Transfer a group member HDU from the grouping table pointed to by
+ infptr to the grouping table pointed to by outfptr. The member HDU to
+ transfer is identified by its row number within infptr as specified by
+ the parameter 'member' (first member == 1). If tfopt == OPT\_MCP\_ADD then
+ the member HDU is made
+ a member of outfptr and remains a member of infptr. If tfopt == OPT\_MCP\_MOV
+ then the member HDU is deleted from infptr after the transfer to outfptr. \label{ffgmtf}
+\end{description}
+
+\begin{verbatim}
+ int fits_transfer_member / ffgmtf
+ (fitsfile *infptr, fitsfile *outfptr, long member, int tfopt,
+ > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[6 ]Remove a member HDU from the grouping table pointed to by gfptr. The
+ member HDU to be deleted is identified by its row number in the grouping
+ table as specified by the parameter 'member' (first member == 1). The rmopt
+ parameter may take on the following values: OPT\_RM\_ENTRY which
+ removes the member HDU entry from the grouping table and updates the
+ member's GRPIDn/GRPLCn keywords, and OPT\_RM\_MBR which removes the member
+ HDU entry from the grouping table and deletes the member HDU itself. \label{ffgmrm}
+\end{description}
+
+\begin{verbatim}
+ int fits_remove_member / ffgmrm
+ (fitsfile *fptr, long member, int rmopt, > int *status)
+\end{verbatim}
+
+\chapter{ Specialized CFITSIO Interface Routines }
+
+The basic interface routines described previously are recommended
+for most uses, but the routines described in this chapter
+are also available if necessary. Some of these routines perform more
+specialized function that cannot easily be done with the basic
+interface routines while others duplicate the functionality of the
+basic routines but have a slightly different calling sequence.
+See Appendix B for the definition of each function parameter.
+
+
+\section{FITS File Access Routines}
+
+
+\begin{description}
+\item[1 ] Open an existing FITS file residing in core computer memory. This
+routine is analogous to fits\_open\_file. The 'filename' is
+currently ignored by this routine and may be any arbitrary string. In
+general, the application must have preallocated an initial block of
+memory to hold the FITS file prior to calling this routine: 'memptr'
+points to the starting address and 'memsize' gives the initial size of
+the block of memory. 'mem\_realloc' is a pointer to an optional
+function that CFITSIO can call to allocate additional memory, if needed
+(only if mode = READWRITE), and is modeled after the standard C
+'realloc' function; a null pointer may be given if the initial
+allocation of memory is all that will be required (e.g., if the file is
+opened with mode = READONLY). The 'deltasize' parameter may be used to
+suggest a minimum amount of additional memory that should be allocated
+during each call to the memory reallocation function. By default,
+CFITSIO will reallocate enough additional space to hold the entire
+currently defined FITS file (as given by the NAXISn keywords) or 1 FITS
+block (= 2880 bytes), which ever is larger. Values of deltasize less
+than 2880 will be ignored. Since the memory reallocation operation can
+be computationally expensive, allocating a larger initial block of
+memory, and/or specifying a larger deltasize value may help to reduce
+the number of reallocation calls and make the application program run
+ faster. \label{ffomem}
+\end{description}
+
+\begin{verbatim}
+ int fits_open_memfile / ffomem
+ (fitsfile **fptr, const char *filename, int mode, void **memptr,
+ size_t *memsize, size_t deltasize,
+ void *(*mem_realloc)(void *p, size_t newsize), int *status)
+\end{verbatim}
+
+\begin{description}
+\item[2 ] Create a new FITS file residing in core computer memory. This
+routine is analogous to fits\_create\_file. In general, the
+application must have preallocated an initial block of memory to hold
+the FITS file prior to calling this routine: 'memptr' points to the
+starting address and 'memsize' gives the initial size of the block of
+memory. 'mem\_realloc' is a pointer to an optional function that
+CFITSIO can call to allocate additional memory, if needed, and is
+modeled after the standard C 'realloc' function; a null pointer may be
+given if the initial allocation of memory is all that will be
+required. The 'deltasize' parameter may be used to suggest a minimum
+amount of additional memory that should be allocated during each call
+to the memory reallocation function. By default, CFITSIO will
+reallocate enough additional space to hold 1 FITS block (= 2880 bytes)
+and values of deltasize less than 2880 will be ignored. Since the
+memory reallocation operation can be computationally expensive,
+allocating a larger initial block of memory, and/or specifying a larger
+deltasize value may help to reduce the number of reallocation calls
+and make the application program run
+ faster. \label{ffimem}
+\end{description}
+
+\begin{verbatim}
+ int fits_create_memfile / ffimem
+ (fitsfile **fptr, void **memptr,
+ size_t *memsize, size_t deltasize,
+ void *(*mem_realloc)(void *p, size_t newsize), int *status)
+\end{verbatim}
+
+\begin{description}
+\item[3 ] Reopen a FITS file that was previously opened with
+ fits\_open\_file or fits\_create\_file. The new fitsfile
+ pointer may then be treated as a separate file, and one may
+ simultaneously read or write to 2 (or more) different extensions in
+ the same file. The fits\_open\_file routine (above) automatically
+ detects cases where a previously opened file is being opened again,
+ and then internally call fits\_reopen\_file, so programs should rarely
+ need to explicitly call this routine.
+\label{ffreopen}
+\end{description}
+
+\begin{verbatim}
+ int fits_reopen_file / ffreopen
+ (fitsfile *openfptr, fitsfile **newfptr, > int *status)
+\end{verbatim}
+
+
+\begin{description}
+\item[4 ] Create a new FITS file, using a template file to define its
+ initial size and structure. The template may be another FITS HDU
+ or an ASCII template file. If the input template file name pointer
+ is null, then this routine behaves the same as fits\_create\_file.
+ The currently supported format of the ASCII template file is described
+ under the fits\_parse\_template routine (in the general Utilities
+ section)
+\label{fftplt}
+\end{description}
+
+\begin{verbatim}
+ int fits_create_template / fftplt
+ (fitsfile **fptr, char *filename, char *tpltfile > int *status)
+\end{verbatim}
+
+
+\begin{description}
+\item[5 ] Parse the input filename or URL into its component parts: the file
+type (file://, ftp://, http://, etc), the base input file name, the
+name of the output file that the input file is to be copied to prior
+to opening, the HDU or extension specification, the filtering
+specifier, the binning specifier, and the column specifier. Null
+strings will be returned for any components that are not present
+ in the input file name. \label{ffiurl}
+\end{description}
+
+\begin{verbatim}
+ int fits_parse_input_url / ffiurl
+ (char *filename, > char *filetype, char *infile, char *outfile, char
+ *extspec, char *filter, char *binspec, char *colspec, int *status)
+\end{verbatim}
+
+\begin{description}
+\item[6 ] Parse the input filename and return the HDU number that would be
+moved to if the file were opened with fits\_open\_file. The returned
+HDU number begins with 1 for the primary array, so for example, if the
+input filename = `myfile.fits[2]' then hdunum = 3 will be returned.
+CFITSIO does not open the file to check if the extension actually
+exists if an extension number is specified. If an extension name is
+included in the file name specification (e.g. `myfile.fits[EVENTS]'
+then this routine will have to open the FITS file and look for the
+position of the named extension, then close file again. This is not
+possible if the file is being read from the stdin stream, and an error
+will be returned in this case. If the filename does not specify an
+explicit extension (e.g. 'myfile.fits') then hdunum = -99 will be
+returned, which is functionally equivalent to hdunum = 1. This routine
+is mainly used for backward compatibility in the ftools software
+package and is not recommended for general use. It is generally better
+and more efficient to first open the FITS file with fits\_open\_file,
+then use fits\_get\_hdu\_num to determine which HDU in the file has
+been opened, rather than calling fits\_parse\_input\_url followed by a
+call to fits\_open\_file.
+ \label{ffextn}
+\end{description}
+
+\begin{verbatim}
+ int fits_parse_extnum / ffextn
+ (char *filename, > int *hdunum, int *status)
+\end{verbatim}
+
+\begin{description}
+\item[7 ]Parse the input file name and return the root file name. The root
+name includes the file type if specified, (e.g. 'ftp://' or 'http://')
+and the full path name, to the extent that it is specified in the input
+filename. It does not include the HDU name or number, or any filtering
+specifications.
+ \label{ffrtnm}
+\end{description}
+
+\begin{verbatim}
+ int fits_parse_rootname / ffrtnm
+ (char *filename, > char *rootname, int *status);
+\end{verbatim}
+
+\begin{description}
+\item[8 ]Test if the input file or a compressed version of the file (with
+a .gz, .Z, .z, or .zip extension) exists on disk. The returned value of
+the 'exists' parameter will have 1 of the 4 following values:
+
+\begin{verbatim}
+ 2: the file does not exist, but a compressed version does exist
+ 1: the disk file does exist
+ 0: neither the file nor a compressed version of the file exist
+ -1: the input file name is not a disk file (could be a ftp, http,
+ smem, or mem file, or a file piped in on the STDIN stream)
+\end{verbatim}
+
+ \label{ffexist}
+\end{description}
+
+\begin{verbatim}
+ int fits_file_exists / ffexist
+ (char *filename, > int *exists, int *status);
+\end{verbatim}
+
+\begin{description}
+\item[9 ]Flush any internal buffers of data to the output FITS file. These
+ routines rarely need to be called, but can be useful in cases where
+ other processes need to access the same FITS file in real time,
+ either on disk or in memory. These routines also help to ensure
+ that if the application program subsequently aborts then the FITS
+ file will have been closed properly. The first routine,
+ fits\_flush\_file is more rigorous and completely closes, then
+ reopens, the current HDU, before flushing the internal buffers, thus
+ ensuring that the output FITS file is identical to what would be
+ produced if the FITS was closed at that point (i.e., with a call to
+ fits\_close\_file). The second routine, fits\_flush\_buffer simply
+ flushes the internal CFITSIO buffers of data to the output FITS
+ file, without updating and closing the current HDU. This is much
+ faster, but there may be circumstances where the flushed file does
+ not completely reflect the final state of the file as it will exist
+ when the file is actually closed.
+
+ A typical use of these routines would be to flush the state of a
+ FITS table to disk after each row of the table is written. It is
+ recommend that fits\_flush\_file be called after the first row is
+ written, then fits\_flush\_buffer may be called after each
+ subsequent row is written. Note that this latter routine will not
+ automatically update the NAXIS2 keyword which records the number of
+ rows of data in the table, so this keyword must be explicitly
+ updated by the application program after each row is written.
+ \label{ffflus}
+\end{description}
+
+\begin{verbatim}
+ int fits_flush_file / ffflus
+ (fitsfile *fptr, > int *status)
+
+ int fits_flush_buffer / ffflsh
+ (fitsfile *fptr, 0, > int *status)
+
+ (Note: The second argument must be 0).
+\end{verbatim}
+
+
+\section{HDU Access Routines}
+
+
+\begin{description}
+\item[1 ] Get the byte offsets in the FITS file to the start of the header
+ and the start and end of the data in the CHDU. The difference
+ between headstart and dataend equals the size of the CHDU. If the
+ CHDU is the last HDU in the file, then dataend is also equal to the
+ size of the entire FITS file. Null pointers may be input for any
+ of the address parameters if their values are not needed. The
+ fits\_get\_hduaddr routine is obsolete and should no longer be
+ used. The newer fits\_get\_hduoff routine uses the 'off\_t'
+ data type which can support offsets in large files greater than
+ 2.1GB in size. \label{ffghad}
+\end{description}
+
+\begin{verbatim}
+ int fits_get_hduoff / ffghof
+ (fitsfile *fptr, > off_t *headstart, off_t *datastart, off_t *dataend,
+ int *status)
+
+ int fits_get_hduaddr / ffghad (OBSOLETE routine)
+ (fitsfile *fptr, > long *headstart, long *datastart, long *dataend,
+ int *status)
+\end{verbatim}
+
+\begin{description}
+\item[2 ] Create (append) a new empty HDU at the end of the FITS file.
+ This is now the CHDU but it is completely empty and has
+ no header keywords. It is recommended that fits\_create\_img or
+ fits\_create\_tbl be used instead of this routine. \label{ffcrhd}
+\end{description}
+
+\begin{verbatim}
+ int fits_create_hdu / ffcrhd
+ (fitsfile *fptr, > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[3 ] Insert a new IMAGE extension immediately following the CHDU, or
+ insert a new Primary Array at the beginning of the file. Any
+ following extensions in the file will be shifted down to make room
+ for the new extension. If the CHDU is the last HDU in the file
+ then the new image extension will simply be appended to the end of
+ the file. One can force a new primary array to be inserted at the
+ beginning of the FITS file by setting status = PREPEND\_PRIMARY prior
+ to calling the routine. In this case the old primary array will be
+ converted to an IMAGE extension. The new extension (or primary
+ array) will become the CHDU. Refer to Chapter 9 for a list of
+ pre-defined bitpix values. \label{ffiimg}
+\end{description}
+
+\begin{verbatim}
+ int fits_insert_img / ffiimg
+ (fitsfile *fptr, int bitpix, int naxis, long *naxes, > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[4 ] Insert a new ASCII or binary table extension immediately following the CHDU.
+ Any following extensions will be shifted down to make room for the
+ new extension. If there are no other following extensions then the
+ new table extension will simply be appended to the end of the
+ file. If the FITS file is currently empty then this routine will
+ create a dummy primary array before appending the table to it. The
+ new extension will become the CHDU. The tunit and extname
+ parameters are optional and a null pointer may be given if they are
+ not defined. When inserting an ASCII table with
+ fits\_insert\_atbl, a null pointer may given for the *tbcol
+ parameter in which case each column of the table will be separated
+ by a single space character. Similarly, if the input value of
+ rowlen is 0, then CFITSIO will calculate the default rowlength
+ based on the tbcol and ttype values. When inserting a binary table
+ with fits\_insert\_btbl, if there are following extensions in the
+ file and if the table contains variable length array columns then
+ pcount must specify the expected final size of the data heap,
+ otherwise pcount must = 0. \label{ffitab} \label{ffibin}
+\end{description}
+
+\begin{verbatim}
+ int fits_insert_atbl / ffitab
+ (fitsfile *fptr, long rowlen, long nrows, int tfields, char *ttype[],
+ long *tbcol, char *tform[], char *tunit[], char *extname, > int *status)
+
+ int fits_insert_btbl / ffibin
+ (fitsfile *fptr, long nrows, int tfields, char **ttype,
+ char **tform, char **tunit, char *extname, long pcount, > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[5 ] Modify the size, dimensions, and/or data type of the current
+ primary array or image extension. If the new image, as specified
+ by the input arguments, is larger than the current existing image
+ in the FITS file then zero fill data will be inserted at the end
+ of the current image and any following extensions will be moved
+ further back in the file. Similarly, if the new image is
+ smaller than the current image then any following extensions
+ will be shifted up towards the beginning of the FITS file
+ and the image data will be truncated to the new size.
+ This routine rewrites the BITPIX, NAXIS, and NAXISn keywords
+ with the appropriate values for the new image. \label{ffrsim}
+\end{description}
+
+\begin{verbatim}
+ int fits_resize_img / ffrsim
+ (fitsfile *fptr, int bitpix, int naxis, long *naxes, > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[6 ] Copy the data (and not the header) from the CHDU associated with infptr
+ to the CHDU associated with outfptr. This will overwrite any data
+ previously in the output CHDU. This low level routine is used by
+ fits\_copy\_hdu, but it may also be useful in certain application programs
+ that want to copy the data from one FITS file to another but also
+ want to modify the header keywords. The required FITS header keywords
+ which define the structure of the HDU must be written to the
+ output CHDU before calling this routine. \label{ffcpdt}
+\end{description}
+
+\begin{verbatim}
+ int fits_copy_data / ffcpdt
+ (fitsfile *infptr, fitsfile *outfptr, > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[7 ] This routine forces CFITSIO to rescan the current header keywords that
+ define the structure of the HDU (such as the NAXIS and BITPIX
+ keywords) so that it reinitializes the internal buffers that
+ describe the HDU structure. This routine is useful for
+ reinitializing the structure of an HDU if any of the required
+ keywords (e.g., NAXISn) have been modified. In practice it should
+ rarely be necessary to call this routine because CFITSIO
+ internally calls it in most situations. \label{ffrdef}
+\end{description}
+
+\begin{verbatim}
+ int fits_set_hdustruc / ffrdef
+ (fitsfile *fptr, > int *status) (DEPRECATED)
+\end{verbatim}
+
+\section{Specialized Header Keyword Routines}
+
+
+\subsection{Header Information Routines}
+
+
+\begin{description}
+\item[1 ] Reserve space in the CHU for MOREKEYS more header keywords.
+ This routine may be called to allocate space for additional keywords
+ at the time the header is created (prior to writing any data).
+ CFITSIO can dynamically add more space to the header when needed,
+ however it is more efficient to preallocate the required space
+ if the size is known in advance. \label{ffhdef}
+\end{description}
+
+\begin{verbatim}
+ int fits_set_hdrsize / ffhdef
+ (fitsfile *fptr, int morekeys, > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[2 ] Return the number of keywords in the header (not counting the END
+ keyword) and the current position
+ in the header. The position is the number of the keyword record that
+ will be read next (or one greater than the position of the last keyword
+ that was read). A value of 1 is returned if the pointer is
+ positioned at the beginning of the header. \label{ffghps}
+\end{description}
+
+\begin{verbatim}
+ int fits_get_hdrpos / ffghps
+ (fitsfile *fptr, > int *keysexist, int *keynum, int *status)
+\end{verbatim}
+
+
+\subsection{Read and Write the Required Keywords}
+
+
+\begin{description}
+\item[1 ] Write the primary header or IMAGE extension keywords into the CHU.
+ The simpler fits\_write\_imghdr routine is equivalent to calling
+ fits\_write\_grphdr with the default values of simple = TRUE, pcount
+ = 0, gcount = 1, and extend = TRUE. The PCOUNT, GCOUNT and EXTEND
+ keywords are not required in the primary header and are only written
+ if pcount is not equal to zero, gcount is not equal to zero or one,
+ and if extend is TRUE, respectively. When writing to an IMAGE
+ extension, the SIMPLE and EXTEND parameters are ignored. It is
+ recommended that fits\_create\_image or fits\_create\_tbl be used
+ instead of these routines to write the
+ required header keywords. \label{ffphpr} \label{ffphps}
+\end{description}
+
+\begin{verbatim}
+ int fits_write_imghdr / ffphps
+ (fitsfile *fptr, int bitpix, int naxis, long *naxes, > int *status)
+
+ int fits_write_grphdr / ffphpr
+ (fitsfile *fptr, int simple, int bitpix, int naxis, long *naxes,
+ long pcount, long gcount, int extend, > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[2 ] Write the ASCII table header keywords into the CHU. The optional
+ TUNITn and EXTNAME keywords are written only if the input pointers
+ are not null. A null pointer may given for the
+ *tbcol parameter in which case a single space will be inserted
+ between each column of the table. Similarly, if rowlen is
+ given = 0, then CFITSIO will calculate the default rowlength based on
+ the tbcol and ttype values. \label{ffphtb}
+\end{description}
+
+\begin{verbatim}
+ int fits_write_atblhdr / ffphtb
+ (fitsfile *fptr, long rowlen, long nrows, int tfields, char **ttype,
+ long *tbcol, char **tform, char **tunit, char *extname, > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[3 ] Write the binary table header keywords into the CHU. The optional
+ TUNITn and EXTNAME keywords are written only if the input pointers
+ are not null. The pcount parameter, which specifies the
+ size of the variable length array heap, should initially = 0;
+ CFITSIO will automatically update the PCOUNT keyword value if any
+ variable length array data is written to the heap. The TFORM keyword
+ value for variable length vector columns should have the form 'Pt(len)'
+ or '1Pt(len)' where `t' is the data type code letter (A,I,J,E,D, etc.)
+ and `len' is an integer specifying the maximum length of the vectors
+ in that column (len must be greater than or equal to the longest
+ vector in the column). If `len' is not specified when the table is
+ created (e.g., the input TFORMn value is just '1Pt') then CFITSIO will
+ scan the column when the table is first closed and will append the
+ maximum length to the TFORM keyword value. Note that if the table
+ is subsequently modified to increase the maximum length of the vectors
+ then the modifying program is responsible for also updating the TFORM
+ keyword value. \label{ffphbn}
+\end{description}
+
+\begin{verbatim}
+ int fits_write_btblhdr / ffphbn
+ (fitsfile *fptr, long nrows, int tfields, char **ttype,
+ char **tform, char **tunit, char *extname, long pcount, > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[4 ] Read the required keywords from the CHDU (image or table). When
+ reading from an IMAGE extension the SIMPLE and EXTEND parameters are
+ ignored. A null pointer may be supplied for any of the returned
+ parameters that are not needed. \label{ffghpr} \label{ffghtb} \label{ffghbn}
+\end{description}
+
+\begin{verbatim}
+ int fits_read_imghdr / ffghpr
+ (fitsfile *fptr, int maxdim, > int *simple, int *bitpix, int *naxis,
+ long *naxes, long *pcount, long *gcount, int *extend, int *status)
+
+ int fits_read_atblhdr / ffghtb
+ (fitsfile *fptr,int maxdim, > long *rowlen, long *nrows,
+ int *tfields, char **ttype, long *tbcol, char **tform, char **tunit,
+ char *extname, int *status)
+
+ int fits_read_btblhdr / ffghbn
+ (fitsfile *fptr, int maxdim, > long *nrows, int *tfields,
+ char **ttype, char **tform, char **tunit, char *extname,
+ long *pcount, int *status)
+\end{verbatim}
+
+\subsection{Write Keyword Routines}
+
+These routines simply append a new keyword to the header and do not
+check to see if a keyword with the same name already exists. In
+general it is preferable to use the fits\_update\_key routine to ensure
+that the same keyword is not written more than once to the header. See
+Appendix B for the definition of the parameters used in these
+routines.
+
+
+
+\begin{description}
+\item[1 ] Write (append) a new keyword of the appropriate data type into the CHU.
+ A null pointer may be entered for the comment parameter, which
+ will cause the comment field of the keyword to be left blank. The
+ flt, dbl, cmp, and dblcmp versions of this routine have the added
+ feature that if the 'decimals' parameter is negative, then the 'G'
+ display format rather then the 'E' format will be used when
+ constructing the keyword value, taking the absolute value of
+ 'decimals' for the precision. This will suppress trailing zeros,
+ and will use a fixed format rather than an exponential format,
+ depending on the magnitude of the value. \label{ffpkyx}
+\end{description}
+
+\begin{verbatim}
+ int fits_write_key_str / ffpkys
+ (fitsfile *fptr, char *keyname, char *value, char *comment,
+ > int *status)
+
+ int fits_write_key_[log, lng] / ffpky[lj]
+ (fitsfile *fptr, char *keyname, DTYPE numval, char *comment,
+ > int *status)
+
+ int fits_write_key_[flt, dbl, fixflg, fixdbl] / ffpky[edfg]
+ (fitsfile *fptr, char *keyname, DTYPE numval, int decimals,
+ char *comment, > int *status)
+
+ int fits_write_key_[cmp, dblcmp, fixcmp, fixdblcmp] / ffpk[yc,ym,fc,fm]
+ (fitsfile *fptr, char *keyname, DTYPE *numval, int decimals,
+ char *comment, > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[2 ] Write (append) a string valued keyword into the CHU which may be longer
+ than 68 characters in length. This uses the Long String Keyword
+ convention that is described in the`Local FITS Conventions' section
+ in Chapter 4. Since this uses a non-standard FITS convention to
+ encode the long keyword string, programs which use this routine
+ should also call the fits\_write\_key\_longwarn routine to add some
+ COMMENT keywords to warn users of the FITS file that this
+ convention is being used. The fits\_write\_key\_longwarn routine
+ also writes a keyword called LONGSTRN to record the version of the
+ longstring convention that has been used, in case a new convention
+ is adopted at some point in the future. If the LONGSTRN keyword
+ is already present in the header, then fits\_write\_key\_longwarn
+ will
+ simply return without doing anything. \label{ffpkls} \label{ffplsw}
+\end{description}
+
+\begin{verbatim}
+ int fits_write_key_longstr / ffpkls
+ (fitsfile *fptr, char *keyname, char *longstr, char *comment,
+ > int *status)
+
+ int fits_write_key_longwarn / ffplsw
+ (fitsfile *fptr, > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[3 ] Write (append) a numbered sequence of keywords into the CHU. The
+ starting index number (nstart) must be greater than 0. One may
+ append the same comment to every keyword (and eliminate the need
+ to have an array of identical comment strings, one for each keyword) by
+ including the ampersand character as the last non-blank character in the
+ (first) COMMENTS string parameter. This same string
+ will then be used for the comment field in all the keywords.
+ One may also enter a null pointer for the comment parameter to
+ leave the comment field of the keyword blank. \label{ffpknx}
+\end{description}
+
+\begin{verbatim}
+ int fits_write_keys_str / ffpkns
+ (fitsfile *fptr, char *keyroot, int nstart, int nkeys,
+ char **value, char **comment, > int *status)
+
+ int fits_write_keys_[log, lng] / ffpkn[lj]
+ (fitsfile *fptr, char *keyroot, int nstart, int nkeys,
+ DTYPE *numval, char **comment, int *status)
+
+ int fits_write_keys_[flt, dbl, fixflg, fixdbl] / ffpkne[edfg]
+ (fitsfile *fptr, char *keyroot, int nstart, int nkey,
+ DTYPE *numval, int decimals, char **comment, > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[4 ]Copy an indexed keyword from one HDU to another, modifying
+ the index number of the keyword name in the process. For example,
+ this routine could read the TLMIN3 keyword from the input HDU
+ (by giving keyroot = `TLMIN' and innum = 3) and write it to the
+ output HDU with the keyword name TLMIN4 (by setting outnum = 4).
+ If the input keyword does not exist, then this routine simply
+ returns without indicating an error. \label{ffcpky}
+\end{description}
+
+\begin{verbatim}
+ int fits_copy_key / ffcpky
+ (fitsfile *infptr, fitsfile *outfptr, int innum, int outnum,
+ char *keyroot, > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[5 ]Write (append) a `triple precision' keyword into the CHU in F28.16 format.
+ The floating point keyword value is constructed by concatenating the
+ input integer value with the input double precision fraction value
+ (which must have a value between 0.0 and 1.0). The ffgkyt routine should
+ be used to read this keyword value, because the other keyword reading
+ routines will not preserve the full precision of the value. \label{ffpkyt}
+\end{description}
+
+\begin{verbatim}
+ int fits_write_key_triple / ffpkyt
+ (fitsfile *fptr, char *keyname, long intval, double frac,
+ char *comment, > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[6 ]Write keywords to the CHDU that are defined in an ASCII template file.
+ The format of the template file is described under the fits\_parse\_template
+ routine. \label{ffpktp}
+\end{description}
+
+\begin{verbatim}
+ int fits_write_key_template / ffpktp
+ (fitsfile *fptr, const char *filename, > int *status)
+\end{verbatim}
+
+\subsection{Insert Keyword Routines}
+
+These insert routines are somewhat less efficient than the `update' or
+`write' keyword routines because the following keywords in the header
+must be shifted down to make room for the inserted keyword. See
+Appendix B for the definition of the parameters used in these
+routines.
+
+
+\begin{description}
+\item[1 ] Insert a new keyword record into the CHU at the specified position
+ (i.e., immediately preceding the (keynum)th keyword in the header.)
+ \label{ffirec}
+\end{description}
+
+\begin{verbatim}
+ int fits_insert_record / ffirec
+ (fitsfile *fptr, int keynum, char *card, > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[2 ] Insert a new keyword into the CHU. The new keyword is inserted
+ immediately following the last keyword that has been read from the
+ header. The `longstr' version has the same functionality as the
+ `str' version except that it also supports the local long string
+ keyword convention for strings longer than 68 characters. A null
+ pointer may be entered for the comment parameter which will cause
+ the comment field to be left blank. The flt, dbl, cmp, and dblcmp
+ versions of this routine have the added
+ feature that if the 'decimals' parameter is negative, then the 'G'
+ display format rather then the 'E' format will be used when
+ constructing the keyword value, taking the absolute value of
+ 'decimals' for the precision. This will suppress trailing zeros,
+ and will use a fixed format rather than an exponential format,
+ depending on the magnitude of the value. \label{ffikyx}
+\end{description}
+
+\begin{verbatim}
+ int fits_insert_card / ffikey
+ (fitsfile *fptr, char *card, > &status)
+
+ int fits_insert_key_[str, longstr] / ffi[kys, kls]
+ (fitsfile *fptr, char *keyname, char *value, char *comment,
+ > int *status)
+
+ int fits_insert_key_[log, lng] / ffiky[lj]
+ (fitsfile *fptr, char *keyname, DTYPE numval, char *comment,
+ > int *status)
+
+ int fits_insert_key_[flt, fixflt, dbl, fixdbl] / ffiky[edfg]
+ (fitsfile *fptr, char *keyname, DTYPE numval, int decimals,
+ char *comment, > int *status)
+
+ int fits_insert_key_[cmp, dblcmp, fixcmp, fixdblcmp] / ffik[yc,ym,fc,fm]
+ (fitsfile *fptr, char *keyname, DTYPE *numval, int decimals,
+ char *comment, > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[3 ] Insert a new keyword with an undefined, or null, value into the CHU.
+ The value string of the keyword is left blank in this case. \label{ffikyu}
+\end{description}
+
+\begin{verbatim}
+ int fits_insert_key_null / ffikyu
+ (fitsfile *fptr, char *keyname, char *comment, > int *status)
+\end{verbatim}
+
+
+\subsection{Read Keyword Routines}
+
+Wild card characters may be used when specifying the name of the
+keyword to be read.
+
+
+\begin{description}
+\item[1 ] Read a keyword value (with the appropriate data type) and comment from
+ the CHU. If a NULL comment pointer is given on input, then the comment
+ string will not be returned. If the value of the keyword is not defined
+ (i.e., the value field is blank) then an error status = VALUE\_UNDEFINED
+ will be returned and the input value will not be changed (except that
+ ffgkys will reset the value to a null string).
+ \label{ffgkyx} \label{ffgkls}
+\end{description}
+
+\begin{verbatim}
+ int fits_read_key_str / ffgkys
+ (fitsfile *fptr, char *keyname, > char *value, char *comment,
+ int *status);
+
+ NOTE: after calling the following routine, programs must explicitly free
+ the memory allocated for 'longstr' after it is no longer needed.
+
+ int fits_read_key_longstr / ffgkls
+ (fitsfile *fptr, char *keyname, > char **longstr, char *comment,
+ int *status)
+
+ int fits_read_key_[log, lng, flt, dbl, cmp, dblcmp] / ffgky[ljedcm]
+ (fitsfile *fptr, char *keyname, > DTYPE *numval, char *comment,
+ int *status)
+
+\end{verbatim}
+
+\begin{description}
+\item[2 ] Read a sequence of indexed keyword values (e.g., NAXIS1, NAXIS2, ...).
+ The input starting index number (nstart) must be greater than 0.
+ If the value of any of the keywords is not defined (i.e., the value
+ field is blank) then an error status = VALUE\_UNDEFINED will be
+ returned and the input value for the undefined keyword(s) will not
+ be changed. These routines do not support wild card characters in
+ the root name. If there are no indexed keywords in the header with
+ the input root name then these routines do not return a non-zero
+ status value and instead simply return nfound = 0. \label{ffgknx}
+\end{description}
+
+\begin{verbatim}
+ int fits_read_keys_str / ffgkns
+ (fitsfile *fptr, char *keyname, int nstart, int nkeys,
+ > char **value, int *nfound, int *status)
+
+ int fits_read_keys_[log, lng, flt, dbl] / ffgkn[ljed]
+ (fitsfile *fptr, char *keyname, int nstart, int nkeys,
+ > DTYPE *numval, int *nfound, int *status)
+\end{verbatim}
+
+\begin{description}
+\item[3 ] Read the value of a floating point keyword, returning the integer and
+ fractional parts of the value in separate routine arguments.
+ This routine may be used to read any keyword but is especially
+ useful for reading the 'triple precision' keywords written by ffpkyt.
+ \label{ffgkyt}
+\end{description}
+
+\begin{verbatim}
+ int fits_read_key_triple / ffgkyt
+ (fitsfile *fptr, char *keyname, > long *intval, double *frac,
+ char *comment, int *status)
+\end{verbatim}
+
+\subsection{Modify Keyword Routines}
+
+These routines modify the value of an existing keyword. An error is
+returned if the keyword does not exist. Wild card characters may be
+used when specifying the name of the keyword to be modified. See
+Appendix B for the definition of the parameters used in these
+routines.
+
+
+\begin{description}
+\item[1 ] Modify (overwrite) the nth 80-character header record in the CHU. \label{ffmrec}
+\end{description}
+
+\begin{verbatim}
+ int fits_modify_record / ffmrec
+ (fitsfile *fptr, int keynum, char *card, > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[2 ] Modify (overwrite) the 80-character header record for the named keyword
+ in the CHU. This can be used to overwrite the name of the keyword as
+ well as its value and comment fields. \label{ffmcrd}
+\end{description}
+
+\begin{verbatim}
+ int fits_modify_card / ffmcrd
+ (fitsfile *fptr, char *keyname, char *card, > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[5 ] Modify the value and comment fields of an existing keyword in the CHU.
+ The `longstr' version has the same functionality as the `str'
+ version except that it also supports the local long string keyword
+ convention for strings longer than 68 characters. Optionally, one
+ may modify only the value field and leave the comment field
+ unchanged by setting the input COMMENT parameter equal to the
+ ampersand character (\&) or by entering a null pointer for the
+ comment parameter. The flt, dbl, cmp, and dblcmp versions of this
+ routine have the added feature that if the 'decimals' parameter is
+ negative, then the 'G' display format rather then the 'E' format
+ will be used when constructing the keyword value, taking the
+ absolute value of 'decimals' for the precision. This will suppress
+ trailing zeros, and will use a fixed format rather than an
+ exponential format,
+ depending on the magnitude of the value. \label{ffmkyx}
+\end{description}
+
+\begin{verbatim}
+ int fits_modify_key_[str, longstr] / ffm[kys, kls]
+ (fitsfile *fptr, char *keyname, char *value, char *comment,
+ > int *status);
+
+ int fits_modify_key_[log, lng] / ffmky[lj]
+ (fitsfile *fptr, char *keyname, DTYPE numval, char *comment,
+ > int *status)
+
+ int fits_modify_key_[flt, dbl, fixflt, fixdbl] / ffmky[edfg]
+ (fitsfile *fptr, char *keyname, DTYPE numval, int decimals,
+ char *comment, > int *status)
+
+ int fits_modify_key_[cmp, dblcmp, fixcmp, fixdblcmp] / ffmk[yc,ym,fc,fm]
+ (fitsfile *fptr, char *keyname, DTYPE *numval, int decimals,
+ char *comment, > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[6 ] Modify the value of an existing keyword to be undefined, or null.
+ The value string of the keyword is set to blank.
+ Optionally, one may leave the comment field unchanged by setting the
+ input COMMENT parameter equal to
+ the ampersand character (\&) or by entering a null pointer. \label{ffmkyu}
+\end{description}
+
+\begin{verbatim}
+ int fits_modify_key_null / ffmkyu
+ (fitsfile *fptr, char *keyname, char *comment, > int *status)
+\end{verbatim}
+
+\subsection{Update Keyword Routines}
+
+
+\begin{description}
+\item[1 ] These update routines modify the value, and optionally the comment field,
+ of the keyword if it already exists, otherwise the new keyword is
+ appended to the header. A separate routine is provided for each
+ keyword data type. The `longstr' version has the same functionality
+ as the `str' version except that it also supports the local long
+ string keyword convention for strings longer than 68 characters. A
+ null pointer may be entered for the comment parameter which will
+ leave the comment field unchanged or blank. The flt, dbl, cmp, and
+ dblcmp versions of this routine have the added feature that if the
+ 'decimals' parameter is negative, then the 'G' display format
+ rather then the 'E' format will be used when constructing the
+ keyword value, taking the absolute value of 'decimals' for the
+ precision. This will suppress trailing zeros, and will use a fixed
+ format rather than an exponential format,
+ depending on the magnitude of the value. \label{ffukyx}
+\end{description}
+
+\begin{verbatim}
+ int fits_update_key_[str, longstr] / ffu[kys, kls]
+ (fitsfile *fptr, char *keyname, char *value, char *comment,
+ > int *status)
+
+ int fits_update_key_[log, lng] / ffuky[lj]
+ (fitsfile *fptr, char *keyname, DTYPE numval, char *comment,
+ > int *status)
+
+ int fits_update_key_[flt, dbl, fixflt, fixdbl] / ffuky[edfg]
+ (fitsfile *fptr, char *keyname, DTYPE numval, int decimals,
+ char *comment, > int *status)
+
+ int fits_update_key_[cmp, dblcmp, fixcmp, fixdblcmp] / ffuk[yc,ym,fc,fm]
+ (fitsfile *fptr, char *keyname, DTYPE *numval, int decimals,
+ char *comment, > int *status)
+\end{verbatim}
+
+
+\section{Define Data Scaling and Undefined Pixel Parameters}
+
+These routines set or modify the internal parameters used by CFITSIO
+to either scale the data or to represent undefined pixels. Generally
+CFITSIO will scale the data according to the values of the BSCALE and
+BZERO (or TSCALn and TZEROn) keywords, however these routines may be
+used to override the keyword values. This may be useful when one wants
+to read or write the raw unscaled values in the FITS file. Similarly,
+CFITSIO generally uses the value of the BLANK or TNULLn keyword to
+signify an undefined pixel, but these routines may be used to override
+this value. These routines do not create or modify the corresponding
+header keyword values. See Appendix B for the definition of the
+parameters used in these routines.
+
+
+\begin{description}
+\item[1 ] Reset the scaling factors in the primary array or image extension; does
+ not change the BSCALE and BZERO keyword values and only affects the
+ automatic scaling performed when the data elements are written/read
+ to/from the FITS file. When reading from a FITS file the returned
+ data value = (the value given in the FITS array) * BSCALE + BZERO.
+ The inverse formula is used when writing data values to the FITS
+ file. \label{ffpscl}
+\end{description}
+
+\begin{verbatim}
+ int fits_set_bscale / ffpscl
+ (fitsfile *fptr, double scale, double zero, > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[2 ] Reset the scaling parameters for a table column; does not change
+ the TSCALn or TZEROn keyword values and only affects the automatic
+ scaling performed when the data elements are written/read to/from
+ the FITS file. When reading from a FITS file the returned data
+ value = (the value given in the FITS array) * TSCAL + TZERO. The
+ inverse formula is used when writing data values to the FITS file.
+ \label{fftscl}
+\end{description}
+
+\begin{verbatim}
+ int fits_set_tscale / fftscl
+ (fitsfile *fptr, int colnum, double scale, double zero,
+ > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[3 ] Define the integer value to be used to signify undefined pixels in the
+ primary array or image extension. This is only used if BITPIX = 8, 16,
+ or 32. This does not create or change the value of the BLANK keyword in
+ the header. \label{ffpnul}
+\end{description}
+
+\begin{verbatim}
+ int fits_set_imgnull / ffpnul
+ (fitsfile *fptr, long nulval, > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[4 ] Define the string to be used to signify undefined pixels in
+ a column in an ASCII table. This does not create or change the value
+ of the TNULLn keyword. \label{ffsnul}
+\end{description}
+
+\begin{verbatim}
+ int fits_set_atblnull / ffsnul
+ (fitsfile *fptr, int colnum, char *nulstr, > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[5 ] Define the value to be used to signify undefined pixels in
+ an integer column in a binary table (where TFORMn = 'B', 'I', or 'J').
+ This does not create or change the value of the TNULLn keyword.
+ \label{fftnul}
+\end{description}
+
+\begin{verbatim}
+ int fits_set_btblnull / fftnul
+ (fitsfile *fptr, int colnum, long nulval, > int *status)
+\end{verbatim}
+
+
+\section{Specialized FITS Primary Array or IMAGE Extension I/O Routines}
+
+These routines read or write data values in the primary data array
+(i.e., the first HDU in the FITS file) or an IMAGE extension.
+Automatic data type conversion is performed for if the data type of the
+FITS array (as defined by the BITPIX keyword) differs from the data
+type of the array in the calling routine. The data values are
+automatically scaled by the BSCALE and BZERO header values as they are
+being written or read from the FITS array. Unlike the basic routines
+described in the previous chapter, most of these routines specifically
+support the FITS random groups format. See Appendix B for the
+definition of the parameters used in these routines.
+
+The more primitive reading and writing routines (i. e., ffppr\_,
+ffppn\_, ffppn, ffgpv\_, or ffgpf\_) simply treat the primary array as
+a long 1-dimensional array of pixels, ignoring the intrinsic
+dimensionality of the array. When dealing with a 2D image, for
+example, the application program must calculate the pixel offset in the
+1-D array that corresponds to any particular X, Y coordinate in the
+image. C programmers should note that the ordering of arrays in FITS
+files, and hence in all the CFITSIO calls, is more similar to the
+dimensionality of arrays in Fortran rather than C. For instance if a
+FITS image has NAXIS1 = 100 and NAXIS2 = 50, then a 2-D array just
+large enough to hold the image should be declared as array[50][100] and
+not as array[100][50].
+
+For convenience, higher-level routines are also provided to specificly
+deal with 2D images (ffp2d\_ and ffg2d\_) and 3D data cubes (ffp3d\_
+and ffg3d\_). The dimensionality of the FITS image is passed by the
+naxis1, naxis2, and naxis3 parameters and the declared dimensions of
+the program array are passed in the dim1 and dim2 parameters. Note
+that the dimensions of the program array may be larger than the
+dimensions of the FITS array. For example if a FITS image with NAXIS1
+= NAXIS2 = 400 is read into a program array which is dimensioned as 512
+x 512 pixels, then the image will just fill the lower left corner of
+the array with pixels in the range 1 - 400 in the X an Y directions.
+This has the effect of taking a contiguous set of pixel value in the
+FITS array and writing them to a non-contiguous array in program memory
+(i.e., there are now some blank pixels around the edge of the image in
+the program array).
+
+The most general set of routines (ffpss\_, ffgsv\_, and ffgsf\_) may be
+used to transfer a rectangular subset of the pixels in a FITS
+N-dimensional image to or from an array which has been declared in the
+calling program. The fpixel and lpixel parameters are integer arrays
+which specify the starting and ending pixel coordinate in each dimension
+(starting with 1, not 0) of the FITS image that is to be read or
+written. It is important to note that these are the starting and
+ending pixels in the FITS image, not in the declared array in the
+program. The array parameter in these routines is treated simply as a
+large one-dimensional array of the appropriate data type containing the
+pixel values; The pixel values in the FITS array are read/written
+from/to this program array in strict sequence without any gaps; it is
+up to the calling routine to correctly interpret the dimensionality of
+this array. The two FITS reading routines (ffgsv\_ and ffgsf\_ ) also
+have an `inc' parameter which defines the data sampling interval in
+each dimension of the FITS array. For example, if inc[0]=2 and
+inc[1]=3 when reading a 2-dimensional FITS image, then only every other
+pixel in the first dimension and every 3rd pixel in the second
+dimension will be returned to the 'array' parameter.
+
+Two types of routines are provided to read the data array which differ in
+the way undefined pixels are handled. The first type of routines (e.g.,
+ffgpv\_) simply return an array of data elements in which undefined
+pixels are set equal to a value specified by the user in the `nulval'
+parameter. An additional feature of these routines is that if the user
+sets nulval = 0, then no checks for undefined pixels will be performed,
+thus reducing the amount of CPU processing. The second type of routines
+(e.g., ffgpf\_) returns the data element array and, in addition, a char
+array that indicates whether the value of the corresponding data pixel
+is undefined (= 1) or defined (= 0). The latter type of routines may
+be more convenient to use in some circumstances, however, it requires
+an additional array of logical values which can be unwieldy when working
+with large data arrays.
+
+
+\begin{description}
+\item[1 ] Write elements into the FITS data array.
+ \label{ffppr} \label{ffpprx} \label{ffppn} \label{ffppnx}
+\end{description}
+
+\begin{verbatim}
+ int fits_write_img / ffppr
+ (fitsfile *fptr, int datatype, long firstelem, long nelements,
+ DTYPE *array, int *status);
+
+ int fits_write_img_[byt, sht, usht, int, uint, lng, ulng, lnglng, flt, dbl] /
+ ffppr[b,i,ui,k,uk,j,uj,jj,e,d]
+ (fitsfile *fptr, long group, long firstelem, long nelements,
+ DTYPE *array, > int *status);
+
+ int fits_write_imgnull / ffppn
+ (fitsfile *fptr, int datatype, long firstelem, long nelements,
+ DTYPE *array, DTYPE *nulval, > int *status);
+
+ int fits_write_imgnull_[byt, sht, usht, int, uint, lng, ulng, lnglng, flt, dbl] /
+ ffppn[b,i,ui,k,uk,j,uj,jj,e,d]
+ (fitsfile *fptr, long group, long firstelem,
+ long nelements, DTYPE *array, DTYPE nulval, > int *status);
+\end{verbatim}
+
+\begin{description}
+\item[2 ]Set data array elements as undefined. \label{ffppru}
+\end{description}
+
+\begin{verbatim}
+ int fits_write_img_null / ffppru
+ (fitsfile *fptr, long group, long firstelem, long nelements,
+ > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[3 ] Write values into group parameters. This routine only applies
+ to the `Random Grouped' FITS format which has been used for
+ applications in radio interferometry, but is officially deprecated
+ for future use. \label{ffpgpx}
+\end{description}
+
+\begin{verbatim}
+ int fits_write_grppar_[byt, sht, usht, int, uint, lng, ulng, lnglng, flt, dbl] /
+ ffpgp[b,i,ui,k,uk,j,uj,jj,e,d]
+ (fitsfile *fptr, long group, long firstelem, long nelements,
+ > DTYPE *array, int *status)
+\end{verbatim}
+
+\begin{description}
+\item[4 ] Write a 2-D or 3-D image into the data array. \label{ffp2dx} \label{ffp3dx}
+\end{description}
+
+\begin{verbatim}
+ int fits_write_2d_[byt, sht, usht, int, uint, lng, ulng, lnglng, flt, dbl] /
+ ffp2d[b,i,ui,k,uk,j,uj,jj,e,d]
+ (fitsfile *fptr, long group, long dim1, long naxis1,
+ long naxis2, DTYPE *array, > int *status)
+
+ int fits_write_3d_[byt, sht, usht, int, uint, lng, ulng, lnglng, flt, dbl] /
+ ffp3d[b,i,ui,k,uk,j,uj,jj,e,d]
+ (fitsfile *fptr, long group, long dim1, long dim2,
+ long naxis1, long naxis2, long naxis3, DTYPE *array, > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[5 ] Write an arbitrary data subsection into the data array. \label{ffpssx}
+\end{description}
+
+\begin{verbatim}
+ int fits_write_subset_[byt, sht, usht, int, uint, lng, ulng, lnglng, flt, dbl] /
+ ffpss[b,i,ui,k,uk,j,uj,jj,e,d]
+ (fitsfile *fptr, long group, long naxis, long *naxes,
+ long *fpixel, long *lpixel, DTYPE *array, > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[6 ] Read elements from the FITS data array.
+ \label{ffgpv} \label{ffgpvx} \label{ffgpf} \label{ffgpfx}
+\end{description}
+
+\begin{verbatim}
+ int fits_read_img / ffgpv
+ (fitsfile *fptr, int datatype, long firstelem, long nelements,
+ DTYPE *nulval, > DTYPE *array, int *anynul, int *status)
+
+ int fits_read_img_[byt, sht, usht, int, uint, lng, ulng, lnglng, flt, dbl] /
+ ffgpv[b,i,ui,k,uk,j,uj,jj,e,d]
+ (fitsfile *fptr, long group, long firstelem, long nelements,
+ DTYPE nulval, > DTYPE *array, int *anynul, int *status)
+
+ int fits_read_imgnull / ffgpf
+ (fitsfile *fptr, int datatype, long firstelem, long nelements,
+ > DTYPE *array, char *nullarray, int *anynul, int *status)
+
+ int fits_read_imgnull_[byt, sht, usht, int, uint, lng, ulng, flt, dbl] /
+ ffgpf[b,i,ui,k,uk,j,uj,jj,e,d]
+ (fitsfile *fptr, long group, long firstelem, long nelements,
+ > DTYPE *array, char *nullarray, int *anynul, int *status)
+\end{verbatim}
+
+\begin{description}
+\item[7 ] Read values from group parameters. This routine only applies
+ to the `Random Grouped' FITS format which has been used for
+ applications in radio interferometry, but is officially deprecated
+ for future use. \label{ffggpx}
+\end{description}
+
+\begin{verbatim}
+ int fits_read_grppar_[byt, sht, usht, int, uint, lng, ulng, lnglng, flt, dbl] /
+ ffggp[b,i,ui,k,uk,j,uj,jj,e,d]
+ (fitsfile *fptr, long group, long firstelem, long nelements,
+ > DTYPE *array, int *status)
+\end{verbatim}
+
+\begin{description}
+\item[8 ] Read 2-D or 3-D image from the data array. Undefined
+ pixels in the array will be set equal to the value of 'nulval',
+ unless nulval=0 in which case no testing for undefined pixels will
+ be performed. \label{ffg2dx} \label{ffg3dx}
+\end{description}
+
+\begin{verbatim}
+ int fits_read_2d_[byt, sht, usht, int, uint, lng, ulng, lnglng, flt, dbl] /
+ ffg2d[b,i,ui,k,uk,j,uj,jj,e,d]
+ (fitsfile *fptr, long group, DTYPE nulval, long dim1, long naxis1,
+ long naxis2, > DTYPE *array, int *anynul, int *status)
+
+ int fits_read_3d_[byt, sht, usht, int, uint, lng, ulng, lnglng, flt, dbl] /
+ ffg3d[b,i,ui,k,uk,j,uj,jj,e,d]
+ (fitsfile *fptr, long group, DTYPE nulval, long dim1,
+ long dim2, long naxis1, long naxis2, long naxis3,
+ > DTYPE *array, int *anynul, int *status)
+\end{verbatim}
+
+\begin{description}
+\item[9 ] Read an arbitrary data subsection from the data array.
+ \label{ffgsvx} \label{ffgsfx}
+\end{description}
+
+\begin{verbatim}
+ int fits_read_subset_[byt, sht, usht, int, uint, lng, ulng, lnglng, flt, dbl] /
+ ffgsv[b,i,ui,k,uk,j,uj,jj,e,d]
+ (fitsfile *fptr, int group, int naxis, long *naxes,
+ long *fpixel, long *lpixel, long *inc, DTYPE nulval,
+ > DTYPE *array, int *anynul, int *status)
+
+ int fits_read_subsetnull_[byt, sht, usht, int, uint, lng, ulng, lnglng, flt, dbl] /
+ ffgsf[b,i,ui,k,uk,j,uj,jj,e,d]
+ (fitsfile *fptr, int group, int naxis, long *naxes,
+ long *fpixel, long *lpixel, long *inc, > DTYPE *array,
+ char *nullarray, int *anynul, int *status)
+\end{verbatim}
+
+
+\section{Specialized FITS ASCII and Binary Table Routines}
+
+
+\subsection{General Column Routines}
+
+
+\begin{description}
+\item[1 ] Get information about an existing ASCII or binary table column. A null
+ pointer may be given for any of the output parameters that are not
+ needed. DATATYPE is a character string which returns the data type
+ of the column as defined by the TFORMn keyword (e.g., 'I', 'J','E',
+ 'D', etc.). In the case of an ASCII character column, typecode
+ will have a value of the form 'An' where 'n' is an integer
+ expressing the width of the field in characters. For example, if
+ TFORM = '160A8' then ffgbcl will return typechar='A8' and
+ repeat=20. All the returned parameters are scalar quantities.
+ \label{ffgacl} \label{ffgbcl}
+\end{description}
+
+\begin{verbatim}
+ int fits_get_acolparms / ffgacl
+ (fitsfile *fptr, int colnum, > char *ttype, long *tbcol,
+ char *tunit, char *tform, double *scale, double *zero,
+ char *nulstr, char *tdisp, int *status)
+
+ int fits_get_bcolparms / ffgbcl
+ (fitsfile *fptr, int colnum, > char *ttype, char *tunit,
+ char *typechar, long *repeat, double *scale, double *zero,
+ long *nulval, char *tdisp, int *status)
+\end{verbatim}
+
+\begin{description}
+\item[2 ] Return optimal number of rows to read or write at one time for
+ maximum I/O efficiency. Refer to the
+ ``Optimizing Code'' section in Chapter 5 for more discussion on how
+ to use this routine. \label{ffgrsz}
+\end{description}
+
+\begin{verbatim}
+ int fits_get_rowsize / ffgrsz
+ (fitsfile *fptr, long *nrows, *status)
+\end{verbatim}
+
+\begin{description}
+\item[3 ] Define the zero indexed byte offset of the 'heap' measured from
+ the start of the binary table data. By default the heap is assumed
+ to start immediately following the regular table data, i.e., at
+ location NAXIS1 x NAXIS2. This routine is only relevant for
+ binary tables which contain variable length array columns (with
+ TFORMn = 'Pt'). This routine also automatically writes
+ the value of theap to a keyword in the extension header. This
+ routine must be called after the required keywords have been
+ written (with ffphbn)
+ but before any data is written to the table. \label{ffpthp}
+\end{description}
+
+\begin{verbatim}
+ int fits_write_theap / ffpthp
+ (fitsfile *fptr, long theap, > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[4 ] Test the contents of the binary table variable array heap, returning
+ the size of the heap, the number of unused bytes that are not currently
+ pointed to by any of the descriptors, and the number of bytes which are
+ pointed to by multiple descriptors. It also returns valid = FALSE if
+ any of the descriptors point to invalid addresses out of range of the
+ heap. \label{fftheap}
+\end{description}
+
+\begin{verbatim}
+ int fits_test_heap / fftheap
+ (fitsfile *fptr, > long *heapsize, long *unused, long *overlap,
+ int *validheap, int *status)
+\end{verbatim}
+
+\begin{description}
+\item[5 ] Re-pack the vectors in the binary table variable array heap to recover
+ any unused space. Normally, when a vector in a variable length
+ array column is rewritten the previously written array remains in
+ the heap as wasted unused space. This routine will repack the
+ arrays that are still in use, thus eliminating any bytes in the
+ heap that are no longer in use. Note that if several vectors point
+ to the same bytes in the heap, then this routine will make
+ duplicate copies of the bytes for each vector, which will actually
+ expand the size of the heap. \label{ffcmph}
+\end{description}
+
+\begin{verbatim}
+ int fits_compress_heap / ffcmph
+ (fitsfile *fptr, > int *status)
+\end{verbatim}
+
+
+\subsection{Low-Level Table Access Routines}
+
+The following 2 routines provide low-level access to the data in ASCII
+or binary tables and are mainly useful as an efficient way to copy all
+or part of a table from one location to another. These routines simply
+read or write the specified number of consecutive bytes in an ASCII or
+binary table, without regard for column boundaries or the row length in
+the table. These routines do not perform any machine dependent data
+conversion or byte swapping. See Appendix B for the definition of the
+parameters used in these routines.
+
+
+\begin{description}
+\item[1 ] Read or write a consecutive array of bytes from an ASCII or binary
+ table \label{ffgtbb} \label{ffptbb}
+\end{description}
+
+\begin{verbatim}
+ int fits_read_tblbytes / ffgtbb
+ (fitsfile *fptr, long firstrow, long firstchar, long nchars,
+ > unsigned char *values, int *status)
+
+ int fits_write_tblbytes / ffptbb
+ (fitsfile *fptr, long firstrow, long firstchar, long nchars,
+ unsigned char *values, > int *status)
+\end{verbatim}
+
+
+\subsection{Write Column Data Routines}
+
+
+\begin{description}
+\item[1 ] Write elements into an ASCII or binary table column (in the CDU).
+ The data type of the array is implied by the suffix of the
+ routine name. \label{ffpcls}
+\end{description}
+
+\begin{verbatim}
+ int fits_write_col_str / ffpcls
+ (fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelements, char **array, > int *status)
+
+ int fits_write_col_[log,byt,sht,usht,int,uint,lng,ulng,lnglng,flt,dbl,cmp,dblcmp] /
+ ffpcl[l,b,i,ui,k,uk,j,uj,jj,e,d,c,m]
+ (fitsfile *fptr, int colnum, long firstrow,
+ long firstelem, long nelements, DTYPE *array, > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[2 ] Write elements into an ASCII or binary table column
+ substituting the appropriate FITS null value for any elements that
+ are equal to the nulval parameter. This routines must not be used to
+ write to variable length array columns. \label{ffpcnx}
+\end{description}
+
+\begin{verbatim}
+ int fits_write_colnull_[log, byt, sht, usht, int, uint, lng, ulng, lnglng, flt, dbl] /
+ ffpcn[l,b,i,ui,k,uk,j,uj,jj,e,d]
+ (fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelements, DTYPE *array, DTYPE nulval, > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[3 ] Write string elements into a binary table column (in the CDU)
+ substituting the FITS null value for any elements that
+ are equal to the nulstr string. This routine must NOT be
+ used to write to variable length array columns. \label{ffpcns}
+\end{description}
+
+\begin{verbatim}
+ int fits_write_colnull_str / ffpcns
+ (fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelements, char **array, char *nulstr, > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[4 ] Write bit values into a binary byte ('B') or bit ('X') table column (in
+ the CDU). Larray is an array of characters corresponding to the
+ sequence of bits to be written. If an element of larray is true
+ (not equal to zero) then the corresponding bit in the FITS table is
+ set to 1, otherwise the bit is set to 0. The 'X' column in a FITS
+ table is always padded out to a multiple of 8 bits where the bit
+ array starts with the most significant bit of the byte and works
+ down towards the 1's bit. For example, a '4X' array, with the
+ first bit = 1 and the remaining 3 bits = 0 is equivalent to the 8-bit
+ unsigned byte decimal value of 128 ('1000 0000B'). In the case of
+ 'X' columns, CFITSIO can write to all 8 bits of each byte whether
+ they are formally valid or not. Thus if the column is defined as
+ '4X', and one calls ffpclx with firstbit=1 and nbits=8, then all
+ 8 bits will be written into the first byte (as opposed to writing
+ the first 4 bits into the first row and then the next 4 bits into
+ the next row), even though the last 4 bits of each byte are formally
+ not defined and should all be set = 0. It should also be noted that
+ it is more efficient to write 'X' columns an entire byte at a time,
+ instead of bit by bit. Any of the CFITSIO routines that write to
+ columns (e.g. fits\_write\_col\_byt) may be used for this purpose.
+ These routines will interpret 'X' columns as though they were 'B'
+ columns (e.g., '1X' through '8X' is equivalent
+ to '1B', and '9X' through '16X' is equivalent to '2B'). \label{ffpclx}
+\end{description}
+
+\begin{verbatim}
+ int fits_write_col_bit / ffpclx
+ (fitsfile *fptr, int colnum, long firstrow, long firstbit,
+ long nbits, char *larray, > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[5 ] Write the descriptor for a variable length column in a binary table.
+ This routine can be used in conjunction with ffgdes to enable
+ 2 or more arrays to point to the same storage location to save
+ storage space if the arrays are identical. \label{ffpdes}
+\end{description}
+
+\begin{verbatim}
+ int fits_write_descript / ffpdes
+ (fitsfile *fptr, int colnum, long rownum, long repeat,
+ long offset, > int *status)
+\end{verbatim}
+
+\subsection{Read Column Data Routines}
+
+Two types of routines are provided to get the column data which differ
+in the way undefined pixels are handled. The first set of routines
+(ffgcv) simply return an array of data elements in which undefined
+pixels are set equal to a value specified by the user in the 'nullval'
+parameter. If nullval = 0, then no checks for undefined pixels will be
+performed, thus increasing the speed of the program. The second set of
+routines (ffgcf) returns the data element array and in addition a
+logical array of flags which defines whether the corresponding data
+pixel is undefined. See Appendix B for the definition of the
+parameters used in these routines.
+
+ Any column, regardless of it's intrinsic data type, may be read as a
+ string. It should be noted however that reading a numeric column as
+ a string is 10 - 100 times slower than reading the same column as a number
+ due to the large overhead in constructing the formatted strings.
+ The display format of the returned strings will be
+ determined by the TDISPn keyword, if it exists, otherwise by the
+ data type of the column. The length of the returned strings (not
+ including the null terminating character) can be determined with
+ the fits\_get\_col\_display\_width routine. The following TDISPn
+ display formats are currently supported:
+
+\begin{verbatim}
+ Iw.m Integer
+ Ow.m Octal integer
+ Zw.m Hexadecimal integer
+ Fw.d Fixed floating point
+ Ew.d Exponential floating point
+ Dw.d Exponential floating point
+ Gw.d General; uses Fw.d if significance not lost, else Ew.d
+\end{verbatim}
+ where w is the width in characters of the displayed values, m is
+ the minimum number of digits displayed, and d is the number of
+ digits to the right of the decimal. The .m field is optional.
+
+
+\begin{description}
+\item[1 ] Read elements from an ASCII or binary table column (in the CDU). These
+ routines return the values of the table column array elements. Undefined
+ array elements will be returned with a value = nulval, unless nulval = 0
+ (or = ' ' for ffgcvs) in which case no checking for undefined values will
+ be performed. The ANYF parameter is set to true if any of the returned
+ elements are undefined. \label{ffgcvx}
+\end{description}
+
+\begin{verbatim}
+ int fits_read_col_str / ffgcvs
+ (fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelements, char *nulstr, > char **array, int *anynul,
+ int *status)
+
+ int fits_read_col_[log,byt,sht,usht,int,uint,lng,ulng, lnglng, flt, dbl, cmp, dblcmp] /
+ ffgcv[l,b,i,ui,k,uk,j,uj,jj,e,d,c,m]
+ (fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelements, DTYPE nulval, > DTYPE *array, int *anynul,
+ int *status)
+\end{verbatim}
+
+\begin{description}
+\item[2 ] Read elements and null flags from an ASCII or binary table column (in the
+ CHDU). These routines return the values of the table column array elements.
+ Any undefined array elements will have the corresponding nullarray element
+ set equal to TRUE. The anynul parameter is set to true if any of the
+ returned elements are undefined. \label{ffgcfx}
+\end{description}
+
+\begin{verbatim}
+ int fits_read_colnull_str / ffgcfs
+ (fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelements, > char **array, char *nullarray, int *anynul,
+ int *status)
+
+ int fits_read_colnull_[log,byt,sht,usht,int,uint,lng,ulng,lnglng,flt,dbl,cmp,dblcmp] /
+ ffgcf[l,b,i,ui,k,uk,j,uj,jj,e,d,c,m]
+ (fitsfile *fptr, int colnum, long firstrow,
+ long firstelem, long nelements, > DTYPE *array,
+ char *nullarray, int *anynul, int *status)
+\end{verbatim}
+
+\begin{description}
+\item[3 ] Read an arbitrary data subsection from an N-dimensional array
+ in a binary table vector column. Undefined pixels
+ in the array will be set equal to the value of 'nulval',
+ unless nulval=0 in which case no testing for undefined pixels will
+ be performed. The first and last rows in the table to be read
+ are specified by fpixel(naxis+1) and lpixel(naxis+1), and hence
+ are treated as the next higher dimension of the FITS N-dimensional
+ array. The INC parameter specifies the sampling interval in
+ each dimension between the data elements that will be returned. \label{ffgsvx2}
+\end{description}
+
+\begin{verbatim}
+ int fits_read_subset_[byt, sht, usht, int, uint, lng, ulng, lnglng, flt, dbl] /
+ ffgsv[b,i,ui,k,uk,j,uj,jj,e,d]
+ (fitsfile *fptr, int colnum, int naxis, long *naxes, long *fpixel,
+ long *lpixel, long *inc, DTYPE nulval, > DTYPE *array, int *anynul,
+ int *status)
+\end{verbatim}
+
+\begin{description}
+\item[4 ] Read an arbitrary data subsection from an N-dimensional array
+ in a binary table vector column. Any Undefined
+ pixels in the array will have the corresponding 'nullarray'
+ element set equal to TRUE. The first and last rows in the table
+ to be read are specified by fpixel(naxis+1) and lpixel(naxis+1),
+ and hence are treated as the next higher dimension of the FITS
+ N-dimensional array. The INC parameter specifies the sampling
+ interval in each dimension between the data elements that will be
+ returned. \label{ffgsfx2}
+\end{description}
+
+\begin{verbatim}
+ int fits_read_subsetnull_[byt, sht, usht, int, uint, lng, ulng, lnglng, flt, dbl] /
+ ffgsf[b,i,ui,k,uk,j,uj,jj,e,d]
+ (fitsfile *fptr, int colnum, int naxis, long *naxes,
+ long *fpixel, long *lpixel, long *inc, > DTYPE *array,
+ char *nullarray, int *anynul, int *status)
+\end{verbatim}
+
+\begin{description}
+\item[5 ] Read bit values from a byte ('B') or bit (`X`) table column (in the
+ CDU). Larray is an array of logical values corresponding to the
+ sequence of bits to be read. If larray is true then the
+ corresponding bit was set to 1, otherwise the bit was set to 0.
+ The 'X' column in a FITS table is always padded out to a multiple
+ of 8 bits where the bit array starts with the most significant bit
+ of the byte and works down towards the 1's bit. For example, a
+ '4X' array, with the first bit = 1 and the remaining 3 bits = 0 is
+ equivalent to the 8-bit unsigned byte value of 128.
+ Note that in the case of 'X' columns, CFITSIO can read all 8 bits
+ of each byte whether they are formally valid or not. Thus if the
+ column is defined as '4X', and one calls ffgcx with firstbit=1 and
+ nbits=8, then all 8 bits will be read from the first byte (as
+ opposed to reading the first 4 bits from the first row and then the
+ first 4 bits from the next row), even though the last 4 bits of
+ each byte are formally not defined. It should also be noted that
+ it is more efficient to read 'X' columns an entire byte at a time,
+ instead of bit by bit. Any of the CFITSIO routines that read
+ columns (e.g. fits\_read\_col\_byt) may be used for this
+ purpose. These routines will interpret 'X' columns as though they
+ were 'B' columns (e.g., '8X' is equivalent to '1B', and '16X' is
+ equivalent to '2B'). \label{ffgcx}
+\end{description}
+
+\begin{verbatim}
+ int fits_read_col_bit / ffgcx
+ (fitsfile *fptr, int colnum, long firstrow, long firstbit,
+ long nbits, > char *larray, int *status)
+\end{verbatim}
+
+\begin{description}
+\item[6 ] Read any consecutive set of bits from an 'X' or 'B' column and
+ interpret them as an unsigned n-bit integer. nbits must be less
+ than 16 or 32 in ffgcxui and ffgcxuk, respectively. If nrows
+ is greater than 1, then the same set of bits will be read from
+ each row, starting with firstrow. The bits are numbered with
+ 1 = the most significant bit of the first element of the column.
+ \label{ffgcxui}
+\end{description}
+
+\begin{verbatim}
+ int fits_read_col_bit_[usht, uint] / ffgcx[ui,uk]
+ (fitsfile *fptr, int colnum, long firstrow, long, nrows,
+ long firstbit, long nbits, > DTYPE *array, int *status)
+\end{verbatim}
+
+\begin{description}
+\item[7 ] Return the descriptor for a variable length column in a binary table.
+ The descriptor consists of 2 integer parameters: the number of elements
+ in the array and the starting offset relative to the start of the heap.
+ The first routine returns a single descriptor whereas the second routine
+ returns the descriptors for a range of rows in the table.
+ \label{ffgdes}
+\end{description}
+
+\begin{verbatim}
+ int fits_read_descript / ffgdes
+ (fitsfile *fptr, int colnum, long rownum, > long *repeat,
+ long *offset, int *status)
+
+ int fits_read_descripts / ffgdess
+ (fitsfile *fptr, int colnum, long firstrow, long nrows > long *repeat,
+ long *offset, int *status)
+\end{verbatim}
+
+\chapter{ Extended File Name Syntax }
+
+
+\section{Overview}
+
+CFITSIO supports an extended syntax when specifying the name of the
+data file to be opened or created that includes the following
+features:
+
+\begin{itemize}
+\item
+CFITSIO can read IRAF format images which have header file names that
+end with the '.imh' extension, as well as reading and writing FITS
+files, This feature is implemented in CFITSIO by first converting the
+IRAF image into a temporary FITS format file in memory, then opening
+the FITS file. Any of the usual CFITSIO routines then may be used to
+read the image header or data. Similarly, raw binary data arrays can
+be read by converting them on the fly into virtual FITS images.
+
+\item
+FITS files on the internet can be read (and sometimes written) using the FTP,
+HTTP, or ROOT protocols.
+
+\item
+FITS files can be piped between tasks on the stdin and stdout streams.
+
+\item
+FITS files can be read and written in shared memory. This can
+potentially achieve better data I/O performance compared to reading and
+writing the same FITS files on magnetic disk.
+
+\item
+Compressed FITS files in gzip or Unix COMPRESS format can be directly read.
+
+\item
+Output FITS files can be written directly in compressed gzip format,
+thus saving disk space.
+
+\item
+FITS table columns can be created, modified, or deleted 'on-the-fly' as
+the table is opened by CFITSIO. This creates a virtual FITS file containing
+the modifications that is then opened by the application program.
+
+\item
+Table rows may be selected, or filtered out, on the fly when the table
+is opened by CFITSIO, based on an user-specified expression.
+Only rows for which the expression evaluates to 'TRUE' are retained
+in the copy of the table that is opened by the application program.
+
+\item
+Histogram images may be created on the fly by binning the values in
+table columns, resulting in a virtual N-dimensional FITS image. The
+application program then only sees the FITS image (in the primary
+array) instead of the original FITS table.
+\end{itemize}
+
+The latter 3 table filtering features in particular add very powerful
+data processing capabilities directly into CFITSIO, and hence into
+every task that uses CFITSIO to read or write FITS files. For example,
+these features transform a very simple program that just copies an
+input FITS file to a new output file (like the `fitscopy' program that
+is distributed with CFITSIO) into a multipurpose FITS file processing
+tool. By appending fairly simple qualifiers onto the name of the input
+FITS file, the user can perform quite complex table editing operations
+(e.g., create new columns, or filter out rows in a table) or create
+FITS images by binning or histogramming the values in table columns.
+In addition, these functions have been coded using new state-of-the art
+algorithms that are, in some cases, 10 - 100 times faster than previous
+widely used implementations.
+
+Before describing the complete syntax for the extended FITS file names
+in the next section, here are a few examples of FITS file names that
+give a quick overview of the allowed syntax:
+
+\begin{itemize}
+\item
+{\tt myfile.fits}: the simplest case of a FITS file on disk in the current
+directory.
+
+\item
+{\tt myfile.imh}: opens an IRAF format image file and converts it on the
+fly into a temporary FITS format image in memory which can then be read with
+any other CFITSIO routine.
+
+\item
+{\tt rawfile.dat[i512,512]}: opens a raw binary data array (a 512 x 512
+short integer array in this case) and converts it on the fly into a
+temporary FITS format image in memory which can then be read with any
+other CFITSIO routine.
+
+\item
+{\tt myfile.fits.gz}: if this is the name of a new output file, the '.gz'
+suffix will cause it to be compressed in gzip format when it is written to
+disk.
+
+\item
+{\tt myfile.fits.gz[events, 2]}: opens and uncompresses the gzipped file
+myfile.fits then moves to the extension with the keywords EXTNAME
+= 'EVENTS' and EXTVER = 2.
+
+\item
+{\tt -}: a dash (minus sign) signifies that the input file is to be read
+from the stdin file stream, or that the output file is to be written to
+the stdout stream.
+
+\item
+{\tt ftp://legacy.gsfc.nasa.gov/test/vela.fits}: FITS files in any ftp
+archive site on the internet may be directly opened with read-only
+access.
+
+\item
+{\tt http://legacy.gsfc.nasa.gov/software/test.fits}: any valid URL to a
+FITS file on the Web may be opened with read-only access.
+
+\item
+{\tt root://legacy.gsfc.nasa.gov/test/vela.fits}: similar to ftp access
+except that it provides write as well as read access to the files
+across the network. This uses the root protocol developed at CERN.
+
+\item
+{\tt shmem://h2[events]}: opens the FITS file in a shared memory segment and
+moves to the EVENTS extension.
+
+\item
+{\tt mem://}: creates a scratch output file in core computer memory. The
+resulting 'file' will disappear when the program exits, so this
+is mainly useful for testing purposes when one does not want a
+permanent copy of the output file.
+
+\item
+{\tt myfile.fits[3; Images(10)]}: opens a copy of the image contained in the
+10th row of the 'Images' column in the binary table in the 3th extension
+of the FITS file. The virtual file that is opened by the application just
+contains this single image in the primary array.
+
+\item
+{\tt myfile.fits[1:512:2, 1:512:2]}: opens a section of the input image
+ranging from the 1st to the 512th pixel in X and Y, and selects every
+second pixel in both dimensions, resulting in a 256 x 256 pixel input image
+in this case.
+
+\item
+{\tt myfile.fits[EVENTS][col Rad = sqrt(X**2 + Y**2)]}: creates and opens
+a virtual file on the fly that is identical to
+myfile.fits except that it will contain a new column in the EVENTS
+extension called 'Rad' whose value is computed using the indicated
+expression which is a function of the values in the X and Y columns.
+
+\item
+{\tt myfile.fits[EVENTS][PHA > 5]}: creates and opens a virtual FITS
+files that is identical to 'myfile.fits' except that the EVENTS table
+will only contain the rows that have values of the PHA column greater
+than 5. In general, any arbitrary boolean expression using a C or
+Fortran-like syntax, which may combine AND and OR operators,
+may be used to select rows from a table.
+
+\item
+{\tt myfile.fits[EVENTS][bin (X,Y)=1,2048,4]}: creates a temporary FITS
+primary array image which is computed on the fly by binning (i.e,
+computing the 2-dimensional histogram) of the values in the X and Y
+columns of the EVENTS extension. In this case the X and Y coordinates
+range from 1 to 2048 and the image pixel size is 4 units in both
+dimensions, so the resulting image is 512 x 512 pixels in size.
+
+\item
+The final example combines many of these feature into one complex
+expression (it is broken into several lines for clarity):
+
+\begin{verbatim}
+ ftp://legacy.gsfc.nasa.gov/data/sample.fits.gz[EVENTS]
+ [col phacorr = pha * 1.1 - 0.3][phacorr >= 5.0 && phacorr <= 14.0]
+ [bin (X,Y)=32]
+\end{verbatim}
+In this case, CFITSIO (1) copies and uncompresses the FITS file from
+the ftp site on the legacy machine, (2) moves to the 'EVENTS'
+extension, (3) calculates a new column called 'phacorr', (4) selects
+the rows in the table that have phacorr in the range 5 to 14, and
+finally (5) bins the remaining rows on the X and Y column coordinates,
+using a pixel size = 32 to create a 2D image. All this processing is
+completely transparent to the application program, which simply sees
+the final 2-D image in the primary array of the opened file.
+\end{itemize}
+
+The full extended CFITSIO FITS file name can contain several different
+components depending on the context. These components are described in
+the following sections:
+
+\begin{verbatim}
+When creating a new file:
+ filetype://BaseFilename(templateName)[compress]
+
+When opening an existing primary array or image HDU:
+ filetype://BaseFilename(outName)[HDUlocation][ImageSection]
+
+When opening an existing table HDU:
+ filetype://BaseFilename(outName)[HDUlocation][colFilter][rowFilter][binSpec]
+\end{verbatim}
+The filetype, BaseFilename, outName, HDUlocation, and ImageSection
+components, if present, must be given in that order, but the colFilter,
+rowFilter, and binSpec specifiers may follow in any order. Regardless
+of the order, however, the colFilter specifier, if present, will be
+processed first by CFITSIO, followed by the rowFilter specifier, and
+finally by the binSpec specifier.
+
+
+\section{Filetype}
+
+The type of file determines the medium on which the file is located
+(e.g., disk or network) and, hence, which internal device driver is used by
+CFITSIO to read and/or write the file. Currently supported types are
+
+\begin{verbatim}
+ file:// - file on local magnetic disk (default)
+ ftp:// - a readonly file accessed with the anonymous FTP protocol.
+ It also supports ftp://username:password@hostname/...
+ for accessing password-protected ftp sites.
+ http:// - a readonly file accessed with the HTTP protocol. It
+ does not support username:password like the ftp driver.
+ Proxy HTTP survers are supported using the http_proxy
+ environment variable.
+ root:// - uses the CERN root protocol for writing as well as
+ reading files over the network.
+ shmem:// - opens or creates a file which persists in the computer's
+ shared memory.
+ mem:// - opens a temporary file in core memory. The file
+ disappears when the program exits so this is mainly
+ useful for test purposes when a permanent output file
+ is not desired.
+\end{verbatim}
+If the filetype is not specified, then type file:// is assumed.
+The double slashes '//' are optional and may be omitted in most cases.
+
+
+\subsection{Notes about HTTP proxy servers}
+
+A proxy HTTP server may be used by defining the address (URL) and port
+number of the proxy server with the http\_proxy environment variable.
+For example
+
+\begin{verbatim}
+ setenv http_proxy http://heasarc.gsfc.nasa.gov:3128
+\end{verbatim}
+will cause CFITSIO to use port 3128 on the heasarc proxy server whenever
+reading a FITS file with HTTP.
+
+
+\subsection{Notes about the root filetype}
+
+The original rootd server can be obtained from:
+\verb-ftp://root.cern.ch/root/rootd.tar.gz-
+but, for it to work correctly with CFITSIO one has to use a modified
+version which supports a command to return the length of the file.
+This modified version is available in rootd subdirectory
+in the CFITSIO ftp area at
+
+\begin{verbatim}
+ ftp://legacy.gsfc.nasa.gov/software/fitsio/c/root/rootd.tar.gz.
+\end{verbatim}
+
+This small server is started either by inetd when a client requests a
+connection to a rootd server or by hand (i.e. from the command line).
+The rootd server works with the ROOT TNetFile class. It allows remote
+access to ROOT database files in either read or write mode. By default
+TNetFile assumes port 432 (which requires rootd to be started as root).
+To run rootd via inetd add the following line to /etc/services:
+
+\begin{verbatim}
+ rootd 432/tcp
+\end{verbatim}
+and to /etc/inetd.conf, add the following line:
+
+\begin{verbatim}
+ rootd stream tcp nowait root /user/rdm/root/bin/rootd rootd -i
+\end{verbatim}
+Force inetd to reread its conf file with \verb+kill -HUP <pid inetd>+.
+You can also start rootd by hand running directly under your private
+account (no root system privileges needed). For example to start
+rootd listening on port 5151 just type: \verb+rootd -p 5151+
+Notice that no \& is needed. Rootd will go into background by itself.
+
+\begin{verbatim}
+ Rootd arguments:
+ -i says we were started by inetd
+ -p port# specifies a different port to listen on
+ -d level level of debug info written to syslog
+ 0 = no debug (default)
+ 1 = minimum
+ 2 = medium
+ 3 = maximum
+\end{verbatim}
+Rootd can also be configured for anonymous usage (like anonymous ftp).
+To setup rootd to accept anonymous logins do the following (while being
+logged in as root):
+
+\begin{verbatim}
+ - Add the following line to /etc/passwd:
+
+ rootd:*:71:72:Anonymous rootd:/var/spool/rootd:/bin/false
+
+ where you may modify the uid, gid (71, 72) and the home directory
+ to suite your system.
+
+ - Add the following line to /etc/group:
+
+ rootd:*:72:rootd
+
+ where the gid must match the gid in /etc/passwd.
+
+ - Create the directories:
+
+ mkdir /var/spool/rootd
+ mkdir /var/spool/rootd/tmp
+ chmod 777 /var/spool/rootd/tmp
+
+ Where /var/spool/rootd must match the rootd home directory as
+ specified in the rootd /etc/passwd entry.
+
+ - To make writeable directories for anonymous do, for example:
+
+ mkdir /var/spool/rootd/pub
+ chown rootd:rootd /var/spool/rootd/pub
+\end{verbatim}
+That's all. Several additional remarks: you can login to an anonymous
+server either with the names "anonymous" or "rootd". The password should
+be of type user@host.do.main. Only the @ is enforced for the time
+being. In anonymous mode the top of the file tree is set to the rootd
+home directory, therefore only files below the home directory can be
+accessed. Anonymous mode only works when the server is started via
+inetd.
+
+
+\subsection{Notes about the shmem filetype:}
+
+Shared memory files are currently supported on most Unix platforms,
+where the shared memory segments are managed by the operating system
+kernel and `live' independently of processes. They are not deleted (by
+default) when the process which created them terminates, although they
+will disappear if the system is rebooted. Applications can create
+shared memory files in CFITSIO by calling:
+
+\begin{verbatim}
+ fit_create_file(&fitsfileptr, "shmem://h2", &status);
+\end{verbatim}
+where the root `file' names are currently restricted to be 'h0', 'h1',
+'h2', 'h3', etc., up to a maximum number defined by the the value of
+SHARED\_MAXSEG (equal to 16 by default). This is a prototype
+implementation of the shared memory interface and a more robust
+interface, which will have fewer restrictions on the number of files
+and on their names, may be developed in the future.
+
+When opening an already existing FITS file in shared memory one calls
+the usual CFITSIO routine:
+
+\begin{verbatim}
+ fits_open_file(&fitsfileptr, "shmem://h7", mode, &status)
+\end{verbatim}
+The file mode can be READWRITE or READONLY just as with disk files.
+More than one process can operate on READONLY mode files at the same
+time. CFITSIO supports proper file locking (both in READONLY and
+READWRITE modes), so calls to fits\_open\_file may be locked out until
+another other process closes the file.
+
+When an application is finished accessing a FITS file in a shared
+memory segment, it may close it (and the file will remain in the
+system) with fits\_close\_file, or delete it with fits\_delete\_file.
+Physical deletion is postponed until the last process calls
+ffclos/ffdelt. fits\_delete\_file tries to obtain a READWRITE lock on
+the file to be deleted, thus it can be blocked if the object was not
+opened in READWRITE mode.
+
+A shared memory management utility program called `smem', is included
+with the CFITSIO distribution. It can be built by typing `make smem';
+then type `smem -h' to get a list of valid options. Executing smem
+without any options causes it to list all the shared memory segments
+currently residing in the system and managed by the shared memory
+driver. To get a list of all the shared memory objects, run the system
+utility program `ipcs [-a]'.
+
+
+\section{Base Filename}
+
+The base filename is the name of the file optionally including the
+director/subdirectory path, and in the case of `ftp', `http', and `root'
+filetypes, the machine identifier. Examples:
+
+\begin{verbatim}
+ myfile.fits
+ !data.fits
+ /data/myfile.fits
+ fits.gsfc.nasa.gov/ftp/sampledata/myfile.fits.gz
+\end{verbatim}
+
+When creating a new output file on magnetic disk (of type file://) if
+the base filename begins with an exclamation point (!) then any
+existing file with that same basename will be deleted prior to creating
+the new FITS file. Otherwise if the file to be created already exists,
+then CFITSIO will return an error and will not overwrite the existing
+file. Note that the exclamation point, '!', is a special UNIX
+character, so if it is used on the command line rather than entered at
+a task prompt, it must be preceded by a backslash to force the UNIX
+shell to pass it verbatim to the application program.
+
+If the output disk file name ends with the suffix '.gz', then CFITSIO
+will compress the file using the gzip compression algorithm before
+writing it to disk. This can reduce the amount of disk space used by
+the file. Note that this feature requires that the uncompressed file
+be constructed in memory before it is compressed and written to disk,
+so it can fail if there is insufficient available memory.
+
+An input FITS file may be compressed with the gzip or Unix compress
+algorithms, in which case CFITSIO will uncompress the file on the fly
+into a temporary file (in memory or on disk). Compressed files may
+only be opened with read-only permission. When specifying the name of
+a compressed FITS file it is not necessary to append the file suffix
+(e.g., `.gz' or `.Z'). If CFITSIO cannot find the input file name
+without the suffix, then it will automatically search for a compressed
+file with the same root name. In the case of reading ftp and http type
+files, CFITSIO generally looks for a compressed version of the file
+first, before trying to open the uncompressed file. By default,
+CFITSIO copies (and uncompressed if necessary) the ftp or http FITS
+file into memory on the local machine before opening it. This will
+fail if the local machine does not have enough memory to hold the whole
+FITS file, so in this case, the output filename specifier (see the next
+section) can be used to further control how CFITSIO reads ftp and http
+files.
+
+If the input file is an IRAF image file (*.imh file) then CFITSIO will
+automatically convert it on the fly into a virtual FITS image before it
+is opened by the application program. IRAF images can only be opened
+with READONLY file access.
+
+Similarly, if the input file is a raw binary data array, then CFITSIO
+will convert it on the fly into a virtual FITS image with the basic set
+of required header keywords before it is opened by the application
+program (with READONLY access). In this case the data type and
+dimensions of the image must be specified in square brackets following
+the filename (e.g. rawfile.dat[ib512,512]). The first character (case
+insensitive) defines the data type of the array:
+
+\begin{verbatim}
+ b 8-bit unsigned byte
+ i 16-bit signed integer
+ u 16-bit unsigned integer
+ j 32-bit signed integer
+ r or f 32-bit floating point
+ d 64-bit floating point
+\end{verbatim}
+An optional second character specifies the byte order of the array
+values: b or B indicates big endian (as in FITS files and the native
+format of SUN UNIX workstations and Mac PCs) and l or L indicates
+little endian (native format of DEC OSF workstations and IBM PCs). If
+this character is omitted then the array is assumed to have the native
+byte order of the local machine. These data type characters are then
+followed by a series of one or more integer values separated by commas
+which define the size of each dimension of the raw array. Arrays with
+up to 5 dimensions are currently supported. Finally, a byte offset to
+the position of the first pixel in the data file may be specified by
+separating it with a ':' from the last dimension value. If omitted, it
+is assumed that the offset = 0. This parameter may be used to skip
+over any header information in the file that precedes the binary data.
+Further examples:
+
+\begin{verbatim}
+ raw.dat[b10000] 1-dimensional 10000 pixel byte array
+ raw.dat[rb400,400,12] 3-dimensional floating point big-endian array
+ img.fits[ib512,512:2880] reads the 512 x 512 short integer array in
+ a FITS file, skipping over the 2880 byte header
+\end{verbatim}
+
+One special case of input file is where the filename = `-' (a dash or
+minus sign) or 'stdin' or 'stdout', which signifies that the input file
+is to be read from the stdin stream, or written to the stdout stream if
+a new output file is being created. In the case of reading from stdin,
+CFITSIO first copies the whole stream into a temporary FITS file (in
+memory or on disk), and subsequent reading of the FITS file occurs in
+this copy. When writing to stdout, CFITSIO first constructs the whole
+file in memory (since random access is required), then flushes it out
+to the stdout stream when the file is closed. In addition, if the
+output filename = '-.gz' or 'stdout.gz' then it will be gzip compressed
+before being written to stdout.
+
+This ability to read and write on the stdin and stdout steams allows
+FITS files to be piped between tasks in memory rather than having to
+create temporary intermediate FITS files on disk. For example if task1
+creates an output FITS file, and task2 reads an input FITS file, the
+FITS file may be piped between the 2 tasks by specifying
+
+\begin{verbatim}
+ task1 - | task2 -
+\end{verbatim}
+where the vertical bar is the Unix piping symbol. This assumes that the 2
+tasks read the name of the FITS file off of the command line.
+
+
+\section{Output File Name when Opening an Existing File}
+
+An optional output filename may be specified in parentheses immediately
+following the base file name to be opened. This is mainly useful in
+those cases where CFITSIO creates a temporary copy of the input FITS
+file before it is opened and passed to the application program. This
+happens by default when opening a network FTP or HTTP-type file, when
+reading a compressed FITS file on a local disk, when reading from the
+stdin stream, or when a column filter, row filter, or binning specifier
+is included as part of the input file specification. By default this
+temporary file is created in memory. If there is not enough memory to
+create the file copy, then CFITSIO will exit with an error. In these
+cases one can force a permanent file to be created on disk, instead of
+a temporary file in memory, by supplying the name in parentheses
+immediately following the base file name. The output filename can
+include the '!' clobber flag.
+
+Thus, if the input filename to CFITSIO is:
+\verb+file1.fits.gz(file2.fits)+
+then CFITSIO will uncompress `file1.fits.gz' into the local disk file
+`file2.fits' before opening it. CFITSIO does not automatically delete
+the output file, so it will still exist after the application program
+exits.
+
+The output filename "mem://" is also allowed, which will write the
+output file into memory, and also allow write access to the file. This
+'file' will disappear when it is closed, but this may be useful for
+some applications which only need to modify a temporary copy of the file.
+
+In some cases, several different temporary FITS files will be created
+in sequence, for instance, if one opens a remote file using FTP, then
+filters rows in a binary table extension, then create an image by
+binning a pair of columns. In this case, the remote file will be
+copied to a temporary local file, then a second temporary file will be
+created containing the filtered rows of the table, and finally a third
+temporary file containing the binned image will be created. In cases
+like this where multiple files are created, the outfile specifier will
+be interpreted the name of the final file as described below, in descending
+priority:
+
+\begin{itemize}
+\item
+as the name of the final image file if an image within a single binary
+table cell is opened or if an image is created by binning a table column.
+\item
+as the name of the file containing the filtered table if a column filter
+and/or a row filter are specified.
+\item
+as the name of the local copy of the remote FTP or HTTP file.
+\item
+as the name of the uncompressed version of the FITS file, if a
+compressed FITS file on local disk has been opened.
+\item
+otherwise, the output filename is ignored.
+\end{itemize}
+
+The output file specifier is useful when reading FTP or HTTP-type
+FITS files since it can be used to create a local disk copy of the file
+that can be reused in the future. If the output file name = `*' then a
+local file with the same name as the network file will be created.
+Note that CFITSIO will behave differently depending on whether the
+remote file is compressed or not as shown by the following examples:
+\begin{itemize}
+\item
+\verb+ftp://remote.machine/tmp/myfile.fits.gz(*)+ - the remote compressed
+file is copied to the local compressed file `myfile.fits.gz', which
+is then uncompressed in local memory before being opened and passed
+to the application program.
+
+\item
+\verb+ftp://remote.machine/tmp/myfile.fits.gz(myfile.fits)+ - the
+remote compressed file is copied and uncompressed into the local file
+`myfile.fits'. This example requires less local memory than the
+previous example since the file is uncompressed on disk instead of in
+memory.
+
+\item
+\verb+ftp://remote.machine/tmp/myfile.fits(myfile.fits.gz)+ - this will
+usually produce an error since CFITSIO itself cannot compress files.
+\end{itemize}
+
+The exact behavior of CFITSIO in the latter case depends on the type of
+ftp server running on the remote machine and how it is configured. In
+some cases, if the file `myfile.fits.gz' exists on the remote machine,
+then the server will copy it to the local machine. In other cases the
+ftp server will automatically create and transmit a compressed version
+of the file if only the uncompressed version exists. This can get
+rather confusing, so users should use a certain amount of caution when
+using the output file specifier with FTP or HTTP file types, to make
+sure they get the behavior that they expect.
+
+
+\section{Template File Name when Creating a New File}
+
+When a new FITS file is created with a call to fits\_create\_file, the
+name of a template file may be supplied in parentheses immediately
+following the name of the new file to be created. This template is
+used to define the structure of one or more HDUs in the new file. The
+template file may be another FITS file, in which case the newly created
+file will have exactly the same keywords in each HDU as in the template
+FITS file, but all the data units will be filled with zeros. The
+template file may also be an ASCII text file, where each line (in
+general) describes one FITS keyword record. The format of the ASCII
+template file is described in the following Template Files chapter.
+
+
+\section{Image Tile-Compression Specification}
+
+When specifying the name of the output FITS file to be created, the
+user can indicate that images should be written in tile-compressed
+format (see section 5.5, ``Primary Array or IMAGE Extension I/O
+Routines'') by enclosing the compression parameters in square brackets
+following the root disk file name. Here are some examples of the
+syntax for specifying tile-compressed output images:
+
+\begin{verbatim}
+ myfile.fit[compress] - use Rice algorithm and default tile size
+
+ myfile.fit[compress GZIP] - use the specified compression algorithm;
+ myfile.fit[compress Rice] only the first letter of the algorithm
+ myfile.fit[compress PLIO] name is required.
+
+ myfile.fit[compress Rice 100,100] - use 100 x 100 pixel tile size
+ myfile.fit[compress Rice 100,100;2] - as above, and use noisebits = 2
+\end{verbatim}
+
+
+\section{HDU Location Specification}
+
+The optional HDU location specifier defines which HDU (Header-Data
+Unit, also known as an `extension') within the FITS file to initially
+open. It must immediately follow the base file name (or the output
+file name if present). If it is not specified then the first HDU (the
+primary array) is opened. The HDU location specifier is required if
+the colFilter, rowFilter, or binSpec specifiers are present, because
+the primary array is not a valid HDU for these operations. The HDU may
+be specified either by absolute position number, starting with 0 for
+the primary array, or by reference to the HDU name, and optionally, the
+version number and the HDU type of the desired extension. The location
+of an image within a single cell of a binary table may also be
+specified, as described below.
+
+The absolute position of the extension is specified either by enclosed
+the number in square brackets (e.g., `[1]' = the first extension
+following the primary array) or by preceded the number with a plus sign
+(`+1'). To specify the HDU by name, give the name of the desired HDU
+(the value of the EXTNAME or HDUNAME keyword) and optionally the
+extension version number (value of the EXTVER keyword) and the
+extension type (value of the XTENSION keyword: IMAGE, ASCII or TABLE,
+or BINTABLE), separated by commas and all enclosed in square brackets.
+If the value of EXTVER and XTENSION are not specified, then the first
+extension with the correct value of EXTNAME is opened. The extension
+name and type are not case sensitive, and the extension type may be
+abbreviated to a single letter (e.g., I = IMAGE extension or primary
+array, A or T = ASCII table extension, and B = binary table BINTABLE
+extension). If the HDU location specifier is equal to `[PRIMARY]' or
+`[P]', then the primary array (the first HDU) will be opened.
+
+FITS images are most commonly stored in the primary array or an image
+extension, but images can also be stored as a vector in a single cell
+of a binary table (i.e. each row of the vector column contains a
+different image). Such an image can be opened with CFITSIO by
+specifying the desired column name and the row number after the binary
+table HDU specifier as shown in the following examples. The column name
+is separated from the HDU specifier by a semicolon and the row number
+is enclosed in parentheses. In this case CFITSIO copies the image from
+the table cell into a temporary primary array before it is opened. The
+application program then just sees the image in the primary array,
+without any extensions. The particular row to be opened may be
+specified either by giving an absolute integer row number (starting
+with 1 for the first row), or by specifying a boolean expression that
+evaluates to TRUE for the desired row. The first row that satisfies
+the expression will be used. The row selection expression has the same
+syntax as described in the Row Filter Specifier section, below.
+
+ Examples:
+
+\begin{verbatim}
+ myfile.fits[3] - open the 3rd HDU following the primary array
+ myfile.fits+3 - same as above, but using the FTOOLS-style notation
+ myfile.fits[EVENTS] - open the extension that has EXTNAME = 'EVENTS'
+ myfile.fits[EVENTS, 2] - same as above, but also requires EXTVER = 2
+ myfile.fits[events,2,b] - same, but also requires XTENSION = 'BINTABLE'
+ myfile.fits[3; images(17)] - opens the image in row 17 of the 'images'
+ column in the 3rd extension of the file.
+ myfile.fits[3; images(exposure > 100)] - as above, but opens the image
+ in the first row that has an 'exposure' column value
+ greater than 100.
+\end{verbatim}
+
+
+\section{Image Section}
+
+A virtual file containing a rectangular subsection of an image can be
+extracted and opened by specifying the range of pixels (start:end)
+along each axis to be extracted from the original image. One can also
+specify an optional pixel increment (start:end:step) for each axis of
+the input image. A pixel step = 1 will be assumed if it is not
+specified. If the start pixel is larger then the end pixel, then the
+image will be flipped (producing a mirror image) along that dimension.
+An asterisk, '*', may be used to specify the entire range of an axis,
+and '-*' will flip the entire axis. The input image can be in the
+primary array, in an image extension, or contained in a vector cell of
+a binary table. In the later 2 cases the extension name or number must
+be specified before the image section specifier.
+
+ Examples:
+
+\begin{verbatim}
+ myfile.fits[1:512:2, 2:512:2] - open a 256x256 pixel image
+ consisting of the odd numbered columns (1st axis) and
+ the even numbered rows (2nd axis) of the image in the
+ primary array of the file.
+
+ myfile.fits[*, 512:256] - open an image consisting of all the columns
+ in the input image, but only rows 256 through 512.
+ The image will be flipped along the 2nd axis since
+ the starting pixel is greater than the ending pixel.
+
+ myfile.fits[*:2, 512:256:2] - same as above but keeping only
+ every other row and column in the input image.
+
+ myfile.fits[-*, *] - copy the entire image, flipping it along
+ the first axis.
+
+ myfile.fits[3][1:256,1:256] - opens a subsection of the image that
+ is in the 3rd extension of the file.
+
+ myfile.fits[4; images(12)][1:10,1:10] - open an image consisting
+ of the first 10 pixels in both dimensions. The original
+ image resides in the 12th row of the 'images' vector
+ column in the table in the 4th extension of the file.
+\end{verbatim}
+
+When CFITSIO opens an image section it first creates a temporary file
+containing the image section plus a copy of any other HDUs in the
+file. This temporary file is then opened by the application program,
+so it is not possible to write to or modify the input file when
+specifying an image section. Note that CFITSIO automatically updates
+the world coordinate system keywords in the header of the image
+section, if they exist, so that the coordinate associated with each
+pixel in the image section will be computed correctly.
+
+
+\section{Column and Keyword Filtering Specification}
+
+The optional column/keyword filtering specifier is used to modify the
+column structure and/or the header keywords in the HDU that was
+selected with the previous HDU location specifier. This filtering
+specifier must be enclosed in square brackets and can be distinguished
+from a general row filter specifier (described below) by the fact that
+it begins with the string 'col ' and is not immediately followed by an
+equals sign. The original file is not changed by this filtering
+operation, and instead the modifications are made on a copy of the
+input FITS file (usually in memory), which also contains a copy of all
+the other HDUs in the file. This temporary file is passed to the
+application program and will persist only until the file is closed or
+until the program exits, unless the outfile specifier (see above) is
+also supplied.
+
+The column/keyword filter can be used to perform the following
+operations. More than one operation may be specified by separating
+them with semi-colons.
+
+\begin{itemize}
+
+\item
+Copy only a specified list of columns columns to the filtered input file.
+The list of column name should be separated by semi-colons. Wild card
+characters may be used in the column names to match multiple columns.
+If the expression contains both a list of columns to be included and
+columns to be deleted, then all the columns in the original table
+except the explicitly deleted columns will appear in the filtered
+table (i.e., there is no need to explicitly list the columns to
+be included if any columns are being deleted).
+
+\item
+Delete a column or keyword by listing the name preceded by a minus sign
+or an exclamation mark (!), e.g., '-TIME' will delete the TIME column
+if it exists, otherwise the TIME keyword. An error is returned if
+neither a column nor keyword with this name exists. Note that the
+exclamation point, '!', is a special UNIX character, so if it is used
+on the command line rather than entered at a task prompt, it must be
+preceded by a backslash to force the UNIX shell to ignore it.
+
+\item
+Rename an existing column or keyword with the syntax 'NewName ==
+OldName'. An error is returned if neither a column nor keyword with
+this name exists.
+
+\item
+Append a new column or keyword to the table. To create a column,
+give the new name, optionally followed by the data type in parentheses,
+followed by a single equals sign and an expression to be used to
+compute the value (e.g., 'newcol(1J) = 0' will create a new 32-bit
+integer column called 'newcol' filled with zeros). The data type is
+specified using the same syntax that is allowed for the value of the
+FITS TFORMn keyword (e.g., 'I', 'J', 'E', 'D', etc. for binary tables,
+and 'I8', F12.3', 'E20.12', etc. for ASCII tables). If the data type is
+not specified then an appropriate data type will be chosen depending on
+the form of the expression (may be a character string, logical, bit, long
+integer, or double column). An appropriate vector count (in the case
+of binary tables) will also be added if not explicitly specified.
+
+When creating a new keyword, the keyword name must be preceded by a
+pound sign '\#', and the expression must evaluate to a scalar
+(i.e., cannot have a column name in the expression). The comment
+string for the keyword may be specified in parentheses immediately
+following the keyword name (instead of supplying a data type as in
+the case of creating a new column).
+
+\item
+Recompute (overwrite) the values in an existing column or keyword by
+giving the name followed by an equals sign and an arithmetic
+expression.
+\end{itemize}
+
+The expression that is used when appending or recomputing columns or
+keywords can be arbitrarily complex and may be a function of other
+header keyword values and other columns (in the same row). The full
+syntax and available functions for the expression are described below
+in the row filter specification section.
+
+
+For complex or commonly used operations, one can also place the
+operations into an external text file and import it into the column
+filter using the syntax '[col @filename.txt]'. The operations can
+extend over multiple lines of the file, but multiple operations must
+still be separated by semicolons. Any lines in the external text file
+that begin with 2 slash characters ('//') will be ignored and may be
+used to add comments into the file.
+
+Examples:
+
+\begin{verbatim}
+ [col Time;rate] - only the Time and rate columns will
+ appear in the filtered input file.
+
+ [col Time;*raw] - include the Time column and any other
+ columns whose name ends with 'raw'.
+
+ [col -TIME; Good == STATUS] - deletes the TIME column and
+ renames the status column to 'Good'
+
+ [col PI=PHA * 1.1 + 0.2] - creates new PI column from PHA values
+
+ [col rate = rate/exposure] - recomputes the rate column by dividing
+ it by the EXPOSURE keyword value.
+\end{verbatim}
+
+
+\section{Row Filtering Specification}
+
+ When entering the name of a FITS table that is to be opened by a
+ program, an optional row filter may be specified to select a subset
+ of the rows in the table. A temporary new FITS file is created on
+ the fly which contains only those rows for which the row filter
+ expression evaluates to true. (The primary array and any other
+ extensions in the input file are also copied to the temporary
+ file). The original FITS file is closed and the new virtual file
+ is opened by the application program. The row filter expression is
+ enclosed in square brackets following the file name and extension
+ name (e.g., 'file.fits[events][GRADE==50]' selects only those rows
+ where the GRADE column value equals 50). When dealing with tables
+ where each row has an associated time and/or 2D spatial position,
+ the row filter expression can also be used to select rows based on
+ the times in a Good Time Intervals (GTI) extension, or on spatial
+ position as given in a SAO-style region file.
+
+
+\subsection{General Syntax}
+
+ The row filtering expression can be an arbitrarily complex series
+ of operations performed on constants, keyword values, and column
+ data taken from the specified FITS TABLE extension. The expression
+ must evaluate to a boolean value for each row of the table, where
+ a value of FALSE means that the row will be excluded.
+
+ For complex or commonly used filters, one can place the expression
+ into a text file and import it into the row filter using the syntax
+ '[@filename.txt]'. The expression can be arbitrarily complex and
+ extend over multiple lines of the file. Any lines in the external
+ text file that begin with 2 slash characters ('//') will be ignored
+ and may be used to add comments into the file.
+
+ Keyword and column data are referenced by name. Any string of
+ characters not surrounded by quotes (ie, a constant string) or
+ followed by an open parentheses (ie, a function name) will be
+ initially interpreted as a column name and its contents for the
+ current row inserted into the expression. If no such column exists,
+ a keyword of that name will be searched for and its value used, if
+ found. To force the name to be interpreted as a keyword (in case
+ there is both a column and keyword with the same name), precede the
+ keyword name with a single pound sign, '\#', as in '\#NAXIS2'. Due to
+ the generalities of FITS column and keyword names, if the column or
+ keyword name contains a space or a character which might appear as
+ an arithmetic term then inclose the name in '\$' characters as in
+ \$MAX PHA\$ or \#\$MAX-PHA\$. Names are case insensitive.
+
+ To access a table entry in a row other than the current one, follow
+ the column's name with a row offset within curly braces. For
+ example, 'PHA\{-3\}' will evaluate to the value of column PHA, 3 rows
+ above the row currently being processed. One cannot specify an
+ absolute row number, only a relative offset. Rows that fall outside
+ the table will be treated as undefined, or NULLs.
+
+ Boolean operators can be used in the expression in either their
+ Fortran or C forms. The following boolean operators are available:
+
+\begin{verbatim}
+ "equal" .eq. .EQ. == "not equal" .ne. .NE. !=
+ "less than" .lt. .LT. < "less than/equal" .le. .LE. <= =<
+ "greater than" .gt. .GT. > "greater than/equal" .ge. .GE. >= =>
+ "or" .or. .OR. || "and" .and. .AND. &&
+ "negation" .not. .NOT. ! "approx. equal(1e-7)" ~
+\end{verbatim}
+
+Note that the exclamation
+point, '!', is a special UNIX character, so if it is used on the
+command line rather than entered at a task prompt, it must be preceded
+by a backslash to force the UNIX shell to ignore it.
+
+ The expression may also include arithmetic operators and functions.
+ Trigonometric functions use radians, not degrees. The following
+ arithmetic operators and functions can be used in the expression
+ (function names are case insensitive). A null value will be returned
+ in case of illegal operations such as divide by zero, sqrt(negative)
+ log(negative), log10(negative), arccos(.gt. 1), arcsin(.gt. 1).
+
+
+\begin{verbatim}
+ "addition" + "subtraction" -
+ "multiplication" * "division" /
+ "negation" - "exponentiation" ** ^
+ "absolute value" abs(x) "cosine" cos(x)
+ "sine" sin(x) "tangent" tan(x)
+ "arc cosine" arccos(x) "arc sine" arcsin(x)
+ "arc tangent" arctan(x) "arc tangent" arctan2(x,y)
+ "hyperbolic cos" cosh(x) "hyperbolic sin" sinh(x)
+ "hyperbolic tan" tanh(x) "round to nearest int" round(x)
+ "round down to int" floor(x) "round up to int" ceil(x)
+ "exponential" exp(x) "square root" sqrt(x)
+ "natural log" log(x) "common log" log10(x)
+ "modulus" i % j "random # [0.0,1.0)" random()
+ "minimum" min(x,y) "maximum" max(x,y)
+ "cumulative sum" accum(x) "sequential difference" seqdiff(x)
+ "if-then-else" b?x:y
+\end{verbatim}
+
+ An alternate syntax for the min and max functions has only a single
+ argument which should be a vector value (see below). The result
+ will be the minimum/maximum element contained within the vector.
+
+ The accum(x) function forms the cumulative sum of x, element by element.
+ Vector columns are supported simply by performing the summation process
+ through all the values. Null values are treated as 0. The seqdiff(x)
+ function forms the sequential difference of x, element by element.
+ The first value of seqdiff is the first value of x. A single null
+ value in x causes a pair of nulls in the output. The seqdiff and
+ accum functions are functional inverses, i.e., seqdiff(accum(x)) == x
+ as long as no null values are present.
+
+ The following type casting operators are available, where the
+ inclosing parentheses are required and taken from the C language
+ usage. Also, the integer to real casts values to double precision:
+
+\begin{verbatim}
+ "real to integer" (int) x (INT) x
+ "integer to real" (float) i (FLOAT) i
+\end{verbatim}
+
+ In addition, several constants are built in for use in numerical
+ expressions:
+
+
+\begin{verbatim}
+ #pi 3.1415... #e 2.7182...
+ #deg #pi/180 #row current row number
+ #null undefined value #snull undefined string
+\end{verbatim}
+
+ A string constant must be enclosed in quotes as in 'Crab'. The
+ "null" constants are useful for conditionally setting table values
+ to a NULL, or undefined, value (eg., "col1==-99 ? \#NULL : col1").
+
+ There is also a function for testing if two values are close to
+ each other, i.e., if they are "near" each other to within a user
+ specified tolerance. The arguments, value\_1 and value\_2 can be
+ integer or real and represent the two values who's proximity is
+ being tested to be within the specified tolerance, also an integer
+ or real:
+
+\begin{verbatim}
+ near(value_1, value_2, tolerance)
+\end{verbatim}
+ When a NULL, or undefined, value is encountered in the FITS table,
+ the expression will evaluate to NULL unless the undefined value is
+ not actually required for evaluation, e.g. "TRUE .or. NULL"
+ evaluates to TRUE. The following two functions allow some NULL
+ detection and handling:
+
+\begin{verbatim}
+ "a null value?" ISNULL(x)
+ "define a value for null" DEFNULL(x,y)
+\end{verbatim}
+ The former
+ returns a boolean value of TRUE if the argument x is NULL. The
+ later "defines" a value to be substituted for NULL values; it
+ returns the value of x if x is not NULL, otherwise it returns the
+ value of y.
+
+
+
+
+\subsection{Bit Masks}
+
+ Bit masks can be used to select out rows from bit columns (TFORMn =
+ \#X) in FITS files. To represent the mask, binary, octal, and hex
+ formats are allowed:
+
+
+\begin{verbatim}
+ binary: b0110xx1010000101xxxx0001
+ octal: o720x1 -> (b111010000xxx001)
+ hex: h0FxD -> (b00001111xxxx1101)
+\end{verbatim}
+
+ In all the representations, an x or X is allowed in the mask as a
+ wild card. Note that the x represents a different number of wild
+ card bits in each representation. All representations are case
+ insensitive.
+
+ To construct the boolean expression using the mask as the boolean
+ equal operator described above on a bit table column. For example,
+ if you had a 7 bit column named flags in a FITS table and wanted
+ all rows having the bit pattern 0010011, the selection expression
+ would be:
+
+
+\begin{verbatim}
+ flags == b0010011
+ or
+ flags .eq. b10011
+\end{verbatim}
+
+ It is also possible to test if a range of bits is less than, less
+ than equal, greater than and greater than equal to a particular
+ boolean value:
+
+
+\begin{verbatim}
+ flags <= bxxx010xx
+ flags .gt. bxxx100xx
+ flags .le. b1xxxxxxx
+\end{verbatim}
+
+ Notice the use of the x bit value to limit the range of bits being
+ compared.
+
+ It is not necessary to specify the leading (most significant) zero
+ (0) bits in the mask, as shown in the second expression above.
+
+ Bit wise AND, OR and NOT operations are also possible on two or
+ more bit fields using the '\&'(AND), '$|$'(OR), and the '!'(NOT)
+ operators. All of these operators result in a bit field which can
+ then be used with the equal operator. For example:
+
+
+\begin{verbatim}
+ (!flags) == b1101100
+ (flags & b1000001) == bx000001
+\end{verbatim}
+
+ Bit fields can be appended as well using the '+' operator. Strings
+ can be concatenated this way, too.
+
+
+\subsection{Vector Columns}
+
+ Vector columns can also be used in building the expression. No
+ special syntax is required if one wants to operate on all elements
+ of the vector. Simply use the column name as for a scalar column.
+ Vector columns can be freely intermixed with scalar columns or
+ constants in virtually all expressions. The result will be of the
+ same dimension as the vector. Two vectors in an expression, though,
+ need to have the same number of elements and have the same
+ dimensions. The only places a vector column cannot be used (for
+ now, anyway) are the SAO region functions and the NEAR boolean
+ function.
+
+ Arithmetic and logical operations are all performed on an element by
+ element basis. Comparing two vector columns, eg "COL1 == COL2",
+ thus results in another vector of boolean values indicating which
+ elements of the two vectors are equal.
+
+ Eight functions are available that operate on a vector and return a
+ scalar result:
+
+\begin{verbatim}
+ "minimum" MIN(V) "maximum" MAX(V)
+ "average" AVERAGE(V) "median" MEDIAN(V)
+ "sumation" SUM(V) "standard deviation" STDDEV(V)
+ "# of values" NELEM(V) "# of non-null values" NVALID(V)
+\end{verbatim}
+ where V represents the name of a vector column or a manually
+ constructed vector using curly brackets as described below. The
+ first 6 of these functions ignore any null values in the vector when
+ computing the result.
+
+ The SUM function literally sums all the elements in x, returning a
+ scalar value. If V is a boolean vector, SUM returns the number
+ of TRUE elements. The NELEM function returns the number of elements
+ in vector V whereas NVALID return the number of non-null elements in
+ the vector. (NELEM also operates on bit and string columns,
+ returning their column widths.) As an example, to test whether all
+ elements of two vectors satisfy a given logical comparison, one can
+ use the expression
+
+\begin{verbatim}
+ SUM( COL1 > COL2 ) == NELEM( COL1 )
+\end{verbatim}
+
+ which will return TRUE if all elements of COL1 are greater than
+ their corresponding elements in COL2.
+
+ To specify a single element of a vector, give the column name
+ followed by a comma-separated list of coordinates enclosed in
+ square brackets. For example, if a vector column named PHAS exists
+ in the table as a one dimensional, 256 component list of numbers
+ from which you wanted to select the 57th component for use in the
+ expression, then PHAS[57] would do the trick. Higher dimensional
+ arrays of data may appear in a column. But in order to interpret
+ them, the TDIMn keyword must appear in the header. Assuming that a
+ (4,4,4,4) array is packed into each row of a column named ARRAY4D,
+ the (1,2,3,4) component element of each row is accessed by
+ ARRAY4D[1,2,3,4]. Arrays up to dimension 5 are currently
+ supported. Each vector index can itself be an expression, although
+ it must evaluate to an integer value within the bounds of the
+ vector. Vector columns which contain spaces or arithmetic operators
+ must have their names enclosed in "\$" characters as with
+ \$ARRAY-4D\$[1,2,3,4].
+
+ A more C-like syntax for specifying vector indices is also
+ available. The element used in the preceding example alternatively
+ could be specified with the syntax ARRAY4D[4][3][2][1]. Note the
+ reverse order of indices (as in C), as well as the fact that the
+ values are still ones-based (as in Fortran -- adopted to avoid
+ ambiguity for 1D vectors). With this syntax, one does not need to
+ specify all of the indices. To extract a 3D slice of this 4D
+ array, use ARRAY4D[4].
+
+ Variable-length vector columns are not supported.
+
+ Vectors can be manually constructed within the expression using a
+ comma-separated list of elements surrounded by curly braces ('\{\}').
+ For example, '\{1,3,6,1\}' is a 4-element vector containing the values
+ 1, 3, 6, and 1. The vector can contain only boolean, integer, and
+ real values (or expressions). The elements will be promoted to the
+ highest data type present. Any elements which are themselves
+ vectors, will be expanded out with each of its elements becoming an
+ element in the constructed vector.
+
+
+\subsection{Good Time Interval Filtering}
+
+ A common filtering method involves selecting rows which have a time
+ value which lies within what is called a Good Time Interval or GTI.
+ The time intervals are defined in a separate FITS table extension
+ which contains 2 columns giving the start and stop time of each
+ good interval. The filtering operation accepts only those rows of
+ the input table which have an associated time which falls within
+ one of the time intervals defined in the GTI extension. A high
+ level function, gtifilter(a,b,c,d), is available which evaluates
+ each row of the input table and returns TRUE or FALSE depending
+ whether the row is inside or outside the good time interval. The
+ syntax is
+
+\begin{verbatim}
+ gtifilter( [ "gtifile" [, expr [, "STARTCOL", "STOPCOL" ] ] ] )
+ or
+ gtifilter( [ 'gtifile' [, expr [, 'STARTCOL', 'STOPCOL' ] ] ] )
+\end{verbatim}
+ where each "[]" demarks optional parameters. Note that the quotes
+ around the gtifile and START/STOP column are required. Either single
+ or double quotes may be used. In cases where this expression is
+ entered on the Unix command line, enclose the entire expression in
+ double quotes, and then use single quotes within the expression to
+ enclose the 'gtifile' and other terms. It is also usually possible
+ to do the reverse, and enclose the whole expression in single quotes
+ and then use double quotes within the expression. The gtifile,
+ if specified, can be blank ("") which will mean to use the first
+ extension with the name "*GTI*" in the current file, a plain
+ extension specifier (eg, "+2", "[2]", or "[STDGTI]") which will be
+ used to select an extension in the current file, or a regular
+ filename with or without an extension specifier which in the latter
+ case will mean to use the first extension with an extension name
+ "*GTI*". Expr can be any arithmetic expression, including simply
+ the time column name. A vector time expression will produce a
+ vector boolean result. STARTCOL and STOPCOL are the names of the
+ START/STOP columns in the GTI extension. If one of them is
+ specified, they both must be.
+
+ In its simplest form, no parameters need to be provided -- default
+ values will be used. The expression "gtifilter()" is equivalent to
+
+\begin{verbatim}
+ gtifilter( "", TIME, "*START*", "*STOP*" )
+\end{verbatim}
+ This will search the current file for a GTI extension, filter the
+ TIME column in the current table, using START/STOP times taken from
+ columns in the GTI extension with names containing the strings
+ "START" and "STOP". The wildcards ('*') allow slight variations in
+ naming conventions such as "TSTART" or "STARTTIME". The same
+ default values apply for unspecified parameters when the first one
+ or two parameters are specified. The function automatically
+ searches for TIMEZERO/I/F keywords in the current and GTI
+ extensions, applying a relative time offset, if necessary.
+
+
+\subsection{Spatial Region Filtering}
+
+ Another common filtering method selects rows based on whether the
+ spatial position associated with each row is located within a given
+ 2-dimensional region. The syntax for this high-level filter is
+
+\begin{verbatim}
+ regfilter( "regfilename" [ , Xexpr, Yexpr [ , "wcs cols" ] ] )
+\end{verbatim}
+ where each "[]" demarks optional parameters. The region file name
+ is required and must be enclosed in quotes. The remaining
+ parameters are optional. The region file is an ASCII text file
+ which contains a list of one or more geometric shapes (circle,
+ ellipse, box, etc.) which defines a region on the celestial sphere
+ or an area within a particular 2D image. The region file is
+ typically generated using an image display program such as fv/POW
+ (distribute by the HEASARC), or ds9 (distributed by the Smithsonian
+ Astrophysical Observatory). Users should refer to the documentation
+ provided with these programs for more details on the syntax used in
+ the region files.
+
+ In its simpliest form, (e.g., regfilter("region.reg") ) the
+ coordinates in the default 'X' and 'Y' columns will be used to
+ determine if each row is inside or outside the area specified in
+ the region file. Alternate position column names, or expressions,
+ may be entered if needed, as in
+
+\begin{verbatim}
+ regfilter("region.reg", XPOS, YPOS)
+\end{verbatim}
+ Region filtering can be applied most unambiguously if the positions
+ in the region file and in the table to be filtered are both give in
+ terms of absolute celestial coordinate units. In this case the
+ locations and sizes of the geometric shapes in the region file are
+ specified in angular units on the sky (e.g., positions given in
+ R.A. and Dec. and sizes in arcseconds or arcminutes). Similarly,
+ each row of the filtered table will have a celestial coordinate
+ associated with it. This association is usually implemented using
+ a set of so-called 'World Coordinate System' (or WCS) FITS keywords
+ that define the coordinate transformation that must be applied to
+ the values in the 'X' and 'Y' columns to calculate the coordinate.
+
+ Alternatively, one can perform spatial filtering using unitless
+ 'pixel' coordinates for the regions and row positions. In this
+ case the user must be careful to ensure that the positions in the 2
+ files are self-consistent. A typical problem is that the region
+ file may be generated using a binned image, but the unbinned
+ coordinates are given in the event table. The ROSAT events files,
+ for example, have X and Y pixel coordinates that range from 1 -
+ 15360. These coordinates are typically binned by a factor of 32 to
+ produce a 480x480 pixel image. If one then uses a region file
+ generated from this image (in image pixel units) to filter the
+ ROSAT events file, then the X and Y column values must be converted
+ to corresponding pixel units as in:
+
+\begin{verbatim}
+ regfilter("rosat.reg", X/32.+.5, Y/32.+.5)
+\end{verbatim}
+ Note that this binning conversion is not necessary if the region
+ file is specified using celestial coordinate units instead of pixel
+ units because CFITSIO is then able to directly compare the
+ celestial coordinate of each row in the table with the celestial
+ coordinates in the region file without having to know anything
+ about how the image may have been binned.
+
+ The last "wcs cols" parameter should rarely be needed. If supplied,
+ this string contains the names of the 2 columns (space or comma
+ separated) which have the associated WCS keywords. If not supplied,
+ the filter will scan the X and Y expressions for column names.
+ If only one is found in each expression, those columns will be
+ used, otherwise an error will be returned.
+
+ These region shapes are supported (names are case insensitive):
+
+\begin{verbatim}
+ Point ( X1, Y1 ) <- One pixel square region
+ Line ( X1, Y1, X2, Y2 ) <- One pixel wide region
+ Polygon ( X1, Y1, X2, Y2, ... ) <- Rest are interiors with
+ Rectangle ( X1, Y1, X2, Y2, A ) | boundaries considered
+ Box ( Xc, Yc, Wdth, Hght, A ) V within the region
+ Diamond ( Xc, Yc, Wdth, Hght, A )
+ Circle ( Xc, Yc, R )
+ Annulus ( Xc, Yc, Rin, Rout )
+ Ellipse ( Xc, Yc, Rx, Ry, A )
+ Elliptannulus ( Xc, Yc, Rinx, Riny, Routx, Routy, Ain, Aout )
+ Sector ( Xc, Yc, Amin, Amax )
+\end{verbatim}
+ where (Xc,Yc) is the coordinate of the shape's center; (X\#,Y\#) are
+ the coordinates of the shape's edges; Rxxx are the shapes' various
+ Radii or semimajor/minor axes; and Axxx are the angles of rotation
+ (or bounding angles for Sector) in degrees. For rotated shapes, the
+ rotation angle can be left off, indicating no rotation. Common
+ alternate names for the regions can also be used: rotbox = box;
+ rotrectangle = rectangle; (rot)rhombus = (rot)diamond; and pie
+ = sector. When a shape's name is preceded by a minus sign, '-',
+ the defined region is instead the area *outside* its boundary (ie,
+ the region is inverted). All the shapes within a single region
+ file are OR'd together to create the region, and the order is
+ significant. The overall way of looking at region files is that if
+ the first region is an excluded region then a dummy included region
+ of the whole detector is inserted in the front. Then each region
+ specification as it is processed overrides any selections inside of
+ that region specified by previous regions. Another way of thinking
+ about this is that if a previous excluded region is completely
+ inside of a subsequent included region the excluded region is
+ ignored.
+
+ The positional coordinates may be given either in pixel units,
+ decimal degrees or hh:mm:ss.s, dd:mm:ss.s units. The shape sizes
+ may be given in pixels, degrees, arcminutes, or arcseconds. Look
+ at examples of region file produced by fv/POW or ds9 for further
+ details of the region file format.
+
+ There are three functions that are primarily for use with SAO region
+ files and the FSAOI task, but they can be used directly. They
+ return a boolean true or false depending on whether a two
+ dimensional point is in the region or not:
+
+\begin{verbatim}
+ "point in a circular region"
+ circle(xcntr,ycntr,radius,Xcolumn,Ycolumn)
+
+ "point in an elliptical region"
+ ellipse(xcntr,ycntr,xhlf_wdth,yhlf_wdth,rotation,Xcolumn,Ycolumn)
+
+ "point in a rectangular region"
+ box(xcntr,ycntr,xfll_wdth,yfll_wdth,rotation,Xcolumn,Ycolumn)
+
+ where
+ (xcntr,ycntr) are the (x,y) position of the center of the region
+ (xhlf_wdth,yhlf_wdth) are the (x,y) half widths of the region
+ (xfll_wdth,yfll_wdth) are the (x,y) full widths of the region
+ (radius) is half the diameter of the circle
+ (rotation) is the angle(degrees) that the region is rotated with
+ respect to (xcntr,ycntr)
+ (Xcoord,Ycoord) are the (x,y) coordinates to test, usually column
+ names
+ NOTE: each parameter can itself be an expression, not merely a
+ column name or constant.
+\end{verbatim}
+
+
+\subsection{Example Row Filters}
+
+\begin{verbatim}
+ [ binary && mag <= 5.0] - Extract all binary stars brighter
+ than fifth magnitude (note that
+ the initial space is necessary to
+ prevent it from being treated as a
+ binning specification)
+
+ [#row >= 125 && #row <= 175] - Extract row numbers 125 through 175
+
+ [IMAGE[4,5] .gt. 100] - Extract all rows that have the
+ (4,5) component of the IMAGE column
+ greater than 100
+
+ [abs(sin(theta * #deg)) < 0.5] - Extract all rows having the
+ absolute value of the sine of theta
+ less than a half where the angles
+ are tabulated in degrees
+
+ [SUM( SPEC > 3*BACKGRND )>=1] - Extract all rows containing a
+ spectrum, held in vector column
+ SPEC, with at least one value 3
+ times greater than the background
+ level held in a keyword, BACKGRND
+
+ [VCOL=={1,4,2}] - Extract all rows whose vector column
+ VCOL contains the 3-elements 1, 4, and
+ 2.
+
+ [@rowFilter.txt] - Extract rows using the expression
+ contained within the text file
+ rowFilter.txt
+
+ [gtifilter()] - Search the current file for a GTI
+ extension, filter the TIME
+ column in the current table, using
+ START/STOP times taken from
+ columns in the GTI extension
+
+ [regfilter("pow.reg")] - Extract rows which have a coordinate
+ (as given in the X and Y columns)
+ within the spatial region specified
+ in the pow.reg region file.
+
+ [regfilter("pow.reg", Xs, Ys)] - Same as above, except that the
+ Xs and Ys columns will be used to
+ determine the coordinate of each
+ row in the table.
+\end{verbatim}
+
+
+\section{ Binning or Histogramming Specification}
+
+The optional binning specifier is enclosed in square brackets and can
+be distinguished from a general row filter specification by the fact
+that it begins with the keyword 'bin' not immediately followed by an
+equals sign. When binning is specified, a temporary N-dimensional FITS
+primary array is created by computing the histogram of the values in
+the specified columns of a FITS table extension. After the histogram
+is computed the input FITS file containing the table is then closed and
+the temporary FITS primary array is opened and passed to the
+application program. Thus, the application program never sees the
+original FITS table and only sees the image in the new temporary file
+(which has no additional extensions). Obviously, the application
+program must be expecting to open a FITS image and not a FITS table in
+this case.
+
+The data type of the FITS histogram image may be specified by appending
+'b' (for 8-bit byte), 'i' (for 16-bit integers), 'j' (for 32-bit
+integer), 'r' (for 32-bit floating points), or 'd' (for 64-bit double
+precision floating point) to the 'bin' keyword (e.g. '[binr X]'
+creates a real floating point image). If the data type is not
+explicitly specified then a 32-bit integer image will be created by
+default, unless the weighting option is also specified in which case
+the image will have a 32-bit floating point data type by default.
+
+The histogram image may have from 1 to 4 dimensions (axes), depending
+on the number of columns that are specified. The general form of the
+binning specification is:
+
+\begin{verbatim}
+ [bin{bijrd} Xcol=min:max:binsize, Ycol= ..., Zcol=..., Tcol=...; weight]
+\end{verbatim}
+in which up to 4 columns, each corresponding to an axis of the image,
+are listed. The column names are case insensitive, and the column
+number may be given instead of the name, preceded by a pound sign
+(e.g., [bin \#4=1:512]). If the column name is not specified, then
+CFITSIO will first try to use the 'preferred column' as specified by
+the CPREF keyword if it exists (e.g., 'CPREF = 'DETX,DETY'), otherwise
+column names 'X', 'Y', 'Z', and 'T' will be assumed for each of the 4
+axes, respectively. In cases where the column name could be confused
+with an arithmetic expression, enclose the column name in parentheses to
+force the name to be interpreted literally.
+
+Each column name may be followed by an equals sign and then the lower
+and upper range of the histogram, and the size of the histogram bins,
+separated by colons. Spaces are allowed before and after the equals
+sign but not within the 'min:max:binsize' string. The min, max and
+binsize values may be integer or floating point numbers, or they may be
+the names of keywords in the header of the table. If the latter, then
+the value of that keyword is substituted into the expression.
+
+Default values for the min, max and binsize quantities will be
+used if not explicitly given in the binning expression as shown
+in these examples:
+
+\begin{verbatim}
+ [bin x = :512:2] - use default minimum value
+ [bin x = 1::2] - use default maximum value
+ [bin x = 1:512] - use default bin size
+ [bin x = 1:] - use default maximum value and bin size
+ [bin x = :512] - use default minimum value and bin size
+ [bin x = 2] - use default minimum and maximum values
+ [bin x] - use default minimum, maximum and bin size
+ [bin 4] - default 2-D image, bin size = 4 in both axes
+ [bin] - default 2-D image
+\end{verbatim}
+CFITSIO will use the value of the TLMINn, TLMAXn, and TDBINn keywords,
+if they exist, for the default min, max, and binsize, respectively. If
+they do not exist then CFITSIO will use the actual minimum and maximum
+values in the column for the histogram min and max values. The default
+binsize will be set to 1, or (max - min) / 10., whichever is smaller,
+so that the histogram will have at least 10 bins along each axis.
+
+A shortcut notation is allowed if all the columns/axes have the same
+binning specification. In this case all the column names may be listed
+within parentheses, followed by the (single) binning specification, as
+in:
+
+\begin{verbatim}
+ [bin (X,Y)=1:512:2]
+ [bin (X,Y) = 5]
+\end{verbatim}
+
+The optional weighting factor is the last item in the binning specifier
+and, if present, is separated from the list of columns by a
+semi-colon. As the histogram is accumulated, this weight is used to
+incremented the value of the appropriated bin in the histogram. If the
+weighting factor is not specified, then the default weight = 1 is
+assumed. The weighting factor may be a constant integer or floating
+point number, or the name of a keyword containing the weighting value.
+Or the weighting factor may be the name of a table column in which case
+the value in that column, on a row by row basis, will be used.
+
+In some cases, the column or keyword may give the reciprocal of the
+actual weight value that is needed. In this case, precede the weight
+keyword or column name by a slash '/' to tell CFITSIO to use the
+reciprocal of the value when constructing the histogram.
+
+For complex or commonly used histograms, one can also place its
+description into a text file and import it into the binning
+specification using the syntax [bin @filename.txt]. The file's
+contents can extend over multiple lines, although it must still
+conform to the no-spaces rule for the min:max:binsize syntax and each
+axis specification must still be comma-separated. Any lines in the
+external text file that begin with 2 slash characters ('//') will be
+ignored and may be used to add comments into the file.
+
+ Examples:
+
+
+\begin{verbatim}
+ [bini detx, dety] - 2-D, 16-bit integer histogram
+ of DETX and DETY columns, using
+ default values for the histogram
+ range and binsize
+
+ [bin (detx, dety)=16; /exposure] - 2-D, 32-bit real histogram of DETX
+ and DETY columns with a bin size = 16
+ in both axes. The histogram values
+ are divided by the EXPOSURE keyword
+ value.
+
+ [bin time=TSTART:TSTOP:0.1] - 1-D lightcurve, range determined by
+ the TSTART and TSTOP keywords,
+ with 0.1 unit size bins.
+
+ [bin pha, time=8000.:8100.:0.1] - 2-D image using default binning
+ of the PHA column for the X axis,
+ and 1000 bins in the range
+ 8000. to 8100. for the Y axis.
+
+ [bin @binFilter.txt] - Use the contents of the text file
+ binFilter.txt for the binning
+ specifications.
+
+\end{verbatim}
+\chapter{Template Files }
+
+When a new FITS file is created with a call to fits\_create\_file, the
+name of a template file may be supplied in parentheses immediately
+following the name of the new file to be created. This template is
+used to define the structure of one or more HDUs in the new file. The
+template file may be another FITS file, in which case the newly created
+file will have exactly the same keywords in each HDU as in the template
+FITS file, but all the data units will be filled with zeros. The
+template file may also be an ASCII text file, where each line (in
+general) describes one FITS keyword record. The format of the ASCII
+template file is described in the following sections.
+
+
+\section{Detailed Template Line Format}
+
+The format of each ASCII template line closely follows the format of a
+FITS keyword record:
+
+\begin{verbatim}
+ KEYWORD = KEYVALUE / COMMENT
+\end{verbatim}
+except that free format may be used (e.g., the equals sign may appear
+at any position in the line) and TAB characters are allowed and are
+treated the same as space characters. The KEYVALUE and COMMENT fields
+are optional. The equals sign character is also optional, but it is
+recommended that it be included for clarity. Any template line that
+begins with the pound '\#' character is ignored by the template parser
+and may be use to insert comments into the template file itself.
+
+The KEYWORD name field is limited to 8 characters in length and only
+the letters A-Z, digits 0-9, and the hyphen and underscore characters
+may be used, without any embedded spaces. Lowercase letters in the
+template keyword name will be converted to uppercase. Leading spaces
+in the template line preceding the keyword name are generally ignored,
+except if the first 8 characters of a template line are all blank, then
+the entire line is treated as a FITS comment keyword (with a blank
+keyword name) and is copied verbatim into the FITS header.
+
+The KEYVALUE field may have any allowed FITS data type: character
+string, logical, integer, real, complex integer, or complex real. The
+character string values need not be enclosed in single quote characters
+unless they are necessary to distinguish the string from a different
+data type (e.g. 2.0 is a real but '2.0' is a string). The keyword has
+an undefined (null) value if the template record only contains blanks
+following the "=" or between the "=" and the "/" comment field
+delimiter.
+
+String keyword values longer than 68 characters (the maximum length
+that will fit in a single FITS keyword record) are permitted using the
+CFITSIO long string convention. They can either be specified as a
+single long line in the template, or by using multiple lines where the
+continuing lines contain the 'CONTINUE' keyword, as in this example:
+
+\begin{verbatim}
+ LONGKEY = 'This is a long string value that is contin&'
+ CONTINUE 'ued over 2 records' / comment field goes here
+\end{verbatim}
+The format of template lines with CONTINUE keyword is very strict: 3
+spaces must follow CONTINUE and the rest of the line is copied verbatim
+to the FITS file.
+
+The start of the optional COMMENT field must be preceded by "/", which
+is used to separate it from the keyword value field. Exceptions are if
+the KEYWORD name field contains COMMENT, HISTORY, CONTINUE, or if the
+first 8 characters of the template line are blanks.
+
+More than one Header-Data Unit (HDU) may be defined in the template
+file. The start of an HDU definition is denoted with a SIMPLE or
+XTENSION template line:
+
+1) SIMPLE begins a Primary HDU definition. SIMPLE may only appear as
+the first keyword in the template file. If the template file begins
+with XTENSION instead of SIMPLE, then a default empty Primary HDU is
+created, and the template is then assumed to define the keywords
+starting with the first extension following the Primary HDU.
+
+2) XTENSION marks the beginning of a new extension HDU definition. The
+previous HDU will be closed at this point and processing of the next
+extension begins.
+
+
+\section{Auto-indexing of Keywords}
+
+If a template keyword name ends with a "\#" character, it is said to be
+'auto-indexed'. Each "\#" character will be replaced by the current
+integer index value, which gets reset = 1 at the start of each new HDU
+in the file (or 7 in the special case of a GROUP definition). The
+FIRST indexed keyword in each template HDU definition is used as the
+'incrementor'; each subsequent occurrence of this SAME keyword will
+cause the index value to be incremented. This behavior can be rather
+subtle, as illustrated in the following examples in which the TTYPE
+keyword is the incrementor in both cases:
+
+\begin{verbatim}
+ TTYPE# = TIME
+ TFORM# = 1D
+ TTYPE# = RATE
+ TFORM# = 1E
+\end{verbatim}
+will create TTYPE1, TFORM1, TTYPE2, and TFORM2 keywords. But if the
+template looks like,
+
+\begin{verbatim}
+ TTYPE# = TIME
+ TTYPE# = RATE
+ TFORM# = 1D
+ TFORM# = 1E
+\end{verbatim}
+this results in a FITS files with TTYPE1, TTYPE2, TFORM2, and TFORM2,
+which is probably not what was intended!
+
+
+\section{Template Parser Directives}
+
+In addition to the template lines which define individual keywords, the
+template parser recognizes 3 special directives which are each preceded
+by the backslash character: \verb+ \include, \group+, and \verb+ \end+.
+
+The 'include' directive must be followed by a filename. It forces the
+parser to temporarily stop reading the current template file and begin
+reading the include file. Once the parser reaches the end of the
+include file it continues parsing the current template file. Include
+files can be nested, and HDU definitions can span multiple template
+files.
+
+The start of a GROUP definition is denoted with the 'group' directive,
+and the end of a GROUP definition is denoted with the 'end' directive.
+Each GROUP contains 0 or more member blocks (HDUs or GROUPs). Member
+blocks of type GROUP can contain their own member blocks. The GROUP
+definition itself occupies one FITS file HDU of special type (GROUP
+HDU), so if a template specifies 1 group with 1 member HDU like:
+
+\begin{verbatim}
+\group
+grpdescr = 'demo'
+xtension bintable
+# this bintable has 0 cols, 0 rows
+\end
+\end{verbatim}
+then the parser creates a FITS file with 3 HDUs :
+
+\begin{verbatim}
+1) dummy PHDU
+2) GROUP HDU (has 1 member, which is bintable in HDU number 3)
+3) bintable (member of GROUP in HDU number 2)
+\end{verbatim}
+Technically speaking, the GROUP HDU is a BINTABLE with 6 columns. Applications
+can define additional columns in a GROUP HDU using TFORMn and TTYPEn
+(where n is 7, 8, ....) keywords or their auto-indexing equivalents.
+
+For a more complicated example of a template file using the group directives,
+look at the sample.tpl file that is included in the CFITSIO distribution.
+
+
+\section{Formal Template Syntax}
+
+The template syntax can formally be defined as follows:
+
+\begin{verbatim}
+ TEMPLATE = BLOCK [ BLOCK ... ]
+
+ BLOCK = { HDU | GROUP }
+
+ GROUP = \GROUP [ BLOCK ... ] \END
+
+ HDU = XTENSION [ LINE ... ] { XTENSION | \GROUP | \END | EOF }
+
+ LINE = [ KEYWORD [ = ] ] [ VALUE ] [ / COMMENT ]
+
+ X ... - X can be present 1 or more times
+ { X | Y } - X or Y
+ [ X ] - X is optional
+\end{verbatim}
+
+At the topmost level, the template defines 1 or more template blocks. Blocks
+can be either HDU (Header Data Unit) or a GROUP. For each block the parser
+creates 1 (or more for GROUPs) FITS file HDUs.
+
+
+
+\section{Errors}
+
+In general the fits\_execute\_template() function tries to be as atomic
+as possible, so either everything is done or nothing is done. If an
+error occurs during parsing of the template, fits\_execute\_template()
+will (try to) delete the top level BLOCK (with all its children if any)
+in which the error occurred, then it will stop reading the template file
+and it will return with an error.
+
+
+\section{Examples}
+
+1. This template file will create a 200 x 300 pixel image, with 4-byte
+integer pixel values, in the primary HDU:
+
+\begin{verbatim}
+ SIMPLE = T
+ BITPIX = 32
+ NAXIS = 2 / number of dimensions
+ NAXIS1 = 100 / length of first axis
+ NAXIS2 = 200 / length of second axis
+ OBJECT = NGC 253 / name of observed object
+\end{verbatim}
+The allowed values of BITPIX are 8, 16, 32, -32, or -64,
+representing, respectively, 8-bit integer, 16-bit integer, 32-bit
+integer, 32-bit floating point, or 64 bit floating point pixels.
+
+2. To create a FITS table, the template first needs to include
+XTENSION = TABLE or BINTABLE to define whether it is an ASCII or binary
+table, and NAXIS2 to define the number of rows in the table. Two
+template lines are then needed to define the name (TTYPEn) and FITS data
+format (TFORMn) of the columns, as in this example:
+
+\begin{verbatim}
+ xtension = bintable
+ naxis2 = 40
+ ttype# = Name
+ tform# = 10a
+ ttype# = Npoints
+ tform# = j
+ ttype# = Rate
+ tunit# = counts/s
+ tform# = e
+\end{verbatim}
+The above example defines a null primary array followed by a 40-row
+binary table extension with 3 columns called 'Name', 'Npoints', and
+'Rate', with data formats of '10A' (ASCII character string), '1J'
+(integer) and '1E' (floating point), respectively. Note that the other
+required FITS keywords (BITPIX, NAXIS, NAXIS1, PCOUNT, GCOUNT, TFIELDS,
+and END) do not need to be explicitly defined in the template because
+their values can be inferred from the other keywords in the template.
+This example also illustrates that the templates are generally
+case-insensitive (the keyword names and TFORMn values are converted to
+upper-case in the FITS file) and that string keyword values generally
+do not need to be enclosed in quotes.
+
+\chapter{ Local FITS Conventions }
+
+CFITSIO supports several local FITS conventions which are not
+defined in the official NOST FITS standard and which are not
+necessarily recognized or supported by other FITS software packages.
+Programmers should be cautious about using these features, especially
+if the FITS files that are produced are expected to be processed by
+other software systems which do not use the CFITSIO interface.
+
+
+\section{64-Bit Long Integers}
+
+CFITSIO can read and write FITS images or table columns containing
+64-bit integer data values. This data type is not recognized in the
+official FITS Standard definition document, but it is likely that FITS
+will eventually support this data type, especially as computers that
+run 64-bit operating systems become more common. Support for reading
+and writing 64-bit integers in CFITSIO can be controlled with the
+\#define statement at the beginning of the fitsio2.h file by setting
+SUPPORT\_64BIT\_INTEGERS to 1 (enable) or 0 (disable).
+
+Under the convention used by CFITSIO, FITS 64-bit images have BITPIX =
+64, and the 64-bit binary table columns have TFORMn = 'K'. The use of
+these data types on platforms where the size of a 'long' (or 'longlong')
+integer = 8 bytes is rather intuitive. CFITSIO will write 64-bit
+'long' variable values to the FITS file and read them back into 'long'
+variables just as one would expect. CFITSIO also supports implicit
+data type conversion between 64-bit integer images and columns and any
+other supported data type, although some loss of numerical precision or
+numerical overflow is likely in this case.
+
+The situation is more difficult on 32-bit computing platforms that do
+not support an intrinsic 64-bit integer data type. In this case it is
+not possible to return the full 64 precision of the FITS data values when
+reading the values into a program variable. CFITSIO will still
+convert the 64-bit integer values into any other supported data type;
+the 64-bit double data type is probably the most useful in this case.
+It only provides about 52-bits of precision in the mantissa, however,
+so some lose of precision is possible.
+
+
+\section{Long String Keyword Values.}
+
+The length of a standard FITS string keyword is limited to 68
+characters because it must fit entirely within a single FITS header
+keyword record. In some instances it is necessary to encode strings
+longer than this limit, so CFITSIO supports a local convention in which
+the string value is continued over multiple keywords. This
+continuation convention uses an ampersand character at the end of each
+substring to indicate that it is continued on the next keyword, and the
+continuation keywords all have the name CONTINUE without an equal sign
+in column 9. The string value may be continued in this way over as many
+additional CONTINUE keywords as is required. The following lines
+illustrate this continuation convention which is used in the value of
+the STRKEY keyword:
+
+\begin{verbatim}
+LONGSTRN= 'OGIP 1.0' / The OGIP Long String Convention may be used.
+STRKEY = 'This is a very long string keyword&' / Optional Comment
+CONTINUE ' value that is continued over 3 keywords in the & '
+CONTINUE 'FITS header.' / This is another optional comment.
+\end{verbatim}
+It is recommended that the LONGSTRN keyword, as shown here, always be
+included in any HDU that uses this longstring convention as a warning
+to any software that must read the keywords. A routine called fits\_write\_key\_longwarn
+has been provided in CFITSIO to write this keyword if it does not
+already exist.
+
+This long string convention is supported by the following CFITSIO
+routines:
+
+\begin{verbatim}
+ fits_write_key_longstr - write a long string keyword value
+ fits_insert_key_longstr - insert a long string keyword value
+ fits_modify_key_longstr - modify a long string keyword value
+ fits_update_key_longstr - modify a long string keyword value
+ fits_read_key_longstr - read a long string keyword value
+ fits_delete_key - delete a keyword
+\end{verbatim}
+The fits\_read\_key\_longstr routine is unique among all the CFITSIO
+routines in that it internally allocates memory for the long string
+value; all the other CFITSIO routines that deal with arrays require
+that the calling program pre-allocate adequate space to hold the array
+of data. Consequently, programs which use the fits\_read\_key\_longstr
+routine must be careful to free the allocated memory for the string
+when it is no longer needed.
+
+The following 2 routines also have limited support for this long string
+convention,
+
+\begin{verbatim}
+ fits_modify_key_str - modify an existing string keyword value
+ fits_update_key_str - update a string keyword value
+\end{verbatim}
+in that they will correctly overwrite an existing long string value,
+but the new string value is limited to a maximum of 68 characters in
+length.
+
+The more commonly used CFITSIO routines to write string valued keywords
+(fits\_update\_key and fits\_write\_key) do not support this long
+string convention and only support strings up to 68 characters in
+length. This has been done deliberately to prevent programs from
+inadvertently writing keywords using this non-standard convention
+without the explicit intent of the programmer or user. The
+fits\_write\_key\_longstr routine must be called instead to write long
+strings. This routine can also be used to write ordinary string values
+less than 68 characters in length.
+
+
+\section{Arrays of Fixed-Length Strings in Binary Tables}
+
+The definition of the FITS binary table extension format does not
+provide a simple way to specify that a character column contains an
+array of fixed-length strings. To support this feature, CFITSIO uses a
+local convention for the format of the TFORMn keyword value of the form
+'rAw' where 'r' is an integer specifying the total width in characters
+of the column, and 'w' is an integer specifying the (fixed) length of
+an individual unit string within the vector. For example, TFORM1 =
+'120A10' would indicate that the binary table column is 120 characters
+wide and consists of 12 10-character length strings. This convention
+is recognized by the CFITSIO routines that read or write strings in
+binary tables. The Binary Table definition document specifies that
+other optional characters may follow the data type code in the TFORM
+keyword, so this local convention is in compliance with the
+FITS standard although other FITS readers may not
+recognize this convention.
+
+The Binary Table definition document that was approved by the IAU in
+1994 contains an appendix describing an alternate convention for
+specifying arrays of fixed or variable length strings in a binary table
+character column (with the form 'rA:SSTRw/nnn)'. This appendix was not
+officially voted on by the IAU and hence is still provisional. CFITSIO
+does not currently support this proposal.
+
+
+\section{Keyword Units Strings}
+
+One limitation of the current FITS Standard is that it does not define
+a specific convention for recording the physical units of a keyword
+value. The TUNITn keyword can be used to specify the physical units of
+the values in a table column, but there is no analogous convention for
+keyword values. The comment field of the keyword is often used for
+this purpose, but the units are usually not specified in a well defined
+format that FITS readers can easily recognize and extract.
+
+To solve this problem, CFITSIO uses a local convention in which the
+keyword units are enclosed in square brackets as the first token in the
+keyword comment field; more specifically, the opening square bracket
+immediately follows the slash '/' comment field delimiter and a single
+space character. The following examples illustrate keywords that use
+this convention:
+
+
+\begin{verbatim}
+EXPOSURE= 1800.0 / [s] elapsed exposure time
+V_HELIO = 16.23 / [km s**(-1)] heliocentric velocity
+LAMBDA = 5400. / [angstrom] central wavelength
+FLUX = 4.9033487787637465E-30 / [J/cm**2/s] average flux
+\end{verbatim}
+
+In general, the units named in the IAU(1988) Style Guide are
+recommended, with the main exception that the preferred unit for angle
+is 'deg' for degrees.
+
+The fits\_read\_key\_unit and fits\_write\_key\_unit routines in
+CFITSIO read and write, respectively, the keyword unit strings in an
+existing keyword.
+
+
+\section{HIERARCH Convention for Extended Keyword Names}
+
+CFITSIO supports the HIERARCH keyword convention which allows keyword
+names that are longer then 8 characters and may contain the full range
+of printable ASCII text characters. This convention
+was developed at the European Southern Observatory (ESO) to support
+hierarchical FITS keyword such as:
+
+\begin{verbatim}
+HIERARCH ESO INS FOCU POS = -0.00002500 / Focus position
+\end{verbatim}
+Basically, this convention uses the FITS keyword 'HIERARCH' to indicate
+that this convention is being used, then the actual keyword name
+({\tt'ESO INS FOCU POS'} in this example) begins in column 10 and can
+contain any printable ASCII text characters, including spaces. The
+equals sign marks the end of the keyword name and is followed by the
+usual value and comment fields just as in standard FITS keywords.
+Further details of this convention are described at
+http://arcdev.hq.eso.org/dicb/dicd/dic-1-1.4.html (search for
+HIERARCH).
+
+This convention allows a much broader range of keyword names
+than is allowed by the FITS Standard. Here are more examples
+of such keywords:
+
+\begin{verbatim}
+HIERARCH LongKeyword = 47.5 / Keyword has > 8 characters, and mixed case
+HIERARCH XTE$TEMP = 98.6 / Keyword contains the '$' character
+HIERARCH Earth is a star = F / Keyword contains embedded spaces
+\end{verbatim}
+CFITSIO will transparently read and write these keywords, so application
+programs do not in general need to know anything about the specific
+implementation details of the HIERARCH convention. In particular,
+application programs do not need to specify the `HIERARCH' part of the
+keyword name when reading or writing keywords (although it
+may be included if desired). When writing a keyword, CFITSIO first
+checks to see if the keyword name is legal as a standard FITS keyword
+(no more than 8 characters long and containing only letters, digits, or
+a minus sign or underscore). If so it writes it as a standard FITS
+keyword, otherwise it uses the hierarch convention to write the
+keyword. The maximum keyword name length is 67 characters, which
+leaves only 1 space for the value field. A more practical limit is
+about 40 characters, which leaves enough room for most keyword values.
+CFITSIO returns an error if there is not enough room for both the
+keyword name and the keyword value on the 80-character card, except for
+string-valued keywords which are simply truncated so that the closing
+quote character falls in column 80. In the current implementation,
+CFITSIO preserves the case of the letters when writing the keyword
+name, but it is case-insensitive when reading or searching for a
+keyword. The current implementation allows any ASCII text character
+(ASCII 32 to ASCII 126) in the keyword name except for the '='
+character. A space is also required on either side of the equal sign.
+
+
+\section{Tile-Compressed Image Format}
+
+CFITSIO supports a convention for compressing n-dimensional images and
+storing the resulting byte stream in a variable-length column in a FITS
+binary table. The general principle used in this convention is to
+first divide the n-dimensional image into a rectangular grid of
+subimages or `tiles'. Each tile is then compressed as a continuous
+block of data, and the resulting compressed byte stream is stored in a
+row of a variable length column in a FITS binary table. By dividing the
+image into tiles it is generally possible to extract and uncompress
+subsections of the image without having to uncompress the whole image.
+The default tiling pattern treats each row of a 2-dimensional image (or
+higher dimensional cube) as a tile, such that each tile contains NAXIS1
+pixels. Any other rectangular tiling pattern may also be defined. In
+the case of relatively small images it may be sufficient to compress
+the entire image as a single tile, resulting in an output binary table
+with 1 row. In the case of 3-dimensional data cubes, it may be
+advantageous to treat each plane of the cube as a separate tile if
+application software typically needs to access the cube on a plane by
+plane basis.
+
+See section 5.6 ``Image Compression''
+for more information on using this tile-compressed image format.
+
+\chapter{ Optimizing Programs }
+
+CFITSIO has been carefully designed to obtain the highest possible
+speed when reading and writing FITS files. In order to achieve the
+best performance, however, application programmers must be careful to
+call the CFITSIO routines appropriately and in an efficient sequence;
+inappropriate usage of CFITSIO routines can greatly slow down the
+execution speed of a program.
+
+The maximum possible I/O speed of CFITSIO depends of course on the type
+of computer system that it is running on. As a rough guide, the
+current generation of workstations can achieve speeds of 2 -- 10 MB/s
+when reading or writing FITS images and similar, or slightly slower
+speeds with FITS binary tables. Reading of FITS files can occur at
+even higher rates (30MB/s or more) if the FITS file is still cached in
+system memory following a previous read or write operation on the same
+file. To more accurately predict the best performance that is possible
+on any particular system, a diagnostic program called ``speed.c'' is
+included with the CFITSIO distribution which can be run to
+approximately measure the maximum possible speed of writing and reading
+a test FITS file.
+
+The following 2 sections provide some background on how CFITSIO
+internally manages the data I/O and describes some strategies that may
+be used to optimize the processing speed of software that uses
+CFITSIO.
+
+
+\section{How CFITSIO Manages Data I/O}
+
+Many CFITSIO operations involve transferring only a small number of
+bytes to or from the FITS file (e.g, reading a keyword, or writing a
+row in a table); it would be very inefficient to physically read or
+write such small blocks of data directly in the FITS file on disk,
+therefore CFITSIO maintains a set of internal Input--Output (IO)
+buffers in RAM memory that each contain one FITS block (2880 bytes) of
+data. Whenever CFITSIO needs to access data in the FITS file, it first
+transfers the FITS block containing those bytes into one of the IO
+buffers in memory. The next time CFITSIO needs to access bytes in the
+same block it can then go to the fast IO buffer rather than using a
+much slower system disk access routine. The number of available IO
+buffers is determined by the NIOBUF parameter (in fitsio2.h) and is
+currently set to 40 by default.
+
+Whenever CFITSIO reads or writes data it first checks to see if that
+block of the FITS file is already loaded into one of the IO buffers.
+If not, and if there is an empty IO buffer available, then it will load
+that block into the IO buffer (when reading a FITS file) or will
+initialize a new block (when writing to a FITS file). If all the IO
+buffers are already full, it must decide which one to reuse (generally
+the one that has been accessed least recently), and flush the contents
+back to disk if it has been modified before loading the new block.
+
+The one major exception to the above process occurs whenever a large
+contiguous set of bytes are accessed, as might occur when reading or
+writing a FITS image. In this case CFITSIO bypasses the internal IO
+buffers and simply reads or writes the desired bytes directly in the
+disk file with a single call to a low-level file read or write
+routine. The minimum threshold for the number of bytes to read or
+write this way is set by the MINDIRECT parameter and is currently set
+to 3 FITS blocks = 8640 bytes. This is the most efficient way to read
+or write large chunks of data and can achieve IO transfer rates of
+5 -- 10MB/s or greater. Note that this fast direct IO process is not
+applicable when accessing columns of data in a FITS table because the
+bytes are generally not contiguous since they are interleaved by the
+other columns of data in the table. This explains why the speed for
+accessing FITS tables is generally slower than accessing
+FITS images.
+
+Given this background information, the general strategy for efficiently
+accessing FITS files should be apparent: when dealing with FITS
+images, read or write large chunks of data at a time so that the direct
+IO mechanism will be invoked; when accessing FITS headers or FITS
+tables, on the other hand, once a particular FITS block has been
+loading into one of the IO buffers, try to access all the needed
+information in that block before it gets flushed out of the IO buffer.
+It is important to avoid the situation where the same FITS block is
+being read then flushed from a IO buffer multiple times.
+
+The following section gives more specific suggestions for optimizing
+the use of CFITSIO.
+
+
+\section{Optimization Strategies}
+
+1. When dealing with a FITS primary array or IMAGE extension, it is
+more efficient to read or write large chunks of the image at a time
+(at least 3 FITS blocks = 8640 bytes) so that the direct IO mechanism
+will be used as described in the previous section. Smaller chunks of
+data are read or written via the IO buffers, which is somewhat less
+efficient because of the extra copy operation and additional
+bookkeeping steps that are required. In principle it is more efficient
+to read or write as big an array of image pixels at one time as
+possible, however, if the array becomes so large that the operating
+system cannot store it all in RAM, then the performance may be degraded
+because of the increased swapping of virtual memory to disk.
+
+2. When dealing with FITS tables, the most important efficiency factor
+in the software design is to read or write the data in the FITS file in
+a single pass through the file. An example of poor program design
+would be to read a large, 3-column table by sequentially reading the
+entire first column, then going back to read the 2nd column, and
+finally the 3rd column; this obviously requires 3 passes through the
+file which could triple the execution time of an IO limited program.
+For small tables this is not important, but when reading multi-megabyte
+sized tables these inefficiencies can become significant. The more
+efficient procedure in this case is to read or write only as many rows
+of the table as will fit into the available internal IO buffers, then
+access all the necessary columns of data within that range of rows.
+Then after the program is completely finished with the data in those
+rows it can move on to the next range of rows that will fit in the
+buffers, continuing in this way until the entire file has been
+processed. By using this procedure of accessing all the columns of a
+table in parallel rather than sequentially, each block of the FITS file
+will only be read or written once.
+
+The optimal number of rows to read or write at one time in a given
+table depends on the width of the table row, on the number of IO
+buffers that have been allocated in CFITSIO, and also on the number of
+other FITS files that are open at the same time (since one IO buffer is
+always reserved for each open FITS file). The CFITSIO Iterator routine
+will automatically use the optimal-sized buffer, but there is also a
+CFITSIO routine that will return the optimal number of rows for a given
+table: fits\_get\_rowsize. It is not critical to use exactly the
+value of nrows returned by this routine, as long as one does not exceed
+it. Using a very small value however can also lead to poor performance
+because of the overhead from the larger number of subroutine calls.
+
+The optimal number of rows returned by fits\_get\_rowsize is valid only
+as long as the application program is only reading or writing data in
+the specified table. Any other calls to access data in the table
+header or in any other FITS file would cause additional blocks of data
+to be loaded into the IO buffers displacing data from the original
+table, and should be avoided during the critical period while the table
+is being read or written.
+
+Occasionally it is necessary to simultaneously access more than one
+FITS table, for example when transferring values from an input table to
+an output table. In cases like this, one should call
+fits\_get\_rowsize to get the optimal number of rows for each table
+separately, than reduce the number of rows proportionally. For
+example, if the optimal number of rows in the input table is 3600 and
+is 1400 in the output table, then these values should be cut in half to
+1800 and 700, respectively, if both tables are going to be accessed at
+the same time.
+
+3. Use the CFITSIO Iterator routine. This routine provides a
+more `object oriented' way of reading and writing FITS files
+which automatically uses the most appropriate data buffer size
+to achieve the maximum I/O throughput.
+
+4. Use binary table extensions rather than ASCII table
+extensions for better efficiency when dealing with tabular data. The
+I/O to ASCII tables is slower because of the overhead in formatting or
+parsing the ASCII data fields and because ASCII tables are about twice
+as large as binary tables with the same information content.
+
+5. Design software so that it reads the FITS header keywords in the
+same order in which they occur in the file. When reading keywords,
+CFITSIO searches forward starting from the position of the last keyword
+that was read. If it reaches the end of the header without finding the
+keyword, it then goes back to the start of the header and continues the
+search down to the position where it started. In practice, as long as
+the entire FITS header can fit at one time in the available internal IO
+buffers, then the header keyword access will be very fast and it makes
+little difference which order they are accessed.
+
+6. Avoid the use of scaling (by using the BSCALE and BZERO or TSCAL and
+TZERO keywords) in FITS files since the scaling operations add to the
+processing time needed to read or write the data. In some cases it may
+be more efficient to temporarily turn off the scaling (using fits\_set\_bscale or
+fits\_set\_tscale) and then read or write the raw unscaled values in the FITS
+file.
+
+7. Avoid using the `implicit data type conversion' capability in
+CFITSIO. For instance, when reading a FITS image with BITPIX = -32
+(32-bit floating point pixels), read the data into a single precision
+floating point data array in the program. Forcing CFITSIO to convert
+the data to a different data type can slow the program.
+
+8. Where feasible, design FITS binary tables using vector column
+elements so that the data are written as a contiguous set of bytes,
+rather than as single elements in multiple rows. For example, it is
+faster to access the data in a table that contains a single row
+and 2 columns with TFORM keywords equal to '10000E' and '10000J', than
+it is to access the same amount of data in a table with 10000 rows
+which has columns with the TFORM keywords equal to '1E' and '1J'. In
+the former case the 10000 floating point values in the first column are
+all written in a contiguous block of the file which can be read or
+written quickly, whereas in the second case each floating point value
+in the first column is interleaved with the integer value in the second
+column of the same row so CFITSIO has to explicitly move to the
+position of each element to be read or written.
+
+9. Avoid the use of variable length vector columns in binary tables,
+since any reading or writing of these data requires that CFITSIO first
+look up or compute the starting address of each row of data in the
+heap.
+
+10. When copying data from one FITS table to another, it is faster to
+transfer the raw bytes instead of reading then writing each column of
+the table. The CFITSIO routines fits\_read\_tblbytes and
+fits\_write\_tblbytes will perform low-level reads or writes of any
+contiguous range of bytes in a table extension. These routines can be
+used to read or write a whole row (or multiple rows for even greater
+efficiency) of a table with a single function call. These routines
+are fast because they bypass all the usual data scaling, error checking
+and machine dependent data conversion that is normally done by CFITSIO,
+and they allow the program to write the data to the output file in
+exactly the same byte order. For these same reasons, these routines
+can corrupt the FITS data file if used incorrectly because no
+validation or machine dependent conversion is performed by these
+routines. These routines are only recommended for optimizing critical
+pieces of code and should only be used by programmers who thoroughly
+understand the internal format of the FITS tables they are reading or
+writing.
+
+11. Another strategy for improving the speed of writing a FITS table,
+similar to the previous one, is to directly construct the entire byte
+stream for a whole table row (or multiple rows) within the application
+program and then write it to the FITS file with
+fits\_write\_tblbytes. This avoids all the overhead normally present
+in the column-oriented CFITSIO write routines. This technique should
+only be used for critical applications because it makes the code more
+difficult to understand and maintain, and it makes the code more system
+dependent (e.g., do the bytes need to be swapped before writing to the
+FITS file?).
+
+12. Finally, external factors such as the type of magnetic disk
+controller (SCSI or IDE), the size of the disk cache, the average seek
+speed of the disk, the amount of disk fragmentation, and the amount of
+RAM available on the system can all have a significant impact on
+overall I/O efficiency. For critical applications, a system
+administrator should review the proposed system hardware to identify any
+potential I/O bottlenecks.
+
+
+\appendix
+\chapter{Index of Routines }
+\begin{tabular}{lr}
+fits\_add\_group\_member & \pageref{ffgtam} \\
+fits\_ascii\_tform & \pageref{ffasfm} \\
+fits\_binary\_tform & \pageref{ffbnfm} \\
+fits\_calculator & \pageref{ffcalc} \\
+fits\_calculator\_rng & \pageref{ffcalcrng} \\
+fits\_calc\_rows & \pageref{ffcrow} \\
+fits\_change\_group & \pageref{ffgtch} \\
+fits\_clear\_errmark & \pageref{ffpmrk} \\
+fits\_clear\_errmsg & \pageref{ffcmsg} \\
+fits\_close\_file & \pageref{ffclos} \\
+fits\_compact\_group & \pageref{ffgtcm} \\
+fits\_compare\_str & \pageref{ffcmps} \\
+fits\_compress\_heap & \pageref{ffcmph} \\
+fits\_copy\_col & \pageref{ffcpcl} \\
+fits\_copy\_data & \pageref{ffcpdt} \\
+fits\_copy\_file & \pageref{ffcpfl} \\
+fits\_copy\_group & \pageref{ffgtcp} \\
+fits\_copy\_hdu & \pageref{ffcopy} \\
+fits\_copy\_header & \pageref{ffcphd} \\
+fits\_copy\_key & \pageref{ffcpky} \\
+fits\_copy\_member & \pageref{ffgmcp} \\
+fits\_create\_diskfile & \pageref{ffinit} \\
+fits\_create\_file & \pageref{ffinit} \\
+fits\_create\_group & \pageref{ffgtcr} \\
+fits\_create\_hdu & \pageref{ffcrhd} \\
+fits\_create\_img & \pageref{ffcrim} \\
+fits\_create\_memfile & \pageref{ffimem} \\
+fits\_create\_tbl & \pageref{ffcrtb} \\
+fits\_create\_template & \pageref{fftplt} \\
+fits\_date2str & \pageref{ffdt2s} \\
+fits\_decode\_chksum & \pageref{ffdsum} \\
+fits\_decode\_tdim & \pageref{ffdtdm} \\
+
+\end{tabular}
+\begin{tabular}{lr}
+fits\_delete\_col & \pageref{ffdcol} \\
+fits\_delete\_file & \pageref{ffdelt} \\
+fits\_delete\_hdu & \pageref{ffdhdu} \\
+fits\_delete\_key & \pageref{ffdkey} \\
+fits\_delete\_record & \pageref{ffdrec} \\
+fits\_delete\_rowlist & \pageref{ffdrws} \\
+fits\_delete\_rowrange & \pageref{ffdrrg} \\
+fits\_delete\_rows & \pageref{ffdrow} \\
+fits\_encode\_chksum & \pageref{ffesum} \\
+fits\_file\_exists & \pageref{ffexist} \\
+fits\_file\_mode & \pageref{ffflmd} \\
+fits\_file\_name & \pageref{ffflnm} \\
+fits\_find\_first\_row & \pageref{ffffrw} \\
+fits\_find\_nextkey & \pageref{ffgnxk} \\
+fits\_find\_rows & \pageref{fffrow} \\
+fits\_flush\_buffer & \pageref{ffflus} \\
+fits\_flush\_file & \pageref{ffflus} \\
+fits\_get\_acolparms & \pageref{ffgacl} \\
+fits\_get\_bcolparms & \pageref{ffgbcl} \\
+fits\_get\_chksum & \pageref{ffgcks} \\
+fits\_get\_col\_display\_width & \pageref{ffgcdw} \\
+fits\_get\_colname & \pageref{ffgcnn} \\
+fits\_get\_colnum & \pageref{ffgcno} \\
+fits\_get\_coltype & \pageref{ffgtcl} \\
+fits\_get\_compression\_type & \pageref{ffgetcomp} \\
+fits\_get\_eqcoltype & \pageref{ffgtcl} \\
+fits\_get\_errstatus & \pageref{ffgerr} \\
+fits\_get\_hdrpos & \pageref{ffghps} \\
+fits\_get\_hdrspace & \pageref{ffghsp} \\
+fits\_get\_hdu\_num & \pageref{ffghdn} \\
+fits\_get\_hdu\_type & \pageref{ffghdt} \\
+fits\_get\_hduaddr & \pageref{ffghad} \\
+\end{tabular}
+\begin{tabular}{lr}
+fits\_get\_hduoff & \pageref{ffghad} \\
+fits\_get\_img\_dim & \pageref{ffgidm} \\
+fits\_get\_img\_equivtype & \pageref{ffgidt} \\
+fits\_get\_img\_param & \pageref{ffgipr} \\
+fits\_get\_img\_size & \pageref{ffgisz} \\
+fits\_get\_img\_type & \pageref{ffgidt} \\
+fits\_get\_keyclass & \pageref{ffgkcl} \\
+fits\_get\_keyname & \pageref{ffgknm} \\
+fits\_get\_keytype & \pageref{ffdtyp} \\
+fits\_get\_noise\_bits & \pageref{ffgetcomp} \\
+fits\_get\_num\_cols & \pageref{ffgnrw} \\
+fits\_get\_num\_groups & \pageref{ffgmng} \\
+fits\_get\_num\_hdus & \pageref{ffthdu} \\
+fits\_get\_num\_members & \pageref{ffgtnm} \\
+fits\_get\_num\_rows & \pageref{ffgnrw} \\
+fits\_get\_rowsize & \pageref{ffgrsz} \\
+fits\_get\_system\_time & \pageref{ffdt2s} \\
+fits\_get\_tile\_dim & \pageref{ffgetcomp} \\
+fits\_get\_tbcol & \pageref{ffgabc} \\
+fits\_get\_version & \pageref{ffvers} \\
+fits\_hdr2str & \pageref{ffhdr2str}, \pageref{hdr2str} \\
+fits\_insert\_atbl & \pageref{ffitab} \\
+fits\_insert\_btbl & \pageref{ffibin} \\
+fits\_insert\_col & \pageref{fficol} \\
+fits\_insert\_cols & \pageref{fficls} \\
+fits\_insert\_group & \pageref{ffgtis} \\
+fits\_insert\_img & \pageref{ffiimg} \\
+fits\_insert\_key\_null & \pageref{ffikyu} \\
+fits\_insert\_key\_TYP & \pageref{ffikyx} \\
+fits\_insert\_record & \pageref{ffirec} \\
+fits\_insert\_rows & \pageref{ffirow} \\
+fits\_iterate\_data & \pageref{ffiter} \\
+\end{tabular}
+\newpage
+\begin{tabular}{lr}
+fits\_make\_keyn & \pageref{ffkeyn} \\
+fits\_make\_nkey & \pageref{ffnkey} \\
+fits\_merge\_groups & \pageref{ffgtmg} \\
+fits\_modify\_card & \pageref{ffmcrd} \\
+fits\_modify\_comment & \pageref{ffmcom} \\
+fits\_modify\_key\_null & \pageref{ffmkyu} \\
+fits\_modify\_key\_TYP & \pageref{ffmkyx} \\
+fits\_modify\_name & \pageref{ffmnam} \\
+fits\_modify\_record & \pageref{ffmrec} \\
+fits\_modify\_vector\_len & \pageref{ffmvec} \\
+fits\_movabs\_hdu & \pageref{ffmahd} \\
+fits\_movnam\_hdu & \pageref{ffmnhd} \\
+fits\_movrel\_hdu & \pageref{ffmrhd} \\
+fits\_null\_check & \pageref{ffnchk} \\
+fits\_open\_data & \pageref{ffopen} \\
+fits\_open\_diskfile & \pageref{ffopen} \\
+fits\_open\_file & \pageref{ffopen} \\
+fits\_open\_image & \pageref{ffopen} \\
+fits\_open\_table & \pageref{ffopen} \\
+fits\_open\_group & \pageref{ffgtop} \\
+fits\_open\_member & \pageref{ffgmop} \\
+fits\_open\_memfile & \pageref{ffomem} \\
+fits\_parse\_extnum & \pageref{ffextn} \\
+fits\_parse\_input\_url & \pageref{ffiurl} \\
+fits\_parse\_range & \pageref{ffrwrg} \\
+fits\_parse\_rootname & \pageref{ffrtnm} \\
+fits\_parse\_template & \pageref{ffgthd} \\
+fits\_parse\_value & \pageref{ffpsvc} \\
+fits\_pix\_to\_world & \pageref{ffwldp} \\
+fits\_read\_2d\_TYP & \pageref{ffg2dx} \\
+fits\_read\_3d\_TYP & \pageref{ffg3dx} \\
+fits\_read\_atblhdr & \pageref{ffghtb} \\
+fits\_read\_btblhdr & \pageref{ffghbn} \\
+fits\_read\_card & \pageref{ffgcrd} \\
+fits\_read\_col & \pageref{ffgcv} \\
+fits\_read\_col\_bit\_ & \pageref{ffgcx} \\
+fits\_read\_col\_TYP & \pageref{ffgcvx} \\
+fits\_read\_colnull & \pageref{ffgcf} \\
+fits\_read\_colnull\_TYP & \pageref{ffgcfx} \\
+fits\_read\_descript & \pageref{ffgdes} \\
+fits\_read\_descripts & \pageref{ffgdes} \\
+fits\_read\_errmsg & \pageref{ffgmsg} \\
+fits\_read\_grppar\_TYP & \pageref{ffggpx} \\
+fits\_read\_img & \pageref{ffgpv} \\
+fits\_read\_img\_coord & \pageref{ffgics} \\
+fits\_read\_img\_TYP & \pageref{ffgpvx} \\
+fits\_read\_imghdr & \pageref{ffghpr} \\
+
+\end{tabular}
+\begin{tabular}{lr}
+fits\_read\_imgnull & \pageref{ffgpf} \\
+fits\_read\_imgnull\_TYP & \pageref{ffgpfx} \\
+fits\_read\_key & \pageref{ffgky} \\
+fits\_read\_key\_longstr & \pageref{ffgkls} \\
+fits\_read\_key\_triple & \pageref{ffgkyt} \\
+fits\_read\_key\_unit & \pageref{ffgunt} \\
+fits\_read\_key\_TYP & \pageref{ffgkyx} \\
+fits\_read\_keyn & \pageref{ffgkyn} \\
+fits\_read\_keys\_TYP & \pageref{ffgknx} \\
+fits\_read\_keyword & \pageref{ffgkey} \\
+fits\_read\_pix & \pageref{ffgpxv} \\
+fits\_read\_pixnull & \pageref{ffgpxf} \\
+fits\_read\_record & \pageref{ffgrec} \\
+fits\_read\_subset\_TYP & \pageref{ffgsvx} \pageref{ffgsvx2}\\
+fits\_read\_subsetnull\_TYP & \pageref{ffgsfx} \pageref{ffgsfx2} \\
+fits\_read\_tbl\_coord & \pageref{ffgtcs} \\
+fits\_read\_tblbytes & \pageref{ffgtbb} \\
+fits\_read\_tdim & \pageref{ffgtdm} \\
+fits\_remove\_group & \pageref{ffgtrm} \\
+fits\_remove\_member & \pageref{ffgmrm} \\
+fits\_reopen\_file & \pageref{ffreopen} \\
+fits\_report\_error & \pageref{ffrprt} \\
+fits\_resize\_img & \pageref{ffrsim} \\
+fits\_select\_rows & \pageref{ffsrow} \\
+fits\_set\_atblnull & \pageref{ffsnul} \\
+fits\_set\_bscale & \pageref{ffpscl} \\
+fits\_set\_btblnull & \pageref{fftnul} \\
+fits\_set\_compression\_type & \pageref{ffsetcomp} \\
+fits\_set\_hdrsize & \pageref{ffhdef} \\
+fits\_set\_hdustruc & \pageref{ffrdef} \\
+fits\_set\_imgnull & \pageref{ffpnul} \\
+fits\_set\_noise\_bits & \pageref{ffsetcomp} \\
+fits\_set\_tile\_dim & \pageref{ffsetcomp} \\
+fits\_set\_tscale & \pageref{fftscl} \\
+fits\_split\_names & \pageref{splitnames} \\
+fits\_str2date & \pageref{ffdt2s} \\
+fits\_str2time & \pageref{ffdt2s} \\
+fits\_test\_expr & \pageref{fftexp} \\
+fits\_test\_heap & \pageref{fftheap} \\
+fits\_test\_keyword & \pageref{fftkey} \\
+fits\_test\_record & \pageref{fftrec} \\
+fits\_time2str & \pageref{ffdt2s} \\
+fits\_transfer\_member & \pageref{ffgmtf} \\
+fits\_update\_card & \pageref{ffucrd} \\
+fits\_update\_chksum & \pageref{ffupck} \\
+fits\_update\_key & \pageref{ffuky} \\
+fits\_update\_key\_null & \pageref{ffukyu} \\
+fits\_update\_key\_TYP & \pageref{ffukyx} \\
+\end{tabular}
+\begin{tabular}{lr}
+
+fits\_uppercase & \pageref{ffupch} \\
+fits\_url\_type & \pageref{ffurlt} \\
+fits\_verify\_chksum & \pageref{ffvcks} \\
+fits\_verify\_group & \pageref{ffgtvf} \\
+fits\_world\_to\_pix & \pageref{ffxypx} \\
+fits\_write\_2d\_TYP & \pageref{ffp2dx} \\
+fits\_write\_3d\_TYP & \pageref{ffp3dx} \\
+fits\_write\_atblhdr & \pageref{ffphtb} \\
+fits\_write\_btblhdr & \pageref{ffphbn} \\
+fits\_write\_chksum & \pageref{ffpcks} \\
+fits\_write\_col & \pageref{ffpcl} \\
+fits\_write\_col\_bit & \pageref{ffpclx} \\
+fits\_write\_col\_TYP & \pageref{ffpcls} \\
+fits\_write\_col\_null & \pageref{ffpclu} \\
+fits\_write\_colnull & \pageref{ffpcn} \\
+fits\_write\_colnull\_TYP & \pageref{ffpcnx} \\
+fits\_write\_comment & \pageref{ffpcom} \\
+fits\_write\_date & \pageref{ffpdat} \\
+fits\_write\_descript & \pageref{ffpdes} \\
+fits\_write\_errmark & \pageref{ffpmrk} \\
+fits\_write\_errmsg & \pageref{ffpmsg} \\
+fits\_write\_grphdr & \pageref{ffphpr} \\
+fits\_write\_grppar\_TYP & \pageref{ffpgpx} \\
+fits\_write\_history & \pageref{ffphis} \\
+fits\_write\_img & \pageref{ffppr} \\
+fits\_write\_img\_null & \pageref{ffppru} \\
+fits\_write\_img\_TYP & \pageref{ffpprx} \\
+fits\_write\_imghdr & \pageref{ffphps} \\
+fits\_write\_imgnull & \pageref{ffppn} \\
+fits\_write\_imgnull\_TYP & \pageref{ffppnx} \\
+fits\_write\_key & \pageref{ffpky} \\
+fits\_write\_key\_longstr & \pageref{ffpkls} \\
+fits\_write\_key\_longwarn & \pageref{ffplsw} \\
+fits\_write\_key\_null & \pageref{ffpkyu} \\
+fits\_write\_key\_template & \pageref{ffpktp} \\
+fits\_write\_key\_triple & \pageref{ffpkyt} \\
+fits\_write\_key\_unit & \pageref{ffpunt} \\
+fits\_write\_key\_TYP & \pageref{ffpkyx} \\
+fits\_write\_keys\_TYP & \pageref{ffpknx} \\
+fits\_write\_null\_img & \pageref{ffpprn} \\
+fits\_write\_pix & \pageref{ffppx} \\
+fits\_write\_pixnull & \pageref{ffppxn} \\
+fits\_write\_record & \pageref{ffprec} \\
+fits\_write\_subset & \pageref{ffpss} \\
+fits\_write\_subset\_TYP & \pageref{ffpssx} \\
+fits\_write\_tblbytes & \pageref{ffptbb} \\
+fits\_write\_tdim & \pageref{ffptdm} \\
+fits\_write\_theap & \pageref{ffpthp} \\
+\end{tabular}
+\newpage
+
+\begin{tabular}{lr}
+ffasfm & \pageref{ffasfm} \\
+ffbnfm & \pageref{ffbnfm} \\
+ffcalc & \pageref{ffcalc} \\
+ffcalc\_rng & \pageref{ffcalcrng} \\
+ffclos & \pageref{ffclos} \\
+ffcmph & \pageref{ffcmph} \\
+ffcmps & \pageref{ffcmps} \\
+ffcmrk & \pageref{ffpmrk} \\
+ffcmsg & \pageref{ffcmsg} \\
+ffcopy & \pageref{ffcopy} \\
+ffcpcl & \pageref{ffcpcl} \\
+ffcpdt & \pageref{ffcpdt} \\
+ffcpfl & \pageref{ffcpfl} \\
+ffcphd & \pageref{ffcphd} \\
+ffcpky & \pageref{ffcpky} \\
+ffcrhd & \pageref{ffcrhd} \\
+ffcrim & \pageref{ffcrim} \\
+ffcrow & \pageref{ffcrow} \\
+ffcrtb & \pageref{ffcrtb} \\
+ffdcol & \pageref{ffdcol} \\
+ffdelt & \pageref{ffdelt} \\
+ffdhdu & \pageref{ffdhdu} \\
+ffdkey & \pageref{ffdkey} \\
+ffdkinit & \pageref{ffinit} \\
+ffdkopen & \pageref{ffopen} \\
+ffdopn & \pageref{ffopen} \\
+ffdrec & \pageref{ffdrec} \\
+ffdrow & \pageref{ffdrow} \\
+ffdrrg & \pageref{ffdrrg} \\
+ffdrws & \pageref{ffdrws} \\
+ffdsum & \pageref{ffdsum} \\
+ffdt2s & \pageref{ffdt2s} \\
+ffdtdm & \pageref{ffdtdm} \\
+ffdtyp & \pageref{ffdtyp} \\
+ffeqty & \pageref{ffgtcl} \\
+ffesum & \pageref{ffesum} \\
+ffexest & \pageref{ffexist} \\
+ffextn & \pageref{ffextn} \\
+ffffrw & \pageref{ffffrw} \\
+ffflmd & \pageref{ffflmd} \\
+ffflnm & \pageref{ffflnm} \\
+ffflsh & \pageref{ffflus} \\
+ffflus & \pageref{ffflus} \\
+fffrow & \pageref{fffrow} \\
+ffg2d\_ & \pageref{ffg2dx} \\
+ffg3d\_ & \pageref{ffg3dx} \\
+ffgabc & \pageref{ffgabc} \\
+\end{tabular}
+\begin{tabular}{lr}
+ffgacl & \pageref{ffgacl} \\
+ffgbcl & \pageref{ffgbcl} \\
+ffgcdw & \pageref{ffgcdw} \\
+ffgcf & \pageref{ffgcf} \\
+ffgcf\_ & \pageref{ffgcfx} \\
+ffgcks & \pageref{ffgcks} \\
+ffgcnn & \pageref{ffgcnn} \\
+ffgcno & \pageref{ffgcno} \\
+ffgcrd & \pageref{ffgcrd} \\
+ffgcv & \pageref{ffgcv} \\
+ffgcv\_ & \pageref{ffgcvx} \\
+ffgcx & \pageref{ffgcx} \\
+ffgdes & \pageref{ffgdes} \\
+ffgdess & \pageref{ffgdes} \\
+ffgerr & \pageref{ffgerr} \\
+ffggp\_ & \pageref{ffggpx} \\
+ffghad & \pageref{ffghad} \\
+ffghbn & \pageref{ffghbn} \\
+ffghdn & \pageref{ffghdn} \\
+ffghdt & \pageref{ffghdt} \\
+ffghof & \pageref{ffghad} \\
+ffghpr & \pageref{ffghpr} \\
+ffghps & \pageref{ffghps} \\
+ffghsp & \pageref{ffghsp} \\
+ffghtb & \pageref{ffghtb} \\
+ffgics & \pageref{ffgics} \\
+ffgidm & \pageref{ffgidm} \\
+ffgidt & \pageref{ffgidt} \\
+ffgiet & \pageref{ffgidt} \\
+ffgipr & \pageref{ffgipr} \\
+ffgisz & \pageref{ffgisz} \\
+ffgkcl & \pageref{ffgkcl} \\
+ffgkey & \pageref{ffgkey} \\
+ffgkls & \pageref{ffgkls} \\
+ffgkn\_ & \pageref{ffgknx} \\
+ffgknm & \pageref{ffgknm} \\
+ffgky & \pageref{ffgky} \\
+ffgkyn & \pageref{ffgkyn} \\
+ffgkyt & \pageref{ffgkyt} \\
+ffgky\_ & \pageref{ffgkyx} \\
+ffgmcp & \pageref{ffgmcp} \\
+ffgmng & \pageref{ffgmng} \\
+ffgmop & \pageref{ffgmop} \\
+ffgmrm & \pageref{ffgmrm} \\
+ffgmsg & \pageref{ffgmsg} \\
+ffgmtf & \pageref{ffgmtf} \\
+ffgncl & \pageref{ffgnrw} \\
+
+\end{tabular}
+\begin{tabular}{lr}
+ffgnrw & \pageref{ffgnrw} \\
+ffgnxk & \pageref{ffgnxk} \\
+ffgpf & \pageref{ffgpf} \\
+ffgpf\_ & \pageref{ffgpfx} \\
+ffgpv & \pageref{ffgpv} \\
+ffgpv\_ & \pageref{ffgpvx} \\
+ffgpxv & \pageref{ffgpxv} \\
+ffgpxf & \pageref{ffgpxf} \\
+ffgrec & \pageref{ffgrec} \\
+ffgrsz & \pageref{ffgrsz} \\
+ffgsdt & \pageref{ffdt2s} \\
+ffgsf\_ & \pageref{ffgsfx} \pageref{ffgsfx2} \\
+ffgstm & \pageref{ffdt2s} \\
+ffgsv\_ & \pageref{ffgsvx} \pageref{ffgsvx2}\\
+ffgtam & \pageref{ffgtam} \\
+ffgtbb & \pageref{ffgtbb} \\
+ffgtch & \pageref{ffgtch} \\
+ffgtcl & \pageref{ffgtcl} \\
+ffgtcm & \pageref{ffgtcm} \\
+ffgtcp & \pageref{ffgtcp} \\
+ffgtcr & \pageref{ffgtcr} \\
+ffgtcs & \pageref{ffgtcs} \\
+ffgtdm & \pageref{ffgtdm} \\
+ffgthd & \pageref{ffgthd} \\
+ffgtis & \pageref{ffgtis} \\
+ffgtmg & \pageref{ffgtmg} \\
+ffgtnm & \pageref{ffgtnm} \\
+ffgtop & \pageref{ffgtop} \\
+ffgtrm & \pageref{ffgtrm} \\
+ffgtvf & \pageref{ffgtvf} \\
+ffgunt & \pageref{ffgunt} \\
+ffhdef & \pageref{ffhdef} \\
+ffibin & \pageref{ffibin} \\
+fficls & \pageref{fficls} \\
+fficol & \pageref{fficol} \\
+ffiimg & \pageref{ffiimg} \\
+ffikls & \pageref{ffikyx} \\
+ffikyu & \pageref{ffikyu} \\
+ffiky\_ & \pageref{ffikyx} \\
+ffimem & \pageref{ffimem} \\
+ffinit & \pageref{ffinit} \\
+ffiopn & \pageref{ffopen} \\
+ffirec & \pageref{ffirec} \\
+ffirow & \pageref{ffirow} \\
+ffitab & \pageref{ffitab} \\
+ffiter & \pageref{ffiter} \\
+ffiurl & \pageref{ffiurl} \\
+
+\end{tabular}
+\begin{tabular}{lr}
+ffkeyn & \pageref{ffkeyn} \\
+ffmahd & \pageref{ffmahd} \\
+ffmcom & \pageref{ffmcom} \\
+ffmcrd & \pageref{ffmcrd} \\
+ffmkls & \pageref{ffmkyx} \\
+ffmkyu & \pageref{ffmkyu} \\
+ffmky\_ & \pageref{ffmkyx} \\
+ffmnam & \pageref{ffmnam} \\
+ffmnhd & \pageref{ffmnhd} \\
+ffmrec & \pageref{ffmrec} \\
+ffmrhd & \pageref{ffmrhd} \\
+ffmvec & \pageref{ffmvec} \\
+ffnchk & \pageref{ffnchk} \\
+ffnkey & \pageref{ffnkey} \\
+ffomem & \pageref{ffomem} \\
+ffopen & \pageref{ffopen} \\
+ffp2d\_ & \pageref{ffp2dx} \\
+ffp3d\_ & \pageref{ffp3dx} \\
+ffpcks & \pageref{ffpcks} \\
+ffpcl & \pageref{ffpcl} \\
+ffpcls & \pageref{ffpcls} \\
+ffpcl\_ & \pageref{ffpclx} \\
+ffpclu & \pageref{ffpclu} \\
+ffpcn & \pageref{ffpcn} \\
+ffpcn\_ & \pageref{ffpcnx} \\
+ffpcom & \pageref{ffpcom} \\
+ffpdat & \pageref{ffpdat} \\
+ffpdes & \pageref{ffpdes} \\
+ffpgp\_ & \pageref{ffpgpx} \\
+ffphbn & \pageref{ffphbn} \\
+ffphis & \pageref{ffphis} \\
+ffphpr & \pageref{ffphpr} \\
+ffphps & \pageref{ffphps} \\
+ffphtb & \pageref{ffphtb} \\
+ffpkls & \pageref{ffpkls} \\
+ffpkn\_ & \pageref{ffpknx} \\
+ffpktp & \pageref{ffpktp} \\
+ffpky & \pageref{ffpky} \\
+ffpkyt & \pageref{ffpkyt} \\
+ffpkyu & \pageref{ffpkyu} \\
+ffpky\_ & \pageref{ffpkyx} \\
+ffplsw & \pageref{ffplsw} \\
+ffpmrk & \pageref{ffpmrk} \\
+ffpmsg & \pageref{ffpmsg} \\
+ffpnul & \pageref{ffpnul} \\
+ffppn & \pageref{ffppn} \\
+ffppn\_ & \pageref{ffppnx} \\
+
+\end{tabular}
+\begin{tabular}{lr}
+ffppr & \pageref{ffppr} \\
+ffpprn & \pageref{ffpprn} \\
+ffppru & \pageref{ffppru} \\
+ffppr\_ & \pageref{ffpprx} \\
+ffppx & \pageref{ffppx} \\
+ffppxn & \pageref{ffppxn} \\
+ffprec & \pageref{ffprec} \\
+ffpscl & \pageref{ffpscl} \\
+ffpss & \pageref{ffpss} \\
+ffpss\_ & \pageref{ffpssx} \\
+ffpsvc & \pageref{ffpsvc} \\
+ffptbb & \pageref{ffptbb} \\
+ffptdm & \pageref{ffptdm} \\
+ffpthp & \pageref{ffpthp} \\
+ffpunt & \pageref{ffpunt} \\
+ffrdef & \pageref{ffrdef} \\
+ffreopen & \pageref{ffreopen} \\
+ffrprt & \pageref{ffrprt} \\
+ffrsim & \pageref{ffrsim} \\
+ffrtnm & \pageref{ffrtnm} \\
+ffrwrg & \pageref{ffrwrg} \\
+ffs2dt & \pageref{ffdt2s} \\
+ffs2tm & \pageref{ffdt2s} \\
+ffsnul & \pageref{ffsnul} \\
+ffsrow & \pageref{ffsrow} \\
+fftexp & \pageref{fftexp} \\
+ffthdu & \pageref{ffthdu} \\
+fftheap & \pageref{fftheap} \\
+fftkey & \pageref{fftkey} \\
+fftm2s & \pageref{ffdt2s} \\
+fftnul & \pageref{fftnul} \\
+fftopn & \pageref{ffopen} \\
+fftplt & \pageref{fftplt} \\
+fftrec & \pageref{fftrec} \\
+fftscl & \pageref{fftscl} \\
+ffucrd & \pageref{ffucrd} \\
+ffukls & \pageref{ffukyx} \\
+ffuky & \pageref{ffuky} \\
+ffukyu & \pageref{ffukyu} \\
+ffuky\_ & \pageref{ffukyx} \\
+ffupch & \pageref{ffupch} \\
+ffupck & \pageref{ffupck} \\
+ffurlt & \pageref{ffurlt} \\
+ffvcks & \pageref{ffvcks} \\
+ffvers & \pageref{ffvers} \\
+ffwldp & \pageref{ffwldp} \\
+ffxypx & \pageref{ffxypx} \\
+\end{tabular}
+
+
+
+\chapter{Parameter Definitions }
+
+\begin{verbatim}
+anynul - set to TRUE (=1) if any returned values are undefined, else FALSE
+array - array of numerical data values to read or write
+ascii - encoded checksum string
+binspec - the input table binning specifier
+bitpix - bits per pixel. The following symbolic mnemonics are predefined:
+ BYTE_IMG = 8 (unsigned char)
+ SHORT_IMG = 16 (signed short integer)
+ LONG_IMG = 32 (signed long integer)
+ LONGLONG_IMG = 64 (signed long 64-bit integer)
+ FLOAT_IMG = -32 (float)
+ DOUBLE_IMG = -64 (double).
+ The LONGLONG_IMG type is experimental and is not officially
+ recognized in the FITS Standard document.
+ Two additional values, USHORT_IMG and ULONG_IMG are also available
+ for creating unsigned integer images. These are equivalent to
+ creating a signed integer image with BZERO offset keyword values
+ of 32768 or 2147483648, respectively, which is the convention that
+ FITS uses to store unsigned integers.
+card - header record to be read or written (80 char max, null-terminated)
+casesen - CASESEN (=1) for case-sensitive string matching, else CASEINSEN (=0)
+cmopt - grouping table "compact" option parameter. Allowed values are:
+ OPT_CMT_MBR and OPT_CMT_MBR_DEL.
+colname - name of the column (null-terminated)
+colnum - column number (first column = 1)
+colspec - the input file column specification; used to delete, create, or rename
+ table columns
+comment - the keyword comment field (72 char max, null-terminated)
+complm - should the checksum be complemented?
+comptype - compression algorithm to use: GZIP_1, RICE_1, or PLIO_1
+coordtype- type of coordinate projection (-SIN, -TAN, -ARC, -NCP,
+ -GLS, -MER, or -AIT)
+cpopt - grouping table copy option parameter. Allowed values are:
+ OPT_GCP_GPT, OPT_GCP_MBR, OPT_GCP_ALL, OPT_MCP_ADD, OPT_MCP_NADD,
+ OPT_MCP_REPL, amd OPT_MCP_MOV.
+create_col- If TRUE, then insert a new column in the table, otherwise
+ overwrite the existing column.
+current - if TRUE, then the current HDU will be copied
+dataok - was the data unit verification successful (=1) or
+ not (= -1). Equals zero if the DATASUM keyword is not present.
+datasum - 32-bit 1's complement checksum for the data unit
+dataend - address (in bytes) of the end of the HDU
+datastart- address (in bytes) of the start of the data unit
+datatype - specifies the data type of the value. Allowed value are: TSTRING,
+ TLOGICAL, TBYTE, TSBYTE, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG,
+ TFLOAT, TDOUBLE, TCOMPLEX, and TDBLCOMPLEX
+datestr - FITS date/time string: 'YYYY-MM-DDThh:mm:ss.ddd', 'YYYY-MM-dd',
+ or 'dd/mm/yy'
+day - calendar day (UTC) (1-31)
+decimals - number of decimal places to be displayed
+deltasize - increment for allocating more memory
+dim1 - declared size of the first dimension of the image or cube array
+dim2 - declared size of the second dimension of the data cube array
+dispwidth - display width of a column = length of string that will be read
+dtype - data type of the keyword ('C', 'L', 'I', 'F' or 'X')
+ C = character string
+ L = logical
+ I = integer
+ F = floating point number
+ X = complex, e.g., "(1.23, -4.56)"
+err_msg - error message on the internal stack (80 chars max)
+err_text - error message string corresponding to error number (30 chars max)
+exact - TRUE (=1) if the strings match exactly;
+ FALSE (=0) if wildcards are used
+exclist - array of pointers to keyword names to be excluded from search
+exists - flag indicating whether the file or compressed file exists on disk
+expr - boolean or arithmetic expression
+extend - TRUE (=1) if FITS file may have extensions, else FALSE (=0)
+extname - value of the EXTNAME keyword (null-terminated)
+extspec - the extension or HDU specifier; a number or name, version, and type
+extver - value of the EXTVER keyword = integer version number
+filename - full name of the FITS file, including optional HDU and filtering specs
+filetype - type of file (file://, ftp://, http://, etc.)
+filter - the input file filtering specifier
+firstchar- starting byte in the row (first byte of row = 1)
+firstfailed - member HDU ID (if positive) or grouping table GRPIDn index
+ value (if negative) that failed grouping table verification.
+firstelem- first element in a vector (ignored for ASCII tables)
+firstrow - starting row number (first row of table = 1)
+following- if TRUE, any HDUs following the current HDU will be copied
+fpixel - coordinate of the first pixel to be read or written in the
+ FITS array. The array must be of length NAXIS and have values such
+ that fpixel[0] is in the range 1 to NAXIS1, fpixel[1] is in the
+ range 1 to NAXIS2, etc.
+fptr - pointer to a 'fitsfile' structure describing the FITS file.
+frac - factional part of the keyword value
+gcount - number of groups in the primary array (usually = 1)
+gfptr - fitsfile* pointer to a grouping table HDU.
+group - GRPIDn/GRPLCn index value identifying a grouping table HDU, or
+ data group number (=0 for non-grouped data)
+grouptype - Grouping table parameter that specifies the columns to be
+ created in a grouping table HDU. Allowed values are: GT_ID_ALL_URI,
+ GT_ID_REF, GT_ID_POS, GT_ID_ALL, GT_ID_REF_URI, and GT_ID_POS_URI.
+grpname - value to use for the GRPNAME keyword value.
+hdunum - sequence number of the HDU (Primary array = 1)
+hduok - was the HDU verification successful (=1) or
+ not (= -1). Equals zero if the CHECKSUM keyword is not present.
+hdusum - 32 bit 1's complement checksum for the entire CHDU
+hdutype - type of HDU: IMAGE_HDU (=0), ASCII_TBL (=1), or BINARY_TBL (=2)
+header - returned character string containing all the keyword records
+headstart- starting address (in bytes) of the CHDU
+heapsize - size of the binary table heap, in bytes
+history - the HISTORY keyword comment string (70 char max, null-terminated)
+hour - hour within day (UTC) (0 - 23)
+inc - sampling interval for pixels in each FITS dimension
+inclist - array of pointers to matching keyword names
+incolnum - input column number; range = 1 to TFIELDS
+infile - the input filename, including path if specified
+infptr - pointer to a 'fitsfile' structure describing the input FITS file.
+intval - integer part of the keyword value
+iomode - file access mode: either READONLY (=0) or READWRITE (=1)
+keyname - name of a keyword (8 char max, null-terminated)
+keynum - position of keyword in header (1st keyword = 1)
+keyroot - root string for the keyword name (5 char max, null-terminated)
+keysexist- number of existing keyword records in the CHU
+keytype - header record type: -1=delete; 0=append or replace;
+ 1=append; 2=this is the END keyword
+longstr - arbitrarily long string keyword value (null-terminated)
+lpixel - coordinate of the last pixel to be read or written in the
+ FITS array. The array must be of length NAXIS and have values such
+ that lpixel[0] is in the range 1 to NAXIS1, lpixel[1] is in the
+ range 1 to NAXIS2, etc.
+match - TRUE (=1) if the 2 strings match, else FALSE (=0)
+maxdim - maximum number of values to return
+member - row number of a grouping table member HDU.
+memptr - pointer to the a FITS file in memory
+mem_realloc - pointer to a function for reallocating more memory
+memsize - size of the memory block allocated for the FITS file
+mfptr - fitsfile* pointer to a grouping table member HDU.
+mgopt - grouping table merge option parameter. Allowed values are:
+ OPT_MRG_COPY, and OPT_MRG_MOV.
+minute - minute within hour (UTC) (0 - 59)
+month - calendar month (UTC) (1 - 12)
+morekeys - space in the header for this many more keywords
+n_good_rows - number of rows evaluating to TRUE
+namelist - string containing a comma or space delimited list of names
+naxes - size of each dimension in the FITS array
+naxis - number of dimensions in the FITS array
+naxis1 - length of the X/first axis of the FITS array
+naxis2 - length of the Y/second axis of the FITS array
+naxis3 - length of the Z/third axis of the FITS array
+nchars - number of characters to read or write
+nelements- number of data elements to read or write
+newfptr - returned pointer to the reopened file
+newveclen- new value for the column vector repeat parameter
+nexc - number of names in the exclusion list (may = 0)
+nfound - number of keywords found (highest keyword number)
+nkeys - number of keywords in the sequence
+ninc - number of names in the inclusion list
+nmembers - Number of grouping table members (NAXIS2 value).
+nmove - number of HDUs to move (+ or -), relative to current position
+nocomments - if equal to TRUE, then no commentary keywords will be copied
+noisebits- number of bits to ignore when compressing floating point images
+nrows - number of rows in the table
+nstart - first integer value
+nullarray- set to TRUE (=1) if corresponding data element is undefined
+nulval - numerical value to represent undefined pixels
+nulstr - character string used to represent undefined values in ASCII table
+numval - numerical data value, of the appropriate data type
+offset - byte offset in the heap to the first element of the vector
+openfptr - pointer to a currently open FITS file
+overlap - number of bytes in the binary table heap pointed to by more than 1
+ descriptor
+outcolnum- output column number; range = 1 to TFIELDS + 1
+outfile - and optional output filename; the input file will be copied to this prior
+ to opening the file
+outfptr - pointer to a 'fitsfile' structure describing the output FITS file.
+pcount - value of the PCOUNT keyword = size of binary table heap
+previous - if TRUE, any previous HDUs in the input file will be copied.
+repeat - length of column vector (e.g. 12J); == 1 for ASCII table
+rmopt - grouping table remove option parameter. Allowed values are:
+ OPT_RM_GPT, OPT_RM_ENTRY, OPT_RM_MBR, and OPT_RM_ALL.
+rootname - root filename, minus any extension or filtering specifications
+rot - celestial coordinate rotation angle (degrees)
+rowlen - length of a table row, in characters or bytes
+rowlist - sorted list of row numbers to be deleted from the table
+rownum - number of the row (first row = 1)
+rowrange - list of rows or row ranges: '3,6-8,12,56-80' or '500-'
+row_status - array of True/False results for each row that was evaluated
+scale - linear scaling factor; true value = (FITS value) * scale + zero
+second - second within minute (0 - 60.9999999999) (leap second!)
+simple - TRUE (=1) if FITS file conforms to the Standard, else FALSE (=0)
+space - number of blank spaces to leave between ASCII table columns
+status - returned error status code (0 = OK)
+sum - 32 bit unsigned checksum value
+tbcol - byte position in row to start of column (1st col has tbcol = 1)
+tdisp - Fortran style display format for the table column
+tdimstr - the value of the TDIMn keyword
+templt - template string used in comparison (null-terminated)
+tfields - number of fields (columns) in the table
+tfopt - grouping table member transfer option parameter. Allowed values are:
+ OPT_MCP_ADD, and OPT_MCP_MOV.
+tform - format of the column (null-terminated); allowed values are:
+ ASCII tables: Iw, Aw, Fww.dd, Eww.dd, or Dww.dd
+ Binary tables: rL, rX, rB, rI, rJ, rA, rAw, rE, rD, rC, rM
+ where 'w'=width of the field, 'd'=no. of decimals, 'r'=repeat count.
+ Variable length array columns are denoted by a '1P' before the data type
+ character (e.g., '1PJ'). When creating a binary table, 2 addition tform
+ data type codes are recognized by CFITSIO: 'rU' and 'rV' for unsigned
+ 16-bit and unsigned 32-bit integer, respectively.
+
+theap - zero indexed byte offset of starting address of the heap
+ relative to the beginning of the binary table data
+tilesize - array of length NAXIS that specifies the dimensions of
+ the image compression tiles
+ttype - label or name for table column (null-terminated)
+tunit - physical unit for table column (null-terminated)
+typechar - symbolic code of the table column data type
+typecode - data type code of the table column. The negative of
+ the value indicates a variable length array column.
+ Datatype typecode Mnemonic
+ bit, X 1 TBIT
+ byte, B 11 TBYTE
+ logical, L 14 TLOGICAL
+ ASCII character, A 16 TSTRING
+ short integer, I 21 TSHORT
+ integer, J 41 TINT32BIT
+ long long integer, K 81 TLONGLONG
+ real, E 42 TFLOAT
+ double precision, D 82 TDOUBLE
+ complex, C 83 TCOMPLEX
+ double complex, M 163 TDBLCOMPLEX
+ The TLONGLONG column type is experimental and is not
+ recognized in the official FITS Standard document
+unit - the physical unit string (e.g., 'km/s') for a keyword
+unused - number of unused bytes in the binary table heap
+urltype - the file type of the FITS file (file://, ftp://, mem://, etc.)
+validheap- returned value = FALSE if any of the variable length array
+ address are outside the valid range of addresses in the heap
+value - the keyword value string (70 char max, null-terminated)
+version - current version number of the CFITSIO library
+width - width of the character string field
+xcol - number of the column containing the X coordinate values
+xinc - X axis coordinate increment at reference pixel (deg)
+xpix - X axis pixel location
+xpos - X axis celestial coordinate (usually RA) (deg)
+xrefpix - X axis reference pixel array location
+xrefval - X axis coordinate value at the reference pixel (deg)
+ycol - number of the column containing the X coordinate values
+year - calendar year (e.g. 1999, 2000, etc)
+yinc - Y axis coordinate increment at reference pixel (deg)
+ypix - y axis pixel location
+ypos - y axis celestial coordinate (usually DEC) (deg)
+yrefpix - Y axis reference pixel array location
+yrefval - Y axis coordinate value at the reference pixel (deg)
+zero - scaling offset; true value = (FITS value) * scale + zero
+\end{verbatim}
+
+\chapter{CFITSIO Error Status Codes }
+
+The following table lists all the error status codes used by CFITSIO.
+Programmers are encouraged to use the symbolic mnemonics (defined in
+the file fitsio.h) rather than the actual integer status values to
+improve the readability of their code.
+
+\begin{verbatim}
+ Symbolic Const Value Meaning
+ -------------- ----- -----------------------------------------
+ 0 OK, no error
+ SAME_FILE 101 input and output files are the same
+ TOO_MANY_FILES 103 tried to open too many FITS files at once
+ FILE_NOT_OPENED 104 could not open the named file
+ FILE_NOT_CREATED 105 could not create the named file
+ WRITE_ERROR 106 error writing to FITS file
+ END_OF_FILE 107 tried to move past end of file
+ READ_ERROR 108 error reading from FITS file
+ FILE_NOT_CLOSED 110 could not close the file
+ ARRAY_TOO_BIG 111 array dimensions exceed internal limit
+ READONLY_FILE 112 Cannot write to readonly file
+ MEMORY_ALLOCATION 113 Could not allocate memory
+ BAD_FILEPTR 114 invalid fitsfile pointer
+ NULL_INPUT_PTR 115 NULL input pointer to routine
+ SEEK_ERROR 116 error seeking position in file
+
+ BAD_URL_PREFIX 121 invalid URL prefix on file name
+ TOO_MANY_DRIVERS 122 tried to register too many IO drivers
+ DRIVER_INIT_FAILED 123 driver initialization failed
+ NO_MATCHING_DRIVER 124 matching driver is not registered
+ URL_PARSE_ERROR 125 failed to parse input file URL
+ RANGE_PARSE_ERROR 126 parse error in range list
+
+ SHARED_BADARG 151 bad argument in shared memory driver
+ SHARED_NULPTR 152 null pointer passed as an argument
+ SHARED_TABFULL 153 no more free shared memory handles
+ SHARED_NOTINIT 154 shared memory driver is not initialized
+ SHARED_IPCERR 155 IPC error returned by a system call
+ SHARED_NOMEM 156 no memory in shared memory driver
+ SHARED_AGAIN 157 resource deadlock would occur
+ SHARED_NOFILE 158 attempt to open/create lock file failed
+ SHARED_NORESIZE 159 shared memory block cannot be resized at the moment
+
+ HEADER_NOT_EMPTY 201 header already contains keywords
+ KEY_NO_EXIST 202 keyword not found in header
+ KEY_OUT_BOUNDS 203 keyword record number is out of bounds
+ VALUE_UNDEFINED 204 keyword value field is blank
+ NO_QUOTE 205 string is missing the closing quote
+ BAD_KEYCHAR 207 illegal character in keyword name or card
+ BAD_ORDER 208 required keywords out of order
+ NOT_POS_INT 209 keyword value is not a positive integer
+ NO_END 210 couldn't find END keyword
+ BAD_BITPIX 211 illegal BITPIX keyword value
+ BAD_NAXIS 212 illegal NAXIS keyword value
+ BAD_NAXES 213 illegal NAXISn keyword value
+ BAD_PCOUNT 214 illegal PCOUNT keyword value
+ BAD_GCOUNT 215 illegal GCOUNT keyword value
+ BAD_TFIELDS 216 illegal TFIELDS keyword value
+ NEG_WIDTH 217 negative table row size
+ NEG_ROWS 218 negative number of rows in table
+ COL_NOT_FOUND 219 column with this name not found in table
+ BAD_SIMPLE 220 illegal value of SIMPLE keyword
+ NO_SIMPLE 221 Primary array doesn't start with SIMPLE
+ NO_BITPIX 222 Second keyword not BITPIX
+ NO_NAXIS 223 Third keyword not NAXIS
+ NO_NAXES 224 Couldn't find all the NAXISn keywords
+ NO_XTENSION 225 HDU doesn't start with XTENSION keyword
+ NOT_ATABLE 226 the CHDU is not an ASCII table extension
+ NOT_BTABLE 227 the CHDU is not a binary table extension
+ NO_PCOUNT 228 couldn't find PCOUNT keyword
+ NO_GCOUNT 229 couldn't find GCOUNT keyword
+ NO_TFIELDS 230 couldn't find TFIELDS keyword
+ NO_TBCOL 231 couldn't find TBCOLn keyword
+ NO_TFORM 232 couldn't find TFORMn keyword
+ NOT_IMAGE 233 the CHDU is not an IMAGE extension
+ BAD_TBCOL 234 TBCOLn keyword value < 0 or > rowlength
+ NOT_TABLE 235 the CHDU is not a table
+ COL_TOO_WIDE 236 column is too wide to fit in table
+ COL_NOT_UNIQUE 237 more than 1 column name matches template
+ BAD_ROW_WIDTH 241 sum of column widths not = NAXIS1
+ UNKNOWN_EXT 251 unrecognizable FITS extension type
+ UNKNOWN_REC 252 unknown record; 1st keyword not SIMPLE or XTENSION
+ END_JUNK 253 END keyword is not blank
+ BAD_HEADER_FILL 254 Header fill area contains non-blank chars
+ BAD_DATA_FILL 255 Illegal data fill bytes (not zero or blank)
+ BAD_TFORM 261 illegal TFORM format code
+ BAD_TFORM_DTYPE 262 unrecognizable TFORM data type code
+ BAD_TDIM 263 illegal TDIMn keyword value
+ BAD_HEAP_PTR 264 invalid BINTABLE heap pointer is out of range
+
+ BAD_HDU_NUM 301 HDU number < 1
+ BAD_COL_NUM 302 column number < 1 or > tfields
+ NEG_FILE_POS 304 tried to move to negative byte location in file
+ NEG_BYTES 306 tried to read or write negative number of bytes
+ BAD_ROW_NUM 307 illegal starting row number in table
+ BAD_ELEM_NUM 308 illegal starting element number in vector
+ NOT_ASCII_COL 309 this is not an ASCII string column
+ NOT_LOGICAL_COL 310 this is not a logical data type column
+ BAD_ATABLE_FORMAT 311 ASCII table column has wrong format
+ BAD_BTABLE_FORMAT 312 Binary table column has wrong format
+ NO_NULL 314 null value has not been defined
+ NOT_VARI_LEN 317 this is not a variable length column
+ BAD_DIMEN 320 illegal number of dimensions in array
+ BAD_PIX_NUM 321 first pixel number greater than last pixel
+ ZERO_SCALE 322 illegal BSCALE or TSCALn keyword = 0
+ NEG_AXIS 323 illegal axis length < 1
+
+ NOT_GROUP_TABLE 340 Grouping function error
+ HDU_ALREADY_MEMBER 341
+ MEMBER_NOT_FOUND 342
+ GROUP_NOT_FOUND 343
+ BAD_GROUP_ID 344
+ TOO_MANY_HDUS_TRACKED 345
+ HDU_ALREADY_TRACKED 346
+ BAD_OPTION 347
+ IDENTICAL_POINTERS 348
+ BAD_GROUP_ATTACH 349
+ BAD_GROUP_DETACH 350
+
+ NGP_NO_MEMORY 360 malloc failed
+ NGP_READ_ERR 361 read error from file
+ NGP_NUL_PTR 362 null pointer passed as an argument.
+ Passing null pointer as a name of
+ template file raises this error
+ NGP_EMPTY_CURLINE 363 line read seems to be empty (used
+ internally)
+ NGP_UNREAD_QUEUE_FULL 364 cannot unread more then 1 line (or single
+ line twice)
+ NGP_INC_NESTING 365 too deep include file nesting (infinite
+ loop, template includes itself ?)
+ NGP_ERR_FOPEN 366 fopen() failed, cannot open template file
+ NGP_EOF 367 end of file encountered and not expected
+ NGP_BAD_ARG 368 bad arguments passed. Usually means
+ internal parser error. Should not happen
+ NGP_TOKEN_NOT_EXPECT 369 token not expected here
+
+ BAD_I2C 401 bad int to formatted string conversion
+ BAD_F2C 402 bad float to formatted string conversion
+ BAD_INTKEY 403 can't interpret keyword value as integer
+ BAD_LOGICALKEY 404 can't interpret keyword value as logical
+ BAD_FLOATKEY 405 can't interpret keyword value as float
+ BAD_DOUBLEKEY 406 can't interpret keyword value as double
+ BAD_C2I 407 bad formatted string to int conversion
+ BAD_C2F 408 bad formatted string to float conversion
+ BAD_C2D 409 bad formatted string to double conversion
+ BAD_DATATYPE 410 illegal datatype code value
+ BAD_DECIM 411 bad number of decimal places specified
+ NUM_OVERFLOW 412 overflow during data type conversion
+ DATA_COMPRESSION_ERR 413 error compressing image
+ DATA_DECOMPRESSION_ERR 414 error uncompressing image
+
+ BAD_DATE 420 error in date or time conversion
+
+ PARSE_SYNTAX_ERR 431 syntax error in parser expression
+ PARSE_BAD_TYPE 432 expression did not evaluate to desired type
+ PARSE_LRG_VECTOR 433 vector result too large to return in array
+ PARSE_NO_OUTPUT 434 data parser failed not sent an out column
+ PARSE_BAD_COL 435 bad data encounter while parsing column
+ PARSE_BAD_OUTPUT 436 Output file not of proper type
+
+ ANGLE_TOO_BIG 501 celestial angle too large for projection
+ BAD_WCS_VAL 502 bad celestial coordinate or pixel value
+ WCS_ERROR 503 error in celestial coordinate calculation
+ BAD_WCS_PROJ 504 unsupported type of celestial projection
+ NO_WCS_KEY 505 celestial coordinate keywords not found
+ APPROX_WCS_KEY 506 approximate wcs keyword values were returned
+\end{verbatim}
+\end{document}
+
diff --git a/pkg/tbtables/cfitsio/cfitsio.toc b/pkg/tbtables/cfitsio/cfitsio.toc
new file mode 100644
index 00000000..6a396d85
--- /dev/null
+++ b/pkg/tbtables/cfitsio/cfitsio.toc
@@ -0,0 +1,118 @@
+\contentsline {chapter}{\numberline {1}Introduction }{1}
+\contentsline {section}{\numberline {1.1} A Brief Overview}{1}
+\contentsline {section}{\numberline {1.2}Sources of FITS Software and Information}{1}
+\contentsline {section}{\numberline {1.3}Acknowledgements}{2}
+\contentsline {section}{\numberline {1.4}Legal Stuff}{3}
+\contentsline {chapter}{\numberline {2} Creating the CFITSIO Library }{5}
+\contentsline {section}{\numberline {2.1}Building the Library}{5}
+\contentsline {subsection}{\numberline {2.1.1}Unix Systems}{5}
+\contentsline {subsection}{\numberline {2.1.2}VMS}{7}
+\contentsline {subsection}{\numberline {2.1.3}Windows PCs}{7}
+\contentsline {subsection}{\numberline {2.1.4}Macintosh PCs}{7}
+\contentsline {section}{\numberline {2.2}Testing the Library}{8}
+\contentsline {section}{\numberline {2.3}Linking Programs with CFITSIO}{9}
+\contentsline {section}{\numberline {2.4}Getting Started with CFITSIO}{9}
+\contentsline {section}{\numberline {2.5}Example Program}{10}
+\contentsline {chapter}{\numberline {3} A FITS Primer }{13}
+\contentsline {chapter}{\numberline {4} Programming Guidelines }{15}
+\contentsline {section}{\numberline {4.1}CFITSIO Definitions}{15}
+\contentsline {section}{\numberline {4.2}Current Header Data Unit (CHDU)}{17}
+\contentsline {section}{\numberline {4.3}Function Names and Variable Datatypes}{18}
+\contentsline {section}{\numberline {4.4}Support for Unsigned Integers and Signed Bytes}{19}
+\contentsline {section}{\numberline {4.5}Dealing with Character Strings}{21}
+\contentsline {section}{\numberline {4.6}Implicit Data Type Conversion}{22}
+\contentsline {section}{\numberline {4.7}Data Scaling}{22}
+\contentsline {section}{\numberline {4.8}Support for IEEE Special Values}{23}
+\contentsline {section}{\numberline {4.9}Error Status Values and the Error Message Stack}{23}
+\contentsline {section}{\numberline {4.10}Variable-Length Arrays in Binary Tables}{24}
+\contentsline {section}{\numberline {4.11}Multiple Access to the Same FITS File}{25}
+\contentsline {section}{\numberline {4.12}When the Final Size of the FITS HDU is Unknown}{26}
+\contentsline {section}{\numberline {4.13}CFITSIO Size Limitations}{26}
+\contentsline {chapter}{\numberline {5}Basic CFITSIO Interface Routines }{29}
+\contentsline {section}{\numberline {5.1}CFITSIO Error Status Routines}{29}
+\contentsline {section}{\numberline {5.2}FITS File Access Routines}{30}
+\contentsline {section}{\numberline {5.3}HDU Access Routines}{33}
+\contentsline {section}{\numberline {5.4}Header Keyword Read/Write Routines}{35}
+\contentsline {subsection}{\numberline {5.4.1}Keyword Reading Routines}{35}
+\contentsline {subsection}{\numberline {5.4.2}Keyword Writing Routines}{37}
+\contentsline {section}{\numberline {5.5}Primary Array or IMAGE Extension I/O Routines}{39}
+\contentsline {section}{\numberline {5.6}Image Compression}{42}
+\contentsline {section}{\numberline {5.7}ASCII and Binary Table Routines}{45}
+\contentsline {subsection}{\numberline {5.7.1}Create New Table}{45}
+\contentsline {subsection}{\numberline {5.7.2}Column Information Routines}{46}
+\contentsline {subsection}{\numberline {5.7.3}Routines to Edit Rows or Columns}{48}
+\contentsline {subsection}{\numberline {5.7.4}Read and Write Column Data Routines}{50}
+\contentsline {subsection}{\numberline {5.7.5}Row Selection and Calculator Routines}{51}
+\contentsline {section}{\numberline {5.8}Utility Routines}{53}
+\contentsline {subsection}{\numberline {5.8.1}File Checksum Routines}{53}
+\contentsline {subsection}{\numberline {5.8.2}Date and Time Utility Routines}{54}
+\contentsline {subsection}{\numberline {5.8.3}General Utility Routines}{56}
+\contentsline {chapter}{\numberline {6} The CFITSIO Iterator Function }{63}
+\contentsline {section}{\numberline {6.1}The Iterator Work Function}{64}
+\contentsline {section}{\numberline {6.2}The Iterator Driver Function}{66}
+\contentsline {section}{\numberline {6.3}Guidelines for Using the Iterator Function}{67}
+\contentsline {section}{\numberline {6.4}Complete List of Iterator Routines}{68}
+\contentsline {chapter}{\numberline {7} Celestial Coordinate System Routines }{71}
+\contentsline {section}{\numberline {7.1} Self-contained WCS Routines}{72}
+\contentsline {chapter}{\numberline {8} Hierarchical Grouping Routines }{75}
+\contentsline {section}{\numberline {8.1}Grouping Table Routines}{76}
+\contentsline {section}{\numberline {8.2}Group Member Routines}{78}
+\contentsline {chapter}{\numberline {9} Specialized CFITSIO Interface Routines }{81}
+\contentsline {section}{\numberline {9.1}FITS File Access Routines}{81}
+\contentsline {section}{\numberline {9.2}HDU Access Routines}{84}
+\contentsline {section}{\numberline {9.3}Specialized Header Keyword Routines}{86}
+\contentsline {subsection}{\numberline {9.3.1}Header Information Routines}{86}
+\contentsline {subsection}{\numberline {9.3.2}Read and Write the Required Keywords}{86}
+\contentsline {subsection}{\numberline {9.3.3}Write Keyword Routines}{88}
+\contentsline {subsection}{\numberline {9.3.4}Insert Keyword Routines}{90}
+\contentsline {subsection}{\numberline {9.3.5}Read Keyword Routines}{91}
+\contentsline {subsection}{\numberline {9.3.6}Modify Keyword Routines}{92}
+\contentsline {subsection}{\numberline {9.3.7}Update Keyword Routines}{93}
+\contentsline {section}{\numberline {9.4}Define Data Scaling and Undefined Pixel Parameters}{94}
+\contentsline {section}{\numberline {9.5}Specialized FITS Primary Array or IMAGE Extension I/O Routines}{95}
+\contentsline {section}{\numberline {9.6}Specialized FITS ASCII and Binary Table Routines}{99}
+\contentsline {subsection}{\numberline {9.6.1}General Column Routines}{99}
+\contentsline {subsection}{\numberline {9.6.2}Low-Level Table Access Routines}{100}
+\contentsline {subsection}{\numberline {9.6.3}Write Column Data Routines}{100}
+\contentsline {subsection}{\numberline {9.6.4}Read Column Data Routines}{102}
+\contentsline {chapter}{\numberline {10} Extended File Name Syntax }{105}
+\contentsline {section}{\numberline {10.1}Overview}{105}
+\contentsline {section}{\numberline {10.2}Filetype}{108}
+\contentsline {subsection}{\numberline {10.2.1}Notes about HTTP proxy servers}{108}
+\contentsline {subsection}{\numberline {10.2.2}Notes about the root filetype}{108}
+\contentsline {subsection}{\numberline {10.2.3}Notes about the shmem filetype:}{110}
+\contentsline {section}{\numberline {10.3}Base Filename}{111}
+\contentsline {section}{\numberline {10.4}Output File Name when Opening an Existing File}{113}
+\contentsline {section}{\numberline {10.5}Template File Name when Creating a New File}{114}
+\contentsline {section}{\numberline {10.6}Image Tile-Compression Specification}{114}
+\contentsline {section}{\numberline {10.7}HDU Location Specification}{115}
+\contentsline {section}{\numberline {10.8}Image Section}{116}
+\contentsline {section}{\numberline {10.9}Column and Keyword Filtering Specification}{117}
+\contentsline {section}{\numberline {10.10}Row Filtering Specification}{118}
+\contentsline {subsection}{\numberline {10.10.1}General Syntax}{119}
+\contentsline {subsection}{\numberline {10.10.2}Bit Masks}{121}
+\contentsline {subsection}{\numberline {10.10.3}Vector Columns}{122}
+\contentsline {subsection}{\numberline {10.10.4}Good Time Interval Filtering}{123}
+\contentsline {subsection}{\numberline {10.10.5}Spatial Region Filtering}{124}
+\contentsline {subsection}{\numberline {10.10.6}Example Row Filters}{126}
+\contentsline {section}{\numberline {10.11} Binning or Histogramming Specification}{127}
+\contentsline {chapter}{\numberline {11}Template Files }{131}
+\contentsline {section}{\numberline {11.1}Detailed Template Line Format}{131}
+\contentsline {section}{\numberline {11.2}Auto-indexing of Keywords}{132}
+\contentsline {section}{\numberline {11.3}Template Parser Directives}{133}
+\contentsline {section}{\numberline {11.4}Formal Template Syntax}{133}
+\contentsline {section}{\numberline {11.5}Errors}{134}
+\contentsline {section}{\numberline {11.6}Examples}{134}
+\contentsline {chapter}{\numberline {12} Local FITS Conventions }{137}
+\contentsline {section}{\numberline {12.1}64-Bit Long Integers}{137}
+\contentsline {section}{\numberline {12.2}Long String Keyword Values.}{138}
+\contentsline {section}{\numberline {12.3}Arrays of Fixed-Length Strings in Binary Tables}{139}
+\contentsline {section}{\numberline {12.4}Keyword Units Strings}{139}
+\contentsline {section}{\numberline {12.5}HIERARCH Convention for Extended Keyword Names}{140}
+\contentsline {section}{\numberline {12.6}Tile-Compressed Image Format}{140}
+\contentsline {chapter}{\numberline {13} Optimizing Programs }{143}
+\contentsline {section}{\numberline {13.1}How CFITSIO Manages Data I/O}{143}
+\contentsline {section}{\numberline {13.2}Optimization Strategies}{144}
+\contentsline {chapter}{\numberline {A}Index of Routines }{147}
+\contentsline {chapter}{\numberline {B}Parameter Definitions }{151}
+\contentsline {chapter}{\numberline {C}CFITSIO Error Status Codes }{157}
diff --git a/pkg/tbtables/cfitsio/cfitsio_mac.sit.hqx b/pkg/tbtables/cfitsio/cfitsio_mac.sit.hqx
new file mode 100644
index 00000000..0a3dbdfb
--- /dev/null
+++ b/pkg/tbtables/cfitsio/cfitsio_mac.sit.hqx
@@ -0,0 +1 @@
+(This file must be converted with BinHex 4.0) :$f0QDA4cD@pIE@&M,R0TG!"6594%8dP8)3#3"%11!*!%4HY6593K!!%!!%11FNa KG3*6!*!$&ZlZ)#!,BfCTG(0TEepYB@-!N"AR#BB"&J!9!U)"eJ#3!`-!N!q'!!! $([q3"!2JYCR`K,@Cp[N!N!8"mK%!N!C$#2r`rrJ!!-0!!!"0Y`!0$N0'DA4cD@p 38%-ZE@0`!*!4Da3*KJ#3$aB!!$i$!*!$&[q3"%e08(*$9dP&!3#[H%fHYCRfmJ# 3"3(U0!#3"Md0!!"9XJ#3"[8H"[LUJEpCRC+&h2,Qp5XR2!PhHq4S2H%,ApKQqmJ LNkpp8AlddNfr[1A)MP#1Tai![I"-haEmadlZiRN5eLh2&pPQYb@hMpc#pMQahU[ MjF@A)`YEb',mbF)EN!#&l)[`r)9RmFZHm#-lbAEK#qr)l6MKLpjbR($&#Ur-Vr0 fK0r#Ma`RA-)l22Q&,13AFTY-&L1cK5jN"9K($6SEG(C1mZ4R0R4JEhDp%a[NjC! $GhCHIV6,b@DM((4ffHR#LbqH!ph[phRj4[C&&ShX)r[YiRdmbHkebmMq[(KN$cV cFa#2l)[X86b,,-plB#b!Vl2VCAikk,fqbH,(bq[*l53meJ,!&[`"jhIkI5f1'd% 3,!Q#dUUJp-!lJY+$p5"BH5ma(bKeP6LDVcDZZdeKNN4a8UiQm9CAbqCLA5QIqP[ XPi0Jl8H#i"hHrpUqXi,J3lqkj2T6Yh"H2r[XNdTd(rB03A$L`5"Bk[dc2RMIZPh "b@rE'34[ackdki2h"FF(`H@c#NqI)P4GS[!F,Pp*9ei&5TqF6!e5'Z+9D"fM`h3 SKb"@J#a`!MD',FIf`[E'9Q$lB2YLqf(lBdr#RS`GJ$d&1a!l&(XDGKKf1,B5HcV f$1`)l*RBNGLcX'GMcm'HKld!Hb&f0$D-(B3GV&F8@iSYXeH9XJm!'S'I``l"RSX p(cX+1aCEK4f((@pf`QYP)SqYmP[j5"8[%qfa(pAKIHX%hY3A6jljZ2T8+l$Y9P+ 9ZSABJ5Ud2KH'fm*+)da6PhC[$C1M&eJq8#d2EIU0kPcTFK1[N!#9EL'@!Z3P+,c -9icR6L[c8`j9I`iR[I25%D#SDkA4H$YaNp&-Gc1XG32c$IHfjC@#kiCLM)K%k9U d0C!!+Y"B$PJ09iKRp+T'ImNm&#%J!p"afpL5RV[@,,R`mrF[ZH#ElqrD[qq5V[h AhHR6KErIYIm6PcaA6"*I""A*,da(Ij9Gqfr-+elX!'`CYKcE#pX2#j!!mKDmMrF f[!P[`aGVCh(5hqLkFX8[lETZ[FY'fki@68BZ'4rrPF(qU1%Ur52RpBmU,(M&e-r [ZMjp9qrk4M`40Y,amE22fMMRMCjalUk29a)ACUirLCZM'DkYiq-#6)e-2)$BNji $[H19,-l5)CG-ZI*`jkGdGbVIp'Te-(q&F1rJqXfekDJZ"VeXY&TjXIkPJR"+B'p X,f`j0LE!&GXAfcq[XZ"cN!$HrL9`cYkY)A1@E%VP'l5+hlRcbk0[mTDf2KX`YaX e[DrL-$5@ED`1G2ZkcR%$Fa@`J+rA8&Ll`)9ePk4(B5"I%%P5e4$j5bD8ZL99"C' %"%)')C`36FJTK2"&@%JPj,)HqlYBb1JU,136iJN"K@"#6L'VI1!b4*@kJP$@BGG L4Gh4a",#Z4rl8L`BHMX@BVS-#r0EJEd4Za,lHpJef*Z`P0R0f&Z`eGL*@0jl&aD -K&[`XMABGGK*f-RBLl$)*TGJT`JBa8l$6XI1`0CLRiqGLGf"[3%,JGq$I3N@rVF HHkYa$AMM[GJAB+r&3Z`KlK"pb2NXib@3!(k)1%)!K2[P15X)"&GM)IQ)!4"pq!T #!&`#-@!$&R5![%2Qlm4HJpf%I4lfaGM0@05cV9J)r6EXE1`Fl+ABZGKjf-Z`ml% ,X*GM&f,"JLZ`,m3ZaYiPU$4)UGRfhGJP@0',!Vq$[4Ul&,YDF#,f+Zc[B+r%hS0 YCr+j6bUTE-2`KTkK[Zkqc5UCjSmUeDA%`6[rejF4)l,TiR`brVA3*Hm,%a+b-,* 3m2Vmm)Grm!5eR`CPMk%khMkK4`-Vr9'@4R'j@Uf8aebD5H$HN!#%3R@q1)AA(!- ,*PeY!S[6i&1kHG`*(+DSEhGqHe)rN3YqQb2j1!RK3Fcr%)dV5eHAPR@*'(UI%,* )f"hrVb$680&UjfB4V1HqC*df[aL&i!5iCF2hhkV$Xr!4rp,Nc`R6Uq!!q&D2TeQ B,2,38L0LY!''CqYC[k2Ei6&eaif6jJX[#J$6`Cm+2mfIND*raNQlmN!cYD6qDhR iehPEAiE`T##&'[YlPQU9DGfVFiN+aG3d"p9Cr"U,Il(jejT5GAfZ@k+UQ[MRfAQ c2FC,l,`Pec"4*3dBEV-mfqdq1r+cj1VIXf&dS&`T9q*@'MGFZEpRl,pCY8HMYE" hS,I"43%j5H+E+PXTX"5C[L@5"*hjT*ck(p+-T'pPA6eAME"lC``ZA"'DN9&,k4l 3V35k$q"r4B!'5-[V2ffqh+G,[2'9A[C+-mQ4Hce6diRfMY3c"p(TcH-lB&51Ndq [$2IfR9iq[EGRV)IMSS(+Q"TA(#UI-kB[e`fL%R@hP1SR6VjaNXdRhjpH,Bp,dX- 85VFXPH*+Ve+iDrm(e&0&Ve"NH8pG[9G[aNDV88Xp2hqKFUUVaZSTqNGXbG"!4Xq 8bTZ'GimiHUU8),CXb,ASJe,U*bV2S1[LSrHS&biT)+AqS0jakVLrZJPI4G4Sb2F KI(e'Ym6dEDP[iqYl396Ar5"4rBELEIL#kKRV6eqQj!ZUEqNNA2)f3I8iREc$9HK &#UVhD8!MdYX%2iA[&-[h-AbRCT8ahLri(A`$XmE&p*Q&T$F-LPS9hLDN(V6"PDa ",eG)Z[q3!%E()H'(e&meY,&XP$Z&e&pfQ[Lcq2i3hl$H*#3qp(Pm`mH5N!#qYG" Am9@Z)&"m2m3RI@k)kQ(eJCh4UMYU+kbqY4'4VK%i6Ve5CrSqeV#8FGk"12VGk!r $pa!(5f(#AqC!2adqDY(fiN@NcG"I4`Pc2VpVrar!jb2U@EXJ1+&1r868mdCr(MR S4k1h$YmIF"MYm5$bjrM'H$b)2)"[V-H$b02iUM`H409R0XlM395pGH-p(N69qcA "id&8Me[Ym5#UrVf*(JqLYq#VmAJ3r5+q54i2SUV,b4i2BY+4,[*i%"0ZAHca)#E "i"+2"c(edNhap4h6@dleH"$6@dlcH"#l(Crdl9&rXDrMQf(jrN8BD2#J4$ed-cd HP+JAF*E(Ja,9j@b2"bAUmC[MmD"%IAQAHM`S89h1pAK3mL9mmc`HP$b+lc+2"k8 5$HCl2#K92b5pGG,69kSq3hVXj+e,e50*Vaep[26@JFY5ck9-Cp#pGb+2P0l"'5b @[X(5KcR6FbFpJDA2F1DY"&r+K$(df8Q2AjNN#RV[D)AQE[4,#T%S8lI3e4Hj5kR 4-Y@Pp!U'`BNbeHAbJ@DEZLN6hUqSELU$ifArJ1rDLi,cHEpb[HA+4PY[@*lhGPD [8FYJZIM%kNEj21URA2fAer@A"lKRZCT**#re9hiG[M8HrmVr'YpDMhrPUX[Vam+ %ZLNAaXM!MNTk+hZT6h$pU-Y)dNYeZD'-8hc8aNBh'X*EHUQ2%8iL$6Qpe)F)&i" Z[)8$[!2I"cR3qiM[#3kf@kUh-'EEijG)[ZNYE"A9X6Fb@1qmVr06Tk9I`3FhZQ& UEINqI25GlR`m&i&k#f0f5C38hr[`lHETjEkpralI(QT,F+Zh4QcFL'STp95KZVa THQd2H&#KZYbl*48Z93J,ETDL+6lHlKDAPDRV#YAPmrhp+X4ME[AhUp#dNaHdfa( [A[(2q&iS495S%lfKYjhILAMR2Z*aq`+5L`pFS2F5HJ@hi!haJ@(dkq*l0`GkGI( "AH"Sq,l,!Ei$(D-h&@k)MjjFqPcaJ5P`,RcdfG)ELZr9(+K(I1!@ICriU(AH&Kr FL$jKB)aq9[J12VJ42Dri`$,H#Kq#*Afdq(kI!p0,m,fI`rhQq`+(9jM[D3k[p,l qkUGpPIRJ%16(4mm`Ei@2IPfCQ+*pVqG!MH0$#RfYq6l2!4c$pkmFb!-9T5rh!I2 "Ym"Y69(PS&[6a8H0[G&m$h*iNrR!@VJN[Up`J"FE1!m%0jZ2AQ[i1$kDcmL2Mcj TX!iIp3b'ib2[@mhh%3j[-aqm"$b"*S0rEcFII2%GjU-Iq*hQJr[#FI"4jqmb(hF $0r"pQ!1F%4riqV$hR5)qqKlc`6RIDcl`'mc%4rr`RjL2HRl%I0bCZXEhF3l`1(` #[`(K#45(RZX2Q)qHG$J&2[UBVAapUM$ecmd(VX%&m&&,F(Cme"rk!ckd"pj6[S' 5T)R&"pHKM["4hr"@I1!([!mI[%dQlfJIZ)$QJ)qhi`haJAr`GhcJabHmEj!!qVi rD6l`$jc("liqEMjkh)@(D"pi*ra%qkM$6jX2[Jk'ii0,`8IN'b`"L9Kmp,6rMIR SdIjEmr&qi"Xqm)Lh`NHGJ+[ii)*Ip,iK`Sm[Q3m0!Nk+$rjNCh)-%Ik"DILS[kq D$hcL,[LS5HS1hcFiJ#(b$C@fK#D!$r`!Zr$4RdiHI25pIp0mF",d%(aJ)PL"MjV mP[QHj2"YlcY0'XChc%G0`hI``5HrCcii#6`,(aJRlGRDalYc&rQ'5926ij6%"ip mbRa`EMJ12ZB4r,2ji#(8*Mk`$#d#(l8"*XJhA'm2VmG(EF&Pm-(RIQ3qCK[)j#E YJdZBKS2!,i06RZ3hR$VaY-&+HR)BCD0pdVR!U!cY%rk[V(HP%TkZE,j&*4LJV21 m%La6[PFR8+BfY1iRhqQ3!"5PZ32iC,k#XZ&"Ti-V5[L-6rLRm[e$J90d*p-E&$K &8kUBJB#21m%aj6Z$'+8q&(`bld'*fq)6,UM8RB42hPjTlJ3qiA)U*d[L%kaAiT, i"&18Y"hj4R"rTEN(q%6c8MD$B!6m@`N(m%R6K4)1ia0m9H+-q)5V+"0J4i#$5V- Em%QY+XePN!$[61+91#!qi@G+I!fID"h+jPbF#6iTm3Km`Tq8G#eme"ED*Ml"%@A khdMH9jRq0e,eD[@rNHKH-J(0q!5cPI!"Rf#U-[e[*&a#L42K%ka4QVdKheR5)Uh qGaEDJM,plbcTY,U[4Ac#GC8d"(c#Se6HkL)q`@@Pq4[bRDekdYd[iT2l+'N#q%5 I8MB)kQc9+0SJ2Z($5[-hm)&2k$Ri")Z9jQl)G`ieVc4r!jr-he$5ar#*0UE`Dap B`P`1I033A!DIm#*Pc86RJ*8UEp!@D96U5QPZ"ci4UT4`(KmD0CS92Z(j5T`&Rr! pC6hIjm)IP'CNb(FH'+5N1H160e,Lb2L%IfZY'jr`HbAZL8riZC)`KSpDK,2J%`k JT2R)GciiSU6riC2l+r%&I05LkB31R)NHSD6ri411UU6ri42HSU6rbAH"-"KHJ%p U3%Nc`3IfS2rK%ae(L8[L%be!5DI&*aa5D9B)2[#-H4hbA3Jf+Fe9`3G1S,AL%`e 'LI2L%ae%5EI%*aa4L8[L!hIYh+C4F!1PH5li`(+d3Aab0bAY!Kpe3lm"2Y%[P$J M2Z'd5[UEI+-e$3JY!TpJNl*T1+1&$I!eI+*Y+G2r4ZXH9[mE$3G@T[q0d6fXrMG '2!$p%"mD-9S%2UN6C3eBBlL2N[D,$fjN1pI(L"m`4`DID!R+QN2'S%FScB("ar[ "fI%*MeALJ2L%[bPV[KX,$e(LFIJ%aj8d0(b#IFSDmmH#"8VD&$jk)Y#kmFPE+-e N`5HkQa*ra`GqfbEqX@J$b[5rX@J0b[5rXA"eCIVI@''`eIr'`L&eMiCm9A!YCIT I&Ca%QIjA*IbcqPq9"K0BrDq+qP5Qre@T&Uhq9i@ZSdcrUd,E8UEr9D'c+02rUX4 6VIih6K1BV2ih$JkM62mETlYDr@mFpDa-raY(,QAkhcLpYpAraSN6@2e[($aFQIi h(XkQ62mE,jjKpEra`L5VrifRaT6TIq24pC6TIq24UT6TIq24!*6TIq09deErQb# 1CI@r#F*1Urp08(eBr@q#kX2UIa1)9kEr64"rYIVI"(36CITIYDCH@[f['JkT62q VKQmSdrqUK3G@rkY@69MpVaTG6jRq9bd-X2TIY6LheImQ`Vf9kAm6iA[+p,q*F!p PqYp%m@1Vrde869[pEb*kRc,pEk,iK0Ar*UVQV2jA)kjMpEmDiBI9rfVJ)FVd[aV a4D[reBMh@2f[4M9YpEmD0#aPqPm01SXbr@q5F06UIj2%JDcq0dPFfHTrNm"LCIV I*1'heImQkAj@rjXNc,$khb6d(@Akhf6a2k[r6BDl+Y2r*N[RX2VIC$#DbCY1Q3r PUGI)m,#a8r0&eSpX0(SE@2U'3ph*@k+**%a%KDVl"`Elb$c1cZ2Y2-(1ARb0R6I Cq@)lAf,R+ADHDZGTGTjZjaPfVVAc6$[2X[0X1mqamk9fRQ[RHADqc-lclEc!cTI EHD'G&pQjbXjAf(Q*RCIDq8SlAfARCADqfXlAf(QjR9IBq9SlVl6c+MZ[Y[0eGUk cmaSlVlAcHMY[X20'R4QRD2eEl,c9cY[X[(fKRS1[ca[ejqI&[%PGB)%ZZdBr1rG I5+G1BX"G+P[)XT6EZCHGbaDbPLe9`a@6MlL#66"J)8(jm[PHGbm&F`R9mMIP+G6 199HAPTr8cMVT@ppq8Y6+bT16mQpH03NBV@I5Bq8CNqdX16B3XA9FTSpccS'T%Dd 6a6TlfeeId-ZiA,F#p%CIKPll'2SfFYB3,HI`iJ#3!-`NXe%!81m40qN5ekU4Bcd c8mf`B!e[$H-fRA!IC'YVU"C)YdX4Y03&l6V*83$Z@a"ea3aSG0B-SN-(%cXH1`& EMDh"EX*HM,d%1`A,hJ(6X01a-l#ef*PBV@1*RB1p&$XA1`pl'ABqGJ(fFZa#l#* X&IB+l",X8Zb9f+Z`bl"ABkr",XHZ`&k,ABPGK9f0[3jEKef$ABYGMpf!hBMG)U! AZ`flAB43E"!E`SDa6F``*bPZAcaQVT!!#f(B[NrMM8l@TEAGAJP@lE`m1'lANU" mmEU6ejkQMR$h,Iph+Fb86idDE*i)l`JB3"QDfphM1@``eKN`"GY&mECQP3(DCC& 5D)qPlCDf@YTMDBZP(CD''0TZDBHPcC!!pN,D#QQ*T4@@&PKDAfPjTG@9&PGD@fP TTC@9'U$eN!#@3eS0D6'N$C2f5pSZDEHNMC-f6GSYDE1N[C)f6pSiDDpNE!MM3KJ 63SXPVC@d90*+53XPVC1d60)U5BXNVC'dJc*+K"%LM!jKC!JYXE6#dJ*,kbXYYE6 -d[T+bbZYVV6FdP*,UbXYN!#d2Y,b5,XVEDkdYp,@5MXVEDbdVp+f5VXUEDUdjY) @56XNEC!!M$pTfN(&@aQ#m3@-,@"F!@-6')[!Z!*[0aA'%M#1J$%%6EZQ-&l!@qH "-3+-9fKDhB(fFpV1D6HRcCcfGGV6D61R[CbfFYVED9rheQI`eQ9)VXS!2D)Yh&[ c)ENq"'h`Y(V6iZfY'q'Y%m+S$'3e2BP8V,GALaf*%Grki0Lq,ibZB'3&SbVS&'0 -"H-T["eJ[,8N''-!@$-@JE%(b48I'*X!BKpDpB%a!i`AS(Z-F3+-%8#@C)3!S`- B'F#S!-E)b2JBhHl2k"K'aL!m-'U'N6'-LQ&8#Qh"Y-VbCV6MmfkdS20fM)TK4)b -2p(M0'3X$+-dp!J0aX)`GS*DCK3-)f!BrF,)&aReSXF2b,JE4Q``@S14'S`BB*` 'Bc4S#kFGR$C`fVpTqkEPR*CbfVjTpkE0QjCd@XYT+DIeR(C[fVaTlkDYQhCZfVK ThkCYQhCY@YTT@DGGQcCYfV0TbkBGQcCXfU0TLkBGQMCSfTpT[DDeQ[CRfTjTGkB eQaCV@UYT`DEYQACRfTaTEkDYQACQfTKTAkCYQGCZ@VGT@kCGQ6CPfT0T5kBGQI% XM'9K(!)M@4M&`SJA4VJ`LS84,)aHB33-ia-BmD&l4aM43#XiidBBad(E-f-!"(F CYm*S$dCk-'k&-5Z-@'$%#U09'+R#+"9'U$#HJ6%bM2aJe!FM2KM"`(J2aRS`KS2 a'icGB0`')cdBfF'i$FCX-&k$N4q-lQ#X"b-f'+h"5!e'D6"#Jp%CM-aJ9!BM-KL 0`8J-4Q%`!S24&ibmB03&Bd)BFm&i#mCD--j#Ml&Jc)q-pp%M*aMY`dJI4J8a#SL 42ScbBB32Sd!BT`'2BI3'A)C4([!B4[N``SIa'A!D'G[$'"BpIS@a2B`'J'm`USI a#Y!#16#+4ir!B2b#m"l'XM#1K6%AM',4)eJB9F#S%PVA'Bh*q!hDj)@6-)U#F4' -L@!m"+-X'%R"+!T'9M!QJ[%3M)@JCB!a%)arB1`$iaiBmm!S$%CG-1D"m3k-G@# F!f-F[2%0MS)2rM2k16(CU!5M$ZalURYfpJNEUH*SqmBHf[c'ai8a"rBp!lkHEL0 b('hI1*(94Pbiim#q*lma1hZhM8&cXRdZXadr4,pU@[Y"cm$pfHF%DFjdKFb`pkU MH5Upr4`8A5*Lk$Uid6E,1l"-95+9lNcSbD1l&hVbk!k(RMad39aEj+&,BQq4Kmk *L88H1JPULMad)H`UmS#TZiXmG#rX+I,3q6#Tb%2Aa13L$jd9&a9jk,kiZ-K$KmB P44kk0kB8HHM`Q&VNS3YN@T%(pA9kNBFZNKP&(MT0DSXmG+2-,2,3XA*VNBHZPPP &(P6&'iSmG-IX,2,33I1#)JmG0V1,2(6Kc#Rbd+PcDC'(ETkj44kkIHB9HHJ)ZUc )3pI3r#)2R88,LMadF&eHj+(lDf'4Kik3!%9&(VU1VLMbd('fZ-K$pp4Y44kkS*B 8HHKkfeINSIYNDC'(lT8VLcaddYeHj+(ElUSL$aej0aGjk0DlXmK$4ppG44kkrZi ZmY!CH-qL!Zpp1)m$k(2,,8VMVYR"bUf`E&rk5br5U1BQAcTK2PdCMSIkG-p8)c- bjAMD2(-r@##5KrlrB88HCJ--,r)`,f$S5hRL%'TA(kdXmM"[B0P,#N3b$l-)4QR 2S)C)rGPamcS2X`Xb(45qdkcjSdUeC*C2I2eV58KIXPRcCmI5+Mh3CXfIG41G+4C b[90jDUXa2G"QcCrYH@Z,@I1RVUd9AS,IiES$rAh-QMm,`MCeDYEmf65c$(ABV2Q M5P&UpaiDCXY4qmfD2lZA9EAbMelcCdCBQfDjd-H8Cee@4CN+D6C"T4YC6aG"Q+H 1VrNcJRZIiHm6*PE2Zj!![[Z`9$lQBB$'c"SC5CjbZcGpj9,cBFhaJ)",$hjBXaA S,qpI+KhhY1@4qSbSpTLE)HH)HX6T-jHHqmJ'lR1"ca04Qa4c0)3$4$5MK(NDV!M %h)l4j)RCIHbD$a(09V"V2N4jUm!j0,a('5GjTZ8KMQi%ZqC$9!SMA5Tb[qK[Fjp URbHUf5,-jC!![[@SjT6B04qLQJNa5H9[lc0jZU3kL!QrQ0NKq@*kViZe"T(N'6C rlfEFNf92jAh#c,[XUcc"rGH[mrH4&GGNKGLeE[N'YhepVpX@eIapYZIe,HjebeN Kad5Z@miU30C9ASNEF9)UYHV+)b[Ul$dRMbJID'ec#@X,LDpda)80bl-Z8jkkLBC EXE&GCmhA4G'-d'9"11d'aK4AbXT%UK6QH(Cp[4)hfkrMjV@0b,@bJGi961rDcCS lXeTCFZQ+8LPeqEh&bIX3*50jBqrUl8X5(N&#PV'5d2C5+9QQ2(YQF1[Vl-iI41T K%I8!CkJ-6JM[,j@@hZTakR+Rp`rZrkMLi5M%rq@K(LQTXbYmrEbalHXRF+IU4ee @ZTcYa9E6ec4HGj-mebQ2HNrT[F69-4,[qHCESac1JPY&JL9[U'JJYpPhNLR"68K !2ekU*mqK32Y5YrCiYEF%U01"(lX%aMBjLp4R*pNh`(30PeNVqUmqGdeMJ92P@c! kd,GbS*@jT-95Al0QfNK(khkiq@VR0pIjY+2FM'e&iecl[[c1GCd,"mD#ffkfMC) 8qiia14*5-KdCH0SC+frl@([P,BpFP8rm(FSSViUK[JdE%D*Z'4dE1CAckk[9@0, C"dHLZPUX2a%kl@SAH)KiE[AerSCfPJXm-6DN84Q"JpSQ9'jBK[Dj#ch[&,@&LAp 8lm!Bm@TYlq#`KV60MQSCpe)M[8QX)@+VMP[B86XFjF-0p8j!iDhj!%1plia#STD MhRp+aTd0+G[H4M,q6-4ZZbr22Se8X$[8l-[($EJS0[6dR@N*mTQ&,ZeH9@khca( )&Fh1,rU-*iM1(j,2lY6PJ2X!"6TZG2q(E"AUT-1&a'E9UmHM9T4&B52Dm6pXmMR GI[8iC(KVe++jcK&4)rqjDh-kU20,l1cUU&J&S'Y,NL-pCA4+Z`+kd`k[e@4fDY9 ITCT'6b33P,D5rpVVblAb49JC)0Qc[@[,$lZfDCD3!,"d,lF$i6[3TY'FiaGhFXj -3XQ0Gfhph#C5KrYfp4Uhh"3qedCcjh-AFYaqhLL9%`q%m4Q2IYS@bTEa'BrqK4E I&CmGRr(S*br4q)bcY1f$Zf4m4T!!@BP#V3bj!PPGCT!!Gq6EQ'AYYDYAEf9)bDL ddqUZaFh9l55ZGfTCZRTVIAVefGeRVkl(YA4ef)jX-A$(b'IQ*0#r`jb%dNAZjL3 X'"eF'fahbA4D(Xh#9Me-kVBjlFf+VD`Q$[cF`Gl!ejF[F'(G*BZ83BQ2#c'2#h@ eiG(bD+IGC[bdbidpq,J3@V4ZVNU*HP30AC!!YQJKMpZQIk*PZd!rIc#!hJ0EG*2 Y8dQSV9aF+Cp66Q28RiZLlr8DKK8Xakl!ASYGL9f&ABfp$PZ(AB0GLef2hB$GL0f #hBVGKQ8VRZkEHTY!R)JJp2SpXXefX*0H[dFZCqX5[pI[NI6HP6Gmqm'hD'GDPhU [RkYQ9T[$p3X1Imhf(T*pJ4CqDpeKIK!F[PGl8l[-2KI[,#Dhh+5q30IVmj9XcI3 $@9+,N!$C!i0p$0,SBqHqkdFfDP012R856DqTE#(,8QlRAREZ[C!!Y@bTfJ2T$Z3 +*'!e06p"qI,4YQ2B!QQm&(+(@&qL8E$KhlIcAIlX[F@*"-,iGaGYLdh6jh`Crfl feVCEDbrS0,)Sk)m54KiXF9009J!-V2AA&'@NFU#Tm8'bfrCP`9"edf(hM,$4L1- @-k@fY)1K6HA+kXUCCrT%bmV9-+f&MGblf1d)URhpKe1R(S#eZH81@q*0FG+SGpH J,22,P@lb92D(Umk0aYI8hpV08qLiaCe@&M8G`5DN,Y[#1CjVp1&FmK`YYf$1L9l AMaa,"SBhEPB@(CYk&aN%%9Kl0++T,NJ5Ih[VY'q29qcdY"PXVJchca@!MN[8Jdj UAiX,aPm[lY@#`2U`jKCH2&N-bDcQ2Ef)KZH63Y22P`UDh6-@V"ebbC3V$a2EN!" 4JJpNE,f'9aT0"4N[1hZa908hKc5PS6UD3jV5m)V0)C12EQMSqldCDC*NpNZ62l) M39)TIE%[QG!2@p1CR+3$9k"Yl54Mf$E&mQadYHQddm5eVKjPYEKKRShe$KiZXPB UcYTJbPQdFDbCmi#9aT0)XfR1ml`jcqBj6q)@2)Eal*P2ZFGbERDAiYJDeleM4mF H`$Ki!12K!Bb("c!HEQ-mA-CiH!$M5Gb#"c!HRYYk%XRe8iM,[!"iZUf6Cpqe2@c $AGILZUQ@GV*)3EZT-JRDJ+ZTiRHT$,R,MYT032r5@U--6QT)mV*Hf!ae(BENlA5 T(LBp#kQfNfCaXhb4Zh4lR066S+G@)j-JrHiYD6!@JTk3!+IG@G5D5Z&5d#Tj*Zf GdBNDGE5mh8QB"VhD%(5$5mSqCm$c"KD`P*ab6HeH&LBYIj'P9Dkic6@#JC(bF"Z XPh9hGJE',q*CV6qHPRHVMHYZ[@[P[TP4UN@rYV,iT54,2#SZ)5,Q[$2HbXUAPV$ B@`Yc5pab3a*hfX+(RHd`59dLZ,SaE)a2(R*S!-0"a@k-+"KG90ZR*l$LZMlCPJM qV'ZV%rEK%Dh6HREj))Y'*0f8K*1UD(&Yi8SEQ9qB`!J5l(468BbN%E$F!JUl1S+ SJeLmYPCl'EhhcXc-KrVS[56Z*$9A(NXF,3,a!VEF5aI2R%Bm33%Q+R46F`&-GM5 L@'jahG!*bAU,5Q!RLhhDU'@p[B1$clrAaM"apHITLeP@T#',af*p)XK9#+'9Ifl ,!MAF5E+YFEB`rm660dl+P3VcbCUSJ59,KYkYPRh@1`ehlEr`9XkX64S*MKr@-Y1 X@LS,C1L2*F'paJ9@5#eTD#eUXk5dV-L[2`4X6`9Kr9E@M1@l&mZJ8li(X$*QS%6 $%Gk,VE#iMf,l((`NU(2q'VE[a&Dj!XpLq`9[r$Xp)rGRK9KmJr,he-0EP0C326R 1%bVT)U`25`i@+QIe9h`XhbdM$A3q9RJG'2bH4LbShm)hU*dV,@SA"ePK9IYHcQ' )q@4PRm#E'r"bmE(dh'RXc5ip)HTfI-0q0MLCqP*I`$GF1l'+lh-F+VQS[*&kc0H DZYV@Lch$"#-'3Bm)lRJ,F8(G8eCFr3&E!J@erLUV`C+$qM[,Vd`De*,KCr[pMi* kVA1#%fqLI64i&Ejc[4i8[)EcHGVi6AbmdrPqilIJjr"GB(Ik,!G@A-A(ficLIP* 6`Ar$0pSM48Je1FDV6b&KJeh*0D5&jKP2MBmPbPNi(jrFd9[*0E5$`i5HUXC5K+l %9leqFideB%-I%,B)S5I(UcR8j*X3"CCSa-3NeB[ihXlC6UB+#4XZ#Zii$8`+I4E IaG5(e&Y)Up8bAS)FRq%`KIH6@JSpM'qUAi3PT(I9qTMiRZ6!Zq%$5eL&&VJ$5r4 VL!p-B@PkI&,EHM&kI+a$5`hL3beP$9amV"2,%[2iZ!q,bZ160pI,b10MZA8@MXF (AK+,$qaKFAKm9"M,`H0l)3I`#KmeEAZ-`X*1&RR(pcS1LmhhS'%b[SFiX*`l2M# *"GcaIB3$li!2!'@4GRaIi-#bl2LqaB&Da[F$$Lbp$J@J2X!FI'!Sq)N2hX##k[M !!TC3adFGk0%KiZ-GHA0ma,!`1Mj'V0Q&Db,##4BrahFA"`hfiJ-EE$Y,4'r-dZI ihX@"2LamImV"$Lk*h-2"-*(!mF)!kJZI`%)!h0'qTcR!Ck!c[+XGp4CP[9h0Ar# "`CBb4B9jGP1qU0E,K52J!hGXNdj8p8mM'6lUdfUe8G@2V!QXIEb['Bm51%&[FC2 jL,'E@dA&NfifhpdFU!YmVq"JPGbS10UYjRXV"pEfaFGUZq!'2M$b0[0pR)-G2K- 94YT9L+1UHcJ1[LFi[-Kmm"+`@VkBq-mGjQ0GAeB3aXGk[#mf(eJ'4Z'MYPRY&aq e4#hMidej6hcFl4lc`32fQimhVMFIY8iX2YB2&PkNIAr&!5k'MbfU`%0m2q4`RrF j,MkNqG%LL(i%[P%(pMh926[lK(%(4pXh&M'Q#4I'(0Mh$$cXG1-@MVC[($*'%bl FF@$INpqBREhli+*ZZ2#bI*ZR"Pai+AcKEE1cepkjL"XU1'G(HTYQ'HI+jjiEkHf H(c9C0fRp@$*UXSl4cmP4NhA@`Z8dqDaZ1NVVVGSb5(kf2dVRS6*HhM@h3'YUXmC i9XP$i,e&([TrlL[bX*lKX0IbR&K4I!kBmI41ZB(6hQJX2F"TmT(KA6CSpT!!"Ki DTqR(0-2fc)3Y%jFFf*@)5)hY5S5PKddP3QfACb+!k9kqemliLNFN*RfCN!$8[#m 6XLaUMHKa8N&lejahj,f)Q$96Fcb+M0p,ABV3YMFM029Q"(L[j$EkJX'*'q,@XI( 3DQLSZJK!ac$MPQ6`90fV$FMpr&bSiaq0,02EEC[RFr`HYF2[YaP"Z8rQI2+`(6P U'qQ2jR8FZXHmVFPN0rECGf@`f)*0&CYRGE`q&Sq1f)bXirGBfVGjV(YLBGHFjLm eCEEYdrIBQ$ArVrMe2CL5r&bpkRX8X*1TZ-9[q8"9Drhm&Mp!i194fqD9(ApA'4& YCeJGVrZGD@)c[SlIJfp8V3&,2[kZqKjk*YlaHaKqcqcE0VScC2%*TV0JD0!Qhq@ qaLR3"epqdH#2%1E`2C`"$'AKq4Iq'$NEaPQhISi+TP2!cY3SlSjlR(rQBJ(hk(b 3!*rHS`1!Ihk2)T)IZBFXd["rY@qBkI&kKERVHa4HSf(UH[ipGM#)f"&`Ml@[[Qc aA4P&k0fM(BPqHSmGVl,6iV['lq%%B1lk(VZF6DEmcHHHB0`bK,KVL%VMV2r@EeI @@56J(RbM+**Rhj@4UVibIc"*E2%*jZkSB+C1!14d+b$9SDpVKTEl3p14Tfelq@F dRG`ph#DUmc%Y*PXG[p"LZZja9)[TZXG4,DEl(NHdQ1)ph!YD60Ylr%U,b6hX-eT -m4j(YCLfDra5LqQkac%YjZ"&A!4D6'F1ZkG(amF5(m@lTKIpD2kF(jT1&SKqSHR N%GmCS1N8aelfV`aZY&Rj[rRSVh&2G&'i!lSIA#IG"PZ1-5rTHU@c+0(lf[$&'BT lSQ[KHUemHI`cpcL1`('QA'$FrriHlT[ZKpf,!Bb'PfE[FHH8&lUbddAp(ia!,Y* 4dFFB3GFpMM+#VRXF4I,ZHaa"mZ)pMQP9EIIiP9D9Hj!!Cj!!XhL2SmMCGSeI)QI A2BjT93F[%Vp(3Bk4HqKT#Zdjc$hd+R,CMdZX5ifmjr1i!638IBr#i'4INFJMQYa $9R&T[mI#LDdr[SGlGUTjFY&!GmVRSTYUIZ)10-f'lCG9[M0B%1@PC('jb4BXPb0 V62mNAeJj##l)8YH6JqdZQ8l,SeRBUSG*rG!+km6+hLakRf`4GkkRdD1ZlT*&bU$ %ai@Sa`AGdV@NdaEAF,Qa"amA3MNZ10b3!+$Kmh%KY[MXp$`VRlK@#Z#%Gf%R@2M !#@E#BUNR[K(kL&kLA$-LGK9hc(d+@0JD4Uh&RUT3aS[%1&ic[d9m5Vq)1b921FH ZEH-PLVNP`iXm[6QH9Z6T`h&SNBFK3*9&R[iFVhiT6hbVHiNkLH10Vp@&5$kIi6# S9'V9e8NY[X&C0@3D6@JP[L%0laZV0icJ8k8P'j3(Rm3a*@EBdVk'DkB-[5*SmhR ,H[XUSkA5H@[bqlcZQT-ICjPLh[BRXrrbR[RhNErXZlH@5YIZprF1RM`lqp4Q3Xr %MX5HK@AKBZEMMH$jcV(h18re+IB-,$1&,X"HL"f&(8fH-CDR#MX11ail!FZFQSR B'ZcTj*PNH5l#ASaP`#*,)c""4pifm'lXD[*iGF'XYKAB99LQK6-CD41@'YK-RLf @"dD`(FXXTaZ`G+%c*BJ"3#[*XmIbh)6GLi9C#Xr81&CLY4NQ6kRP!EGX5@YX!RF UX1"+Ar,dXcc81h8f!(X+pP6X308f45jj"PZHSF)YXFa"C-)4%hpRBDGJTj0RYZ@ j&(X*PL%YFl(cX-`eBi,b![*S("!I`iHZ`#l'-U0a+IC+l&ABUH4CCRQZ`5iAAL5 "5*Vf`cNJbDXE[(MYRH!&G6!02"J[j%TZ0a,2drMa5)(JjV1#kkkrPraPj"'mN6a 5%HSA5mHVU'kE9I`$`L2UMI[GAb*4iMl[2QFbrfl$Ip[Xi92LI4iiDal2IR$l[q2 C!ffl$r([1aS[q9qQr2(h14$r6VZIi1*69j)RD(Pi3M#!HZ(p)PerqYAbrqZ"pN0 acXqHR,jKG!#&EPXD0eajU02)SV@96TV&cI*&lY,YF9*2AdJa[9Cc+(Z,`Qc,Lr& ,3rS!GjG(ACC&VDNA8ma'%U`F#Y[YPa2-k%50HVP[*NYJcFha6!QSMHYZ[@Zp($i c5K%Jec8RT$kfjE"#69[dSL6HkQVCLf@LUA&Fh-aQ@"BQVCIIZ,Cr5+T8Fq6FNI* `1iZDdBlrZ*ZH#E1`Nl8l,ck1$XmrRSkrDZL&8,q68`TmQfZmN!$%m[RfelFTfTq ITX"m#40H,''rVl!Y@MSQXU'j!M(p,,N#N!#qQBlAed*&4`C8`[cMqb*L@l6hH[C FQ52Ur)LpV9-*UpG-(i0d%Z3!RHJ11#G"(X`*cd%jd9NJpi*c'1"PD#N8,lDeb(9 4j!%m%Am3[h4m-hJ6Pi0ZSV2!(3r12PJVD"0BJ'a5G!#fRb$hh&Q`pS)lbc3$e&j X'UEMJCPbb%%dd6Q!*VSGRSR2JV-AR(R+*$#RJZ@e1Q'B"$NB*VS$KNQ3!)GK`R- `6(3@KVhJA(el'9U+`S[0&88HKK2a"h&*acI$-(%j'#Bk#m2ai1b$YF)`J38B*N8 ($2X*FXqGK@%[Z,0--c$XaDCK1"kB+BFF$"1GJf'Lff'Bq#`-Hm'CTmc#m1bHX@- `6))F$"2G!F-Nb--`i6NB*MS,`ej`VVkp$#e&iFAQLL)2`iRiJlLNijYKQ,JF$"1 GKH&iF2E"@Q'B`!)-Nk)$K[d%ZHI1`V!Ah&QQ'4MfBY-`(!r-P%-1KSR1`6$4l6" -I"D'[H$-8ak!i4jCULK-p8K6AH*88CiU#&5(*+T1NDSJ8h8,9Ge598kX+XT9Km@ P(RQT4f!U5%b(4+C1Q5N[0"@NTU,B9*5EHU5IS[M6)rpd#8"&#DJJ!Kf5J6U&S)) 8e#d'GFY"18'S+!NG&R"k**`H%DFJia`5FMUPR,bB8j!!FiU#6P(5kC&ALJ*,Mm6 5*E)8CCD#d(*)DZN8@`Tb5lIJdLfjj%5ASZab@#6TN8PkK*+#9(*),1Q85r+#58% b+BSQ4GQNd-a4E1I)0h4d0bJ8@K3kQa3+E3S&GEbSMqF9mQl&Yk$jGUUq"Gfh)$F @"FHmj0JYS49%Y%iC,5ZN0DmEPqCF,6P5T+XP342VDXR43,YD-U4i9dZ#*2(+a+F )35D*,CG-H%Hp0*!!Veb+1,&T6@(S9dYSLRqe*%K#86Dqp3RR,L33-'T*IS$GY@4 *%V0-I&FKqY3X%`ihbmEQLc6&cPS5T1KC-X&5Pc)IDfFmPB609l%aP5J,N!#T,1d SQ8U8JmT8QLaHTV*N3$1G*&Z`k8c09C[1d9+H$F@9!p,Q2+eSfT!!j`#NTZ+cZ*V +NJ(A!dQk(VJ&CP-*1V%fP5S$Z1NN4iUi$AV61CV`pd##BK&NN6L9*3[(5pU1$@, *e3('ITSX&2XjfS(B6j1$B6p*&S6p("N)ENb4VGh'2-f9fjLKT5b6TC5$hR5@9Z" 0CMN!Zhjd&R6p("R)E8T4H03@Z2A$1m(@6j5"fXB8KiUe$@BE-c5"E&0ijl0R!GE 2NB9AM`l2G"1GU5QAP$dbYZDB29CpK9$VkTXIYUBk)A1m-aPQaV9M[,e40XlRk*! !9aSeYCB859%Y%cpVTZC!,e(6mLr[bfqCm#k@e&jrU83(Lr!!l@bYa(5D6$Nf-,K m6EBNkQEUqHT-jFQ8D$T*4jfQXa@*EkCLI8"YVpFNJ@bYeLE1dPUVM8NbPCSN![N k2C!!TNMVmMAUCmP8D'1+M[TXc0A*PlTVFffYpTp5!CPke!,5("%-b(4)-b"2Mfa !QL0!3kCZMF(,dX0F[93GaHJPkDR(3hT$)P%"Qh5LGY9"ef%"HXR4)dk3!1B35-I cG1JBm5cG*A-%p-Pd60JJea'1i'IU+F9Z[F6,FK4iZP36,dP11)PRk+UH([Q%0$d #*@N1XbB5G4-R,mY4lZ5PkbUFBMr3NVL6e&aj,('-`Zc3LKCh@S$R3E%(AM#R%8m !)Ch0,2J1*q,G1K+P1(cf&3r+,Le2QHjSq1RYZaieV6GdC22jErCG@m5*PPGY&)U 2hE[V44XjHMVAXYlH`F(RRmq%0(&e%jALj5DNLB1EU!DqE@*5h0U%T'ZL-Fc5Da1 9T0+*L"4l5B5e[E62RK-"(ZlDPfpJaFQJ11fb3BEY'ZF"[QILNM`X%G(mDUfeR!K 0[CT(Xha[kJe6p-Q%T+L5#@QN45BS5B%5%@QkN`KYHc1Ip53#@SRIaM"ap9FJe-4 hL%FQ48ie-[%GFT&*NGH*6)+F3'6L1e'q-8H,HQ45C'@M4(L1YLGbG(+$4*i@HTU )cPGYZi58c("3X,!CQN8M%eR38%b5V0#4##q@5MH05Z6*P8UVpZ'(jUSSThDBq*c -BH,Ep3f6)5YX*-)l&Be%RN1&NT%m%Y%(Ud(QDVF6!F)lH3!CmM5!m%i@3)Cf%N" mRJ-3AU!!U45Y$)!-13,J4HG"c8Y4+&8[6@ZPHX'j3Zh!rN5#0ZMA#9U3!*r!)[# 6)iIlAR5K3RT3hdZ6VC!!JjJIMmc@6Kla#Fm$2Z%GH%q#(0ald3@dpp,de%F@kle JV`UF5CqkYUj&(,HQfC&Y*BDcbH-T1iPVh+PS2PXTaK6AZ)1R@XAK(1,BcY(r2[A (@Lc4h#rdMr0aRbG1hd2ZPi`V[B`P"HcpNR'Vf1kap-&QPZpiP0bNmX-FRLD1R3r mZ0$6(#UE@ASNRp*D"[DGN[IVp4AZFN'cR4k*@r)P&MqFhmbQMVa6@&XqpZAH[,G r[jRD&Z,6cDc"HbAM*[`CprZckL$cQ82Iiqhe0TAb$IiDKe(YK+e$3RGp"KpE9FT h$aZaK!Gmh2YlP-2Q1eHA0h%2[4IID"phhkFiR1RMIU)FGLAr)GTUXFc(rGd`2MD [*0rM(1l0im,R2S52E5cPZeml,mccq4l8FMKX)mQ9EeqS*hq,K'dIeM+9YLlpZ-M 0(2CCAITaBH'%9cGqA&5EC`keZ[(MpYdbAamIdhD6GSZ2I3r1emFfE9eTGiLkij6 jqRMdER`,I0aGfJV5eXG,@IBaS+dhLI[#I(eFYaiI'e-5pr@jqJMYH4)I@e6+GlH fac6e%4j66E+GTP6kcSmXe)'r(QL81SlAJ4mArZK#25AcIA#K2[bi'2H,eiFI0dL EE*Vk#&qKQVEiqe%``pC(q'HZ*X$Z$R'UDXM84rJbl49P0h9mA*KNkL0mP6E*[0& i!29UkL0mm4I`X8%RqIjk(Mp'DKm0kJ+mCpF*@aq[%TEFl12k#*pUmVLq2a$'[F4 `p`dFH[Zi4l3Tk*hfVYqIbpG[ac*m$rLiJF*eQqq*hIM),eqrlmlIljZ2iRZ2MqZ [c8C0[RklKB[[pA&pYEQRHHr!pi9re"h[)AK[hcY`81rdQ)ql6(R0H`Iq4MjUJAZ `SjTjlm"REX)((`'R(jkrhkHI`XHpL101jRiUqD3+eF60qrVmrCl8Qhl-lXe@4HC qUNGepR'lamUjq`9M[4re5(f$8qCq`6F+Ym!%q9CqFqjq`HekXdrjZ$fU$h1ri)l 2iK-HT2%*(Q0`)R,5,q$lQ[%RkRb`MhZ0DSLkNqq2`0Q5YSm,kLfqlH2HIJHBGV+ 2Up,Z(YraeiL#0j9rjH0@LdYqeqjh,cEQmH16fZ6dHmEcK'F%l"jVK5AJ!h(ic(Y (hUQY8rr*iUM4#Rq2KiAh6eUp2U6,QlK(YENV03,ZISR$&"rhT,C#IFTi*29XlK' jm6&m2c4FNHeFe8-qVYHr%N#0JarJE#prMbm+qm!Vm!Rq8HAcVEJ0(cRPZi8kL&4 ph$4aPAme(JchXMMp0['-Ic-H`#DTDqcHi-(6aVHNEVckZ&YFlNIfIY5cVBpc2SE [aclZC'fiqL&r[fq)GpUY5%qqKhFGk11qqNrc&,C#m3rkHfb$0hLVcFD%XjCrI"q I-ZifK)e6JeB(Ei&2H#[6KS9h&PGQ82G+'#*IL6BZ+S1AJcXq[jQ+$K%U+epXpkr aCNVEbI*dXMeV++qRf1i9TjVq!-6GKkq[MkZ(@bYK[RbIH"rjq[ZiNm!QTBeQ`8Z iKHB0XGhh8@2+0Q)j9CaEmiEBqjk&HbPY2-XlNIF-Rkm5,&$'ef2S&UEqBVY[)*F b[PkLYp4i'G[p1Ef0jHX$a&%d(XGfGm(2e&NqVPceq6`Ipa%`5)%cZQlJ*b90pLT ,e)Cq*p&[!KpUKNGhAbX4(cEhVYr-9VNUhrK9q,&XH4YHjq1Q28#FfE&CR3l[-$J GfhX&@mFUEE[+m`S1'Cb1lAN%A&6#4[P1S`i-6XIfDQPETHeKjCXcAkreer2f#Vp q$lQIVBrkc@b4Ue4he-dr(-+Rf0irr#*aXTbXcJIqDGb0lGd%cLREb(B''mmDr)l Y$H"-5Y[CNNq`bZ"hE1m0ZJFEfa)(cl6hH#Am4QQ,@qLmE'aVm$Zfjbkp"j[Gb[F DX0$L5[e[`Qf8YYQ&(m#A0*l&pYccF@'-LGXXc$"i8lm6V85*Ji$Im(jlMhI`4SS Dj(XGA-6JI@c2RGmLMXf#jAX6ZSc&TrSEU3QPlAQTErL$a[[BRZpG54akMRbRL0F Ch0Vr-&LSE11AQ2L*`DhpGi%T5TbD1RMPI2fK"5MHAlp6R0r(p[kPhS-YGZ8E*Yc 4r##fG`IF58PMNDm@hF6`JpMH')kUT)2"ekN6c3pLHem(Pe2DJ"IHrm3KIL$i)4L Pa#APfiM@B[L"h%0d,28QidrS$JCIpcm+*e$D(*JiH*jp[dAS@1TYaZGiAiYc`IZ *XlVA32&JJkreTm+TP1PHmm!2Lkre[`kI8kClKD89fAZ-q50mFKGJlA,UfI$Df0j 2#!2Bh&MLVJ)$,&lZ[d[Da'Gph%e`"3m[[k)D%icPQi9qjZ(PD186rBV[IYl9`m[ TUPIi(Hq"eQMIqir&rG!*LB2[fATpC!mqZ$rm$lbf1,G!R"`p3Ei9UN@,Pkq(f`@ NGj%2($&iZIpCm$)JIB!ikX2HBk5`!&iXheid#3m[2kbDrRXIYdFkVF@jkQ[*`CE $8$MZBqYl`+IaIGR(E8AImI"bJIL0h8`iV$UhpbMrAAaImA%28cm@,qY6m@2"+,l h``-p[(`[R&qCRMTEqT("brTedP$J&q#Ik+mHAMi'Pe@fi9G)R0lJCAdGV89*2k3 1@1h-eTr@@RKciQK0X2AhQ',3#H@l9RU"`F[pMdQMK0m"0E)KQBHA&G*DV)Dm5hU (aFYDD3bm!lL1CQ$`X[l0dNVJ0I+pkX[cH$Ri6`K!db$IQqIamR%d+D80RAQR""q Y[dEB)abCEr!#AXj%Te&k%rPZ%kjB[0`RIX`fd2!Ep%',Pj23m*9d@RJ'HN1*jrF 2`1(9Z)rl!,JFbHXlF0a"Z*Db4@0,a31Y(V!6M&#f#QaIEE&XiL)R`&'9l8Sd8"K QimD+hjKGM03PB*9h[he`"LAq+mGedS00A138DPMC)T,$a5[X[GmRhQ#hqjUR,C* Yh2IJR-TfcC`R,,4a6iQAQ&fE9%6GH[Hq(Crb1U[DaqE0hVfMD!E+G0D9iZ[fr5k rN6LVXki8cl$hqaal-bRMlCY9ccEZafJJbVDT'b3F2kNC(qfV#1FiC2@5Z&lqr`d !"8PMEfi0D@p38%-ZE@0`!*!4H$-*KJ#3$iB!!$q)!*!$&J#3"'PMEfj038063!# eQI#%YCR`K!!!!HB!N!B"&3#3""F@!*!)JE)4!!JF[-XKL%Vqkr)IQ(qRr&[Nla6 hDYcMFCFjq"YaTmHeLN[2GdpFcRaEjcXYAk0m21qMq8VPh6[[,ARVj-h+FeLHar* XRZHi20im2E`Aj5RJ6I0HR2Y9EqIFjhU,j8l,I9eZP$XeGilF20HCZF[QV*!!Frm F0q9-c,&GMVGcP-Pa@1aj14V(GSQp1qE4f25BR@-hL'NEFkrRVTMdQ%GLYiSj-,D qXmMT%0kG+6`p!r+B3c"H,b-CF*54$%p[fY"-D$T(Emh-i#$Rk@eK'$HR8'ZQ(!T cYqY-%A+HIQQ%K@(XR2`ZdLmbcpr'-b3U-8II58AYQIfMclTCrUa,aK5GkLJ8DZY dYLC!(J4+k5cqV!ZZX3#3!`d0$&*&384045j0B@028f0`!*!4KZB*KJ#3$Mi$!!" $(J#3!aErN!4849K8G(4iG!%!VZP",E@CpXm!!!'X!!!%5`#3!md!!!*C*YQfB3# 3"M&!%3!)(1ad#')JLFI%1Rb*Jij4$SQpPB0bK,62fc8T)G'Ij216P-l"P'KkQ)V "9!65Xe)GTD5H!!J3)B2Y3fARKLIIKp0[UTHYN!"1TZXCRhC&(mcFBpDR'HL$*'B bTRkDJEjBKM3rJcd9[(l15!U(i9GF#&#aYR)HIf+0dbT$lV2bl"JXUUC$EZHE"al 2iakBaArh`'Q21'8UXp'm)bLH6D%Jj*ZT4*peCGa0ec5-ImP4+,3"j!m%ZqTYqZ6 3G)IlBUBS06Yib'K"cmeeX!8+SJ#!)!1BM"JC-!+`$L,X(*!!!I2)5Sk5@mQapmK 4)jc-'!()lfAi9c`$q#LHiJRk%3`%F23LI'9'RJd))mKJ"$&X*HX$!2R!j-"86Di hP&T,(j5qZD143lS3BL2ThP2PI'XI5AP$NipTUQ[5Y8[4mDG"DGPqH44E5H18D(G GRYhHlZ5J4h+q)$f2NA("kX4KNAR[25[cBc!alGMBre3)MJ2G"UBhKAa3RC@#L!k YLdqqiJYGlkUJ`N*eRJ92AV,"NXVII@4++M3fa6*3F@STdf5#C'1L-A!6e&"Bmk- i@SYrMNqP%#KPLKKmkB3@RNJV6mT!k,10E!"'#$la2"5TmcHT!P5IN3-mIH58Q96 #$lKPhbr8+NLf&J("!%4ND4QlQ0dA*j@UqNA-l&mPQMPd'+DhCae+d4&89pQj2k, C$*%#4#&Sih`6FaYB&mlVIM,@B(82mSImU#!"I(BSTA4f0&K[0Bhpe#"`31l*&!Q GjeQd21Fj9$,cK*Z5-6*A$6f@S"H0)mXXp68BV-T,`8&6,QpI3ZUC1dK"1cN)G&H &59X*!0YIFKAPj&eMT@k&q-$'e8kVj0K(+E'e@DqffpAjf3A41$Y%i#mMa'&E0V( @dUZSC--2ZAjm2YUCDYGEa'#3!%!*lImdGq`IE-J"rMa-*q8HPC2dkekJ#P#K3!U 6KaS80)bpFKkS&H0D+KTFM!Makqek*cDEeIVmVlaVp`MSlqK9EiHF[1p`(jN120# 90cC%kk9BRkifTk[eqXJhZ,jECVAm"V`IMITMrqNXlklhKl[p$@hPqZ48LRmK)3Y MCQPdFfP[AfeKB`#3&JQ'!4B!&3+L!GB!N!-"!!!rL!#3"aB!N!1'!!!$([q3"!2 JYCR`K,@Cp[N!N!8"mK%!N!C#Q2r`rrJ!!-0!!!!3DBZi!!!: \ No newline at end of file
diff --git a/pkg/tbtables/cfitsio/cfortran.doc b/pkg/tbtables/cfitsio/cfortran.doc
new file mode 100644
index 00000000..6c6f4b3a
--- /dev/null
+++ b/pkg/tbtables/cfitsio/cfortran.doc
@@ -0,0 +1,2051 @@
+/* cfortran.doc 4.3 */
+/* www-zeus.desy.de/~burow OR anonymous ftp@zebra.desy.de */
+/* Burkhard Burow burow@desy.de 1990 - 1998. */
+
+
+ cfortran.h : Interfacing C or C++ and FORTRAN
+
+Supports: Alpha and VAX VMS, Alpha OSF, DECstation and VAX Ultrix, IBM RS/6000,
+ Silicon Graphics, Sun, CRAY, Apollo, HP9000, LynxOS, Convex, Absoft,
+ f2c, g77, NAG f90, PowerStation Fortran with Visual C++, NEC SX-4,
+ Portland Group.
+
+C and C++ are generally equivalent as far as cfortran.h is concerned.
+Unless explicitly noted otherwise, mention of C implicitly includes C++.
+C++ compilers tested include:
+ SunOS> CC +p +w # Clean compiles.
+ IRIX> CC # Clean compiles.
+ IRIX> CC -fullwarn # Still some warnings to be overcome.
+ GNU> g++ -Wall # Compiles are clean, other than warnings for unused
+ # cfortran.h static routines.
+
+N.B.: The best documentation on interfacing C or C++ and Fortran is in
+ the chapter named something like 'Interfacing C and Fortran'
+ to be found in the user's guide of almost every Fortran compiler.
+ Understanding this information for one or more Fortran compilers
+ greatly clarifies the aims and actions of cfortran.h.
+ Such a chapter generally also addresses issues orthogonal to cfortran.h,
+ for example the order of array indices, the index of the first element,
+ as well as compiling and linking issues.
+
+
+0 Short Summary of the Syntax Required to Create the Interface
+--------------------------------------------------------------
+
+e.g. Prototyping a FORTRAN subroutine for C:
+
+/* PROTOCCALLSFSUBn is optional for C, but mandatory for C++. */
+
+ PROTOCCALLSFSUB2(SUB_NAME,sub_name,STRING,PINT)
+#define SUB_NAME(A,B) CCALLSFSUB2(SUB_NAME,sub_name,STRING,PINT, A,B)
+
+ ^ - -
+ number of arguments _____| | STRING BYTE PBYTE BYTEV(..)|
+ / | STRINGV DOUBLE PDOUBLE DOUBLEV(..)|
+ / | PSTRING FLOAT PFLOAT FLOATV(..)|
+ types of arguments ____ / | PNSTRING INT PINT INTV(..)|
+ \ | PPSTRING LOGICAL PLOGICAL LOGICALV(..)|
+ \ | PSTRINGV LONG PLONG LONGV(..)|
+ \ | ZTRINGV SHORT PSHORT SHORTV(..)|
+ | PZTRINGV ROUTINE PVOID SIMPLE |
+ - -
+
+
+e.g. Prototyping a FORTRAN function for C:
+/* PROTOCCALLSFFUNn is mandatory for both C and C++. */
+PROTOCCALLSFFUN1(INT,FUN_NAME,fun_name,STRING)
+#define FUN_NAME(A) CCALLSFFUN1(FUN_NAME,fun_name,STRING, A)
+
+e.g. calling FUN_NAME from C: {int a; a = FUN_NAME("hello");}
+
+
+e.g. Creating a FORTRAN-callable wrapper for
+ a C function returning void, with a 7 dimensional integer array argument:
+ [Not supported from C++.]
+FCALLSCSUB1(csub_name,CSUB_NAME,csub_name,INTVVVVVVV)
+
+
+e.g. Creating a FORTRAN-callable wrapper for other C functions:
+FCALLSCFUN1(STRING,cfun_name,CFUN_NAME,cfun_name,INT)
+ [ ^-- BYTE, DOUBLE, FLOAT, INT, LOGICAL, LONG, SHORT, VOID
+ are other types returned by functions. ]
+
+
+e.g. COMMON BLOCKs:
+FORTRAN: common /fcb/ v,w,x
+ character *(13) v, w(4), x(3,2)
+C:
+typedef struct { char v[13],w[4][13],x[2][3][13]; } FCB_DEF;
+#define FCB COMMON_BLOCK(FCB,fcb)
+COMMON_BLOCK_DEF(FCB_DEF,FCB);
+FCB_DEF FCB; /* Define, i.e. allocate memory, in exactly one *.c file. */
+
+e.g. accessing FCB in C: printf("%.13s",FCB.v);
+
+
+
+I Introduction
+--------------
+
+cfortran.h is an easy-to-use powerful bridge between C and FORTRAN.
+It provides a completely transparent, machine independent interface between
+C and FORTRAN routines (= subroutines and/or functions) and global data,
+i.e. structures and COMMON blocks.
+
+The complete cfortran.h package consists of 4 files: the documentation in
+cfortran.doc, the engine cfortran.h, examples in cfortest.c and
+cfortex.f/or. [cfortex.for under VMS, cfortex.f on other machines.]
+
+The cfortran.h package continues to be developed. The most recent version is
+available via www at http://www-zeus.desy.de/~burow
+or via anonymous ftp at zebra.desy.de (131.169.2.244).
+
+The examples may be run using one of the following sets of instructions:
+
+N.B. Unlike earlier versions, cfortran.h 3.0 and later versions
+ automatically uses the correct ANSI ## or pre-ANSI /**/
+ preprocessor operator as required by the C compiler.
+
+N.B. As a general rule when trying to determine how to link C and Fortran,
+ link a trivial Fortran program using the Fortran compilers verbose option,
+ in order to see how the Fortran compiler drives the linker. e.g.
+ unix> cat f.f
+ END
+ unix> f77 -v f.f
+ .. lots of info. follows ...
+
+N.B. If using a C main(), i.e. Fortran PROGRAM is not entry of the executable,
+ and if the link bombs with a complaint about
+ a missing "MAIN" (e.g. MAIN__, MAIN_, f90_main or similar),
+ then Fortran has hijacked the entry point to the executable
+ and wishes to call the rest of the executable via "MAIN".
+ This can usually be satisfied by doing e.g. 'cc -Dmain=MAIN__ ...'
+ but often kills the command line arguments in argv and argc.
+ The f77 verbose option, usually -v, may point to a solution.
+
+
+RS/6000> # Users are strongly urged to use f77 -qextname and cc -Dextname
+RS/6000> # Use -Dextname=extname if extname is a symbol used in the C code.
+RS/6000> xlf -c -qextname cfortex.f
+RS/6000> cc -c -Dextname cfortest.c
+RS/6000> xlf -o cfortest cfortest.o cfortex.o && cfortest
+
+DECFortran> #Only DECstations with DECFortran for Ultrix RISC Systems.
+DECFortran> cc -c -DDECFortran cfortest.c
+DECFortran> f77 -o cfortest cfortest.o cfortex.f && cfortest
+
+IRIX xxxxxx 5.2 02282015 IP20 mips
+MIPS> # DECstations and Silicon Graphics using the MIPS compilers.
+MIPS> cc -o cfortest cfortest.c cfortex.f -lI77 -lU77 -lF77 && cfortest
+MIPS> # Can also let f77 drive linking, e.g.
+MIPS> cc -c cfortest.c
+MIPS> f77 -o cfortest cfortest.o cfortex.f && cfortest
+
+Apollo> # Some 'C compiler 68K Rev6.8' break. [See Section II o) Notes: Apollo]
+Apollo> f77 -c cfortex.f && cc -o cfortest cfortest.c cfortex.o && cfortest
+
+VMS> define lnk$library sys$library:vaxcrtl
+VMS> cc cfortest.c
+VMS> fortran cfortex.for
+VMS> link/exec=cfortest cfortest,cfortex
+VMS> run cfortest
+
+OSF1 xxxxxx V3.0 347 alpha
+Alpha/OSF> # Probably better to let cc drive linking, e.g.
+Alpha/OSF> f77 -c cfortex.f
+Alpha/OSF> cc -o cfortest cfortest.c cfortex.o -lUfor -lfor -lFutil -lots -lm
+Alpha/OSF> cfortest
+Alpha/OSF> # Else may need 'cc -Dmain=MAIN__' to let f77 drive linking.
+
+Sun> # Some old cc(1) need a little help. [See Section II o) Notes: Sun]
+Sun> f77 -o cfortest cfortest.c cfortex.f -lc -lm && cfortest
+Sun> # Some older f77 may require 'cc -Dmain=MAIN_'.
+
+CRAY> cft77 cfortex.f
+CRAY> cc -c cfortest.c
+CRAY> segldr -o cfortest.e cfortest.o cfortex.o
+CRAY> ./cfortest.e
+
+NEC> cc -c -Xa cfortest.c
+NEC> f77 -o cfortest cfortest.o cfortex.f && cfortest
+
+VAX/Ultrix/cc> # For cc on VAX Ultrix only, do the following once to cfortran.h.
+VAX/Ultrix/cc> mv cfortran.h cftmp.h && grep -v "^#pragma" <cftmp.h >cfortran.h
+
+VAX/Ultrix/f77> # In the following, 'CC' is either 'cc' or 'gcc -ansi'. NOT'vcc'
+VAX/Ultrix/f77> CC -c -Dmain=MAIN_ cfortest.c
+VAX/Ultrix/f77> f77 -o cfortest cfortex.f cfortest.o && cfortest
+
+LynxOS> # In the following, 'CC' is either 'cc' or 'gcc -ansi'.
+LynxOS> # Unfortunately cc is easily overwhelmed by cfortran.h,
+LynxOS> # and won't compile some of the cfortest.c demos.
+LynxOS> f2c -R cfortex.f
+LynxOS> CC -Dlynx -o cfortest cfortest.c cfortex.c -lf2c && cfortest
+
+HP9000> # Tested with HP-UX 7.05 B 9000/380 and with A.08.07 A 9000/730
+HP9000> # CC may be either 'c89 -Aa' or 'cc -Aa'
+HP9000> # Depending on the compiler version, you may need to include the
+HP9000> # option '-tp,/lib/cpp' or worse, you'll have to stick to the K&R C.
+HP9000> # [See Section II o) Notes: HP9000]
+HP9000> # Users are strongly urged to use f77 +ppu and cc -Dextname
+HP9000> # Use -Dextname=extname if extname is a symbol used in the C code.
+HP9000> CC -Dextname -c cfortest.c
+HP9000> f77 +ppu cfortex.f -o cfortest cfortest.o && cfortest
+HP9000> # Older f77 may need
+HP9000> f77 -c cfortex.f
+HP9000> CC -o cfortest cfortest.c cfortex.o -lI77 -lF77 && cfortest
+
+HP0000> # If old-style f77 +800 compiled objects are required:
+HP9000> # #define hpuxFortran800
+HP9000> cc -c -Aa -DhpuxFortran800 cfortest.c
+HP9000> f77 +800 -o cfortest cfortest.o cfortex.f
+
+f2c> # In the following, 'CC' is any C compiler.
+f2c> f2c -R cfortex.f
+f2c> CC -o cfortest -Df2cFortran cfortest.c cfortex.c -lf2c && cfortest
+
+Portland Group $ # Presumably other C compilers also work.
+Portland Group $ pgcc -DpgiFortran -c cfortest.c
+Portland Group $ pgf77 -o cfortest cfortex.f cfortest.o && cfortest
+
+NAGf90> # cfortex.f is distributed with Fortran 77 style comments.
+NAGf90> # To convert to f90 style comments do the following once to cfortex.f:
+NAGf90> mv cfortex.f cf_temp.f && sed 's/^C/\!/g' cf_temp.f > cfortex.f
+NAGf90> # In the following, 'CC' is any C compiler.
+NAGf90> CC -c -DNAGf90Fortran cfortest.c
+NAGf90> f90 -o cfortest cfortest.o cfortex.f && cfortest
+
+PC> # On a PC with PowerStation Fortran and Visual_C++
+PC> cl /c cftest.c
+PC> fl32 cftest.obj cftex.for
+
+GNU> # GNU Fortran
+GNU> # See Section VI caveat on using 'gcc -traditional'.
+GNU> gcc -ansi -Wall -O -c -Df2cFortran cfortest.c
+GNU> g77 -ff2c -o cfortest cfortest.o cfortex.f && cfortest
+
+AbsoftUNIX> # Absoft Fortran for all UNIX based operating systems.
+AbsoftUNIX> # e.g. Linux or Next on Intel or Motorola68000.
+AbsoftUNIX> # Absoft f77 -k allows Fortran routines to be safely called from C.
+AbsoftUNIX> gcc -ansi -Wall -O -c -DAbsoftUNIXFortran cfortest.c
+AbsoftUNIX> f77 -k -o cfortest cfortest.o cfortex.f && cfortest
+
+AbsoftPro> # Absoft Pro Fortran for MacOS
+AbsoftPro> # Use #define AbsoftProFortran
+
+CLIPPER> # INTERGRAPH CLIX using CLIPPER C and Fortran compilers.
+CLIPPER> # N.B. - User, not cfortran.h, is responsible for
+CLIPPER> # f77initio() and f77uninitio() if required.
+CLIPPER> # - LOGICAL values are not mentioned in CLIPPER doc.s,
+CLIPPER> # so they may not yet be correct in cfortran.h.
+CLIPPER> # - K&R mode (-knr or Ac=knr) breaks FLOAT functions
+CLIPPER> # (see CLIPPER doc.s) and cfortran.h does not fix it up.
+CLIPPER> # [cfortran.h ok for old sun C which made the same mistake.]
+CLIPPER> acc cfortest.c -c -DCLIPPERFortran
+CLIPPER> af77 cfortex.f cfortest.o -o cfortest
+
+
+By changing the SELECTion ifdef of cfortest.c and recompiling one can try out
+a few dozen different few-line examples.
+
+
+
+The benefits of using cfortran.h include:
+1. Machine/OS/compiler independent mixing of C and FORTRAN.
+
+2. Identical (within syntax) calls across languages, e.g.
+C FORTRAN
+ CALL HBOOK1(1,'pT spectrum of pi+',100,0.,5.,0.)
+/* C*/
+ HBOOK1(1,"pT spectrum of pi+",100,0.,5.,0.);
+
+3. Each routine need only be set up once in its lifetime. e.g.
+/* Setting up a FORTRAN routine to be called by C.
+ ID,...,VMX are merely the names of arguments.
+ These tags must be unique w.r.t. each other but are otherwise arbitrary. */
+PROTOCCALLSFSUB6(HBOOK1,hbook1,INT,STRING,INT,FLOAT,FLOAT,FLOAT)
+#define HBOOK1(ID,CHTITLE,NX,XMI,XMA,VMX) \
+ CCALLSFSUB6(HBOOK1,hbook1,INT,STRING,INT,FLOAT,FLOAT,FLOAT, \
+ ID,CHTITLE,NX,XMI,XMA,VMX)
+
+4. Source code is NOT required for the C routines exported to FORTRAN, nor for
+ the FORTRAN routines imported to C. In fact, routines are most easily
+ prototyped using the information in the routines' documentation.
+
+5. Routines, and the code calling them, can be coded naturally in the language
+ of choice. C routines may be coded with the natural assumption of being
+ called only by C code. cfortran.h does all the required work for FORTRAN
+ code to call C routines. Similarly it also does all the work required for C
+ to call FORTRAN routines. Therefore:
+ - C programmers need not embed FORTRAN argument passing mechanisms into
+ their code.
+ - FORTRAN code need not be converted into C code. i.e. The honed and
+ time-honored FORTRAN routines are called by C.
+
+6. cfortran.h is a single ~1700 line C include file; portable to most
+ remaining, if not all, platforms.
+
+7. STRINGS and VECTORS of STRINGS along with the usual simple arguments to
+ routines are supported as are functions returning STRINGS or numbers. Arrays
+ of pointers to strings and values of structures as C arguments, will soon be
+ implemented. After learning the machinery of cfortran.h, users can expand
+ it to create custom types of arguments. [This requires no modification to
+ cfortran.h, all the preprocessor directives required to implement the
+ custom types can be defined outside cfortran.h]
+
+8. cfortran.h requires each routine to be exported to be explicitly set up.
+ While is usually only be done once in a header file it would be best if
+ applications were required to do no work at all in order to cross languages.
+ cfortran.h's simple syntax could be a convenient back-end for a program
+ which would export FORTRAN or C routines directly from the source code.
+
+
+ -----
+
+Example 1 - cfortran.h has been used to make the C header file hbook.h,
+ which then gives any C programmer, e.g. example.c, full and
+ completely transparent access to CERN's HBOOK library of routines.
+ Each HBOOK routine required about 3 lines of simple code in
+ hbook.h. The example also demonstrates how FORTRAN common blocks
+ are defined and used.
+
+/* hbook.h */
+#include "cfortran.h"
+ :
+PROTOCCALLSFSUB6(HBOOK1,hbook1,INT,STRING,INT,FLOAT,FLOAT,FLOAT)
+#define HBOOK1(ID,CHTITLE,NX,XMI,XMA,VMX) \
+ CCALLSFSUB6(HBOOK1,hbook1,INT,STRING,INT,FLOAT,FLOAT,FLOAT, \
+ ID,CHTITLE,NX,XMI,XMA,VMX)
+ :
+/* end hbook.h */
+
+/* example.c */
+#include "hbook.h"
+ :
+typedef struct {
+ int lines;
+ int status[SIZE];
+ float p[SIZE]; /* momentum */
+} FAKE_DEF;
+#define FAKE COMMON_BLOCK(FAKE,fake)
+COMMON_BLOCK_DEF(FAKE_DEF,FAKE);
+ :
+main ()
+{
+ :
+ HBOOK1(1,"pT spectrum of pi+",100,0.,5.,0.);
+/* c.f. the call in FORTRAN:
+ CALL HBOOK1(1,'pT spectrum of pi+',100,0.,5.,0.)
+*/
+ :
+ FAKE.p[7]=1.0;
+ :
+}
+
+N.B. i) The routine is language independent.
+ ii) hbook.h is machine independent.
+ iii) Applications using routines via cfortran.h are machine independent.
+
+ -----
+
+Example 2 - Many VMS System calls are most easily called from FORTRAN, but
+ cfortran.h now gives that ease in C.
+
+#include "cfortran.h"
+
+PROTOCCALLSFSUB3(LIB$SPAWN,lib$spawn,STRING,STRING,STRING)
+#define LIB$SPAWN(command,input_file,output_file) \
+ CCALLSFSUB3(LIB$SPAWN,lib$spawn,STRING,STRING,STRING, \
+ command,input_file,output_file)
+
+main ()
+{
+LIB$SPAWN("set term/width=132","","");
+}
+
+Obviously the cfortran.h command above could be put into a header file along
+with the description of the other system calls, but as this example shows, it's
+not much hassle to set up cfortran.h for even a single call.
+
+ -----
+
+Example 3 - cfortran.h and the source cstring.c create the cstring.obj library
+ which gives FORTRAN access to all the functions in C's system
+ library described by the system's C header file string.h.
+
+C EXAMPLE.FOR
+ PROGRAM EXAMPLE
+ DIMENSION I(20), J(30)
+ :
+ CALL MEMCPY(I,J,7)
+ :
+ END
+
+/* cstring.c */
+#include <string.h> /* string.h prototypes memcpy() */
+#include "cfortran.h"
+
+ :
+FCALLSCSUB3(memcpy,MEMCPY,memcpy,PVOID,PVOID,INT)
+ :
+
+
+The simplicity exhibited in the above example exists for many but not all
+machines. Note 4. of Section II ii) details the limitations and describes tools
+which try to maintain the best possible interface when FORTRAN calls C
+routines.
+
+ -----
+
+
+II Using cfortran.h
+-------------------
+
+The user is asked to look at the source files cfortest.c and cfortex.f
+for clarification by example.
+
+o) Notes:
+
+o Specifying the Fortran compiler
+ cfortran.h generates interfaces for the default Fortran compiler. The default
+can be overridden by defining,
+ . in the code, e.g.: #define NAGf90Fortran
+ OR . in the compile directive, e.g.: unix> cc -DNAGf90Fortran
+one of the following before including cfortran.h:
+ NAGf90Fortran f2cFortran hpuxFortran apolloFortran sunFortran
+ IBMR2Fortran CRAYFortran mipsFortran DECFortran vmsFortran
+ CONVEXFortran PowerStationFortran AbsoftUNIXFortran
+ SXFortran pgiFortran AbsoftProFortran
+This also allows crosscompilation.
+If wanted, NAGf90Fortran, f2cFortran, DECFortran, AbsoftUNIXFortran,
+AbsoftProFortran and pgiFortran must be requested by the user.
+
+o /**/
+ cfortran.h (ab)uses the comment kludge /**/ when the ANSI C preprocessor
+catenation operator ## doesn't exist. In at least MIPS C, this kludge is
+sensitive to blanks surrounding arguments to macros.
+ Therefore, for applications using non-ANSI C compilers, the argtype_i,
+routine_name, routine_type and common_block_name arguments to the
+PROTOCCALLSFFUNn, CCALLSFSUB/FUNn, FCALLSCSUB/FUNn and COMMON_BLOCK macros
+--- MUST NOT --- be followed by any white space characters such as
+blanks, tabs or newlines.
+
+o LOGICAL
+ FORTRAN LOGICAL values of .TRUE. and .FALSE. do not agree with the C
+representation of TRUE and FALSE on all machines. cfortran.h does the
+conversion for LOGICAL and PLOGICAL arguments and for functions returning
+LOGICAL. Users must convert arrays of LOGICALs from C to FORTRAN with the
+C2FLOGICALV(array_name, elements_in_array); macro. Similarly, arrays of LOGICAL
+values may be converted from the FORTRAN into C representation by using
+F2CLOGICALV(array_name, elements_in_array);
+
+ When C passes or returns LOGICAL values to FORTRAN, by default cfortran.h
+only makes the minimal changes required to the value. [e.g. Set/Unset the
+single relevant bit or do nothing for FORTRAN compilers which use 0 as FALSE
+and treat all other values as TRUE.] Therefore cfortran.h will pass LOGICALs
+to FORTRAN which do not have an identical representation to .TRUE. or .FALSE.
+This is fine except for abuses of FORTRAN/77 in the style of:
+ logical l
+ if (l .eq. .TRUE.) ! (1)
+instead of the correct:
+ if (l .eqv. .TRUE.) ! (2)
+or:
+ if (l) ! (3)
+For FORTRAN code which treats LOGICALs from C in the method of (1),
+LOGICAL_STRICT must be defined before including cfortran.h, either in the
+code, "#define LOGICAL_STRICT", or compile with "cc -DLOGICAL_STRICT".
+There is no reason to use LOGICAL_STRICT for FORTRAN code which does not do (1).
+At least the IBM's xlf and the Apollo's f77 do not even allow code along the
+lines of (1).
+
+ DECstations' DECFortran and MIPS FORTRAN compilers use different internal
+representations for LOGICAL values. [Both compilers are usually called f77,
+although when both are installed on a single machine the MIPS' one is usually
+renamed. (e.g. f772.1 for version 2.10.)] cc doesn't know which FORTRAN
+compiler is present, so cfortran.h assumes MIPS f77. To use cc with DECFortran
+define the preprocessor constant 'DECFortran'.
+e.g. i) cc -DDECFortran -c the_code.c
+ or ii) #define DECFortran /* in the C code or add to cfortran.h. */
+
+ MIPS f77 [SGI and DECstations], f2c, and f77 on VAX Ultrix treat
+.eqv./.neqv. as .eq./.ne.. Therefore, for these compilers, LOGICAL_STRICT is
+defined by default in cfortran.h. [The Sun and HP compilers have not been
+tested, so they may also require LOGICAL_STRICT as the default.]
+
+o SHORT and BYTE
+ They are irrelevant for the CRAY where FORTRAN has no equivalent to C's short.
+Similarly BYTE is irrelevant for f2c and for VAX Ultrix f77 and fort. The
+author has tested SHORT and BYTE with a modified cfortest.c/cfortex.f on all
+machines supported except for the HP9000 and the Sun.
+
+ BYTE is a signed 8-bit quantity, i.e. values are -128 to 127, on all machines
+except for the SGI [at least for MIPS Computer Systems 2.0.] On the SGI it is
+an unsigned 8-bit quantity, i.e. values are 0 to 255, although the SGI 'FORTRAN
+77 Programmers Guide' claims BYTE is signed. Perhaps MIPS 2.0 is dated, since
+the DECstations using MIPS 2.10 f77 have a signed BYTE.
+
+ To minimize the difficulties of signed and unsigned BYTE, cfortran.h creates
+the type 'INTEGER_BYTE' to agree with FORTRAN's BYTE. Users may define
+SIGNED_BYTE or UNSIGNED_BYTE, before including cfortran.h, to specify FORTRAN's
+BYTE. If neither is defined, cfortran.h assumes SIGNED_BYTE.
+
+o CRAY
+ The type DOUBLE in cfortran.h corresponds to FORTRAN's DOUBLE PRECISION.
+ The type FLOAT in cfortran.h corresponds to FORTRAN's REAL.
+
+On a classic CRAY [i.e. all models except for the t3e]:
+( 64 bit) C float == C double == Fortran REAL
+(128 bit) C long double == Fortran DOUBLE PRECISION
+Therefore when moving a mixed C and FORTRAN app. to/from a classic CRAY,
+either the C code will have to change,
+or the FORTRAN code and cfortran.h declarations will have to change.
+DOUBLE_PRECISION is a cfortran.h macro which provides the former option,
+i.e. the C code is automatically changed.
+DOUBLE_PRECISION is 'long double' on classic CRAY and 'double' elsewhere.
+DOUBLE_PRECISION thus corresponds to FORTRAN's DOUBLE PRECISION
+on all machines, including classic CRAY.
+
+On a classic CRAY with the fortran compiler flag '-dp':
+Fortran DOUBLE PRECISION thus is also the faster 64bit type.
+(This switch is often used since the application is usually satisfied by
+ 64 bit precision and the application needs the speed.)
+DOUBLE_PRECISION is thus not required in this case,
+since the classic CRAY behaves like all other machines.
+If DOUBLE_PRECISION is used nonetheless, then on the classic CRAY
+the default cfortran.h behavior must be overridden,
+for example by the C compiler option '-DDOUBLE_PRECISION=double'.
+
+On a CRAY t3e:
+(32 bit) C float == Fortran Unavailable
+(64 bit) C double == C long double == Fortran REAL == Fortran DOUBLE PRECISION
+Notes:
+- (32 bit) is available as Fortran REAL*4 and
+ (64 bit) is available as Fortran REAL*8.
+ Since cfortran.h is all about more portability, not about less portability,
+ the use of the nonstandard REAL*4 and REAL*8 is strongly discouraged.
+- Fortran DOUBLE PRECISION is folded to REAL with the following warning:
+ 'DOUBLE PRECISION is not supported on this platform. REAL will be used.'
+ Similarly, Fortran REAL*16 is mapped to REAL*8 with a warning.
+This behavior differs from that of other machines, including the classic CRAY.
+FORTRAN_REAL is thus introduced for the t3e,
+just as DOUBLE_PRECISION is introduced for the classic CRAY.
+FORTRAN_REAL is 'double' on t3e and 'float' elsewhere.
+FORTRAN_REAL thus corresponds to FORTRAN's REAL on all machines, including t3e.
+
+
+o f2c
+ f2c, by default promotes REAL functions to double. cfortran.h does not (yet)
+support this, so the f2c -R option must be used to turn this promotion off.
+
+o f2c
+[Thanks to Dario Autiero for pointing out the following.]
+f2c has a strange feature in that either one or two underscores are appended
+to a Fortran name of a routine or common block,
+depending on whether or not the original name contains an underscore.
+
+ S.I. Feldman et al., "A fortran to C converter",
+ Computing Science Technical Report No. 149.
+
+ page 2, chapter 2: INTERLANGUAGE conventions
+ ...........
+ To avoid conflict with the names of library routines and with names that
+ f2c generates,
+ Fortran names may have one or two underscores appended. Fortran names are
+ forced to lower case (unless the -U option described in Appendix B is in
+ effect); external names, i.e. the names of fortran procedures and common
+ blocks, have a single underscore appended if they do not contain any
+ underscore and have a pair of underscores appended if they do contain
+ underscores. Thus fortran subroutines names ABC, A_B_C and A_B_C_ result
+ in C functions named abc_, a_b_c__ and a_b_c___.
+ ...........
+
+cfortran.h is unable to change the naming convention on a name by name basis.
+Fortran routine and common block names which do not contain an underscore
+are unaffected by this feature.
+Names which do contain an underscore may use the following work-around:
+
+/* First 2 lines are a completely standard cfortran.h interface
+ to the Fortran routine E_ASY . */
+ PROTOCCALLSFSUB2(E_ASY,e_asy, PINT, INT)
+#define E_ASY(A,B) CCALLSFSUB2(E_ASY,e_asy, PINT, INT, A, B)
+#ifdef f2cFortran
+#define e_asy_ e_asy__
+#endif
+/* Last three lines are a work-around for the strange f2c naming feature. */
+
+o NAG f90
+ The Fortran 77 subset of Fortran 90 is supported. Extending cfortran.h to
+interface C with all of Fortran 90 has not yet been examined.
+ The NAG f90 library hijacks the main() of any program and starts the user's
+program with a call to: void f90_main(void);
+While this in itself is only a minor hassle, a major problem arises because
+NAG f90 provides no mechanism to access command line arguments.
+ At least version 'NAGWare f90 compiler Version 1.1(334)' appended _CB to
+common block names instead of the usual _. To fix, add this to cfortran.h:
+#ifdef old_NAG_f90_CB_COMMON
+#define COMMON_BLOCK CFC_ /* for all other Fortran compilers */
+#else
+#define COMMON_BLOCK(UN,LN) _(LN,_CB)
+#endif
+
+o RS/6000
+ Using "xlf -qextname ...", which appends an underscore, '_', to all FORTRAN
+external references, requires "cc -Dextname ..." so that cfortran.h also
+generates these underscores.
+Use -Dextname=extname if extname is a symbol used in the C code.
+The use of "xlf -qextname" is STRONGLY ENCOURAGED, since it allows for
+transparent naming schemes when mixing C and Fortran.
+
+o HP9000
+ Using "f77 +ppu ...", which appends an underscore, '_', to all FORTRAN
+external references, requires "cc -Dextname ..." so that cfortran.h also
+generates these underscores.
+Use -Dextname=extname if extname is a symbol used in the C code.
+The use of "f77 +ppu" is STRONGLY ENCOURAGED, since it allows for
+transparent naming schemes when mixing C and Fortran.
+
+ At least one release of the HP /lib/cpp.ansi preprocessor is broken and will
+go into an infinite loop when trying to process cfortran.h with the
+## catenation operator. The K&R version of cfortran.h must then be used and the
+K&R preprocessor must be specified. e.g.
+ HP9000> cc -Aa -tp,/lib/cpp -c source.c
+The same problem with a similar solution exists on the Apollo.
+An irrelevant error message '0: extraneous name /usr/include' will appear for
+each source file due to another HP bug, and can be safely ignored.
+e.g. 'cc -v -c -Aa -tp,/lib/cpp cfortest.c' will show that the driver passes
+'-I /usr/include' instead of '-I/usr/include' to /lib/cpp
+
+On some machines the above error causes compilation to stop; one must then use
+K&R C, as with old HP compilers which don't support function prototyping.
+cfortran.h has to be informed that K&R C is to being used, e.g.
+HP9000> cc -D__CF__KnR -c source.c
+
+o AbsoftUNIXFortran
+By default, cfortran.h follows the default AbsoftUNIX/ProFortran and prepends _C
+to each COMMON BLOCK name. To override the cfortran.h behavior
+#define COMMON_BLOCK(UN,LN) before #including cfortran.h.
+[Search for COMMON_BLOCK in cfortran.h for examples.]
+
+o Apollo
+On at least one release, 'C compiler 68K Rev6.8(168)', the default C
+preprocessor, from cc -A xansi or cc -A ansi, enters an infinite loop when
+using cfortran.h. This Apollo bug can be circumvented by using:
+ . cc -DANSI_C_preprocessor=0 to force use of /**/, instead of '##'.
+ AND . The pre-ANSI preprocessor, i.e. use cc -Yp,/usr/lib
+The same problem with a similar solution exists on the HP.
+
+o Sun
+Old versions of cc(1), say <~1986, may require help for cfortran.h applications:
+ . #pragma may not be understood, hence cfortran.h and cfortest.c may require
+ sun> mv cfortran.h cftmp.h && grep -v "^#pragma" <cftmp.h >cfortran.h
+ sun> mv cfortest.c cftmp.c && grep -v "^#pragma" <cftmp.c >cfortest.c
+ . Old copies of math.h may not include the following from a newer math.h.
+ [For an ancient math.h on a 386 or sparc, get similar from a new math.h.]
+ #ifdef mc68000 /* 5 lines Copyright (c) 1988 by Sun Microsystems, Inc. */
+ #define FLOATFUNCTIONTYPE int
+ #define RETURNFLOAT(x) return (*(int *)(&(x)))
+ #define ASSIGNFLOAT(x,y) *(int *)(&x) = y
+ #endif
+
+o CRAY, Sun, Apollo [pre 6.8 cc], VAX Ultrix and HP9000
+ Only FORTRAN routines with less than 15 arguments can be prototyped for C,
+since these compilers don't allow more than 31 arguments to a C macro. This can
+be overcome, [see Section IV], with access to any C compiler without this
+limitation, e.g. gcc, on ANY machine.
+
+o VAX Ultrix
+ vcc (1) with f77 is not supported. Although:
+VAXUltrix> f77 -c cfortex.f
+VAXUltrix> vcc -o cfortest cfortest.c cfortex.o -lI77 -lU77 -lF77 && cfortest
+will link and run. However, the FORTRAN standard I/O is NOT merged with the
+stdin and stdout of C, and instead uses the files fort.6 and fort.5. For vcc,
+f77 can't drive the linking, as for gcc and cc, since vcc objects must be
+linked using lk (1). f77 -v doesn't tell much, and without VAX Ultrix manuals,
+the author can only wait for the info. required.
+
+ fort (1) is not supported. Without VAX Ultrix manuals the author cannot
+convince vcc/gcc/cc and fort to generate names of routines and COMMON blocks
+that match at the linker, lk (1). i.e. vcc/gcc/cc prepend a single underscore
+to external references, e.g. NAME becomes _NAME, while fort does not modify the
+references. So ... either fort has prepend an underscore to external
+references, or vcc/gcc/cc have to generate unmodified names. man 1 fort
+mentions JBL, is JBL the only way?
+
+o VAX VMS C
+ The compiler 'easily' exhausts its table space and generates:
+%CC-F-BUGCHECK, Compiler bug check during parser phase .
+ Submit an SPR with a problem description.
+ At line number 777 in DISK:[DIR]FILE.C;1.
+where the line given, '777', includes a call across C and FORTRAN via
+cfortran.h, usually with >7 arguments and/or very long argument expressions.
+This SPR can be staved off, with the simple modification to cfortran.h, such
+that the relevant CCALLSFSUBn (or CCALLSFFUNn or FCALLSCFUNn) is not
+cascaded up to CCALLSFSUB14, and instead has its own copy of the contents of
+CCALLSFSUB14. [If these instructions are not obvious after examining cfortran.h
+please contact the author.]
+[Thanks go to Mark Kyprianou (kyp@stsci.edu) for this solution.]
+
+o Mips compilers
+ e.g. DECstations and SGI, require applications with a C main() and calls to
+GETARG(3F), i.e. FORTRAN routines returning the command line arguments, to use
+two macros as shown:
+ :
+CF_DECLARE_GETARG; /* This must be external to all routines. */
+ :
+main(int argc, char *argv[])
+{
+ :
+CF_SET_GETARG(argc,argv); /* This must precede any calls to GETARG(3F). */
+ :
+}
+The macros are null and benign on all other systems. Sun's GETARG(3F) also
+doesn't work with a generic C main() and perhaps a workaround similar to the
+Mips' one exists.
+
+o Alpha/OSF
+Using the DEC Fortran and the DEC C compilers of DEC OSF/1 [RT] V1.2 (Rev. 10),
+Fortran, when called from C, has occasional trouble using a routine received as
+a dummy argument.
+
+e.g. In the following the Fortran routine 'e' will crash when it tries to use
+ the C routine 'c' or the Fortran routine 'f'.
+ The example works on other systems.
+
+C FORTRAN /* C */
+ integer function f() #include <stdio.h>
+ f = 2 int f_();
+ return int e_(int (*u)());
+ end
+ int c(){ return 1;}
+ integer function e(u) int d (int (*u)()) { return u();}
+ integer u
+ external u main()
+ e=u() { /* Calls to d work. */
+ return printf("d (c ) returns %d.\n",d (c ));
+ end printf("d (f_) returns %d.\n",d (f_));
+ /* Calls to e_ crash. */
+ printf("e_(c ) returns %d.\n",e_(c ));
+ printf("e_(f_) returns %d.\n",e_(f_));
+ }
+
+Solutions to the problem are welcomed!
+A kludge which allows the above example to work correctly, requires an extra
+argument to be given when calling the dummy argument function.
+i.e. Replacing 'e=u()' by 'e=u(1)' allows the above example to work.
+
+
+o The FORTRAN routines are called using macro expansions, therefore the usual
+caveats for expressions in arguments apply. The expressions to the routines may
+be evaluated more than once, leading to lower performance and in the worst case
+bizarre bugs.
+
+o For those who wish to use cfortran.h in large applications. [See Section IV.]
+This release is intended to make it easy to get applications up and running.
+This implies that applications are not as efficient as they could be:
+- The current mechanism is inefficient if a single header file is used to
+ describe a large library of FORTRAN functions. Code for a static wrapper fn.
+ is generated in each piece of C source code for each FORTRAN function
+ specified with the CCALLSFFUNn statement, irrespective of whether or not the
+ function is ever called.
+- Code for several static utility routines internal to cfortran.h is placed
+ into any source code which #includes cfortran.h. These routines should
+ probably be in a library.
+
+
+i) Calling FORTRAN routines from C:
+ --------------------------------
+
+The FORTRAN routines are defined by one of the following two instructions:
+
+for a SUBROUTINE:
+/* PROTOCCALLSFSUBn is optional for C, but mandatory for C++. */
+PROTOCCALLSFSUBn(ROUTINE_NAME,routine_name,argtype_1,...,argtype_n)
+#define Routine_name(argname_1,..,argname_n) \
+CCALLSFSUBn(ROUTINE_NAME,routine_name,argtype_1,...,argtype_n, \
+ argname_1,..,argname_n)
+
+for a FUNCTION:
+PROTOCCALLSFFUNn(routine_type,ROUTINE_NAME,routine_name,argtype_1,...,argtype_n)
+#define Routine_name(argname_1,..,argname_n) \
+CCALLSFFUNn(ROUTINE_NAME,routine_name,argtype_1,...,argtype_n, \
+ argname_1,..,argname_n)
+
+Where:
+'n' = 0->14 [SUBROUTINE's ->27] (easily expanded in cfortran.h to > 14 [27]) is
+ the number of arguments to the routine.
+Routine_name = C name of the routine (IN UPPER CASE LETTERS).[see 2.below]
+ROUTINE_NAME = FORTRAN name of the routine (IN UPPER CASE LETTERS).
+routine_name = FORTRAN name of the routine (IN lower case LETTERS).
+routine_type = the type of argument returned by FORTRAN functions.
+ = BYTE, DOUBLE, FLOAT, INT, LOGICAL, LONG, SHORT, STRING, VOID.
+ [Instead of VOID one would usually use CCALLSFSUBn.
+ VOID forces a wrapper function to be used.]
+argtype_i = the type of argument passed to the FORTRAN routine and must be
+ consistent in the definition and prototyping of the routine s.a.
+ = BYTE, DOUBLE, FLOAT, INT, LOGICAL, LONG, SHORT, STRING.
+ For vectors, i.e. 1 dim. arrays use
+ = BYTEV, DOUBLEV, FLOATV, INTV, LOGICALV, LONGV, SHORTV,
+ STRINGV, ZTRINGV.
+ For vectors of vectors, i.e. 2 dim. arrays use
+ = BYTEVV, DOUBLEVV, FLOATVV, INTVV, LOGICALVV, LONGVV, SHORTVV.
+ For n-dim. arrays, 1<=n<=7 [7 is the maximum in Fortran 77],
+ = BYTEV..nV's..V, DOUBLEV..V, FLOATV..V, INTV..V, LOGICALV..V,
+ LONGV..V, SHORTV..V.
+ N.B. Array dimensions and types are checked by the C compiler.
+ For routines changing the values of an argument, the keyword is
+ prepended by a 'P'.
+ = PBYTE, PDOUBLE, PFLOAT, PINT, PLOGICAL, PLONG, PSHORT,
+ PSTRING, PSTRINGV, PZTRINGV.
+ For EXTERNAL procedures passed as arguments use
+ = ROUTINE.
+ For exceptional arguments which require no massaging to fit the
+ argument passing mechanisms use
+ = PVOID.
+ The argument is cast and passed as (void *).
+ Although PVOID could be used to describe all array arguments on
+ most (all?) machines , it shouldn't be because the C compiler
+ can no longer check the type and dimension of the array.
+argname_i = any valid unique C tag, but must be consistent in the definition
+ as shown.
+
+Notes:
+
+1. cfortran.h may be expanded to handle a more argument type. To suppport new
+arguments requiring complicated massaging when passed between Fortran and C,
+the user will have to understand cfortran.h and follow its code and mechanisms.
+
+To define types requiring little or no massaging when passed between Fortran
+and C, the pseudo argument type SIMPLE may be used.
+For a user defined type called 'newtype', the definitions required are:
+
+/* The following 7 lines are required verbatim.
+ 'newtype' is the name of the new user defined argument type.
+*/
+#define newtype_cfV( T,A,B,F) SIMPLE_cfV(T,A,B,F)
+#define newtype_cfSEP(T, B) SIMPLE_cfSEP(T,B)
+#define newtype_cfINT(N,A,B,X,Y,Z) SIMPLE_cfINT(N,A,B,X,Y,Z)
+#define newtype_cfSTR(N,T,A,B,C,D,E) SIMPLE_cfSTR(N,T,A,B,C,D,E)
+#define newtype_cfCC( T,A,B) SIMPLE_cfCC(T,A,B)
+#define newtype_cfAA( T,A,B) newtype_cfB(T,A) /* Argument B not used. */
+#define newtype_cfU( T,A) newtype_cfN(T,A)
+
+/* 'parameter_type(A)' is a declaration for 'A' and describes the type of the
+parameter expected by the Fortran function. This type will be used in the
+prototype for the function, if using ANSI C, and to declare the argument used
+by the intermediate function if calling a Fortran FUNCTION.
+Valid 'parameter_type(A)' include: int A
+ void (*A)()
+ double A[17]
+*/
+#define newtype_cfN( T,A) parameter_type(A) /* Argument T not used. */
+
+/* Before any argument of the new type is passed to the Fortran routine, it may
+be massaged as given by 'massage(A)'.
+*/
+#define newtype_cfB( T,A) massage(A) /* Argument T not used. */
+
+An example of a simple user defined type is given cfortex.f and cfortest.c.
+Two uses of SIMPLE user defined types are [don't show the 7 verbatim #defines]:
+
+/* Pass the address of a structure, using a type called PSTRUCT */
+#define PSTRUCT_cfN( T,A) void *A
+#define PSTRUCT_cfB( T,A) (void *) &(A)
+
+/* Pass an integer by value, (not standard F77 ), using a type called INTVAL */
+#define INTVAL_cfN( T,A) int A
+#define INTVAL_cfB( T,A) (A)
+
+[If using VAX VMS, surrounding the #defines with "#pragma (no)standard" allows
+ the %CC-I-PARAMNOTUSED messages to be avoided.]
+
+Upgrades to cfortran.h try to be, and have been, backwards compatible. This
+compatibility cannot be offered to user defined types. SIMPLE user defined
+types are less of a risk since they require so little effort in their creation.
+If a user defined type is required in more than one C header file of interfaces
+to libraries of Fortran routines, good programming practice, and ease of code
+maintenance, suggests keeping any user defined type within a single file which
+is #included as required. To date, changes to the SIMPLE macros were introduced
+in versions 2.6, 3.0 and 3.2 of cfortran.h.
+
+
+2. Routine_name is the name of the macro which the C programmer will use in
+order to call a FORTRAN routine. In theory Routine_name could be any valid and
+unique name, but in practice, the name of the FORTRAN routine in UPPER CASE
+works everywhere and would seem to be an obvious choice.
+
+
+3. <BYTE|DOUBLE|BYTE|DOUBLE|FLOAT|INT|LOGICAL|LONG|SHORT><V|VV|VVV|...>
+
+cfortran.h encourages the exact specification of the type and dimension of
+array parameters because it allows the C compiler to detect errors in the
+arguments when calling the routine.
+
+cfortran.h does not strictly require the exact specification since the argument
+is merely the address of the array and is passed on to the calling routine.
+Any array parameter could be declared as PVOID, but this circumvents
+C's compiletime ability to check the correctness of arguments and is therefore
+discouraged.
+
+Passing the address of these arguments implies that PBYTEV, PFLOATV, ... ,
+PDOUBLEVV, ... don't exist in cfortran.h, since by default the routine and the
+calling code share the same array, i.e. the same values at the same memory
+location.
+
+These comments do NOT apply to arrays of (P)S/ZTRINGV. For these parameters,
+cfortran.h passes a massaged copy of the array to the routine. When the routine
+returns, S/ZTRINGV ignores the copy, while PS/ZTRINGV replaces the calling
+code's original array with copy, which may have been modified by the called
+routine.
+
+
+4. (P)STRING(V):
+- STRING - If the argument is a fixed length character array, e.g. char ar[8];,
+the string is blank, ' ', padded on the right to fill out the array before
+being passed to the FORTRAN routine. The useful size of the string is the same
+in both languages, e.g. ar[8] is passed as character*7. If the argument is a
+pointer, the string cannot be blank padded, so the length is passed as
+strlen(argument). On return from the FORTRAN routine, pointer arguments are not
+disturbed, but arrays have the terminating '\0' replaced to its original
+position. i.e. The padding blanks are never visible to the C code.
+
+- PSTRING - The argument is massaged as with STRING before being passed to the
+FORTRAN routine. On return, the argument has all trailing blanks removed,
+regardless of whether the argument was a pointer or an array.
+
+- (P)STRINGV - Passes a 1- or 2-dimensional char array. e.g. char a[7],b[6][8];
+STRINGV may thus also pass a string constant, e.g. "hiho".
+(P)STRINGV does NOT pass a pointer, e.g. char *, to either a 1- or a
+2-dimensional array, since it cannot determine the array dimensions.
+A pointer can only be passed using (P)ZTRINGV.
+N.B. If a C routine receives a character array argument, e.g. char a[2][3],
+ such an argument is actually a pointer and my thus not be passed by
+ (P)STRINGV. Instead (P)ZTRINGV must be used.
+
+- STRINGV - The elements of the argument are copied into space malloc'd, and
+each element is padded with blanks. The useful size of each element is the same
+in both languages. Therefore char bb[6][8]; is equivalent to character*7 bb(6).
+On return from the routine the malloc'd space is simply released.
+
+- PSTRINGV - Since FORTRAN has no trailing '\0', elements in an array of
+strings are contiguous. Therefore each element of the C array is padded with
+blanks and strip out C's trailing '\0'. After returning from the routine, the
+trailing '\0' is reinserted and kill the trailing blanks in each element.
+
+- SUMMARY: STRING(V) arguments are blank padded during the call to the FORTRAN
+routine, but remain original in the C code. (P)STRINGV arguments are blank
+padded for the FORTRAN call, and after returning from FORTRAN trailing blanks
+are stripped off.
+
+
+5. (P)ZTRINGV:
+- (P)ZTRINGV - is identical to (P)STRINGV,
+except that the dimensions of the array of strings is explicitly specified,
+which thus also allows a pointer to be passed.
+(P)ZTRINGV can thus pass a 1- or 2-dimensional char array, e.g. char b[6][8],
+or it can pass a pointer to such an array, e.g. char *p;.
+ZTRINGV may thus also pass a string constant, e.g. "hiho".
+If passing a 1-dimensional array, routine_name_ELEMS_j (see below) must be 1.
+[Users of (P)ZTRINGV should examine cfortest.c for examples.]:
+
+- (P)ZTRINGV must thus be used instead of (P)STRINGV whenever sizeof()
+can't be used to determine the dimensions of the array of string or strings.
+e.g. when calling FORTRAN from C with a char * received by C as an argument.
+
+- There is no (P)ZTRING type, since (P)ZTRINGV can pass a 1-dimensional
+array or a pointer to such an array, e.g. char a[7], *b;
+If passing a 1-dimensional array, routine_name_ELEMS_j (see below) must be 1.
+
+- To specify the numbers of elements,
+routine_name_ELEMS_j and routine_name_ELEMLEN_j must be defined as shown below
+before interfacing the routine with CCALLSFSUBn, PROTOCCALLSFFUNn, etc.
+
+#define routine_name_ELEMS_j ZTRINGV_ARGS(k)
+ [..ARGS for subroutines, ..ARGF for functions.]
+or
+#define routine_name_ELEMS_j ZTRINGV_NUM(l)
+Where: routine_name is as above.
+ j [1-n], is the argument being specifying.
+ k [1-n], the value of the k'th argument is the dynamic number
+ of elements for argument j. The k'th argument must be
+ of type BYTE, DOUBLE, FLOAT, INT, LONG or SHORT.
+ l the number of elements for argument j. This must be an
+ integer constant available at compile time.
+ i.e. it is static.
+
+- Similarly to specify the useful length, [i.e. don't count C's trailing '\0',]
+of each element:
+#define routine_name_ELEMLEN_j ZTRINGV_ARGS(m)
+ [..ARGS for subroutines, ..ARGF for functions.]
+or
+#define routine_name_ELEMLEN_j ZTRINGV_NUM(q)
+Where: m [1-n], as for k but this is the length of each element.
+ q as for l but this is the length of each element.
+
+
+6. ROUTINE
+The argument is an EXTERNAL procedure.
+
+When C passes a routine to Fortran, the language of the function must be
+specified as follows: [The case of some_*_function must be given as shown.]
+
+When C passes a C routine to a Fortran:
+ FORTRAN_ROUTINE(arg1, .... ,
+ C_FUNCTION(SOME_C_FUNCTION,some_c_function),
+ ...., argn);
+
+and similarly when C passes a Fortran routine to Fortran:
+ FORTRAN_ROUTINE(arg1, .... ,
+ FORTRAN_FUNCTION(SOME_FORT_FUNCTION,some_fort_function),
+ ...., argn);
+
+If fcallsc has been redefined; the same definition of fcallsc used when creating
+the wrapper for 'some_c_function' must also be defined when C_FUNCTION is used.
+See ii) 4. of this section for when and how to redefine fcallsc.
+
+ROUTINE was introduced with cfortran.h version 2.6. Earlier versions of
+cfortran.h used PVOID to pass external procedures as arguments. Using PVOID for
+this purpose is no longer recommended since it won't work 'as is' for
+apolloFortran, hpuxFortran800, AbsoftUNIXFortran, AbsoftProFortran.
+
+7. CRAY only:
+In a given piece of source code, where FFUNC is any FORTRAN routine,
+FORTRAN_FUNCTION(FFUNC,ffunc)
+disallows a previous
+#define FFUNC(..) CCALLSFSUBn(FFUNC,ffunc,...) [ or CCALLSFFUNn]
+in order to make the UPPER CASE FFUNC callable from C.
+#define Ffunc(..) ... is OK though, as are obviously any other names.
+
+
+ii) Calling C routines from FORTRAN:
+ --------------------------------
+
+Each of the following two statements to export a C routine to FORTRAN create
+FORTRAN 'wrappers', written in C, which must be compiled and linked along with
+the original C routines and with the FORTRAN calling code.
+
+FORTRAN callable 'wrappers' may also be created for C macros. i.e. in this
+section, the term 'C function' may be replaced by 'C macro'.
+
+for C functions returning void:
+FCALLSCSUBn( Routine_name,ROUTINE_NAME,routine_name,argtype_1,...,argtype_n)
+
+for all other C functions:
+FCALLSCFUNn(routine_type,Routine_name,ROUTINE_NAME,routine_name,argtype_1,...,argtype_n)
+
+Where:
+'n' = 0->27 (easily expanded to > 27) stands for the number of arguments to the
+ routine.
+Routine_name = the C name of the routine. [see 9. below]
+ROUTINE_NAME = the FORTRAN name of the routine (IN UPPER CASE LETTERS).
+routine_name = the FORTRAN name of the routine (IN lower case LETTERS).
+routine_type = the type of argument returned by C functions.
+ = BYTE, DOUBLE, FLOAT, INT, LOGICAL, LONG, SHORT, STRING, VOID.
+ [Instead of VOID, FCALLSCSUBn is recommended.]
+argtype_i = the type of argument passed to the FORTRAN routine and must be
+ consistent in the definition and prototyping of the routine
+ = BYTE, DOUBLE, FLOAT, INT, LOGICAL, LONG, SHORT, STRING.
+ For vectors, i.e. 1 dim. arrays use
+ = BYTEV, DOUBLEV, FLOATV, INTV, LOGICALV, LONGV, SHORTV, STRINGV.
+ For vectors of vectors, 2 dim. arrays use
+ = BYTEVV, DOUBLEVV, FLOATVV, INTVV, LOGICALVV, LONGVV, SHORTVV.
+ For n-dim. arrays use
+ = BYTEV..nV's..V, DOUBLEV..V, FLOATV..V, INTV..V, LOGICALV..V,
+ LONGV..V, SHORTV..V.
+ For routines changing the values of an argument, the keyword is
+ prepended by a 'P'.
+ = PBYTE, PDOUBLE, PFLOAT, PINT, PLOGICAL, PLONG, PSHORT,
+ PSTRING, PNSTRING, PPSTRING, PSTRINGV.
+ For EXTERNAL procedures passed as arguments use
+ = ROUTINE.
+ For exceptional arguments which require no massaging to fit the
+ argument passing mechanisms use
+ = PVOID.
+ The argument is cast and passed as (void *).
+
+
+Notes:
+
+0. For Fortran calling C++ routines, C++ does NOT easily allow support for:
+ STRINGV.
+ BYTEVV, DOUBLEVV, FLOATVV, INTVV, LOGICALVV, LONGVV, SHORTVV.
+ BYTEV..V, DOUBLEV..V, FLOATV..V, INTV..V, LOGICALV..V, LONGV..V, SHORTV..V.
+Though there are ways to get around this restriction,
+the restriction is not serious since these types are unlikely to be used as
+arguments for a C++ routine.
+
+1. FCALLSCSUB/FUNn expect that the routine to be 'wrapped' has been properly
+prototyped, or at least declared.
+
+
+2. cfortran.h may be expanded to handle a new argument type not already among
+the above.
+
+
+3. <BYTE|DOUBLE|BYTE|DOUBLE|FLOAT|INT|LOGICAL|LONG|SHORT><V|VV|VVV|...>
+
+cfortran.h encourages the exact specification of the type and dimension of
+array parameters because it allows the C compiler to detect errors in the
+arguments when declaring the routine using FCALLSCSUB/FUNn, assuming the
+routine to be 'wrapped' has been properly prototyped.
+
+cfortran.h does not strictly require the exact specification since the argument
+is merely the address of the array and is passed on to the calling routine.
+Any array parameter could be declared as PVOID, but this circumvents
+C's compiletime ability to check the correctness of arguments and is therefore
+discouraged.
+
+Passing the address of these arguments implies that PBYTEV, PFLOATV, ... ,
+PDOUBLEVV, ... don't exist in cfortran.h, since by default the routine and the
+calling code share the same array, i.e. the same values at the same memory
+location.
+
+These comments do NOT apply to arrays of (P)STRINGV. For these parameters,
+cfortran.h passes a massaged copy of the array to the routine. When the routine
+returns, STRINGV ignores the copy, while PSTRINGV replaces the calling
+code's original array with copy, which may have been modified by the called
+routine.
+
+
+4. (P(N))STRING arguments have any trailing blanks removed before being passed
+to C, the same holds true for each element in (P)STRINGV. Space is malloc'd in
+all cases big enough to hold the original string (elements) as well as C's
+terminating '\0'. i.e. The useful size of the string (elements) is the same in
+both languages. P(N)STRING(V) => the string (elements) will be copied from the
+malloc'd space back into the FORTRAN bytes. If one of the two escape mechanisms
+mentioned below for PNSTRING has been used, the copying back to FORTRAN is
+obviously not relevant.
+
+
+5. (PN)STRING's, [NOT PSTRING's nor (P)STRINGV's,] behavior may be overridden
+in two cases. In both cases PNSTRING and STRING behave identically.
+
+a) If a (PN)STRING argument's first 4 bytes are all the NUL character,
+i.e. '\0\0\0\0' the NULL pointer is passed to the C routine.
+
+b) If the characters of a (PN)STRING argument contain at least one HEX-00, i.e.
+the NUL character, i.e. C strings' terminating '\0', the address of the string
+is simply passed to the C routine. i.e. The argument is treated in this case as
+it would be with PPSTRING, to which we refer the reader for more detail.
+
+Mechanism a) overrides b). Therefore, to use this mechanism to pass the NULL
+string, "", to C, the first character of the string must obviously be the NUL
+character, but of the first 4 characters in the string, at least one must not
+be HEX-00.
+
+Example:
+C FORTRAN /* C */
+ character*40 str #include "cfortran.h"
+C Set up a NULL as : void cs(char *s) {if (s) printf("%s.\n",s);}
+C i) 4 NUL characters. FCALLSCSUB1(cs,CS,cs,STRING)
+C ii) NULL pointer.
+ character*4 NULL
+ NULL = CHAR(0)//CHAR(0)//CHAR(0)//CHAR(0)
+
+ data str/'just some string'/
+
+C Passing the NULL pointer to cs.
+ call cs(NULL)
+C Passing a copy of 'str' to cs.
+ call cs(str)
+C Passing address of 'str' to cs. Trailing blanks NOT killed.
+ str(40:) = NULL
+ call cs(str)
+ end
+
+Strings passed from Fortran to C via (PN)STRING must not have undefined
+contents, otherwise undefined behavior will result, since one of the above two
+escape mechanisms may occur depending on the contents of the string.
+
+This is not be a problem for STRING arguments, which are read-only in the C
+routine and hence must have a well defined value when being passed in.
+
+PNSTRING arguments require special care. Even if they are write-only in the C
+routine, PNSTRING's above two escape mechanisms require that the value of the
+argument be well defined when being passed in from Fortran to C. Therefore,
+unless one or both of PNSTRING's escape mechanisms are required, PSTRING should
+be used instead of PNSTRING.
+Prior to version 2.8, PSTRING did have the above two escape mechanisms,
+but they were removed from PSTRING to allow strings with undefined contents to
+be passed in. PNSTRING behaves like the old PSTRING.
+[Thanks go to Paul Dubois (dubios@icf.llnl.gov) for pointing out that PSTRING
+ must allow for strings with undefined contents to be passed in.]
+
+Example:
+C FORTRAN /* C */
+ character*10 s,sn #include "cfortran.h"
+ void ps(char *s) {strcpy(s,"hello");}
+C Can call ps with undef. s. FCALLSCSUB1(ps,PS,ps,PSTRING)
+ call ps(s) FCALLSCSUB1(ps,PNS,pns,PNSTRING)
+ print *,s,'=s'
+
+C Can't call pns with undef. s.
+C e.g. If first 4 bytes of s were
+C "\0\0\0\0", ps would try
+C to copy to NULL because
+C of PNSTRING mechanism.
+ sn = ""
+ call pns(sn)
+ print *,sn,'=sn'
+
+ end
+
+
+6. PPSTRING
+The address of the string argument is simply passed to the C routine. Therefore
+the C routine and the FORTRAN calling code share the same string at the same
+memory location. If the C routine modifies the string, the string will also be
+modified for the FORTRAN calling code.
+The user is responsible for negociating the differences in representation of a
+string in Fortran and in C, i.e. the differences are not automatically resolved
+as they are for (P(N)STRING(V).
+This mechanism is provided for two reasons:
+ - Some C routines require the string to exist at the given memory location,
+ after the C routine has exited. Recall that for the usual (P(N)STRING(V)
+ mechanism, a copy of the FORTRAN string is given to the C routine, and this
+ copy ceases to exist after returning to the FORTRAN calling code.
+ - This mechanism can save runtime CPU cycles over (P(N)STRING(V), since it
+ does not perform their malloc, copy and kill trailing blanks of the string
+ to be passed.
+ Only in a small minority of cases does the potential benefit of the saved
+ CPU cycles outweigh the programming effort required to manually resolve
+ the differences in representation of a string in Fortran and in C.
+
+For arguments passed via PPSTRING, the argument passed may also be an array of
+strings.
+
+
+7. ROUTINE
+ANSI C requires that the type of the value returned by the routine be known,
+For all ROUTINE arguments passed from Fortran to C, the type of ROUTINE is
+specified by defining a cast as follows:
+
+#undef ROUTINE_j
+#define ROUTINE_j (cast)
+where:
+ j [1-n], is the argument being specifying.
+ (cast) is a cast matching that of the argument expected by the C
+ function protoytpe for which a wrapper is being defined.
+
+e.g. To create a Fortran wrapper for qsort(3C):
+#undef ROUTINE_4
+#define ROUTINE_4 (int (*)(void *,void *))
+FCALLSCSUB4(qsort,FQSORT,fqsort,PVOID,INT,INT,ROUTINE)
+
+In order to maintain backward compatibility, cfortran.h defines a generic cast
+for ROUTINE_1, ROUTINE_2, ..., ROUTINE_27. The user's definition is therefore
+strictly required only for DEC C, which at the moment is the only compiler
+which insists on the correct cast for pointers to functions.
+
+When using the ROUTINE argument inside some Fortran code:
+- it is difficult to pass a C routine as the parameter,
+ since in many Fortran implementations,
+ Fortran has no access to the normal C namespace.
+ e.g. For most UNIX,
+ Fortran implicitly only has access to C routines ending in _.
+ If the calling Fortran code receives the routine as a parameter
+ it can of course easily pass it along.
+- if a Fortran routine is passed directly as the parameter,
+ the called C routine must call the parameter routine
+ using the Fortran argument passing conventions.
+- if a Fortran routine is to be passed as the parameter,
+ but if Fortran can be made to pass a C routine as the parameter,
+ then it may be best to pass a C-callable wrapper for the Fortran routine.
+ The called C routine is thus spared all Fortran argument passing conventions.
+ cfortran.h can be used to create such a C-callable wrapper
+ to the parameter Fortran routine.
+
+ONLY PowerStationFortran:
+This Fortran provides no easy way to pass a Fortran routine as an argument to a
+C routine. The problem arises because in Fortran the stack is cleared by the
+called routine, while in C/C++ it is cleared by the caller.
+The C/C++ stack clearing behavior can be changed to that of Fortran by using
+stdcall__ in the function prototype. The stdcall__ cannot be applied in this
+case since the called C routine expects the ROUTINE parameter to be a C routine
+and does not know that it should apply stdcall__.
+In principle the cfortran.h generated Fortran callable wrapper for the called C
+routine should be able to massage the ROUTINE argument such that stdcall__ is
+performed, but it is not yet known how this could be easily done.
+
+
+8. THE FOLLOWING INSTRUCTIONS ARE NOT REQUIRED FOR VAX VMS
+ ------------
+(P)STRINGV information [NOT required for VAX VMS]: cfortran.h cannot convert
+the FORTRAN vector of STRINGS to the required C vector of STRINGS without
+explicitly knowing the number of elements in the vector. The application must
+do one of the following for each (P)STRINGV argument in a routine before that
+routine's FCALLSCFUNn/SUBn is called:
+
+#define routine_name_STRV_Ai NUM_ELEMS(j)
+ or
+#define routine_name_STRV_Ai NUM_ELEM_ARG(k)
+ or
+#define routine_name_STRV_Ai TERM_CHARS(l,m)
+
+where: routine_name is as above.
+ i [i=1->n.] specifies the argument number of a STRING VECTOR.
+ j would specify a fixed number of elements.
+ k [k=1->n. k!=i] would specify an integer argument which specifies the
+ number of elements.
+ l [char] the terminating character at the beginning of an
+ element, indicating to cfortran.h that the preceding
+ elements in the vector are the valid ones.
+ m [m=1-...] the number of terminating characters required to appear
+ at the beginning of the terminating string element.
+ The terminating element is NOT passed on to
+ the C routine.
+
+e.g. #define ce_STRV_A1 TERM_CHARS(' ',2)
+ FCALLSCSUB1(ce,CE,ce,STRINGV)
+
+cfortran.h will pass on all elements, in the 1st and only argument to the C
+routine ce, of the STRING VECTOR until, but not including, the first string
+element beginning with 2 blank, ' ', characters.
+
+
+9. INSTRUCTIONS REQUIRED ONLY FOR FORTRAN COMPILERS WHICH GENERATE
+ -------------
+ ROUTINE NAMES WHICH ARE UNDISTINGUISHABLE FROM C ROUTINE NAMES
+ i.e. VAX VMS
+ AbsoftUNIXFortran (AbsoftProFortran ok, since it uses Uppercase names.)
+ HP9000 if not using the +ppu option of f77
+ IBM RS/6000 if not using the -qextname option of xlf
+ Call them the same_namespace compilers.
+
+FCALLSCSUBn(...) and FCALLSCFUNn(...), when compiled, are expanded into
+'wrapper' functions, so called because they wrap around the original C
+functions and interface the format of the original C functions' arguments and
+return values with the format of the FORTRAN call.
+
+Ideally one wants to be able to call the C routine from FORTRAN using the same
+name as the original C name. This is not a problem for FORTRAN compilers which
+append an underscore, '_', to the names of routines, since the original C
+routine has the name 'name', and the FORTRAN wrapper is called 'name_'.
+Similarly, if the FORTRAN compiler generates upper case names for routines, the
+original C routine 'name' can have a wrapper called 'NAME', [Assuming the C
+routine name is not in upper case.] For these compilers, e.g. Mips, CRAY, IBM
+RS/6000 'xlf -qextname', HP-UX 'f77 +ppu', the naming of the wrappers is done
+automatically.
+
+For same_namespace compilers things are not as simple, but cfortran.h tries to
+provide tools and guidelines to minimize the costs involved in meeting their
+constraints. The following two options can provide same_namespace compilers
+with distinct names for the wrapper and the original C function.
+
+These compilers are flagged by cfortran.h with the CF_SAME_NAMESPACE constant,
+so that the change in the C name occurs only when required.
+
+For the remainder of the discussion, routine names generated by FORTRAN
+compilers are referred to in lower case, these names should be read as upper
+case for the appropriate compilers.
+
+
+HP9000: (When f77 +ppu is not used.)
+f77 has a -U option which forces uppercase external names to be generated.
+Unfortunately, cc does not handle recursive macros. Hence, if one wished to use
+-U for separate C and FORTRAN namespaces, one would have to adopt a different
+convention of naming the macros which allow C to call FORTRAN subroutines.
+(Functions are not a problem.) The macros are currently the uppercase of the
+original FORTRAN name, and would have to be changed to lower case or mixed
+case, or to a different name. (Lower case would of course cause conflicts on
+many other machines.) Therefore, it is suggested that f77 -U not be used, and
+instead that Option a) or Option b) outlined below be used.
+
+
+VAX/VMS:
+For the name used by FORTRAN in calling a C routine to be the same as that of
+the C routine, the source code of the C routine is required. A preprocessor
+directive can then force the C compiler to generate a different name for the C
+routine.
+e.g. #if defined(vms)
+ #define name name_
+ #endif
+ void name() {printf("name: was called.\n");}
+ FCALLSCSUB0(name,NAME,name)
+
+In the above, the C compiler generates the original routine with the name
+'name_' and a wrapper called 'NAME'. This assumes that the name of the routine,
+as seen by the C programmer, is not in upper case. The VAX VMS linker is not
+case sensitive, allowing cfortran.h to export the upper case name as the
+wrapper, which then doesn't conflict with the routine name in C. Since the IBM,
+HP and AbsoftUNIXFortran platforms have case sensitive linkers
+this technique is not available to them.
+
+The above technique is required even if the C name is in mixed case, see
+Option a) for the other compilers, but is obviously not required when
+Option b) is used.
+
+
+Option a) Mixed Case names for the C routines to be called by FORTRAN.
+
+If the original C routines have mixed case names, there are no name space
+conflicts.
+
+Nevertheless for VAX/VMS, the technique outlined above must also used.
+
+
+Option b) Modifying the names of C routines when used by FORTRAN:
+
+The more robust naming mechanism, which guarantees portability to all machines,
+'renames' C routines when called by FORTRAN. Indeed, one must change the names
+on same_namespace compilers when FORTRAN calls C routines for which the source
+is unavailable. [Even when the source is available, renaming may be preferable
+to Option a) for large libraries of C routines.]
+
+Obviously, if done for a single type of machine, it must be done for all
+machines since the names of routines used in FORTRAN code cannot be easily
+redefined for different machines.
+
+The simplest way to achieve this end is to do explicitly give the modified
+FORTRAN name in the FCALLSCSUBn(...) and FCALLSCFUNn(...) declarations. e.g.
+
+FCALLSCSUB0(name,CFNAME,cfname)
+
+This allows FORTRAN to call the C routine 'name' as 'cfname'. Any name can of
+course be used for a given routine when it is called from FORTRAN, although
+this is discouraged due to the confusion it is sure to cause. e.g. Bizarre,
+but valid and allowing C's 'call_back' routine to be called from FORTRAN as
+'abcd':
+
+FCALLSCSUB0(call_back,ABCD,abcd)
+
+
+cfortran.h also provides preprocessor directives for a systematic 'renaming' of
+the C routines when they are called from FORTRAN. This is done by redefining
+the fcallsc macro before the FCALLSCSUB/FUN/n declarations as follows:
+
+#undef fcallsc
+#define fcallsc(UN,LN) preface_fcallsc(CF,cf,UN,LN)
+
+FCALLSCSUB0(hello,HELLO,hello)
+
+Will cause C's routine 'hello' to be known in FORTRAN as 'cfhello'. Similarly
+all subsequent FCALLSCSUB/FUN/n declarations will generate wrappers to allow
+FORTRAN to call C with the C routine's name prefaced by 'cf'. The following has
+the same effect, with subsequent FCALLSCSUB/FUN/n's appending the modifier to
+the original C routines name.
+
+#undef fcallsc
+#define fcallsc(UN,LN) append_fcallsc(Y,y,UN,LN)
+
+FCALLSCSUB0(Xroutine,ROUTINE,routine)
+
+Hence, C's Xroutine is called from FORTRAN as:
+ CALL XROUTINEY()
+
+The original behavior of FCALLSCSUB/FUN/n, where FORTRAN routine names are left
+identical to those of C, is returned using:
+
+#undef fcallsc
+#define fcallsc(UN,LN) orig_fcallsc(UN,LN)
+
+
+In C, when passing a C routine, i.e. its wrapper, as an argument to a FORTRAN
+routine, the FORTRAN name declared is used and the correct fcallsc must be in
+effect. E.g. Passing 'name' and 'routine' of the above examples to the FORTRAN
+routines, FT1 and FT2, respectively:
+
+/* This might not be needed if fcallsc is already orig_fcallsc. */
+#undef fcallsc
+#define fcallsc(UN,LN) orig_fcallsc(UN,LN)
+FT1(C_FUNCTION(CFNAME,cfname));
+
+#undef fcallsc
+#define fcallsc(UN,LN) append_fcallsc(Y,y,UN,LN)
+FT1(C_FUNCTION(XROUTINE,xroutine));
+
+If the names of C routines are modified when used by FORTRAN, fcallsc would
+usually be defined once in a header_file.h for the application. This definition
+would then be used and be valid for the entire application and fcallsc would at
+no point need to be redefined.
+
+
+ONCE AGAIN: THE DEFINITIONS, INSTRUCTIONS, DECLARATIONS AND DIFFICULTIES
+DESCRIBED HERE, NOTE 9. of II ii),
+APPLY ONLY FOR VAX VMS,
+ IBM RS/6000 WITHOUT THE -qextname OPTION FOR xlf, OR
+ HP-UX WITHOUT THE +ppu OPTION FOR f77
+ AbsoftUNIXFortran
+AND APPLY ONLY WHEN CREATING WRAPPERS WHICH ENABLE FORTRAN TO CALL C ROUTINES.
+
+
+
+iii) Using C to manipulate FORTRAN COMMON BLOCKS:
+ -------------------------------------------------------
+
+FORTRAN common blocks are set up with the following three constructs:
+
+1.
+#define Common_block_name COMMON_BLOCK(COMMON_BLOCK_NAME,common_block_name)
+
+Common_block_name is in UPPER CASE.
+COMMON_BLOCK_NAME is in UPPER CASE.
+common_block_name is in lower case.
+[Common_block_name actually follows the same 'rules' as Routine_name in Note 2.
+ of II i).] This construct exists to ensure that C code accessing the common
+block is machine independent.
+
+2.
+COMMON_BLOCK_DEF(TYPEDEF_OF_STRUCT, Common_block_name);
+
+where
+typedef { ... } TYPEDEF_OF_STRUCT;
+declares the structure which maps on to the common block. The #define of
+Common_block_name must come before the use of COMMON_BLOCK_DEF.
+
+3.
+In exactly one of the C source files, storage should be set aside for the
+common block with the definition:
+
+TYPEDEF_OF_STRUCT Common_block_name;
+
+The above definition may have to be omitted on some machines for a common block
+which is initialized by Fortran BLOCK DATA or is declared with a smaller size
+in the C routines than in the Fortran routines.
+
+The rules for common blocks are not well defined when linking/loading a mixture
+of C and Fortran, but the following information may help resolve problems.
+
+From the 2nd or ANSI ed. of K&R C, p.31, last paragraph:
+i)
+ An external variable must be defined, exactly once, outside of any function;
+ this sets aside storage for it.
+ii)
+ The variable must also be declared in each function that wants to access it;
+ ...
+ The declaration ... may be implicit from context.
+
+In Fortran, every routine says 'common /bar/ foo',
+i.e. part ii) of the above, but there's no part i) requirement.
+cc/ld on some machines don't require i) either.
+Therefore, when handling Fortran, and sometimes C,
+the loader/linker must automagically set aside storage for common blocks.
+
+Some loaders, including at least one for the CRAY, turn off the
+'automagically set aside storage' capability for Fortran common blocks,
+if any C object declares that common block.
+Therefore, C code should define, i.e. set aside storage,
+for the the common block as shown above.
+
+e.g.
+C Fortran
+ common /fcb/ v,w,x
+ character *(13) v, w(4), x(3,2)
+
+/* C */
+typedef struct { char v[13],w[4][13],x[2][3][13]; } FCB_DEF;
+#define Fcb COMMON_BLOCK(FCB,fcb)
+COMMON_BLOCK_DEF(FCB_DEF,Fcb);
+FCB_DEF Fcb; /* Definition, which sets aside storage for Fcb, */
+ /* may appear in at most one C source file. */
+
+
+C programs can place a string (or a multidimensional array of strings) into a
+FORTRAN common block using the following call:
+
+C2FCBSTR( CSTR, FSTR,DIMENSIONS);
+
+where:
+
+CSTR is a pointer to the first element of C's copy of the string (array).
+ The C code must use a duplicate of, not the original, common block string,
+ because the FORTRAN common block does not allocate space for C strings'
+ terminating '\0'.
+
+FSTR is a pointer to the first element of the string (array) in the common
+ block.
+
+DIMENSIONS is the number of dimensions of string array.
+ e.g. char a[10] has DIMENSIONS=0.
+ char aa[10][17] has DIMENSIONS=1.
+ etc...
+
+C2FCBSTR will copy the string (array) from CSTR to FSTR, padding with blanks,
+' ', the trailing characters as required. C2FCBSTR uses DIMENSIONS and FSTR to
+determine the lengths of the individual string elements and the total number of
+elements in the string array.
+
+Note that:
+- the number of string elements in CSTR and FSTR are identical.
+- for arrays of strings, the useful lengths of strings in CSTR and FSTR must be
+ the same. i.e. CSTR elements each have 1 extra character to accommodate the
+ terminating '\0'.
+- On most non-ANSI compilers, the DIMENSION argument cannot be prepended by any
+ blanks.
+
+
+FCB2CSTR( FSTR, CSTR,DIMENSIONS)
+
+is the inverse of C2FCBSTR, and shares the same arguments and caveats.
+FCB2CSTR copies each string element of FSTR to CSTR, minus FORTRAN strings'
+trailing blanks.
+
+
+cfortran.h USERS ARE STRONGLY URGED TO EXAMINE THE COMMON BLOCK EXAMPLES IN
+cfortest.c AND cfortex.f. The use of strings in common blocks is
+demonstrated, along with a suggested way for C to imitate FORTRAN EQUIVALENCE'd
+variables.
+
+
+ ===> USERS OF CFORTRAN.H NEED READ NO FURTHER <===
+
+
+III Some Musings
+----------------
+
+cfortran.h is simple enough to be used by the most basic of applications, i.e.
+making a single C/FORTRAN routine available to the FORTRAN/C programmers. Yet
+cfortran.h is powerful enough to easily make entire C/FORTRAN libraries
+available to FORTRAN/C programmers.
+
+
+cfortran.h is the ideal tool for FORTRAN libraries which are being (re)written
+in C, but are to (continue to) support FORTRAN users. It allows the routines to
+be written in 'natural C', without having to consider the FORTRAN argument
+passing mechanisms of any machine. It also allows C code accessing these
+rewritten routines, to use the C entry point. Without cfortran.h, one risks the
+perverse practice of C code calling a C function using FORTRAN argument passing
+mechanisms!
+
+
+Perhaps the philosophy and mechanisms of cfortran.h could be used and extended
+to create other language bridges such as ADAFORTRAN, CPASCAL, COCCAM, etc.
+
+
+The code generation machinery inside cfortran.h, i.e. the global structure is
+quite good, being clean and workable as seen by its ability to meet the needs
+and constraints of many different compilers. Though the individual instructions
+of the A..., C..., T..., R... and K... tables deserve to be cleaned up.
+
+
+
+IV Getting Serious with cfortran.h
+-----------------------------------
+
+cfortran.h is set up to be as simple as possible for the casual user. While
+this ease of use will always be present, 'hooks', i.e. preprocessor directives,
+are required in cfortran.h so that some of the following 'inefficiencies' can
+be eliminated if they cause difficulties:
+
+o cfortran.h contains a few small routines for string manipulation. These
+routines are declared static and are included and compiled in all source code
+which uses cfortran.h. Hooks should be provided in cfortran.h to create an
+object file of these routines, allowing cfortran.h to merely prototypes
+these routines in the application source code. This is the only 'problem' which
+afflicts both halves of cfortran.h. The remaining discussion refers to the C
+calls FORTRAN half only.
+
+o Similar to the above routines, cfortran.h generates code for a 'wrapper'
+routine for each FUNCTION exported from FORTRAN. Again cfortran.h needs
+preprocessor directives to create a single object file of these routines,
+and to merely prototype them in the applications.
+
+o Libraries often contain hundreds of routines. While the preprocessor makes
+quick work of generating the required interface code from cfortran.h and the
+application.h's, it may be convenient for very large stable libraries to have
+final_application.h's which already contain the interface code, i.e. these
+final_application.h's would not require cfortran.h. [The convenience can be
+imagined for the VAX VMS CC compiler which has a fixed amount of memory for
+preprocessor directives. Not requiring cfortran.h, with its hundreds of
+directives, could help prevent this compiler from choking on its internal
+limits quite so often.]
+
+With a similar goal in mind, cfortran.h defines 100's of preprocessor
+directives. There is always the potential that these will clash with other tags
+in the users code, so final_applications.h, which don't require cfortran.h,
+also provide the solution.
+
+In the same vein, routines with more than 14 arguments can not be interfaced by
+cfortran.h with compilers which limit C macros to 31 arguments. To resolve this
+difficulty, final_application.h's can be created on a compiler without this
+limitation.
+
+Therefore, new machinery is required to do:
+
+application.h + cfortran.h => final_application.h
+
+The following example may help clarify the means and ends:
+
+If the following definition of the HBOOK1 routine, the /*commented_out_part*/,
+is passed through the preprocessor [perhaps #undefing and #defining preprocessor
+constants if creating an application.h for compiler other than that of the
+preprocessor being used, e.g. cpp -Umips -DCRAY ... ] :
+
+#include "cfortran.h"
+PROTOCCALLSFSUB6(HBOOK1,hbook1,INT,STRING,INT,FLOAT,FLOAT,FLOAT)
+/*#define HBOOK1(ID,CHTITLE,NX,XMI,XMA,VMX) \*/
+ CCALLSFSUB6(HBOOK1,hbook1,INT,STRING,INT,FLOAT,FLOAT,FLOAT, \
+ ID,CHTITLE,NX,XMI,XMA,VMX)
+
+A function prototype is produced by the PROTOCCALLSFSUB6(...).
+Interface code is produced, based on the 'variables',
+ID,CHTITLE,NX,XMI,XMA,VMX, which will correctly massage a HBOOK1 call.
+Therefore, adding the #define line:
+
+'prototype code'
+#define HBOOK1(ID,CHTITLE,NX,XMI,XMA,VMX) \
+ 'interface code'(ID,CHTITLE,NX,XMI,XMA,VMX)
+
+which is placed into final_application.h.
+
+The only known limitation of the above method does not allow the 'variable'
+names to include B1,B2,...,B9,BA,BB,...
+
+Obviously the machinery to automatically generate final_applications.h from
+cfortran.h and applications.h needs more than just some preprocessor
+directives, but a fairly simple unix shell script should be sufficient. Any
+takers?
+
+
+
+V Machine Dependencies of cfortran.h
+------------------------------------
+
+Porting cfortran.h applications, e.g. the hbook.h and cstring.c mentioned
+above, to other machines is trivial since they are machine independent. Porting
+cfortran.h requires a solid knowledge of the new machines C preprocessor, and
+its FORTRAN argument passing mechanisms. Logically cfortran.h exists as two
+halves, a "C CALLS FORTRAN" and a "FORTRAN CALLS C" utility. In some cases it
+may be perfectly reasonable to port only 'one half' of cfortran.h onto a new
+system.
+
+
+The lucky programmer porting cfortran.h to a new machine, must discover the
+FORTRAN argument passing mechanisms. A safe starting point is to assume that
+variables and arrays are simply passed by reference, but nothing is guaranteed.
+Strings, and n-dimensional arrays of strings are a different story. It is
+doubtful that any systems do it quite like VAX VMS does it, so that a UNIX or
+f2c versions may provide an easier starting point.
+
+
+cfortran.h uses and abuses the preprocessor's ## operator. Although the ##
+operator does not exist in many compilers, many kludges do. cfortran.h uses
+/**/ with no space allowed between the slashes, '/', and the macros or tags
+to be concatenated. e.g.
+#define concat(a,b) a/**/b /* works*/
+main()
+{
+ concat(pri,ntf)("hello"); /* e.g. */
+}
+N.B. On some compilers without ##, /**/ may also not work. The author may be
+able to offer alternate kludges.
+
+
+
+VI Bugs in vendors C compilers and other curiosities
+----------------------------------------------------
+
+1. ULTRIX xxxxxx 4.3 1 RISC
+
+Condolences to long suffering ultrix users!
+DEC supplies a working C front end for alpha/OSF, but not for ultrix.
+
+From K&R ANSI C p. 231:
+ ultrix> cat cat.c
+ #define cat(x, y) x ## y
+ #define xcat(x,y) cat(x,y)
+ cat(cat(1,2),3)
+ xcat(xcat(1,2),3)
+ ultrix> cc -E cat.c
+ 123 <---- Should be: cat(1,2)3
+ 123 <---- Correct.
+ ultrix>
+
+The problem for cfortran.h, preventing use of -std and -std1:
+ ultrix> cat c.c
+ #define cat(x, y) x ## y
+ #define xcat(x,y) cat(x,y)
+ #define AB(X) X+X
+ #define C(E,F,G) cat(E,F)(G)
+ #define X(E,F,G) xcat(E,F)(G)
+ C(A,B,2)
+ X(A,B,2)
+ ultrix> cc -std1 -E c.c
+ 2+2
+ AB (2) <---- ?????????????
+ ultrix>
+ ultrix> cc -std0 -E c.c
+ 2+2
+ AB(2) <---- ?????????????
+ ultrix>
+
+Due to further ultrix preprocessor problems,
+for all definitions of definitions with arguments,
+cfortran.h >= 3.0 includes the arguments and recommends the same,
+even though it is not required by ANSI C.
+e.g. Users are advised to do
+ #define fcallsc(UN,LN) orig_fcallsc(UN,LN)
+instead of
+ #define fcallsc orig_fcallsc
+since ultrix fails to properly preprocess the latter example.
+CRAY used to (still does?) occasionally trip up on this problem.
+
+
+2. ConvexOS convex C210 11.0 convex
+
+In a program with a C main, output to LUN=6=* from Fortran goes into
+$pwd/fort.6 instead of stdout. Presumably, a magic incantation can be called
+from the C main in order to properly initialize the Fortran I/O.
+
+
+3. SunOS 5.3 Generic_101318-69 sun4m sparc
+
+The default data and code alignments produced by cc, gcc and f77 are compatible.
+If deviating from the defaults, consistent alignment options must be used
+across all objects compiled by cc and f77. [Does gcc provide such options?]
+
+
+4. SunOS 5.3 Generic_101318-69 sun4m sparc with cc: SC3.0.1 13 Jul 1994
+ or equivalently
+ ULTRIX 4.4 0 RISC using cc -oldc
+ are K&R C preprocessors that suffer from infinite loop macros, e.g.
+
+ zedy03> cat src.c
+ #include "cfortran.h"
+ PROTOCCALLSFFUN1(INT,FREV,frev, INTV)
+ #define FREV(A1) CCALLSFFUN1( FREV,frev, INTV, A1)
+ /* To avoid the problem, deletete these ---^^^^--- spaces. */
+ main() { static int a[] = {1,2}; FREV(a); return EXIT_SUCCESS; }
+
+ zedy03> cc -c -Xs -v -DMAX_PREPRO_ARGS=31 -D__CF__KnR src.c
+ "src.c", line 4: FREV: actuals too long
+ "src.c", line 4: FREV: actuals too long
+ .... 3427 more lines of the same message
+ "src.c", line 4: FREV: actuals too long
+ cc : Fatal error in /usr/ccs/lib/cpp
+ Segmentation fault (core dumped)
+
+
+5. Older sun C compilers
+
+To link to f77 objects, older sun C compilers require the math.h macros:
+
+#define RETURNFLOAT(x) { union {double _d; float _f; } _kluge; \
+ _kluge._f = (x); return _kluge._d; }
+#define ASSIGNFLOAT(x,y) { union {double _d; float _f; } _kluge; \
+ _kluge._d = (y); x = _kluge._f; }
+
+Unfortunately, in at least some copies of the sun math.h, the semi-colon
+for 'float _f;' is left out, leading to compiler warnings.
+
+The solution is to correct math.h, or to change cfortran.h to #define
+RETURNFLOAT(x) and ASSIGNFLOAT(x,y) instead of including math.h.
+
+
+6. gcc version 2.6.3 and probably all other versions as well
+
+Unlike all other C compilers supported by cfortran.h,
+'gcc -traditional' promotes to double all functions returning float
+as demonstrated bu the following example.
+
+/* m.c */
+#include <stdio.h>
+int main() { FLOAT_FUNCTION d(); float f; f = d(); printf("%f\n",f); return 0; }
+
+/* d.c */
+float d() { return -123.124; }
+
+burow[29] gcc -c -traditional d.c
+burow[30] gcc -DFLOAT_FUNCTION=float m.c d.o && a.out
+0.000000
+burow[31] gcc -DFLOAT_FUNCTION=double m.c d.o && a.out
+-123.124001
+burow[32]
+
+Thus, 'gcc -traditional' is not supported by cfortran.h.
+Support would require the same RETURNFLOAT, etc. macro machinery
+present in old sun math.h, before sun gave up the same promotion.
+
+
+7. CRAY
+
+At least some versions of the t3e and t3d C preprocessor are broken
+in the fashion described below.
+At least some versions of the t90 C preprocessor do not have this problem.
+
+On the CRAY, all Fortran names are converted to uppercase.
+Generally the uppercase name is also used for the macro interface
+created by cfortran.h.
+
+For example, in the following interface,
+EASY is both the name of the macro in the original C code
+and EASY is the name of the resulting function to be called.
+
+#define EASY(A,B) CCALLSFSUB2(EASY,easy, PINT, INTV, A, B)
+
+The fact that a macro called EASY() expands to a function called EASY()
+is not a problem for a working C preprocessor.
+From Kernighan and Ritchie, 2nd edition, p.230:
+
+ In both kinds of macro, the replacement token sequence is repeatedly
+ rescanned for more identifiers. However, once a given identifier has been
+ replaced in a given expansion, it is not replaced if it turns up again during
+ rescanning; instead it is left unchanged.
+
+Unfortunately, some CRAY preprocessors are broken and don't obey the above rule.
+A work-around is for the user to NOT use the uppercase name
+of the name of the macro interface provided by cfortran.h. For example:
+
+#define Easy(A,B) CCALLSFSUB2(EASY,easy, PINT, INTV, A, B)
+
+Luckily, the above work-around is not required since the following
+work-around within cfortran.h also circumvents the bug:
+
+ /* (UN), not UN, is required in order to get around CRAY preprocessor bug.*/
+ #define CFC_(UN,LN) (UN) /* Uppercase FORTRAN symbols. */
+
+Aside: The Visual C++ compiler is happy with UN, but barfs on (UN),
+ so either (UN) causes nonstandard C/C++ or Visual C++ is broken.
+
+
+VII History and Acknowledgements
+--------------------------------
+
+1.0 - Supports VAX VMS using C 3.1 and FORTRAN 5.4. Oct. '90.
+1.0 - Supports Silicon Graphics w. Mips Computer 2.0 f77 and cc. Feb. '91.
+ [Port of C calls FORTRAN half only.]
+1.1 - Supports Mips Computer System 2.0 f77 and cc. Mar. '91.
+ [Runs on at least: Silicon Graphics IRIX 3.3.1
+ DECstations with Ultrix V4.1]
+1.2 - Internals made simpler, smaller, faster, stronger. May '91.
+ - Mips version works on IBM RS/6000, this is now called the unix version.
+1.3 - UNIX and VAX VMS versions are merged into a single cfortran.h. July '91.
+ - C can help manipulate (arrays of) strings in FORTRAN common blocks.
+ - Dimensions of string arrays arguments can be explicit.
+ - Supports Apollo DomainOS 10.2 (sys5.3) with f77 10.7 and cc 6.7.
+
+2.0 - Improved code generation machinery creates K&R or ANSI C. Aug. '91.
+ - Supports Sun, CRAY. f2c with vcc on VAX Ultrix.
+ - cfortran.h macros now require routine and COMMON block names in both
+ upper and lower case. No changes required to applications though.
+ - PROTOCCALLSFSUBn is eliminated, with no loss to cfortran.h performance.
+ - Improved tools and guidelines for naming C routines called by FORTRAN.
+2.1 - LOGICAL correctly supported across all machines. Oct. '91.
+ - Improved support for DOUBLE PRECISION on the CRAY.
+ - HP9000 fully supported.
+ - VAX Ultrix cc or gcc with f77 now supported.
+2.2 - SHORT, i.e. INTEGER*2, and BYTE now supported. Dec. '91.
+ - LOGICAL_STRICT introduced. More compact and robust internal tables.
+ - typeV and typeVV for type = BYTE, DOUBLE, FLOAT, INT, LOGICAL, LONG,SHORT.
+ - FORTRAN passing strings and NULL pointer to C routines improved.
+2.3 - Extraneous arguments removed from many internal tables. May '92.
+ - Introduce pseudo argument type SIMPLE for user defined types.
+ - LynxOS using f2c supported. (Tested with LynxOS 2.0 386/AT.)
+2.4 - Separation of internal C and Fortran compilation directives. Oct. '92.
+ - f2c and NAG f90 supported on all machines.
+2.5 - Minor mod.s to source and/or doc for HP9000, f2c, and NAG f90. Nov. '92.
+2.6 - Support external procedures as arguments with type ROUTINE. Dec. '92.
+2.7 - Support Alpha VMS. Support HP9000 f77 +ppu Jan. '93.
+ - Support arrays with up to 7 dimensions.
+ - Minor mod. of Fortran NULL to C via (P)STRING.
+ - Specify the type of ROUTINE passed from Fortran to C [ANSI C requirement.]
+ - Macros never receive a null parameter [RS/6000 requirement.]
+2.8 - PSTRING for Fortran calls C no longer provides escape to pass April'93.
+ NULL pointer nor to pass address of original string.
+ PNSTRING introduced with old PSTRING's behavior.
+ PPSTRING introduced to always pass original address of string.
+ - Support Alpha/OSF.
+ - Document that common blocks used in C should be declared AND defined.
+
+3.0 - Automagic handling of ANSI ## versus K&R /**/ preprocessor op. March'95.
+ - Less chance of name space collisions between cfortran.h and other codes.
+ - SIMPLE macros, supporting user defined types, have changed names.
+3.1 - Internal macro name _INT not used. Conflicted with IRIX 5.3. May '95.
+ - SunOS, all versions, should work out of the box.
+ - ZTRINGV_ARGS|F(k) may no longer point to a PDOUBLE or PFLOAT argument.
+ - ConvexOS 11.0 supported.
+3.2 - __hpux no longer needs to be restricted to MAX_PREPRO_ARGS=31. Oct. '95.
+ - PSTRING bug fixed.
+ - ZTRINGV_ARGS|F(k) may not point to a PBYTE,PINT,PLONG or PSHORT argument.
+ - (P)ZTRINGV machinery improved. Should lead to fewer compiler warnings.
+ (P)ZTRINGV no longer limits recursion or the nesting of routines.
+ - SIMPLE macros, supporting user defined types, have changed slightly.
+3.3 - Supports PowerStation Fortran with Visual C++. Nov. '95.
+ - g77 should work using f2cFortran, though no changes made for it.
+ - (PROTO)CCALLSFFUN10 extended to (PROTO)CCALLSFFUN14.
+ - FCALLSCFUN10 and SUB10 extended to FCALLSCFUN14 and SUB14.
+3.4 - C++ supported, Dec. '95.
+ but it required the reintroduction of PROTOCCALLSFSUBn for users.
+ - HP-UX f77 +800 supported.
+3.5 - Absoft UNIX Fortran supported. Sept.'96.
+3.6 - Minor corrections to cfortran.doc. Oct. '96.
+ - Fixed bug for 15th argument. [Thanks to Tom Epperly at Aspen Tech.]
+ - For AbsoftUNIXFortran, obey default of prepending _C to COMMON BLOCK name.
+ - Fortran calling C with ROUTINE argument fixed and cleaned up.
+3.7 - Circumvent IBM and HP "null argument" preprocessor warning. Oct. '96
+3.8 - (P)STRINGV and (P)ZTRINGV can pass a 1- or 2-dim. char array. Feb. '97
+ (P)ZTRINGV thus effectively also provides (P)ZTRING.
+ - (P)ZTRINGV accepts a (char *) pointer.
+3.9 - Bug fixed for *VVVVV. May '97
+ - f2c: Work-around for strange underscore-dependent naming feature.
+ - NEC SX-4 supported.
+ - CRAY: LOGICAL conversion uses _btol and _ltob from CRAY's fortran.h.
+ - CRAY: Avoid bug of some versions of the C preprocessor.
+ - CRAY T3E: FORTRAN_REAL introduced.
+
+4.0 - new/delete now used for C++. malloc/free still used for C. Jan. '98
+ - FALSE no longer is defined by cfortran.h .
+ - Absoft Pro Fortran for MacOS supported.
+4.1 - COMMA and COLON no longer are defined by cfortran.h . April'98
+ - Bug fixed when 10th arg. or beyond is a string.
+ [Rob Lucchesi of NASA-Goddard pointed out this bug.]
+ - CCALLSFSUB/FUN extended from 14 to 27 arguments.
+ - Workaround SunOS CC 4.2 cast bug. [Thanks to Savrak SAR of CERN.]
+4.2 - Portland Group needs -DpgiFortran . [Thank George Lai of NASA.] June '98
+4.3 - (PROTO)CCALLSFSUB extended from 20 to 27 arguments. July '98
+
+
+['Support' implies these and more recent releases of the respective
+ OS/compilers/linkers can be used with cfortran.h.
+ Earlier releases may also work.]
+
+
+Acknowledgements:
+- CERN very generously sponsored a week in 1994 for me to work on cfortran.h.
+- M.L.Luvisetto (Istituto Nazionale Fisica Nucleare - Centro Nazionale
+ Analisi Fotogrammi, Bologna, Italy) provided all the support for the port to
+ the CRAY. Marisa's encouragement and enthusiasm was also much appreciated.
+- J.Bunn (CERN) supported the port to PowerStation Fortran with Visual C++.
+- Paul Schenk (UC Riverside, CERN PPE/OPAL) in June 1993 extended cfortran.h 2.7
+ to have C++ call Fortran. This was the starting point for full C++ in 3.4.
+- Glenn P.Davis of University Corp. for Atmospheric Research (UCAR) / Unidata
+ supported the NEC SX-4 port and helped understand the CRAY.
+- Tony Goelz of Absoft Corporation ported cfortran.h to Absoft.
+- Though cfortran.h has been created in my 'copious' free time, I thank
+ NSERC for their generous support of my grad. student and postdoc years.
+- Univ.Toronto, DESY, CERN and others have provided time on their computers.
+
+
+THIS PACKAGE, I.E. CFORTRAN.H, THIS DOCUMENT, AND THE CFORTRAN.H EXAMPLE
+PROGRAMS ARE PROPERTY OF THE AUTHOR WHO RESERVES ALL RIGHTS. THIS PACKAGE AND
+THE CODE IT PRODUCES MAY BE FREELY DISTRIBUTED WITHOUT FEES, SUBJECT TO THE
+FOLLOWING RESTRICTIONS:
+- YOU MUST ACCOMPANY ANY COPIES OR DISTRIBUTION WITH THIS (UNALTERED) NOTICE.
+- YOU MAY NOT RECEIVE MONEY FOR THE DISTRIBUTION OR FOR ITS MEDIA
+ (E.G. TAPE, DISK, COMPUTER, PAPER.)
+- YOU MAY NOT PREVENT OTHERS FROM COPYING IT FREELY.
+- YOU MAY NOT DISTRIBUTE MODIFIED VERSIONS WITHOUT CLEARLY DOCUMENTING YOUR
+ CHANGES AND NOTIFYING THE AUTHOR.
+- YOU MAY NOT MISREPRESENTED THE ORIGIN OF THIS SOFTWARE, EITHER BY EXPLICIT
+ CLAIM OR BY OMISSION.
+
+THE INTENT OF THE ABOVE TERMS IS TO ENSURE THAT THE CFORTRAN.H PACKAGE NOT BE
+USED FOR PROFIT MAKING ACTIVITIES UNLESS SOME ROYALTY ARRANGEMENT IS ENTERED
+INTO WITH ITS AUTHOR.
+
+THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
+EXPRESSED OR IMPLIED. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+SOFTWARE IS WITH YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST
+OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. THE AUTHOR IS NOT RESPONSIBLE
+FOR ANY SUPPORT OR SERVICE OF THE CFORTRAN.H PACKAGE.
+
+ Burkhard Burow
+ burow@desy.de
+
+P.S. Your comments and questions are welcomed and usually promptly answered.
+
+VAX VMS and Ultrix, Alpha, OSF, Silicon Graphics (SGI), DECstation, Mips RISC,
+Sun, CRAY, Convex, IBM RS/6000, Apollo DomainOS, HP, LynxOS, f2c, NAG, Absoft,
+NEC SX-4, PowerStation and Visual C++ are registered trademarks of their
+respective owners.
+
+/* end: cfortran.doc */
diff --git a/pkg/tbtables/cfitsio/cfortran.h b/pkg/tbtables/cfitsio/cfortran.h
new file mode 100644
index 00000000..abdeb430
--- /dev/null
+++ b/pkg/tbtables/cfitsio/cfortran.h
@@ -0,0 +1,2397 @@
+/* cfortran.h 4.4_cernlib2002 */
+/* http://www-zeus.desy.de/~burow/cfortran/ */
+/* Burkhard Burow burow@desy.de 1990 - 2002. */
+
+#ifndef __CFORTRAN_LOADED
+#define __CFORTRAN_LOADED
+
+/*
+ THIS FILE IS PROPERTY OF BURKHARD BUROW. IF YOU ARE USING THIS FILE YOU
+ SHOULD ALSO HAVE ACCESS TO CFORTRAN.DOC WHICH PROVIDES TERMS FOR USING,
+ MODIFYING, COPYING AND DISTRIBUTING THE CFORTRAN.H PACKAGE.
+*/
+
+/*******
+ Modifications:
+ Oct 1997: Changed symbol name extname to appendus (PDW/HSTX)
+ (Conflicted with a common variable name in FTOOLS)
+ Nov 1997: If g77Fortran defined, also define f2cFortran (PDW/HSTX)
+ Feb 1998: Let VMS see the NUM_ELEMS code. Lets programs treat
+ single strings as vectors with single elements
+ Nov 1999: If macintoxh defined, also define f2cfortran (for Mac OS-X)
+ Apr 2000: If WIN32 defined, also define PowerStationFortran and
+ VISUAL_CPLUSPLUS (Visual C++)
+ Jun 2000: If __GNUC__ and linux defined, also define f2cFortran
+ (linux/gcc environment detection)
+ Apr 2002: If __CYGWIN__ is defined, also define f2cFortran
+ Nov 2002: If __APPLE__ defined, also define f2cfortran (for Mac OS-X)
+ *******/
+/*
+ Avoid symbols already used by compilers and system *.h:
+ __ - OSF1 zukal06 V3.0 347 alpha, cc -c -std1 cfortest.c
+
+ */
+
+
+/* First prepare for the C compiler. */
+
+#ifndef ANSI_C_preprocessor /* i.e. user can override. */
+#ifdef __CF__KnR
+#define ANSI_C_preprocessor 0
+#else
+#ifdef __STDC__
+#define ANSI_C_preprocessor 1
+#else
+#define _cfleft 1
+#define _cfright
+#define _cfleft_cfright 0
+#define ANSI_C_preprocessor _cfleft/**/_cfright
+#endif
+#endif
+#endif
+
+#if ANSI_C_preprocessor
+#define _0(A,B) A##B
+#define _(A,B) _0(A,B) /* see cat,xcat of K&R ANSI C p. 231 */
+#define _2(A,B) A##B /* K&R ANSI C p.230: .. identifier is not replaced */
+#define _3(A,B,C) _(A,_(B,C))
+#else /* if it turns up again during rescanning. */
+#define _(A,B) A/**/B
+#define _2(A,B) A/**/B
+#define _3(A,B,C) A/**/B/**/C
+#endif
+
+#if (defined(vax)&&defined(unix)) || (defined(__vax__)&&defined(__unix__))
+#define VAXUltrix
+#endif
+
+#include <stdio.h> /* NULL [in all machines stdio.h] */
+#include <string.h> /* strlen, memset, memcpy, memchr. */
+#if !( defined(VAXUltrix) || defined(sun) || (defined(apollo)&&!defined(__STDCPP__)) )
+#include <stdlib.h> /* malloc,free */
+#else
+#include <malloc.h> /* Had to be removed for DomainOS h105 10.4 sys5.3 425t*/
+#ifdef apollo
+#define __CF__APOLLO67 /* __STDCPP__ is in Apollo 6.8 (i.e. ANSI) and onwards */
+#endif
+#endif
+
+#if !defined(__GNUC__) && !defined(__sun) && (defined(sun)||defined(VAXUltrix)||defined(lynx))
+#define __CF__KnR /* Sun, LynxOS and VAX Ultrix cc only supports K&R. */
+ /* Manually define __CF__KnR for HP if desired/required.*/
+#endif /* i.e. We will generate Kernighan and Ritchie C. */
+/* Note that you may define __CF__KnR before #include cfortran.h, in order to
+generate K&R C instead of the default ANSI C. The differences are mainly in the
+function prototypes and declarations. All machines, except the Apollo, work
+with either style. The Apollo's argument promotion rules require ANSI or use of
+the obsolete std_$call which we have not implemented here. Hence on the Apollo,
+only C calling FORTRAN subroutines will work using K&R style.*/
+
+
+/* Remainder of cfortran.h depends on the Fortran compiler. */
+
+#if defined(CLIPPERFortran) || defined(pgiFortran)
+#define f2cFortran
+#endif
+
+/* VAX/VMS does not let us \-split long #if lines. */
+/* Split #if into 2 because some HP-UX can't handle long #if */
+#if !(defined(NAGf90Fortran)||defined(f2cFortran)||defined(hpuxFortran)||defined(apolloFortran)||defined(sunFortran)||defined(IBMR2Fortran)||defined(CRAYFortran))
+#if !(defined(mipsFortran)||defined(DECFortran)||defined(vmsFortran)||defined(CONVEXFortran)||defined(PowerStationFortran)||defined(AbsoftUNIXFortran)||defined(AbsoftProFortran)||defined(SXFortran))
+/* If no Fortran compiler is given, we choose one for the machines we know. */
+#if defined(lynx) || defined(VAXUltrix)
+#define f2cFortran /* Lynx: Only support f2c at the moment.
+ VAXUltrix: f77 behaves like f2c.
+ Support f2c or f77 with gcc, vcc with f2c.
+ f77 with vcc works, missing link magic for f77 I/O.*/
+#endif
+#if defined(WIN32) && !defined(__CYGWIN__) /* 04/13/00 DM: Add these lines for NT */
+#define PowerStationFortran /* with PowerStationFortran and and Visual C++ */
+#define VISUAL_CPLUSPLUS
+#endif
+#if defined(g77Fortran) /* 11/03/97 PDW */
+#define f2cFortran
+#endif
+#if defined(__CYGWIN__) /* 04/11/02 LEB */
+#define f2cFortran
+#endif
+#if defined(__GNUC__) && defined(linux) /* 06/21/00 PDW */
+#define f2cFortran
+#endif
+#if defined(macintosh) /* 11/1999 */
+#define f2cFortran
+#endif
+#if defined(__APPLE__) /* 11/2002 */
+#define f2cFortran
+#endif
+#if defined(__hpux) /* 921107: Use __hpux instead of __hp9000s300 */
+#define hpuxFortran /* Should also allow hp9000s7/800 use.*/
+#endif
+#if defined(apollo)
+#define apolloFortran /* __CF__APOLLO67 also defines some behavior. */
+#endif
+#if defined(sun) || defined(__sun)
+#define sunFortran
+#endif
+#if defined(_IBMR2)
+#define IBMR2Fortran
+#endif
+#if defined(_CRAY)
+#define CRAYFortran /* _CRAYT3E also defines some behavior. */
+#endif
+#if defined(_SX)
+#define SXFortran
+#endif
+#if defined(mips) || defined(__mips)
+#define mipsFortran
+#endif
+#if defined(vms) || defined(__vms)
+#define vmsFortran
+#endif
+#if defined(__alpha) && defined(__unix__)
+#define DECFortran
+#endif
+#if defined(__convex__)
+#define CONVEXFortran
+#endif
+#if defined(VISUAL_CPLUSPLUS)
+#define PowerStationFortran
+#endif
+#endif /* ...Fortran */
+#endif /* ...Fortran */
+
+/* Split #if into 2 because some HP-UX can't handle long #if */
+#if !(defined(NAGf90Fortran)||defined(f2cFortran)||defined(hpuxFortran)||defined(apolloFortran)||defined(sunFortran)||defined(IBMR2Fortran)||defined(CRAYFortran))
+#if !(defined(mipsFortran)||defined(DECFortran)||defined(vmsFortran)||defined(CONVEXFortran)||defined(PowerStationFortran)||defined(AbsoftUNIXFortran)||defined(AbsoftProFortran)||defined(SXFortran))
+/* If your compiler barfs on ' #error', replace # with the trigraph for # */
+ #error "cfortran.h: Can't find your environment among:\
+ - MIPS cc and f77 2.0. (e.g. Silicon Graphics, DECstations, ...) \
+ - IBM AIX XL C and FORTRAN Compiler/6000 Version 01.01.0000.0000 \
+ - VAX VMS CC 3.1 and FORTRAN 5.4. \
+ - Alpha VMS DEC C 1.3 and DEC FORTRAN 6.0. \
+ - Alpha OSF DEC C and DEC Fortran for OSF/1 AXP Version 1.2 \
+ - Apollo DomainOS 10.2 (sys5.3) with f77 10.7 and cc 6.7. \
+ - CRAY \
+ - NEC SX-4 SUPER-UX \
+ - CONVEX \
+ - Sun \
+ - PowerStation Fortran with Visual C++ \
+ - HP9000s300/s700/s800 Latest test with: HP-UX A.08.07 A 9000/730 \
+ - LynxOS: cc or gcc with f2c. \
+ - VAXUltrix: vcc,cc or gcc with f2c. gcc or cc with f77. \
+ - f77 with vcc works; but missing link magic for f77 I/O. \
+ - NO fort. None of gcc, cc or vcc generate required names.\
+ - f2c : Use #define f2cFortran, or cc -Df2cFortran \
+ - NAG f90: Use #define NAGf90Fortran, or cc -DNAGf90Fortran \
+ - Absoft UNIX F77: Use #define AbsoftUNIXFortran or cc -DAbsoftUNIXFortran \
+ - Absoft Pro Fortran: Use #define AbsoftProFortran \
+ - Portland Group Fortran: Use #define pgiFortran"
+/* Compiler must throw us out at this point! */
+#endif
+#endif
+
+
+#if defined(VAXC) && !defined(__VAXC)
+#define OLD_VAXC
+#pragma nostandard /* Prevent %CC-I-PARAMNOTUSED. */
+#endif
+
+/* Throughout cfortran.h we use: UN = Uppercase Name. LN = Lowercase Name. */
+
+#if defined(f2cFortran) || defined(NAGf90Fortran) || defined(DECFortran) || defined(mipsFortran) || defined(apolloFortran) || defined(sunFortran) || defined(CONVEXFortran) || defined(SXFortran) || defined(appendus)
+#define CFC_(UN,LN) _(LN,_) /* Lowercase FORTRAN symbols. */
+#define orig_fcallsc(UN,LN) CFC_(UN,LN)
+#else
+#if defined(CRAYFortran) || defined(PowerStationFortran) || defined(AbsoftProFortran)
+#ifdef _CRAY /* (UN), not UN, circumvents CRAY preprocessor bug. */
+#define CFC_(UN,LN) (UN) /* Uppercase FORTRAN symbols. */
+#else /* At least VISUAL_CPLUSPLUS barfs on (UN), so need UN. */
+#define CFC_(UN,LN) UN /* Uppercase FORTRAN symbols. */
+#endif
+#define orig_fcallsc(UN,LN) CFC_(UN,LN) /* CRAY insists on arg.'s here. */
+#else /* For following machines one may wish to change the fcallsc default. */
+#define CF_SAME_NAMESPACE
+#ifdef vmsFortran
+#define CFC_(UN,LN) LN /* Either case FORTRAN symbols. */
+ /* BUT we usually use UN for C macro to FORTRAN routines, so use LN here,*/
+ /* because VAX/VMS doesn't do recursive macros. */
+#define orig_fcallsc(UN,LN) UN
+#else /* HP-UX without +ppu or IBMR2 without -qextname. NOT reccomended. */
+#define CFC_(UN,LN) LN /* Lowercase FORTRAN symbols. */
+#define orig_fcallsc(UN,LN) CFC_(UN,LN)
+#endif /* vmsFortran */
+#endif /* CRAYFortran PowerStationFortran */
+#endif /* ....Fortran */
+
+#define fcallsc(UN,LN) orig_fcallsc(UN,LN)
+#define preface_fcallsc(P,p,UN,LN) CFC_(_(P,UN),_(p,LN))
+#define append_fcallsc(P,p,UN,LN) CFC_(_(UN,P),_(LN,p))
+
+#define C_FUNCTION(UN,LN) fcallsc(UN,LN)
+#define FORTRAN_FUNCTION(UN,LN) CFC_(UN,LN)
+
+#ifndef COMMON_BLOCK
+#ifndef CONVEXFortran
+#ifndef CLIPPERFortran
+#if !(defined(AbsoftUNIXFortran)||defined(AbsoftProFortran))
+#define COMMON_BLOCK(UN,LN) CFC_(UN,LN)
+#else
+#define COMMON_BLOCK(UN,LN) _(_C,LN)
+#endif /* AbsoftUNIXFortran or AbsoftProFortran */
+#else
+#define COMMON_BLOCK(UN,LN) _(LN,__)
+#endif /* CLIPPERFortran */
+#else
+#define COMMON_BLOCK(UN,LN) _3(_,LN,_)
+#endif /* CONVEXFortran */
+#endif /* COMMON_BLOCK */
+
+#ifndef DOUBLE_PRECISION
+#if defined(CRAYFortran) && !defined(_CRAYT3E)
+#define DOUBLE_PRECISION long double
+#else
+#define DOUBLE_PRECISION double
+#endif
+#endif
+
+#ifndef FORTRAN_REAL
+#if defined(CRAYFortran) && defined(_CRAYT3E)
+#define FORTRAN_REAL double
+#else
+#define FORTRAN_REAL float
+#endif
+#endif
+
+#ifdef CRAYFortran
+#ifdef _CRAY
+#include <fortran.h>
+#else
+#include "fortran.h" /* i.e. if crosscompiling assume user has file. */
+#endif
+#define FLOATVVVVVVV_cfPP (FORTRAN_REAL *) /* Used for C calls FORTRAN. */
+/* CRAY's double==float but CRAY says pointers to doubles and floats are diff.*/
+#define VOIDP (void *) /* When FORTRAN calls C, we don't know if C routine
+ arg.'s have been declared float *, or double *. */
+#else
+#define FLOATVVVVVVV_cfPP
+#define VOIDP
+#endif
+
+#ifdef vmsFortran
+#if defined(vms) || defined(__vms)
+#include <descrip.h>
+#else
+#include "descrip.h" /* i.e. if crosscompiling assume user has file. */
+#endif
+#endif
+
+#ifdef sunFortran
+#if defined(sun) || defined(__sun)
+#include <math.h> /* Sun's FLOATFUNCTIONTYPE, ASSIGNFLOAT, RETURNFLOAT. */
+#else
+#include "math.h" /* i.e. if crosscompiling assume user has file. */
+#endif
+/* At least starting with the default C compiler SC3.0.1 of SunOS 5.3,
+ * FLOATFUNCTIONTYPE, ASSIGNFLOAT, RETURNFLOAT are not required and not in
+ * <math.h>, since sun C no longer promotes C float return values to doubles.
+ * Therefore, only use them if defined.
+ * Even if gcc is being used, assume that it exhibits the Sun C compiler
+ * behavior in order to be able to use *.o from the Sun C compiler.
+ * i.e. If FLOATFUNCTIONTYPE, etc. are in math.h, they required by gcc.
+ */
+#endif
+
+#ifndef apolloFortran
+#define COMMON_BLOCK_DEF(DEFINITION, NAME) DEFINITION NAME
+#define CF_NULL_PROTO
+#else /* HP doesn't understand #elif. */
+/* Without ANSI prototyping, Apollo promotes float functions to double. */
+/* Note that VAX/VMS, IBM, Mips choke on 'type function(...);' prototypes. */
+#define CF_NULL_PROTO ...
+#ifndef __CF__APOLLO67
+#define COMMON_BLOCK_DEF(DEFINITION, NAME) \
+ DEFINITION NAME __attribute((__section(NAME)))
+#else
+#define COMMON_BLOCK_DEF(DEFINITION, NAME) \
+ DEFINITION NAME #attribute[section(NAME)]
+#endif
+#endif
+
+#ifdef __cplusplus
+#undef CF_NULL_PROTO
+#define CF_NULL_PROTO ...
+#endif
+
+
+#ifndef USE_NEW_DELETE
+#ifdef __cplusplus
+#define USE_NEW_DELETE 1
+#else
+#define USE_NEW_DELETE 0
+#endif
+#endif
+#if USE_NEW_DELETE
+#define _cf_malloc(N) new char[N]
+#define _cf_free(P) delete[] P
+#else
+#define _cf_malloc(N) (char *)malloc(N)
+#define _cf_free(P) free(P)
+#endif
+
+#ifdef mipsFortran
+#define CF_DECLARE_GETARG int f77argc; char **f77argv
+#define CF_SET_GETARG(ARGC,ARGV) f77argc = ARGC; f77argv = ARGV
+#else
+#define CF_DECLARE_GETARG
+#define CF_SET_GETARG(ARGC,ARGV)
+#endif
+
+#ifdef OLD_VAXC /* Allow %CC-I-PARAMNOTUSED. */
+#pragma standard
+#endif
+
+#define AcfCOMMA ,
+#define AcfCOLON ;
+
+/*-------------------------------------------------------------------------*/
+
+/* UTILITIES USED WITHIN CFORTRAN.H */
+
+#define _cfMIN(A,B) (A<B?A:B)
+
+/* 970211 - XIX.145:
+ firstindexlength - better name is all_but_last_index_lengths
+ secondindexlength - better name is last_index_length
+ */
+#define firstindexlength(A) (sizeof(A[0])==1 ? 1 : (sizeof(A) / sizeof(A[0])) )
+#define secondindexlength(A) (sizeof(A[0])==1 ? sizeof(A) : sizeof(A[0]) )
+
+/* Behavior of FORTRAN LOGICAL. All machines' LOGICAL is same size as C's int.
+Conversion is automatic except for arrays which require F2CLOGICALV/C2FLOGICALV.
+f2c, MIPS f77 [DECstation, SGI], VAX Ultrix f77,
+HP-UX f77 : as in C.
+VAX/VMS FORTRAN, VAX Ultrix fort,
+Absoft Unix Fortran, IBM RS/6000 xlf : LS Bit = 0/1 = TRUE/FALSE.
+Apollo : neg. = TRUE, else FALSE.
+[Apollo accepts -1 as TRUE for function values, but NOT all other neg. values.]
+[DECFortran for Ultrix RISC is also called f77 but is the same as VAX/VMS.]
+[MIPS f77 treats .eqv./.neqv. as .eq./.ne. and hence requires LOGICAL_STRICT.]*/
+
+#if defined(NAGf90Fortran) || defined(f2cFortran) || defined(mipsFortran) || defined(PowerStationFortran) || defined(hpuxFortran800) || defined(AbsoftUNIXFortran) || defined(AbsoftProFortran) || defined(SXFortran)
+/* SX/PowerStationFortran have 0 and 1 defined, others are neither T nor F. */
+/* hpuxFortran800 has 0 and 0x01000000 defined. Others are unknown. */
+#define LOGICAL_STRICT /* Other Fortran have .eqv./.neqv. == .eq./.ne. */
+#endif
+
+#define C2FLOGICALV(A,I) \
+ do {int __i; for(__i=0;__i<I;__i++) A[__i]=C2FLOGICAL(A[__i]); } while (0)
+#define F2CLOGICALV(A,I) \
+ do {int __i; for(__i=0;__i<I;__i++) A[__i]=F2CLOGICAL(A[__i]); } while (0)
+
+#if defined(apolloFortran)
+#define C2FLOGICAL(L) ((L)?-1:(L)&~((unsigned)1<<sizeof(int)*8-1))
+#define F2CLOGICAL(L) ((L)<0?(L):0)
+#else
+#if defined(CRAYFortran)
+#define C2FLOGICAL(L) _btol(L)
+#define F2CLOGICAL(L) _ltob(&(L)) /* Strangely _ltob() expects a pointer. */
+#else
+#if defined(IBMR2Fortran) || defined(vmsFortran) || defined(DECFortran) || defined(AbsoftUNIXFortran)
+/* How come no AbsoftProFortran ? */
+#define C2FLOGICAL(L) ((L)?(L)|1:(L)&~(int)1)
+#define F2CLOGICAL(L) ((L)&1?(L):0)
+#else
+#if defined(CONVEXFortran)
+#define C2FLOGICAL(L) ((L) ? ~0 : 0 )
+#define F2CLOGICAL(L) (L)
+#else /* others evaluate LOGICALs as for C. */
+#define C2FLOGICAL(L) (L)
+#define F2CLOGICAL(L) (L)
+#ifndef LOGICAL_STRICT
+#undef C2FLOGICALV
+#undef F2CLOGICALV
+#define C2FLOGICALV(A,I)
+#define F2CLOGICALV(A,I)
+#endif /* LOGICAL_STRICT */
+#endif /* CONVEXFortran || All Others */
+#endif /* IBMR2Fortran vmsFortran DECFortran AbsoftUNIXFortran */
+#endif /* CRAYFortran */
+#endif /* apolloFortran */
+
+/* 970514 - In addition to CRAY, there may be other machines
+ for which LOGICAL_STRICT makes no sense. */
+#if defined(LOGICAL_STRICT) && !defined(CRAYFortran)
+/* Force C2FLOGICAL to generate only the values for either .TRUE. or .FALSE.
+ SX/PowerStationFortran only have 0 and 1 defined.
+ Elsewhere, only needed if you want to do:
+ logical lvariable
+ if (lvariable .eq. .true.) then ! (1)
+ instead of
+ if (lvariable .eqv. .true.) then ! (2)
+ - (1) may not even be FORTRAN/77 and that Apollo's f77 and IBM's xlf
+ refuse to compile (1), so you are probably well advised to stay away from
+ (1) and from LOGICAL_STRICT.
+ - You pay a (slight) performance penalty for using LOGICAL_STRICT. */
+#undef C2FLOGICAL
+#ifdef hpuxFortran800
+#define C2FLOGICAL(L) ((L)?0x01000000:0)
+#else
+#if defined(apolloFortran) || defined(vmsFortran) || defined(DECFortran)
+#define C2FLOGICAL(L) ((L)?-1:0) /* These machines use -1/0 for .true./.false.*/
+#else
+#define C2FLOGICAL(L) ((L)? 1:0) /* All others use +1/0 for .true./.false.*/
+#endif
+#endif
+#endif /* LOGICAL_STRICT */
+
+/* Convert a vector of C strings into FORTRAN strings. */
+#ifndef __CF__KnR
+static char *c2fstrv(char* cstr, char *fstr, int elem_len, int sizeofcstr)
+#else
+static char *c2fstrv( cstr, fstr, elem_len, sizeofcstr)
+ char* cstr; char *fstr; int elem_len; int sizeofcstr;
+#endif
+{ int i,j;
+/* elem_len includes \0 for C strings. Fortran strings don't have term. \0.
+ Useful size of string must be the same in both languages. */
+for (i=0; i<sizeofcstr/elem_len; i++) {
+ for (j=1; j<elem_len && *cstr; j++) *fstr++ = *cstr++;
+ cstr += 1+elem_len-j;
+ for (; j<elem_len; j++) *fstr++ = ' ';
+} /* 95109 - Seems to be returning the original fstr. */
+return fstr-sizeofcstr+sizeofcstr/elem_len; }
+
+/* Convert a vector of FORTRAN strings into C strings. */
+#ifndef __CF__KnR
+static char *f2cstrv(char *fstr, char* cstr, int elem_len, int sizeofcstr)
+#else
+static char *f2cstrv( fstr, cstr, elem_len, sizeofcstr)
+ char *fstr; char* cstr; int elem_len; int sizeofcstr;
+#endif
+{ int i,j;
+/* elem_len includes \0 for C strings. Fortran strings don't have term. \0.
+ Useful size of string must be the same in both languages. */
+cstr += sizeofcstr;
+fstr += sizeofcstr - sizeofcstr/elem_len;
+for (i=0; i<sizeofcstr/elem_len; i++) {
+ *--cstr = '\0';
+ for (j=1; j<elem_len; j++) *--cstr = *--fstr;
+} return cstr; }
+
+/* kill the trailing char t's in string s. */
+#ifndef __CF__KnR
+static char *kill_trailing(char *s, char t)
+#else
+static char *kill_trailing( s, t) char *s; char t;
+#endif
+{char *e;
+e = s + strlen(s);
+if (e>s) { /* Need this to handle NULL string.*/
+ while (e>s && *--e==t); /* Don't follow t's past beginning. */
+ e[*e==t?0:1] = '\0'; /* Handle s[0]=t correctly. */
+} return s; }
+
+/* kill_trailingn(s,t,e) will kill the trailing t's in string s. e normally
+points to the terminating '\0' of s, but may actually point to anywhere in s.
+s's new '\0' will be placed at e or earlier in order to remove any trailing t's.
+If e<s string s is left unchanged. */
+#ifndef __CF__KnR
+static char *kill_trailingn(char *s, char t, char *e)
+#else
+static char *kill_trailingn( s, t, e) char *s; char t; char *e;
+#endif
+{
+if (e==s) *e = '\0'; /* Kill the string makes sense here.*/
+else if (e>s) { /* Watch out for neg. length string.*/
+ while (e>s && *--e==t); /* Don't follow t's past beginning. */
+ e[*e==t?0:1] = '\0'; /* Handle s[0]=t correctly. */
+} return s; }
+
+/* Note the following assumes that any element which has t's to be chopped off,
+does indeed fill the entire element. */
+#ifndef __CF__KnR
+static char *vkill_trailing(char* cstr, int elem_len, int sizeofcstr, char t)
+#else
+static char *vkill_trailing( cstr, elem_len, sizeofcstr, t)
+ char* cstr; int elem_len; int sizeofcstr; char t;
+#endif
+{ int i;
+for (i=0; i<sizeofcstr/elem_len; i++) /* elem_len includes \0 for C strings. */
+ kill_trailingn(cstr+elem_len*i,t,cstr+elem_len*(i+1)-1);
+return cstr; }
+
+#ifdef vmsFortran
+typedef struct dsc$descriptor_s fstring;
+#define DSC$DESCRIPTOR_A(DIMCT) \
+struct { \
+ unsigned short dsc$w_length; unsigned char dsc$b_dtype; \
+ unsigned char dsc$b_class; char *dsc$a_pointer; \
+ char dsc$b_scale; unsigned char dsc$b_digits; \
+ struct { \
+ unsigned : 3; unsigned dsc$v_fl_binscale : 1; \
+ unsigned dsc$v_fl_redim : 1; unsigned dsc$v_fl_column : 1; \
+ unsigned dsc$v_fl_coeff : 1; unsigned dsc$v_fl_bounds : 1; \
+ } dsc$b_aflags; \
+ unsigned char dsc$b_dimct; unsigned long dsc$l_arsize; \
+ char *dsc$a_a0; long dsc$l_m [DIMCT]; \
+ struct { \
+ long dsc$l_l; long dsc$l_u; \
+ } dsc$bounds [DIMCT]; \
+}
+typedef DSC$DESCRIPTOR_A(1) fstringvector;
+/*typedef DSC$DESCRIPTOR_A(2) fstringarrarr;
+ typedef DSC$DESCRIPTOR_A(3) fstringarrarrarr;*/
+#define initfstr(F,C,ELEMNO,ELEMLEN) \
+( (F).dsc$l_arsize= ( (F).dsc$w_length =(ELEMLEN) ) \
+ *( (F).dsc$l_m[0]=(F).dsc$bounds[0].dsc$l_u=(ELEMNO) ), \
+ (F).dsc$a_a0 = ( (F).dsc$a_pointer=(C) ) - (F).dsc$w_length ,(F))
+
+#endif /* PDW: 2/10/98 -- Let VMS see NUM_ELEMS definitions */
+#define _NUM_ELEMS -1
+#define _NUM_ELEM_ARG -2
+#define NUM_ELEMS(A) A,_NUM_ELEMS
+#define NUM_ELEM_ARG(B) *_2(A,B),_NUM_ELEM_ARG
+#define TERM_CHARS(A,B) A,B
+#ifndef __CF__KnR
+static int num_elem(char *strv, unsigned elem_len, int term_char, int num_term)
+#else
+static int num_elem( strv, elem_len, term_char, num_term)
+ char *strv; unsigned elem_len; int term_char; int num_term;
+#endif
+/* elem_len is the number of characters in each element of strv, the FORTRAN
+vector of strings. The last element of the vector must begin with at least
+num_term term_char characters, so that this routine can determine how
+many elements are in the vector. */
+{
+unsigned num,i;
+if (num_term == _NUM_ELEMS || num_term == _NUM_ELEM_ARG)
+ return term_char;
+if (num_term <=0) num_term = (int)elem_len;
+for (num=0; ; num++) {
+ for (i=0; i<(unsigned)num_term && *strv==term_char; i++,strv++);
+ if (i==(unsigned)num_term) break;
+ else strv += elem_len-i;
+}
+return (int)num;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* UTILITIES FOR C TO USE STRINGS IN FORTRAN COMMON BLOCKS */
+
+/* C string TO Fortran Common Block STRing. */
+/* DIM is the number of DIMensions of the array in terms of strings, not
+ characters. e.g. char a[12] has DIM = 0, char a[12][4] has DIM = 1, etc. */
+#define C2FCBSTR(CSTR,FSTR,DIM) \
+ c2fstrv((char *)CSTR, (char *)FSTR, sizeof(FSTR)/cfelementsof(FSTR,DIM)+1, \
+ sizeof(FSTR)+cfelementsof(FSTR,DIM))
+
+/* Fortran Common Block string TO C STRing. */
+#define FCB2CSTR(FSTR,CSTR,DIM) \
+ vkill_trailing(f2cstrv((char *)FSTR, (char *)CSTR, \
+ sizeof(FSTR)/cfelementsof(FSTR,DIM)+1, \
+ sizeof(FSTR)+cfelementsof(FSTR,DIM)), \
+ sizeof(FSTR)/cfelementsof(FSTR,DIM)+1, \
+ sizeof(FSTR)+cfelementsof(FSTR,DIM), ' ')
+
+#define cfDEREFERENCE0
+#define cfDEREFERENCE1 *
+#define cfDEREFERENCE2 **
+#define cfDEREFERENCE3 ***
+#define cfDEREFERENCE4 ****
+#define cfDEREFERENCE5 *****
+#define cfelementsof(A,D) (sizeof(A)/sizeof(_(cfDEREFERENCE,D)(A)))
+
+/*-------------------------------------------------------------------------*/
+
+/* UTILITIES FOR C TO CALL FORTRAN SUBROUTINES */
+
+/* Define lookup tables for how to handle the various types of variables. */
+
+#ifdef OLD_VAXC /* Prevent %CC-I-PARAMNOTUSED. */
+#pragma nostandard
+#endif
+
+#define ZTRINGV_NUM(I) I
+#define ZTRINGV_ARGFP(I) (*(_2(A,I))) /* Undocumented. For PINT, etc. */
+#define ZTRINGV_ARGF(I) _2(A,I)
+#ifdef CFSUBASFUN
+#define ZTRINGV_ARGS(I) ZTRINGV_ARGF(I)
+#else
+#define ZTRINGV_ARGS(I) _2(B,I)
+#endif
+
+#define PBYTE_cfVP(A,B) PINT_cfVP(A,B)
+#define PDOUBLE_cfVP(A,B)
+#define PFLOAT_cfVP(A,B)
+#ifdef ZTRINGV_ARGS_allows_Pvariables
+/* This allows Pvariables for ARGS. ARGF machinery is above ARGFP.
+ * B is not needed because the variable may be changed by the Fortran routine,
+ * but because B is the only way to access an arbitrary macro argument. */
+#define PINT_cfVP(A,B) int B = (int)A; /* For ZSTRINGV_ARGS */
+#else
+#define PINT_cfVP(A,B)
+#endif
+#define PLOGICAL_cfVP(A,B) int *B; /* Returning LOGICAL in FUNn and SUBn */
+#define PLONG_cfVP(A,B) PINT_cfVP(A,B)
+#define PSHORT_cfVP(A,B) PINT_cfVP(A,B)
+
+#define VCF_INT_S(T,A,B) _(T,VVVVVVV_cfTYPE) B = A;
+#define VCF_INT_F(T,A,B) _(T,_cfVCF)(A,B)
+/* _cfVCF table is directly mapped to _cfCCC table. */
+#define BYTE_cfVCF(A,B)
+#define DOUBLE_cfVCF(A,B)
+#if !defined(__CF__KnR)
+#define FLOAT_cfVCF(A,B)
+#else
+#define FLOAT_cfVCF(A,B) FORTRAN_REAL B = A;
+#endif
+#define INT_cfVCF(A,B)
+#define LOGICAL_cfVCF(A,B)
+#define LONG_cfVCF(A,B)
+#define SHORT_cfVCF(A,B)
+
+/* 980416
+ Cast (void (*)(CF_NULL_PROTO)) causes SunOS CC 4.2 occasionally to barf,
+ while the following equivalent typedef is fine.
+ For consistency use the typedef on all machines.
+ */
+typedef void (*cfCAST_FUNCTION)(CF_NULL_PROTO);
+
+#define VCF(TN,I) _Icf4(4,V,TN,_(A,I),_(B,I),F)
+#define VVCF(TN,AI,BI) _Icf4(4,V,TN,AI,BI,S)
+#define INT_cfV(T,A,B,F) _(VCF_INT_,F)(T,A,B)
+#define INTV_cfV(T,A,B,F)
+#define INTVV_cfV(T,A,B,F)
+#define INTVVV_cfV(T,A,B,F)
+#define INTVVVV_cfV(T,A,B,F)
+#define INTVVVVV_cfV(T,A,B,F)
+#define INTVVVVVV_cfV(T,A,B,F)
+#define INTVVVVVVV_cfV(T,A,B,F)
+#define PINT_cfV( T,A,B,F) _(T,_cfVP)(A,B)
+#define PVOID_cfV( T,A,B,F)
+#if defined(apolloFortran) || defined(hpuxFortran800) || defined(AbsoftUNIXFortran) || defined(AbsoftProFortran)
+#define ROUTINE_cfV(T,A,B,F) void (*B)(CF_NULL_PROTO) = (cfCAST_FUNCTION)A;
+#else
+#define ROUTINE_cfV(T,A,B,F)
+#endif
+#define SIMPLE_cfV(T,A,B,F)
+#ifdef vmsFortran
+#define STRING_cfV(T,A,B,F) static struct {fstring f; unsigned clen;} B = \
+ {{0,DSC$K_DTYPE_T,DSC$K_CLASS_S,NULL},0};
+#define PSTRING_cfV(T,A,B,F) static fstring B={0,DSC$K_DTYPE_T,DSC$K_CLASS_S,NULL};
+#define STRINGV_cfV(T,A,B,F) static fstringvector B = \
+ {sizeof(A),DSC$K_DTYPE_T,DSC$K_CLASS_A,NULL,0,0,{0,0,1,1,1},1,0,NULL,0,{1,0}};
+#define PSTRINGV_cfV(T,A,B,F) static fstringvector B = \
+ {0,DSC$K_DTYPE_T,DSC$K_CLASS_A,NULL,0,0,{0,0,1,1,1},1,0,NULL,0,{1,0}};
+#else
+#define STRING_cfV(T,A,B,F) struct {unsigned int clen, flen; char *nombre;} B;
+#define STRINGV_cfV(T,A,B,F) struct {char *s, *fs; unsigned flen; char *nombre;} B;
+#define PSTRING_cfV(T,A,B,F) int B;
+#define PSTRINGV_cfV(T,A,B,F) struct{char *fs; unsigned int sizeofA,flen;}B;
+#endif
+#define ZTRINGV_cfV(T,A,B,F) STRINGV_cfV(T,A,B,F)
+#define PZTRINGV_cfV(T,A,B,F) PSTRINGV_cfV(T,A,B,F)
+
+/* Note that the actions of the A table were performed inside the AA table.
+ VAX Ultrix vcc, and HP-UX cc, didn't evaluate arguments to functions left to
+ right, so we had to split the original table into the current robust two. */
+#define ACF(NAME,TN,AI,I) _(TN,_cfSTR)(4,A,NAME,I,AI,_(B,I),0)
+#define DEFAULT_cfA(M,I,A,B)
+#define LOGICAL_cfA(M,I,A,B) B=C2FLOGICAL(B);
+#define PLOGICAL_cfA(M,I,A,B) A=C2FLOGICAL(A);
+#define STRING_cfA(M,I,A,B) STRING_cfC(M,I,A,B,sizeof(A))
+#define PSTRING_cfA(M,I,A,B) PSTRING_cfC(M,I,A,B,sizeof(A))
+#ifdef vmsFortran
+#define AATRINGV_cfA( A,B, sA,filA,silA) \
+ initfstr(B,_cf_malloc((sA)-(filA)),(filA),(silA)-1), \
+ c2fstrv(A,B.dsc$a_pointer,(silA),(sA));
+#define APATRINGV_cfA( A,B, sA,filA,silA) \
+ initfstr(B,A,(filA),(silA)-1),c2fstrv(A,A,(silA),(sA));
+#else
+#define AATRINGV_cfA( A,B, sA,filA,silA) \
+ (B.s=_cf_malloc((sA)-(filA)),B.fs=c2fstrv(A,B.s,(B.flen=(silA)-1)+1,(sA)));
+#define APATRINGV_cfA( A,B, sA,filA,silA) \
+ B.fs=c2fstrv(A,A,(B.flen=(silA)-1)+1,B.sizeofA=(sA));
+#endif
+#define STRINGV_cfA(M,I,A,B) \
+ AATRINGV_cfA((char *)A,B,sizeof(A),firstindexlength(A),secondindexlength(A))
+#define PSTRINGV_cfA(M,I,A,B) \
+ APATRINGV_cfA((char *)A,B,sizeof(A),firstindexlength(A),secondindexlength(A))
+#define ZTRINGV_cfA(M,I,A,B) AATRINGV_cfA( (char *)A,B, \
+ (_3(M,_ELEMS_,I))*(( _3(M,_ELEMLEN_,I))+1), \
+ (_3(M,_ELEMS_,I)),(_3(M,_ELEMLEN_,I))+1)
+#define PZTRINGV_cfA(M,I,A,B) APATRINGV_cfA( (char *)A,B, \
+ (_3(M,_ELEMS_,I))*(( _3(M,_ELEMLEN_,I))+1), \
+ (_3(M,_ELEMS_,I)),(_3(M,_ELEMLEN_,I))+1)
+
+#define PBYTE_cfAAP(A,B) &A
+#define PDOUBLE_cfAAP(A,B) &A
+#define PFLOAT_cfAAP(A,B) FLOATVVVVVVV_cfPP &A
+#define PINT_cfAAP(A,B) &A
+#define PLOGICAL_cfAAP(A,B) B= &A /* B used to keep a common W table. */
+#define PLONG_cfAAP(A,B) &A
+#define PSHORT_cfAAP(A,B) &A
+
+#define AACF(TN,AI,I,C) _SEP_(TN,C,cfCOMMA) _Icf(3,AA,TN,AI,_(B,I))
+#define INT_cfAA(T,A,B) &B
+#define INTV_cfAA(T,A,B) _(T,VVVVVV_cfPP) A
+#define INTVV_cfAA(T,A,B) _(T,VVVVV_cfPP) A[0]
+#define INTVVV_cfAA(T,A,B) _(T,VVVV_cfPP) A[0][0]
+#define INTVVVV_cfAA(T,A,B) _(T,VVV_cfPP) A[0][0][0]
+#define INTVVVVV_cfAA(T,A,B) _(T,VV_cfPP) A[0][0][0][0]
+#define INTVVVVVV_cfAA(T,A,B) _(T,V_cfPP) A[0][0][0][0][0]
+#define INTVVVVVVV_cfAA(T,A,B) _(T,_cfPP) A[0][0][0][0][0][0]
+#define PINT_cfAA(T,A,B) _(T,_cfAAP)(A,B)
+#define PVOID_cfAA(T,A,B) (void *) A
+#if defined(apolloFortran) || defined(hpuxFortran800) || defined(AbsoftUNIXFortran)
+#define ROUTINE_cfAA(T,A,B) &B
+#else
+#define ROUTINE_cfAA(T,A,B) (cfCAST_FUNCTION)A
+#endif
+#define STRING_cfAA(T,A,B) STRING_cfCC(T,A,B)
+#define PSTRING_cfAA(T,A,B) PSTRING_cfCC(T,A,B)
+#ifdef vmsFortran
+#define STRINGV_cfAA(T,A,B) &B
+#else
+#ifdef CRAYFortran
+#define STRINGV_cfAA(T,A,B) _cptofcd(B.fs,B.flen)
+#else
+#define STRINGV_cfAA(T,A,B) B.fs
+#endif
+#endif
+#define PSTRINGV_cfAA(T,A,B) STRINGV_cfAA(T,A,B)
+#define ZTRINGV_cfAA(T,A,B) STRINGV_cfAA(T,A,B)
+#define PZTRINGV_cfAA(T,A,B) STRINGV_cfAA(T,A,B)
+
+#if defined(vmsFortran) || defined(CRAYFortran)
+#define JCF(TN,I)
+#define KCF(TN,I)
+#else
+#define JCF(TN,I) _(TN,_cfSTR)(1,J,_(B,I), 0,0,0,0)
+#if defined(AbsoftUNIXFortran)
+#define DEFAULT_cfJ(B) ,0
+#else
+#define DEFAULT_cfJ(B)
+#endif
+#define LOGICAL_cfJ(B) DEFAULT_cfJ(B)
+#define PLOGICAL_cfJ(B) DEFAULT_cfJ(B)
+#define STRING_cfJ(B) ,B.flen
+#define PSTRING_cfJ(B) ,B
+#define STRINGV_cfJ(B) STRING_cfJ(B)
+#define PSTRINGV_cfJ(B) STRING_cfJ(B)
+#define ZTRINGV_cfJ(B) STRING_cfJ(B)
+#define PZTRINGV_cfJ(B) STRING_cfJ(B)
+
+/* KCF is identical to DCF, except that KCF ZTRING is not empty. */
+#define KCF(TN,I) _(TN,_cfSTR)(1,KK,_(B,I), 0,0,0,0)
+#if defined(AbsoftUNIXFortran)
+#define DEFAULT_cfKK(B) , unsigned B
+#else
+#define DEFAULT_cfKK(B)
+#endif
+#define LOGICAL_cfKK(B) DEFAULT_cfKK(B)
+#define PLOGICAL_cfKK(B) DEFAULT_cfKK(B)
+#define STRING_cfKK(B) , unsigned B
+#define PSTRING_cfKK(B) STRING_cfKK(B)
+#define STRINGV_cfKK(B) STRING_cfKK(B)
+#define PSTRINGV_cfKK(B) STRING_cfKK(B)
+#define ZTRINGV_cfKK(B) STRING_cfKK(B)
+#define PZTRINGV_cfKK(B) STRING_cfKK(B)
+#endif
+
+#define WCF(TN,AN,I) _(TN,_cfSTR)(2,W,AN,_(B,I), 0,0,0)
+#define DEFAULT_cfW(A,B)
+#define LOGICAL_cfW(A,B)
+#define PLOGICAL_cfW(A,B) *B=F2CLOGICAL(*B);
+#define STRING_cfW(A,B) (B.nombre=A,B.nombre[B.clen]!='\0'?B.nombre[B.clen]='\0':0); /* A?="constnt"*/
+#define PSTRING_cfW(A,B) kill_trailing(A,' ');
+#ifdef vmsFortran
+#define STRINGV_cfW(A,B) _cf_free(B.dsc$a_pointer);
+#define PSTRINGV_cfW(A,B) \
+ vkill_trailing(f2cstrv((char*)A, (char*)A, \
+ B.dsc$w_length+1, B.dsc$l_arsize+B.dsc$l_m[0]), \
+ B.dsc$w_length+1, B.dsc$l_arsize+B.dsc$l_m[0], ' ');
+#else
+#define STRINGV_cfW(A,B) _cf_free(B.s);
+#define PSTRINGV_cfW(A,B) vkill_trailing( \
+ f2cstrv((char*)A,(char*)A,B.flen+1,B.sizeofA), B.flen+1,B.sizeofA,' ');
+#endif
+#define ZTRINGV_cfW(A,B) STRINGV_cfW(A,B)
+#define PZTRINGV_cfW(A,B) PSTRINGV_cfW(A,B)
+
+#define NCF(TN,I,C) _SEP_(TN,C,cfCOMMA) _Icf(2,N,TN,_(A,I),0)
+#define NNCF(TN,I,C) UUCF(TN,I,C)
+#define NNNCF(TN,I,C) _SEP_(TN,C,cfCOLON) _Icf(2,N,TN,_(A,I),0)
+#define INT_cfN(T,A) _(T,VVVVVVV_cfTYPE) * A
+#define INTV_cfN(T,A) _(T,VVVVVV_cfTYPE) * A
+#define INTVV_cfN(T,A) _(T,VVVVV_cfTYPE) * A
+#define INTVVV_cfN(T,A) _(T,VVVV_cfTYPE) * A
+#define INTVVVV_cfN(T,A) _(T,VVV_cfTYPE) * A
+#define INTVVVVV_cfN(T,A) _(T,VV_cfTYPE) * A
+#define INTVVVVVV_cfN(T,A) _(T,V_cfTYPE) * A
+#define INTVVVVVVV_cfN(T,A) _(T,_cfTYPE) * A
+#define PINT_cfN(T,A) _(T,_cfTYPE) * A
+#define PVOID_cfN(T,A) void * A
+#if defined(apolloFortran) || defined(hpuxFortran800) || defined(AbsoftUNIXFortran)
+#define ROUTINE_cfN(T,A) void (**A)(CF_NULL_PROTO)
+#else
+#define ROUTINE_cfN(T,A) void ( *A)(CF_NULL_PROTO)
+#endif
+#ifdef vmsFortran
+#define STRING_cfN(T,A) fstring * A
+#define STRINGV_cfN(T,A) fstringvector * A
+#else
+#ifdef CRAYFortran
+#define STRING_cfN(T,A) _fcd A
+#define STRINGV_cfN(T,A) _fcd A
+#else
+#define STRING_cfN(T,A) char * A
+#define STRINGV_cfN(T,A) char * A
+#endif
+#endif
+#define PSTRING_cfN(T,A) STRING_cfN(T,A) /* CRAY insists on arg.'s here. */
+#define PNSTRING_cfN(T,A) STRING_cfN(T,A) /* CRAY insists on arg.'s here. */
+#define PPSTRING_cfN(T,A) STRING_cfN(T,A) /* CRAY insists on arg.'s here. */
+#define PSTRINGV_cfN(T,A) STRINGV_cfN(T,A)
+#define ZTRINGV_cfN(T,A) STRINGV_cfN(T,A)
+#define PZTRINGV_cfN(T,A) PSTRINGV_cfN(T,A)
+
+
+/* Apollo 6.7, CRAY, old Sun, VAX/Ultrix vcc/cc and new ultrix
+ can't hack more than 31 arg's.
+ e.g. ultrix >= 4.3 gives message:
+ zow35> cc -c -DDECFortran cfortest.c
+ cfe: Fatal: Out of memory: cfortest.c
+ zow35>
+ Old __hpux had the problem, but new 'HP-UX A.09.03 A 9000/735' is fine
+ if using -Aa, otherwise we have a problem.
+ */
+#ifndef MAX_PREPRO_ARGS
+#if !defined(__GNUC__) && (defined(VAXUltrix) || defined(__CF__APOLLO67) || (defined(sun)&&!defined(__sun)) || defined(_CRAY) || defined(__ultrix__) || (defined(__hpux)&&defined(__CF__KnR)))
+#define MAX_PREPRO_ARGS 31
+#else
+#define MAX_PREPRO_ARGS 99
+#endif
+#endif
+
+#if defined(AbsoftUNIXFortran) || defined(AbsoftProFortran)
+/* In addition to explicit Absoft stuff, only Absoft requires:
+ - DEFAULT coming from _cfSTR.
+ DEFAULT could have been called e.g. INT, but keep it for clarity.
+ - M term in CFARGT14 and CFARGT14FS.
+ */
+#define ABSOFT_cf1(T0) _(T0,_cfSTR)(0,ABSOFT1,0,0,0,0,0)
+#define ABSOFT_cf2(T0) _(T0,_cfSTR)(0,ABSOFT2,0,0,0,0,0)
+#define ABSOFT_cf3(T0) _(T0,_cfSTR)(0,ABSOFT3,0,0,0,0,0)
+#define DEFAULT_cfABSOFT1
+#define LOGICAL_cfABSOFT1
+#define STRING_cfABSOFT1 ,MAX_LEN_FORTRAN_FUNCTION_STRING
+#define DEFAULT_cfABSOFT2
+#define LOGICAL_cfABSOFT2
+#define STRING_cfABSOFT2 ,unsigned D0
+#define DEFAULT_cfABSOFT3
+#define LOGICAL_cfABSOFT3
+#define STRING_cfABSOFT3 ,D0
+#else
+#define ABSOFT_cf1(T0)
+#define ABSOFT_cf2(T0)
+#define ABSOFT_cf3(T0)
+#endif
+
+/* _Z introduced to cicumvent IBM and HP silly preprocessor warning.
+ e.g. "Macro CFARGT14 invoked with a null argument."
+ */
+#define _Z
+
+#define CFARGT14S(S,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE) \
+ S(T1,1) S(T2,2) S(T3,3) S(T4,4) S(T5,5) S(T6,6) S(T7,7) \
+ S(T8,8) S(T9,9) S(TA,10) S(TB,11) S(TC,12) S(TD,13) S(TE,14)
+#define CFARGT27S(S,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR) \
+ S(T1,1) S(T2,2) S(T3,3) S(T4,4) S(T5,5) S(T6,6) S(T7,7) \
+ S(T8,8) S(T9,9) S(TA,10) S(TB,11) S(TC,12) S(TD,13) S(TE,14) \
+ S(TF,15) S(TG,16) S(TH,17) S(TI,18) S(TJ,19) S(TK,20) S(TL,21) \
+ S(TM,22) S(TN,23) S(TO,24) S(TP,25) S(TQ,26) S(TR,27)
+
+#define CFARGT14FS(F,S,M,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE) \
+ F(T1,1,0) F(T2,2,1) F(T3,3,1) F(T4,4,1) F(T5,5,1) F(T6,6,1) F(T7,7,1) \
+ F(T8,8,1) F(T9,9,1) F(TA,10,1) F(TB,11,1) F(TC,12,1) F(TD,13,1) F(TE,14,1) \
+ M CFARGT14S(S,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)
+#define CFARGT27FS(F,S,M,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR) \
+ F(T1,1,0) F(T2,2,1) F(T3,3,1) F(T4,4,1) F(T5,5,1) F(T6,6,1) F(T7,7,1) \
+ F(T8,8,1) F(T9,9,1) F(TA,10,1) F(TB,11,1) F(TC,12,1) F(TD,13,1) F(TE,14,1) \
+ F(TF,15,1) F(TG,16,1) F(TH,17,1) F(TI,18,1) F(TJ,19,1) F(TK,20,1) F(TL,21,1) \
+ F(TM,22,1) F(TN,23,1) F(TO,24,1) F(TP,25,1) F(TQ,26,1) F(TR,27,1) \
+ M CFARGT27S(S,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR)
+
+#if !(defined(PowerStationFortran)||defined(hpuxFortran800))
+/* Old CFARGT14 -> CFARGT14FS as seen below, for Absoft cross-compile yields:
+ SunOS> cc -c -Xa -DAbsoftUNIXFortran c.c
+ "c.c", line 406: warning: argument mismatch
+ Haven't checked if this is ANSI C or a SunOS bug. SunOS -Xs works ok.
+ Behavior is most clearly seen in example:
+ #define A 1 , 2
+ #define C(X,Y,Z) x=X. y=Y. z=Z.
+ #define D(X,Y,Z) C(X,Y,Z)
+ D(x,A,z)
+ Output from preprocessor is: x = x . y = 1 . z = 2 .
+ #define CFARGT14(F,S,M,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE) \
+ CFARGT14FS(F,S,M,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)
+*/
+#define CFARGT14(F,S,M,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE) \
+ F(T1,1,0) F(T2,2,1) F(T3,3,1) F(T4,4,1) F(T5,5,1) F(T6,6,1) F(T7,7,1) \
+ F(T8,8,1) F(T9,9,1) F(TA,10,1) F(TB,11,1) F(TC,12,1) F(TD,13,1) F(TE,14,1) \
+ M CFARGT14S(S,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)
+#define CFARGT27(F,S,M,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR) \
+ F(T1,1,0) F(T2,2,1) F(T3,3,1) F(T4,4,1) F(T5,5,1) F(T6,6,1) F(T7,7,1) \
+ F(T8,8,1) F(T9,9,1) F(TA,10,1) F(TB,11,1) F(TC,12,1) F(TD,13,1) F(TE,14,1) \
+ F(TF,15,1) F(TG,16,1) F(TH,17,1) F(TI,18,1) F(TJ,19,1) F(TK,20,1) F(TL,21,1) \
+ F(TM,22,1) F(TN,23,1) F(TO,24,1) F(TP,25,1) F(TQ,26,1) F(TR,27,1) \
+ M CFARGT27S(S,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR)
+
+#define CFARGT20(F,S,M,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK) \
+ F(T1,1,0) F(T2,2,1) F(T3,3,1) F(T4,4,1) F(T5,5,1) F(T6,6,1) F(T7,7,1) \
+ F(T8,8,1) F(T9,9,1) F(TA,10,1) F(TB,11,1) F(TC,12,1) F(TD,13,1) F(TE,14,1) \
+ F(TF,15,1) F(TG,16,1) F(TH,17,1) F(TI,18,1) F(TJ,19,1) F(TK,20,1) \
+ S(T1,1) S(T2,2) S(T3,3) S(T4,4) S(T5,5) S(T6,6) S(T7,7) \
+ S(T8,8) S(T9,9) S(TA,10) S(TB,11) S(TC,12) S(TD,13) S(TE,14) \
+ S(TF,15) S(TG,16) S(TH,17) S(TI,18) S(TJ,19) S(TK,20)
+#define CFARGTA14(F,S,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE) \
+ F(T1,A1,1,0) F(T2,A2,2,1) F(T3,A3,3,1) F(T4,A4,4,1) F(T5,A5,5,1) F(T6,A6,6,1) \
+ F(T7,A7,7,1) F(T8,A8,8,1) F(T9,A9,9,1) F(TA,AA,10,1) F(TB,AB,11,1) F(TC,AC,12,1) \
+ F(TD,AD,13,1) F(TE,AE,14,1) S(T1,1) S(T2,2) S(T3,3) S(T4,4) \
+ S(T5,5) S(T6,6) S(T7,7) S(T8,8) S(T9,9) S(TA,10) \
+ S(TB,11) S(TC,12) S(TD,13) S(TE,14)
+#if MAX_PREPRO_ARGS>31
+#define CFARGTA20(F,S,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK) \
+ F(T1,A1,1,0) F(T2,A2,2,1) F(T3,A3,3,1) F(T4,A4,4,1) F(T5,A5,5,1) F(T6,A6,6,1) \
+ F(T7,A7,7,1) F(T8,A8,8,1) F(T9,A9,9,1) F(TA,AA,10,1) F(TB,AB,11,1) F(TC,AC,12,1) \
+ F(TD,AD,13,1) F(TE,AE,14,1) F(TF,AF,15,1) F(TG,AG,16,1) F(TH,AH,17,1) F(TI,AI,18,1) \
+ F(TJ,AJ,19,1) F(TK,AK,20,1) S(T1,1) S(T2,2) S(T3,3) S(T4,4) \
+ S(T5,5) S(T6,6) S(T7,7) S(T8,8) S(T9,9) S(TA,10) \
+ S(TB,11) S(TC,12) S(TD,13) S(TE,14) S(TF,15) S(TG,16) \
+ S(TH,17) S(TI,18) S(TJ,19) S(TK,20)
+#define CFARGTA27(F,S,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO,AP,AQ,AR) \
+ F(T1,A1,1,0) F(T2,A2,2,1) F(T3,A3,3,1) F(T4,A4,4,1) F(T5,A5,5,1) F(T6,A6,6,1) \
+ F(T7,A7,7,1) F(T8,A8,8,1) F(T9,A9,9,1) F(TA,AA,10,1) F(TB,AB,11,1) F(TC,AC,12,1) \
+ F(TD,AD,13,1) F(TE,AE,14,1) F(TF,AF,15,1) F(TG,AG,16,1) F(TH,AH,17,1) F(TI,AI,18,1) \
+ F(TJ,AJ,19,1) F(TK,AK,20,1) F(TL,AL,21,1) F(TM,AM,22,1) F(TN,AN,23,1) F(TO,AO,24,1) \
+ F(TP,AP,25,1) F(TQ,AQ,26,1) F(TR,AR,27,1) S(T1,1) S(T2,2) S(T3,3) \
+ S(T4,4) S(T5,5) S(T6,6) S(T7,7) S(T8,8) S(T9,9) \
+ S(TA,10) S(TB,11) S(TC,12) S(TD,13) S(TE,14) S(TF,15) \
+ S(TG,16) S(TH,17) S(TI,18) S(TJ,19) S(TK,20) S(TL,21) \
+ S(TM,22) S(TN,23) S(TO,24) S(TP,25) S(TQ,26) S(TR,27)
+#endif
+#else
+#define CFARGT14(F,S,M,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE) \
+ F(T1,1,0) S(T1,1) F(T2,2,1) S(T2,2) F(T3,3,1) S(T3,3) F(T4,4,1) S(T4,4) \
+ F(T5,5,1) S(T5,5) F(T6,6,1) S(T6,6) F(T7,7,1) S(T7,7) F(T8,8,1) S(T8,8) \
+ F(T9,9,1) S(T9,9) F(TA,10,1) S(TA,10) F(TB,11,1) S(TB,11) F(TC,12,1) S(TC,12) \
+ F(TD,13,1) S(TD,13) F(TE,14,1) S(TE,14)
+#define CFARGT27(F,S,M,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR) \
+ F(T1,1,0) S(T1,1) F(T2,2,1) S(T2,2) F(T3,3,1) S(T3,3) F(T4,4,1) S(T4,4) \
+ F(T5,5,1) S(T5,5) F(T6,6,1) S(T6,6) F(T7,7,1) S(T7,7) F(T8,8,1) S(T8,8) \
+ F(T9,9,1) S(T9,9) F(TA,10,1) S(TA,10) F(TB,11,1) S(TB,11) F(TC,12,1) S(TC,12) \
+ F(TD,13,1) S(TD,13) F(TE,14,1) S(TE,14) F(TF,15,1) S(TF,15) F(TG,16,1) S(TG,16) \
+ F(TH,17,1) S(TH,17) F(TI,18,1) S(TI,18) F(TJ,19,1) S(TJ,19) F(TK,20,1) S(TK,20) \
+ F(TL,21,1) S(TL,21) F(TM,22,1) S(TM,22) F(TN,23,1) S(TN,23) F(TO,24,1) S(TO,24) \
+ F(TP,25,1) S(TP,25) F(TQ,26,1) S(TQ,26) F(TR,27,1) S(TR,27)
+
+#define CFARGT20(F,S,M,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK) \
+ F(T1,1,0) S(T1,1) F(T2,2,1) S(T2,2) F(T3,3,1) S(T3,3) F(T4,4,1) S(T4,4) \
+ F(T5,5,1) S(T5,5) F(T6,6,1) S(T6,6) F(T7,7,1) S(T7,7) F(T8,8,1) S(T8,8) \
+ F(T9,9,1) S(T9,9) F(TA,10,1) S(TA,10) F(TB,11,1) S(TB,11) F(TC,12,1) S(TC,12) \
+ F(TD,13,1) S(TD,13) F(TE,14,1) S(TE,14) F(TF,15,1) S(TF,15) F(TG,16,1) S(TG,16) \
+ F(TH,17,1) S(TH,17) F(TI,18,1) S(TI,18) F(TJ,19,1) S(TJ,19) F(TK,20,1) S(TK,20)
+#define CFARGTA14(F,S,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE) \
+ F(T1,A1,1,0) S(T1,1) F(T2,A2,2,1) S(T2,2) F(T3,A3,3,1) S(T3,3) \
+ F(T4,A4,4,1) S(T4,4) F(T5,A5,5,1) S(T5,5) F(T6,A6,6,1) S(T6,6) \
+ F(T7,A7,7,1) S(T7,7) F(T8,A8,8,1) S(T8,8) F(T9,A9,9,1) S(T9,9) \
+ F(TA,AA,10,1) S(TA,10) F(TB,AB,11,1) S(TB,11) F(TC,AC,12,1) S(TC,12) \
+ F(TD,AD,13,1) S(TD,13) F(TE,AE,14,1) S(TE,14)
+#if MAX_PREPRO_ARGS>31
+#define CFARGTA20(F,S,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK) \
+ F(T1,A1,1,0) S(T1,1) F(T2,A2,2,1) S(T2,2) F(T3,A3,3,1) S(T3,3) \
+ F(T4,A4,4,1) S(T4,4) F(T5,A5,5,1) S(T5,5) F(T6,A6,6,1) S(T6,6) \
+ F(T7,A7,7,1) S(T7,7) F(T8,A8,8,1) S(T8,8) F(T9,A9,9,1) S(T9,9) \
+ F(TA,AA,10,1) S(TA,10) F(TB,AB,11,1) S(TB,11) F(TC,AC,12,1) S(TC,12) \
+ F(TD,AD,13,1) S(TD,13) F(TE,AE,14,1) S(TE,14) F(TF,AF,15,1) S(TF,15) \
+ F(TG,AG,16,1) S(TG,16) F(TH,AH,17,1) S(TH,17) F(TI,AI,18,1) S(TI,18) \
+ F(TJ,AJ,19,1) S(TJ,19) F(TK,AK,20,1) S(TK,20)
+#define CFARGTA27(F,S,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO,AP,AQ,AR) \
+ F(T1,A1,1,0) S(T1,1) F(T2,A2,2,1) S(T2,2) F(T3,A3,3,1) S(T3,3) \
+ F(T4,A4,4,1) S(T4,4) F(T5,A5,5,1) S(T5,5) F(T6,A6,6,1) S(T6,6) \
+ F(T7,A7,7,1) S(T7,7) F(T8,A8,8,1) S(T8,8) F(T9,A9,9,1) S(T9,9) \
+ F(TA,AA,10,1) S(TA,10) F(TB,AB,11,1) S(TB,11) F(TC,AC,12,1) S(TC,12) \
+ F(TD,AD,13,1) S(TD,13) F(TE,AE,14,1) S(TE,14) F(TF,AF,15,1) S(TF,15) \
+ F(TG,AG,16,1) S(TG,16) F(TH,AH,17,1) S(TH,17) F(TI,AI,18,1) S(TI,18) \
+ F(TJ,AJ,19,1) S(TJ,19) F(TK,AK,20,1) S(TK,20) F(TL,AL,21,1) S(TL,21) \
+ F(TM,AM,22,1) S(TM,22) F(TN,AN,23,1) S(TN,23) F(TO,AO,24,1) S(TO,24) \
+ F(TP,AP,25,1) S(TP,25) F(TQ,AQ,26,1) S(TQ,26) F(TR,AR,27,1) S(TR,27)
+#endif
+#endif
+
+
+#define PROTOCCALLSFSUB1( UN,LN,T1) \
+ PROTOCCALLSFSUB14(UN,LN,T1,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0)
+#define PROTOCCALLSFSUB2( UN,LN,T1,T2) \
+ PROTOCCALLSFSUB14(UN,LN,T1,T2,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0)
+#define PROTOCCALLSFSUB3( UN,LN,T1,T2,T3) \
+ PROTOCCALLSFSUB14(UN,LN,T1,T2,T3,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0)
+#define PROTOCCALLSFSUB4( UN,LN,T1,T2,T3,T4) \
+ PROTOCCALLSFSUB14(UN,LN,T1,T2,T3,T4,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0)
+#define PROTOCCALLSFSUB5( UN,LN,T1,T2,T3,T4,T5) \
+ PROTOCCALLSFSUB14(UN,LN,T1,T2,T3,T4,T5,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0)
+#define PROTOCCALLSFSUB6( UN,LN,T1,T2,T3,T4,T5,T6) \
+ PROTOCCALLSFSUB14(UN,LN,T1,T2,T3,T4,T5,T6,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0)
+#define PROTOCCALLSFSUB7( UN,LN,T1,T2,T3,T4,T5,T6,T7) \
+ PROTOCCALLSFSUB14(UN,LN,T1,T2,T3,T4,T5,T6,T7,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0)
+#define PROTOCCALLSFSUB8( UN,LN,T1,T2,T3,T4,T5,T6,T7,T8) \
+ PROTOCCALLSFSUB14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0)
+#define PROTOCCALLSFSUB9( UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9) \
+ PROTOCCALLSFSUB14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,CF_0,CF_0,CF_0,CF_0,CF_0)
+#define PROTOCCALLSFSUB10(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA) \
+ PROTOCCALLSFSUB14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,CF_0,CF_0,CF_0,CF_0)
+#define PROTOCCALLSFSUB11(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB) \
+ PROTOCCALLSFSUB14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,CF_0,CF_0,CF_0)
+#define PROTOCCALLSFSUB12(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC) \
+ PROTOCCALLSFSUB14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,CF_0,CF_0)
+#define PROTOCCALLSFSUB13(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD) \
+ PROTOCCALLSFSUB14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,CF_0)
+
+
+#define PROTOCCALLSFSUB15(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF) \
+ PROTOCCALLSFSUB20(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,CF_0,CF_0,CF_0,CF_0,CF_0)
+#define PROTOCCALLSFSUB16(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG) \
+ PROTOCCALLSFSUB20(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,CF_0,CF_0,CF_0,CF_0)
+#define PROTOCCALLSFSUB17(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH) \
+ PROTOCCALLSFSUB20(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,CF_0,CF_0,CF_0)
+#define PROTOCCALLSFSUB18(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI) \
+ PROTOCCALLSFSUB20(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,CF_0,CF_0)
+#define PROTOCCALLSFSUB19(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ) \
+ PROTOCCALLSFSUB20(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,CF_0)
+
+#define PROTOCCALLSFSUB21(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL) \
+ PROTOCCALLSFSUB27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0)
+#define PROTOCCALLSFSUB22(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM) \
+ PROTOCCALLSFSUB27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,CF_0,CF_0,CF_0,CF_0,CF_0)
+#define PROTOCCALLSFSUB23(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN) \
+ PROTOCCALLSFSUB27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,CF_0,CF_0,CF_0,CF_0)
+#define PROTOCCALLSFSUB24(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO) \
+ PROTOCCALLSFSUB27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,CF_0,CF_0,CF_0)
+#define PROTOCCALLSFSUB25(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP) \
+ PROTOCCALLSFSUB27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,CF_0,CF_0)
+#define PROTOCCALLSFSUB26(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ) \
+ PROTOCCALLSFSUB27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,CF_0)
+
+
+#ifndef FCALLSC_QUALIFIER
+#ifdef VISUAL_CPLUSPLUS
+#define FCALLSC_QUALIFIER __stdcall
+#else
+#define FCALLSC_QUALIFIER
+#endif
+#endif
+
+#ifdef __cplusplus
+#define CFextern extern "C"
+#else
+#define CFextern extern
+#endif
+
+
+#ifdef CFSUBASFUN
+#define PROTOCCALLSFSUB0(UN,LN) \
+ PROTOCCALLSFFUN0( VOID,UN,LN)
+#define PROTOCCALLSFSUB14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE) \
+ PROTOCCALLSFFUN14(VOID,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)
+#define PROTOCCALLSFSUB20(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK)\
+ PROTOCCALLSFFUN20(VOID,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK)
+#define PROTOCCALLSFSUB27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR)\
+ PROTOCCALLSFFUN27(VOID,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR)
+#else
+/* Note: Prevent compiler warnings, null #define PROTOCCALLSFSUB14/20 after
+ #include-ing cfortran.h if calling the FORTRAN wrapper within the same
+ source code where the wrapper is created. */
+#define PROTOCCALLSFSUB0(UN,LN) _(VOID,_cfPU)(CFC_(UN,LN))();
+#ifndef __CF__KnR
+#define PROTOCCALLSFSUB14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE) \
+ _(VOID,_cfPU)(CFC_(UN,LN))( CFARGT14(NCF,KCF,_Z,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE) );
+#define PROTOCCALLSFSUB20(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK)\
+ _(VOID,_cfPU)(CFC_(UN,LN))( CFARGT20(NCF,KCF,_Z,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK) );
+#define PROTOCCALLSFSUB27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR)\
+ _(VOID,_cfPU)(CFC_(UN,LN))( CFARGT27(NCF,KCF,_Z,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR) );
+#else
+#define PROTOCCALLSFSUB14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE) \
+ PROTOCCALLSFSUB0(UN,LN)
+#define PROTOCCALLSFSUB20(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK) \
+ PROTOCCALLSFSUB0(UN,LN)
+#define PROTOCCALLSFSUB27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR) \
+ PROTOCCALLSFSUB0(UN,LN)
+#endif
+#endif
+
+
+#ifdef OLD_VAXC /* Allow %CC-I-PARAMNOTUSED. */
+#pragma standard
+#endif
+
+
+#define CCALLSFSUB1( UN,LN,T1, A1) \
+ CCALLSFSUB5 (UN,LN,T1,CF_0,CF_0,CF_0,CF_0,A1,0,0,0,0)
+#define CCALLSFSUB2( UN,LN,T1,T2, A1,A2) \
+ CCALLSFSUB5 (UN,LN,T1,T2,CF_0,CF_0,CF_0,A1,A2,0,0,0)
+#define CCALLSFSUB3( UN,LN,T1,T2,T3, A1,A2,A3) \
+ CCALLSFSUB5 (UN,LN,T1,T2,T3,CF_0,CF_0,A1,A2,A3,0,0)
+#define CCALLSFSUB4( UN,LN,T1,T2,T3,T4, A1,A2,A3,A4)\
+ CCALLSFSUB5 (UN,LN,T1,T2,T3,T4,CF_0,A1,A2,A3,A4,0)
+#define CCALLSFSUB5( UN,LN,T1,T2,T3,T4,T5, A1,A2,A3,A4,A5) \
+ CCALLSFSUB10(UN,LN,T1,T2,T3,T4,T5,CF_0,CF_0,CF_0,CF_0,CF_0,A1,A2,A3,A4,A5,0,0,0,0,0)
+#define CCALLSFSUB6( UN,LN,T1,T2,T3,T4,T5,T6, A1,A2,A3,A4,A5,A6) \
+ CCALLSFSUB10(UN,LN,T1,T2,T3,T4,T5,T6,CF_0,CF_0,CF_0,CF_0,A1,A2,A3,A4,A5,A6,0,0,0,0)
+#define CCALLSFSUB7( UN,LN,T1,T2,T3,T4,T5,T6,T7, A1,A2,A3,A4,A5,A6,A7) \
+ CCALLSFSUB10(UN,LN,T1,T2,T3,T4,T5,T6,T7,CF_0,CF_0,CF_0,A1,A2,A3,A4,A5,A6,A7,0,0,0)
+#define CCALLSFSUB8( UN,LN,T1,T2,T3,T4,T5,T6,T7,T8, A1,A2,A3,A4,A5,A6,A7,A8) \
+ CCALLSFSUB10(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,CF_0,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,0,0)
+#define CCALLSFSUB9( UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,A1,A2,A3,A4,A5,A6,A7,A8,A9)\
+ CCALLSFSUB10(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,A9,0)
+#define CCALLSFSUB10(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA)\
+ CCALLSFSUB14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,CF_0,CF_0,CF_0,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,0,0,0,0)
+#define CCALLSFSUB11(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB)\
+ CCALLSFSUB14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,CF_0,CF_0,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,0,0,0)
+#define CCALLSFSUB12(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC)\
+ CCALLSFSUB14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,CF_0,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,0,0)
+#define CCALLSFSUB13(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD)\
+ CCALLSFSUB14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,0)
+
+#ifdef __cplusplus
+#define CPPPROTOCLSFSUB0( UN,LN)
+#define CPPPROTOCLSFSUB14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)
+#define CPPPROTOCLSFSUB20(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK)
+#define CPPPROTOCLSFSUB27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR)
+#else
+#define CPPPROTOCLSFSUB0(UN,LN) \
+ PROTOCCALLSFSUB0(UN,LN)
+#define CPPPROTOCLSFSUB14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE) \
+ PROTOCCALLSFSUB14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)
+#define CPPPROTOCLSFSUB20(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK) \
+ PROTOCCALLSFSUB20(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK)
+#define CPPPROTOCLSFSUB27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR) \
+ PROTOCCALLSFSUB27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR)
+#endif
+
+#ifdef CFSUBASFUN
+#define CCALLSFSUB0(UN,LN) CCALLSFFUN0(UN,LN)
+#define CCALLSFSUB14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE)\
+ CCALLSFFUN14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE)
+#else
+/* do{...}while(0) allows if(a==b) FORT(); else BORT(); */
+#define CCALLSFSUB0( UN,LN) do{CPPPROTOCLSFSUB0(UN,LN) CFC_(UN,LN)();}while(0)
+#define CCALLSFSUB14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE)\
+do{VVCF(T1,A1,B1) VVCF(T2,A2,B2) VVCF(T3,A3,B3) VVCF(T4,A4,B4) VVCF(T5,A5,B5) \
+ VVCF(T6,A6,B6) VVCF(T7,A7,B7) VVCF(T8,A8,B8) VVCF(T9,A9,B9) VVCF(TA,AA,B10) \
+ VVCF(TB,AB,B11) VVCF(TC,AC,B12) VVCF(TD,AD,B13) VVCF(TE,AE,B14) \
+ CPPPROTOCLSFSUB14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE) \
+ ACF(LN,T1,A1,1) ACF(LN,T2,A2,2) ACF(LN,T3,A3,3) \
+ ACF(LN,T4,A4,4) ACF(LN,T5,A5,5) ACF(LN,T6,A6,6) ACF(LN,T7,A7,7) \
+ ACF(LN,T8,A8,8) ACF(LN,T9,A9,9) ACF(LN,TA,AA,10) ACF(LN,TB,AB,11) \
+ ACF(LN,TC,AC,12) ACF(LN,TD,AD,13) ACF(LN,TE,AE,14) \
+ CFC_(UN,LN)( CFARGTA14(AACF,JCF,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE) );\
+ WCF(T1,A1,1) WCF(T2,A2,2) WCF(T3,A3,3) WCF(T4,A4,4) WCF(T5,A5,5) \
+ WCF(T6,A6,6) WCF(T7,A7,7) WCF(T8,A8,8) WCF(T9,A9,9) WCF(TA,AA,10) \
+ WCF(TB,AB,11) WCF(TC,AC,12) WCF(TD,AD,13) WCF(TE,AE,14) }while(0)
+#endif
+
+
+#if MAX_PREPRO_ARGS>31
+#define CCALLSFSUB15(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF)\
+ CCALLSFSUB20(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,CF_0,CF_0,CF_0,CF_0,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,0,0,0,0,0)
+#define CCALLSFSUB16(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG)\
+ CCALLSFSUB20(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,CF_0,CF_0,CF_0,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,0,0,0,0)
+#define CCALLSFSUB17(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH)\
+ CCALLSFSUB20(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,CF_0,CF_0,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,0,0,0)
+#define CCALLSFSUB18(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI)\
+ CCALLSFSUB20(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,CF_0,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,0,0)
+#define CCALLSFSUB19(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ)\
+ CCALLSFSUB20(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,0)
+
+#ifdef CFSUBASFUN
+#define CCALLSFSUB20(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH, \
+ TI,TJ,TK, A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK) \
+ CCALLSFFUN20(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH, \
+ TI,TJ,TK, A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK)
+#else
+#define CCALLSFSUB20(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH, \
+ TI,TJ,TK, A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK) \
+do{VVCF(T1,A1,B1) VVCF(T2,A2,B2) VVCF(T3,A3,B3) VVCF(T4,A4,B4) VVCF(T5,A5,B5) \
+ VVCF(T6,A6,B6) VVCF(T7,A7,B7) VVCF(T8,A8,B8) VVCF(T9,A9,B9) VVCF(TA,AA,B10) \
+ VVCF(TB,AB,B11) VVCF(TC,AC,B12) VVCF(TD,AD,B13) VVCF(TE,AE,B14) VVCF(TF,AF,B15) \
+ VVCF(TG,AG,B16) VVCF(TH,AH,B17) VVCF(TI,AI,B18) VVCF(TJ,AJ,B19) VVCF(TK,AK,B20) \
+ CPPPROTOCLSFSUB20(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK) \
+ ACF(LN,T1,A1,1) ACF(LN,T2,A2,2) ACF(LN,T3,A3,3) ACF(LN,T4,A4,4) \
+ ACF(LN,T5,A5,5) ACF(LN,T6,A6,6) ACF(LN,T7,A7,7) ACF(LN,T8,A8,8) \
+ ACF(LN,T9,A9,9) ACF(LN,TA,AA,10) ACF(LN,TB,AB,11) ACF(LN,TC,AC,12) \
+ ACF(LN,TD,AD,13) ACF(LN,TE,AE,14) ACF(LN,TF,AF,15) ACF(LN,TG,AG,16) \
+ ACF(LN,TH,AH,17) ACF(LN,TI,AI,18) ACF(LN,TJ,AJ,19) ACF(LN,TK,AK,20) \
+ CFC_(UN,LN)( CFARGTA20(AACF,JCF,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK) ); \
+ WCF(T1,A1,1) WCF(T2,A2,2) WCF(T3,A3,3) WCF(T4,A4,4) WCF(T5,A5,5) WCF(T6,A6,6) \
+ WCF(T7,A7,7) WCF(T8,A8,8) WCF(T9,A9,9) WCF(TA,AA,10) WCF(TB,AB,11) WCF(TC,AC,12) \
+ WCF(TD,AD,13) WCF(TE,AE,14) WCF(TF,AF,15) WCF(TG,AG,16) WCF(TH,AH,17) WCF(TI,AI,18) \
+ WCF(TJ,AJ,19) WCF(TK,AK,20) }while(0)
+#endif
+#endif /* MAX_PREPRO_ARGS */
+
+#if MAX_PREPRO_ARGS>31
+#define CCALLSFSUB21(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL)\
+ CCALLSFSUB27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,0,0,0,0,0,0)
+#define CCALLSFSUB22(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM)\
+ CCALLSFSUB27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,CF_0,CF_0,CF_0,CF_0,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,0,0,0,0,0)
+#define CCALLSFSUB23(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN)\
+ CCALLSFSUB27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,CF_0,CF_0,CF_0,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,0,0,0,0)
+#define CCALLSFSUB24(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO)\
+ CCALLSFSUB27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,CF_0,CF_0,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO,0,0,0)
+#define CCALLSFSUB25(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO,AP)\
+ CCALLSFSUB27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,CF_0,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO,AP,0,0)
+#define CCALLSFSUB26(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO,AP,AQ)\
+ CCALLSFSUB27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO,AP,AQ,0)
+
+#ifdef CFSUBASFUN
+#define CCALLSFSUB27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR, \
+ A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO,AP,AQ,AR) \
+ CCALLSFFUN27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR, \
+ A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO,AP,AQ,AR)
+#else
+#define CCALLSFSUB27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR, \
+ A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO,AP,AQ,AR) \
+do{VVCF(T1,A1,B1) VVCF(T2,A2,B2) VVCF(T3,A3,B3) VVCF(T4,A4,B4) VVCF(T5,A5,B5) \
+ VVCF(T6,A6,B6) VVCF(T7,A7,B7) VVCF(T8,A8,B8) VVCF(T9,A9,B9) VVCF(TA,AA,B10) \
+ VVCF(TB,AB,B11) VVCF(TC,AC,B12) VVCF(TD,AD,B13) VVCF(TE,AE,B14) VVCF(TF,AF,B15) \
+ VVCF(TG,AG,B16) VVCF(TH,AH,B17) VVCF(TI,AI,B18) VVCF(TJ,AJ,B19) VVCF(TK,AK,B20) \
+ VVCF(TL,AL,B21) VVCF(TM,AM,B22) VVCF(TN,AN,B23) VVCF(TO,AO,B24) VVCF(TP,AP,B25) \
+ VVCF(TQ,AQ,B26) VVCF(TR,AR,B27) \
+ CPPPROTOCLSFSUB27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR) \
+ ACF(LN,T1,A1,1) ACF(LN,T2,A2,2) ACF(LN,T3,A3,3) ACF(LN,T4,A4,4) \
+ ACF(LN,T5,A5,5) ACF(LN,T6,A6,6) ACF(LN,T7,A7,7) ACF(LN,T8,A8,8) \
+ ACF(LN,T9,A9,9) ACF(LN,TA,AA,10) ACF(LN,TB,AB,11) ACF(LN,TC,AC,12) \
+ ACF(LN,TD,AD,13) ACF(LN,TE,AE,14) ACF(LN,TF,AF,15) ACF(LN,TG,AG,16) \
+ ACF(LN,TH,AH,17) ACF(LN,TI,AI,18) ACF(LN,TJ,AJ,19) ACF(LN,TK,AK,20) \
+ ACF(LN,TL,AL,21) ACF(LN,TM,AM,22) ACF(LN,TN,AN,23) ACF(LN,TO,AO,24) \
+ ACF(LN,TP,AP,25) ACF(LN,TQ,AQ,26) ACF(LN,TR,AR,27) \
+ CFC_(UN,LN)( CFARGTA27(AACF,JCF,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR,\
+ A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO,AP,AQ,AR) ); \
+ WCF(T1,A1,1) WCF(T2,A2,2) WCF(T3,A3,3) WCF(T4,A4,4) WCF(T5,A5,5) WCF(T6,A6,6) \
+ WCF(T7,A7,7) WCF(T8,A8,8) WCF(T9,A9,9) WCF(TA,AA,10) WCF(TB,AB,11) WCF(TC,AC,12) \
+ WCF(TD,AD,13) WCF(TE,AE,14) WCF(TF,AF,15) WCF(TG,AG,16) WCF(TH,AH,17) WCF(TI,AI,18) \
+ WCF(TJ,AJ,19) WCF(TK,AK,20) WCF(TL,AL,21) WCF(TM,AM,22) WCF(TN,AN,23) WCF(TO,AO,24) \
+ WCF(TP,AP,25) WCF(TQ,AQ,26) WCF(TR,AR,27) }while(0)
+#endif
+#endif /* MAX_PREPRO_ARGS */
+
+/*-------------------------------------------------------------------------*/
+
+/* UTILITIES FOR C TO CALL FORTRAN FUNCTIONS */
+
+/*N.B. PROTOCCALLSFFUNn(..) generates code, whether or not the FORTRAN
+ function is called. Therefore, especially for creator's of C header files
+ for large FORTRAN libraries which include many functions, to reduce
+ compile time and object code size, it may be desirable to create
+ preprocessor directives to allow users to create code for only those
+ functions which they use. */
+
+/* The following defines the maximum length string that a function can return.
+ Of course it may be undefine-d and re-define-d before individual
+ PROTOCCALLSFFUNn(..) as required. It would also be nice to have this derived
+ from the individual machines' limits. */
+#define MAX_LEN_FORTRAN_FUNCTION_STRING 0x4FE
+
+/* The following defines a character used by CFORTRAN.H to flag the end of a
+ string coming out of a FORTRAN routine. */
+#define CFORTRAN_NON_CHAR 0x7F
+
+#ifdef OLD_VAXC /* Prevent %CC-I-PARAMNOTUSED. */
+#pragma nostandard
+#endif
+
+#define _SEP_(TN,C,cfCOMMA) _(__SEP_,C)(TN,cfCOMMA)
+#define __SEP_0(TN,cfCOMMA)
+#define __SEP_1(TN,cfCOMMA) _Icf(2,SEP,TN,cfCOMMA,0)
+#define INT_cfSEP(T,B) _(A,B)
+#define INTV_cfSEP(T,B) INT_cfSEP(T,B)
+#define INTVV_cfSEP(T,B) INT_cfSEP(T,B)
+#define INTVVV_cfSEP(T,B) INT_cfSEP(T,B)
+#define INTVVVV_cfSEP(T,B) INT_cfSEP(T,B)
+#define INTVVVVV_cfSEP(T,B) INT_cfSEP(T,B)
+#define INTVVVVVV_cfSEP(T,B) INT_cfSEP(T,B)
+#define INTVVVVVVV_cfSEP(T,B) INT_cfSEP(T,B)
+#define PINT_cfSEP(T,B) INT_cfSEP(T,B)
+#define PVOID_cfSEP(T,B) INT_cfSEP(T,B)
+#define ROUTINE_cfSEP(T,B) INT_cfSEP(T,B)
+#define SIMPLE_cfSEP(T,B) INT_cfSEP(T,B)
+#define VOID_cfSEP(T,B) INT_cfSEP(T,B) /* For FORTRAN calls C subr.s.*/
+#define STRING_cfSEP(T,B) INT_cfSEP(T,B)
+#define STRINGV_cfSEP(T,B) INT_cfSEP(T,B)
+#define PSTRING_cfSEP(T,B) INT_cfSEP(T,B)
+#define PSTRINGV_cfSEP(T,B) INT_cfSEP(T,B)
+#define PNSTRING_cfSEP(T,B) INT_cfSEP(T,B)
+#define PPSTRING_cfSEP(T,B) INT_cfSEP(T,B)
+#define ZTRINGV_cfSEP(T,B) INT_cfSEP(T,B)
+#define PZTRINGV_cfSEP(T,B) INT_cfSEP(T,B)
+
+#if defined(SIGNED_BYTE) || !defined(UNSIGNED_BYTE)
+#ifdef OLD_VAXC
+#define INTEGER_BYTE char /* Old VAXC barfs on 'signed char' */
+#else
+#define INTEGER_BYTE signed char /* default */
+#endif
+#else
+#define INTEGER_BYTE unsigned char
+#endif
+#define BYTEVVVVVVV_cfTYPE INTEGER_BYTE
+#define DOUBLEVVVVVVV_cfTYPE DOUBLE_PRECISION
+#define FLOATVVVVVVV_cfTYPE FORTRAN_REAL
+#define INTVVVVVVV_cfTYPE int
+#define LOGICALVVVVVVV_cfTYPE int
+#define LONGVVVVVVV_cfTYPE long
+#define SHORTVVVVVVV_cfTYPE short
+#define PBYTE_cfTYPE INTEGER_BYTE
+#define PDOUBLE_cfTYPE DOUBLE_PRECISION
+#define PFLOAT_cfTYPE FORTRAN_REAL
+#define PINT_cfTYPE int
+#define PLOGICAL_cfTYPE int
+#define PLONG_cfTYPE long
+#define PSHORT_cfTYPE short
+
+#define CFARGS0(A,T,V,W,X,Y,Z) _3(T,_cf,A)
+#define CFARGS1(A,T,V,W,X,Y,Z) _3(T,_cf,A)(V)
+#define CFARGS2(A,T,V,W,X,Y,Z) _3(T,_cf,A)(V,W)
+#define CFARGS3(A,T,V,W,X,Y,Z) _3(T,_cf,A)(V,W,X)
+#define CFARGS4(A,T,V,W,X,Y,Z) _3(T,_cf,A)(V,W,X,Y)
+#define CFARGS5(A,T,V,W,X,Y,Z) _3(T,_cf,A)(V,W,X,Y,Z)
+
+#define _Icf(N,T,I,X,Y) _(I,_cfINT)(N,T,I,X,Y,0)
+#define _Icf4(N,T,I,X,Y,Z) _(I,_cfINT)(N,T,I,X,Y,Z)
+#define BYTE_cfINT(N,A,B,X,Y,Z) DOUBLE_cfINT(N,A,B,X,Y,Z)
+#define DOUBLE_cfINT(N,A,B,X,Y,Z) _(CFARGS,N)(A,INT,B,X,Y,Z,0)
+#define FLOAT_cfINT(N,A,B,X,Y,Z) DOUBLE_cfINT(N,A,B,X,Y,Z)
+#define INT_cfINT(N,A,B,X,Y,Z) DOUBLE_cfINT(N,A,B,X,Y,Z)
+#define LOGICAL_cfINT(N,A,B,X,Y,Z) DOUBLE_cfINT(N,A,B,X,Y,Z)
+#define LONG_cfINT(N,A,B,X,Y,Z) DOUBLE_cfINT(N,A,B,X,Y,Z)
+#define SHORT_cfINT(N,A,B,X,Y,Z) DOUBLE_cfINT(N,A,B,X,Y,Z)
+#define PBYTE_cfINT(N,A,B,X,Y,Z) PDOUBLE_cfINT(N,A,B,X,Y,Z)
+#define PDOUBLE_cfINT(N,A,B,X,Y,Z) _(CFARGS,N)(A,PINT,B,X,Y,Z,0)
+#define PFLOAT_cfINT(N,A,B,X,Y,Z) PDOUBLE_cfINT(N,A,B,X,Y,Z)
+#define PINT_cfINT(N,A,B,X,Y,Z) PDOUBLE_cfINT(N,A,B,X,Y,Z)
+#define PLOGICAL_cfINT(N,A,B,X,Y,Z) PDOUBLE_cfINT(N,A,B,X,Y,Z)
+#define PLONG_cfINT(N,A,B,X,Y,Z) PDOUBLE_cfINT(N,A,B,X,Y,Z)
+#define PSHORT_cfINT(N,A,B,X,Y,Z) PDOUBLE_cfINT(N,A,B,X,Y,Z)
+#define BYTEV_cfINT(N,A,B,X,Y,Z) DOUBLEV_cfINT(N,A,B,X,Y,Z)
+#define BYTEVV_cfINT(N,A,B,X,Y,Z) DOUBLEVV_cfINT(N,A,B,X,Y,Z)
+#define BYTEVVV_cfINT(N,A,B,X,Y,Z) DOUBLEVVV_cfINT(N,A,B,X,Y,Z)
+#define BYTEVVVV_cfINT(N,A,B,X,Y,Z) DOUBLEVVVV_cfINT(N,A,B,X,Y,Z)
+#define BYTEVVVVV_cfINT(N,A,B,X,Y,Z) DOUBLEVVVVV_cfINT(N,A,B,X,Y,Z)
+#define BYTEVVVVVV_cfINT(N,A,B,X,Y,Z) DOUBLEVVVVVV_cfINT(N,A,B,X,Y,Z)
+#define BYTEVVVVVVV_cfINT(N,A,B,X,Y,Z) DOUBLEVVVVVVV_cfINT(N,A,B,X,Y,Z)
+#define DOUBLEV_cfINT(N,A,B,X,Y,Z) _(CFARGS,N)(A,INTV,B,X,Y,Z,0)
+#define DOUBLEVV_cfINT(N,A,B,X,Y,Z) _(CFARGS,N)(A,INTVV,B,X,Y,Z,0)
+#define DOUBLEVVV_cfINT(N,A,B,X,Y,Z) _(CFARGS,N)(A,INTVVV,B,X,Y,Z,0)
+#define DOUBLEVVVV_cfINT(N,A,B,X,Y,Z) _(CFARGS,N)(A,INTVVVV,B,X,Y,Z,0)
+#define DOUBLEVVVVV_cfINT(N,A,B,X,Y,Z) _(CFARGS,N)(A,INTVVVVV,B,X,Y,Z,0)
+#define DOUBLEVVVVVV_cfINT(N,A,B,X,Y,Z) _(CFARGS,N)(A,INTVVVVVV,B,X,Y,Z,0)
+#define DOUBLEVVVVVVV_cfINT(N,A,B,X,Y,Z) _(CFARGS,N)(A,INTVVVVVVV,B,X,Y,Z,0)
+#define FLOATV_cfINT(N,A,B,X,Y,Z) DOUBLEV_cfINT(N,A,B,X,Y,Z)
+#define FLOATVV_cfINT(N,A,B,X,Y,Z) DOUBLEVV_cfINT(N,A,B,X,Y,Z)
+#define FLOATVVV_cfINT(N,A,B,X,Y,Z) DOUBLEVVV_cfINT(N,A,B,X,Y,Z)
+#define FLOATVVVV_cfINT(N,A,B,X,Y,Z) DOUBLEVVVV_cfINT(N,A,B,X,Y,Z)
+#define FLOATVVVVV_cfINT(N,A,B,X,Y,Z) DOUBLEVVVVV_cfINT(N,A,B,X,Y,Z)
+#define FLOATVVVVVV_cfINT(N,A,B,X,Y,Z) DOUBLEVVVVVV_cfINT(N,A,B,X,Y,Z)
+#define FLOATVVVVVVV_cfINT(N,A,B,X,Y,Z) DOUBLEVVVVVVV_cfINT(N,A,B,X,Y,Z)
+#define INTV_cfINT(N,A,B,X,Y,Z) DOUBLEV_cfINT(N,A,B,X,Y,Z)
+#define INTVV_cfINT(N,A,B,X,Y,Z) DOUBLEVV_cfINT(N,A,B,X,Y,Z)
+#define INTVVV_cfINT(N,A,B,X,Y,Z) DOUBLEVVV_cfINT(N,A,B,X,Y,Z)
+#define INTVVVV_cfINT(N,A,B,X,Y,Z) DOUBLEVVVV_cfINT(N,A,B,X,Y,Z)
+#define INTVVVVV_cfINT(N,A,B,X,Y,Z) DOUBLEVVVVV_cfINT(N,A,B,X,Y,Z)
+#define INTVVVVVV_cfINT(N,A,B,X,Y,Z) DOUBLEVVVVVV_cfINT(N,A,B,X,Y,Z)
+#define INTVVVVVVV_cfINT(N,A,B,X,Y,Z) DOUBLEVVVVVVV_cfINT(N,A,B,X,Y,Z)
+#define LOGICALV_cfINT(N,A,B,X,Y,Z) DOUBLEV_cfINT(N,A,B,X,Y,Z)
+#define LOGICALVV_cfINT(N,A,B,X,Y,Z) DOUBLEVV_cfINT(N,A,B,X,Y,Z)
+#define LOGICALVVV_cfINT(N,A,B,X,Y,Z) DOUBLEVVV_cfINT(N,A,B,X,Y,Z)
+#define LOGICALVVVV_cfINT(N,A,B,X,Y,Z) DOUBLEVVVV_cfINT(N,A,B,X,Y,Z)
+#define LOGICALVVVVV_cfINT(N,A,B,X,Y,Z) DOUBLEVVVVV_cfINT(N,A,B,X,Y,Z)
+#define LOGICALVVVVVV_cfINT(N,A,B,X,Y,Z) DOUBLEVVVVVV_cfINT(N,A,B,X,Y,Z)
+#define LOGICALVVVVVVV_cfINT(N,A,B,X,Y,Z) DOUBLEVVVVVVV_cfINT(N,A,B,X,Y,Z)
+#define LONGV_cfINT(N,A,B,X,Y,Z) DOUBLEV_cfINT(N,A,B,X,Y,Z)
+#define LONGVV_cfINT(N,A,B,X,Y,Z) DOUBLEVV_cfINT(N,A,B,X,Y,Z)
+#define LONGVVV_cfINT(N,A,B,X,Y,Z) DOUBLEVVV_cfINT(N,A,B,X,Y,Z)
+#define LONGVVVV_cfINT(N,A,B,X,Y,Z) DOUBLEVVVV_cfINT(N,A,B,X,Y,Z)
+#define LONGVVVVV_cfINT(N,A,B,X,Y,Z) DOUBLEVVVVV_cfINT(N,A,B,X,Y,Z)
+#define LONGVVVVVV_cfINT(N,A,B,X,Y,Z) DOUBLEVVVVVV_cfINT(N,A,B,X,Y,Z)
+#define LONGVVVVVVV_cfINT(N,A,B,X,Y,Z) DOUBLEVVVVVVV_cfINT(N,A,B,X,Y,Z)
+#define SHORTV_cfINT(N,A,B,X,Y,Z) DOUBLEV_cfINT(N,A,B,X,Y,Z)
+#define SHORTVV_cfINT(N,A,B,X,Y,Z) DOUBLEVV_cfINT(N,A,B,X,Y,Z)
+#define SHORTVVV_cfINT(N,A,B,X,Y,Z) DOUBLEVVV_cfINT(N,A,B,X,Y,Z)
+#define SHORTVVVV_cfINT(N,A,B,X,Y,Z) DOUBLEVVVV_cfINT(N,A,B,X,Y,Z)
+#define SHORTVVVVV_cfINT(N,A,B,X,Y,Z) DOUBLEVVVVV_cfINT(N,A,B,X,Y,Z)
+#define SHORTVVVVVV_cfINT(N,A,B,X,Y,Z) DOUBLEVVVVVV_cfINT(N,A,B,X,Y,Z)
+#define SHORTVVVVVVV_cfINT(N,A,B,X,Y,Z) DOUBLEVVVVVVV_cfINT(N,A,B,X,Y,Z)
+#define PVOID_cfINT(N,A,B,X,Y,Z) _(CFARGS,N)(A,B,B,X,Y,Z,0)
+#define ROUTINE_cfINT(N,A,B,X,Y,Z) PVOID_cfINT(N,A,B,X,Y,Z)
+/*CRAY coughs on the first,
+ i.e. the usual trouble of not being able to
+ define macros to macros with arguments.
+ New ultrix is worse, it coughs on all such uses.
+ */
+/*#define SIMPLE_cfINT PVOID_cfINT*/
+#define SIMPLE_cfINT(N,A,B,X,Y,Z) PVOID_cfINT(N,A,B,X,Y,Z)
+#define VOID_cfINT(N,A,B,X,Y,Z) PVOID_cfINT(N,A,B,X,Y,Z)
+#define STRING_cfINT(N,A,B,X,Y,Z) PVOID_cfINT(N,A,B,X,Y,Z)
+#define STRINGV_cfINT(N,A,B,X,Y,Z) PVOID_cfINT(N,A,B,X,Y,Z)
+#define PSTRING_cfINT(N,A,B,X,Y,Z) PVOID_cfINT(N,A,B,X,Y,Z)
+#define PSTRINGV_cfINT(N,A,B,X,Y,Z) PVOID_cfINT(N,A,B,X,Y,Z)
+#define PNSTRING_cfINT(N,A,B,X,Y,Z) PVOID_cfINT(N,A,B,X,Y,Z)
+#define PPSTRING_cfINT(N,A,B,X,Y,Z) PVOID_cfINT(N,A,B,X,Y,Z)
+#define ZTRINGV_cfINT(N,A,B,X,Y,Z) PVOID_cfINT(N,A,B,X,Y,Z)
+#define PZTRINGV_cfINT(N,A,B,X,Y,Z) PVOID_cfINT(N,A,B,X,Y,Z)
+#define CF_0_cfINT(N,A,B,X,Y,Z)
+
+
+#define UCF(TN,I,C) _SEP_(TN,C,cfCOMMA) _Icf(2,U,TN,_(A,I),0)
+#define UUCF(TN,I,C) _SEP_(TN,C,cfCOMMA) _SEP_(TN,1,I)
+#define UUUCF(TN,I,C) _SEP_(TN,C,cfCOLON) _Icf(2,U,TN,_(A,I),0)
+#define INT_cfU(T,A) _(T,VVVVVVV_cfTYPE) A
+#define INTV_cfU(T,A) _(T,VVVVVV_cfTYPE) * A
+#define INTVV_cfU(T,A) _(T,VVVVV_cfTYPE) * A
+#define INTVVV_cfU(T,A) _(T,VVVV_cfTYPE) * A
+#define INTVVVV_cfU(T,A) _(T,VVV_cfTYPE) * A
+#define INTVVVVV_cfU(T,A) _(T,VV_cfTYPE) * A
+#define INTVVVVVV_cfU(T,A) _(T,V_cfTYPE) * A
+#define INTVVVVVVV_cfU(T,A) _(T,_cfTYPE) * A
+#define PINT_cfU(T,A) _(T,_cfTYPE) * A
+#define PVOID_cfU(T,A) void *A
+#define ROUTINE_cfU(T,A) void (*A)(CF_NULL_PROTO)
+#define VOID_cfU(T,A) void A /* Needed for C calls FORTRAN sub.s. */
+#define STRING_cfU(T,A) char *A /* via VOID and wrapper. */
+#define STRINGV_cfU(T,A) char *A
+#define PSTRING_cfU(T,A) char *A
+#define PSTRINGV_cfU(T,A) char *A
+#define ZTRINGV_cfU(T,A) char *A
+#define PZTRINGV_cfU(T,A) char *A
+
+/* VOID breaks U into U and UU. */
+#define INT_cfUU(T,A) _(T,VVVVVVV_cfTYPE) A
+#define VOID_cfUU(T,A) /* Needed for FORTRAN calls C sub.s. */
+#define STRING_cfUU(T,A) char *A
+
+
+#define BYTE_cfPU(A) CFextern INTEGER_BYTE FCALLSC_QUALIFIER A
+#define DOUBLE_cfPU(A) CFextern DOUBLE_PRECISION FCALLSC_QUALIFIER A
+#if ! (defined(FLOATFUNCTIONTYPE)&&defined(ASSIGNFLOAT)&&defined(RETURNFLOAT))
+#define FLOAT_cfPU(A) CFextern FORTRAN_REAL FCALLSC_QUALIFIER A
+#else
+#define FLOAT_cfPU(A) CFextern FLOATFUNCTIONTYPE FCALLSC_QUALIFIER A
+#endif
+#define INT_cfPU(A) CFextern int FCALLSC_QUALIFIER A
+#define LOGICAL_cfPU(A) CFextern int FCALLSC_QUALIFIER A
+#define LONG_cfPU(A) CFextern long FCALLSC_QUALIFIER A
+#define SHORT_cfPU(A) CFextern short FCALLSC_QUALIFIER A
+#define STRING_cfPU(A) CFextern void FCALLSC_QUALIFIER A
+#define VOID_cfPU(A) CFextern void FCALLSC_QUALIFIER A
+
+#define BYTE_cfE INTEGER_BYTE A0;
+#define DOUBLE_cfE DOUBLE_PRECISION A0;
+#if ! (defined(FLOATFUNCTIONTYPE)&&defined(ASSIGNFLOAT)&&defined(RETURNFLOAT))
+#define FLOAT_cfE FORTRAN_REAL A0;
+#else
+#define FLOAT_cfE FORTRAN_REAL AA0; FLOATFUNCTIONTYPE A0;
+#endif
+#define INT_cfE int A0;
+#define LOGICAL_cfE int A0;
+#define LONG_cfE long A0;
+#define SHORT_cfE short A0;
+#define VOID_cfE
+#ifdef vmsFortran
+#define STRING_cfE static char AA0[1+MAX_LEN_FORTRAN_FUNCTION_STRING]; \
+ static fstring A0 = \
+ {MAX_LEN_FORTRAN_FUNCTION_STRING,DSC$K_DTYPE_T,DSC$K_CLASS_S,AA0};\
+ memset(AA0, CFORTRAN_NON_CHAR, MAX_LEN_FORTRAN_FUNCTION_STRING);\
+ *(AA0+MAX_LEN_FORTRAN_FUNCTION_STRING)='\0';
+#else
+#ifdef CRAYFortran
+#define STRING_cfE static char AA0[1+MAX_LEN_FORTRAN_FUNCTION_STRING]; \
+ static _fcd A0; *(AA0+MAX_LEN_FORTRAN_FUNCTION_STRING)='\0';\
+ memset(AA0,CFORTRAN_NON_CHAR, MAX_LEN_FORTRAN_FUNCTION_STRING);\
+ A0 = _cptofcd(AA0,MAX_LEN_FORTRAN_FUNCTION_STRING);
+#else
+/* 'cc: SC3.0.1 13 Jul 1994' barfs on char A0[0x4FE+1];
+ * char A0[0x4FE +1]; char A0[1+0x4FE]; are both OK. */
+#define STRING_cfE static char A0[1+MAX_LEN_FORTRAN_FUNCTION_STRING]; \
+ memset(A0, CFORTRAN_NON_CHAR, \
+ MAX_LEN_FORTRAN_FUNCTION_STRING); \
+ *(A0+MAX_LEN_FORTRAN_FUNCTION_STRING)='\0';
+#endif
+#endif
+/* ESTRING must use static char. array which is guaranteed to exist after
+ function returns. */
+
+/* N.B.i) The diff. for 0 (Zero) and >=1 arguments.
+ ii)That the following create an unmatched bracket, i.e. '(', which
+ must of course be matched in the call.
+ iii)Commas must be handled very carefully */
+#define INT_cfGZ(T,UN,LN) A0=CFC_(UN,LN)(
+#define VOID_cfGZ(T,UN,LN) CFC_(UN,LN)(
+#ifdef vmsFortran
+#define STRING_cfGZ(T,UN,LN) CFC_(UN,LN)(&A0
+#else
+#if defined(CRAYFortran) || defined(AbsoftUNIXFortran) || defined(AbsoftProFortran)
+#define STRING_cfGZ(T,UN,LN) CFC_(UN,LN)( A0
+#else
+#define STRING_cfGZ(T,UN,LN) CFC_(UN,LN)( A0,MAX_LEN_FORTRAN_FUNCTION_STRING
+#endif
+#endif
+
+#define INT_cfG(T,UN,LN) INT_cfGZ(T,UN,LN)
+#define VOID_cfG(T,UN,LN) VOID_cfGZ(T,UN,LN)
+#define STRING_cfG(T,UN,LN) STRING_cfGZ(T,UN,LN), /*, is only diff. from _cfG*/
+
+#define BYTEVVVVVVV_cfPP
+#define INTVVVVVVV_cfPP /* These complement FLOATVVVVVVV_cfPP. */
+#define DOUBLEVVVVVVV_cfPP
+#define LOGICALVVVVVVV_cfPP
+#define LONGVVVVVVV_cfPP
+#define SHORTVVVVVVV_cfPP
+#define PBYTE_cfPP
+#define PINT_cfPP
+#define PDOUBLE_cfPP
+#define PLOGICAL_cfPP
+#define PLONG_cfPP
+#define PSHORT_cfPP
+#define PFLOAT_cfPP FLOATVVVVVVV_cfPP
+
+#define BCF(TN,AN,C) _SEP_(TN,C,cfCOMMA) _Icf(2,B,TN,AN,0)
+#define INT_cfB(T,A) (_(T,VVVVVVV_cfTYPE)) A
+#define INTV_cfB(T,A) A
+#define INTVV_cfB(T,A) (A)[0]
+#define INTVVV_cfB(T,A) (A)[0][0]
+#define INTVVVV_cfB(T,A) (A)[0][0][0]
+#define INTVVVVV_cfB(T,A) (A)[0][0][0][0]
+#define INTVVVVVV_cfB(T,A) (A)[0][0][0][0][0]
+#define INTVVVVVVV_cfB(T,A) (A)[0][0][0][0][0][0]
+#define PINT_cfB(T,A) _(T,_cfPP)&A
+#define STRING_cfB(T,A) (char *) A
+#define STRINGV_cfB(T,A) (char *) A
+#define PSTRING_cfB(T,A) (char *) A
+#define PSTRINGV_cfB(T,A) (char *) A
+#define PVOID_cfB(T,A) (void *) A
+#define ROUTINE_cfB(T,A) (cfCAST_FUNCTION)A
+#define ZTRINGV_cfB(T,A) (char *) A
+#define PZTRINGV_cfB(T,A) (char *) A
+
+#define SCF(TN,NAME,I,A) _(TN,_cfSTR)(3,S,NAME,I,A,0,0)
+#define DEFAULT_cfS(M,I,A)
+#define LOGICAL_cfS(M,I,A)
+#define PLOGICAL_cfS(M,I,A)
+#define STRING_cfS(M,I,A) ,sizeof(A)
+#define STRINGV_cfS(M,I,A) ,( (unsigned)0xFFFF*firstindexlength(A) \
+ +secondindexlength(A))
+#define PSTRING_cfS(M,I,A) ,sizeof(A)
+#define PSTRINGV_cfS(M,I,A) STRINGV_cfS(M,I,A)
+#define ZTRINGV_cfS(M,I,A)
+#define PZTRINGV_cfS(M,I,A)
+
+#define HCF(TN,I) _(TN,_cfSTR)(3,H,cfCOMMA, H,_(C,I),0,0)
+#define HHCF(TN,I) _(TN,_cfSTR)(3,H,cfCOMMA,HH,_(C,I),0,0)
+#define HHHCF(TN,I) _(TN,_cfSTR)(3,H,cfCOLON, H,_(C,I),0,0)
+#define H_CF_SPECIAL unsigned
+#define HH_CF_SPECIAL
+#define DEFAULT_cfH(M,I,A)
+#define LOGICAL_cfH(S,U,B)
+#define PLOGICAL_cfH(S,U,B)
+#define STRING_cfH(S,U,B) _(A,S) _(U,_CF_SPECIAL) B
+#define STRINGV_cfH(S,U,B) STRING_cfH(S,U,B)
+#define PSTRING_cfH(S,U,B) STRING_cfH(S,U,B)
+#define PSTRINGV_cfH(S,U,B) STRING_cfH(S,U,B)
+#define PNSTRING_cfH(S,U,B) STRING_cfH(S,U,B)
+#define PPSTRING_cfH(S,U,B) STRING_cfH(S,U,B)
+#define ZTRINGV_cfH(S,U,B)
+#define PZTRINGV_cfH(S,U,B)
+
+/* Need VOID_cfSTR because Absoft forced function types go through _cfSTR. */
+/* No spaces inside expansion. They screws up macro catenation kludge. */
+#define VOID_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define BYTE_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define DOUBLE_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define FLOAT_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define INT_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define LOGICAL_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,LOGICAL,A,B,C,D,E)
+#define LONG_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define SHORT_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define BYTEV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define BYTEVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define BYTEVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define BYTEVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define BYTEVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define BYTEVVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define BYTEVVVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define DOUBLEV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define DOUBLEVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define DOUBLEVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define DOUBLEVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define DOUBLEVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define DOUBLEVVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define DOUBLEVVVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define FLOATV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define FLOATVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define FLOATVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define FLOATVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define FLOATVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define FLOATVVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define FLOATVVVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define INTV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define INTVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define INTVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define INTVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define INTVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define INTVVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define INTVVVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define LOGICALV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define LOGICALVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define LOGICALVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define LOGICALVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define LOGICALVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define LOGICALVVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define LOGICALVVVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define LONGV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define LONGVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define LONGVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define LONGVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define LONGVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define LONGVVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define LONGVVVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define SHORTV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define SHORTVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define SHORTVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define SHORTVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define SHORTVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define SHORTVVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define SHORTVVVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define PBYTE_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define PDOUBLE_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define PFLOAT_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define PINT_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define PLOGICAL_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,PLOGICAL,A,B,C,D,E)
+#define PLONG_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define PSHORT_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define STRING_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,STRING,A,B,C,D,E)
+#define PSTRING_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,PSTRING,A,B,C,D,E)
+#define STRINGV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,STRINGV,A,B,C,D,E)
+#define PSTRINGV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,PSTRINGV,A,B,C,D,E)
+#define PNSTRING_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,PNSTRING,A,B,C,D,E)
+#define PPSTRING_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,PPSTRING,A,B,C,D,E)
+#define PVOID_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define ROUTINE_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define SIMPLE_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define ZTRINGV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,ZTRINGV,A,B,C,D,E)
+#define PZTRINGV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,PZTRINGV,A,B,C,D,E)
+#define CF_0_cfSTR(N,T,A,B,C,D,E)
+
+/* See ACF table comments, which explain why CCF was split into two. */
+#define CCF(NAME,TN,I) _(TN,_cfSTR)(5,C,NAME,I,_(A,I),_(B,I),_(C,I))
+#define DEFAULT_cfC(M,I,A,B,C)
+#define LOGICAL_cfC(M,I,A,B,C) A=C2FLOGICAL( A);
+#define PLOGICAL_cfC(M,I,A,B,C) *A=C2FLOGICAL(*A);
+#ifdef vmsFortran
+#define STRING_cfC(M,I,A,B,C) (B.clen=strlen(A),B.f.dsc$a_pointer=A, \
+ C==sizeof(char*)||C==(unsigned)(B.clen+1)?B.f.dsc$w_length=B.clen: \
+ (memset((A)+B.clen,' ',C-B.clen-1),A[B.f.dsc$w_length=C-1]='\0'));
+ /* PSTRING_cfC to beware of array A which does not contain any \0. */
+#define PSTRING_cfC(M,I,A,B,C) (B.dsc$a_pointer=A, C==sizeof(char*) ? \
+ B.dsc$w_length=strlen(A): (A[C-1]='\0',B.dsc$w_length=strlen(A), \
+ memset((A)+B.dsc$w_length,' ',C-B.dsc$w_length-1), B.dsc$w_length=C-1));
+#else
+#define STRING_cfC(M,I,A,B,C) (B.nombre=A,B.clen=strlen(A), \
+ C==sizeof(char*)||C==(unsigned)(B.clen+1)?B.flen=B.clen: \
+ (memset(B.nombre+B.clen,' ',C-B.clen-1),B.nombre[B.flen=C-1]='\0'));
+#define PSTRING_cfC(M,I,A,B,C) (C==sizeof(char*)? B=strlen(A): \
+ (A[C-1]='\0',B=strlen(A),memset((A)+B,' ',C-B-1),B=C-1));
+#endif
+ /* For CRAYFortran for (P)STRINGV_cfC, B.fs is set, but irrelevant. */
+#define STRINGV_cfC(M,I,A,B,C) \
+ AATRINGV_cfA( A,B,(C/0xFFFF)*(C%0xFFFF),C/0xFFFF,C%0xFFFF)
+#define PSTRINGV_cfC(M,I,A,B,C) \
+ APATRINGV_cfA( A,B,(C/0xFFFF)*(C%0xFFFF),C/0xFFFF,C%0xFFFF)
+#define ZTRINGV_cfC(M,I,A,B,C) \
+ AATRINGV_cfA( A,B, (_3(M,_ELEMS_,I))*((_3(M,_ELEMLEN_,I))+1), \
+ (_3(M,_ELEMS_,I)), (_3(M,_ELEMLEN_,I))+1 )
+#define PZTRINGV_cfC(M,I,A,B,C) \
+ APATRINGV_cfA( A,B, (_3(M,_ELEMS_,I))*((_3(M,_ELEMLEN_,I))+1), \
+ (_3(M,_ELEMS_,I)), (_3(M,_ELEMLEN_,I))+1 )
+
+#define BYTE_cfCCC(A,B) &A
+#define DOUBLE_cfCCC(A,B) &A
+#if !defined(__CF__KnR)
+#define FLOAT_cfCCC(A,B) &A
+ /* Although the VAX doesn't, at least the */
+#else /* HP and K&R mips promote float arg.'s of */
+#define FLOAT_cfCCC(A,B) &B /* unprototyped functions to double. Cannot */
+#endif /* use A here to pass the argument to FORTRAN. */
+#define INT_cfCCC(A,B) &A
+#define LOGICAL_cfCCC(A,B) &A
+#define LONG_cfCCC(A,B) &A
+#define SHORT_cfCCC(A,B) &A
+#define PBYTE_cfCCC(A,B) A
+#define PDOUBLE_cfCCC(A,B) A
+#define PFLOAT_cfCCC(A,B) A
+#define PINT_cfCCC(A,B) A
+#define PLOGICAL_cfCCC(A,B) B=A /* B used to keep a common W table. */
+#define PLONG_cfCCC(A,B) A
+#define PSHORT_cfCCC(A,B) A
+
+#define CCCF(TN,I,M) _SEP_(TN,M,cfCOMMA) _Icf(3,CC,TN,_(A,I),_(B,I))
+#define INT_cfCC(T,A,B) _(T,_cfCCC)(A,B)
+#define INTV_cfCC(T,A,B) A
+#define INTVV_cfCC(T,A,B) A
+#define INTVVV_cfCC(T,A,B) A
+#define INTVVVV_cfCC(T,A,B) A
+#define INTVVVVV_cfCC(T,A,B) A
+#define INTVVVVVV_cfCC(T,A,B) A
+#define INTVVVVVVV_cfCC(T,A,B) A
+#define PINT_cfCC(T,A,B) _(T,_cfCCC)(A,B)
+#define PVOID_cfCC(T,A,B) A
+#if defined(apolloFortran) || defined(hpuxFortran800) || defined(AbsoftUNIXFortran)
+#define ROUTINE_cfCC(T,A,B) &A
+#else
+#define ROUTINE_cfCC(T,A,B) A
+#endif
+#define SIMPLE_cfCC(T,A,B) A
+#ifdef vmsFortran
+#define STRING_cfCC(T,A,B) &B.f
+#define STRINGV_cfCC(T,A,B) &B
+#define PSTRING_cfCC(T,A,B) &B
+#define PSTRINGV_cfCC(T,A,B) &B
+#else
+#ifdef CRAYFortran
+#define STRING_cfCC(T,A,B) _cptofcd(A,B.flen)
+#define STRINGV_cfCC(T,A,B) _cptofcd(B.s,B.flen)
+#define PSTRING_cfCC(T,A,B) _cptofcd(A,B)
+#define PSTRINGV_cfCC(T,A,B) _cptofcd(A,B.flen)
+#else
+#define STRING_cfCC(T,A,B) A
+#define STRINGV_cfCC(T,A,B) B.fs
+#define PSTRING_cfCC(T,A,B) A
+#define PSTRINGV_cfCC(T,A,B) B.fs
+#endif
+#endif
+#define ZTRINGV_cfCC(T,A,B) STRINGV_cfCC(T,A,B)
+#define PZTRINGV_cfCC(T,A,B) PSTRINGV_cfCC(T,A,B)
+
+#define BYTE_cfX return A0;
+#define DOUBLE_cfX return A0;
+#if ! (defined(FLOATFUNCTIONTYPE)&&defined(ASSIGNFLOAT)&&defined(RETURNFLOAT))
+#define FLOAT_cfX return A0;
+#else
+#define FLOAT_cfX ASSIGNFLOAT(AA0,A0); return AA0;
+#endif
+#define INT_cfX return A0;
+#define LOGICAL_cfX return F2CLOGICAL(A0);
+#define LONG_cfX return A0;
+#define SHORT_cfX return A0;
+#define VOID_cfX return ;
+#if defined(vmsFortran) || defined(CRAYFortran)
+#define STRING_cfX return kill_trailing( \
+ kill_trailing(AA0,CFORTRAN_NON_CHAR),' ');
+#else
+#define STRING_cfX return kill_trailing( \
+ kill_trailing( A0,CFORTRAN_NON_CHAR),' ');
+#endif
+
+#define CFFUN(NAME) _(__cf__,NAME)
+
+/* Note that we don't use LN here, but we keep it for consistency. */
+#define CCALLSFFUN0(UN,LN) CFFUN(UN)()
+
+#ifdef OLD_VAXC /* Allow %CC-I-PARAMNOTUSED. */
+#pragma standard
+#endif
+
+#define CCALLSFFUN1( UN,LN,T1, A1) \
+ CCALLSFFUN5 (UN,LN,T1,CF_0,CF_0,CF_0,CF_0,A1,0,0,0,0)
+#define CCALLSFFUN2( UN,LN,T1,T2, A1,A2) \
+ CCALLSFFUN5 (UN,LN,T1,T2,CF_0,CF_0,CF_0,A1,A2,0,0,0)
+#define CCALLSFFUN3( UN,LN,T1,T2,T3, A1,A2,A3) \
+ CCALLSFFUN5 (UN,LN,T1,T2,T3,CF_0,CF_0,A1,A2,A3,0,0)
+#define CCALLSFFUN4( UN,LN,T1,T2,T3,T4, A1,A2,A3,A4)\
+ CCALLSFFUN5 (UN,LN,T1,T2,T3,T4,CF_0,A1,A2,A3,A4,0)
+#define CCALLSFFUN5( UN,LN,T1,T2,T3,T4,T5, A1,A2,A3,A4,A5) \
+ CCALLSFFUN10(UN,LN,T1,T2,T3,T4,T5,CF_0,CF_0,CF_0,CF_0,CF_0,A1,A2,A3,A4,A5,0,0,0,0,0)
+#define CCALLSFFUN6( UN,LN,T1,T2,T3,T4,T5,T6, A1,A2,A3,A4,A5,A6) \
+ CCALLSFFUN10(UN,LN,T1,T2,T3,T4,T5,T6,CF_0,CF_0,CF_0,CF_0,A1,A2,A3,A4,A5,A6,0,0,0,0)
+#define CCALLSFFUN7( UN,LN,T1,T2,T3,T4,T5,T6,T7, A1,A2,A3,A4,A5,A6,A7) \
+ CCALLSFFUN10(UN,LN,T1,T2,T3,T4,T5,T6,T7,CF_0,CF_0,CF_0,A1,A2,A3,A4,A5,A6,A7,0,0,0)
+#define CCALLSFFUN8( UN,LN,T1,T2,T3,T4,T5,T6,T7,T8, A1,A2,A3,A4,A5,A6,A7,A8) \
+ CCALLSFFUN10(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,CF_0,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,0,0)
+#define CCALLSFFUN9( UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,A1,A2,A3,A4,A5,A6,A7,A8,A9)\
+ CCALLSFFUN10(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,A9,0)
+#define CCALLSFFUN10(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA)\
+ CCALLSFFUN14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,CF_0,CF_0,CF_0,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,0,0,0,0)
+#define CCALLSFFUN11(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB)\
+ CCALLSFFUN14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,CF_0,CF_0,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,0,0,0)
+#define CCALLSFFUN12(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC)\
+ CCALLSFFUN14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,CF_0,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,0,0)
+#define CCALLSFFUN13(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD)\
+ CCALLSFFUN14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,0)
+
+#define CCALLSFFUN14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE)\
+((CFFUN(UN)( BCF(T1,A1,0) BCF(T2,A2,1) BCF(T3,A3,1) BCF(T4,A4,1) BCF(T5,A5,1) \
+ BCF(T6,A6,1) BCF(T7,A7,1) BCF(T8,A8,1) BCF(T9,A9,1) BCF(TA,AA,1) \
+ BCF(TB,AB,1) BCF(TC,AC,1) BCF(TD,AD,1) BCF(TE,AE,1) \
+ SCF(T1,LN,1,A1) SCF(T2,LN,2,A2) SCF(T3,LN,3,A3) SCF(T4,LN,4,A4) \
+ SCF(T5,LN,5,A5) SCF(T6,LN,6,A6) SCF(T7,LN,7,A7) SCF(T8,LN,8,A8) \
+ SCF(T9,LN,9,A9) SCF(TA,LN,10,AA) SCF(TB,LN,11,AB) SCF(TC,LN,12,AC) \
+ SCF(TD,LN,13,AD) SCF(TE,LN,14,AE))))
+
+/* N.B. Create a separate function instead of using (call function, function
+value here) because in order to create the variables needed for the input
+arg.'s which may be const.'s one has to do the creation within {}, but these
+can never be placed within ()'s. Therefore one must create wrapper functions.
+gcc, on the other hand may be able to avoid the wrapper functions. */
+
+/* Prototypes are needed to correctly handle the value returned correctly. N.B.
+Can only have prototype arg.'s with difficulty, a la G... table since FORTRAN
+functions returning strings have extra arg.'s. Don't bother, since this only
+causes a compiler warning to come up when one uses FCALLSCFUNn and CCALLSFFUNn
+for the same function in the same source code. Something done by the experts in
+debugging only.*/
+
+#define PROTOCCALLSFFUN0(F,UN,LN) \
+_(F,_cfPU)( CFC_(UN,LN))(CF_NULL_PROTO); \
+static _Icf(2,U,F,CFFUN(UN),0)() {_(F,_cfE) _Icf(3,GZ,F,UN,LN) ABSOFT_cf1(F));_(F,_cfX)}
+
+#define PROTOCCALLSFFUN1( T0,UN,LN,T1) \
+ PROTOCCALLSFFUN5 (T0,UN,LN,T1,CF_0,CF_0,CF_0,CF_0)
+#define PROTOCCALLSFFUN2( T0,UN,LN,T1,T2) \
+ PROTOCCALLSFFUN5 (T0,UN,LN,T1,T2,CF_0,CF_0,CF_0)
+#define PROTOCCALLSFFUN3( T0,UN,LN,T1,T2,T3) \
+ PROTOCCALLSFFUN5 (T0,UN,LN,T1,T2,T3,CF_0,CF_0)
+#define PROTOCCALLSFFUN4( T0,UN,LN,T1,T2,T3,T4) \
+ PROTOCCALLSFFUN5 (T0,UN,LN,T1,T2,T3,T4,CF_0)
+#define PROTOCCALLSFFUN5( T0,UN,LN,T1,T2,T3,T4,T5) \
+ PROTOCCALLSFFUN10(T0,UN,LN,T1,T2,T3,T4,T5,CF_0,CF_0,CF_0,CF_0,CF_0)
+#define PROTOCCALLSFFUN6( T0,UN,LN,T1,T2,T3,T4,T5,T6) \
+ PROTOCCALLSFFUN10(T0,UN,LN,T1,T2,T3,T4,T5,T6,CF_0,CF_0,CF_0,CF_0)
+#define PROTOCCALLSFFUN7( T0,UN,LN,T1,T2,T3,T4,T5,T6,T7) \
+ PROTOCCALLSFFUN10(T0,UN,LN,T1,T2,T3,T4,T5,T6,T7,CF_0,CF_0,CF_0)
+#define PROTOCCALLSFFUN8( T0,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8) \
+ PROTOCCALLSFFUN10(T0,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,CF_0,CF_0)
+#define PROTOCCALLSFFUN9( T0,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9) \
+ PROTOCCALLSFFUN10(T0,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,CF_0)
+#define PROTOCCALLSFFUN10(T0,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA) \
+ PROTOCCALLSFFUN14(T0,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,CF_0,CF_0,CF_0,CF_0)
+#define PROTOCCALLSFFUN11(T0,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB) \
+ PROTOCCALLSFFUN14(T0,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,CF_0,CF_0,CF_0)
+#define PROTOCCALLSFFUN12(T0,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC) \
+ PROTOCCALLSFFUN14(T0,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,CF_0,CF_0)
+#define PROTOCCALLSFFUN13(T0,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD) \
+ PROTOCCALLSFFUN14(T0,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,CF_0)
+
+/* HP/UX 9.01 cc requires the blank between '_Icf(3,G,T0,UN,LN) CCCF(T1,1,0)' */
+
+#ifndef __CF__KnR
+#define PROTOCCALLSFFUN14(T0,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE) \
+ _(T0,_cfPU)(CFC_(UN,LN))(CF_NULL_PROTO); static _Icf(2,U,T0,CFFUN(UN),0)( \
+ CFARGT14FS(UCF,HCF,_Z,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE) ) \
+{ CFARGT14S(VCF,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE) _(T0,_cfE) \
+ CCF(LN,T1,1) CCF(LN,T2,2) CCF(LN,T3,3) CCF(LN,T4,4) CCF(LN,T5,5) \
+ CCF(LN,T6,6) CCF(LN,T7,7) CCF(LN,T8,8) CCF(LN,T9,9) CCF(LN,TA,10) \
+ CCF(LN,TB,11) CCF(LN,TC,12) CCF(LN,TD,13) CCF(LN,TE,14) _Icf(3,G,T0,UN,LN) \
+ CFARGT14(CCCF,JCF,ABSOFT_cf1(T0),T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)); \
+ WCF(T1,A1,1) WCF(T2,A2,2) WCF(T3,A3,3) WCF(T4,A4,4) WCF(T5,A5,5) \
+ WCF(T6,A6,6) WCF(T7,A7,7) WCF(T8,A8,8) WCF(T9,A9,9) WCF(TA,A10,10) \
+ WCF(TB,A11,11) WCF(TC,A12,12) WCF(TD,A13,13) WCF(TE,A14,14) _(T0,_cfX)}
+#else
+#define PROTOCCALLSFFUN14(T0,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE) \
+ _(T0,_cfPU)(CFC_(UN,LN))(CF_NULL_PROTO); static _Icf(2,U,T0,CFFUN(UN),0)( \
+ CFARGT14FS(UUCF,HHCF,_Z,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE) ) \
+ CFARGT14FS(UUUCF,HHHCF,_Z,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE) ; \
+{ CFARGT14S(VCF,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE) _(T0,_cfE) \
+ CCF(LN,T1,1) CCF(LN,T2,2) CCF(LN,T3,3) CCF(LN,T4,4) CCF(LN,T5,5) \
+ CCF(LN,T6,6) CCF(LN,T7,7) CCF(LN,T8,8) CCF(LN,T9,9) CCF(LN,TA,10) \
+ CCF(LN,TB,11) CCF(LN,TC,12) CCF(LN,TD,13) CCF(LN,TE,14) _Icf(3,G,T0,UN,LN) \
+ CFARGT14(CCCF,JCF,ABSOFT_cf1(T0),T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)); \
+ WCF(T1,A1,1) WCF(T2,A2,2) WCF(T3,A3,3) WCF(T4,A4,4) WCF(T5,A5,5) \
+ WCF(T6,A6,6) WCF(T7,A7,7) WCF(T8,A8,8) WCF(T9,A9,9) WCF(TA,A10,10) \
+ WCF(TB,A11,11) WCF(TC,A12,12) WCF(TD,A13,13) WCF(TE,A14,14) _(T0,_cfX)}
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+/* UTILITIES FOR FORTRAN TO CALL C ROUTINES */
+
+#ifdef OLD_VAXC /* Prevent %CC-I-PARAMNOTUSED. */
+#pragma nostandard
+#endif
+
+#if defined(vmsFortran) || defined(CRAYFortran)
+#define DCF(TN,I)
+#define DDCF(TN,I)
+#define DDDCF(TN,I)
+#else
+#define DCF(TN,I) HCF(TN,I)
+#define DDCF(TN,I) HHCF(TN,I)
+#define DDDCF(TN,I) HHHCF(TN,I)
+#endif
+
+#define QCF(TN,I) _(TN,_cfSTR)(1,Q,_(B,I), 0,0,0,0)
+#define DEFAULT_cfQ(B)
+#define LOGICAL_cfQ(B)
+#define PLOGICAL_cfQ(B)
+#define STRINGV_cfQ(B) char *B; unsigned int _(B,N);
+#define STRING_cfQ(B) char *B=NULL;
+#define PSTRING_cfQ(B) char *B=NULL;
+#define PSTRINGV_cfQ(B) STRINGV_cfQ(B)
+#define PNSTRING_cfQ(B) char *B=NULL;
+#define PPSTRING_cfQ(B)
+
+#ifdef __sgi /* Else SGI gives warning 182 contrary to its C LRM A.17.7 */
+#define ROUTINE_orig *(void**)&
+#else
+#define ROUTINE_orig (void *)
+#endif
+
+#define ROUTINE_1 ROUTINE_orig
+#define ROUTINE_2 ROUTINE_orig
+#define ROUTINE_3 ROUTINE_orig
+#define ROUTINE_4 ROUTINE_orig
+#define ROUTINE_5 ROUTINE_orig
+#define ROUTINE_6 ROUTINE_orig
+#define ROUTINE_7 ROUTINE_orig
+#define ROUTINE_8 ROUTINE_orig
+#define ROUTINE_9 ROUTINE_orig
+#define ROUTINE_10 ROUTINE_orig
+#define ROUTINE_11 ROUTINE_orig
+#define ROUTINE_12 ROUTINE_orig
+#define ROUTINE_13 ROUTINE_orig
+#define ROUTINE_14 ROUTINE_orig
+#define ROUTINE_15 ROUTINE_orig
+#define ROUTINE_16 ROUTINE_orig
+#define ROUTINE_17 ROUTINE_orig
+#define ROUTINE_18 ROUTINE_orig
+#define ROUTINE_19 ROUTINE_orig
+#define ROUTINE_20 ROUTINE_orig
+#define ROUTINE_21 ROUTINE_orig
+#define ROUTINE_22 ROUTINE_orig
+#define ROUTINE_23 ROUTINE_orig
+#define ROUTINE_24 ROUTINE_orig
+#define ROUTINE_25 ROUTINE_orig
+#define ROUTINE_26 ROUTINE_orig
+#define ROUTINE_27 ROUTINE_orig
+
+#define TCF(NAME,TN,I,M) _SEP_(TN,M,cfCOMMA) _(TN,_cfT)(NAME,I,_(A,I),_(B,I),_(C,I))
+#define BYTE_cfT(M,I,A,B,D) *A
+#define DOUBLE_cfT(M,I,A,B,D) *A
+#define FLOAT_cfT(M,I,A,B,D) *A
+#define INT_cfT(M,I,A,B,D) *A
+#define LOGICAL_cfT(M,I,A,B,D) F2CLOGICAL(*A)
+#define LONG_cfT(M,I,A,B,D) *A
+#define SHORT_cfT(M,I,A,B,D) *A
+#define BYTEV_cfT(M,I,A,B,D) A
+#define DOUBLEV_cfT(M,I,A,B,D) A
+#define FLOATV_cfT(M,I,A,B,D) VOIDP A
+#define INTV_cfT(M,I,A,B,D) A
+#define LOGICALV_cfT(M,I,A,B,D) A
+#define LONGV_cfT(M,I,A,B,D) A
+#define SHORTV_cfT(M,I,A,B,D) A
+#define BYTEVV_cfT(M,I,A,B,D) (void *)A /* We have to cast to void *,*/
+#define BYTEVVV_cfT(M,I,A,B,D) (void *)A /* since we don't know the */
+#define BYTEVVVV_cfT(M,I,A,B,D) (void *)A /* dimensions of the array. */
+#define BYTEVVVVV_cfT(M,I,A,B,D) (void *)A /* i.e. Unfortunately, can't */
+#define BYTEVVVVVV_cfT(M,I,A,B,D) (void *)A /* check that the type */
+#define BYTEVVVVVVV_cfT(M,I,A,B,D) (void *)A /* matches the prototype. */
+#define DOUBLEVV_cfT(M,I,A,B,D) (void *)A
+#define DOUBLEVVV_cfT(M,I,A,B,D) (void *)A
+#define DOUBLEVVVV_cfT(M,I,A,B,D) (void *)A
+#define DOUBLEVVVVV_cfT(M,I,A,B,D) (void *)A
+#define DOUBLEVVVVVV_cfT(M,I,A,B,D) (void *)A
+#define DOUBLEVVVVVVV_cfT(M,I,A,B,D) (void *)A
+#define FLOATVV_cfT(M,I,A,B,D) (void *)A
+#define FLOATVVV_cfT(M,I,A,B,D) (void *)A
+#define FLOATVVVV_cfT(M,I,A,B,D) (void *)A
+#define FLOATVVVVV_cfT(M,I,A,B,D) (void *)A
+#define FLOATVVVVVV_cfT(M,I,A,B,D) (void *)A
+#define FLOATVVVVVVV_cfT(M,I,A,B,D) (void *)A
+#define INTVV_cfT(M,I,A,B,D) (void *)A
+#define INTVVV_cfT(M,I,A,B,D) (void *)A
+#define INTVVVV_cfT(M,I,A,B,D) (void *)A
+#define INTVVVVV_cfT(M,I,A,B,D) (void *)A
+#define INTVVVVVV_cfT(M,I,A,B,D) (void *)A
+#define INTVVVVVVV_cfT(M,I,A,B,D) (void *)A
+#define LOGICALVV_cfT(M,I,A,B,D) (void *)A
+#define LOGICALVVV_cfT(M,I,A,B,D) (void *)A
+#define LOGICALVVVV_cfT(M,I,A,B,D) (void *)A
+#define LOGICALVVVVV_cfT(M,I,A,B,D) (void *)A
+#define LOGICALVVVVVV_cfT(M,I,A,B,D) (void *)A
+#define LOGICALVVVVVVV_cfT(M,I,A,B,D) (void *)A
+#define LONGVV_cfT(M,I,A,B,D) (void *)A
+#define LONGVVV_cfT(M,I,A,B,D) (void *)A
+#define LONGVVVV_cfT(M,I,A,B,D) (void *)A
+#define LONGVVVVV_cfT(M,I,A,B,D) (void *)A
+#define LONGVVVVVV_cfT(M,I,A,B,D) (void *)A
+#define LONGVVVVVVV_cfT(M,I,A,B,D) (void *)A
+#define SHORTVV_cfT(M,I,A,B,D) (void *)A
+#define SHORTVVV_cfT(M,I,A,B,D) (void *)A
+#define SHORTVVVV_cfT(M,I,A,B,D) (void *)A
+#define SHORTVVVVV_cfT(M,I,A,B,D) (void *)A
+#define SHORTVVVVVV_cfT(M,I,A,B,D) (void *)A
+#define SHORTVVVVVVV_cfT(M,I,A,B,D) (void *)A
+#define PBYTE_cfT(M,I,A,B,D) A
+#define PDOUBLE_cfT(M,I,A,B,D) A
+#define PFLOAT_cfT(M,I,A,B,D) VOIDP A
+#define PINT_cfT(M,I,A,B,D) A
+#define PLOGICAL_cfT(M,I,A,B,D) ((*A=F2CLOGICAL(*A)),A)
+#define PLONG_cfT(M,I,A,B,D) A
+#define PSHORT_cfT(M,I,A,B,D) A
+#define PVOID_cfT(M,I,A,B,D) A
+#if defined(apolloFortran) || defined(hpuxFortran800) || defined(AbsoftUNIXFortran)
+#define ROUTINE_cfT(M,I,A,B,D) _(ROUTINE_,I) (*A)
+#else
+#define ROUTINE_cfT(M,I,A,B,D) _(ROUTINE_,I) A
+#endif
+/* A == pointer to the characters
+ D == length of the string, or of an element in an array of strings
+ E == number of elements in an array of strings */
+#define TTSTR( A,B,D) \
+ ((B=_cf_malloc(D+1))[D]='\0', memcpy(B,A,D), kill_trailing(B,' '))
+#define TTTTSTR( A,B,D) (!(D<4||A[0]||A[1]||A[2]||A[3]))?NULL: \
+ memchr(A,'\0',D) ?A : TTSTR(A,B,D)
+#define TTTTSTRV( A,B,D,E) (_(B,N)=E,B=_cf_malloc(_(B,N)*(D+1)), (void *) \
+ vkill_trailing(f2cstrv(A,B,D+1, _(B,N)*(D+1)), D+1,_(B,N)*(D+1),' '))
+#ifdef vmsFortran
+#define STRING_cfT(M,I,A,B,D) TTTTSTR( A->dsc$a_pointer,B,A->dsc$w_length)
+#define STRINGV_cfT(M,I,A,B,D) TTTTSTRV(A->dsc$a_pointer, B, \
+ A->dsc$w_length , A->dsc$l_m[0])
+#define PSTRING_cfT(M,I,A,B,D) TTSTR( A->dsc$a_pointer,B,A->dsc$w_length)
+#define PPSTRING_cfT(M,I,A,B,D) A->dsc$a_pointer
+#else
+#ifdef CRAYFortran
+#define STRING_cfT(M,I,A,B,D) TTTTSTR( _fcdtocp(A),B,_fcdlen(A))
+#define STRINGV_cfT(M,I,A,B,D) TTTTSTRV(_fcdtocp(A),B,_fcdlen(A), \
+ num_elem(_fcdtocp(A),_fcdlen(A),_3(M,_STRV_A,I)))
+#define PSTRING_cfT(M,I,A,B,D) TTSTR( _fcdtocp(A),B,_fcdlen(A))
+#define PPSTRING_cfT(M,I,A,B,D) _fcdtocp(A)
+#else
+#define STRING_cfT(M,I,A,B,D) TTTTSTR( A,B,D)
+#define STRINGV_cfT(M,I,A,B,D) TTTTSTRV(A,B,D, num_elem(A,D,_3(M,_STRV_A,I)))
+#define PSTRING_cfT(M,I,A,B,D) TTSTR( A,B,D)
+#define PPSTRING_cfT(M,I,A,B,D) A
+#endif
+#endif
+#define PNSTRING_cfT(M,I,A,B,D) STRING_cfT(M,I,A,B,D)
+#define PSTRINGV_cfT(M,I,A,B,D) STRINGV_cfT(M,I,A,B,D)
+#define CF_0_cfT(M,I,A,B,D)
+
+#define RCF(TN,I) _(TN,_cfSTR)(3,R,_(A,I),_(B,I),_(C,I),0,0)
+#define DEFAULT_cfR(A,B,D)
+#define LOGICAL_cfR(A,B,D)
+#define PLOGICAL_cfR(A,B,D) *A=C2FLOGICAL(*A);
+#define STRING_cfR(A,B,D) if (B) _cf_free(B);
+#define STRINGV_cfR(A,B,D) _cf_free(B);
+/* A and D as defined above for TSTRING(V) */
+#define RRRRPSTR( A,B,D) if (B) memcpy(A,B, _cfMIN(strlen(B),D)), \
+ (D>strlen(B)?memset(A+strlen(B),' ', D-strlen(B)):0), _cf_free(B);
+#define RRRRPSTRV(A,B,D) c2fstrv(B,A,D+1,(D+1)*_(B,N)), _cf_free(B);
+#ifdef vmsFortran
+#define PSTRING_cfR(A,B,D) RRRRPSTR( A->dsc$a_pointer,B,A->dsc$w_length)
+#define PSTRINGV_cfR(A,B,D) RRRRPSTRV(A->dsc$a_pointer,B,A->dsc$w_length)
+#else
+#ifdef CRAYFortran
+#define PSTRING_cfR(A,B,D) RRRRPSTR( _fcdtocp(A),B,_fcdlen(A))
+#define PSTRINGV_cfR(A,B,D) RRRRPSTRV(_fcdtocp(A),B,_fcdlen(A))
+#else
+#define PSTRING_cfR(A,B,D) RRRRPSTR( A,B,D)
+#define PSTRINGV_cfR(A,B,D) RRRRPSTRV(A,B,D)
+#endif
+#endif
+#define PNSTRING_cfR(A,B,D) PSTRING_cfR(A,B,D)
+#define PPSTRING_cfR(A,B,D)
+
+#define BYTE_cfFZ(UN,LN) INTEGER_BYTE FCALLSC_QUALIFIER fcallsc(UN,LN)(
+#define DOUBLE_cfFZ(UN,LN) DOUBLE_PRECISION FCALLSC_QUALIFIER fcallsc(UN,LN)(
+#define INT_cfFZ(UN,LN) int FCALLSC_QUALIFIER fcallsc(UN,LN)(
+#define LOGICAL_cfFZ(UN,LN) int FCALLSC_QUALIFIER fcallsc(UN,LN)(
+#define LONG_cfFZ(UN,LN) long FCALLSC_QUALIFIER fcallsc(UN,LN)(
+#define SHORT_cfFZ(UN,LN) short FCALLSC_QUALIFIER fcallsc(UN,LN)(
+#define VOID_cfFZ(UN,LN) void FCALLSC_QUALIFIER fcallsc(UN,LN)(
+#ifndef __CF__KnR
+/* The void is req'd by the Apollo, to make this an ANSI function declaration.
+ The Apollo promotes K&R float functions to double. */
+#define FLOAT_cfFZ(UN,LN) FORTRAN_REAL FCALLSC_QUALIFIER fcallsc(UN,LN)(void
+#ifdef vmsFortran
+#define STRING_cfFZ(UN,LN) void FCALLSC_QUALIFIER fcallsc(UN,LN)(fstring *AS
+#else
+#ifdef CRAYFortran
+#define STRING_cfFZ(UN,LN) void FCALLSC_QUALIFIER fcallsc(UN,LN)(_fcd AS
+#else
+#if defined(AbsoftUNIXFortran) || defined(AbsoftProFortran)
+#define STRING_cfFZ(UN,LN) void FCALLSC_QUALIFIER fcallsc(UN,LN)(char *AS
+#else
+#define STRING_cfFZ(UN,LN) void FCALLSC_QUALIFIER fcallsc(UN,LN)(char *AS, unsigned D0
+#endif
+#endif
+#endif
+#else
+#if ! (defined(FLOATFUNCTIONTYPE)&&defined(ASSIGNFLOAT)&&defined(RETURNFLOAT))
+#define FLOAT_cfFZ(UN,LN) FORTRAN_REAL FCALLSC_QUALIFIER fcallsc(UN,LN)(
+#else
+#define FLOAT_cfFZ(UN,LN) FLOATFUNCTIONTYPE FCALLSC_QUALIFIER fcallsc(UN,LN)(
+#endif
+#if defined(vmsFortran) || defined(CRAYFortran) || defined(AbsoftUNIXFortran)
+#define STRING_cfFZ(UN,LN) void FCALLSC_QUALIFIER fcallsc(UN,LN)(AS
+#else
+#define STRING_cfFZ(UN,LN) void FCALLSC_QUALIFIER fcallsc(UN,LN)(AS, D0
+#endif
+#endif
+
+#define BYTE_cfF(UN,LN) BYTE_cfFZ(UN,LN)
+#define DOUBLE_cfF(UN,LN) DOUBLE_cfFZ(UN,LN)
+#ifndef __CF_KnR
+#define FLOAT_cfF(UN,LN) FORTRAN_REAL FCALLSC_QUALIFIER fcallsc(UN,LN)(
+#else
+#define FLOAT_cfF(UN,LN) FLOAT_cfFZ(UN,LN)
+#endif
+#define INT_cfF(UN,LN) INT_cfFZ(UN,LN)
+#define LOGICAL_cfF(UN,LN) LOGICAL_cfFZ(UN,LN)
+#define LONG_cfF(UN,LN) LONG_cfFZ(UN,LN)
+#define SHORT_cfF(UN,LN) SHORT_cfFZ(UN,LN)
+#define VOID_cfF(UN,LN) VOID_cfFZ(UN,LN)
+#define STRING_cfF(UN,LN) STRING_cfFZ(UN,LN),
+
+#define INT_cfFF
+#define VOID_cfFF
+#ifdef vmsFortran
+#define STRING_cfFF fstring *AS;
+#else
+#ifdef CRAYFortran
+#define STRING_cfFF _fcd AS;
+#else
+#define STRING_cfFF char *AS; unsigned D0;
+#endif
+#endif
+
+#define INT_cfL A0=
+#define STRING_cfL A0=
+#define VOID_cfL
+
+#define INT_cfK
+#define VOID_cfK
+/* KSTRING copies the string into the position provided by the caller. */
+#ifdef vmsFortran
+#define STRING_cfK \
+ memcpy(AS->dsc$a_pointer,A0,_cfMIN(AS->dsc$w_length,(A0==NULL?0:strlen(A0))));\
+ AS->dsc$w_length>(A0==NULL?0:strlen(A0))? \
+ memset(AS->dsc$a_pointer+(A0==NULL?0:strlen(A0)),' ', \
+ AS->dsc$w_length-(A0==NULL?0:strlen(A0))):0;
+#else
+#ifdef CRAYFortran
+#define STRING_cfK \
+ memcpy(_fcdtocp(AS),A0, _cfMIN(_fcdlen(AS),(A0==NULL?0:strlen(A0))) ); \
+ _fcdlen(AS)>(A0==NULL?0:strlen(A0))? \
+ memset(_fcdtocp(AS)+(A0==NULL?0:strlen(A0)),' ', \
+ _fcdlen(AS)-(A0==NULL?0:strlen(A0))):0;
+#else
+#define STRING_cfK memcpy(AS,A0, _cfMIN(D0,(A0==NULL?0:strlen(A0))) ); \
+ D0>(A0==NULL?0:strlen(A0))?memset(AS+(A0==NULL?0:strlen(A0)), \
+ ' ', D0-(A0==NULL?0:strlen(A0))):0;
+#endif
+#endif
+
+/* Note that K.. and I.. can't be combined since K.. has to access data before
+R.., in order for functions returning strings which are also passed in as
+arguments to work correctly. Note that R.. frees and hence may corrupt the
+string. */
+#define BYTE_cfI return A0;
+#define DOUBLE_cfI return A0;
+#if ! (defined(FLOATFUNCTIONTYPE)&&defined(ASSIGNFLOAT)&&defined(RETURNFLOAT))
+#define FLOAT_cfI return A0;
+#else
+#define FLOAT_cfI RETURNFLOAT(A0);
+#endif
+#define INT_cfI return A0;
+#ifdef hpuxFortran800
+/* Incredibly, functions must return true as 1, elsewhere .true.==0x01000000. */
+#define LOGICAL_cfI return ((A0)?1:0);
+#else
+#define LOGICAL_cfI return C2FLOGICAL(A0);
+#endif
+#define LONG_cfI return A0;
+#define SHORT_cfI return A0;
+#define STRING_cfI return ;
+#define VOID_cfI return ;
+
+#ifdef OLD_VAXC /* Allow %CC-I-PARAMNOTUSED. */
+#pragma standard
+#endif
+
+#define FCALLSCSUB0( CN,UN,LN) FCALLSCFUN0(VOID,CN,UN,LN)
+#define FCALLSCSUB1( CN,UN,LN,T1) FCALLSCFUN1(VOID,CN,UN,LN,T1)
+#define FCALLSCSUB2( CN,UN,LN,T1,T2) FCALLSCFUN2(VOID,CN,UN,LN,T1,T2)
+#define FCALLSCSUB3( CN,UN,LN,T1,T2,T3) FCALLSCFUN3(VOID,CN,UN,LN,T1,T2,T3)
+#define FCALLSCSUB4( CN,UN,LN,T1,T2,T3,T4) \
+ FCALLSCFUN4(VOID,CN,UN,LN,T1,T2,T3,T4)
+#define FCALLSCSUB5( CN,UN,LN,T1,T2,T3,T4,T5) \
+ FCALLSCFUN5(VOID,CN,UN,LN,T1,T2,T3,T4,T5)
+#define FCALLSCSUB6( CN,UN,LN,T1,T2,T3,T4,T5,T6) \
+ FCALLSCFUN6(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6)
+#define FCALLSCSUB7( CN,UN,LN,T1,T2,T3,T4,T5,T6,T7) \
+ FCALLSCFUN7(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7)
+#define FCALLSCSUB8( CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8) \
+ FCALLSCFUN8(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8)
+#define FCALLSCSUB9( CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9) \
+ FCALLSCFUN9(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9)
+#define FCALLSCSUB10(CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA) \
+ FCALLSCFUN10(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA)
+#define FCALLSCSUB11(CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB) \
+ FCALLSCFUN11(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB)
+#define FCALLSCSUB12(CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC) \
+ FCALLSCFUN12(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC)
+#define FCALLSCSUB13(CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD) \
+ FCALLSCFUN13(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD)
+#define FCALLSCSUB14(CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE) \
+ FCALLSCFUN14(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)
+#define FCALLSCSUB15(CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF) \
+ FCALLSCFUN15(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF)
+#define FCALLSCSUB16(CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG) \
+ FCALLSCFUN16(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG)
+#define FCALLSCSUB17(CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH) \
+ FCALLSCFUN17(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH)
+#define FCALLSCSUB18(CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI) \
+ FCALLSCFUN18(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI)
+#define FCALLSCSUB19(CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ) \
+ FCALLSCFUN19(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ)
+#define FCALLSCSUB20(CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK) \
+ FCALLSCFUN20(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK)
+#define FCALLSCSUB21(CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL) \
+ FCALLSCFUN21(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL)
+#define FCALLSCSUB22(CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM) \
+ FCALLSCFUN22(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM)
+#define FCALLSCSUB23(CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN) \
+ FCALLSCFUN23(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN)
+#define FCALLSCSUB24(CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO) \
+ FCALLSCFUN24(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO)
+#define FCALLSCSUB25(CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP) \
+ FCALLSCFUN25(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP)
+#define FCALLSCSUB26(CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ) \
+ FCALLSCFUN26(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ)
+#define FCALLSCSUB27(CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR) \
+ FCALLSCFUN27(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR)
+
+
+#define FCALLSCFUN1( T0,CN,UN,LN,T1) \
+ FCALLSCFUN5 (T0,CN,UN,LN,T1,CF_0,CF_0,CF_0,CF_0)
+#define FCALLSCFUN2( T0,CN,UN,LN,T1,T2) \
+ FCALLSCFUN5 (T0,CN,UN,LN,T1,T2,CF_0,CF_0,CF_0)
+#define FCALLSCFUN3( T0,CN,UN,LN,T1,T2,T3) \
+ FCALLSCFUN5 (T0,CN,UN,LN,T1,T2,T3,CF_0,CF_0)
+#define FCALLSCFUN4( T0,CN,UN,LN,T1,T2,T3,T4) \
+ FCALLSCFUN5 (T0,CN,UN,LN,T1,T2,T3,T4,CF_0)
+#define FCALLSCFUN5( T0,CN,UN,LN,T1,T2,T3,T4,T5) \
+ FCALLSCFUN10(T0,CN,UN,LN,T1,T2,T3,T4,T5,CF_0,CF_0,CF_0,CF_0,CF_0)
+#define FCALLSCFUN6( T0,CN,UN,LN,T1,T2,T3,T4,T5,T6) \
+ FCALLSCFUN10(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,CF_0,CF_0,CF_0,CF_0)
+#define FCALLSCFUN7( T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7) \
+ FCALLSCFUN10(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,CF_0,CF_0,CF_0)
+#define FCALLSCFUN8( T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8) \
+ FCALLSCFUN10(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,CF_0,CF_0)
+#define FCALLSCFUN9( T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9) \
+ FCALLSCFUN10(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,CF_0)
+#define FCALLSCFUN10(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA) \
+ FCALLSCFUN14(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,CF_0,CF_0,CF_0,CF_0)
+#define FCALLSCFUN11(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB) \
+ FCALLSCFUN14(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,CF_0,CF_0,CF_0)
+#define FCALLSCFUN12(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC) \
+ FCALLSCFUN14(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,CF_0,CF_0)
+#define FCALLSCFUN13(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD) \
+ FCALLSCFUN14(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,CF_0)
+
+
+#define FCALLSCFUN15(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF) \
+ FCALLSCFUN20(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,CF_0,CF_0,CF_0,CF_0,CF_0)
+#define FCALLSCFUN16(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG) \
+ FCALLSCFUN20(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,CF_0,CF_0,CF_0,CF_0)
+#define FCALLSCFUN17(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH) \
+ FCALLSCFUN20(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,CF_0,CF_0,CF_0)
+#define FCALLSCFUN18(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI) \
+ FCALLSCFUN20(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,CF_0,CF_0)
+#define FCALLSCFUN19(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ) \
+ FCALLSCFUN20(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,CF_0)
+#define FCALLSCFUN20(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK) \
+ FCALLSCFUN27(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0)
+#define FCALLSCFUN21(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL) \
+ FCALLSCFUN27(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0)
+#define FCALLSCFUN22(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM) \
+ FCALLSCFUN27(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,CF_0,CF_0,CF_0,CF_0,CF_0)
+#define FCALLSCFUN23(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN) \
+ FCALLSCFUN27(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,CF_0,CF_0,CF_0,CF_0)
+#define FCALLSCFUN24(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO) \
+ FCALLSCFUN27(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,CF_0,CF_0,CF_0)
+#define FCALLSCFUN25(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP) \
+ FCALLSCFUN27(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,CF_0,CF_0)
+#define FCALLSCFUN26(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ) \
+ FCALLSCFUN27(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,CF_0)
+
+
+#ifndef __CF__KnR
+#define FCALLSCFUN0(T0,CN,UN,LN) CFextern _(T0,_cfFZ)(UN,LN) ABSOFT_cf2(T0)) \
+ {_Icf(2,UU,T0,A0,0); _Icf(0,L,T0,0,0) CN(); _Icf(0,K,T0,0,0) _(T0,_cfI)}
+
+#define FCALLSCFUN14(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE) \
+ CFextern _(T0,_cfF)(UN,LN) \
+ CFARGT14(NCF,DCF,ABSOFT_cf2(T0),T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE) ) \
+ { CFARGT14S(QCF,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE) \
+ _Icf(2,UU,T0,A0,0); _Icf(0,L,T0,0,0) CN( TCF(LN,T1,1,0) TCF(LN,T2,2,1) \
+ TCF(LN,T3,3,1) TCF(LN,T4,4,1) TCF(LN,T5,5,1) TCF(LN,T6,6,1) TCF(LN,T7,7,1) \
+ TCF(LN,T8,8,1) TCF(LN,T9,9,1) TCF(LN,TA,10,1) TCF(LN,TB,11,1) TCF(LN,TC,12,1) \
+ TCF(LN,TD,13,1) TCF(LN,TE,14,1) ); _Icf(0,K,T0,0,0) \
+ CFARGT14S(RCF,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE) _(T0,_cfI) }
+
+#define FCALLSCFUN27(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR) \
+ CFextern _(T0,_cfF)(UN,LN) \
+ CFARGT27(NCF,DCF,ABSOFT_cf2(T0),T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR) ) \
+ { CFARGT27S(QCF,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR) \
+ _Icf(2,UU,T0,A0,0); _Icf(0,L,T0,0,0) CN( TCF(LN,T1,1,0) TCF(LN,T2,2,1) \
+ TCF(LN,T3,3,1) TCF(LN,T4,4,1) TCF(LN,T5,5,1) TCF(LN,T6,6,1) TCF(LN,T7,7,1) \
+ TCF(LN,T8,8,1) TCF(LN,T9,9,1) TCF(LN,TA,10,1) TCF(LN,TB,11,1) TCF(LN,TC,12,1) \
+ TCF(LN,TD,13,1) TCF(LN,TE,14,1) TCF(LN,TF,15,1) TCF(LN,TG,16,1) TCF(LN,TH,17,1) \
+ TCF(LN,TI,18,1) TCF(LN,TJ,19,1) TCF(LN,TK,20,1) TCF(LN,TL,21,1) TCF(LN,TM,22,1) \
+ TCF(LN,TN,23,1) TCF(LN,TO,24,1) TCF(LN,TP,25,1) TCF(LN,TQ,26,1) TCF(LN,TR,27,1) ); _Icf(0,K,T0,0,0) \
+ CFARGT27S(RCF,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR) _(T0,_cfI) }
+
+#else
+#define FCALLSCFUN0(T0,CN,UN,LN) CFextern _(T0,_cfFZ)(UN,LN) ABSOFT_cf3(T0)) _Icf(0,FF,T0,0,0)\
+ {_Icf(2,UU,T0,A0,0); _Icf(0,L,T0,0,0) CN(); _Icf(0,K,T0,0,0) _(T0,_cfI)}
+
+#define FCALLSCFUN14(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE) \
+ CFextern _(T0,_cfF)(UN,LN) \
+ CFARGT14(NNCF,DDCF,ABSOFT_cf3(T0),T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)) _Icf(0,FF,T0,0,0) \
+ CFARGT14FS(NNNCF,DDDCF,_Z,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE); \
+ { CFARGT14S(QCF,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE) \
+ _Icf(2,UU,T0,A0,0); _Icf(0,L,T0,0,0) CN( TCF(LN,T1,1,0) TCF(LN,T2,2,1) \
+ TCF(LN,T3,3,1) TCF(LN,T4,4,1) TCF(LN,T5,5,1) TCF(LN,T6,6,1) TCF(LN,T7,7,1) \
+ TCF(LN,T8,8,1) TCF(LN,T9,9,1) TCF(LN,TA,10,1) TCF(LN,TB,11,1) TCF(LN,TC,12,1) \
+ TCF(LN,TD,13,1) TCF(LN,TE,14,1) ); _Icf(0,K,T0,0,0) \
+ CFARGT14S(RCF,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE) _(T0,_cfI)}
+
+#define FCALLSCFUN27(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR) \
+ CFextern _(T0,_cfF)(UN,LN) \
+ CFARGT27(NNCF,DDCF,ABSOFT_cf3(T0),T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR)) _Icf(0,FF,T0,0,0) \
+ CFARGT27FS(NNNCF,DDDCF,_Z,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR); \
+ { CFARGT27S(QCF,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR) \
+ _Icf(2,UU,T0,A0,0); _Icf(0,L,T0,0,0) CN( TCF(LN,T1,1,0) TCF(LN,T2,2,1) \
+ TCF(LN,T3,3,1) TCF(LN,T4,4,1) TCF(LN,T5,5,1) TCF(LN,T6,6,1) TCF(LN,T7,7,1) \
+ TCF(LN,T8,8,1) TCF(LN,T9,9,1) TCF(LN,TA,10,1) TCF(LN,TB,11,1) TCF(LN,TC,12,1) \
+ TCF(LN,TD,13,1) TCF(LN,TE,14,1) TCF(LN,TF,15,1) TCF(LN,TG,16,1) TCF(LN,TH,17,1) \
+ TCF(LN,TI,18,1) TCF(LN,TJ,19,1) TCF(LN,TK,20,1) TCF(LN,TL,21,1) TCF(LN,TM,22,1) \
+ TCF(LN,TN,23,1) TCF(LN,TO,24,1) TCF(LN,TP,25,1) TCF(LN,TQ,26,1) TCF(LN,TR,27,1) ); _Icf(0,K,T0,0,0) \
+ CFARGT27S(RCF,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR) _(T0,_cfI)}
+
+#endif
+
+
+#endif /* __CFORTRAN_LOADED */
diff --git a/pkg/tbtables/cfitsio/changes.txt b/pkg/tbtables/cfitsio/changes.txt
new file mode 100644
index 00000000..dceeb0fb
--- /dev/null
+++ b/pkg/tbtables/cfitsio/changes.txt
@@ -0,0 +1,2521 @@
+ Log of Changes Made to CFITSIO
+
+
+Version 2.501 - 2 December 2004
+
+ New Routines:
+
+ - added fits_open_diskfile and fits_create_diskfile routines that simply
+ open or create a FITS file with a specified name. CFITSIO does not
+ try to parse the name using the extended filename syntax.
+
+ - 2 new C functions, CFITS2Unit and CUnit2FITS, were added to convert
+ between the C fitsfile pointer value and the Fortran unit number.
+ These functions may be useful in mixed language C and Fortran programs.
+
+ Enhancements:
+
+ - added the ability to recognize and open a compressed FITS file
+ (compressed with gzip or unix compress) on the stdin standard input
+ stream.
+
+ - Craig Markwardt (GSFC) provided 2 more lexical parser functions:
+ accum(x) and seqdiff(x) that compute the cummulative sum and the
+ sequential difference of the values of x.
+
+ - modified putcole.c and putcold.c so that when writing arrays of
+ pixels to the FITS image or column that contain null values, and
+ there are also numerical overflows when converting some of the
+ non-null values to the FITS values, CFITSIO will now ignore the
+ overflow error until after all the data have been written. Previously,
+ in some circumstances CFITSIO would have simply stopped writing any
+ data after the first overflow error.
+
+ - modified fitsio2.h to try to eliminate compiler warning messages
+ on some platforms about the use of 'long long' constants when
+ defining the value of LONGLONG_MAX (whether to use L or LL
+ suffix).
+
+ - modified region.c to support 'physical' regions in addition to
+ 'image', 'fk4', etc.
+
+ - modified ffiurl (input filename parsing routine) to increase the
+ maximum allowed extension number that can be specified from 9999
+ to 99999 (e.g. 'myfile.fits+99999')
+
+ Bug Fixes:
+
+ - added check to fits_create_template to force it to start with
+ the primary array in the template file, in case an extension
+ number was specified as part of the template FITS file name.
+
+Version 2.500 - 28 & 30 July 2004
+
+ New Routine:
+
+ - fits_file_exists tests whether the specified input file, or a
+ compressed version of the file, exists on disk.
+
+ Enhancements:
+
+ - modified the way CFITSIO reads and writes data in COMPLEX ('C') and
+ DBLCOMPLEX 'M' columns. Now, in all cases, when referring to the
+ number of elements in the vector, or the value of the offset to a
+ particular element within the vector, CFITSIO considers each pair of
+ numbers (the imaginary and real parts) as a single element instead of
+ treating each single number as an element. In particular, this changes
+ the behavior of fits_write_col_null when writing to complex columns.
+ It also changes the length of the 'nullarray' vector in the
+ fits_read_colnull routine; it is now only 1/2 as long as before.
+ Each element of the nullarray is set = 1 if either the real or
+ imaginary parts of the corresponding complex value have a null
+ value.(this change was added to version 2.500 on 30 July).
+
+ - Craig Markwardt, at GSFC, provided a number of significant enhancements
+ to the CFITSIO lexical parser that is used to evaluate expressions:
+
+ - the parser now can operate on bit columns ('X') in a similar
+ way as for other numeric columns (e.g., 'B' or 'I' columns)
+
+ - range checking has been implemented, so that the following
+ conditions return a Null value, rather than returning an error:
+ divide by zero, sqrt(negative), arccos(>1), arcsin(>1),
+ log(negative), log10(negative)
+
+ - new vector functions: MEDIAN, AVERAGE, STDDEV, and
+ NVALID (returns the number of non-null values in the vector)
+
+ - all the new functions (and SUM, MIN and MAX) ignore null values
+
+ - modified the iterator to support variable-length array columns
+
+ - modified configure to support AIX systems that have flock in a non-
+ standard location.
+
+ - modified configure to remove the -D_FILE_OFFSET_BITS flag when running
+ on Mac Darwin systems. This caused conflicts with the Fortran
+ wrappers, and should only be needed in any case when using CFITSIO
+ to read/write FITS files greater than 2.1 GB in size.
+
+ - modified fitsio2.h to support compilers that define LONG_LONG_MAX.
+
+ - modified ffrsim (resize an existing image) so that it supports changing
+ the datatype to an unsigned integer image using the USHORT_IMG and
+ ULONG_IMG definitions.
+
+ - modified the disk file driver (drvrfile.c) so that if an output
+ file is specified when opening an ordinary file (e.g. with the syntax
+ 'myfile.fits(outputfile.fits)' then it will make a copy of the file,
+ close the original file and open the copy. Previously, the
+ specified output file would be ignored unless the file was compressed.
+
+ - modified f77_wrap.h and f77_wrap3.c to support the Fortran wrappers
+ on 64-bit AMD Opteron machines
+
+ Bug fixes:
+
+ - made small change to ffsrow in eval_f.c to avoid potential array
+ bounds overflow.
+
+ - made small change to group.c to fix problem where an 'int' was
+ incorrectly being cast to a 'long'.
+
+ - corrected a memory allocation error in the new fits_hdr2str routine
+ that was added in version 2.48
+
+ - The on-the-fly row-selection filtering would fail with a segfault
+ if the length of a table row (NAXIS1 value) was greater than
+ 500000 bytes. A small change to eval_f.c was required to fix this.
+
+Version 2.490 - 11 February 2004
+
+ Bug fixes:
+
+ - fixed a bug that was introduced in the previous release, which caused
+ the CFITSIO parser to no longer move to a named extension when opening
+ a FITS file, e.g., when opening myfile.fit[events] CFITSIO would just
+ open the primary array instead of moving to the EVENTS extension.
+
+ - new group.c file from the INTEGRAL Science Data Center. It fixes
+ a problem when you attach a child to a parent and they are both
+ is the same file, but, that parent contains groups in other files.
+ In certain cases the attach would not happen because it seemed that
+ the new child was already in the parent group.
+
+ - fixed bug in fits_calculator_rng when performing a calculation
+ on a range of rows in a table, so that it does not reset the
+ value in all the other rows that are not in the range = 0.
+
+ - modified fits_write_chksum so that it updates the TFORMn
+ keywords for any variable length vector table columns BEFORE
+ calculating the CHECKSUM values. Otherwise the CHECKSUM
+ value is invalidated when the HDU is subsequently closed.
+
+Version 2.480 - 28 January 2004
+
+ New Routines:
+
+ - fits_get_img_equivtype - just like fits_get_img_type, except in
+ the case of scaled integer images, it returns the 'equivalent'
+ data type that is necessary to store the scaled data values.
+
+ - fits_hdr2str copies all the header keywords in the current HDU
+ into a single long character string. This is a convenient method
+ of passing the header information to other subroutines.
+ The user may exclude any specified keywords from the list.
+
+ Enhancements:
+
+ - modified the filename parser so that it accepts extension
+ names that begin with digits, as in 'myfile.fits[123TEST]'.
+ In this case CFITSIO will try to open the extension with
+ EXTNAME = '123TEST' instead of trying to move to the 123rd
+ extension in the file.
+
+ - the template keyword parser now preserves the comments on the
+ the mandatory FITS keywords if present, otherwise a standard
+ default comment is provided.
+
+ - modified the ftp driver file (drvrnet.c) to overcome a timeout
+ or hangup problem caused by some firewall software at the user's
+ end (Thanks to Bruce O'Neel for this fix).
+
+ - modified iraffits.c to incorporate Doug Mink's latest changes to
+ his wcstools library routines. The biggest change is that now
+ the actual image dimensions, rather than the physically stored
+ dimensions, are used when converting an IRAF file to FITS.
+
+ Bug fixes:
+
+ - when writing to ASCII FITS tables, the 'elemnum' parameter was
+ supposed to be ignored if it did not have the default value of 1.
+ In some cases however setting elemnum to a value other than 1
+ could cause the wrong number of rows to be produced in the output
+ table.
+
+ - If a cfitsio calculator expression was imported from a text file
+ (e.g. using the extended filename syntax 'file.fits[col @file.calc]')
+ and if any individual lines in that text file were greater than
+ 255 characters long, then a space character would be inserted
+ after the 255th character. This could corrupt the line if the space
+ was inserted within a column name or keyword name token.
+
+Version 2.480beta (used in the FTOOLS 5.3 release, 1 Nov 2003)
+
+ New Routines:
+
+ - fits_get_eqcoltype - just like fits_get_coltype, except in the
+ case of scaled integer columns, it returns the 'equivalent'
+ data type that is necessary to store the scaled data values.
+
+ - fits_split_names - splits an input string containing a comma or
+ space delimited list of names (typically file names or column
+ names) into individual name tokens.
+
+ Enhancements:
+
+ - changed fhist in histo.c so that it can make histograms of ASCII
+ table columns as well as binary table columns (as long as they
+ contain numeric data).
+
+ Bug fixes:
+
+ - removed an erroneous reference to listhead.c in makefile.vcc, that is
+ used to build the cfitsio dll under Windows. This caused a 'main'
+ routine to be added to the library, which causes problems when linking
+ fortran programs to cfitsio under windows.
+
+ - if an error occurs when opening for a 2nd time (with ffopen) a file that
+ is already open (e.g., the specified extension doesn't exist), and
+ if the file had been modified before attempting to reopen it, then
+ the modified buffers may not get written to disk and the internal
+ state of the file may become corrupted. ffclos was modified to
+ always set status=0 before calling ffflsh if the file has been
+ concurrently opened more than once.
+
+Version 2.470 - 18 August 2003
+
+ Enhancements:
+
+ - defined 'TSBYTE' to represent the 'signed char' datatype (similar to
+ 'TBYTE' that represents the 'unsigned char' datatype) and added
+ support for this datatype to all the routines that read or write
+ data to a FITS image or table. This was implemented by adding 2
+ new C source code files to the package: getcolsb.c and putcolsb.c.
+
+ - Defined a new '1S' shorthand data code for a signed byted column in
+ a binary table. CFITSIO will write TFORMn = '1B' and
+ TZEROn = -128 in this case, which is the convention used to
+ store signed byte values in a 'B' type column.
+
+ - in fitsio2.h, added test of whether `__x86_64__` is defined, to
+ support the new AMD Opteron 64-bit processor
+
+ - modified configure to not use the -fast compiler flag on Solaris
+ platforms when using the proprietary Solaris cc compilar. This
+ flag causes compilation problems in eval_y.c (compiler just
+ hangs forever).
+
+ Bug fixes:
+
+ - In the special case of writing 0 elements to a vector table column
+ that contains 0 rows, ffgcpr no longer adds a blank row to the table.
+
+ - added error checking code for cases where a ASCII string column
+ in a binary table is greater than 28800 characters wide, to avoid
+ going into an infinite loop.
+
+ - the fits_get_col_display_width routine was incorrectly returning
+ width = 0 for a 'A' binary table column that did not have an
+ explicit vector length character.
+
+Version 2.460 - 20 May 2003
+
+ Enhancements:
+
+ - modified the HTTP driver in drvrnet.c so that CFITSIO can read
+ FITS files via a proxy HTTP server. (This code was contributed by
+ Philippe Prugniel, Obs. de Lyon). To use this feature, the
+ 'http_proxy' environment variable must be defined with the
+ address (URL) and port number of the proxy server, i.e.,
+ > setenv http_proxy http://heasarc.gsfc.nasa.gov:3128
+ will use port 3128 on heasarc.gsfc.nasa.gov
+
+ - suppressed some compiler warnings by casting a variable of
+ type 'size_t' to type 'int' in fftkey (in fitscore.c) and
+ iraftofits and irafrdimge (in iraffits.c).
+
+Version 2.450 - 30 April 2003
+
+ Enhancements:
+
+ - modified the WCS keyword reading routine (ffgics) to support cases
+ where some of the CDi_j keywords are omitted (with an assumed
+ value = 0).
+
+ - Made a change to http_open_network in drvrnet.c to add a 'Host: '
+ string to the open request. This is required by newer HTTP 1.1
+ servers (so-called virtual servers).
+
+ - modified ffgcll (read logical table column) to return the illegal
+ character value itself if the FITS file contains a logical value that is
+ not equal to T, F or zero. Previously it treated this case the
+ same as if the FITS file value was = 0.
+
+ - modified fits_movnam_hdu (ffmnhd) so that it will move to a tile-
+ compressed image (that is stored in a binary table) if the input
+ desired HDU type is BINARY_TBL as well as if the HDU type = IMAGE_HDU.
+
+ Bug fixes:
+
+ - in the routine that checks the data fill bytes (ffcdfl), the call
+ to ffmbyt should not ignore an EOF error when trying to read the bytes.
+ This is a little-used routine that is not called by any other CFITSIO
+ routine.
+
+ - fits_copy_file was not reporting an error if it hit the End Of File
+ while copying the last extension in the input file to the output file.
+
+ - fixed inconsistencies in the virtual file column filter parser
+ (ffedit_columns) to properly support expressions which create or
+ modify a keyword, instead of a column. Previously it was only possible
+ to modify keywords in a table extension (not an image), and the
+ keyword filtering could cause some of the table columns to not
+ get propagated into the virtual file. Also, spaces are now
+ allowed within the specified keyword comment field.
+
+ - ffdtyp was incorrectly returning the data type of FITS keyword
+ values of the form '1E-09' (i.e., an exponential value without
+ a decimal point) as integer rather than floating point.
+
+ - The enhancement in the previous 2.440 release to allow more files to be
+ opened at one time introduced a bug: if ffclos is called with
+ a non-zero status value, then any subsequent call to ffopen will likely
+ cause a segmentation fault. The fits_clear_Fptr routine was modified
+ to fix this.
+
+ - rearranged the order of some computations in fits_resize_img so as
+ to not exceed the range of a 32-bit integer when dealing with
+ large images.
+
+ - the template parser routine, ngp_read_xtension, was testing for
+ "ASCIITABLE" instead of "TABLE" as the XTENSION value of an ASCII
+ table, and it did not allow for optional trailing spaces in the IMAGE"
+ or "TABLE" string value.
+
+Version 2.440 - 8 January 2003
+
+ Enhancements:
+
+ - modified the iterator function, ffiter, to operate on random
+ groups files.
+
+ - decoupled the NIOBUF (= 40) parameter from the limit on the number
+ FITS files that can be opened, so that more files may be opened
+ without the overhead of having to increase the number of NIOBUF
+ buffers. A new NMAXFILES parameter is defined in fitsio2.h which sets
+ the maximum number of opened FITS files. It is set = 300 by default.
+ Note however, that the underlying compiler or operating system may
+ not allow this many files to be opened at one time.
+
+ - updated the version of cfortran.h that is distributed with CFITSIO from
+ version 3.9 to version 4.4. This required changes to f77_wrap.h
+ and f77_wrap3.c. The original cfortran.h v4.4 file was modified
+ slightly to support CFITSIO and ftools (see comments in the header
+ of cfortran.h).
+
+ - modified ffhist so that it copies all the non-structural keywords from
+ the original binary table header to the binned image header.
+
+ - modified fits_get_keyclass so that it recognizes EXTNAME =
+ COMPRESSED_IMAGE as a special tile compression keyword.
+
+ - modified Makefile.in to support the standard --prefix convention
+ for specifying the install target directory.
+
+ Bug fixes:
+
+ - in fits_decompress_img, needed to add a call to ffpscl to turn
+ off the BZERO and BSCALE scaline when reading the compressed image.
+
+Version 2.430 - 4 November 2002
+
+ Enhancements:
+
+ - modified fits_create_hdu/ffcrhd so that it returns without doing
+ anything and does not generate an error if the current HDU is
+ already an empty HDU. There is no need in this case to append
+ a new empty HDU to the file.
+
+ - new version of group.c (supplied by B. O'Neel at the ISDC) fixes 2
+ limitations: 1 - Groups now have 256 characters rather than 160
+ for the path lengths in the group tables. - ISDC SPR 1720. 2 -
+ Groups now can have backpointers longer than 68 chars using the long
+ string convention. - ISDC SPR 1738.
+
+ - small change to f77_wrap.h and f77_wrap3.c to support the fortran
+ wrappers on SUN solaris 64-bit sparc systems (see also change to v2.033)
+
+ - small change to find_column in eval_f.c to support unsigned long
+ columns in binary tables (with TZEROn = 2147483648.0)
+
+ - small modification to cfortran.h to support Mac OS-X, (Darwin)
+
+ Bug fixes:
+
+ - When reading tile-compress images, the BSCALE and BZERO scaling
+ keywords were not being applied, if present.
+
+ - Previous changes to the error message stack code caused the
+ tile compressed image routines to not clean up spurious error
+ messages properly.
+
+ - fits_open_image was not skipping over null primary arrays.
+
+Version 2.420 - 19 July 2002
+
+ Enhancements:
+
+ - modified the virtual filename parser to support exponential notation
+ when specifing the min, max or binsize in a binning specifier, as in:
+ myfile.fits[binr X=1:10:1.0E-01, Y=1:10:1.0E-01]
+
+ - removed the limitation on the maximum number of HDUs in a FITS file
+ (limit used to be 1000 HDUs per file). Now any number of HDUs
+ can be written/read in a FITS file. (BUT files that have huge numbers
+ of HDUs can be difficult to manage and are not recommended);
+
+ - modified grparser.c to support HIERARCH keywords, based on
+ code supplied by Richard Mathar (Max-Planck)
+
+ - moved the ffflsh (fits_flush_buffer) from the private to the
+ public interface, since this routine may be useful for some
+ applications. It is much faster than ffflus.
+
+ - small change to the definition of OFF_T in fitsio.h to support
+ large files on IBM AIX operating systems.
+
+ Bug fixes:
+
+ - fixed potential problem reading beyond array bounds in ffpkls. This
+ would not have affected the content of any previously generated FITS
+ files.
+
+ - in the net driver code in drvrnet.c, the requested protocol string
+ was changed from "http/1.0" to "HTTP/1.0" to support apache 1.3.26.
+
+ - When using the virtual file syntax to open a vector cell in a binary
+ table as if it were a primary array image, there was a bug
+ in fits_copy_image_cell which garbled the data if the vector
+ was more than 30000 bytes long.
+
+ - fixed problem that caused fits_report_error to crash under Visual
+ C++ on Windows systems. The fix is to use the '/MD' switch
+ on the cl command line, or, in Visual Studio, under project
+ settings / C++ select use runtime library multithreaded DLL
+
+ - modified ffpscl so it does not attempt to reset the scaling values
+ in the internal structure if the image is tile-compressed.
+
+ - fixed multiple bugs in mem_rawfile_open which affected the case
+ where a raw binary file is read and converted on the fly into
+ a FITS file.
+
+ - several small changes to group.c to suppress compiler warnings.
+
+Version 2.410 - 22 April 2002 (used in the FTOOLS 5.2 release)
+
+ New Routines:
+
+ - fits_open_data behaves similarly to fits_open_file except that it
+ also will move to the first HDU containing significant data if
+ and an explicit HDU name or number to open was not specified.
+ This is useful for automatically skipping over a null primary
+ array when opening the file.
+
+ - fits_open_table and fits_open_image behaves similarly to
+ fits_open_data, except they move to the first table or image
+ HDU in the file, respectively.
+
+ - fits_write_errmark and fits_clear_errmark routines can be use
+ to write an invisible marker to the CFITSIO error stack, and
+ then clear any more recent messages on the stack, back to
+ that mark. This preserves any older messages on the stack.
+
+ - fits_parse_range utility routine parses a row list string
+ and returns integer arrays giving the min and max row in each
+ range.
+
+ - fits_delete_rowrange deletes a specified list of rows or row
+ ranges.
+
+ - fits_copy_file copies all or part of the HDUs in the input file
+ to the output file.
+
+ - added fits_insert_card/ffikey to the publicly defined set
+ of routines (previously, it was a private routine).
+
+ Enhancements:
+
+ - changed the default numeric display format in ffgkys from 'E' format
+ to 'G' format, and changed the format for 'X' columns to a
+ string of 8 1s or 0s representing each bit value.
+
+ - modified ffflsh so the system 'fflush' call is not made in cases
+ where the file was opened with 'READONLY' access.
+
+ - modified the output filename parser so the "-.gz", and "stdout.gz"
+ now cause the output file to be initially created in memory,
+ and then compressed and written out to the stdout stream when
+ the file is closed.
+
+ - modified the routines that delete rows from a table to also
+ update the variable length array heap, to remove any orphaned
+ data from the heap.
+
+ - modified ffedit_columns so that wild card characters may be
+ used when specifying column names in the 'col' file filter
+ specifier (e.g., file.fits[col TIME; *RAW] will create a
+ virtual table contain only the TIME column and any other columns
+ whose name ends with 'RAW').
+
+ - modified the keyword classifier utility, fits_get_keyclass, to
+ support cases where the input string is just the keyword name,
+ not the entire 80-character card.
+
+ - modified configure.in and configure to see if a proprietary
+ C compiler is available (e.g. 'cc'), and only use 'gcc' if not.
+
+ - modified ffcpcl (copy columns from one table to another) so that
+ it also copies any WCS keywords related to that column.
+
+ - included an alternate source file that can be used to replace
+ compress.c, which is distributed under the GNU General Public
+ License. The alternate file contains non-functional stubs for
+ the compression routines, which can be used to make a version of
+ CFITSIO that does not have the GPL restrictions (and is also less
+ functional since it cannot read or write compressed FITS files).
+
+ - modifications to the iterator routine (ffiter) to support writing
+ tile compressed output images.
+
+ - modified ffourl to support the [compress] qualifier when specifying
+ the optional output file name. E.g., file.fit(out.file[compress])[3]
+
+ - modified imcomp_compress_tile to fully support implicit data type
+ conversion when writing to tile-compressed images. Previously,
+ one could not write a floating point array to an integer compressed
+ image.
+
+ - increased the number of internal 2880-byte I/O buffers allocated
+ by CFITSIO from 25 to 40, in recognition of the larger amount
+ of memory available on typical machines today compared with
+ a few years ago. The number of buffers can be set by the user
+ with the NIOBUF parameter in fitsio2.h. (Setting this too large
+ can actually hurt performance).
+
+ - modified the #if statements in fitsio2.h, f77_wrap.h and f77_wrap1.c
+ to support the new Itanium 64-bit Intel PC.
+
+ - a couple minor modifications to fitsio.h needed to support the off_t
+ datatype on debian linux systems.
+
+ - increased internal buffer sizes in ffshft and ffsrow to improve
+ the I/O performance.
+
+ Bug fixes:
+
+ - fits_get_keyclass could sometimes try to append to an unterminated
+ string, causing an overflow of a string array.
+
+ - fits_create_template no longer worked because of improvements made
+ to other routines. Had to modify ffghdt to not try to rescan
+ the header keywords if the file is still empty and contains no
+ keywords yet.
+
+ - ffrtnm, which returns the root filename, sometimes did not work
+ properly when testing if the 'filename+n' convention was used for
+ specifying an extension number.
+
+ - fixed minor problem in the keyword template parsing routine, ffgthd
+ which in rare cases could cause an improperly terminated string to
+ be returned.
+
+ - the routine to compare 2 strings, ffcmps, failed to find a match
+ in comparing strings like "*R" and "ERROR" where the match occurs
+ on the last character, but where the same matching character occurs
+ previously in the 2nd string.
+
+ - the region file reading routine (ffrrgn) did not work correctly if
+ the region file (created by POW and perhaps other programs) had an
+ 'exclude' region (beginning with a '-' sign) as the first region
+ in the file. In this case all points outside the excluded region
+ should be accepted, but in fact no points were being accepted
+ in this case.
+
+Version 2.401 - 28 Jan 2002
+
+ - added the imcopy example program to the release (and Makefile)
+
+ Bug fixes:
+
+ - fixed typo in the imcompress code which affected compression
+ of 3D datacubes.
+
+ - made small change to fficls (insert column) to allow colums with
+ TFORMn = '1PU' and '1PV' to be inserted in a binary table. The
+ 'U' and 'V' are codes only used within CFITSIO to represent unsigned
+ 16-bit and 32-bit integers; They get replaced by '1PI' and '1PJ'
+ respectively in the FITS table header, along with the appropriate
+ TZEROn keyword.
+
+Version 2.400 - 18 Jan 2002
+
+ (N.B.: Application programs must be recompiled, not just relinked
+ with the new CFITSIO library because of changes made to fitsio.h)
+
+ New Routines:
+
+ - fits_write_subset/ffpss writes a rectangular subset (or the whole
+ image) to a FITS image.
+
+ - added a whole new family of routines to read and write arrays of
+ 'long long' integers (64-bit) to FITS images or table columns. The
+ new routine names all end in 'jj': ffpprjj, ffppnjj, ffp2djj,
+ ffp3djj, ffppssjj, ffpgpjj, ffpcljj, ffpcnjj. ffgpvjj, ffgpfjj,
+ ffg2djj, ffg3djj, ffgsvjj, ffgsfjj, ffggpjj, ffgcvjj, and ffgcfjj.
+
+ - added a set of helper routines that are used in conjunction with
+ the new support for tiled image compression. 3 routines set the
+ parameters that should be used when CFITSIO compresses an image:
+ fits_set_compression_type
+ fits_set_tile_dim
+ fits_set_noise_bits
+
+ 3 corresponding routines report back the current settings:
+ fits_get_compression_type
+ fits_get_tile_dim
+ fits_get_noise_bits
+
+ Enhancements:
+
+ - major enhancement was made to support writing to tile-compressed
+ images. In this format, the image is divided up into a rectangular
+ grid of tiles, and each tile of pixels is compressed individually
+ and stored in a row of a variable-length array column in a binary
+ table. CFITSIO has been able to transparently read this compressed
+ image format ever since version 2.1. Now all the CFITSIO image
+ writing routines also transparently support this format. There are
+ 2 ways to force CFITSIO to write compressed images: 1) call the
+ fits_set_compression_type routine before writing the image header
+ keywords, or 2), specify that the image should be compressed when
+ entering the name of the output FITS file, using a new extended
+ filename syntax. (examples: "myfile.fits[compress]" will use the
+ default compression parameters, and "myfile.fits[compress GZIP
+ 100,100] will use the GZIP compression algorithm with 100 x 100
+ pixel tiles.
+
+ - added new driver to support creating output .gz compressed fits
+ files. If the name of the output FITS file to be created ends with
+ '.gz' then CFITSIO will initially write the FITS file in memory and
+ then, when the FITS file is closed, CFITSIO will gzip the entire
+ file before writing it out to disk.
+
+ - when over-writing vectors in a variable length array in a binary
+ table, if the new vector to be written is less than or equal to
+ the length of the previously written vector, then CFITSIO will now
+ reuse the existing space in the heap, rather than always appending
+ the new array to the end of the heap.
+
+ - modified configure.in to support building cfitsio as a dynamic
+ library on Mac OS X. Use 'make shared' like on other UNIX platforms,
+ but a .dylib file will be created instead of .so. If installed in a
+ nonstandard location, add its location to the DYLD_LIBRARY_PATH
+ environment variable so that the library can be found at run time.
+
+ - made various modifications to better support the 8-byte long integer
+ datatype on more platforms. The 'LONGLONG' datatype is typedef'ed
+ to equal 'long long' on most Unix platforms and MacOS, and equal
+ to '__int64' on Windows machines.
+
+ - modified configure.in and makefile.in to better support cases
+ where the system has no Fortran compiler and thus the f77 wrapper
+ routines should not be compiled.
+
+ - made small modification to eval.y and eval_y.f to get rid of warning
+ on some platforms about redefinition of the 'alloca'.
+
+ Bug fixes:
+
+ - other recent bug fixes in ffdblk (delete blocks) caused ffdhdu (delete
+ HDU) to fail when trying to replace the primary array with a null
+ primary array.
+
+ - fixed bug that prevented inserting a new variable length column
+ into a table that already contained variable length data.
+
+ - modified fits_delete_file so that it will delete the file even if
+ the input status value is not equal to zero.
+
+ - in fits_resize_image, it was sometimes necessary to call ffrdef to
+ force the image structure to be defined.
+
+ - modified the filename parser to support input files with names like:
+ "myfile.fits.gz(mem://tmp)" in which the url type is specified for
+ the output file but not for the input file itself. This required
+ modifications to ffiurl and ffrtnm.
+
+Version 2.301 - 7 Dec 2001
+
+ Enhancements:
+
+ - modified the http file driver so that if the filename to be opened
+ contains a '?' character (most likely a cgi related string) then it
+ will not attempt to append a .gz or .Z as it would normally do.
+
+ - added support for the '!' clobber character when specifying
+ the output disk file name in CFITSIO's extended filename syntax, e.g.,
+ 'http://a.b.c.d/myfile.fits.gz(!outfile.fits)'
+
+ - added new device driver which is used when opening a compressed FITS
+ file on disk by uncompressing it into memory with READWRITE
+ access. This happens when specifying an output filename
+ 'mem://'.
+
+ - added 2 other device drivers to open http and ftp files in memory
+ with write access.
+
+ - improved the error trapping and reporting in cases where program
+ attempts to write to a READONLY file (especially in cases where the
+ 'file' resides in memory, as is the case when opening an ftp or http
+ file.
+
+ - modified the extended filename parser so that it is does not confuse
+ the bracket character '[' which is sometimes used in the root name
+ of files of type 'http://', as the start of an extname or row filter
+ expression. If the file is of type 'http://', the parser now
+ checks to see if the last character in the extended file name is
+ a ')' or ']'. If not, it does not try to parse the file name
+ any further.
+
+ - improved the efficiency when writing FITS files in memory, by
+ initially allocating enough memory for the entire HDU when it is
+ created, rather than incrementally reallocing memory 2880 bytes
+ at a time (modified ffrhdu and mem_truncate). This change also
+ means that the program will fail much sooner if it cannot allocate
+ enough memory to hold the entire FITS HDU.
+
+ Bug fixes:
+
+ - There was an error in the definition of the Fortran ftphtb wrapper
+ routine (writes required ASCII table header keywords) that caused
+ it to fail on DEC OSF and other platforms where sizeof(long) = 8.
+
+Version 2.300 - 23 Oct 2001
+
+ New Routines:
+
+ - fits_comp_img and fits_decomp_img are now fully supported and
+ documented. These routine compress and decompress, respective,
+ a FITS image using a new algorithm in which the image is first
+ divided into a grid of rectangular tiles, then the compressed byte
+ stream from each tile is stored in a row of a binary table.
+ CFITSIO can transparently read FITS images stored in this
+ compressed format. Compression ratios of 3 - 6 are typically
+ achieved. Large compression ratios are achieved for floating
+ point images by throwing away non-significant noise bits in the
+ pixel values.
+
+ - fits_test_heap tests the integrity of the binary table heap and
+ returns statistics on the amount of unused space in the heap and
+ the amount of space that is pointed to by more than 1 descriptor.
+
+ - fits_compress_heap which will reorder the arrays in the binary
+ table heap, recovering any unused space.
+
+ Enhancements:
+
+ - made substantial internal changes to the code to support FITS
+ files containing 64-bit integer data values. These files have
+ BITPIX = 64 or TFORMn = 'K'. This new feature in CFITSIO is
+ currently only enabled if SUPPORT_64BIT_INTEGERS is defined = 1 in
+ the beginning of the fitsio2.h file. By default support for
+ 64-bit integers is not enabled.
+
+ - improved the ability to read and return a table column value as a
+ formatted string by supporting quasi-legal TDISPn values which
+ have a lowercase format code letter, and by completely ignoring
+ other unrecognizable TDISPn values. Previously, unrecognized
+ TDISPn values could cause zero length strings to be returned.
+
+ - made fits_write_key_longstr more efficient when writing keywords
+ using the long string CONTINUE convention. It previously did not
+ use all the available space on each card when the string to be
+ written contained many single quote characters.
+
+ - added a new "CFITSIO Quick Start Guide" which provides all the
+ basic information needed to write C programs using CFITSIO.
+
+ - updated the standard COMMENT keywords that are written at the
+ beginning of every primary array to refer to the newly published
+ FITS Standard document in Astronomy and Astrophysics.
+ Note: because of this change, any FITS file created with this
+ version of CFITSIO will not be identical to the same file written
+ with a previous version of CFITSIO.
+
+ - replaced the 2 routines in pliocomp.c with new versions provided by
+ D Tody and N Zarate. These routines compress/uncompress image pixels
+ using the IRAF pixel list compression algorithm.
+
+ - modified fits_copy_hdu so that when copying a Primary Array
+ to an Image extension, the COMMENT cards which give the reference
+ to the A&A journal article about FITS are not copied. In the
+ inverse case the COMMENT keywords are inserted in the header.
+
+ - modified configure and Makefile.in to add capability to build a
+ shared version of the CFITSIO library. Type 'make shared' or
+ 'make libcfitsio.so' to invoke this option.
+
+ - disabled some uninformative error messages on the error stack:
+ 1) when calling ffclos (and then ffchdu) with input status > 0
+ 2) when ffmahd tries to move beyond the end of file.
+ The returned status value remains the same as before, but the
+ annoying error messages no longer get written to the error stack.
+
+ - The syntax for column filtering has been modified so that
+ if one only specifies a list of column names, then only those
+ columns will be copied into the output file. This provides a simple
+ way to make a copy of a table containing only a specified list of
+ columns. If the column specifier explicitly deletes a column, however,
+ than all the other columns will be copied to the filtered input
+ file, regardless of whether the columns were listed or not.
+ Similarly, if the expression specifies only a column to be modified
+ or created, then all the other columns in the table will be
+ copied.
+
+ mytable.fit[1][col Time;Rate] - only the Time and Rate
+ columns will be copied to the filtered input file.
+
+ mytable.fit[1][col -Time ] - all but the Time column are copied
+ to the filtered input file.
+
+ mytable.fit[1][col Rate;-Time] - same as above.
+
+ - changed a '#if defined' statement in f77_wrap.h and f77_wrap1.c
+ to support the fortran wrappers on 64-bit IBM/RS6000 systems
+
+ - modified group.c so that when attaching one group (the child) to
+ another (the parent), check in each file for the existence of a
+ pointer to the other before adding the link. This is to prevent
+ multiple links from forming under all circumstances.
+
+ - modified the filename parser to accept 'STDIN', 'stdin',
+ 'STDOUT' and 'stdout' in addition to '-' to mean read the
+ file from standard input or write to standard output.
+
+ - Added support for reversing an axis when reading a subsection
+ of a compressed image using the extended filename syntax, as in
+ myfile.fits+1[-*, *] or myfile.fits+1[600:501,501:600]
+
+ - When copying a compressed image to a uncompressed image, the
+ EXTNAME keyword is no longer copied if the value is equal to
+ 'COMPRESSED_IMAGE'.
+
+ - slight change to the comment field of the DATE keyword to reflect
+ the fact that the Unix system date and time is not true UTC time.
+
+ Bug fixes:
+
+ - fits_write_key_longstr was not writing the keyword if a null
+ input string value was given.
+
+ - writing data to a variable length column, if that binary table is not
+ the last HDU in the FITS file, might overwrite the following HDU.
+ Fixed this by changing the order of a couple operations in ffgcpr.
+
+ - deleting a column from a table containing variable length columns
+ could cause the last few FITS blocks of the file to be reset = 0.
+ This bug occurred as a result of modifications to ffdblk in v2.202.
+ This mainly affects users of the 'compress_fits' utility
+ program.
+
+ - fixed obscure problem when writing bits to a variable length 'B'
+ column.
+
+ - when reading a subsection of an image, the BSCALE and BZERO pixel
+ scaling may not have been applied when reading image pixel values
+ (even though the scaling keywords were properly written in the
+ header).
+
+ - fits_get_keyclass was not returning 'TYP_STRUCT_KEY' for the
+ END keyword.
+
+Version 2.204 - 26 July 2001
+
+ Bug fixes:
+
+ - Re-write of fits_clean_url in group.c to solve various problems
+ with invalid bounds checking.
+
+Version 2.203 - 19 July 2001 (version in FTOOLS v5.1)
+
+ Enhancements:
+
+ - When a row selection or calculator expression is written in
+ an external file (and read by CFITSIO with the '@filename' syntax)
+ the file can now contain comment lines. The comment line must
+ begin with 2 slash characters as the first 2 characters on the
+ line. CFITSIO will ignore the entire line when reading the
+ expression.
+
+ Bug fixes:
+
+ - With previous versions of CFITSIO, the pixel values in a FITS
+ image could be read incorrectly in the following case: when
+ opening a subset of a FITS image (using the
+ 'filename.fits[Xmin:Xmax,Ymin:Ymax]' notation) on a PC linux, PC
+ Windows, or DEC OSF machine (but not on a SUN or Mac). This
+ problem only occurs when reading more than 8640 bytes of data
+ (2160 4-byte integers) at a time, and usually only occurs if the
+ reading program reads the pixel data immediately after opening the
+ file, without first reading any header keywords. This error would
+ cause strips of zero valued pixels to appear at semi-random
+ positions in the image, where each strip usually would be 2880
+ bytes long. This problem does not affect cases where the input
+ subsetted image is simply copied to a new output FITS file.
+
+
+Version 2.202 - 22 May 2001
+
+ Enhancements:
+
+ - revised the logic in the routine that tests if a point is
+ within a region: if the first region is an excluded region,
+ then it implicitly assumes a prior include region covering
+ the entire detector. It also now supports cases where a
+ smaller include region is within a prior exclude region.
+
+ - made enhancement to ffgclb (read bytes) so that it can
+ also read values from a logical column, returning an array
+ of 1s and 0s.
+
+ - defined 2 new grouping error status values (349, 350) in
+ cfitsio.h and made minor changes to group.c to use these new
+ status values.
+
+ - modified fits_open_file so that if it encounters an error while
+ trying to move to a user-specified extension (or select a subset
+ of the rows in an input table, or make a histogram of the
+ column values) it will close the input file instead of leaving
+ it open.
+
+ - when using the extended filename syntax to filter the rows in
+ an input table, or create a histogram image from the values in
+ a table column, CFITSIO now writes HISTORY keywords in the
+ output file to document the filtering expression that was used.
+
+ Bug fixes:
+
+ - ffdblk (called by ffdrow) could overwrite the last FITS block(s) in
+ the file in some cases where one writes data to a variable length
+ column and then calls ffdrow to delete rows in the table. This
+ bug was similar to the ffiblk bug that was fixed in v2.033.
+
+ - modified fits_write_col_null to fix a problem which under unusual
+ circumstances would cause a End-of-File error when trying to
+ read back the value in an ASCII string column, after initializing
+ if by writing a null value to it.
+
+ - fixed obscure bug in the calculator function that caused an
+ error when trying to modify the value of a keyword in a HDU
+ that does not have a NAXIS2 keyword (e.g., a null primary array).
+
+ - the iterator function (in putcol.c) had a bug when calculating
+ the optimum number rows to process in the case where the table
+ has very wide rows (>33120 bytes) and the calculator expression
+ involves columns from more than one FITS table. This could
+ cause an infinite loop in calls to the ffcalc calculator function.
+
+ - fixed bug in ffmvec, which modifies the length of an
+ existing vector column in a binary table. If the vector
+ was reduced in length, the FITS file could sometimes be left
+ in a corrupted state, and in all cases the values in the remaining
+ vector elements of that column would be altered.
+
+ - in drvrfile.c, replaced calls to fsetpos and fgetpos with
+ fseek and ftell (or fseeko and ftello) because the fpos_t
+ filetype used in fsetpos is incompatible with the off_t
+ filetype used in fseek, at least on some platforms (Linux 7.0).
+ (This fix was inserted into the V2.201 release on April 4).
+
+ - added "#define fits_write_pixnull ffppxn" to longnam.h
+
+Version 2.201 - 15 March 2001
+
+ Enhancements
+
+ - enhanced the keyword reading routines so that they will do
+ implicit datatype conversion from a string keyword value
+ to a numeric keyword value, if the string consist of a
+ valid number enclosed in quotes. For example, the keyword
+ mykey = '37.5' can be read by ffgkye.
+
+ - modified ffiimg so that it is possible to insert a new
+ primary array at the beginning of the file. The original
+ primary array is then converted into an IMAGE extension.
+
+ - modified ffcpdt (copy data unit) to support the case where
+ the data unit is being copied between 2 HDUs in the same file.
+
+ - enhanced the fits_read_pix and fits_read_pixnull routines so
+ that they support the tiled image compression format that the
+ other image reading routines also support.
+
+ - modified the Extended File Name syntax to also accept a
+ minus sign (-) as well as an exclamation point (!) as
+ the leading character when specifying a column or or keyword
+ to be deleted, as in [col -time] will delete the TIME column.
+
+ - now completely support reading subimages, including pixel
+ increments in each dimension, for tile-compressed images
+ (where the compressed image tiles are stored in a binary
+ table).
+
+ Bug fixes:
+
+ - fixed confusion in the use of the fpos_t and off_t datatypes
+ in the fgetpos and fsetpos routines in drvrfile.c which caused
+ problems with the Windows VC++ compiler. (fpos_t is not
+ necessarily identical to off_t)
+
+ - fixed a typo in the fits_get_url function in group.c which
+ caused problems when determining the relative URL to a compressed
+ FITS file.
+
+ - included fitsio.h in the shared memory utility program,
+ smem.c, in order to define OFF_T.
+
+ - fixed typo in the datatype of 'nullvalue' in ffgsvi, which caused
+ attempts to read subsections of a short integer tiled compressed
+ image to fail with a bus error.
+
+ - fixed bug in ffdkey which sometimes worked incorrectly if one
+ tried to delete a nonexistent keyword beyond the end of the header.
+
+ - fixed problem in fits_select_image_section when it writes a dummy
+ value to the last pixel of the section. If the image contains
+ scaled integer pixels, then in some cases the pixel value could end
+ up out of range.
+
+ - fixed obscure bug in the ffpcn_ family of routines which gave
+ a floating exception when trying to write zero number of pixels to
+ a zero length array (why would anyone do this?)
+
+Version 2.200 - 26 Jan 2001
+
+ Enhancements
+
+ - updated the region filtering code to support the latest region
+ file formats that are generated by the POW, SAOtng and ds9
+ programs. Region positions may now be given in HH:MM:SS.s,
+ DD:MM:SS.s format, and region sizes may be given arcsec or arcmin
+ instead of only in pixel units. Also changed the logic so that if
+ multiple 'include' regions are specified in the region file, they
+ are ORed together, instead of ANDed, so that the filtering keeps
+ points that are located within any of the 'include' regions, not
+ just the intersection of the regions.
+
+ - added support for reading raw binary data arrays by converting
+ them on the fly into virtual FITS files.
+
+ - modified ffpmsg, which writes error messages to CFITSIO's internal
+ error stack, so that messages > 80 characters long will be wrapped
+ around into multiple 80 character messages, instead of just
+ being truncated at 80 characters.
+
+ - modified the CFITSIO parser so that expression which involve
+ scaled integer columns get cast to double rather than int.
+
+ - Modified the keyword template parsing routine, ffgthd, to
+ support the HIERARCH keyword.
+
+ - modified ffainit and ffbinit so that they don't unnecessarily
+ allocate 0 bytes of memory if there are no columns (TFIELDS = 0)
+ in the table that is being opened.
+
+ - modified fitsio2.h to support NetBSD on Alpha OSF platforms
+ (NetBSD does not define the '__unix__' symbol).
+
+ - changed the way OFF_T is defined in fitsio.h for greater
+ portability.
+
+ - changed drvrsmem.c so it is compiled only when HAVE_SHMEM_SERVICES
+ is defined in order to removed the conditional logic from the Makefile
+
+ - reorganized the CFITSIO User's guide to make it
+ clearer and easier for new users to learn the basic routines.
+
+ - fixed ffhdef (which reserves space for more header keywords) so
+ that is also updates the start position of the next HDU. This
+ affected the offset values returned by ffghof.
+
+Version 2.100 - 18 Oct 2000
+
+ Enhancements
+
+ - made substantial modification to the code to support Large files,
+ i.e., files larger than 2**31 bytes = 2.1GB. FITS files up to
+ 6 terabytes in size may now be read and written on platforms
+ that support Large files (currently only Solaris).
+
+ - modified ffpcom and ffphis, which write COMMENT and HISTORY
+ keywords, respectively, so that they now use columns 9 - 80,
+ instead of only columns 11 - 80. Previously, these routines
+ avoided using columns 9 and 10, but this is was unnecessarily
+ restrictive.
+
+ - modified ffdhdu so that instead of refusing to delete the
+ primary array, it will replace the current primary array
+ with a null primary array containing the bare minimum of
+ required keywords and no data.
+
+ New Routines
+
+ - fits_read_pix, fits_read_pixnull, fits_read_subset, and fits_write_pix
+ routines were added to enable reading and writing of Large images,
+ with more than 2.1e9 pixels. These new routines are now recommended
+ as the basic routines for reading and writing all images.
+
+ - fits_get_hduoff returns the byte offset in the file to
+ the start and end of the current HDU. This routine replaces the
+ now obsolete fits_get_hduaddr routine; it uses 'off_t' instead of
+ 'long' as the datatype of the arguments and can support offsets
+ in files greater than 2.1GB in size.
+
+ Bug fixes:
+
+ - fixed bug in fits_select_image_section that caused an integer
+ overflow when reading very large image sections (bigger than
+ 8192 x 8192 4-byte pixels).
+
+ - improved ffptbb, the low-level table writing routine, so that
+ it will insert additional rows in the table if the table is
+ not already big enough. Previously it would have just over-
+ written any HDUs following the table in the FITS file.
+
+ - fixed a bug in the fits_write_col_bit/ffpclx routine which
+ could not write to a bit 'X' column if that was the first column
+ in the table to be written to. This bug would not appear if
+ any other datatype column was written to first.
+
+ - nonsensible (but still formally legal) binary table TFORM values
+ such as '8A15', or '1A8' or 'A8' would confuse CFITSIO and cause it
+ to return a 308 error. When parsing the TFORMn = 'rAw' value,
+ the ffbnfm routine has been modified to ignore the 'w' value in cases
+ where w > r.
+
+ - fixed bug in the blsearch routine in iraffits.c which sometimes
+ caused an out-of-bounds string pointer to be returned when searching
+ for blank space in the header just before the 'END' keyword.
+
+ - fixed minor problem in ffgtcr in group.c, which sometimes failed
+ while trying to move to the end of file before appending a
+ grouping table.
+
+ - on Solaris, with Sun CC 5.0, one must check for '__unix' rather
+ than '__unix__' or 'unix' as it's symbol. Needed to modify this
+ in drvrfile.c in 3 places.
+
+ - in ffextn, the FITS file would be left open if the named
+ extension doesn't exist, thus preventing the file from being
+ opened again later with write access.
+
+ - fixed bug in ffiimg that would cause attempts to insert a new
+ image extension following a table extension, and in front of any
+ other type of extension, to fail.
+
+Version 2.037 - 6 July 2000
+
+ Enhancements
+
+ - added support in the extended filename syntax for flipping
+ an image along any axis either by specifying a starting
+ section pixel number greater than the ending pixel number,
+ or by using '-*' to flip the whole axis. Examples:
+ "myfile.fits[1:100, 50:10]" or "myfile.fits[-*,*]".
+
+ - when reading a section of an image with the extended filename
+ syntax (e.g. image.fits[1:100:2, 1:100:2), any CDi_j WCS keywords
+ will be updated if necessary to transfer the world coordinate
+ system from the imput image to the output image section.
+
+ - on UNIX platforms, added support for filenames that begin
+ with "~/" or "~user/". The "~" symbol will get expanded
+ into a string that gives the user's home directory.
+
+ - changed the filename parser to support disk file names that
+ begin with a minus sign. Previously, the leading minus sign would
+ cause CFITSIO to try to read/write the file from/to stdin/stdout.
+
+ - modified the general fits_update_key routine, which writes
+ or updates a keyword value, to use the 'G' display format
+ instead of the 'E' format for floating point keyword values.
+ This will eliminate trailing zeros from appearing in the value.
+
+ - added support for the "-CAR" celestial coordinate projection
+ in the ffwldp and ffxypx routines. The "-CAR" projection is
+ the default simplest possible linear projection.
+
+ - added new fits_create_memfile/ffimem routine to create a new
+ fits file at a designated memory location.
+
+ - ported f77_wrap.h and f77_wrap1.c so that the Fortran interface
+ wrappers work correctly on 64-bit SGI operating systems. In this
+ environment, C 'long's are 8-bytes long, but Fortran 'integers'
+ are still only 4-bytes long, so the words have to be converted
+ by the wrappers.
+
+ - minor modification to cfortran.h to automatically detect when it
+ is running on a linux platform, and then define f2cFortran in that
+ case. This eliminates the need to define -Df2cFortran on the
+ command line.
+
+ - modified group.c to support multiple "/" characters in
+ the path name of the file to be opened/created.
+
+ - minor modifications to the parser (eval.y, eval_f.c, eval_y.c)
+ to a) add the unary '+' operator, and b) support copying the
+ TDIMn keyword from the input to the output image under certain
+ circumstances.
+
+ - modified the lexical parser in eval_l.y and eval_l.c to
+ support #NULL and #SNULL constants which act to set the
+ value to Null. Support was also added for the C-conditional
+ expression: 'boolean ? trueVal : falseVal'.
+
+ - small modification to eval_f.c to write an error message to
+ the error stack if numerical overflow occurs when evaluating
+ an expression.
+
+ - configure and configure.in now support the egcs g77 compiler
+ on Linux platforms.
+
+ Bug fixes:
+
+ - fixed a significant bug when using the extended filename binning
+ syntax to generate a 2-dimensional image from a histogram of the
+ values in 2 table columns. This bug would cause table events that
+ should have been located in the row just below the bottom row of
+ the image (and thus should have been excluded from the histogram)
+ to be instead added into the first row of the image. Similarly,
+ the first plane of a 3-D or 4-D data cube would include the events
+ that should have been excluded as falling in the previous plane of
+ the cube.
+
+ - fixed minor bug when parsing an extended filename that contains
+ nested pairs of square brackets (e.g., '[col newcol=oldcol[9]]').
+
+ - fixed bug when reading unsigned integer values from a table or
+ image with fits_read_col_uint/ffgcvuk. This bug only occurred on
+ systems like Digital Unix (now Tru64 Unix) in which 'long'
+ integers are 8 bytes long, and only when reading more than 7200
+ elements at a time. This bug would generally cause the program to
+ crash with a segmentation fault.
+
+ - modified ffgcpr to update 'heapstart' as well as 'numrows' when
+ writing more rows beyond the end of the table. heapstart
+ is needed to calculate if more space needs to be inserted in the
+ table when inserting columns into the table.
+
+ - modified fficls (insert column), ffmvec, ffdrow and ffdcol to
+ not use the value of the NAXIS2 keyword as the number of rows
+ in the table, and instead use the value that is stored in
+ an internal structure, because the keyword value may not
+ be up to date.
+
+ - Fixed bug in the iterator function that affected the handling
+ of null values in string columns in ASCII and binary tables.
+
+ - Reading a subsample of pixels in very large images, (e.g.,
+ file = myfile.fits[1:10000:10,1:10000:10], could cause a
+ long integer overflow (value > 2**31) in the computation of the
+ starting byte offset in the file, and cause a return error status
+ = 304 (negative byte address). This was fixed by changing the
+ order of the arithmetic operations in calculating the value of
+ 'readptr' in the ffgcli, ffgclj, ffgcle, ffgcld, etc. routines.
+
+ - In version 2.031, a fix to prevent compressed files from being
+ opened with write privilege was implemented incorrectly. The fix
+ was intended to not allow a compressed FITS file to be opened
+ except when a local uncompressed copy of the file is being
+ produced (then the copy is opened with write access), but in fact
+ the opposite behavior occurred: Compressed files could be opened
+ with write access, EXCEPT when a local copy is produced. This
+ has been fixed in the mem_compress_open and file_compress_open
+ routines.
+
+ - in iraffits.c, a global variable called 'val' caused multiply
+ defined symbols warning when linking cfitsio and IRAF libraries.
+ This was fixed by making 'val' a local variable within the
+ routine.
+
+Version 2.036 - 1 Feb 2000
+
+ - added 2 new generic routines, ffgpf and ffgcf which are analogous
+ to ffgpv and ffgcv but return an array of null flag values instead
+ of setting null pixels to a reserved value.
+
+ - minor change to eval_y.c and eval.y to "define alloca malloc"
+ on all platforms, not just VMS.
+
+ - added support for the unsigned int datatype (TUINT) in the
+ generic ffuky routine and changed ffpky so that unsigned ints
+ are cast to double instead of long before being written to
+ the header.
+
+ - modified ffs2c so that if a null string is given as input then
+ a null FITS string (2 successive single quotes) will be returned.
+ Previously this routine would just return a string with a single
+ quote, which could cause an illegal keyword record to be written.
+
+ - The file flush operation on Windows platforms apparently
+ changes the internal file position pointer (!) in violation of the
+ C standard. Put a patch into the file_flush routine to explicitly
+ seek back to the original file position.
+
+ - changed the name of imcomp_get_compressed_image_parms to
+ imcomp_get_compressed_image_par to not exceed the 31 character
+ limit on some compilers.
+
+ - modified the filename parser (which is used when moving to a
+ named HDU) to support EXTNAME values which contain embedded blanks.
+
+ - modified drvrnet.c to deal with ftp compressed files better so
+ that even fits files returned from cgi queries which have the wrong
+ mime types and/or wrong types of file names should still decompress.
+
+ - modified ffgics to reduce the tolerance for acceptable skewness
+ between the axes, and added a new warning return status =
+ APPROX_WCS_KEY in cases where there is significant skewness
+ between the axes.
+
+ - fixed bug in ffgics that affected cases where the first coordinate
+ axis was DEC, not RA, and the image was a mirror image of the sky.
+
+ - fixed bug in ffhist when trying to read the default binning
+ factor keyword, TDBIN.
+
+ - modified ffhist so that is correctly computes the rotation angle
+ in a 2-D image if the first histogram column has a CROTA type
+ keyword but the 2nd column does not.
+
+ - modified ffcpcl so that it preserves the comment fields on the
+ TTYPE and TFORM keywords when the column is copied to a new file.
+
+ - make small change to configure.in to support FreeBSD Linux
+ by setting CFLAGS = -Df2cFortran instead of -Dg77Fortran. Then
+ regenerated configure with autoconf 2.13 instead of 2.12.
+
+Version 2.035 - 7 Dec 1999 (internal release only, FTOOLS 5.0.2)
+
+ - added new routine called fits_get_keyclass/ffgkcl that returns
+ the general class of the keyword, e.g., required structural
+ keyword, WCS keyword, Comment keyword, etc. 15 classes of
+ keywords have been defined in fitsio.h
+
+ - added new routine called fits_get_img_parm/ffgipr that is similar
+ to ffgphd but it only return the bitpix, naxis, and naxisn values.
+
+ - added 3 new routines that support the long string keyword
+ convention: fits_insert_key_longstr, fits_modify_key_longstr
+ fits_update_key_longstr.
+
+ - modified ffgphd which reads image header keywords to support
+ the new experimental compressed image format.
+
+ - when opening a .Z compressed file, CFITSIO tries to allocate
+ memory equal to 3 times the file size, which may be excessive
+ in some cases. This was changed so that if the allocation fails,
+ then CFITSIO will try again to allocate only enough memory
+ equal to 1 times the file size. More memory will be allocated
+ later if this turns out to be too small.
+
+ - improved the error checking in the fits_insert_key routine
+ to check for illegal characters in the keyword.
+
+Version 2.034 - 23 Nov 1999
+
+ - enhanced support for the new 'CD' matrix world coordinate system
+ keywords in the ffigics routine. This routine has been enhanced
+ to look for the new 'CD' keywords, if present, and convert them
+ back to the old CDELTn and CROTAn values, which are then returned.
+ The routine will also swap the WCS parameters for the 2 axes if
+ the declination-like axis is the first WCS axis.
+
+ - modified ffphbn in putkey.c to support the 'U' and 'V" TFORM characters
+ (which represent unsigned short and unsigned int columns) in variable
+ length array columns. (previously only supported these types in
+ fixed length columns).
+
+ - added checks when reading gzipped files to detect unexpected EOF.
+ Previously, the 'inflate_codes' routine would just sit in an infinite
+ loop if the file ended unexpectedly.
+
+ - modified fits_verify_chksum/ffvcks so that checksum keywords with
+ a blank value string are treated as undefined, the same as
+ if the keyword did not exist at all.
+
+ - fixed ffghtb and ffghbn so that they return the extname value
+ in cases where there are no columns in the table.
+
+ - fixed bug in the ffgtwcs routine (this is a little utility
+ routine to aid in interfacing to Doug Mink's WCS routines);
+ it was not correctly padding the length of string-valued keywords
+ in the returned string.
+
+ - fixed bug in 'iraffits.c' that prevented Type-2 IRAF images from
+ being correctly byte-swapped on PCs and DEC-OSF machines.
+
+ - fixed tiny memory leak in irafncmp in iraffits.c. Only relevant when
+ reading IRAF .imh files.
+
+ - fixed a bug (introduced in version 2.027) that caused the keyword
+ reading routines to sometimes not find a matching keyword if the
+ input name template used the '*' wildcard as the last character.
+ (e.g., if input name = 'COMMENT*' then it would not find the
+ 'COMMENT' keywords. (It would have found longer keywords like
+ 'COMMENTX' correctly). The fix required a minor change to ffgcrd
+ in getkey.c
+
+ - modified the routine (ffswap8) that does byteswapping of
+ double precision numbers. Some linux systems have reported floating
+ point exceptions because they were trying to interpret the bytes
+ as a double before the bytes had been swapped.
+
+ - fixed bug in the calculation of the position of the last byte
+ in the string of bits to be read in ffgcxuk and ffgcxui. This
+ bug generally caused no harm, but could cause the routine to
+ exit with an invalid error message about trying to read
+ beyond the size of the field.
+
+ - If a unix machine did not have '__unix__', 'unix', or '__unix'
+ C preprocessor symbols defined, then CFITSIO would correctly open
+ one FITS file, but would not correctly open subsequent files. Instead
+ it would think that the same file was being opened multiple times.
+ This problem has only been seen on an IBM/AIX machine. The fits_path2url
+ and fits_url2path routines in group.c were modified to fix the problem.
+
+ - fixed bug in group.c, which affected WINDOWS platforms only, that
+ caused programs to go into infinite loop when trying to open
+ certain files.
+
+ - the ftrsim Fortran wrapper routine to ffrsim was not defined
+ correctly, which caused the naxis(2) value to be passed incorrectly
+ on Dec OSF machines, where sizeof(long) != sizeof(int).
+
+Version 2.033 - 17 Sept 1999
+
+ - New Feature: enhanced the row selection parser so that comparisons
+ between values in different rows of the table are allowed, and the
+ string comparisons with <, >, <=, and >= are supported.
+
+ - added new routine the returns the name of the keyword in the
+ input keyword record string. The name is usually the first
+ 8 characters of the record, except if the HIERARCH convention
+ is being used in which case the name may be up to 67 characters
+ long.
+
+ - added new routine called fits_null_check/ffnchk that checks to
+ see if the current header contains any null (ASCII 0) characters.
+ These characters are illegal in FITS headers, but they go undetected
+ by the other CFITSIO routines that read the header keywords.
+
+ - the group.c file has been replaced with a new version as supplied
+ by the ISDC. The changes are mainly to support partial URLs and
+ absolute URLs more robustly. Host dependent directory paths are
+ now converted to true URLs before being read from/written to
+ grouping tables.
+
+ - modified ffnmhd slightly so that it will move to the first extension
+ in which either the EXTNAME or the HDUNAME keyword is equal to the
+ user-specified name. Previously, it only checked for HDUNAME if
+ the EXTNAME keyword did not exist.
+
+ - made small change to drvrnet.c so that it uncompress files
+ which end in .Z and .gz just as for ftp files.
+
+ - rewrote ffcphd (copy header) to handle the case where the
+ input and output HDU are in the same physical FITS file.
+
+ - fixed bug in how long string keyword values (using the CONTINUE
+ convention) were read. If the string keyword value ended in an
+ '&' character, then fits_read_key_longstr, fits_modify_key_str,
+ and fits_delete_key would interpret the following keyword as
+ a continuation, regardless of whether that keyword name was
+ 'CONTINUE' as required by this convention. There was also a bug
+ in that if the string keyword value was all blanks, then
+ fits_modify_key_str could in certain unusual cases think
+ that the keyword ended in an '&' and go into an infinite loop.
+
+ - modified ffgpv so that it calls the higher level ffgpv_ routine
+ rather than directly calling the lower level ffgcl_ routine. This
+ change is needed to eventually support reading compressed images.
+
+ - added 3 new routines to get the image datatype, image dimensions,
+ and image axes length. These support the case where the image is
+ compressed and stored in a binary table.
+
+ - fixed bug in ffiblk that could sometimes cause it to insert a
+ new block in a file somewhere in the middle of the data, instead
+ of at the end of the HDU. This fortunately is a rare problem,
+ mainly only occurring in certain cases when inserting rows in a binary
+ table that contains variable length array data (i.e., has a heap).
+
+ - modified fits_write_tdim so that it double checks the TFORMn
+ value directly if the column repeat count stored in the internal
+ structure is not equal to the product of all the dimensions.
+
+ - fixed bug that prevented ffitab or ffibin from inserting a new
+ table after a null primary array (can't read NAXIS2 keyword).
+ Required a small change to ffrdef.
+
+ - modified testprog.c so that it will continue to run even if
+ it cannot open or process the template file testprog.tpt.
+
+ - modified the logic in lines 1182-1185 of grparser.c so that
+ it returns the correct status value in case of an error.
+
+ - added test in fitsio2.h to see if __sparcv9 is defined; this
+ identifies a machine running Solaris 7 in 64-bit mode where
+ long integers are 64 bits long.
+
+Version 2.032 - 25 May 1999
+
+ - the distribution .tar file was changed so that all the files
+ will be untarred into a subdirectory by default instead of
+ into the current directory.
+
+ - modified ffclos so that it always frees the space allocated by
+ the fptr pointer, even when another fptr points to the same file.
+
+ - plugged a potential (but rare in practice) memory leak in ffpinit
+
+ - fixed bug in all the ffp3d_ and ffg3d_ routines in cases where
+ the data cube that has been allocated in memory has more planes
+ than the data cube in the FITS file.
+
+ - modified drvrsmem.c so that it allocates a small shared
+ memory segment only if CFITSIO tries to read or write a
+ FITS file in shared memory. Previously it always allocated
+ the segment whether it was needed or not. Also, this small
+ segment is removed if 0 shared memory segments remain in
+ the system.
+
+ - put "static" in front of 7 DECLARE macros in compress.c
+ because these global variables were causing conflicts with other
+ applications programs that had variables with the same names.
+
+ - modified ffasfm to return datatype = TDOUBLE instead of TFLOAT
+ if the ASCII table column has TFORMn = 'Ew.d' with d > 6.
+
+ - modified the column reading routines to a) print out the offending
+ entry if an error occurs when trying to read a numeric ASCII table
+ column, and b) print out the column number that had the error
+ (the messages are written to CFITSIOs error stack)
+
+ - major updates to the Fortran FITSIO User's Guide to include many
+ new functions that have been added to CFITSIO in the past year.
+
+ - modified fitsio2.h so that the test for __D_FLOAT etc. is only
+ made on Alpha VMS machines, to avoid syntax errors on some other
+ platforms.
+
+ - modified ffgthd so that it recognizes a floating point value
+ that uses the 'd' or 'D' exponent character.
+
+ - removed the range check in fftm2s that returned an error if
+ 'decimals' was less than zero. A negative value is OK and is
+ used to return only the date and not the time in the string.
+
+Version 2.031 - 31 Mar 1999
+
+ - moved the code that updates the NAXIS2 and PCOUNT keywords from
+ ffchdu into the lower lever ffrdef routine. This ensures that
+ other routines which call ffrdef will correctly update these 2
+ keywords if required. Otherwise, for instance, calling
+ fits_write_checksum before closing the HDU could cause the NAXIS2
+ keyword (number of rows in the table) to not be updated.
+
+ - fixed bug (introduced in version 2.030) when writing null values
+ to a primary array or image extension. If trying to set more
+ than 1 pixel to null at a time, then typically only 1 null would
+ be written. Also fixed related bug when writing null values to
+ rows in a table that are beyond the currently defined size of the
+ table (the size of the table was not being expanded properly).
+
+ - enhanced the extended filename parser to support '*' in image
+ section specifiers, to mean use the whole range of the axis.
+ myfile.fits[*,1:100] means use the whole range of the first
+ axis and pixels 1 to 100 in the second axis. Also supports
+ an increment, as in myfile.fits[*:2, *:2] to use just the
+ odd numbered rows and columns.
+
+ - modified fitscore.c to set the initial max size of the header, when
+ first reading it, to the current size of the file, rather than to
+ 2 x 10**9 to avoid rare cases where CFITSIO ends up writing a huge
+ file to disk.
+
+ - modified file_compress_open so that it will not allow a compressed
+ FITS file to be opened with write access. Otherwise, a program
+ could write to the temporary copy of the uncompressed file, but
+ the modification would be lost when the program exits.
+
+Version 2.030 - 24 Feb 1999
+
+ - fixed bug in ffpclu when trying to write a null value to a row
+ beyond the current size of the table (wouldn't append new rows
+ like it should).
+
+ - major new feature: enhanced the routines that read ASCII string
+ columns in tables so that they can read any table column, including
+ logical and numeric valued columns. The column values are returned
+ as a formatted string. The format is determined by the TDISPn
+ keyword if present, otherwise a default format based on the
+ datatype of the column is used.
+
+ - new routine: fits_get_col_display_width/ffgcdw returns the length
+ of the formatted strings that will be returned by the routines that
+ read table columns as strings.
+
+ - major new feature: added support for specifying an 'image section'
+ when opening an image: e.g, myfile.fits[1:512:2,2:512:2] to
+ open a 256x256 pixel image consisting of the odd columns and the
+ even numbered rows of the input image.
+
+ - added supporting project files and instructions for building
+ CFITSIO under Windows NT with the Microsoft Visual C++ compiler.
+
+ - changed the variable 'template' to 'templt' in testprog.c since
+ it conflicted with a reserved word on some compilers.
+
+ - modified group.c to conditionally include sys/stat.h only on
+ unix platforms
+
+ - fixed bug in the ffiter iterator function that caused it to always
+ pass 'firstn' = 1 to the work function when reading from the
+ primary array or IMAGE extension. It worked correctly for tables.
+
+ - fixed bug in the template header keyword parser (ffgthd) in cases
+ where the input template line contains a logical valued keyword
+ (T or F) without any following comment string. It was previously
+ interpreting this as a string-valued keyword.
+
+ - modified ffrhdu that reads and opens a new HDU, so that it
+ ignores any leading blank characters in the XTENSION name, e.g.,
+ XTENSION= ' BINTABLE' will not cause any errors, even though
+ this technically violates the FITS Standard.
+
+ - modified ffgtbp that reads the required table keywords to make
+ it more lenient and not exit with an error if the THEAP keyword
+ in binary tables cannot be read as an integer. Now it will
+ simply ignore this keyword if it cannot be read.
+
+ - added test for 'WIN32' as well as '__WIN32__' in fitsio2.h,
+ eval.l and eval_l.c in a preprocessor statement.
+
+ - changed definition of strcasecmp and strncasecmp in fitsio2.h,
+ eval.l and eval_l.c to conform to the function prototypes under
+ the Alpha VMS v7.1 compiler.
+
+ - corrected the long function names in longnam.h for the new WCS
+ utility functions in wcssubs.c
+
+Version 2.029 - 11 Feb 1999
+
+ - fixed bug in the way NANs and underflows were being detected on
+ VAX and Alpha VMS machines.
+
+ - enhanced the filename parser to distinguish between a VMS-style
+ directory name (e.g. disk:[directory]myfile.fits) and a CFITSIO
+ filter specifier at the end of the name.
+
+ - modified ffgthd to support the HIERARCH convention for keyword
+ names that are longer than 8 characters or contain characters
+ that would be illegal in standard FITS keyword names.
+
+ - modified the include statements in grparser.c so that malloc.h
+ and memory.h are only included on the few platforms that really
+ need them.
+
+ - modified the file_read routine in drvrfile.c to ignore the last
+ record in the FITS file it it only contains a single character that
+ is equal to 0, 10 or 32. Text editors sometimes append a character
+ like this to the end of the file, so CFITSIO will ignore it and
+ treat it as if it had reached the end of file.
+
+ - minor modifications to fitsio.h to help support the ROOT environment.
+
+ - installed new version of group.c and group.h; the main change
+ is to support relative paths (e.g. "../filename") in the URLs
+
+ - modified the histogramming routines so that it looks for the
+ default preferred column axes in a keyword of the form
+ CPREF = 'Xcol, Ycol'
+ instead of separate keywords of the form
+ CPREF1 = 'Xcol'
+ CPREF2 = 'Ycol'
+
+ - fixed bug so that if the binning spec is just a single integer,
+ as in [bin 4] then this will be interpreted as meaning to make
+ a 2D histogram using the preferred or default axes, with the
+ integer taken as the binning factor in both axes.
+
+Version 2.028 - 27 Jan 1999
+
+ - if the TNULLn keyword value was outside the range of a 'I' or 'B'
+ column, an overflow would occur when setting the short or char
+ to the TNULLn value, leading to incorrect values being flagged as
+ being undefined. This has been fixed so that CFITSIO will ignore
+ TNULLn values that are beyond the range of the column data type.
+
+ - changed a few instances of the string {"\0"} to {'\0'} in the
+ file groups.c
+
+ - installed new version of the grparser.c file from the ISDC
+
+ - added new WCS support routines (in wcssub.c) which make it easier
+ to call Doug Mink's WCSlib routines for converting between plate
+ and sky coordinates. The CFITSIO routines themselves never
+ call a WCSlib routine, so CFITSIO is not dependent on WCSlib.
+
+ - modified ffopen so that if you use the extended filename
+ syntax to both select rows in a table and then bin columns into
+ a histogram, then CFITSIO will simply construct an array listing
+ the good row numbers to be used when making the histogram,
+ instead of making a whole new temporary FITS file containing
+ the selected rows.
+
+ - modified ffgphd which parses the primary array header keywords
+ when opening a file, to not choke on minor format errors in
+ optional keywords. Otherwise, this prevents CFITSIO from
+ even opening the file.
+
+ - changed a few more variable declarations in compress.c from global
+ to static.
+
+Version 2.027 - 12 Jan 1999
+
+ - modified the usage of the output filename specifier so that it,
+ a) gives the name of the binned image, if specified, else,
+ b) gives the name of column filtered and/or row filtered table, if
+ specified, else
+ c) is the name for a local copy of the ftp or http file, else,
+ d) is the name for the local uncompressed version of the compressed
+ FITS file, else,
+ e) the output filename is ignored.
+
+ - fixed minor bug in ffcmps, when comparing 2 strings while using
+ a '*' wild card character.
+
+ - fixed bug in ftgthd that affected cases where the template string
+ started with a minus sign and contained 2 tokens (to rename a
+ keyword).
+
+ - added support for the HIERARCH keyword convention for reading
+ and writing keywords longer than 8 characters or that contain
+ ASCII characters not allowed in normal FITS keywords.
+
+ - modified the extended filename syntax to support opening images
+ that are contained in a single cell of a binary table with syntax:
+ filename.fits[extname; col_name(row_expression)]
+
+Version 2.026 - 23 Dec 1998
+
+ - modified the group parser to:
+ a) support CFITSIO_INCLUDE_FILES environment variable, which can
+ point to the location of template files, and,
+ b) the FITS file parameter passed to the parser no longer has to point
+ to an empty file. If there are already HDUs in the file, then the
+ parser appends new HDUs to the end of the file.
+
+ - make a small change to the drvrnet.c file to accommodate creating
+ a static version of the CFITSIO library.
+
+ - added 2 new routines to read consecutive bits as an unsigned integer
+ from a Bit 'X' or Byte 'B' column (ffgcxui and ffgcxuk).
+
+ - modified the logic for determining histogram boundaries in ffhisto
+ to add one more bin by default, to catch values that are right on
+ the upper boundary of the histogram, or are in the last partial bin.
+
+ - modified cfitsio2.h to support the new Solaris 7 64-bit mode operating
+ system.
+
+ - Add utility routine, CFits2Unit, to the Fortran wrappers which searches
+ the gFitsFiles array for a fptr, returning its element (Fortran unit
+ number), or allocating a new element if one doesn't already
+ exists... for C calling Fortran calling CFITSIO.
+
+ - modified configure so that it does not use the compiler optimizer
+ when using gcc 2.8.x on Linux
+
+ - (re)added the fitsio.* documentation files that describe the
+ Fortran-callable FITSIO interface to the C routines.
+
+ - modified the lexical parser in eval_f.c to fix bug in null detections
+ and bug in ffsrow when nrows = 0.
+
+ - modified ffcalc so that it creates a TNULLn keyword if appropriate
+ when a new column is created. Also fixed detection of OVERFLOWs
+ so that it ignores null values.
+
+ - added hyperbolic trig and rounding functions to
+ the lexical parser in the eval* files.
+
+ - improved error message that gets written when the group number is
+ out of range when reading a 'random groups' array.
+
+ - added description of shared memory, grouping, and template parsing
+ error messages to ffgerr and to the User's Guide. Moved the error
+ code definitions from drvsmem.h to fitsio.h.
+
+ - modified grparser.c to compile correctly on Alpha/OSF machines
+
+ - modified drvrnet.c to eliminate compiler warnings
+
+ - Modified Makefile.in to include targets for building all the sample
+ programs that are included with CFITSIO.
+
+Version 2.025 - 1 Dec 1998
+
+ - modified ffgphd and ffgtbp so that they ignores BLANK and TNULLn keywords
+ that do not have a valid integer value. Also, any error while reading
+ the BSCALE, BZERO, TSCALn, or TZEROn keywords will be ignored.
+ Previously, CFITSIO would have simply refused to read an HDU that had
+ such an invalid keyword.
+
+ - modified the parser in eval_f.c to accept out of order times in GTIs
+
+ - updated cfitsio_mac.sit.hqx to fix bad target parameters for Mac's
+ speed test program
+
+ - modified template parser in grparser.c to: 1) not write GRPNAME keyword
+ twice, and 2) assign correct value for EXTVERS keyword.
+
+ - fixed minor bugs in group.c; mainly would only affect users of the
+ INTEGRAL Data Access Layer.
+
+ - temporarily removed the prototype for ffiwcs from fitsio.h until
+ full WCS support is added to CFITSIO in the near future.
+
+ - modified the HTTP driver to send a User-Agent string:
+ HEASARC/CFITSIO/<version number>
+
+ - declared local variables in compress.c as 'static' to avoid
+ conflicts with other libraries.
+
+Version 2.024 - 9 Nov 1998
+
+ - added new function fits_url_type which returns the driver prefix string
+ associated with a particular FITS file pointer.
+
+Version 2.023 - 1 Nov 1998 - first full release of CFITSIO 2.0
+
+ - slightly modified the way real keyword values are formatted, to ensure
+ that it includes a decimal point. E.g., '1.0E-09' instead of '1E-09'
+
+ - added new function to support template files when creating new FITS files.
+
+ - support the TCROTn WCS keyword in tables, when reading the WCS keywords.
+
+ - modified the iterator to support null values in logical columns in
+ binary tables.
+
+ - fixed bug in iterator to support null values in integer columns in
+ ASCII tables.
+
+ - changed the values for FLOATNULLVALUE and DOUBLENULLVALUE to make them
+ less likely to duplicate actual values in the data.
+
+ - fixed major bug when freeing memory in the iterator function. It caused
+ mysterious crashes on a few platforms, but had no effect on most others.
+
+ - added support for reading IRAF format image (.imh files)
+
+ - added more error checking to return an error if the size of the FITS
+ file exceeds the largest value of a long integer (2.1 GB on 32-bit
+ platforms).
+
+ - CFITSIO now will automatically insert space for additional table rows
+ or add space to the data heap, if one writes beyond the current end
+ of the table or heap. This prevents any HDUs which might follow
+ the current HDU from being overwritten. It is thus no longer necessary
+ to explicitly call fits_insert_rows before writing new rows of data
+ to the FITS file.
+
+ - CFITSIO now automatically keeps track of the number of rows that have
+ been written to a FITS table, and updates the NAXIS2 keyword accordingly
+ when the table is closed. It is no longer necessary for the application
+ program to updated NAXIS2.
+
+ - When reading from a FITS table, CFITSIO will now return an error if the
+ application tries to read beyond the end of the table.
+
+ - added 2 routines to get the number of rows or columns in a table.
+
+ - improved the undocumented feature that allows a '20A' column to be
+ read as though it were a '20B' column by fits_read_col_byt.
+
+ - added overflow error checking when reading keywords. Previously, the
+ returned value could be silently truncated to the maximum allowed value
+ for that data type. Now an error status is returned whenever an
+ overflow occurs.
+
+ - added new set of routines dealing with hierarchical groups of files.
+ These were provided by Don Jennings of the INTEGRAL Science Data Center.
+
+ - added new URL parsing routines.
+
+ - changed the calling sequence to ffghad (get HDU address) from
+ ffghad(fitsfile *fptr, > long *headstart, long *dataend) to
+ ffghad(fitsfile *fptr, > long *headstart, long datastart,
+ long *dataend, int *status)
+
+ - major modification to support opening the same FITS file more
+ than once. Now one can open the same file multiple times and
+ read and write simultaneously to different HDUs within the file.
+ fits_open_file automatically detects if the file is already opened.
+
+ - added the ability to clobber/overwrite an existing file
+ with the same name when creating a new output file. Just
+ preceed the output file name with '!' (an exclamation mark)
+
+ - changed the ffpdat routine which writes the DATE keyword
+ to use the new 'YYYY-MM-DDThh:mm:ss' format.
+
+ - added several new routines to create or parse the new date/time
+ format string.
+
+ - changed ifdef for DECFortran in f77_wrap.h and f77_wrap1.c:
+ expanded to recognize Linux/Alpha
+
+ - added new lexical parsing routines (from Peter Wilson):
+ eval_l.c, eval_y.c, eval_f.c, eval_defs.h, and eval_tab.h.
+ These are used when doing on-the-fly table row selections.
+
+ - added new family of routines to support reading and writing
+ 'unsigned int' data type values in keywords, images or tables.
+
+ - restructured all the putcol and getcol routines to provide
+ simpler and more robust support for machines which have
+ sizeof(long) = 8. Defined a new datatype INT32BIT which is
+ always 32 bits long (platform independent) and is used internally
+ in CFITSIO when reading or writing BITPIX = 32 images or 'J'
+ columns. This eliminated the need for specialize routines like
+ ffswaplong, ffunswaplong, and ffpacklong.
+
+ - overhauled cfileio.c (and other files) to use loadable drivers for
+ doing data I/O to different devices. Now CFITSIO support network
+ access to ftp:// and http:// files, and to shared memory files.
+
+ - removed the ffsmem routine and replaced it with ffomem. This will
+ only affect software that reads an existing file in core memory.
+ (written there by some other process).
+
+ - modified all the ffgkn[] routines (get an array of keywords) so
+ that the 'nfound' parameter is = the number of keywords returned,
+ not the highest index value on the returned keywords. This makes
+ no difference if the starting index value to look for = 1.
+ This change is not backward compatible with previous versions
+ of CFITSIO, but is the way that FITSIO behaved.
+
+ - added new error code = 1 for any application error external
+ to CFITSIO. Also reports "unknown error status" if the
+ value doesn't match a known CFITSIO error.
+
+Version 1.42 - 30 April 1998 (included in FTOOLS 4.1 release)
+
+ - modified the routines which read a FITS float values into
+ a float array, or read FITS double values into a double array,
+ so that the array value is also explicitly set in addition
+ to setting the array of flag values, if the FITS value is a NaN.
+ This ensures that no NaN values get passed back to the calling
+ program, which can cause serious problems on some platforms (OSF).
+
+ - added calls to ffrdef at the beginning of the insert
+ or delete rows or columns routines in editcol.c to make sure
+ that CFITSIO has correctly initialized the HDU information.
+
+ - added new routine ffdrws to delete a list of rows in a table
+
+ - added ffcphd to copy the header keywords from one hdu to another
+
+ - made the anynul parameter in the ffgcl* routines optional
+ by first checking to see if the pointer is not null before
+ initializing it.
+
+ - modified ffbinit and ffainit to ignore minor format
+ errors in header keywords so that cfitsio can at least
+ move to an extension that contains illegal keywords.
+
+ - modified all the ffgcl* routines to simply return without
+ error if nelem = 0.
+
+ - added check to ffclose to check the validity of the fitsfile
+ pointer before closing it. This should prevent program crashes
+ when someone tries to close the same file more than once.
+
+ - replaced calls to strcmp and strncmp with macros FSTRCMP and
+ FSTRNCMP in a few places to improve performance when reading
+ header keywords (suggested by Mike Noble)
+
+ Bug Fixes:
+
+ - fixed typo in macro definition of error 504 in the file fitsio.h.
+
+ - in ffopen, reserved space for 4 more characters in the input
+ file name in case a '.zip' suffix needs to be added.
+
+ - small changes to ffpclx to fix problems when writing bit (X) data
+ columns beyond the current end of file.
+
+ - fixed small bug in ffcrhd where a dummy pointer was not initialized
+
+ - initialized the dummy variable in ffgcfe and ffgcfd which
+ was causing crashes under OSF in some cases.
+
+ - increased the length of the allocated string ffgkls by 2
+ to support the case of reading a numeric keyword as a string
+ which doesn't have the enclosing quote characters.
+
+Version 1.4 - 6 Feb 1998
+
+ - major restructuring of the CFITSIO User's Guide
+
+ - added the new 'iterator' function. The fortran wrapper is
+ in f77_iter.c for now.
+
+ - enhanced ffcrtb so that it writes a dummy primary array
+ if none currently exists before appending the table.
+
+ - removed the ffgcl routine and replaced it with ffgcvl
+
+ - modified ffpcnl to just take a single input null value instead
+ of an entire array of null value flags.
+
+ - modified ffcmps and ffgnxk so that, for example, the string 'rate'
+ is not considered a match to the string 'rate2', and 'rate*'
+ is a match to the string 'rate'.
+
+ - modified ffgrsz to also work with images, in which case
+ it returns the optimum number of pixels to process at
+ one time.
+
+ - modified ffgthd to support null valued keywords
+
+ - added a new source file 'f77_wrap.c' that includes all the
+ Fortran77 wrapper routines for calling CFITSIO. This will
+ eventually replace the Fortran FITSIO library.
+
+ - added new routines:
+ ffppn - generic write primary array with null values
+ ffpprn - write null values to primary array
+
+ ffuky - 'update' a keyword value, with any specified datatype.
+
+ ffrprt - write out report of error status and error messages
+ ffiter - apply a user function iteratively to all the rows of a table
+ ffpkyc - write complex-valued keyword
+ ffpkym - write double complex-valued keyword
+ ffpkfc - write complex-valued keyword in fixed format
+ ffpkfm - write double complex-valued keyword in fixed format
+
+ ffgkyc - read complex-valued keyword
+ ffgkym - read double complex-valued keyword
+
+ ffmkyc - modify complex-valued keyword
+ ffmkym - modify double complex-valued keyword
+ ffmkfc - modify complex-valued keyword in fixed format
+ ffmkfm - modify double complex-valued keyword in fixed format
+
+ ffukyc - update complex-valued keyword
+ ffukym - update double complex-valued keyword
+ ffukfc - update complex-valued keyword in fixed format
+ ffukfm - update double complex-valued keyword in fixed format
+
+ ffikyc - insert complex-valued keyword
+ ffikym - insert double complex-valued keyword
+ ffikfc - insert complex-valued keyword in fixed format
+ ffikfm - insert double complex-valued keyword in fixed format
+
+ ffpktp - write or modify keywords using ASCII template file
+ ffcpcl - copy a column from one table to another
+ ffcpky - copy an indexed keyword from one HDU to another
+ ffpcnl - write logical values, including nulls, to binary table
+ ffpcns - write string values, including nulls, to table
+ ffmnhd - move to HDU with given exttype, EXTNAME and EXTVERS values
+ ffthdu - return the total number of HDUs in the file
+ ffghdt - return the type of the CHDU
+ ffflnm - return the name of the open FITS file
+ ffflmd - return the mode of the file (READONLY or READWRITE)
+
+ - modified ffmahd and ffmrhd (to move to a new extension) so that
+ a null pointer may be given for the returned HDUTYPE argument.
+
+ - worked around a bug in the Mac CWpro2 compiler by changing all
+ the statements like "#if BYTESWAPPED == TRUE" to "if BYTESWAPPED".
+
+ - modified ffitab (insert new ASCII table) to allow tables with
+ zero number of columns
+
+ - modified Makefile.in and configure to define the -Dg77Fortran
+ CFLAGS variable on Linux platforms. This is needed to
+ compile the new f77_wrap.c file (which includes cfortran.h)
+
+ Bug Fixes:
+
+ - fixed small bug in ffgrz (get optimum row size) which sometimes
+ caused it to return slightly less than the maximum optimum size.
+ This bug would have done no harm to application programs.
+
+ - fixed bug in ffpclk and ffgclk to add an 'else' case
+ if size of int is not equal to size of short or size of long.
+
+ - added test to ffgkls to check if the input string is not null before
+ allocating memory for it.
+
+Version 1.32 - 21 November 1997 (internal release only)
+
+ - fixed bug in the memory deallocation (free) statements
+ in the ffopen routine in the cfileio.c file.
+
+ - modified ffgphd to tolerate minor violations of the FITS
+ standard in the format of the XTENSION = 'IMAGE '
+ keyword when reading FITS files. Extra trailing spaces
+ are now allowed in the keyword value. (FITS standard
+ will be changed so that this is not a violation).
+
+Version 1.31 - 4 November 1997 (internal release only)
+
+ Enhancements:
+
+ - added support for directly reading compressed FITS files
+ by copying the algorithms from the gzip program. This
+ supports the Unix compress, gzip and pkzip algorithms.
+
+ - modified ffiimg, ffitab, and ffibin (insert HDUs into
+ a FITS file) so that if the inserted HDU is at the end of
+ the FITS file, then it simply appends a new empty HDU
+ and writes the required keywords. This allows space
+ to be reserved for additional keywords in the header
+ if desired.
+
+ - added the ffchfl and ffcdfl routines to check the header and
+ data fill values, for compatibility with the Fortran FITSIO
+ library.
+
+ - added the ffgsdt routine to return the system date
+ for compatibility with the Fortran FITSIO library.
+
+ - added a diagnostic error message (written to the error stack)
+ if the routines that read data from image or column fail.
+
+ - modified ffgclb so that it simply copies the bytes from
+ an ASCII 'nA' or 'An' format column into the user's byte
+ array. Previously, CFITSIO would return an error when
+ trying to read an 'A' column with ffgclb.
+
+ - modified ffpclb so that it simply copies the input array
+ of bytes to an ASCII 'nA' or 'An' format column.
+ Previously, CFITSIO would return an error when
+ trying to write to an 'A' column with ffpclb.
+
+ Bug Fixes:
+
+ - ffgkls was allocating one too few bytes when reading continued
+ string keyword values.
+
+ - in testprog.c added code to properly free the memory that
+ had been allocated for string arrays.
+
+ - corrected typographical errors in the User's Guide.
+
+Version 1.30 - 11 September 1997
+
+ - major overhaul to support reading and writing FITS files
+ in memory. The new routines fits_set_mem_buff and
+ fits_write_mem_buff have been added to initialize and
+ copy out the memory buffer, respectively.
+
+ - added support for reading FITS files piped in on 'stdin'
+ and piped out on 'stdout'. Just specify the file name as '-'
+ when opening or creating the FITS file.
+
+ - added support for 64-bit SGI IRIX machines. This required
+ adding routines to pack and unpack 32-bit integers into
+ 64-bit integers.
+
+ - cleaned up the code that supports G_FLOAT and IEEE_FLOAT
+ on Alpha VMS systems. Now, the type of float is determined
+ at compile time, not run time.
+
+ Bug Fixes:
+
+ - replaced the malloc calls in the error message stack routines
+ with a static fixed size array. The malloc's cause more
+ problems than they solved, and were prone to cause memory
+ leaks if users don't clear the error message stack when
+ closing the FITS file.
+
+ - when writing float or double keywords, test that the value
+ is not a special IEEE value such as a NaN. Some
+ compilers would write the string 'NaN' in this case into
+ the output value string.
+
+ - fixed bug in ffiblk, to ignore EOF status return if it is
+ inserting blocks at the end of the file.
+
+ - removed the 'l' from printf format string that is constructed
+ in the ffcfmt routine. This 'l' is non-standard and causes problems
+ with the Metrowerks compiler on a Mac.
+
+ - the default null value in images was mistakenly being set
+ equal to NO_NULL = 314, rather than NULL_UNDEFINED = 1234554321
+ in the ffgphd routine.
+
+ - check status value in ffgkls to make sure the keyword exists
+ before allocating memory for the value string.
+
+ - fixed the support for writing and reading unsigned long integer
+ keyword values in ffpky and ffgky by internally treating
+ the values as doubles. This required changes to ffc2r and
+ ffc2d as well.
+
+ - added explicit cast to 'double' in one place in putcolb.c and
+ 6 places in pubcolui.c, to get rid of warning messages issued
+ by one compiler.
+
+ - in ffbinit and ffainit, it is necessary to test that tfield > 0
+ before trying to allocate memory with calloc. Otherwise, some
+ compilers return a null pointer which CFITSIO interprets to
+ mean the memory allocation failed.
+
+ - had to explicitly cast the null buffer pointer to a char
+ pointer (cptr = (char *)buffer;) in 4 places in the buffers.c
+ file to satisfy a picky C++ compiler.
+
+ - changed the test for an ALPHA VMS system to see if
+ '__VMS' is defined, rather than 'VMS'. The latter
+ is not defined by at least one C++ compiler.
+
+ - modified ffpcls so that it can write a null string to
+ a variable length string column, without going into
+ an infinite loop.
+
+ - fixed bug in ffgcfl that caused the 'next' variable to be
+ incremented twice.
+
+ - fixed bug in ffgcpr that caused it write 2x the number of
+ complex elements into the descriptor when writing to
+ a complex or double complex variable length array column.
+
+ - added call to ffrdef at the end of ffrsim to ensure that
+ the internal structures are updated to correspond to the
+ modified header keywords
+
+Version 1.25 - 7 July 1997
+
+ - improved the efficiency of the ffiblk routine, when inserting
+ more than one block into the file.
+
+ - fixed bug in ffwend that in rare instances caused the beginning
+ of the following extension to be overwritten by blank fill.
+
+ - added new routine to modify the size of an existing primary
+ array or image extension: fits_resize_img/ffrsim.
+
+ - added support for null-valued keywords, e.g., keywords that
+ have no defined value. These keywords have an equal sign and
+ space in columns 9-10, but have not value string. Example:
+ KEYNAME = / null-valued keyword
+ Support for this feature required the following changes:
+ - modified ffpsvc to return a null value string without error
+ - modified ffc2[ilrd] to return error VALUE_UNDEFINED in this case
+ - modified ffgkn[sljed] to continue reading additional keywords
+ even if one or more keywords have undefined values.
+ - added 4 new routines: ffpkyu, ffikyu, ffmkyu, ffukyu to
+ write, insert, modify, or update an undefined keyword
+
+ - a new makefile.os2 file was added, for building CFITSIO
+ on OS/2 systems.
+
+ - modified ffgtkn so that if it finds an unexpected keyword
+ name, the returned error status = BAD_ORDER instead of
+ NOT_POS_INT.
+
+ - added 2 new routines, fits_write_key_unit/ffpunt and
+ fits_read_key_unit/ffgunt to write/read the physical
+ units of a keyword value. These routines use a local
+ FITS convention for storing the units in square brackets
+ following the '/' comment field separator, as in:
+ VELOCITY= 12 / [km/s] orbit speed
+ The testprog.c program was modified to test these
+ new routines.
+
+ - in the test of Alpha OSF/1 machines in fitsio2.h,
+ change 'defined(unix)' to 'defined(__unix__)' which
+ appears to be a more robust test.
+
+ - remove test for linux environment variable from fitsio2.h
+
+Version 1.24 - 2 May 1997
+
+ - fixed bug in ffpbyt that incorrectly computed the current
+ location in the FITS file when writing > 10000 bytes.
+
+ - changed the datatype of the 'nbytes' parameter in ffpbyt
+ from 'int' to 'long'. Made corresponding datatype change
+ to some internal variables in ffshft.
+
+ - changed '(unsigned short *)' to '(short *)' in getcolui.c, and
+ changed '(unsigned long *)' to '(long *)' in getcoluj.c, to
+ work around problem with the VAX/VMS cc compiler.
+
+Version 1.23 - 24 April 1997
+
+ - modified ffcins and ffdins (in editcol.c) to simply return
+ without error if there are no (zero) rows in the table.
+
+Version 1.22 - 18 April 1997
+
+ - fixed bug in ffgcpr that caused it to think that all values were
+ undefined in ASCII tables columns that have TNULLn = ' '
+ (i.e., the TNULLn keyword value is a string of blanks.
+
+ - fixed bug in the ffgcl[bdeijk,ui,uj] family of routines
+ when parsing a numeric value in an ASCII table. The
+ returned values would have the decimal place shifted to
+ the left if the table field contained an explicit decimal
+ point followed by blanks. Example: in an F5.2 column,
+ the value '16. ' would be returned as 0.16. If the
+ trailing zeros were present, then cfitsio returned the
+ correct value (e.g., '16.00' returns 16.).
+
+ - fixed another bug in the ffgcl[bdeijk,ui,uj] family of routines
+ that caused them to misread values in an ASCII table in rows
+ following an undefined value when all the values were read
+ at once in a single call to the routine.
+
+Version 1.21 - 26 March 1997
+
+ - added general support for reading and writing unsigned integer
+ keywords, images, and binary table column values.
+
+ - fixed bug in the way the column number was used in ffgsve and
+ similar routines. This bug caused cfitsio to read (colnum - 1)
+ rather than the desired column.
+
+ - fixed a bug in ftgkls that prevented it from reading more than one
+ continuation line of a long string keyword value.
+
+ - fixed the definition of fits_write_longwarn in longnam.h
+
+Version 1.20 - 29 Jan 1997
+
+ - when creating a binary table with variable length vector columns, if the
+ calling routine does not specify a value for the maximum length of
+ the vector (e.g., TFORMn = '1PE(400)') then cfitsio will automatically
+ calculate the maximum value and append it to the TFORM value
+ when the binary table is first closed.
+
+ - added the set of routines to do coordinate system transformations
+
+ - added support for wildcards ('*', '?', and '#') in the input
+ keyword name when reading, modifying, or deleting keywords.
+
+ - added new general keyword reading routine, ffgnxk, to return
+ the next keyword whose name matches a list of template names,
+ but does not match any names on a second template list.
+
+ - modified ftgrec so that it simply moves to the beginning
+ of the header if the input keyword number = 0
+
+ - added check in ffdelt to make sure the input fits file pointer is
+ not already null
+
+ - added check in ffcopy to make sure the output HDU does not
+ already contain any keywords (it must be empty).
+
+ - modified ffgcls so that it does not test if each string column
+ value equals the null string value if the null string value
+ is longer than the width of the column.
+
+ - fixed bug in ftgtdm that caused it to fail if the TDIMn
+ keyword did not exist in the FITS file
+
+ - modified testprog.c to include tests of keyword wildcards
+ and the WCS coordinate transformation routines.
+
+ - added a test for 'EMX' in fitsio2.h so that cfitsio builds
+ correctly on a PC running OS/2.
+
+Version 1.11 - 04 Dec 1996
+
+ - modified the testprog.c program that is included with the
+ distribution, so that the output FITS file is identical to
+ that produced by the Fortran FITSIO test program.
+
+ - changed all instances of the 'extname' variable to 'extnm'
+ to avoid a conflict with the -Dextname switch in cfortran.h
+ on HP machines.
+
+ - in all the routines like ffi4fi1, which convert an array
+ of values to integers just prior to writing them to the FITS
+ file, the integer value is now rounded to the nearest integer
+ rather than truncated. (ffi4fi1, ffi4fi2, ffi4fi4, etc)
+
+ - changed ffgcfl (and hence ffgcl) so that the input value
+ of the logical array element is not changed if the corresponding
+ FITS value is undefined.
+
+ - in ffgacl, the returned value of TBCOL was off by 1 (too small)
+
+ - fixed the comment of EXTNAME keyword to read 'binary table'
+ instead of 'ASCII table' in the header of binary tables.
+
+Version 1.101 - 17 Nov 1996
+
+ - Made major I/O efficiency improvements by adding internal buffers
+ rather than directly reading or writing to disk. Access to
+ columns in binary tables is now 50 - 150 times faster. Access to
+ FITS image is also slightly faster.
+
+ - made significant speed improvements when reading numerical data
+ in FITS ASCII tables by writing my own number parsing routines
+ rather than using the sscanf C library routine. This change
+ requires that the -lm argument now be included when linking
+ a program that calls cfitsio (under UNIX).
+
+ - regrouped the source files into logically related sets of routines.
+ The Makefile now runs much faster since every single routine is
+ not split into a separate file.
+
+ - now use the memcpy function, rather than a 'for' loop in several
+ places for added efficiency
+
+ - redesigned the low-level binary table read and write routines
+ (ffpbytoff and ffgbytoff) for greater efficiency.
+
+ - added a new error status: 103 = too many open FITS files.
+
+ - added a 'extern "C"' statement around the function prototypes
+ in fitsio.h, to support use of cfitsio by C++ compilers.
+
+ - fixed routines for writing or reading fixed-length substrings
+ within a binary table ASCII column, with TFORM values of
+ of the form 'rAw' where 'r' is the total width of the ASCII
+ column and 'w' is the width of a substring within the column.
+
+ - no longer automatically rewrite the END card and following fill
+ values if they are already correct.
+
+ - all the 'get keyword value and comment' routines have been changed
+ so that the comment is not returned if the input pointer is NULL.
+
+ - added new routine to return the optimum number of tables rows
+ that should be read or written at one time for optimum efficiency.
+
+ - modified the way numerical values in ASCII tables are parsed so
+ that embedded spaces in the value are ignored, and implicit
+ decimal points are now supported. (e.g, the string '123E 12'
+ in a 'E10.2' format column will be interpreted as 1.23 * 10**12).
+
+ - modified ffpcl and ffgcl to support binary table columns of
+ all datatype (added logical, bit, complex, and double complex)
+
+ - when writing numerical data to ASCII table columns, the ffpcl_
+ routines now return an overflow error if a value is too large
+ to be expressed in the column format.
+
+ - closed small memory leak in ffpcls.
+
+ - initialized the 'incre' variable in ffgcpr to eliminate compiler warning.
+
+Version 1.04 - 17 Sept 1996
+
+ - added README.MacOS and cfitsio_mac.sit.hqx to the distribution
+ to support the Mac platforms.
+
+ - fixed bug in ffpdfl that caused an EOF error (107) when a program
+ creates a new extension that is an exact multiple of 2880 bytes long,
+ AND the program does not write a value to the last element
+ in the table or image.
+
+ - fixed bug in all the ffgsf* and ffgcv* routines which caused
+ core dumps when reading null values in a table.
+
+Version 1.03 - 20 August 1996
+
+ - added full support for reading and writing the C 'int'
+ data type. This was a problem on Alpha/OSF where short,
+ int, and long datatypes are 2, 4, and 8 bytes long, respectively.
+
+ - cleaned up the code in the byte-swapping routines.
+
+ - renamed the file 'longname.h' to 'longnam.h' to avoid conflict
+ with a file with the same name in another unrelated package.
+
+Version 1.02 - 15 August 1996
+
+ - ffgtbp was not correctly reading the THEAP keyword, hence would
+ not correctly read variable length data in binary tables if
+ the heap was not at the default starting location (i.e.,
+ starting immediately after the fixed length table).
+
+ - now force the cbuff variable in ffpcl_ and ffgcl_ to be
+ aligned on a double word boundary. Non-alignment can
+ cause program to crash on some systems.
+
+Version 1.01 - 12 August 1996
+
+ - initial public release
diff --git a/pkg/tbtables/cfitsio/checksum.c b/pkg/tbtables/cfitsio/checksum.c
new file mode 100644
index 00000000..3cde9951
--- /dev/null
+++ b/pkg/tbtables/cfitsio/checksum.c
@@ -0,0 +1,508 @@
+/* This file, checksum.c, contains the checksum-related routines in the */
+/* FITSIO library. */
+
+/* The FITSIO software was written by William Pence at the High Energy */
+/* Astrophysic Science Archive Research Center (HEASARC) at the NASA */
+/* Goddard Space Flight Center. */
+
+#include <string.h>
+#include <stdlib.h>
+#include "fitsio2.h"
+/*------------------------------------------------------------------------*/
+int ffcsum(fitsfile *fptr, /* I - FITS file pointer */
+ long nrec, /* I - number of 2880-byte blocks to sum */
+ unsigned long *sum, /* IO - accumulated checksum */
+ int *status) /* IO - error status */
+/*
+ Calculate a 32-bit 1's complement checksum of the FITS 2880-byte blocks.
+ This routine is based on the C algorithm developed by Rob
+ Seaman at NOAO that was presented at the 1994 ADASS conference,
+ published in the Astronomical Society of the Pacific Conference Series.
+ This uses a 32-bit 1's complement checksum in which the overflow bits
+ are permuted back into the sum and therefore all bit positions are
+ sampled evenly.
+*/
+{
+ long ii, jj;
+ unsigned short sbuf[1440];
+ unsigned long hi, lo, hicarry, locarry;
+
+ if (*status > 0)
+ return(*status);
+ /*
+ Sum the specified number of FITS 2880-byte records. This assumes that
+ the FITSIO file pointer points to the start of the records to be summed.
+ Read each FITS block as 1440 short values (do byte swapping if needed).
+ */
+ for (jj = 0; jj < nrec; jj++)
+ {
+ ffgbyt(fptr, 2880, sbuf, status);
+
+#if BYTESWAPPED
+
+ ffswap2( (short *)sbuf, 1440); /* reverse order of bytes in each value */
+
+#endif
+
+ hi = (*sum >> 16);
+ lo = *sum & 0xFFFF;
+
+ for (ii = 0; ii < 1440; ii += 2)
+ {
+ hi += sbuf[ii];
+ lo += sbuf[ii+1];
+ }
+
+ hicarry = hi >> 16; /* fold carry bits in */
+ locarry = lo >> 16;
+
+ while (hicarry | locarry)
+ {
+ hi = (hi & 0xFFFF) + locarry;
+ lo = (lo & 0xFFFF) + hicarry;
+ hicarry = hi >> 16;
+ locarry = lo >> 16;
+ }
+
+ *sum = (hi << 16) + lo;
+ }
+ return(*status);
+}
+/*-------------------------------------------------------------------------*/
+void ffesum(unsigned long sum, /* I - accumulated checksum */
+ int complm, /* I - = 1 to encode complement of the sum */
+ char *ascii) /* O - 16-char ASCII encoded checksum */
+/*
+ encode the 32 bit checksum by converting every
+ 2 bits of each byte into an ASCII character (32 bit word encoded
+ as 16 character string). Only ASCII letters and digits are used
+ to encode the values (no ASCII punctuation characters).
+
+ If complm=TRUE, then the complement of the sum will be encoded.
+
+ This routine is based on the C algorithm developed by Rob
+ Seaman at NOAO that was presented at the 1994 ADASS conference,
+ published in the Astronomical Society of the Pacific Conference Series.
+*/
+{
+ unsigned int exclude[13] = { 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40,
+ 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60 };
+ unsigned long mask[4] = { 0xff000000, 0xff0000, 0xff00, 0xff };
+
+ int offset = 0x30; /* ASCII 0 (zero) */
+
+ unsigned long value;
+ int byte, quotient, remainder, ch[4], check, ii, jj, kk;
+ char asc[32];
+
+ if (complm)
+ value = 0xFFFFFFFF - sum; /* complement each bit of the value */
+ else
+ value = sum;
+
+ for (ii = 0; ii < 4; ii++)
+ {
+ byte = (value & mask[ii]) >> (24 - (8 * ii));
+ quotient = byte / 4 + offset;
+ remainder = byte % 4;
+ for (jj = 0; jj < 4; jj++)
+ ch[jj] = quotient;
+
+ ch[0] += remainder;
+
+ for (check = 1; check;) /* avoid ASCII punctuation */
+ for (check = 0, kk = 0; kk < 13; kk++)
+ for (jj = 0; jj < 4; jj += 2)
+ if ((unsigned char) ch[jj] == exclude[kk] ||
+ (unsigned char) ch[jj+1] == exclude[kk])
+ {
+ ch[jj]++;
+ ch[jj+1]--;
+ check++;
+ }
+
+ for (jj = 0; jj < 4; jj++) /* assign the bytes */
+ asc[4*jj+ii] = ch[jj];
+ }
+
+ for (ii = 0; ii < 16; ii++) /* shift the bytes 1 to the right */
+ ascii[ii] = asc[(ii+15)%16];
+
+ ascii[16] = '\0';
+}
+/*-------------------------------------------------------------------------*/
+unsigned long ffdsum(char *ascii, /* I - 16-char ASCII encoded checksum */
+ int complm, /* I - =1 to decode complement of the */
+ unsigned long *sum) /* O - 32-bit checksum */
+/*
+ decode the 16-char ASCII encoded checksum into an unsigned 32-bit long.
+ If complm=TRUE, then the complement of the sum will be decoded.
+
+ This routine is based on the C algorithm developed by Rob
+ Seaman at NOAO that was presented at the 1994 ADASS conference,
+ published in the Astronomical Society of the Pacific Conference Series.
+*/
+{
+ char cbuf[16];
+ unsigned long hi = 0, lo = 0, hicarry, locarry;
+ int ii;
+
+ /* remove the permuted FITS byte alignment and the ASCII 0 offset */
+ for (ii = 0; ii < 16; ii++)
+ {
+ cbuf[ii] = ascii[(ii+1)%16];
+ cbuf[ii] -= 0x30;
+ }
+
+ for (ii = 0; ii < 16; ii += 4)
+ {
+ hi += (cbuf[ii] << 8) + cbuf[ii+1];
+ lo += (cbuf[ii+2] << 8) + cbuf[ii+3];
+ }
+
+ hicarry = hi >> 16;
+ locarry = lo >> 16;
+ while (hicarry || locarry)
+ {
+ hi = (hi & 0xFFFF) + locarry;
+ lo = (lo & 0xFFFF) + hicarry;
+ hicarry = hi >> 16;
+ locarry = lo >> 16;
+ }
+
+ *sum = (hi << 16) + lo;
+ if (complm)
+ *sum = 0xFFFFFFFF - *sum; /* complement each bit of the value */
+
+ return(*sum);
+}
+/*------------------------------------------------------------------------*/
+int ffpcks(fitsfile *fptr, /* I - FITS file pointer */
+ int *status) /* IO - error status */
+/*
+ Create or update the checksum keywords in the CHDU. These keywords
+ provide a checksum verification of the FITS HDU based on the ASCII
+ coded 1's complement checksum algorithm developed by Rob Seaman at NOAO.
+*/
+{
+ char datestr[20], checksum[FLEN_VALUE], datasum[FLEN_VALUE];
+ char comm[FLEN_COMMENT], chkcomm[FLEN_COMMENT], datacomm[FLEN_COMMENT];
+ int tstatus;
+ long nrec;
+ OFF_T headstart, datastart, dataend;
+ unsigned long dsum, olddsum, sum;
+ double tdouble;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ /* generate current date string and construct the keyword comments */
+ ffgstm(datestr, NULL, status);
+ strcpy(chkcomm, "HDU checksum updated ");
+ strcat(chkcomm, datestr);
+ strcpy(datacomm, "data unit checksum updated ");
+ strcat(datacomm, datestr);
+
+ /* write the CHECKSUM keyword if it does not exist */
+ tstatus = *status;
+ if (ffgkys(fptr, "CHECKSUM", checksum, comm, status) == KEY_NO_EXIST)
+ {
+ *status = tstatus;
+ strcpy(checksum, "0000000000000000");
+ ffpkys(fptr, "CHECKSUM", checksum, chkcomm, status);
+ }
+
+ /* write the DATASUM keyword if it does not exist */
+ tstatus = *status;
+ if (ffgkys(fptr, "DATASUM", datasum, comm, status) == KEY_NO_EXIST)
+ {
+ *status = tstatus;
+ olddsum = 0;
+ ffpkys(fptr, "DATASUM", " 0", datacomm, status);
+
+ /* set the CHECKSUM keyword as undefined, if it isn't already */
+ if (strcmp(checksum, "0000000000000000") )
+ {
+ strcpy(checksum, "0000000000000000");
+ ffmkys(fptr, "CHECKSUM", checksum, chkcomm, status);
+ }
+ }
+ else
+ {
+ /* decode the datasum into an unsigned long variable */
+
+ /* olddsum = strtoul(datasum, 0, 10); doesn't work on SUN OS */
+
+ tdouble = atof(datasum);
+ olddsum = tdouble;
+ }
+
+ /* close header: rewrite END keyword and following blank fill */
+ /* and re-read the required keywords to determine the structure */
+ if (ffrdef(fptr, status) > 0)
+ return(*status);
+
+ if ((fptr->Fptr)->heapsize > 0)
+ ffuptf(fptr, status); /* update the variable length TFORM values */
+
+ /* write the correct data fill values, if they are not already correct */
+ if (ffpdfl(fptr, status) > 0)
+ return(*status);
+
+ /* calc size of data unit, in FITS 2880-byte blocks */
+ if (ffghof(fptr, &headstart, &datastart, &dataend, status) > 0)
+ return(*status);
+
+ nrec = (dataend - datastart) / 2880;
+ dsum = 0;
+
+ if (nrec > 0)
+ {
+ /* accumulate the 32-bit 1's complement checksum */
+ ffmbyt(fptr, datastart, REPORT_EOF, status);
+ if (ffcsum(fptr, nrec, &dsum, status) > 0)
+ return(*status);
+ }
+
+ if (dsum != olddsum)
+ {
+ /* update the DATASUM keyword with the correct value */
+ sprintf(datasum, "%lu", dsum);
+ ffmkys(fptr, "DATASUM", datasum, datacomm, status);
+
+ /* set the CHECKSUM keyword as undefined, if it isn't already */
+ if (strcmp(checksum, "0000000000000000") )
+ {
+ strcpy(checksum, "0000000000000000");
+ ffmkys(fptr, "CHECKSUM", checksum, chkcomm, status);
+ }
+ }
+
+ if (strcmp(checksum, "0000000000000000") )
+ {
+ /* check if CHECKSUM is still OK; move to the start of the header */
+ ffmbyt(fptr, headstart, REPORT_EOF, status);
+
+ /* accumulate the header checksum into the previous data checksum */
+ nrec = (datastart - headstart) / 2880;
+ sum = dsum;
+ if (ffcsum(fptr, nrec, &sum, status) > 0)
+ return(*status);
+
+ if (sum == 0 || sum == 0xFFFFFFFF)
+ return(*status); /* CHECKSUM is correct */
+
+ /* Zero the CHECKSUM and recompute the new value */
+ ffmkys(fptr, "CHECKSUM", "0000000000000000", chkcomm, status);
+ }
+
+ /* move to the start of the header */
+ ffmbyt(fptr, headstart, REPORT_EOF, status);
+
+ /* accumulate the header checksum into the previous data checksum */
+ nrec = (datastart - headstart) / 2880;
+ sum = dsum;
+ if (ffcsum(fptr, nrec, &sum, status) > 0)
+ return(*status);
+
+ /* encode the COMPLEMENT of the checksum into a 16-character string */
+ ffesum(sum, TRUE, checksum);
+
+ /* update the CHECKSUM keyword value with the new string */
+ ffmkys(fptr, "CHECKSUM", checksum, "&", status);
+
+ return(*status);
+}
+/*------------------------------------------------------------------------*/
+int ffupck(fitsfile *fptr, /* I - FITS file pointer */
+ int *status) /* IO - error status */
+/*
+ Update the CHECKSUM keyword value. This assumes that the DATASUM
+ keyword exists and has the correct value.
+*/
+{
+ char datestr[20], chkcomm[FLEN_COMMENT], comm[FLEN_COMMENT];
+ char checksum[FLEN_VALUE], datasum[FLEN_VALUE];
+ int tstatus;
+ long nrec;
+ OFF_T headstart, datastart, dataend;
+ unsigned long sum, dsum;
+ double tdouble;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ /* generate current date string and construct the keyword comments */
+ ffgstm(datestr, NULL, status);
+ strcpy(chkcomm, "HDU checksum updated ");
+ strcat(chkcomm, datestr);
+
+ /* get the DATASUM keyword and convert it to a unsigned long */
+ if (ffgkys(fptr, "DATASUM", datasum, comm, status) == KEY_NO_EXIST)
+ {
+ ffpmsg("DATASUM keyword not found (ffupck");
+ return(*status);
+ }
+
+ tdouble = atof(datasum); /* read as a double as a workaround */
+ dsum = tdouble;
+
+ /* get size of the HDU */
+ if (ffghof(fptr, &headstart, &datastart, &dataend, status) > 0)
+ return(*status);
+
+ /* get the checksum keyword, if it exists */
+ tstatus = *status;
+ if (ffgkys(fptr, "CHECKSUM", checksum, comm, status) == KEY_NO_EXIST)
+ {
+ *status = tstatus;
+ strcpy(checksum, "0000000000000000");
+ ffpkys(fptr, "CHECKSUM", checksum, chkcomm, status);
+ }
+ else
+ {
+ /* check if CHECKSUM is still OK */
+ /* rewrite END keyword and following blank fill */
+ if (ffwend(fptr, status) > 0)
+ return(*status);
+
+ /* move to the start of the header */
+ ffmbyt(fptr, headstart, REPORT_EOF, status);
+
+ /* accumulate the header checksum into the previous data checksum */
+ nrec = (datastart - headstart) / 2880;
+ sum = dsum;
+ if (ffcsum(fptr, nrec, &sum, status) > 0)
+ return(*status);
+
+ if (sum == 0 || sum == 0xFFFFFFFF)
+ return(*status); /* CHECKSUM is already correct */
+
+ /* Zero the CHECKSUM and recompute the new value */
+ ffmkys(fptr, "CHECKSUM", "0000000000000000", chkcomm, status);
+ }
+
+ /* move to the start of the header */
+ ffmbyt(fptr, headstart, REPORT_EOF, status);
+
+ /* accumulate the header checksum into the previous data checksum */
+ nrec = (datastart - headstart) / 2880;
+ sum = dsum;
+ if (ffcsum(fptr, nrec, &sum, status) > 0)
+ return(*status);
+
+ /* encode the COMPLEMENT of the checksum into a 16-character string */
+ ffesum(sum, TRUE, checksum);
+
+ /* update the CHECKSUM keyword value with the new string */
+ ffmkys(fptr, "CHECKSUM", checksum, "&", status);
+
+ return(*status);
+}
+/*------------------------------------------------------------------------*/
+int ffvcks(fitsfile *fptr, /* I - FITS file pointer */
+ int *datastatus, /* O - data checksum status */
+ int *hdustatus, /* O - hdu checksum status */
+ /* 1 verification is correct */
+ /* 0 checksum keyword is not present */
+ /* -1 verification not correct */
+ int *status) /* IO - error status */
+/*
+ Verify the HDU by comparing the value of the computed checksums against
+ the values of the DATASUM and CHECKSUM keywords if they are present.
+*/
+{
+ int tstatus;
+ double tdouble;
+ unsigned long datasum, hdusum, olddatasum;
+ char chksum[FLEN_VALUE], comm[FLEN_COMMENT];
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ *datastatus = -1;
+ *hdustatus = -1;
+
+ tstatus = *status;
+ if (ffgkys(fptr, "CHECKSUM", chksum, comm, status) == KEY_NO_EXIST)
+ {
+ *hdustatus = 0; /* CHECKSUM keyword does not exist */
+ *status = tstatus;
+ }
+ if (chksum[0] == '\0')
+ *hdustatus = 0; /* all blank checksum means it is undefined */
+
+ if (ffgkys(fptr, "DATASUM", chksum, comm, status) == KEY_NO_EXIST)
+ {
+ *datastatus = 0; /* DATASUM keyword does not exist */
+ *status = tstatus;
+ }
+ if (chksum[0] == '\0')
+ *datastatus = 0; /* all blank checksum means it is undefined */
+
+ if ( *status > 0 || (!(*hdustatus) && !(*datastatus)) )
+ return(*status); /* return if neither keywords exist */
+
+ /* convert string to unsigned long */
+
+ /* olddatasum = strtoul(chksum, 0, 10); doesn't work w/ gcc on SUN OS */
+ /* sscanf(chksum, "%u", &olddatasum); doesn't work w/ cc on VAX/VMS */
+
+ tdouble = atof(chksum); /* read as a double as a workaround */
+ olddatasum = tdouble;
+
+ /* calculate the data checksum and the HDU checksum */
+ if (ffgcks(fptr, &datasum, &hdusum, status) > 0)
+ return(*status);
+
+ if (*datastatus)
+ if (datasum == olddatasum)
+ *datastatus = 1;
+
+ if (*hdustatus)
+ if (hdusum == 0 || hdusum == 0xFFFFFFFF)
+ *hdustatus = 1;
+
+ return(*status);
+}
+/*------------------------------------------------------------------------*/
+int ffgcks(fitsfile *fptr, /* I - FITS file pointer */
+ unsigned long *datasum, /* O - data checksum */
+ unsigned long *hdusum, /* O - hdu checksum */
+ int *status) /* IO - error status */
+
+ /* calculate the checksums of the data unit and the total HDU */
+{
+ long nrec;
+ OFF_T headstart, datastart, dataend;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ /* get size of the HDU */
+ if (ffghof(fptr, &headstart, &datastart, &dataend, status) > 0)
+ return(*status);
+
+ nrec = (dataend - datastart) / 2880;
+
+ *datasum = 0;
+
+ if (nrec > 0)
+ {
+ /* accumulate the 32-bit 1's complement checksum */
+ ffmbyt(fptr, datastart, REPORT_EOF, status);
+ if (ffcsum(fptr, nrec, datasum, status) > 0)
+ return(*status);
+ }
+
+ /* move to the start of the header and calc. size of header */
+ ffmbyt(fptr, headstart, REPORT_EOF, status);
+ nrec = (datastart - headstart) / 2880;
+
+ /* accumulate the header checksum into the previous data checksum */
+ *hdusum = *datasum;
+ ffcsum(fptr, nrec, hdusum, status);
+
+ return(*status);
+}
+
diff --git a/pkg/tbtables/cfitsio/compress.c b/pkg/tbtables/cfitsio/compress.c
new file mode 100644
index 00000000..7ae5a91b
--- /dev/null
+++ b/pkg/tbtables/cfitsio/compress.c
@@ -0,0 +1,155 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+/* ======================================================================
+
+This file contains stubs for the compression and uncompression routines
+that are contained in the source file compress.c. Those routines (in
+compress.c) can only be used by software which adheres to the terms of
+the GNU General Public License. Users who want to use CFITSIO but are
+unwilling to release their code under the terms of the GNU General
+Public License should replace the compress.c file with this current
+file before building the CFITSIO library. This alternative version of
+CFITSIO will behave the same as the standard version, except that it
+will not support reading or writing of FITS files in compressed format.
+
+======================================================================== */
+/* prototype for the following functions */
+
+void ffpmsg(const char *err_message);
+
+int uncompress2mem(char *filename,
+ FILE *diskfile,
+ char **buffptr,
+ size_t *buffsize,
+ void *(*mem_realloc)(void *p, size_t newsize),
+ size_t *filesize,
+ int *status);
+
+int uncompress2mem_from_mem(
+ char *inmemptr,
+ size_t inmemsize,
+ char **buffptr,
+ size_t *buffsize,
+ void *(*mem_realloc)(void *p, size_t newsize),
+ size_t *filesize,
+ int *status);
+
+int uncompress2file(char *filename,
+ FILE *indiskfile,
+ FILE *outdiskfile,
+ int *status);
+
+int compress2mem_from_mem(
+ char *inmemptr,
+ size_t inmemsize,
+ char **buffptr,
+ size_t *buffsize,
+ void *(*mem_realloc)(void *p, size_t newsize),
+ size_t *filesize,
+ int *status);
+
+int compress2file_from_mem(
+ char *inmemptr,
+ size_t inmemsize,
+ FILE *outdiskfile,
+ size_t *filesize, /* O - size of file, in bytes */
+ int *status);
+/*--------------------------------------------------------------------------*/
+int uncompress2mem(char *filename, /* name of input file */
+ FILE *diskfile, /* I - file pointer */
+ char **buffptr, /* IO - memory pointer */
+ size_t *buffsize, /* IO - size of buffer, in bytes */
+ void *(*mem_realloc)(void *p, size_t newsize), /* function */
+ size_t *filesize, /* O - size of file, in bytes */
+ int *status) /* IO - error status */
+
+/*
+ Uncompress the file into memory. Fill whatever amount of memory has
+ already been allocated, then realloc more memory, using the supplied
+ input function, if necessary.
+*/
+{
+ if (*status > 0)
+ return(*status);
+
+ ffpmsg("This non-GNU version of CFITSIO does not support compressed files");
+ return(*status = 414);
+}
+/*--------------------------------------------------------------------------*/
+int uncompress2mem_from_mem(
+ char *inmemptr, /* I - memory pointer to compressed bytes */
+ size_t inmemsize, /* I - size of input compressed file */
+ char **buffptr, /* IO - memory pointer */
+ size_t *buffsize, /* IO - size of buffer, in bytes */
+ void *(*mem_realloc)(void *p, size_t newsize), /* function */
+ size_t *filesize, /* O - size of file, in bytes */
+ int *status) /* IO - error status */
+
+/*
+ Uncompress the file into memory. Fill whatever amount of memory has
+ already been allocated, then realloc more memory, using the supplied
+ input function, if necessary.
+*/
+{
+ if (*status > 0)
+ return(*status);
+
+ ffpmsg("This non-GNU version of CFITSIO does not support compressed files");
+ return(*status = 414);
+}
+/*--------------------------------------------------------------------------*/
+int uncompress2file(char *filename, /* name of input file */
+ FILE *indiskfile, /* I - input file pointer */
+ FILE *outdiskfile, /* I - output file pointer */
+ int *status) /* IO - error status */
+
+/*
+ Uncompress the file into file.
+*/
+{
+ if (*status > 0)
+ return(*status);
+
+ ffpmsg("This non-GNU version of CFITSIO does not support compressed files");
+ return(*status = 414);
+}
+/*--------------------------------------------------------------------------*/
+int compress2mem_from_mem(
+ char *inmemptr, /* I - memory pointer to uncompressed bytes */
+ size_t inmemsize, /* I - size of input uncompressed file */
+ char **buffptr, /* IO - memory pointer for compressed file */
+ size_t *buffsize, /* IO - size of buffer, in bytes */
+ void *(*mem_realloc)(void *p, size_t newsize), /* function */
+ size_t *filesize, /* O - size of file, in bytes */
+ int *status) /* IO - error status */
+
+/*
+ Compress the file into memory. Fill whatever amount of memory has
+ already been allocated, then realloc more memory, using the supplied
+ input function, if necessary.
+*/
+{
+ if (*status > 0)
+ return(*status);
+
+ ffpmsg("This non-GNU version of CFITSIO does not support compressed files");
+ return(*status = 413);
+}
+/*--------------------------------------------------------------------------*/
+int compress2file_from_mem(
+ char *inmemptr, /* I - memory pointer to uncompressed bytes */
+ size_t inmemsize, /* I - size of input uncompressed file */
+ FILE *outdiskfile,
+ size_t *filesize, /* O - size of file, in bytes */
+ int *status)
+/*
+ Compress the memory file into disk file.
+*/
+{
+ if (*status > 0)
+ return(*status);
+
+ ffpmsg("This non-GNU version of CFITSIO does not support compressed files");
+ return(*status = 413);
+}
diff --git a/pkg/tbtables/cfitsio/compress.h b/pkg/tbtables/cfitsio/compress.h
new file mode 100644
index 00000000..7e3c4066
--- /dev/null
+++ b/pkg/tbtables/cfitsio/compress.h
@@ -0,0 +1,212 @@
+/* compress.h -- definitions for the decompression routines used in CFITSIO */
+
+/* Blatantly copied and modified from the original gzip-1.2.4 source code. */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+/* 'near' is only relevant for 16-bit PC with small memory model */
+# define near
+
+#if defined(VAXC) || defined(VMS)
+# define RECORD_IO 1
+#else
+# define RECORD_IO 0
+#endif
+
+#define get_char() get_byte()
+
+/* gzip.h -- common declarations for all gzip modules */
+
+#define OF(args) args
+typedef void *voidp;
+
+#define memzero(s, n) memset ((voidp)(s), 0, (n))
+
+typedef unsigned char uch;
+typedef unsigned short ush;
+typedef unsigned long ulg;
+
+/* Return codes from gzip */
+#define OK 0
+#define ERROR 1
+#define WARNING 2
+
+/* Compression methods (see algorithm.doc) */
+#define STORED 0
+#define COMPRESSED 1
+#define PACKED 2
+#define LZHED 3
+/* methods 4 to 7 reserved */
+#define DEFLATED 8
+#define MAX_METHODS 9
+
+#define INBUFSIZ 0x8000 /* input buffer size */
+#define INBUF_EXTRA 64 /* required by unlzw() */
+#define OUTBUFSIZ 16384 /* output buffer size */
+#define OUTBUF_EXTRA 2048 /* required by unlzw() */
+#define DIST_BUFSIZE 0x8000 /* buffer for distances, see trees.c */
+#define WSIZE 0x8000 /* window size--must be a power of two, and */
+
+#define DECLARE(type, array, size) type array[size]
+
+#define tab_suffix window
+#define tab_prefix prev /* hash link (see deflate.c) */
+#define head (prev+WSIZE) /* hash head (see deflate.c) */
+
+#define PACK_MAGIC "\037\036" /* Magic header for packed files */
+#define GZIP_MAGIC "\037\213" /* Magic header for gzip files, 1F 8B */
+#define OLD_GZIP_MAGIC "\037\236" /* Magic header for gzip 0.5 = freeze 1.x */
+#define LZH_MAGIC "\037\240" /* Magic header for SCO LZH Compress files*/
+#define LZW_MAGIC "\037\235" /* Magic header for lzw files, 1F 9D */
+#define PKZIP_MAGIC "\120\113\003\004" /* Magic header for pkzip files */
+
+/* gzip flag byte */
+#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
+#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
+#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
+#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
+#define COMMENT 0x10 /* bit 4 set: file comment present */
+#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */
+#define RESERVED 0xC0 /* bit 6,7: reserved */
+
+#define MIN_MATCH 3
+#define MAX_MATCH 258
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+#define MAX_DIST (WSIZE-MIN_LOOKAHEAD)
+#define translate_eol 0 /* no option -a yet */
+
+#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf(0))
+#define try_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf(1))
+#define put_ubyte(c) {window[outcnt++]=(uch)(c); if (outcnt==WSIZE)\
+ flush_window();}
+
+/* Macros for getting two-byte and four-byte header values */
+#define SH(p) ((ush)(uch)((p)[0]) | ((ush)(uch)((p)[1]) << 8))
+#define LG(p) ((ulg)(SH(p)) | ((ulg)(SH((p)+2)) << 16))
+
+/* Diagnostic functions */
+# define Assert(cond,msg)
+# define Trace(x)
+# define Tracev(x)
+# define Tracevv(x)
+# define Tracec(c,x)
+# define Tracecv(c,x)
+
+/* lzw.h -- define the lzw functions. */
+
+#ifndef BITS
+# define BITS 16
+#endif
+#define INIT_BITS 9 /* Initial number of bits per code */
+#define BIT_MASK 0x1f /* Mask for 'number of compression bits' */
+#define BLOCK_MODE 0x80
+#define LZW_RESERVED 0x60 /* reserved bits */
+#define CLEAR 256 /* flush the dictionary */
+#define FIRST (CLEAR+1) /* first free entry */
+
+/* prototypes */
+
+#define local static
+void ffpmsg(const char *err_message);
+
+local int get_method OF((FILE *in));
+
+local ulg updcrc OF((uch *s, unsigned n));
+local int fill_inbuf OF((int eof_ok));
+local void flush_outbuf OF((void));
+local void flush_window OF((void));
+local void write_buf OF((voidp buf, unsigned cnt));
+local void error OF((char *m));
+local ulg flush_block OF((char *buf, ulg stored_len, int eof));
+typedef int file_t; /* Do not use stdio */
+#define NO_FILE (-1) /* in memory compression */
+local int file_read OF((char *buf, unsigned size));
+local void send_bits OF((int value, int length));
+local unsigned bi_reverse OF((unsigned value, int length));
+local void bi_windup OF((void));
+local void copy_block OF((char *buf, unsigned len, int header));
+local int (*read_buf) OF((char *buf, unsigned size));
+local void lm_init OF((int pack_level, ush *flags));
+local ulg deflate OF((void));
+local void ct_init OF((ush *attr, int *method));
+local int ct_tally OF((int dist, int lc));
+local void bi_init OF((file_t zipfile));
+
+#define put_byte(c) {outbuf[outcnt++]=(uch)(c); if (outcnt==OUTBUFSIZ)\
+ flush_outbuf();}
+
+/* Output a 16 bit value, lsb first */
+#define put_short(w) \
+{ if (outcnt < OUTBUFSIZ-2) { \
+ outbuf[outcnt++] = (uch) ((w) & 0xff); \
+ outbuf[outcnt++] = (uch) ((ush)(w) >> 8); \
+ } else { \
+ put_byte((uch)((w) & 0xff)); \
+ put_byte((uch)((ush)(w) >> 8)); \
+ } \
+}
+
+/* Output a 32 bit value to the bit stream, lsb first */
+#define put_long(n) { \
+ put_short((n) & 0xffff); \
+ put_short(((ulg)(n)) >> 16); \
+}
+
+#define seekable() 0 /* force sequential output */
+
+/* io.c */
+local void fillbuf OF((int n));
+local unsigned getbits OF((int n));
+local void init_getbits OF((void));
+
+/* maketbl.c */
+local void make_table OF((int nchar, uch bitlen[],
+ int tablebits, ush table[]));
+
+/* huf.c */
+local void read_pt_len OF((int nn, int nbit, int i_special));
+local void read_c_len OF((void));
+local unsigned decode_c OF((void));
+local unsigned decode_p OF((void));
+local void huf_decode_start OF((void));
+
+/* decode.c */
+local void decode_start OF((void));
+local unsigned decode OF((unsigned count, uch buffer[]));
+
+local int unlzh OF((FILE *in, FILE *out));
+local int unlzw OF((FILE *in, FILE *out));
+
+local void read_tree OF((void));
+local void build_tree_unpack OF((void));
+
+local int unpack OF((FILE *in, FILE *out));
+local int check_zipfile OF((FILE *in));
+local int unzip OF((FILE *in, FILE *out));
+
+int (*work) OF((FILE *infile, FILE *outfile)) = unzip; /* function to call */
+
+/* inflate.c */
+struct huft {
+ uch e; /* number of extra bits or operation */
+ uch b; /* number of bits in this code or subcode */
+ union {
+ ush n; /* literal, length base, or distance base */
+ struct huft *t; /* pointer to next level of table */
+ } v;
+};
+
+local int huft_build OF((unsigned *, unsigned, unsigned, ush *, ush *,
+ struct huft **, int *));
+local int huft_free OF((struct huft *));
+local int inflate_codes OF((struct huft *, struct huft *, int, int));
+local int inflate_stored OF((void));
+local int inflate_fixed OF((void));
+local int inflate_dynamic OF((void));
+local int inflate_block OF((int *));
+local int inflate OF((void));
+
+/* end of compress.h include file */
diff --git a/pkg/tbtables/cfitsio/configure b/pkg/tbtables/cfitsio/configure
new file mode 100755
index 00000000..f277be6a
--- /dev/null
+++ b/pkg/tbtables/cfitsio/configure
@@ -0,0 +1,1886 @@
+#! /bin/sh
+
+# Guess values for system-dependent variables and create Makefiles.
+# Generated automatically using autoconf version 2.13
+# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc.
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+
+# Defaults:
+ac_help=
+ac_default_prefix=/usr/local
+# Any additions from configure.in:
+
+# Initialize some variables set by options.
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+build=NONE
+cache_file=./config.cache
+exec_prefix=NONE
+host=NONE
+no_create=
+nonopt=NONE
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+target=NONE
+verbose=
+x_includes=NONE
+x_libraries=NONE
+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'
+
+# Initialize some other variables.
+subdirs=
+MFLAGS= MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+# Maximum number of lines to put in a shell here document.
+ac_max_here_lines=12
+
+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
+
+ case "$ac_option" in
+ -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+ *) ac_optarg= ;;
+ esac
+
+ # 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 ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build="$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" ;;
+
+ -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+ | --da=*)
+ datadir="$ac_optarg" ;;
+
+ -disable-* | --disable-*)
+ ac_feature=`echo $ac_option|sed -e 's/-*disable-//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then
+ { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+ fi
+ ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+ eval "enable_${ac_feature}=no" ;;
+
+ -enable-* | --enable-*)
+ ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then
+ { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+ fi
+ ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+ case "$ac_option" in
+ *=*) ;;
+ *) 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)
+ # 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 << EOF
+Usage: configure [options] [host]
+Options: [defaults in brackets after descriptions]
+Configuration:
+ --cache-file=FILE cache test results in FILE
+ --help print this message
+ --no-create do not create output files
+ --quiet, --silent do not print \`checking...' messages
+ --version print the version of autoconf that created configure
+Directory and file names:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [same as prefix]
+ --bindir=DIR user executables in DIR [EPREFIX/bin]
+ --sbindir=DIR system admin executables in DIR [EPREFIX/sbin]
+ --libexecdir=DIR program executables in DIR [EPREFIX/libexec]
+ --datadir=DIR read-only architecture-independent data in DIR
+ [PREFIX/share]
+ --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data in DIR
+ [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var]
+ --libdir=DIR object code libraries in DIR [EPREFIX/lib]
+ --includedir=DIR C header files in DIR [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include]
+ --infodir=DIR info documentation in DIR [PREFIX/info]
+ --mandir=DIR man documentation in DIR [PREFIX/man]
+ --srcdir=DIR find the sources in DIR [configure dir or ..]
+ --program-prefix=PREFIX prepend PREFIX to installed program names
+ --program-suffix=SUFFIX append SUFFIX to installed program names
+ --program-transform-name=PROGRAM
+ run sed PROGRAM on installed program names
+EOF
+ cat << EOF
+Host type:
+ --build=BUILD configure for building on BUILD [BUILD=HOST]
+ --host=HOST configure for HOST [guessed]
+ --target=TARGET configure for TARGET [TARGET=HOST]
+Features and packages:
+ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
+ --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --x-includes=DIR X include files are in DIR
+ --x-libraries=DIR X library files are in DIR
+EOF
+ if test -n "$ac_help"; then
+ echo "--enable and --with options recognized:$ac_help"
+ fi
+ exit 0 ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host="$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)
+ 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 ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target="$ac_optarg" ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers)
+ echo "configure generated by autoconf version 2.13"
+ exit 0 ;;
+
+ -with-* | --with-*)
+ ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then
+ { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+ fi
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ case "$ac_option" in
+ *=*) ;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "with_${ac_package}='$ac_optarg'" ;;
+
+ -without-* | --without-*)
+ ac_package=`echo $ac_option|sed -e 's/-*without-//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then
+ { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+ fi
+ 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 "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; }
+ ;;
+
+ *)
+ if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then
+ echo "configure: warning: $ac_option: invalid host type" 1>&2
+ fi
+ if test "x$nonopt" != xNONE; then
+ { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; }
+ fi
+ nonopt="$ac_option"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; }
+fi
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+# File descriptor usage:
+# 0 standard input
+# 1 file creation
+# 2 errors and warnings
+# 3 some systems may open it to /dev/tty
+# 4 used on the Kubota Titan
+# 6 checking for... messages and results
+# 5 compiler messages saved in config.log
+if test "$silent" = yes; then
+ exec 6>/dev/null
+else
+ exec 6>&1
+fi
+exec 5>./config.log
+
+echo "\
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+" 1>&5
+
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Also quote any args containing shell metacharacters.
+ac_configure_args=
+for ac_arg
+do
+ case "$ac_arg" in
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c) ;;
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;;
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*)
+ ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+ *) ac_configure_args="$ac_configure_args $ac_arg" ;;
+ esac
+done
+
+# NLS nuisances.
+# Only set these to C if already set. These must not be set unconditionally
+# because not all systems understand e.g. LANG=C (notably SCO).
+# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'!
+# Non-C LC_CTYPE values break the ctype check.
+if test "${LANG+set}" = set; then LANG=C; export LANG; fi
+if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
+if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi
+if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi
+
+# 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
+
+# A filename unique to this package, relative to the directory that
+# configure is in, which we can look for to find out if srcdir is correct.
+ac_unique_file=fitscore.c
+
+# 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_prog=$0
+ ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'`
+ test "x$ac_confdir" = "x$ac_prog" && ac_confdir=.
+ 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 "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; }
+ else
+ { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; }
+ fi
+fi
+srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'`
+
+# 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 "loading site script $ac_site_file"
+ . "$ac_site_file"
+ fi
+done
+
+if test -r "$cache_file"; then
+ echo "loading cache $cache_file"
+ . $cache_file
+else
+ echo "creating cache $cache_file"
+ > $cache_file
+fi
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+ac_exeext=
+ac_objext=o
+if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
+ # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu.
+ if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
+ ac_n= ac_c='
+' ac_t=' '
+ else
+ ac_n=-n ac_c= ac_t=
+ fi
+else
+ ac_n= ac_c='\c' ac_t=
+fi
+
+
+
+#--------------------------------------------------------------------
+# Check "uname" to determine system type
+#--------------------------------------------------------------------
+# Extract the first word of "uname", so it can be a program name with args.
+set dummy uname; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:532: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_uname_found'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$uname_found"; then
+ ac_cv_prog_uname_found="$uname_found" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_uname_found="1"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+ test -z "$ac_cv_prog_uname_found" && ac_cv_prog_uname_found="0"
+fi
+fi
+uname_found="$ac_cv_prog_uname_found"
+if test -n "$uname_found"; then
+ echo "$ac_t""$uname_found" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+if test $uname_found -eq 0 ; then
+ echo "cfitsio: No uname found; setting system type to unknown."
+ system="unknown"
+else
+ system=`uname -s`-`uname -r`
+fi
+
+
+# Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:570: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_CC="gcc"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+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 $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:600: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_prog_rejected=no
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+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 $# -gt 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
+ set dummy "$ac_dir/$ac_word" "$@"
+ shift
+ ac_cv_prog_CC="$@"
+ fi
+fi
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ if test -z "$CC"; then
+ case "`uname -s`" in
+ *win32* | *WIN32*)
+ # Extract the first word of "cl", so it can be a program name with args.
+set dummy cl; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:651: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_CC="cl"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+ ;;
+ esac
+ fi
+ test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; }
+fi
+
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6
+echo "configure:683: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+cat > conftest.$ac_ext << EOF
+
+#line 694 "configure"
+#include "confdefs.h"
+
+main(){return(0);}
+EOF
+if { (eval echo configure:699: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ ac_cv_prog_cc_works=yes
+ # If we can't run a trivial program, we are probably using a cross compiler.
+ if (./conftest; exit) 2>/dev/null; then
+ ac_cv_prog_cc_cross=no
+ else
+ ac_cv_prog_cc_cross=yes
+ fi
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ ac_cv_prog_cc_works=no
+fi
+rm -fr conftest*
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo "$ac_t""$ac_cv_prog_cc_works" 1>&6
+if test $ac_cv_prog_cc_works = no; then
+ { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; }
+fi
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
+echo "configure:725: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
+echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
+echo "configure:730: checking whether we are using GNU C" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.c <<EOF
+#ifdef __GNUC__
+ yes;
+#endif
+EOF
+if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:739: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+ ac_cv_prog_gcc=yes
+else
+ ac_cv_prog_gcc=no
+fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gcc" 1>&6
+
+if test $ac_cv_prog_gcc = yes; then
+ GCC=yes
+else
+ GCC=
+fi
+
+ac_test_CFLAGS="${CFLAGS+set}"
+ac_save_CFLAGS="$CFLAGS"
+CFLAGS=
+echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
+echo "configure:758: checking whether ${CC-cc} accepts -g" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ echo 'void f(){}' > conftest.c
+if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then
+ ac_cv_prog_cc_g=yes
+else
+ ac_cv_prog_cc_g=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_prog_cc_g" 1>&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
+
+
+for ac_prog in f77 xlf cf77 gf77 g77 af77 ncf f2c
+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 $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:795: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_FC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$FC"; then
+ ac_cv_prog_FC="$FC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_FC="$ac_prog"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+fi
+fi
+FC="$ac_cv_prog_FC"
+if test -n "$FC"; then
+ echo "$ac_t""$FC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+test -n "$FC" && break
+done
+test -n "$FC" || FC="nope"
+
+if test $FC = 'nope' ; then
+ echo "configure: warning: cfitsio: == No acceptable f77 found in \$PATH" 1>&2
+ echo "configure: warning: cfitsio: == Cfitsio will be built without Fortran wrapper support" 1>&2
+ FC=
+ F77_WRAPPERS=
+else
+ CFORTRANFLAGS=
+ F77_WRAPPERS="\${FITSIO_SRC}"
+ echo $ac_n "checking whether we are using GNU Fortran""... $ac_c" 1>&6
+ if test `$FC --version -c < /dev/null 2> /dev/null | grep -c GNU` -gt 0 -o \
+ `$FC --version -c < /dev/null 2> /dev/null | grep -ic egcs` -gt 0
+ then
+ echo "$ac_t""yes" 1>&6
+ echo $ac_n "cfitsio: == Adding wrapper support for GNU Fortran""... $ac_c" 1>&6
+ CFORTRANFLAGS="-Dg77Fortran"
+ echo "$ac_t"" done" 1>&6
+ else
+ echo "$ac_t""no" 1>&6
+ if test $FC = 'f2c' ; then
+ echo $ac_n "cfitsio: == Adding wrapper support for f2c""... $ac_c" 1>&6
+ CFORTRANFLAGS="-Df2cFortran"
+ echo "$ac_t"" done" 1>&6
+ fi
+ fi
+fi
+
+# Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:854: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$RANLIB"; then
+ ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_RANLIB="ranlib"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+ test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":"
+fi
+fi
+RANLIB="$ac_cv_prog_RANLIB"
+if test -n "$RANLIB"; then
+ echo "$ac_t""$RANLIB" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+
+echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
+echo "configure:883: checking how to run the C preprocessor" >&5
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ # This must be in double quotes, not single quotes, because CPP may get
+ # substituted into the Makefile and "${CC-cc}" will confuse make.
+ CPP="${CC-cc} -E"
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp.
+ cat > conftest.$ac_ext <<EOF
+#line 898 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:904: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ CPP="${CC-cc} -E -traditional-cpp"
+ cat > conftest.$ac_ext <<EOF
+#line 915 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:921: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ CPP="${CC-cc} -nologo -E"
+ cat > conftest.$ac_ext <<EOF
+#line 932 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:938: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ CPP=/lib/cpp
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+ ac_cv_prog_CPP="$CPP"
+fi
+ CPP="$ac_cv_prog_CPP"
+else
+ ac_cv_prog_CPP="$CPP"
+fi
+echo "$ac_t""$CPP" 1>&6
+
+for ac_hdr in stdlib.h string.h math.h limits.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:966: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 971 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:976: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+ ANSI_HEADER=yes
+else
+ echo "$ac_t""no" 1>&6
+ANSI_HEADER=no
+fi
+done
+
+cat > conftest.$ac_ext <<EOF
+#line 1004 "configure"
+#include "confdefs.h"
+
+int main() {
+void d( int , double)
+; return 0; }
+EOF
+if { (eval echo configure:1011: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ PROTO=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ PROTO=no
+fi
+rm -f conftest*
+if test $ANSI_HEADER = no -o $PROTO = no; then
+ echo " *********** WARNING: CFITSIO CONFIGURE FAILURE ************ "
+ echo "cfitsio: ANSI C environment NOT found. Aborting cfitsio configure."
+ if test $ANSI_HEADER = no; then
+ echo "cfitsio: You're missing a needed ANSI header file."
+ fi
+ if test $PROTO = no; then
+ echo "cfitsio: Your compiler can't do ANSI function prototypes."
+ fi
+ echo "cfitsio: You need an ANSI C compiler and all ANSI trappings"
+ echo "cfitsio: to build cfitsio. "
+ echo " ******************************************************* "
+ exit 0;
+fi
+
+CFLAGS="$CFLAGS"
+LIBPRE=""
+
+case $system in
+ Darwin-*)
+ # Darwin can be powerpc or i386
+ ARCH=`uname -p`
+ EXT="darwin"
+ CFLAGS="$CFLAGS -D_FILE_OFFSET_BITS=64"
+ ;;
+ SunOS-4*)
+ ARCH="sun"
+ EXT="sun"
+ ;;
+ HP-UX-*)
+ ARCH="hp"
+ EXT="hpu"
+ if test "x$CFORTRANFLAGS" = x ; then
+ CFORTRANFLAGS="-Dappendus"
+ fi
+ CFLAGS="$CFLAGS -DPG_PPU"
+ LIBPRE="-Wl,"
+ ;;
+ SunOS-5*)
+ ARCH="solaris"
+ EXT="sol"
+ if test "x$CFORTRANFLAGS" = x ; then
+ CFORTRANFLAGS="-Dsolaris"
+ fi
+ ;;
+ OSF1*)
+ ARCH="alpha"
+ EXT="osf"
+ ;;
+ IRIX*)
+ ARCH="sgi"
+ EXT="sgi"
+ CFLAGS="$CFLAGS -DHAVE_POSIX_SIGNALS"
+ RANLIB="touch"
+ ;;
+ ULTRIX*)
+ ARCH="dec"
+ EXT="dec"
+ ;;
+ Linux*)
+ ARCH="linux"
+ EXT="lnx"
+ ;;
+ FREEBSD*|FreeBSD*)
+ ARCH="linux"
+ EXT="lnx"
+ ;;
+ CYGWIN*)
+ ARCH="cygwin"
+ EXT="cygwin"
+ CFLAGS="$CFLAGS -DHAVE_POSIX_SIGNALS"
+ ;;
+ *)
+ echo "cfitsio: == Don't know what do do with $system"
+ ;;
+esac
+
+CFLAGS="$CFLAGS $CFORTRANFLAGS"
+
+case $CC in
+ gcc)
+ GCCVERSION="`gcc -v 2>&1 | grep version`"
+ echo "cfitsio: == Using $GCCVERSION"
+
+
+ if test `echo $GCCVERSION | grep -c 'version 2\.[45678]\.'` -gt 0
+ then
+ CFLAGS=`echo $CFLAGS | sed 's:-O[^ ]* *::'`
+ echo "configure: warning: This gcc is pretty old. Disabling optimization to be safe." 1>&2
+ fi
+
+ ;;
+ cc)
+ echo "cfitsio: Old CFLAGS is $CFLAGS"
+ CFLAGS=`echo $CFLAGS | sed -e "s/-g/-O/"`
+ case $system in
+ SunOS-5*)
+ CFLAGS="$CFLAGS -DHAVE_ALLOCA_H -DHAVE_POSIX_SIGNALS"
+ ;;
+ *)
+ echo "== No special changes for $system"
+ ;;
+ esac
+ echo "New CFLAGS is $CFLAGS"
+ ;;
+ *)
+ # Don't do anything now
+ ;;
+esac
+
+# Shared library section
+#-------------------------------------------------------------------------------
+SHLIB_LD=:
+SHLIB_SUFFIX=".so"
+lhea_shlib_cflags=
+case $EXT in
+ darwin)
+ SHLIB_LD="cc -dynamiclib"
+ SHLIB_SUFFIX=".dylib"
+ lhea_shlib_cflags="-fPIC -fno-common"
+ ;;
+ hpu)
+ SHLIB_LD="ld -b"
+ SHLIB_SUFFIX=".sl"
+ ;;
+ lnx|cygwin)
+ SHLIB_LD=":"
+ ;;
+ osf)
+ SHLIB_LD="ld -shared -expect_unresolved '*'"
+ LD_FLAGS="-taso"
+ ;;
+ sol)
+ SHLIB_LD="/usr/ccs/bin/ld -G"
+ lhea_shlib_cflags="-KPIC"
+ ;;
+ sgi)
+ SHLIB_LD="ld -shared -rdata_shared"
+ ;;
+ *)
+ echo "configure: warning: Unable to determine how to make a shared library" 1>&2
+ ;;
+esac
+# Darwin uses gcc (=cc), but needs different flags (see above)
+# if test "x$GCC" = xyes; then
+if test "x$GCC" = xyes && test "x$EXT" != xdarwin; then
+ SHLIB_LD="$CC -shared"
+ lhea_shlib_cflags='-fPIC'
+fi
+if test "x$lhea_shlib_cflags" != x; then
+ CFLAGS="$CFLAGS $lhea_shlib_cflags"
+fi
+
+
+
+# ================= test for the unix ftruncate function ================
+
+echo $ac_n "checking "whether ftruncate works"""... $ac_c" 1>&6
+echo "configure:1179: checking "whether ftruncate works"" >&5
+cat > conftest.$ac_ext <<EOF
+#line 1181 "configure"
+#include "confdefs.h"
+#include <unistd.h>
+
+int main() {
+
+ftruncate(0, 0);
+
+; return 0; }
+EOF
+if { (eval echo configure:1191: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+
+cat >> confdefs.h <<\EOF
+#define HAVE_FTRUNCATE 1
+EOF
+
+echo "$ac_t"""yes"" 1>&6
+
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ echo "$ac_t"""no"" 1>&6
+fi
+rm -f conftest*
+
+# ---------------------------------------------------------
+# some systems define long long for 64-bit ints
+# ---------------------------------------------------------
+
+echo $ac_n "checking "whether long long is defined"""... $ac_c" 1>&6
+echo "configure:1213: checking "whether long long is defined"" >&5
+cat > conftest.$ac_ext <<EOF
+#line 1215 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+
+int main() {
+
+long long filler;
+
+; return 0; }
+EOF
+if { (eval echo configure:1225: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+
+cat >> confdefs.h <<\EOF
+#define HAVE_LONGLONG 1
+EOF
+
+echo "$ac_t"""yes"" 1>&6
+
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ echo "$ac_t"""no"" 1>&6
+fi
+rm -f conftest*
+
+# ==================== SHARED MEMORY DRIVER SECTION =======================
+#
+# 09-Mar-98 : modified by JB/ISDC
+# 3 checks added to support autoconfiguration of shared memory
+# driver. First generic check is made whether shared memory is supported
+# at all, then 2 more specific checks are made (architecture dependent).
+# Currently tested on : sparc-solaris, intel-linux, sgi-irix, dec-alpha-osf
+
+# -------------------------------------------------------------------------
+# check is System V IPC is supported on this machine
+# -------------------------------------------------------------------------
+
+echo $ac_n "checking "whether system V style IPC services are supported"""... $ac_c" 1>&6
+echo "configure:1255: checking "whether system V style IPC services are supported"" >&5
+cat > conftest.$ac_ext <<EOF
+#line 1257 "configure"
+#include "confdefs.h"
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/sem.h>
+
+int main() {
+
+shmat(0, 0, 0);
+shmdt(0);
+shmget(0, 0, 0);
+semget(0, 0, 0);
+
+; return 0; }
+EOF
+if { (eval echo configure:1272: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+
+cat >> confdefs.h <<\EOF
+#define HAVE_SHMEM_SERVICES 1
+EOF
+
+my_shmem=\${SOURCES_SHMEM}
+echo "$ac_t"""yes"" 1>&6
+
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ echo "$ac_t"""no"" 1>&6
+fi
+rm -f conftest*
+
+
+
+# -------------------------------------------------------------------------
+# some systems define flock_t, for others we have to define it ourselves
+# -------------------------------------------------------------------------
+
+echo $ac_n "checking "do we have flock_t defined"""... $ac_c" 1>&6
+echo "configure:1297: checking "do we have flock_t defined"" >&5
+cat > conftest.$ac_ext <<EOF
+#line 1299 "configure"
+#include "confdefs.h"
+#include <sys/fcntl.h>
+
+int main() {
+
+flock_t filler;
+
+; return 0; }
+EOF
+if { (eval echo configure:1309: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+
+cat >> confdefs.h <<\EOF
+#define HAVE_FLOCK_T 1
+EOF
+
+echo "$ac_t"""yes"" 1>&6
+
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ echo "$ac_t"""no"" 1>&6
+fi
+rm -f conftest*
+
+
+# -------------------------------------------------------------------------
+# there are some idiosyncrasies with semun defs (used in semxxx). Solaris
+# does not define it at all
+# -------------------------------------------------------------------------
+
+echo $ac_n "checking "do we have union semun defined"""... $ac_c" 1>&6
+echo "configure:1333: checking "do we have union semun defined"" >&5
+cat > conftest.$ac_ext <<EOF
+#line 1335 "configure"
+#include "confdefs.h"
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/sem.h>
+
+int main() {
+
+union semun filler;
+
+; return 0; }
+EOF
+if { (eval echo configure:1347: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+
+cat >> confdefs.h <<\EOF
+#define HAVE_UNION_SEMUN 1
+EOF
+
+echo "$ac_t"""yes"" 1>&6
+
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ echo "$ac_t"""no"" 1>&6
+fi
+rm -f conftest*
+
+# ==================== END OF SHARED MEMORY DRIVER SECTION ================
+# ================= test for the unix networking functions ================
+
+#--------------------------------------------------------------------
+# Check for the existence of the -lsocket and -lnsl libraries.
+# The order here is important, so that they end up in the right
+# order in the command line generated by make. Here are some
+# special considerations:
+# 1. Use "connect" and "accept" to check for -lsocket, and
+# "gethostbyname" to check for -lnsl.
+# 2. Use each function name only once: can't redo a check because
+# autoconf caches the results of the last check and won't redo it.
+# 3. Use -lnsl and -lsocket only if they supply procedures that
+# aren't already present in the normal libraries. This is because
+# IRIX 5.2 has libraries, but they aren't needed and they're
+# bogus: they goof up name resolution if used.
+# 4. On some SVR4 systems, can't use -lsocket without -lnsl too.
+# To get around this problem, check for both libraries together
+# if -lsocket doesn't work by itself.
+#--------------------------------------------------------------------
+cfitsio_checkBoth=0
+echo $ac_n "checking for connect""... $ac_c" 1>&6
+echo "configure:1386: checking for connect" >&5
+if eval "test \"`echo '$''{'ac_cv_func_connect'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1391 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char connect(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* 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() {
+
+/* 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
+connect();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:1414: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_connect=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_connect=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'connect`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ cfitsio_checkSocket=0
+else
+ echo "$ac_t""no" 1>&6
+cfitsio_checkSocket=1
+fi
+
+if test "$cfitsio_checkSocket" = 1; then
+ echo $ac_n "checking for main in -lsocket""... $ac_c" 1>&6
+echo "configure:1436: checking for main in -lsocket" >&5
+ac_lib_var=`echo socket'_'main | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lsocket $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1444 "configure"
+#include "confdefs.h"
+
+int main() {
+main()
+; return 0; }
+EOF
+if { (eval echo configure:1451: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ LIBS="$LIBS -lsocket"
+else
+ echo "$ac_t""no" 1>&6
+cfitsio_checkBoth=1
+fi
+
+fi
+if test "$cfitsio_checkBoth" = 1; then
+ tk_oldLibs=$LIBS
+ LIBS="$LIBS -lsocket -lnsl"
+ echo $ac_n "checking for accept""... $ac_c" 1>&6
+echo "configure:1477: checking for accept" >&5
+if eval "test \"`echo '$''{'ac_cv_func_accept'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1482 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char accept(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char accept();
+
+int main() {
+
+/* 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_accept) || defined (__stub___accept)
+choke me
+#else
+accept();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:1505: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_accept=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_accept=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'accept`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ cfitsio_checkNsl=0
+else
+ echo "$ac_t""no" 1>&6
+LIBS=$tk_oldLibs
+fi
+
+fi
+echo $ac_n "checking for gethostbyname""... $ac_c" 1>&6
+echo "configure:1527: checking for gethostbyname" >&5
+if eval "test \"`echo '$''{'ac_cv_func_gethostbyname'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1532 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char gethostbyname(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* 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() {
+
+/* 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
+gethostbyname();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:1555: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_gethostbyname=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_gethostbyname=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'gethostbyname`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ :
+else
+ echo "$ac_t""no" 1>&6
+echo $ac_n "checking for main in -lnsl""... $ac_c" 1>&6
+echo "configure:1573: checking for main in -lnsl" >&5
+ac_lib_var=`echo nsl'_'main | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lnsl $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1581 "configure"
+#include "confdefs.h"
+
+int main() {
+main()
+; return 0; }
+EOF
+if { (eval echo configure:1588: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ LIBS="$LIBS -lnsl"
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+
+cat >> confdefs.h <<\EOF
+#define HAVE_NET_SERVICES 1
+EOF
+
+
+# ==================== END OF unix networking SECTION ================
+
+
+trap '' 1 2 15
+cat > confcache <<\EOF
+# 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. It is not useful on other systems.
+# If it contains results you don't want to keep, you may remove or edit it.
+#
+# By default, configure uses ./config.cache as the cache file,
+# creating it if it does not exist already. You can give configure
+# the --cache-file=FILE option to use a different cache file; that is
+# what configure does when it calls configure scripts in
+# subdirectories, so they share the cache.
+# Giving --cache-file=/dev/null disables caching, for debugging configure.
+# config.status only pays attention to the cache file if you give it the
+# --recheck option to rerun configure.
+#
+EOF
+# 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 \
+ -e "s/'/'\\\\''/g" \
+ -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p"
+ ;;
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p'
+ ;;
+ esac >> confcache
+if cmp -s $cache_file confcache; then
+ :
+else
+ if test -w $cache_file; then
+ echo "updating cache $cache_file"
+ cat confcache > $cache_file
+ else
+ echo "not updating unwritable cache $cache_file"
+ fi
+fi
+rm -f confcache
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Any assignment to VPATH causes Sun make to only execute
+# the first set of double-colon rules, so remove it if not needed.
+# If there is a colon in the path, we need to keep it.
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d'
+fi
+
+trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15
+
+# Transform confdefs.h into DEFS.
+# Protect against shell expansion while executing Makefile rules.
+# Protect against Makefile macro expansion.
+cat > conftest.defs <<\EOF
+s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%-D\1=\2%g
+s%[ `~#$^&*(){}\\|;'"<>?]%\\&%g
+s%\[%\\&%g
+s%\]%\\&%g
+s%\$%$$%g
+EOF
+DEFS=`sed -f conftest.defs confdefs.h | tr '\012' ' '`
+rm -f conftest.defs
+
+
+# Without the "./", some shells look in PATH for config.status.
+: ${CONFIG_STATUS=./config.status}
+
+echo creating $CONFIG_STATUS
+rm -f $CONFIG_STATUS
+cat > $CONFIG_STATUS <<EOF
+#! /bin/sh
+# Generated automatically by configure.
+# Run this file to recreate the current configuration.
+# This directory was configured as follows,
+# on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+#
+# $0 $ac_configure_args
+#
+# Compiler output produced by configure, useful for debugging
+# configure, is in ./config.log if it exists.
+
+ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]"
+for ac_option
+do
+ case "\$ac_option" in
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion"
+ exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;;
+ -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
+ echo "$CONFIG_STATUS generated by autoconf version 2.13"
+ exit 0 ;;
+ -help | --help | --hel | --he | --h)
+ echo "\$ac_cs_usage"; exit 0 ;;
+ *) echo "\$ac_cs_usage"; exit 1 ;;
+ esac
+done
+
+ac_given_srcdir=$srcdir
+
+trap 'rm -fr `echo "Makefile" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+# Protect against being on the right side of a sed subst in config.status.
+sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g;
+ s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF
+$ac_vpsub
+$extrasub
+s%@SHELL@%$SHELL%g
+s%@CFLAGS@%$CFLAGS%g
+s%@CPPFLAGS@%$CPPFLAGS%g
+s%@CXXFLAGS@%$CXXFLAGS%g
+s%@FFLAGS@%$FFLAGS%g
+s%@DEFS@%$DEFS%g
+s%@LDFLAGS@%$LDFLAGS%g
+s%@LIBS@%$LIBS%g
+s%@exec_prefix@%$exec_prefix%g
+s%@prefix@%$prefix%g
+s%@program_transform_name@%$program_transform_name%g
+s%@bindir@%$bindir%g
+s%@sbindir@%$sbindir%g
+s%@libexecdir@%$libexecdir%g
+s%@datadir@%$datadir%g
+s%@sysconfdir@%$sysconfdir%g
+s%@sharedstatedir@%$sharedstatedir%g
+s%@localstatedir@%$localstatedir%g
+s%@libdir@%$libdir%g
+s%@includedir@%$includedir%g
+s%@oldincludedir@%$oldincludedir%g
+s%@infodir@%$infodir%g
+s%@mandir@%$mandir%g
+s%@uname_found@%$uname_found%g
+s%@CC@%$CC%g
+s%@FC@%$FC%g
+s%@RANLIB@%$RANLIB%g
+s%@CPP@%$CPP%g
+s%@GCCVERSION@%$GCCVERSION%g
+s%@ARCH@%$ARCH%g
+s%@LIBPRE@%$LIBPRE%g
+s%@SHLIB_LD@%$SHLIB_LD%g
+s%@SHLIB_SUFFIX@%$SHLIB_SUFFIX%g
+s%@F77_WRAPPERS@%$F77_WRAPPERS%g
+s%@my_shmem@%$my_shmem%g
+
+CEOF
+EOF
+
+cat >> $CONFIG_STATUS <<\EOF
+
+# 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_cmds=90 # Maximum number of lines to put in a sed script.
+ac_file=1 # Number of current file.
+ac_beg=1 # First line for current file.
+ac_end=$ac_max_sed_cmds # 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" conftest.subs > conftest.s$ac_file
+ else
+ sed "${ac_end}q" conftest.subs > conftest.s$ac_file
+ fi
+ if test ! -s conftest.s$ac_file; then
+ ac_more_lines=false
+ rm -f conftest.s$ac_file
+ else
+ if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds="sed -f conftest.s$ac_file"
+ else
+ ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file"
+ fi
+ ac_file=`expr $ac_file + 1`
+ ac_beg=$ac_end
+ ac_end=`expr $ac_end + $ac_max_sed_cmds`
+ fi
+done
+if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds=cat
+fi
+EOF
+
+cat >> $CONFIG_STATUS <<EOF
+
+CONFIG_FILES=\${CONFIG_FILES-"Makefile"}
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case "$ac_file" in
+ *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+ ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+ *) ac_file_in="${ac_file}.in" ;;
+ esac
+
+ # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories.
+
+ # Remove last slash and all that follows it. Not all systems have dirname.
+ ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+ if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+ # The file is in a subdirectory.
+ test ! -d "$ac_dir" && mkdir "$ac_dir"
+ ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`"
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
+ else
+ ac_dir_suffix= ac_dots=
+ fi
+
+ case "$ac_given_srcdir" in
+ .) srcdir=.
+ if test -z "$ac_dots"; then top_srcdir=.
+ else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
+ /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
+ *) # Relative path.
+ srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
+ top_srcdir="$ac_dots$ac_given_srcdir" ;;
+ esac
+
+
+ echo creating "$ac_file"
+ rm -f "$ac_file"
+ configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
+ case "$ac_file" in
+ *Makefile*) ac_comsub="1i\\
+# $configure_input" ;;
+ *) ac_comsub= ;;
+ esac
+
+ ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+ sed -e "$ac_comsub
+s%@configure_input@%$configure_input%g
+s%@srcdir@%$srcdir%g
+s%@top_srcdir@%$top_srcdir%g
+" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file
+fi; done
+rm -f conftest.s*
+
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+
+exit 0
+EOF
+chmod +x $CONFIG_STATUS
+rm -fr confdefs* $ac_clean_files
+test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1
+
+
+echo "$ac_t""" 1>&6
+echo "$ac_t"" Congratulations, Makefile update was successful." 1>&6
+echo "$ac_t"" You may want to run \"make\" now." 1>&6
+echo "$ac_t""" 1>&6
+
diff --git a/pkg/tbtables/cfitsio/configure.in b/pkg/tbtables/cfitsio/configure.in
new file mode 100644
index 00000000..5bbd92dc
--- /dev/null
+++ b/pkg/tbtables/cfitsio/configure.in
@@ -0,0 +1,352 @@
+#
+# configure.in for cfitsio
+#
+# /redshift/sgi6/lheavc/ftools/cfitsio/configure.in,v 3.4 1996/07/26 20:27:53 pence Exp
+#
+# copied from host and modified
+#
+
+dnl Process this file with autoconf to produce a configure script.
+AC_INIT(fitscore.c)
+
+#--------------------------------------------------------------------
+# Check "uname" to determine system type
+#--------------------------------------------------------------------
+AC_PROGRAM_CHECK(uname_found, uname, 1, 0)
+if test $uname_found -eq 0 ; then
+ echo "cfitsio: No uname found; setting system type to unknown."
+ system="unknown"
+else
+ system=`uname -s`-`uname -r`
+fi
+
+
+dnl Checks for programs.
+AC_PROG_CC
+
+AC_CHECK_PROGS(FC, f77 xlf cf77 gf77 g77 af77 ncf f2c , nope)
+if test $FC = 'nope' ; then
+ AC_MSG_WARN(cfitsio: == No acceptable f77 found in \$PATH)
+ AC_MSG_WARN(cfitsio: == Cfitsio will be built without Fortran wrapper support)
+ FC=
+ F77_WRAPPERS=
+else
+ CFORTRANFLAGS=
+ F77_WRAPPERS="\${FITSIO_SRC}"
+ echo $ac_n "checking whether we are using GNU Fortran""... $ac_c" 1>&6
+ if test `$FC --version -c < /dev/null 2> /dev/null | grep -c GNU` -gt 0 -o \
+ `$FC --version -c < /dev/null 2> /dev/null | grep -ic egcs` -gt 0
+ then
+ echo "$ac_t""yes" 1>&6
+ echo $ac_n "cfitsio: == Adding wrapper support for GNU Fortran""... $ac_c" 1>&6
+ CFORTRANFLAGS="-Dg77Fortran"
+ echo "$ac_t"" done" 1>&6
+ else
+ echo "$ac_t""no" 1>&6
+ if test $FC = 'f2c' ; then
+ echo $ac_n "cfitsio: == Adding wrapper support for f2c""... $ac_c" 1>&6
+ CFORTRANFLAGS="-Df2cFortran"
+ echo "$ac_t"" done" 1>&6
+ fi
+ fi
+fi
+
+AC_PROG_RANLIB
+
+dnl Checks for ANSI stdlib.h.
+AC_CHECK_HEADERS(stdlib.h string.h math.h limits.h ,ANSI_HEADER=yes,ANSI_HEADER=no)dnl
+
+dnl Check if prototyping is allowed.
+AC_TRY_COMPILE( , void d( int , double) , PROTO=yes, PROTO=no)dnl
+
+if test $ANSI_HEADER = no -o $PROTO = no; then
+ echo " *********** WARNING: CFITSIO CONFIGURE FAILURE ************ "
+ echo "cfitsio: ANSI C environment NOT found. Aborting cfitsio configure."
+ if test $ANSI_HEADER = no; then
+ echo "cfitsio: You're missing a needed ANSI header file."
+ fi
+ if test $PROTO = no; then
+ echo "cfitsio: Your compiler can't do ANSI function prototypes."
+ fi
+ echo "cfitsio: You need an ANSI C compiler and all ANSI trappings"
+ echo "cfitsio: to build cfitsio. "
+ echo " ******************************************************* "
+ exit 0;
+fi
+
+CFLAGS="$CFLAGS"
+LIBPRE=""
+
+case $system in
+ Darwin-*)
+ # Darwin can be powerpc or i386
+ ARCH=`uname -p`
+ EXT="darwin"
+ CFLAGS="$CFLAGS -D_FILE_OFFSET_BITS=64"
+ ;;
+ SunOS-4*)
+ ARCH="sun"
+ EXT="sun"
+ ;;
+ HP-UX-*)
+ ARCH="hp"
+ EXT="hpu"
+ if test "x$CFORTRANFLAGS" = x ; then
+ CFORTRANFLAGS="-Dappendus"
+ fi
+ CFLAGS="$CFLAGS -DPG_PPU"
+ LIBPRE="-Wl,"
+ ;;
+ SunOS-5*)
+ ARCH="solaris"
+ EXT="sol"
+ if test "x$CFORTRANFLAGS" = x ; then
+ CFORTRANFLAGS="-Dsolaris"
+ fi
+ ;;
+ OSF1*)
+ ARCH="alpha"
+ EXT="osf"
+ ;;
+ IRIX*)
+ ARCH="sgi"
+ EXT="sgi"
+ CFLAGS="$CFLAGS -DHAVE_POSIX_SIGNALS"
+ RANLIB="touch"
+ ;;
+ ULTRIX*)
+ ARCH="dec"
+ EXT="dec"
+ ;;
+ Linux*)
+ ARCH="linux"
+ EXT="lnx"
+ ;;
+ FREEBSD*|FreeBSD*)
+ ARCH="linux"
+ EXT="lnx"
+ ;;
+ CYGWIN*)
+ ARCH="cygwin"
+ EXT="cygwin"
+ CFLAGS="$CFLAGS -DHAVE_POSIX_SIGNALS"
+ ;;
+ *)
+ echo "cfitsio: == Don't know what do do with $system"
+ ;;
+esac
+
+CFLAGS="$CFLAGS $CFORTRANFLAGS"
+
+case $CC in
+ gcc)
+ GCCVERSION="`gcc -v 2>&1 | grep version`"
+ echo "cfitsio: == Using $GCCVERSION"
+ AC_SUBST(GCCVERSION)
+ changequote(,)
+ if test `echo $GCCVERSION | grep -c 'version 2\.[45678]\.'` -gt 0
+ then
+ CFLAGS=`echo $CFLAGS | sed 's:-O[^ ]* *::'`
+ AC_MSG_WARN(This gcc is pretty old. Disabling optimization to be safe.)
+ fi
+ changequote([,])
+ ;;
+ cc)
+ echo "cfitsio: Old CFLAGS is $CFLAGS"
+ CFLAGS=`echo $CFLAGS | sed -e "s/-g/-O/"`
+ case $system in
+ SunOS-5*)
+ CFLAGS="$CFLAGS -DHAVE_ALLOCA_H -DHAVE_POSIX_SIGNALS"
+ ;;
+ *)
+ echo "== No special changes for $system"
+ ;;
+ esac
+ echo "New CFLAGS is $CFLAGS"
+ ;;
+ *)
+ # Don't do anything now
+ ;;
+esac
+
+# Shared library section
+#-------------------------------------------------------------------------------
+SHLIB_LD=:
+SHLIB_SUFFIX=".so"
+lhea_shlib_cflags=
+case $EXT in
+ darwin)
+ SHLIB_LD="cc -dynamiclib"
+ SHLIB_SUFFIX=".dylib"
+ lhea_shlib_cflags="-fPIC -fno-common"
+ ;;
+ hpu)
+ SHLIB_LD="ld -b"
+ SHLIB_SUFFIX=".sl"
+ ;;
+ lnx|cygwin)
+ SHLIB_LD=":"
+ ;;
+ osf)
+ SHLIB_LD="ld -shared -expect_unresolved '*'"
+ LD_FLAGS="-taso"
+ ;;
+ sol)
+ SHLIB_LD="/usr/ccs/bin/ld -G"
+ lhea_shlib_cflags="-KPIC"
+ ;;
+ sgi)
+ SHLIB_LD="ld -shared -rdata_shared"
+ ;;
+ *)
+ AC_MSG_WARN(Unable to determine how to make a shared library)
+ ;;
+esac
+# Darwin uses gcc (=cc), but needs different flags (see above)
+# if test "x$GCC" = xyes; then
+if test "x$GCC" = xyes && test "x$EXT" != xdarwin; then
+ SHLIB_LD="$CC -shared"
+ lhea_shlib_cflags='-fPIC'
+fi
+if test "x$lhea_shlib_cflags" != x; then
+ CFLAGS="$CFLAGS $lhea_shlib_cflags"
+fi
+
+AC_SUBST(ARCH)dnl
+AC_SUBST(CFLAGS)dnl
+AC_SUBST(CC)dnl
+AC_SUBST(FC)dnl
+AC_SUBST(LIBPRE)dnl
+AC_SUBST(SHLIB_LD)dnl
+AC_SUBST(SHLIB_SUFFIX)dnl
+AC_SUBST(F77_WRAPPERS)
+
+# ================= test for the unix ftruncate function ================
+
+AC_MSG_CHECKING("whether ftruncate works")
+AC_TRY_LINK([#include <unistd.h>
+], [
+ftruncate(0, 0);
+], [
+AC_DEFINE(HAVE_FTRUNCATE)
+AC_MSG_RESULT("yes")
+], AC_MSG_RESULT("no") )
+
+# ---------------------------------------------------------
+# some systems define long long for 64-bit ints
+# ---------------------------------------------------------
+
+AC_MSG_CHECKING("whether long long is defined")
+AC_TRY_COMPILE([#include <stdlib.h>
+], [
+long long filler;
+], [
+AC_DEFINE(HAVE_LONGLONG)
+AC_MSG_RESULT("yes")
+], AC_MSG_RESULT("no") )
+
+# ==================== SHARED MEMORY DRIVER SECTION =======================
+#
+# 09-Mar-98 : modified by JB/ISDC
+# 3 checks added to support autoconfiguration of shared memory
+# driver. First generic check is made whether shared memory is supported
+# at all, then 2 more specific checks are made (architecture dependent).
+# Currently tested on : sparc-solaris, intel-linux, sgi-irix, dec-alpha-osf
+
+# -------------------------------------------------------------------------
+# check is System V IPC is supported on this machine
+# -------------------------------------------------------------------------
+
+AC_MSG_CHECKING("whether system V style IPC services are supported")
+AC_TRY_LINK([#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/sem.h>
+], [
+shmat(0, 0, 0);
+shmdt(0);
+shmget(0, 0, 0);
+semget(0, 0, 0);
+], [
+AC_DEFINE(HAVE_SHMEM_SERVICES)
+my_shmem=\${SOURCES_SHMEM}
+AC_MSG_RESULT("yes")
+], AC_MSG_RESULT("no") )
+
+AC_SUBST(my_shmem)
+
+# -------------------------------------------------------------------------
+# some systems define flock_t, for others we have to define it ourselves
+# -------------------------------------------------------------------------
+
+AC_MSG_CHECKING("do we have flock_t defined")
+AC_TRY_COMPILE([#include <sys/fcntl.h>
+], [
+flock_t filler;
+], [
+AC_DEFINE(HAVE_FLOCK_T)
+AC_MSG_RESULT("yes")
+], AC_MSG_RESULT("no") )
+
+
+# -------------------------------------------------------------------------
+# there are some idiosyncrasies with semun defs (used in semxxx). Solaris
+# does not define it at all
+# -------------------------------------------------------------------------
+
+AC_MSG_CHECKING("do we have union semun defined")
+AC_TRY_COMPILE(
+[#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/sem.h>
+], [
+union semun filler;
+], [
+AC_DEFINE(HAVE_UNION_SEMUN)
+AC_MSG_RESULT("yes")
+], AC_MSG_RESULT("no") )
+
+# ==================== END OF SHARED MEMORY DRIVER SECTION ================
+# ================= test for the unix networking functions ================
+
+#--------------------------------------------------------------------
+# Check for the existence of the -lsocket and -lnsl libraries.
+# The order here is important, so that they end up in the right
+# order in the command line generated by make. Here are some
+# special considerations:
+# 1. Use "connect" and "accept" to check for -lsocket, and
+# "gethostbyname" to check for -lnsl.
+# 2. Use each function name only once: can't redo a check because
+# autoconf caches the results of the last check and won't redo it.
+# 3. Use -lnsl and -lsocket only if they supply procedures that
+# aren't already present in the normal libraries. This is because
+# IRIX 5.2 has libraries, but they aren't needed and they're
+# bogus: they goof up name resolution if used.
+# 4. On some SVR4 systems, can't use -lsocket without -lnsl too.
+# To get around this problem, check for both libraries together
+# if -lsocket doesn't work by itself.
+#--------------------------------------------------------------------
+cfitsio_checkBoth=0
+AC_CHECK_FUNC(connect, cfitsio_checkSocket=0, cfitsio_checkSocket=1)
+if test "$cfitsio_checkSocket" = 1; then
+ AC_CHECK_LIB(socket, main, LIBS="$LIBS -lsocket", cfitsio_checkBoth=1)
+fi
+if test "$cfitsio_checkBoth" = 1; then
+ tk_oldLibs=$LIBS
+ LIBS="$LIBS -lsocket -lnsl"
+ AC_CHECK_FUNC(accept, cfitsio_checkNsl=0, [LIBS=$tk_oldLibs])
+fi
+AC_CHECK_FUNC(gethostbyname, , AC_CHECK_LIB(nsl, main, [LIBS="$LIBS -lnsl"]))
+
+AC_DEFINE(HAVE_NET_SERVICES)
+
+# ==================== END OF unix networking SECTION ================
+
+
+AC_OUTPUT(Makefile)dnl
+
+
+AC_MSG_RESULT([])
+AC_MSG_RESULT([ Congratulations, Makefile update was successful.])
+AC_MSG_RESULT([ You may want to run \"make\" now.])
+AC_MSG_RESULT([])
+
diff --git a/pkg/tbtables/cfitsio/cookbook.c b/pkg/tbtables/cfitsio/cookbook.c
new file mode 100644
index 00000000..3b42ac61
--- /dev/null
+++ b/pkg/tbtables/cfitsio/cookbook.c
@@ -0,0 +1,571 @@
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+/*
+ Every program which uses the CFITSIO interface must include the
+ the fitsio.h header file. This contains the prototypes for all
+ the routines and defines the error status values and other symbolic
+ constants used in the interface.
+*/
+#include "fitsio.h"
+
+int main( void );
+void writeimage( void );
+void writeascii( void );
+void writebintable( void );
+void copyhdu( void );
+void selectrows( void );
+void readheader( void );
+void readimage( void );
+void readtable( void );
+void printerror( int status);
+
+int main()
+{
+/*************************************************************************
+ This is a simple main program that calls the following routines:
+
+ writeimage - write a FITS primary array image
+ writeascii - write a FITS ASCII table extension
+ writebintable - write a FITS binary table extension
+ copyhdu - copy a header/data unit from one FITS file to another
+ selectrows - copy selected row from one HDU to another
+ readheader - read and print the header keywords in every extension
+ readimage - read a FITS image and compute the min and max value
+ readtable - read columns of data from ASCII and binary tables
+
+**************************************************************************/
+
+ writeimage();
+ writeascii();
+ writebintable();
+ copyhdu();
+ selectrows();
+ readheader();
+ readimage();
+ readtable();
+
+ printf("\nAll the cfitsio cookbook routines ran successfully.\n");
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+void writeimage( void )
+
+ /******************************************************/
+ /* Create a FITS primary array containing a 2-D image */
+ /******************************************************/
+{
+ fitsfile *fptr; /* pointer to the FITS file, defined in fitsio.h */
+ int status, ii, jj;
+ long fpixel, nelements, exposure;
+ unsigned short *array[200];
+
+ /* initialize FITS image parameters */
+ char filename[] = "atestfil.fit"; /* name for new FITS file */
+ int bitpix = USHORT_IMG; /* 16-bit unsigned short pixel values */
+ long naxis = 2; /* 2-dimensional image */
+ long naxes[2] = { 300, 200 }; /* image is 300 pixels wide by 200 rows */
+
+ /* allocate memory for the whole image */
+ array[0] = (unsigned short *)malloc( naxes[0] * naxes[1]
+ * sizeof( unsigned short ) );
+
+ /* initialize pointers to the start of each row of the image */
+ for( ii=1; ii<naxes[1]; ii++ )
+ array[ii] = array[ii-1] + naxes[0];
+
+ remove(filename); /* Delete old file if it already exists */
+
+ status = 0; /* initialize status before calling fitsio routines */
+
+ if (fits_create_file(&fptr, filename, &status)) /* create new FITS file */
+ printerror( status ); /* call printerror if error occurs */
+
+ /* write the required keywords for the primary array image. */
+ /* Since bitpix = USHORT_IMG, this will cause cfitsio to create */
+ /* a FITS image with BITPIX = 16 (signed short integers) with */
+ /* BSCALE = 1.0 and BZERO = 32768. This is the convention that */
+ /* FITS uses to store unsigned integers. Note that the BSCALE */
+ /* and BZERO keywords will be automatically written by cfitsio */
+ /* in this case. */
+
+ if ( fits_create_img(fptr, bitpix, naxis, naxes, &status) )
+ printerror( status );
+
+ /* initialize the values in the image with a linear ramp function */
+ for (jj = 0; jj < naxes[1]; jj++)
+ { for (ii = 0; ii < naxes[0]; ii++)
+ {
+ array[jj][ii] = ii + jj;
+ }
+ }
+
+ fpixel = 1; /* first pixel to write */
+ nelements = naxes[0] * naxes[1]; /* number of pixels to write */
+
+ /* write the array of unsigned integers to the FITS file */
+ if ( fits_write_img(fptr, TUSHORT, fpixel, nelements, array[0], &status) )
+ printerror( status );
+
+ free( array[0] ); /* free previously allocated memory */
+
+ /* write another optional keyword to the header */
+ /* Note that the ADDRESS of the value is passed in the routine */
+ exposure = 1500.;
+ if ( fits_update_key(fptr, TLONG, "EXPOSURE", &exposure,
+ "Total Exposure Time", &status) )
+ printerror( status );
+
+ if ( fits_close_file(fptr, &status) ) /* close the file */
+ printerror( status );
+
+ return;
+}
+/*--------------------------------------------------------------------------*/
+void writeascii ( void )
+
+ /*******************************************************************/
+ /* Create an ASCII table extension containing 3 columns and 6 rows */
+ /*******************************************************************/
+{
+ fitsfile *fptr; /* pointer to the FITS file, defined in fitsio.h */
+ int status;
+ long firstrow, firstelem;
+
+ int tfields = 3; /* table will have 3 columns */
+ long nrows = 6; /* table will have 6 rows */
+
+ char filename[] = "atestfil.fit"; /* name for new FITS file */
+ char extname[] = "PLANETS_ASCII"; /* extension name */
+
+ /* define the name, datatype, and physical units for the 3 columns */
+ char *ttype[] = { "Planet", "Diameter", "Density" };
+ char *tform[] = { "a8", "I6", "F4.2" };
+ char *tunit[] = { "\0", "km", "g/cm" };
+
+ /* define the name diameter, and density of each planet */
+ char *planet[] = {"Mercury", "Venus", "Earth", "Mars","Jupiter","Saturn"};
+ long diameter[] = {4880, 12112, 12742, 6800, 143000, 121000};
+ float density[] = { 5.1, 5.3, 5.52, 3.94, 1.33, 0.69};
+
+ status=0;
+
+ /* open with write access the FITS file containing a primary array */
+ if ( fits_open_file(&fptr, filename, READWRITE, &status) )
+ printerror( status );
+
+ /* append a new empty ASCII table onto the FITS file */
+ if ( fits_create_tbl( fptr, ASCII_TBL, nrows, tfields, ttype, tform,
+ tunit, extname, &status) )
+ printerror( status );
+
+ firstrow = 1; /* first row in table to write */
+ firstelem = 1; /* first element in row (ignored in ASCII tables) */
+
+ /* write names to the first column (character strings) */
+ /* write diameters to the second column (longs) */
+ /* write density to the third column (floats) */
+
+ fits_write_col(fptr, TSTRING, 1, firstrow, firstelem, nrows, planet,
+ &status);
+ fits_write_col(fptr, TLONG, 2, firstrow, firstelem, nrows, diameter,
+ &status);
+ fits_write_col(fptr, TFLOAT, 3, firstrow, firstelem, nrows, density,
+ &status);
+
+ if ( fits_close_file(fptr, &status) ) /* close the FITS file */
+ printerror( status );
+ return;
+}
+/*--------------------------------------------------------------------------*/
+void writebintable ( void )
+
+ /*******************************************************************/
+ /* Create a binary table extension containing 3 columns and 6 rows */
+ /*******************************************************************/
+{
+ fitsfile *fptr; /* pointer to the FITS file, defined in fitsio.h */
+ int status, hdutype;
+ long firstrow, firstelem;
+
+ int tfields = 3; /* table will have 3 columns */
+ long nrows = 6; /* table will have 6 rows */
+
+ char filename[] = "atestfil.fit"; /* name for new FITS file */
+ char extname[] = "PLANETS_Binary"; /* extension name */
+
+ /* define the name, datatype, and physical units for the 3 columns */
+ char *ttype[] = { "Planet", "Diameter", "Density" };
+ char *tform[] = { "8a", "1J", "1E" };
+ char *tunit[] = { "\0", "km", "g/cm" };
+
+ /* define the name diameter, and density of each planet */
+ char *planet[] = {"Mercury", "Venus", "Earth", "Mars","Jupiter","Saturn"};
+ long diameter[] = {4880, 12112, 12742, 6800, 143000, 121000};
+ float density[] = { 5.1, 5.3, 5.52, 3.94, 1.33, 0.69};
+
+ status=0;
+
+ /* open the FITS file containing a primary array and an ASCII table */
+ if ( fits_open_file(&fptr, filename, READWRITE, &status) )
+ printerror( status );
+
+ if ( fits_movabs_hdu(fptr, 2, &hdutype, &status) ) /* move to 2nd HDU */
+ printerror( status );
+
+ /* append a new empty binary table onto the FITS file */
+ if ( fits_create_tbl( fptr, BINARY_TBL, nrows, tfields, ttype, tform,
+ tunit, extname, &status) )
+ printerror( status );
+
+ firstrow = 1; /* first row in table to write */
+ firstelem = 1; /* first element in row (ignored in ASCII tables) */
+
+ /* write names to the first column (character strings) */
+ /* write diameters to the second column (longs) */
+ /* write density to the third column (floats) */
+
+ fits_write_col(fptr, TSTRING, 1, firstrow, firstelem, nrows, planet,
+ &status);
+ fits_write_col(fptr, TLONG, 2, firstrow, firstelem, nrows, diameter,
+ &status);
+ fits_write_col(fptr, TFLOAT, 3, firstrow, firstelem, nrows, density,
+ &status);
+
+ if ( fits_close_file(fptr, &status) ) /* close the FITS file */
+ printerror( status );
+ return;
+}
+/*--------------------------------------------------------------------------*/
+void copyhdu( void)
+{
+ /********************************************************************/
+ /* copy the 1st and 3rd HDUs from the input file to a new FITS file */
+ /********************************************************************/
+ fitsfile *infptr; /* pointer to the FITS file, defined in fitsio.h */
+ fitsfile *outfptr; /* pointer to the new FITS file */
+
+ char infilename[] = "atestfil.fit"; /* name for existing FITS file */
+ char outfilename[] = "btestfil.fit"; /* name for new FITS file */
+
+ int status, morekeys, hdutype;
+
+ status = 0;
+
+ remove(outfilename); /* Delete old file if it already exists */
+
+ /* open the existing FITS file */
+ if ( fits_open_file(&infptr, infilename, READONLY, &status) )
+ printerror( status );
+
+ if (fits_create_file(&outfptr, outfilename, &status)) /*create FITS file*/
+ printerror( status ); /* call printerror if error occurs */
+
+ /* copy the primary array from the input file to the output file */
+ morekeys = 0; /* don't reserve space for additional keywords */
+ if ( fits_copy_hdu(infptr, outfptr, morekeys, &status) )
+ printerror( status );
+
+ /* move to the 3rd HDU in the input file */
+ if ( fits_movabs_hdu(infptr, 3, &hdutype, &status) )
+ printerror( status );
+
+ /* copy 3rd HDU from the input file to the output file (to 2nd HDU) */
+ if ( fits_copy_hdu(infptr, outfptr, morekeys, &status) )
+ printerror( status );
+
+ if (fits_close_file(outfptr, &status) ||
+ fits_close_file(infptr, &status)) /* close files */
+ printerror( status );
+
+ return;
+}
+/*--------------------------------------------------------------------------*/
+void selectrows( void )
+
+ /*********************************************************************/
+ /* select rows from an input table and copy them to the output table */
+ /*********************************************************************/
+{
+ fitsfile *infptr, *outfptr; /* pointer to input and output FITS files */
+ unsigned char *buffer;
+ char card[FLEN_CARD];
+ int status, hdutype, nkeys, keypos, nfound, colnum, anynulls, ii;
+ long naxes[2], frow, felem, noutrows, irow;
+ float nullval, density[6];
+
+ char infilename[] = "atestfil.fit"; /* name for existing FITS file */
+ char outfilename[] = "btestfil.fit"; /* name for new FITS file */
+
+ status = 0;
+
+ /* open the existing FITS files */
+ if ( fits_open_file(&infptr, infilename, READONLY, &status) ||
+ fits_open_file(&outfptr, outfilename, READWRITE, &status) )
+ printerror( status );
+
+ /* move to the 3rd HDU in the input file (a binary table in this case) */
+ if ( fits_movabs_hdu(infptr, 3, &hdutype, &status) )
+ printerror( status );
+
+ if (hdutype != BINARY_TBL) {
+ printf("Error: expected to find a binary table in this HDU\n");
+ return;
+ }
+ /* move to the last (2rd) HDU in the output file */
+ if ( fits_movabs_hdu(outfptr, 2, &hdutype, &status) )
+ printerror( status );
+
+ /* create new extension in the output file */
+ if ( fits_create_hdu(outfptr, &status) )
+ printerror( status );
+
+ /* get number of keywords */
+ if ( fits_get_hdrpos(infptr, &nkeys, &keypos, &status) )
+ printerror( status );
+
+ /* copy all the keywords from the input to the output extension */
+ for (ii = 1; ii <= nkeys; ii++) {
+ fits_read_record (infptr, ii, card, &status);
+ fits_write_record(outfptr, card, &status);
+ }
+
+ /* read the NAXIS1 and NAXIS2 keyword to get table size */
+ if (fits_read_keys_lng(infptr, "NAXIS", 1, 2, naxes, &nfound, &status) )
+ printerror( status );
+
+ /* find which column contains the DENSITY values */
+ if ( fits_get_colnum(infptr, CASEINSEN, "density", &colnum, &status) )
+ printerror( status );
+
+ /* read the DENSITY column values */
+ frow = 1;
+ felem = 1;
+ nullval = -99.;
+ if (fits_read_col(infptr, TFLOAT, colnum, frow, felem, naxes[1],
+ &nullval, density, &anynulls, &status) )
+ printerror( status );
+
+ /* allocate buffer large enough for 1 row of the table */
+ buffer = (unsigned char *) malloc(naxes[0]);
+
+ /* If the density is less than 3.0, copy the row to the output table */
+ for (noutrows = 0, irow = 1; irow <= naxes[1]; irow++) {
+ if (density[irow - 1] < 3.0) {
+ noutrows++;
+ fits_read_tblbytes( infptr, irow, 1, naxes[0], buffer, &status);
+ fits_write_tblbytes(outfptr, noutrows, 1, naxes[0], buffer, &status);
+ } }
+
+ /* update the NAXIS2 keyword with the correct number of rows */
+ if ( fits_update_key(outfptr, TLONG, "NAXIS2", &noutrows, 0, &status) )
+ printerror( status );
+
+ if (fits_close_file(outfptr, &status) || fits_close_file(infptr, &status))
+ printerror( status );
+
+ return;
+}
+/*--------------------------------------------------------------------------*/
+void readheader ( void )
+
+ /**********************************************************************/
+ /* Print out all the header keywords in all extensions of a FITS file */
+ /**********************************************************************/
+{
+ fitsfile *fptr; /* pointer to the FITS file, defined in fitsio.h */
+
+ int status, nkeys, keypos, hdutype, ii, jj;
+ char filename[] = "atestfil.fit"; /* name of existing FITS file */
+ char card[FLEN_CARD]; /* standard string lengths defined in fitsioc.h */
+
+ status = 0;
+
+ if ( fits_open_file(&fptr, filename, READONLY, &status) )
+ printerror( status );
+
+ /* attempt to move to next HDU, until we get an EOF error */
+ for (ii = 1; !(fits_movabs_hdu(fptr, ii, &hdutype, &status) ); ii++)
+ {
+ /* get no. of keywords */
+ if (fits_get_hdrpos(fptr, &nkeys, &keypos, &status) )
+ printerror( status );
+
+ printf("Header listing for HDU #%d:\n", ii);
+ for (jj = 1; jj <= nkeys; jj++) {
+ if ( fits_read_record(fptr, jj, card, &status) )
+ printerror( status );
+
+ printf("%s\n", card); /* print the keyword card */
+ }
+ printf("END\n\n"); /* terminate listing with END */
+ }
+
+ if (status == END_OF_FILE) /* status values are defined in fitsioc.h */
+ status = 0; /* got the expected EOF error; reset = 0 */
+ else
+ printerror( status ); /* got an unexpected error */
+
+ if ( fits_close_file(fptr, &status) )
+ printerror( status );
+
+ return;
+}
+/*--------------------------------------------------------------------------*/
+void readimage( void )
+
+ /************************************************************************/
+ /* Read a FITS image and determine the minimum and maximum pixel values */
+ /************************************************************************/
+{
+ fitsfile *fptr; /* pointer to the FITS file, defined in fitsio.h */
+ int status, nfound, anynull;
+ long naxes[2], fpixel, nbuffer, npixels, ii;
+
+#define buffsize 1000
+ float datamin, datamax, nullval, buffer[buffsize];
+ char filename[] = "atestfil.fit"; /* name of existing FITS file */
+
+ status = 0;
+
+ if ( fits_open_file(&fptr, filename, READONLY, &status) )
+ printerror( status );
+
+ /* read the NAXIS1 and NAXIS2 keyword to get image size */
+ if ( fits_read_keys_lng(fptr, "NAXIS", 1, 2, naxes, &nfound, &status) )
+ printerror( status );
+
+ npixels = naxes[0] * naxes[1]; /* number of pixels in the image */
+ fpixel = 1;
+ nullval = 0; /* don't check for null values in the image */
+ datamin = 1.0E30;
+ datamax = -1.0E30;
+
+ while (npixels > 0)
+ {
+ nbuffer = npixels;
+ if (npixels > buffsize)
+ nbuffer = buffsize; /* read as many pixels as will fit in buffer */
+
+ /* Note that even though the FITS images contains unsigned integer */
+ /* pixel values (or more accurately, signed integer pixels with */
+ /* a bias of 32768), this routine is reading the values into a */
+ /* float array. Cfitsio automatically performs the datatype */
+ /* conversion in cases like this. */
+
+ if ( fits_read_img(fptr, TFLOAT, fpixel, nbuffer, &nullval,
+ buffer, &anynull, &status) )
+ printerror( status );
+
+ for (ii = 0; ii < nbuffer; ii++) {
+ if ( buffer[ii] < datamin )
+ datamin = buffer[ii];
+
+ if ( buffer[ii] > datamax )
+ datamax = buffer[ii];
+ }
+ npixels -= nbuffer; /* increment remaining number of pixels */
+ fpixel += nbuffer; /* next pixel to be read in image */
+ }
+
+ printf("\nMin and max image pixels = %.0f, %.0f\n", datamin, datamax);
+
+ if ( fits_close_file(fptr, &status) )
+ printerror( status );
+
+ return;
+}
+/*--------------------------------------------------------------------------*/
+void readtable( void )
+
+ /************************************************************/
+ /* read and print data values from an ASCII or binary table */
+ /************************************************************/
+{
+ fitsfile *fptr; /* pointer to the FITS file, defined in fitsio.h */
+ int status, hdunum, hdutype, nfound, anynull, ii;
+ long frow, felem, nelem, longnull, dia[6];
+ float floatnull, den[6];
+ char strnull[10], *name[6], *ttype[3];
+
+ char filename[] = "atestfil.fit"; /* name of existing FITS file */
+
+ status = 0;
+
+ if ( fits_open_file(&fptr, filename, READONLY, &status) )
+ printerror( status );
+
+ for (ii = 0; ii < 3; ii++) /* allocate space for the column labels */
+ ttype[ii] = (char *) malloc(FLEN_VALUE); /* max label length = 69 */
+
+ for (ii = 0; ii < 6; ii++) /* allocate space for string column value */
+ name[ii] = (char *) malloc(10);
+
+ for (hdunum = 2; hdunum <= 3; hdunum++) /*read ASCII, then binary table */
+ {
+ /* move to the HDU */
+ if ( fits_movabs_hdu(fptr, hdunum, &hdutype, &status) )
+ printerror( status );
+
+ if (hdutype == ASCII_TBL)
+ printf("\nReading ASCII table in HDU %d:\n", hdunum);
+ else if (hdutype == BINARY_TBL)
+ printf("\nReading binary table in HDU %d:\n", hdunum);
+ else
+ {
+ printf("Error: this HDU is not an ASCII or binary table\n");
+ printerror( status );
+ }
+
+ /* read the column names from the TTYPEn keywords */
+ fits_read_keys_str(fptr, "TTYPE", 1, 3, ttype, &nfound, &status);
+
+ printf(" Row %10s %10s %10s\n", ttype[0], ttype[1], ttype[2]);
+
+ frow = 1;
+ felem = 1;
+ nelem = 6;
+ strcpy(strnull, " ");
+ longnull = 0;
+ floatnull = 0.;
+
+ /* read the columns */
+ fits_read_col(fptr, TSTRING, 1, frow, felem, nelem, strnull, name,
+ &anynull, &status);
+ fits_read_col(fptr, TLONG, 2, frow, felem, nelem, &longnull, dia,
+ &anynull, &status);
+ fits_read_col(fptr, TFLOAT, 3, frow, felem, nelem, &floatnull, den,
+ &anynull, &status);
+
+ for (ii = 0; ii < 6; ii++)
+ printf("%5d %10s %10ld %10.2f\n", ii + 1, name[ii], dia[ii], den[ii]);
+ }
+
+ for (ii = 0; ii < 3; ii++) /* free the memory for the column labels */
+ free( ttype[ii] );
+
+ for (ii = 0; ii < 6; ii++) /* free the memory for the string column */
+ free( name[ii] );
+
+ if ( fits_close_file(fptr, &status) )
+ printerror( status );
+
+ return;
+}
+/*--------------------------------------------------------------------------*/
+void printerror( int status)
+{
+ /*****************************************************/
+ /* Print out cfitsio error messages and exit program */
+ /*****************************************************/
+
+
+ if (status)
+ {
+ fits_report_error(stderr, status); /* print error report */
+
+ exit( status ); /* terminate the program, returning error status */
+ }
+ return;
+}
diff --git a/pkg/tbtables/cfitsio/cookbook.f b/pkg/tbtables/cfitsio/cookbook.f
new file mode 100644
index 00000000..8becfdd2
--- /dev/null
+++ b/pkg/tbtables/cfitsio/cookbook.f
@@ -0,0 +1,772 @@
+ program main
+
+C This is the FITSIO cookbook program that contains an annotated listing of
+C various computer programs that read and write files in FITS format
+C using the FITSIO subroutine interface. These examples are
+C working programs which users may adapt and modify for their own
+C purposes. This Cookbook serves as a companion to the FITSIO User's
+C Guide that provides more complete documentation on all the
+C available FITSIO subroutines.
+
+C Call each subroutine in turn:
+
+ call writeimage
+ call writeascii
+ call writebintable
+ call copyhdu
+ call selectrows
+ call readheader
+ call readimage
+ call readtable
+ print *
+ print *,"All the fitsio cookbook routines ran successfully."
+
+ end
+C *************************************************************************
+ subroutine writeimage
+
+C Create a FITS primary array containing a 2-D image
+
+ integer status,unit,blocksize,bitpix,naxis,naxes(2)
+ integer i,j,group,fpixel,nelements,array(300,200)
+ character filename*80
+ logical simple,extend
+
+C The STATUS parameter must be initialized before using FITSIO. A
+C positive value of STATUS is returned whenever a serious error occurs.
+C FITSIO uses an `inherited status' convention, which means that if a
+C subroutine is called with a positive input value of STATUS, then the
+C subroutine will exit immediately, preserving the status value. For
+C simplicity, this program only checks the status value at the end of
+C the program, but it is usually better practice to check the status
+C value more frequently.
+
+ status=0
+
+C Name of the FITS file to be created:
+ filename='ATESTFILEZ.FITS'
+
+C Delete the file if it already exists, so we can then recreate it.
+C The deletefile subroutine is listed at the end of this file.
+ call deletefile(filename,status)
+
+C Get an unused Logical Unit Number to use to open the FITS file.
+C This routine is not required; programmers can choose any unused
+C unit number to open the file.
+ call ftgiou(unit,status)
+
+C Create the new empty FITS file. The blocksize parameter is a
+C historical artifact and the value is ignored by FITSIO.
+ blocksize=1
+ call ftinit(unit,filename,blocksize,status)
+
+C Initialize parameters about the FITS image.
+C BITPIX = 16 means that the image pixels will consist of 16-bit
+C integers. The size of the image is given by the NAXES values.
+C The EXTEND = TRUE parameter indicates that the FITS file
+C may contain extensions following the primary array.
+ simple=.true.
+ bitpix=16
+ naxis=2
+ naxes(1)=300
+ naxes(2)=200
+ extend=.true.
+
+C Write the required header keywords to the file
+ call ftphpr(unit,simple,bitpix,naxis,naxes,0,1,extend,status)
+
+C Initialize the values in the image with a linear ramp function
+ do j=1,naxes(2)
+ do i=1,naxes(1)
+ array(i,j)=i - 1 +j - 1
+ end do
+ end do
+
+C Write the array to the FITS file.
+C The last letter of the subroutine name defines the datatype of the
+C array argument; in this case the 'J' indicates that the array has an
+C integer*4 datatype. ('I' = I*2, 'E' = Real*4, 'D' = Real*8).
+C The 2D array is treated as a single 1-D array with NAXIS1 * NAXIS2
+C total number of pixels. GROUP is seldom used parameter that should
+C almost always be set = 1.
+ group=1
+ fpixel=1
+ nelements=naxes(1)*naxes(2)
+ call ftpprj(unit,group,fpixel,nelements,array,status)
+
+C Write another optional keyword to the header
+C The keyword record will look like this in the FITS file:
+C
+C EXPOSURE= 1500 / Total Exposure Time
+C
+ call ftpkyj(unit,'EXPOSURE',1500,'Total Exposure Time',status)
+
+C The FITS file must always be closed before exiting the program.
+C Any unit numbers allocated with FTGIOU must be freed with FTFIOU.
+ call ftclos(unit, status)
+ call ftfiou(unit, status)
+
+C Check for any errors, and if so print out error messages.
+C The PRINTERROR subroutine is listed near the end of this file.
+ if (status .gt. 0)call printerror(status)
+ end
+C *************************************************************************
+ subroutine writeascii
+
+C Create an ASCII table containing 3 columns and 6 rows. For convenience,
+C the ASCII table extension is appended to the FITS image file created
+C previously by the WRITEIMAGE subroutine.
+
+ integer status,unit,readwrite,blocksize,tfields,nrows,rowlen
+ integer nspace,tbcol(3),diameter(6), colnum,frow,felem
+ real density(6)
+ character filename*40,extname*16
+ character*16 ttype(3),tform(3),tunit(3),name(6)
+ data ttype/'Planet','Diameter','Density'/
+ data tform/'A8','I6','F4.2'/
+ data tunit/' ','km','g/cm'/
+ data name/'Mercury','Venus','Earth','Mars','Jupiter','Saturn'/
+ data diameter/4880,12112,12742,6800,143000,121000/
+ data density/5.1,5.3,5.52,3.94,1.33,0.69/
+
+C The STATUS parameter must always be initialized.
+ status=0
+
+C Name of the FITS file to append the ASCII table to:
+ filename='ATESTFILEZ.FITS'
+
+C Get an unused Logical Unit Number to use to open the FITS file.
+ call ftgiou(unit,status)
+
+C Open the FITS file with write access.
+C (readwrite = 0 would open the file with readonly access).
+ readwrite=1
+ call ftopen(unit,filename,readwrite,blocksize,status)
+
+C FTCRHD creates a new empty FITS extension following the current
+C extension and moves to it. In this case, FITSIO was initially
+C positioned on the primary array when the FITS file was first opened, so
+C FTCRHD appends an empty extension and moves to it. All future FITSIO
+C calls then operate on the new extension (which will be an ASCII
+C table).
+ call ftcrhd(unit,status)
+
+C define parameters for the ASCII table (see the above data statements)
+ tfields=3
+ nrows=6
+ extname='PLANETS_ASCII'
+
+C FTGABC is a convenient subroutine for calculating the total width of
+C the table and the starting position of each column in an ASCII table.
+C Any number of blank spaces (including zero) may be inserted between
+C each column of the table, as specified by the NSPACE parameter.
+ nspace=1
+ call ftgabc(tfields,tform,nspace,rowlen,tbcol,status)
+
+C FTPHTB writes all the required header keywords which define the
+C structure of the ASCII table. NROWS and TFIELDS give the number of
+C rows and columns in the table, and the TTYPE, TBCOL, TFORM, and TUNIT
+C arrays give the column name, starting position, format, and units,
+C respectively of each column. The values of the ROWLEN and TBCOL parameters
+C were previously calculated by the FTGABC routine.
+ call ftphtb(unit,rowlen,nrows,tfields,ttype,tbcol,tform,tunit,
+ & extname,status)
+
+C Write names to the first column, diameters to 2nd col., and density to 3rd
+C FTPCLS writes the string values to the NAME column (column 1) of the
+C table. The FTPCLJ and FTPCLE routines write the diameter (integer) and
+C density (real) value to the 2nd and 3rd columns. The FITSIO routines
+C are column oriented, so it is usually easier to read or write data in a
+C table in a column by column order rather than row by row.
+ frow=1
+ felem=1
+ colnum=1
+ call ftpcls(unit,colnum,frow,felem,nrows,name,status)
+ colnum=2
+ call ftpclj(unit,colnum,frow,felem,nrows,diameter,status)
+ colnum=3
+ call ftpcle(unit,colnum,frow,felem,nrows,density,status)
+
+C The FITS file must always be closed before exiting the program.
+C Any unit numbers allocated with FTGIOU must be freed with FTFIOU.
+ call ftclos(unit, status)
+ call ftfiou(unit, status)
+
+C Check for any error, and if so print out error messages.
+C The PRINTERROR subroutine is listed near the end of this file.
+ if (status .gt. 0)call printerror(status)
+ end
+C *************************************************************************
+ subroutine writebintable
+
+C This routine creates a FITS binary table, or BINTABLE, containing
+C 3 columns and 6 rows. This routine is nearly identical to the
+C previous WRITEASCII routine, except that the call to FTGABC is not
+C needed, and FTPHBN is called rather than FTPHTB to write the
+C required header keywords.
+
+ integer status,unit,readwrite,blocksize,hdutype,tfields,nrows
+ integer varidat,diameter(6), colnum,frow,felem
+ real density(6)
+ character filename*40,extname*16
+ character*16 ttype(3),tform(3),tunit(3),name(6)
+ data ttype/'Planet','Diameter','Density'/
+ data tform/'8A','1J','1E'/
+ data tunit/' ','km','g/cm'/
+ data name/'Mercury','Venus','Earth','Mars','Jupiter','Saturn'/
+ data diameter/4880,12112,12742,6800,143000,121000/
+ data density/5.1,5.3,5.52,3.94,1.33,0.69/
+
+C The STATUS parameter must always be initialized.
+ status=0
+
+C Name of the FITS file to append the ASCII table to:
+ filename='ATESTFILEZ.FITS'
+
+C Get an unused Logical Unit Number to use to open the FITS file.
+ call ftgiou(unit,status)
+
+C Open the FITS file, with write access.
+ readwrite=1
+ call ftopen(unit,filename,readwrite,blocksize,status)
+
+C Move to the last (2nd) HDU in the file (the ASCII table).
+ call ftmahd(unit,2,hdutype,status)
+
+C Append/create a new empty HDU onto the end of the file and move to it.
+ call ftcrhd(unit,status)
+
+C Define parameters for the binary table (see the above data statements)
+ tfields=3
+ nrows=6
+ extname='PLANETS_BINARY'
+ varidat=0
+
+C FTPHBN writes all the required header keywords which define the
+C structure of the binary table. NROWS and TFIELDS gives the number of
+C rows and columns in the table, and the TTYPE, TFORM, and TUNIT arrays
+C give the column name, format, and units, respectively of each column.
+ call ftphbn(unit,nrows,tfields,ttype,tform,tunit,
+ & extname,varidat,status)
+
+C Write names to the first column, diameters to 2nd col., and density to 3rd
+C FTPCLS writes the string values to the NAME column (column 1) of the
+C table. The FTPCLJ and FTPCLE routines write the diameter (integer) and
+C density (real) value to the 2nd and 3rd columns. The FITSIO routines
+C are column oriented, so it is usually easier to read or write data in a
+C table in a column by column order rather than row by row. Note that
+C the identical subroutine calls are used to write to either ASCII or
+C binary FITS tables.
+ frow=1
+ felem=1
+ colnum=1
+ call ftpcls(unit,colnum,frow,felem,nrows,name,status)
+ colnum=2
+ call ftpclj(unit,colnum,frow,felem,nrows,diameter,status)
+ colnum=3
+ call ftpcle(unit,colnum,frow,felem,nrows,density,status)
+
+C The FITS file must always be closed before exiting the program.
+C Any unit numbers allocated with FTGIOU must be freed with FTFIOU.
+ call ftclos(unit, status)
+ call ftfiou(unit, status)
+
+C Check for any error, and if so print out error messages.
+C The PRINTERROR subroutine is listed near the end of this file.
+ if (status .gt. 0)call printerror(status)
+ end
+C *************************************************************************
+ subroutine copyhdu
+
+C Copy the 1st and 3rd HDUs from the input file to a new FITS file
+
+ integer status,inunit,outunit,readwrite,blocksize,morekeys,hdutype
+ character infilename*40,outfilename*40
+
+C The STATUS parameter must always be initialized.
+ status=0
+
+C Name of the FITS files:
+ infilename='ATESTFILEZ.FITS'
+ outfilename='BTESTFILEZ.FITS'
+
+C Delete the file if it already exists, so we can then recreate it
+C The deletefile subroutine is listed at the end of this file.
+ call deletefile(outfilename,status)
+
+C Get unused Logical Unit Numbers to use to open the FITS files.
+ call ftgiou(inunit,status)
+ call ftgiou(outunit,status)
+
+C Open the input FITS file, with readonly access
+ readwrite=0
+ call ftopen(inunit,infilename,readwrite,blocksize,status)
+
+C Create the new empty FITS file (value of blocksize is ignored)
+ blocksize=1
+ call ftinit(outunit,outfilename,blocksize,status)
+
+C FTCOPY copies the current HDU from the input FITS file to the output
+C file. The MOREKEY parameter allows one to reserve space for additional
+C header keywords when the HDU is created. FITSIO will automatically
+C insert more header space if required, so programmers do not have to
+C reserve space ahead of time, although it is more efficient to do so if
+C it is known that more keywords will be appended to the header.
+ morekeys=0
+ call ftcopy(inunit,outunit,morekeys,status)
+
+C Append/create a new empty extension on the end of the output file
+ call ftcrhd(outunit,status)
+
+C Skip to the 3rd extension in the input file which in this case
+C is the binary table created by the previous WRITEBINARY routine.
+ call ftmahd(inunit,3,hdutype,status)
+
+C FTCOPY now copies the binary table from the input FITS file
+C to the output file.
+ call ftcopy(inunit,outunit,morekeys,status)
+
+C The FITS files must always be closed before exiting the program.
+C Any unit numbers allocated with FTGIOU must be freed with FTFIOU.
+C Giving -1 for the value of the first argument causes all previously
+C allocated unit numbers to be released.
+
+ call ftclos(inunit, status)
+ call ftclos(outunit, status)
+ call ftfiou(-1, status)
+
+C Check for any error, and if so print out error messages.
+C The PRINTERROR subroutine is listed near the end of this file.
+ if (status .gt. 0)call printerror(status)
+ end
+C *************************************************************************
+ subroutine selectrows
+
+C This routine copies selected rows from an input table into a new output
+C FITS table. In this example all the rows in the input table that have
+C a value of the DENSITY column less that 3.0 are copied to the output
+C table. This program illustrates several generally useful techniques,
+C including:
+C how to locate the end of a FITS file
+C how to create a table when the total number of rows in the table
+C is not known until the table is completed
+C how to efficiently copy entire rows from one table to another.
+
+ integer status,inunit,outunit,readwrite,blocksize,hdutype
+ integer nkeys,nspace,naxes(2),nfound,colnum,frow,felem
+ integer noutrows,irow,temp(100),i
+ real nullval,density(6)
+ character infilename*40,outfilename*40,record*80
+ logical exact,anynulls
+
+C The STATUS parameter must always be initialized.
+ status=0
+
+C Names of the FITS files:
+ infilename='ATESTFILEZ.FITS'
+ outfilename='BTESTFILEZ.FITS'
+
+C Get unused Logical Unit Numbers to use to open the FITS files.
+ call ftgiou(inunit,status)
+ call ftgiou(outunit,status)
+
+C The input FITS file is opened with READONLY access, and the output
+C FITS file is opened with WRITE access.
+ readwrite=0
+ call ftopen(inunit,infilename,readwrite,blocksize,status)
+ readwrite=1
+ call ftopen(outunit,outfilename,readwrite,blocksize,status)
+
+C move to the 3rd HDU in the input file (a binary table in this case)
+ call ftmahd(inunit,3,hdutype,status)
+
+C This do-loop illustrates how to move to the last extension in any FITS
+C file. The call to FTMRHD moves one extension at a time through the
+C FITS file until an `End-of-file' status value (= 107) is returned.
+ do while (status .eq. 0)
+ call ftmrhd(outunit,1,hdutype,status)
+ end do
+
+C After locating the end of the FITS file, it is necessary to reset the
+C status value to zero and also clear the internal error message stack
+C in FITSIO. The previous `End-of-file' error will have produced
+C an unimportant message on the error stack which can be cleared with
+C the call to the FTCMSG routine (which has no arguments).
+
+ if (status .eq. 107)then
+ status=0
+ call ftcmsg
+ end if
+
+C Create a new empty extension in the output file.
+ call ftcrhd(outunit,status)
+
+C Find the number of keywords in the input table header.
+ call ftghsp(inunit,nkeys,nspace,status)
+
+C This do-loop of calls to FTGREC and FTPREC copies all the keywords from
+C the input to the output FITS file. Notice that the specified number
+C of rows in the output table, as given by the NAXIS2 keyword, will be
+C incorrect. This value will be modified later after it is known how many
+C rows will be in the table, so it does not matter how many rows are specified
+C initially.
+ do i=1,nkeys
+ call ftgrec(inunit,i,record,status)
+ call ftprec(outunit,record,status)
+ end do
+
+C FTGKNJ is used to get the value of the NAXIS1 and NAXIS2 keywords,
+C which define the width of the table in bytes, and the number of
+C rows in the table.
+ call ftgknj(inunit,'NAXIS',1,2,naxes,nfound,status)
+
+C FTGCNO gets the column number of the `DENSITY' column; the column
+C number is needed when reading the data in the column. The EXACT
+C parameter determines whether or not the match to the column names
+C will be case sensitive.
+ exact=.false.
+ call ftgcno(inunit,exact,'DENSITY',colnum,status)
+
+C FTGCVE reads all 6 rows of data in the `DENSITY' column. The number
+C of rows in the table is given by NAXES(2). Any null values in the
+C table will be returned with the corresponding value set to -99
+C (= the value of NULLVAL). The ANYNULLS parameter will be set to TRUE
+C if any null values were found while reading the data values in the table.
+ frow=1
+ felem=1
+ nullval=-99.
+ call ftgcve(inunit,colnum,frow,felem,naxes(2),nullval,
+ & density,anynulls,status)
+
+C If the density is less than 3.0, copy the row to the output table.
+C FTGTBB and FTPTBB are low-level routines to read and write, respectively,
+C a specified number of bytes in the table, starting at the specified
+C row number and beginning byte within the row. These routines do
+C not do any interpretation of the bytes, and simply pass them to or
+C from the FITS file without any modification. This is a faster
+C way of transferring large chunks of data from one FITS file to another,
+C than reading and then writing each column of data individually.
+C In this case an entire row of bytes (the row length is specified
+C by the naxes(1) parameter) is transferred. The datatype of the
+C buffer array (TEMP in this case) is immaterial so long as it is
+C declared large enough to hold the required number of bytes.
+ noutrows=0
+ do irow=1,naxes(2)
+ if (density(irow) .lt. 3.0)then
+ noutrows=noutrows+1
+ call ftgtbb(inunit,irow,1,naxes(1),temp,status)
+ call ftptbb(outunit,noutrows,1,naxes(1),temp,status)
+ end if
+ end do
+
+C Update the NAXIS2 keyword with the correct no. of rows in the output file.
+C After all the rows have been written to the output table, the
+C FTMKYJ routine is used to overwrite the NAXIS2 keyword value with
+C the correct number of rows. Specifying `\&' for the comment string
+C tells FITSIO to keep the current comment string in the keyword and
+C only modify the value. Because the total number of rows in the table
+C was unknown when the table was first created, any value (including 0)
+C could have been used for the initial NAXIS2 keyword value.
+ call ftmkyj(outunit,'NAXIS2',noutrows,'&',status)
+
+C The FITS files must always be closed before exiting the program.
+C Any unit numbers allocated with FTGIOU must be freed with FTFIOU.
+ call ftclos(inunit, status)
+ call ftclos(outunit, status)
+ call ftfiou(-1, status)
+
+C Check for any error, and if so print out error messages.
+C The PRINTERROR subroutine is listed near the end of this file.
+ if (status .gt. 0)call printerror(status)
+ end
+C *************************************************************************
+ subroutine readheader
+
+C Print out all the header keywords in all extensions of a FITS file
+
+ integer status,unit,readwrite,blocksize,nkeys,nspace,hdutype,i,j
+ character filename*80,record*80
+
+C The STATUS parameter must always be initialized.
+ status=0
+
+C Get an unused Logical Unit Number to use to open the FITS file.
+ call ftgiou(unit,status)
+
+C name of FITS file
+ filename='ATESTFILEZ.FITS'
+
+C open the FITS file, with read-only access. The returned BLOCKSIZE
+C parameter is obsolete and should be ignored.
+ readwrite=0
+ call ftopen(unit,filename,readwrite,blocksize,status)
+
+ j = 0
+100 continue
+ j = j + 1
+
+ print *,'Header listing for HDU', j
+
+C The FTGHSP subroutine returns the number of existing keywords in the
+C current header data unit (CHDU), not counting the required END keyword,
+ call ftghsp(unit,nkeys,nspace,status)
+
+C Read each 80-character keyword record, and print it out.
+ do i = 1, nkeys
+ call ftgrec(unit,i,record,status)
+ print *,record
+ end do
+
+C Print out an END record, and a blank line to mark the end of the header.
+ if (status .eq. 0)then
+ print *,'END'
+ print *,' '
+ end if
+
+C Try moving to the next extension in the FITS file, if it exists.
+C The FTMRHD subroutine attempts to move to the next HDU, as specified by
+C the second parameter. This subroutine moves by a relative number of
+C HDUs from the current HDU. The related FTMAHD routine may be used to
+C move to an absolute HDU number in the FITS file. If the end-of-file is
+C encountered when trying to move to the specified extension, then a
+C status = 107 is returned.
+ call ftmrhd(unit,1,hdutype,status)
+
+ if (status .eq. 0)then
+C success, so jump back and print out keywords in this extension
+ go to 100
+
+ else if (status .eq. 107)then
+C hit end of file, so quit
+ status=0
+ end if
+
+C The FITS file must always be closed before exiting the program.
+C Any unit numbers allocated with FTGIOU must be freed with FTFIOU.
+ call ftclos(unit, status)
+ call ftfiou(unit, status)
+
+C Check for any error, and if so print out error messages.
+C The PRINTERROR subroutine is listed near the end of this file.
+ if (status .gt. 0)call printerror(status)
+ end
+C *************************************************************************
+ subroutine readimage
+
+C Read a FITS image and determine the minimum and maximum pixel value.
+C Rather than reading the entire image in
+C at once (which could require a very large array), the image is read
+C in pieces, 100 pixels at a time.
+
+ integer status,unit,readwrite,blocksize,naxes(2),nfound
+ integer group,firstpix,nbuffer,npixels,i
+ real datamin,datamax,nullval,buffer(100)
+ logical anynull
+ character filename*80
+
+C The STATUS parameter must always be initialized.
+ status=0
+
+C Get an unused Logical Unit Number to use to open the FITS file.
+ call ftgiou(unit,status)
+
+C Open the FITS file previously created by WRITEIMAGE
+ filename='ATESTFILEZ.FITS'
+ readwrite=0
+ call ftopen(unit,filename,readwrite,blocksize,status)
+
+C Determine the size of the image.
+ call ftgknj(unit,'NAXIS',1,2,naxes,nfound,status)
+
+C Check that it found both NAXIS1 and NAXIS2 keywords.
+ if (nfound .ne. 2)then
+ print *,'READIMAGE failed to read the NAXISn keywords.'
+ return
+ end if
+
+C Initialize variables
+ npixels=naxes(1)*naxes(2)
+ group=1
+ firstpix=1
+ nullval=-999
+ datamin=1.0E30
+ datamax=-1.0E30
+
+ do while (npixels .gt. 0)
+C read up to 100 pixels at a time
+ nbuffer=min(100,npixels)
+
+ call ftgpve(unit,group,firstpix,nbuffer,nullval,
+ & buffer,anynull,status)
+
+C find the min and max values
+ do i=1,nbuffer
+ datamin=min(datamin,buffer(i))
+ datamax=max(datamax,buffer(i))
+ end do
+
+C increment pointers and loop back to read the next group of pixels
+ npixels=npixels-nbuffer
+ firstpix=firstpix+nbuffer
+ end do
+
+ print *
+ print *,'Min and max image pixels = ',datamin,datamax
+
+C The FITS file must always be closed before exiting the program.
+C Any unit numbers allocated with FTGIOU must be freed with FTFIOU.
+ call ftclos(unit, status)
+ call ftfiou(unit, status)
+
+C Check for any error, and if so print out error messages.
+C The PRINTERROR subroutine is listed near the end of this file.
+ if (status .gt. 0)call printerror(status)
+ end
+C *************************************************************************
+ subroutine readtable
+
+C Read and print data values from an ASCII or binary table
+C This example reads and prints out all the data in the ASCII and
+C the binary tables that were previously created by WRITEASCII and
+C WRITEBINTABLE. Note that the exact same FITSIO routines are
+C used to read both types of tables.
+
+ integer status,unit,readwrite,blocksize,hdutype,ntable
+ integer felem,nelems,nullj,diameter,nfound,irow,colnum
+ real nulle,density
+ character filename*40,nullstr*1,name*8,ttype(3)*10
+ logical anynull
+
+C The STATUS parameter must always be initialized.
+ status=0
+
+C Get an unused Logical Unit Number to use to open the FITS file.
+ call ftgiou(unit,status)
+
+C Open the FITS file previously created by WRITEIMAGE
+ filename='ATESTFILEZ.FITS'
+ readwrite=0
+ call ftopen(unit,filename,readwrite,blocksize,status)
+
+C Loop twice, first reading the ASCII table, then the binary table
+ do ntable=2,3
+
+C Move to the next extension
+ call ftmahd(unit,ntable,hdutype,status)
+
+ print *,' '
+ if (hdutype .eq. 1)then
+ print *,'Reading ASCII table in HDU ',ntable
+ else if (hdutype .eq. 2)then
+ print *,'Reading binary table in HDU ',ntable
+ end if
+
+C Read the TTYPEn keywords, which give the names of the columns
+ call ftgkns(unit,'TTYPE',1,3,ttype,nfound,status)
+ write(*,2000)ttype
+2000 format(2x,"Row ",3a10)
+
+C Read the data, one row at a time, and print them out
+ felem=1
+ nelems=1
+ nullstr=' '
+ nullj=0
+ nulle=0.
+ do irow=1,6
+C FTGCVS reads the NAMES from the first column of the table.
+ colnum=1
+ call ftgcvs(unit,colnum,irow,felem,nelems,nullstr,name,
+ & anynull,status)
+
+C FTGCVJ reads the DIAMETER values from the second column.
+ colnum=2
+ call ftgcvj(unit,colnum,irow,felem,nelems,nullj,diameter,
+ & anynull,status)
+
+C FTGCVE reads the DENSITY values from the third column.
+ colnum=3
+ call ftgcve(unit,colnum,irow,felem,nelems,nulle,density,
+ & anynull,status)
+ write(*,2001)irow,name,diameter,density
+2001 format(i5,a10,i10,f10.2)
+ end do
+ end do
+
+C The FITS file must always be closed before exiting the program.
+C Any unit numbers allocated with FTGIOU must be freed with FTFIOU.
+ call ftclos(unit, status)
+ call ftfiou(unit, status)
+
+C Check for any error, and if so print out error messages.
+C The PRINTERROR subroutine is listed near the end of this file.
+ if (status .gt. 0)call printerror(status)
+ end
+C *************************************************************************
+ subroutine printerror(status)
+
+C This subroutine prints out the descriptive text corresponding to the
+C error status value and prints out the contents of the internal
+C error message stack generated by FITSIO whenever an error occurs.
+
+ integer status
+ character errtext*30,errmessage*80
+
+C Check if status is OK (no error); if so, simply return
+ if (status .le. 0)return
+
+C The FTGERR subroutine returns a descriptive 30-character text string that
+C corresponds to the integer error status number. A complete list of all
+C the error numbers can be found in the back of the FITSIO User's Guide.
+ call ftgerr(status,errtext)
+ print *,'FITSIO Error Status =',status,': ',errtext
+
+C FITSIO usually generates an internal stack of error messages whenever
+C an error occurs. These messages provide much more information on the
+C cause of the problem than can be provided by the single integer error
+C status value. The FTGMSG subroutine retrieves the oldest message from
+C the stack and shifts any remaining messages on the stack down one
+C position. FTGMSG is called repeatedly until a blank message is
+C returned, which indicates that the stack is empty. Each error message
+C may be up to 80 characters in length. Another subroutine, called
+C FTCMSG, is available to simply clear the whole error message stack in
+C cases where one is not interested in the contents.
+ call ftgmsg(errmessage)
+ do while (errmessage .ne. ' ')
+ print *,errmessage
+ call ftgmsg(errmessage)
+ end do
+ end
+C *************************************************************************
+ subroutine deletefile(filename,status)
+
+C A simple little routine to delete a FITS file
+
+ integer status,unit,blocksize
+ character*(*) filename
+
+C Simply return if status is greater than zero
+ if (status .gt. 0)return
+
+C Get an unused Logical Unit Number to use to open the FITS file
+ call ftgiou(unit,status)
+
+C Try to open the file, to see if it exists
+ call ftopen(unit,filename,1,blocksize,status)
+
+ if (status .eq. 0)then
+C file was opened; so now delete it
+ call ftdelt(unit,status)
+ else if (status .eq. 103)then
+C file doesn't exist, so just reset status to zero and clear errors
+ status=0
+ call ftcmsg
+ else
+C there was some other error opening the file; delete the file anyway
+ status=0
+ call ftcmsg
+ call ftdelt(unit,status)
+ end if
+
+C Free the unit number for later reuse
+ call ftfiou(unit, status)
+ end
diff --git a/pkg/tbtables/cfitsio/drvrfile.c b/pkg/tbtables/cfitsio/drvrfile.c
new file mode 100644
index 00000000..516db58d
--- /dev/null
+++ b/pkg/tbtables/cfitsio/drvrfile.c
@@ -0,0 +1,730 @@
+/* This file, drvrfile.c contains driver routines for disk files. */
+
+/* The FITSIO software was written by William Pence at the High Energy */
+/* Astrophysic Science Archive Research Center (HEASARC) at the NASA */
+/* Goddard Space Flight Center. */
+
+#include <string.h>
+#include <stdlib.h>
+#include "fitsio2.h"
+
+#if defined(unix) || defined(__unix__) || defined(__unix)
+#include <pwd.h> /* needed in file_openfile */
+
+#ifdef REPLACE_LINKS
+#include <sys/types.h>
+#include <sys/stat.h>
+#endif
+
+#endif
+
+#ifdef HAVE_FTRUNCATE
+#include <unistd.h> /* contains prototype of UNIX file truncate fn */
+#endif
+
+#define IO_SEEK 0 /* last file I/O operation was a seek */
+#define IO_READ 1 /* last file I/O operation was a read */
+#define IO_WRITE 2 /* last file I/O operation was a write */
+
+static char file_outfile[FLEN_FILENAME];
+
+typedef struct /* structure containing disk file structure */
+{
+ FILE *fileptr;
+ OFF_T currentpos;
+ int last_io_op;
+} diskdriver;
+
+static diskdriver handleTable[NMAXFILES]; /* allocate diskfile handle tables */
+
+/*--------------------------------------------------------------------------*/
+int file_init(void)
+{
+ int ii;
+
+ for (ii = 0; ii < NMAXFILES; ii++) /* initialize all empty slots in table */
+ {
+ handleTable[ii].fileptr = 0;
+ }
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int file_setoptions(int options)
+{
+ /* do something with the options argument, to stop compiler warning */
+ options = 0;
+ return(options);
+}
+/*--------------------------------------------------------------------------*/
+int file_getoptions(int *options)
+{
+ *options = 0;
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int file_getversion(int *version)
+{
+ *version = 10;
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int file_shutdown(void)
+{
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int file_open(char *filename, int rwmode, int *handle)
+{
+ FILE *diskfile;
+ int copyhandle, ii, status;
+ char recbuf[2880];
+ size_t nread;
+
+ /*
+ if an output filename has been specified as part of the input
+ file, as in "inputfile.fits(outputfile.fit)" then we have to
+ create the output file, copy the input to it, then reopen the
+ the new copy.
+ */
+
+ if (*file_outfile)
+ {
+ /* open the original file, with readonly access */
+ status = file_openfile(filename, READONLY, &diskfile);
+ if (status)
+ return(status);
+
+ /* create the output file */
+ status = file_create(file_outfile,handle);
+ if (status)
+ {
+ ffpmsg("Unable to create output file for copy of input file:");
+ ffpmsg(file_outfile);
+ return(status);
+ }
+
+ /* copy the file from input to output */
+ while(0 != (nread = fread(recbuf,1,2880, diskfile)))
+ {
+ status = file_write(*handle, recbuf, nread);
+ if (status)
+ return(status);
+ }
+
+ /* close both files */
+ fclose(diskfile);
+ copyhandle = *handle;
+ file_close(*handle);
+ *handle = copyhandle; /* reuse the old file handle */
+
+ /* reopen the new copy, with correct rwmode */
+ status = file_openfile(file_outfile, rwmode, &diskfile);
+
+ }
+ else
+ {
+ *handle = -1;
+ for (ii = 0; ii < NMAXFILES; ii++) /* find empty slot in table */
+ {
+ if (handleTable[ii].fileptr == 0)
+ {
+ *handle = ii;
+ break;
+ }
+ }
+
+ if (*handle == -1)
+ return(TOO_MANY_FILES); /* too many files opened */
+
+ /*open the file */
+ status = file_openfile(filename, rwmode, &diskfile);
+ }
+
+ handleTable[*handle].fileptr = diskfile;
+ handleTable[*handle].currentpos = 0;
+ handleTable[*handle].last_io_op = IO_SEEK;
+
+ return(status);
+}
+/*--------------------------------------------------------------------------*/
+int file_openfile(char *filename, int rwmode, FILE **diskfile)
+/*
+ lowest level routine to physically open a disk file
+*/
+{
+ char mode[4];
+
+#if defined(unix) || defined(__unix__) || defined(__unix)
+ char tempname[512], *cptr, user[80];
+ struct passwd *pwd;
+ int ii = 0;
+
+#if defined(REPLACE_LINKS)
+ struct stat stbuf;
+ int success = 0;
+ size_t n;
+ FILE *f1, *f2;
+ char buf[BUFSIZ];
+#endif
+
+#endif
+
+ if (rwmode == READWRITE)
+ {
+ strcpy(mode, "r+b"); /* open existing file with read-write */
+ }
+ else
+ {
+ strcpy(mode, "rb"); /* open existing file readonly */
+ }
+
+#if MACHINE == ALPHAVMS || MACHINE == VAXVMS
+ /* specify VMS record structure: fixed format, 2880 byte records */
+ /* but force stream mode access to enable random I/O access */
+ *diskfile = fopen(filename, mode, "rfm=fix", "mrs=2880", "ctx=stm");
+
+#elif defined(unix) || defined(__unix__) || defined(__unix)
+
+ /* support the ~user/file.fits or ~/file.fits filenames in UNIX */
+
+ if (*filename == '~')
+ {
+ if (filename[1] == '/')
+ {
+ cptr = getenv("HOME");
+ if (cptr)
+ {
+ strcpy(tempname, cptr);
+ strcat(tempname, filename+1);
+ }
+ else
+ {
+ strcpy(tempname, filename);
+ }
+ }
+ else
+ {
+ /* copy user name */
+ cptr = filename+1;
+ while (*cptr && (*cptr != '/'))
+ {
+ user[ii] = *cptr;
+ cptr++;
+ ii++;
+ }
+ user[ii] = '\0';
+
+ /* get structure that includes name of user's home directory */
+ pwd = getpwnam(user);
+
+ /* copy user's home directory */
+ strcpy(tempname, pwd->pw_dir);
+ strcat(tempname, cptr);
+ }
+
+ *diskfile = fopen(tempname, mode);
+ }
+ else
+ {
+ /* don't need to expand the input file name */
+ *diskfile = fopen(filename, mode);
+
+#if defined(REPLACE_LINKS)
+
+ if (!(*diskfile) && (rwmode == READWRITE))
+ {
+ /* failed to open file with READWRITE privilege. Test if */
+ /* the file we are trying to open is a soft link to a file that */
+ /* doesn't have write privilege. */
+
+ lstat(filename, &stbuf);
+ if ((stbuf.st_mode & S_IFMT) == S_IFLNK) /* is this a soft link? */
+ {
+ if ((f1 = fopen(filename, "rb")) != 0) /* try opening READONLY */
+ {
+ strcpy(tempname, filename);
+ strcat(tempname, ".TmxFil");
+ if ((f2 = fopen(tempname, "wb")) != 0) /* create temp file */
+ {
+ success = 1;
+ while ((n = fread(buf, 1, BUFSIZ, f1)) > 0)
+ {
+ /* copy linked file to local temporary file */
+ if (fwrite(buf, 1, n, f2) != n)
+ {
+ success = 0;
+ break;
+ }
+ }
+ fclose(f2);
+ }
+ fclose(f1);
+
+ if (success)
+ {
+ /* delete link and rename temp file to previous link name */
+ remove(filename);
+ rename(tempname, filename);
+
+ /* try once again to open the file with write access */
+ *diskfile = fopen(filename, mode);
+ }
+ else
+ remove(tempname); /* clean up the failed copy */
+ }
+ }
+ }
+#endif
+
+ }
+
+#else
+
+ /* other non-UNIX machines */
+ *diskfile = fopen(filename, mode);
+
+#endif
+
+ if (!(*diskfile)) /* couldn't open file */
+ {
+ return(FILE_NOT_OPENED);
+ }
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int file_create(char *filename, int *handle)
+{
+ FILE *diskfile;
+ int ii;
+ char mode[4];
+
+ *handle = -1;
+ for (ii = 0; ii < NMAXFILES; ii++) /* find empty slot in table */
+ {
+ if (handleTable[ii].fileptr == 0)
+ {
+ *handle = ii;
+ break;
+ }
+ }
+ if (*handle == -1)
+ return(TOO_MANY_FILES); /* too many files opened */
+
+ strcpy(mode, "w+b"); /* create new file with read-write */
+
+ diskfile = fopen(filename, "r"); /* does file already exist? */
+
+ if (diskfile)
+ {
+ fclose(diskfile); /* close file and exit with error */
+ return(FILE_NOT_CREATED);
+ }
+
+#if MACHINE == ALPHAVMS || MACHINE == VAXVMS
+ /* specify VMS record structure: fixed format, 2880 byte records */
+ /* but force stream mode access to enable random I/O access */
+ diskfile = fopen(filename, mode, "rfm=fix", "mrs=2880", "ctx=stm");
+#else
+ diskfile = fopen(filename, mode);
+#endif
+
+ if (!(diskfile)) /* couldn't create file */
+ {
+ return(FILE_NOT_CREATED);
+ }
+
+ handleTable[ii].fileptr = diskfile;
+ handleTable[ii].currentpos = 0;
+ handleTable[ii].last_io_op = IO_SEEK;
+
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int file_truncate(int handle, OFF_T filesize)
+/*
+ truncate the diskfile to a new smaller size
+*/
+{
+
+#ifdef HAVE_FTRUNCATE
+ int fdesc;
+
+ fdesc = fileno(handleTable[handle].fileptr);
+ ftruncate(fdesc, filesize);
+
+ handleTable[handle].currentpos = filesize;
+ handleTable[handle].last_io_op = IO_WRITE;
+
+#endif
+
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int file_size(int handle, OFF_T *filesize)
+/*
+ return the size of the file in bytes
+*/
+{
+ OFF_T position1;
+ FILE *diskfile;
+
+ diskfile = handleTable[handle].fileptr;
+
+#if _FILE_OFFSET_BITS - 0 == 64
+
+/* call the newer ftello and fseeko routines , which support */
+/* Large Files (> 2GB) if they are supported. */
+
+ position1 = ftello(diskfile); /* save current postion */
+ if (position1 < 0)
+ return(SEEK_ERROR);
+
+ if (fseeko(diskfile, 0, 2) != 0) /* seek to end of file */
+ return(SEEK_ERROR);
+
+ *filesize = ftello(diskfile); /* get file size */
+ if (*filesize < 0)
+ return(SEEK_ERROR);
+
+ if (fseeko(diskfile, position1, 0) != 0) /* seek back to original pos */
+ return(SEEK_ERROR);
+
+#else
+
+ position1 = ftell(diskfile); /* save current postion */
+ if (position1 < 0)
+ return(SEEK_ERROR);
+
+ if (fseek(diskfile, 0, 2) != 0) /* seek to end of file */
+ return(SEEK_ERROR);
+
+ *filesize = ftell(diskfile); /* get file size */
+ if (*filesize < 0)
+ return(SEEK_ERROR);
+
+ if (fseek(diskfile, position1, 0) != 0) /* seek back to original pos */
+ return(SEEK_ERROR);
+
+#endif
+
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int file_close(int handle)
+/*
+ close the file
+*/
+{
+
+ if (fclose(handleTable[handle].fileptr) )
+ return(FILE_NOT_CLOSED);
+
+ handleTable[handle].fileptr = 0;
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int file_remove(char *filename)
+/*
+ delete the file from disk
+*/
+{
+ remove(filename);
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int file_flush(int handle)
+/*
+ flush the file
+*/
+{
+ if (fflush(handleTable[handle].fileptr) )
+ return(WRITE_ERROR);
+
+ /* The flush operation is not supposed to move the internal */
+ /* file pointer, but it does on some Windows-95 compilers and */
+ /* perhaps others, so seek to original position to be sure. */
+ /* This seek will do no harm on other systems. */
+
+#if MACHINE == IBMPC
+
+ if (file_seek(handle, handleTable[handle].currentpos))
+ return(SEEK_ERROR);
+
+#endif
+
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int file_seek(int handle, OFF_T offset)
+/*
+ seek to position relative to start of the file
+*/
+{
+
+#if _FILE_OFFSET_BITS - 0 == 64
+
+ if (fseeko(handleTable[handle].fileptr, offset, 0) != 0)
+ return(SEEK_ERROR);
+
+#else
+
+ if (fseek(handleTable[handle].fileptr, offset, 0) != 0)
+ return(SEEK_ERROR);
+
+#endif
+
+ handleTable[handle].currentpos = offset;
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int file_read(int hdl, void *buffer, long nbytes)
+/*
+ read bytes from the current position in the file
+*/
+{
+ long nread;
+ char *cptr;
+
+ if (handleTable[hdl].last_io_op == IO_WRITE)
+ {
+ if (file_seek(hdl, handleTable[hdl].currentpos))
+ return(SEEK_ERROR);
+ }
+
+ nread = (long) fread(buffer, 1, nbytes, handleTable[hdl].fileptr);
+
+ if (nread == 1)
+ {
+ cptr = (char *) buffer;
+
+ /* some editors will add a single end-of-file character to a file */
+ /* Ignore it if the character is a zero, 10, or 32 */
+ if (*cptr == 0 || *cptr == 10 || *cptr == 32)
+ return(END_OF_FILE);
+ else
+ return(READ_ERROR);
+ }
+ else if (nread != nbytes)
+ {
+ return(READ_ERROR);
+ }
+
+ handleTable[hdl].currentpos += nbytes;
+ handleTable[hdl].last_io_op = IO_READ;
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int file_write(int hdl, void *buffer, long nbytes)
+/*
+ write bytes at the current position in the file
+*/
+{
+ if (handleTable[hdl].last_io_op == IO_READ)
+ {
+ if (file_seek(hdl, handleTable[hdl].currentpos))
+ return(SEEK_ERROR);
+ }
+
+ if((long) fwrite(buffer, 1, nbytes, handleTable[hdl].fileptr) != nbytes)
+ return(WRITE_ERROR);
+
+ handleTable[hdl].currentpos += nbytes;
+ handleTable[hdl].last_io_op = IO_WRITE;
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int file_compress_open(char *filename, int rwmode, int *hdl)
+/*
+ This routine opens the compressed diskfile by creating a new uncompressed
+ file then opening it. The input file name (the name of the compressed
+ file) gets replaced with the name of the uncompressed file, which is
+ initially stored in the global file_outfile string. file_outfile
+ then gets set to a null string.
+*/
+{
+ FILE *indiskfile, *outdiskfile;
+ int status, clobber = 0;
+ char *cptr;
+
+ /* open the compressed disk file */
+ status = file_openfile(filename, READONLY, &indiskfile);
+ if (status)
+ {
+ ffpmsg("failed to open compressed disk file (file_compress_open)");
+ ffpmsg(filename);
+ return(status);
+ }
+
+ /* name of the output uncompressed file is stored in the */
+ /* global variable called 'file_outfile'. */
+
+ cptr = file_outfile;
+ if (*cptr == '!')
+ {
+ /* clobber any existing file with the same name */
+ clobber = 1;
+ cptr++;
+ remove(cptr);
+ }
+ else
+ {
+ outdiskfile = fopen(file_outfile, "r"); /* does file already exist? */
+
+ if (outdiskfile)
+ {
+ ffpmsg("uncompressed file already exists: (file_compress_open)");
+ ffpmsg(file_outfile);
+ fclose(outdiskfile); /* close file and exit with error */
+ return(FILE_NOT_CREATED);
+ }
+ }
+
+ outdiskfile = fopen(cptr, "w+b"); /* create new file */
+ if (!outdiskfile)
+ {
+ ffpmsg("could not create uncompressed file: (file_compress_open)");
+ ffpmsg(file_outfile);
+ return(FILE_NOT_CREATED);
+ }
+
+ /* uncompress file into another file */
+ uncompress2file(filename, indiskfile, outdiskfile, &status);
+ fclose(indiskfile);
+ fclose(outdiskfile);
+
+ if (status)
+ {
+ ffpmsg("error in file_compress_open: failed to uncompressed file:");
+ ffpmsg(filename);
+ ffpmsg(" into new output file:");
+ ffpmsg(file_outfile);
+ return(status);
+ }
+
+ strcpy(filename, cptr); /* switch the names */
+ file_outfile[0] = '\0';
+
+ status = file_open(filename, rwmode, hdl);
+
+ return(status);
+}
+/*--------------------------------------------------------------------------*/
+int file_is_compressed(char *filename) /* I - FITS file name */
+/*
+ Test if the disk file is compressed. Returns 1 if compressed, 0 if not.
+ This may modify the filename string by appending a compression suffex.
+*/
+{
+ FILE *diskfile;
+ unsigned char buffer[2];
+ char tmpfilename[FLEN_FILENAME];
+
+ /* Open file. Try various suffix combinations */
+ if (file_openfile(filename, 0, &diskfile))
+ {
+ strcpy(tmpfilename,filename);
+ strcat(filename,".gz");
+ if (file_openfile(filename, 0, &diskfile))
+ {
+ strcpy(filename, tmpfilename);
+ strcat(filename,".Z");
+ if (file_openfile(filename, 0, &diskfile))
+ {
+ strcpy(filename, tmpfilename);
+ strcat(filename,".z"); /* it's often lower case on CDROMs */
+ if (file_openfile(filename, 0, &diskfile))
+ {
+ strcpy(filename, tmpfilename);
+ strcat(filename,".zip");
+ if (file_openfile(filename, 0, &diskfile))
+ {
+ strcpy(filename, tmpfilename);
+ strcat(filename,"-z"); /* VMS suffix */
+ if (file_openfile(filename, 0, &diskfile))
+ {
+ strcpy(filename, tmpfilename);
+ strcat(filename,"-gz"); /* VMS suffix */
+ if (file_openfile(filename, 0, &diskfile))
+ {
+ strcpy(filename,tmpfilename); /* restore original name */
+ return(0); /* file not found */
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (fread(buffer, 1, 2, diskfile) != 2) /* read 2 bytes */
+ {
+ fclose(diskfile); /* error reading file so just return */
+ return(0);
+ }
+
+ fclose(diskfile);
+
+ /* see if the 2 bytes have the magic values for a compressed file */
+ if ( (memcmp(buffer, "\037\213", 2) == 0) || /* GZIP */
+ (memcmp(buffer, "\120\113", 2) == 0) || /* PKZIP */
+ (memcmp(buffer, "\037\036", 2) == 0) || /* PACK */
+ (memcmp(buffer, "\037\235", 2) == 0) || /* LZW */
+ (memcmp(buffer, "\037\240", 2) == 0) ) /* LZH */
+ {
+ return(1); /* this is a compressed file */
+ }
+ else
+ {
+ return(0); /* not a compressed file */
+ }
+}
+/*--------------------------------------------------------------------------*/
+int file_checkfile (char *urltype, char *infile, char *outfile)
+{
+ /* special case: if file:// driver, check if the file is compressed */
+ if ( file_is_compressed(infile) )
+ {
+ /* if output file has been specified, save the name for future use: */
+ /* This is the name of the uncompressed file to be created on disk. */
+ if (strlen(outfile))
+ {
+ if (!strncmp(outfile, "mem:", 4) )
+ {
+ /* uncompress the file in memory, with READ and WRITE access */
+ strcpy(urltype, "compressmem://"); /* use special driver */
+ *file_outfile = '\0';
+ }
+ else
+ {
+ strcpy(urltype, "compressfile://"); /* use special driver */
+
+ /* don't copy the "file://" prefix, if present. */
+ if (!strncmp(outfile, "file://", 7) )
+ strcpy(file_outfile,outfile+7);
+ else
+ strcpy(file_outfile,outfile);
+ }
+ }
+ else
+ {
+ /* uncompress the file in memory */
+ strcpy(urltype, "compress://"); /* use special driver */
+ *file_outfile = '\0'; /* no output file was specified */
+ }
+ }
+ else /* an ordinary, uncompressed FITS file on disk */
+ {
+ /* save the output file name for later use when opening the file. */
+ /* In this case, the file to be opened will be opened READONLY, */
+ /* and copied to this newly created output file. The original file */
+ /* will be closed, and the copy will be opened by CFITSIO for */
+ /* subsequent processing (possibly with READWRITE access). */
+ if (strlen(outfile))
+ strcpy(file_outfile,outfile);
+ }
+
+ return 0;
+}
+
+
+
diff --git a/pkg/tbtables/cfitsio/drvrmem.c b/pkg/tbtables/cfitsio/drvrmem.c
new file mode 100644
index 00000000..62bfd332
--- /dev/null
+++ b/pkg/tbtables/cfitsio/drvrmem.c
@@ -0,0 +1,1163 @@
+/* This file, drvrmem.c, contains driver routines for memory files. */
+
+/* The FITSIO software was written by William Pence at the High Energy */
+/* Astrophysic Science Archive Research Center (HEASARC) at the NASA */
+/* Goddard Space Flight Center. */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h> /* apparently needed to define size_t */
+#include "fitsio2.h"
+
+#define RECBUFLEN 1000
+
+static char stdin_outfile[FLEN_FILENAME];
+
+typedef struct /* structure containing mem file structure */
+{
+ char **memaddrptr; /* Pointer to memory address pointer; */
+ /* This may or may not point to memaddr. */
+ char *memaddr; /* Pointer to starting memory address; may */
+ /* not always be used, so use *memaddrptr instead */
+ size_t *memsizeptr; /* Pointer to the size of the memory allocation. */
+ /* This may or may not point to memsize. */
+ size_t memsize; /* Size of the memory allocation; this may not */
+ /* always be used, so use *memsizeptr instead. */
+ size_t deltasize; /* Suggested increment for reallocating memory */
+ void *(*mem_realloc)(void *p, size_t newsize); /* realloc function */
+ OFF_T currentpos; /* current file position, relative to start */
+ OFF_T fitsfilesize; /* size of the FITS file (always <= *memsizeptr) */
+ FILE *fileptr; /* pointer to compressed output disk file */
+} memdriver;
+
+static memdriver memTable[NMAXFILES]; /* allocate mem file handle tables */
+
+/*--------------------------------------------------------------------------*/
+int mem_init(void)
+{
+ int ii;
+
+ for (ii = 0; ii < NMAXFILES; ii++) /* initialize all empty slots in table */
+ {
+ memTable[ii].memaddrptr = 0;
+ memTable[ii].memaddr = 0;
+ }
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int mem_setoptions(int options)
+{
+ /* do something with the options argument, to stop compiler warning */
+ options = 0;
+ return(options);
+}
+/*--------------------------------------------------------------------------*/
+int mem_getoptions(int *options)
+{
+ *options = 0;
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int mem_getversion(int *version)
+{
+ *version = 10;
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int mem_shutdown(void)
+{
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int mem_create(char *filename, int *handle)
+/*
+ Create a new empty memory file for subsequent writes.
+ The file name is ignored in this case.
+*/
+{
+ int status;
+
+ /* initially allocate 1 FITS block = 2880 bytes */
+ status = mem_createmem(2880L, handle);
+
+ if (status)
+ {
+ ffpmsg("failed to create empty memory file (mem_create)");
+ return(status);
+ }
+
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int mem_create_comp(char *filename, int *handle)
+/*
+ Create a new empty memory file for subsequent writes.
+ Also create an empty compressed .gz file. The memory file
+ will be compressed and written to the disk file when the file is closed.
+*/
+{
+ FILE *diskfile;
+ char mode[4];
+ int status;
+
+ /* first, create disk file for the compressed output */
+
+
+ if ( !strcmp(filename, "-.gz") || !strcmp(filename, "stdout.gz") ||
+ !strcmp(filename, "STDOUT.gz") )
+ {
+ /* special case: create uncompressed FITS file in memory, then
+ compress it an write it out to 'stdout' when it is closed. */
+
+ diskfile = stdout;
+ }
+ else
+ {
+ /* normal case: create disk file for the compressed output */
+
+ strcpy(mode, "w+b"); /* create file with read-write */
+
+ diskfile = fopen(filename, "r"); /* does file already exist? */
+
+ if (diskfile)
+ {
+ fclose(diskfile); /* close file and exit with error */
+ return(FILE_NOT_CREATED);
+ }
+
+#if MACHINE == ALPHAVMS || MACHINE == VAXVMS
+ /* specify VMS record structure: fixed format, 2880 byte records */
+ /* but force stream mode access to enable random I/O access */
+ diskfile = fopen(filename, mode, "rfm=fix", "mrs=2880", "ctx=stm");
+#else
+ diskfile = fopen(filename, mode);
+#endif
+
+ if (!(diskfile)) /* couldn't create file */
+ {
+ return(FILE_NOT_CREATED);
+ }
+ }
+
+ /* now create temporary memory file */
+
+ /* initially allocate 1 FITS block = 2880 bytes */
+ status = mem_createmem(2880L, handle);
+
+ if (status)
+ {
+ ffpmsg("failed to create empty memory file (mem_create_comp)");
+ return(status);
+ }
+
+ memTable[*handle].fileptr = diskfile;
+
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int mem_openmem(void **buffptr, /* I - address of memory pointer */
+ size_t *buffsize, /* I - size of buffer, in bytes */
+ size_t deltasize, /* I - increment for future realloc's */
+ void *(*memrealloc)(void *p, size_t newsize), /* function */
+ int *handle)
+/*
+ lowest level routine to open a pre-existing memory file.
+*/
+{
+ int ii;
+
+ *handle = -1;
+ for (ii = 0; ii < NMAXFILES; ii++) /* find empty slot in handle table */
+ {
+ if (memTable[ii].memaddrptr == 0)
+ {
+ *handle = ii;
+ break;
+ }
+ }
+ if (*handle == -1)
+ return(TOO_MANY_FILES); /* too many files opened */
+
+ memTable[ii].memaddrptr = (char **) buffptr; /* pointer to start addres */
+ memTable[ii].memsizeptr = buffsize; /* allocated size of memory */
+ memTable[ii].deltasize = deltasize; /* suggested realloc increment */
+ memTable[ii].fitsfilesize = *buffsize; /* size of FITS file (upper limit) */
+ memTable[ii].currentpos = 0; /* at beginning of the file */
+ memTable[ii].mem_realloc = memrealloc; /* memory realloc function */
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int mem_createmem(size_t msize, int *handle)
+/*
+ lowest level routine to allocate a memory file.
+*/
+{
+ int ii;
+
+ *handle = -1;
+ for (ii = 0; ii < NMAXFILES; ii++) /* find empty slot in handle table */
+ {
+ if (memTable[ii].memaddrptr == 0)
+ {
+ *handle = ii;
+ break;
+ }
+ }
+ if (*handle == -1)
+ return(TOO_MANY_FILES); /* too many files opened */
+
+ /* use the internally allocated memaddr and memsize variables */
+ memTable[ii].memaddrptr = &memTable[ii].memaddr;
+ memTable[ii].memsizeptr = &memTable[ii].memsize;
+
+ /* allocate initial block of memory for the file */
+ if (msize > 0)
+ {
+ memTable[ii].memaddr = malloc(msize);
+ if ( !(memTable[ii].memaddr) )
+ {
+ ffpmsg("malloc of initial memory failed (mem_createmem)");
+ return(FILE_NOT_OPENED);
+ }
+ }
+
+ /* set initial state of the file */
+ memTable[ii].memsize = msize;
+ memTable[ii].deltasize = 2880;
+ memTable[ii].fitsfilesize = 0;
+ memTable[ii].currentpos = 0;
+ memTable[ii].mem_realloc = realloc;
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int mem_truncate(int handle, OFF_T filesize)
+/*
+ truncate the file to a new size
+*/
+{
+ char *ptr;
+
+ /* call the memory reallocation function, if defined */
+ if ( memTable[handle].mem_realloc )
+ {
+ ptr = (memTable[handle].mem_realloc)(
+ *(memTable[handle].memaddrptr),
+ filesize);
+ if (!ptr)
+ {
+ ffpmsg("Failed to reallocate memory (mem_truncate)");
+ return(MEMORY_ALLOCATION);
+ }
+
+ /* if allocated more memory, initialize it to zero */
+ if ( (size_t) filesize > *(memTable[handle].memsizeptr) )
+ {
+ memset(ptr + *(memTable[handle].memsizeptr),
+ 0,
+ filesize - *(memTable[handle].memsizeptr) );
+ }
+
+ *(memTable[handle].memaddrptr) = ptr;
+ *(memTable[handle].memsizeptr) = filesize;
+ }
+
+ memTable[handle].fitsfilesize = filesize;
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int stdin_checkfile(char *urltype, char *infile, char *outfile)
+/*
+ do any special case checking when opening a file on the stdin stream
+*/
+{
+ if (strlen(outfile))
+ {
+ strcpy(stdin_outfile,outfile); /* an output file is specified */
+ strcpy(urltype,"stdinfile://");
+ }
+ else
+ *stdin_outfile = '\0'; /* no output file was specified */
+
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int stdin_open(char *filename, int rwmode, int *handle)
+/*
+ open a FITS file from the stdin file stream by copying it into memory
+ The file name is ignored in this case.
+*/
+{
+ int status = 0;
+ char cbuff;
+
+ if (*stdin_outfile)
+ {
+ /* copy the stdin stream to the specified disk file then open the file */
+
+ /* Create the output file */
+ status = file_create(stdin_outfile,handle);
+
+ if (status)
+ {
+ ffpmsg("Unable to create output file to copy stdin (stdin_open):");
+ ffpmsg(stdin_outfile);
+ return(status);
+ }
+
+ /* copy the whole stdin stream to the file */
+ status = stdin2file(*handle);
+ file_close(*handle);
+
+ if (status)
+ {
+ ffpmsg("failed to copy stdin to file (stdin_open)");
+ ffpmsg(stdin_outfile);
+ return(status);
+ }
+
+ /* reopen file with proper rwmode attribute */
+ status = file_open(stdin_outfile, rwmode, handle);
+ }
+ else
+ {
+
+ /* get the first character, then put it back */
+ cbuff = fgetc(stdin);
+ ungetc(cbuff, stdin);
+
+ /* compressed files begin with 037 or 'P' */
+ if (cbuff == 31 || cbuff == 75)
+ {
+ /* looks like the input stream is compressed */
+ status = mem_compress_stdin_open(filename, rwmode, handle);
+
+ }
+ else
+ {
+ /* copy the stdin stream into memory then open file in memory */
+
+ if (rwmode != READONLY)
+ {
+ ffpmsg("cannot open stdin with WRITE access");
+ return(READONLY_FILE);
+ }
+
+ status = mem_createmem(2880L, handle);
+
+ if (status)
+ {
+ ffpmsg("failed to create empty memory file (stdin_open)");
+ return(status);
+ }
+
+ /* copy the whole stdin stream into memory */
+ status = stdin2mem(*handle);
+
+ if (status)
+ {
+ ffpmsg("failed to copy stdin into memory (stdin_open)");
+ free(memTable[*handle].memaddr);
+ }
+ }
+ }
+
+ return(status);
+}
+/*--------------------------------------------------------------------------*/
+int stdin2mem(int hd) /* handle number */
+/*
+ Copy the stdin stream into memory. Fill whatever amount of memory
+ has already been allocated, then realloc more memory if necessary.
+*/
+{
+ size_t nread, memsize, delta;
+ OFF_T filesize;
+ char *memptr;
+ char simple[] = "SIMPLE";
+ int c, ii, jj;
+
+ memptr = *memTable[hd].memaddrptr;
+ memsize = *memTable[hd].memsizeptr;
+ delta = memTable[hd].deltasize;
+
+ filesize = 0;
+ ii = 0;
+
+ for(jj = 0; (c = fgetc(stdin)) != EOF && jj < 2000; jj++)
+ {
+ /* Skip over any garbage at the beginning of the stdin stream by */
+ /* reading 1 char at a time, looking for 'S', 'I', 'M', 'P', 'L', 'E' */
+ /* Give up if not found in the first 2000 characters */
+
+ if (c == simple[ii])
+ {
+ ii++;
+ if (ii == 6) /* found the complete string? */
+ {
+ memcpy(memptr, simple, 6); /* copy "SIMPLE" to buffer */
+ filesize = 6;
+ break;
+ }
+ }
+ else
+ ii = 0; /* reset search to beginning of the string */
+ }
+
+ if (filesize == 0)
+ {
+ ffpmsg("Couldn't find the string 'SIMPLE' in the stdin stream.");
+ ffpmsg("This does not look like a FITS file.");
+ return(FILE_NOT_OPENED);
+ }
+
+ /* fill up the remainder of the initial memory allocation */
+ nread = fread(memptr + 6, 1, memsize - 6, stdin);
+ nread += 6; /* add in the 6 characters in 'SIMPLE' */
+
+ if (nread < memsize) /* reached the end? */
+ {
+ memTable[hd].fitsfilesize = nread;
+ return(0);
+ }
+
+ filesize = nread;
+
+ while (1)
+ {
+ /* allocate memory for another FITS block */
+ memptr = realloc(memptr, memsize + delta);
+
+ if (!memptr)
+ {
+ ffpmsg("realloc failed while copying stdin (stdin2mem)");
+ return(MEMORY_ALLOCATION);
+ }
+ memsize += delta;
+
+ /* read another FITS block */
+ nread = fread(memptr + filesize, 1, delta, stdin);
+
+ filesize += nread;
+
+ if (nread < delta) /* reached the end? */
+ break;
+ }
+
+ memTable[hd].fitsfilesize = filesize;
+ *memTable[hd].memaddrptr = memptr;
+ *memTable[hd].memsizeptr = memsize;
+
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int stdin2file(int handle) /* handle number */
+/*
+ Copy the stdin stream to a file. .
+*/
+{
+ size_t nread = 0;
+ char simple[] = "SIMPLE";
+ int c, ii, jj, status = 0;
+ char recbuf[RECBUFLEN];
+
+ ii = 0;
+ for(jj = 0; (c = fgetc(stdin)) != EOF && jj < 2000; jj++)
+ {
+ /* Skip over any garbage at the beginning of the stdin stream by */
+ /* reading 1 char at a time, looking for 'S', 'I', 'M', 'P', 'L', 'E' */
+ /* Give up if not found in the first 2000 characters */
+
+ if (c == simple[ii])
+ {
+ ii++;
+ if (ii == 6) /* found the complete string? */
+ {
+ memcpy(recbuf, simple, 6); /* copy "SIMPLE" to buffer */
+ break;
+ }
+ }
+ else
+ ii = 0; /* reset search to beginning of the string */
+ }
+
+ if (ii != 6)
+ {
+ ffpmsg("Couldn't find the string 'SIMPLE' in the stdin stream");
+ return(FILE_NOT_OPENED);
+ }
+
+ /* fill up the remainder of the buffer */
+ nread = fread(recbuf + 6, 1, RECBUFLEN - 6, stdin);
+ nread += 6; /* add in the 6 characters in 'SIMPLE' */
+
+ status = file_write(handle, recbuf, nread);
+ if (status)
+ return(status);
+
+ /* copy the rest of stdin stream */
+ while(0 != (nread = fread(recbuf,1,RECBUFLEN, stdin)))
+ {
+ status = file_write(handle, recbuf, nread);
+ if (status)
+ return(status);
+ }
+
+ return(status);
+}
+/*--------------------------------------------------------------------------*/
+int stdout_close(int handle)
+/*
+ copy the memory file to stdout, then free the memory
+*/
+{
+ int status = 0;
+
+ /* copy from memory to standard out */
+ if(fwrite(memTable[handle].memaddr, 1,
+ memTable[handle].fitsfilesize, stdout) !=
+ (size_t) memTable[handle].fitsfilesize )
+ {
+ ffpmsg("failed to copy memory file to stdout (stdout_close)");
+ status = WRITE_ERROR;
+ }
+
+ free( memTable[handle].memaddr ); /* free the memory */
+ memTable[handle].memaddrptr = 0;
+ memTable[handle].memaddr = 0;
+ return(status);
+}
+/*--------------------------------------------------------------------------*/
+int mem_compress_openrw(char *filename, int rwmode, int *hdl)
+/*
+ This routine opens the compressed diskfile and creates an empty memory
+ buffer with an appropriate size, then calls mem_uncompress2mem. It allows
+ the memory 'file' to be opened with READWRITE access.
+*/
+{
+ return(mem_compress_open(filename, READONLY, hdl));
+}
+/*--------------------------------------------------------------------------*/
+int mem_compress_open(char *filename, int rwmode, int *hdl)
+/*
+ This routine opens the compressed diskfile and creates an empty memory
+ buffer with an appropriate size, then calls mem_uncompress2mem.
+*/
+{
+ FILE *diskfile;
+ int status, estimated = 1;
+ unsigned char buffer[4];
+ size_t finalsize;
+ char *ptr;
+
+ if (rwmode != READONLY)
+ {
+ ffpmsg(
+ "cannot open compressed file with WRITE access (mem_compress_open)");
+ ffpmsg(filename);
+ return(READONLY_FILE);
+ }
+
+ /* open the compressed disk file */
+ status = file_openfile(filename, READONLY, &diskfile);
+ if (status)
+ {
+ ffpmsg("failed to open compressed disk file (compress_open)");
+ ffpmsg(filename);
+ return(status);
+ }
+
+ if (fread(buffer, 1, 2, diskfile) != 2) /* read 2 bytes */
+ {
+ fclose(diskfile);
+ return(READ_ERROR);
+ }
+
+ if (memcmp(buffer, "\037\213", 2) == 0) /* GZIP */
+ {
+ /* the uncompressed file size is give at the end of the file */
+
+ fseek(diskfile, 0, 2); /* move to end of file */
+ fseek(diskfile, -4L, 1); /* move back 4 bytes */
+ fread(buffer, 1, 4L, diskfile); /* read 4 bytes */
+
+ /* have to worry about integer byte order */
+ finalsize = buffer[0];
+ finalsize |= buffer[1] << 8;
+ finalsize |= buffer[2] << 16;
+ finalsize |= buffer[3] << 24;
+
+ estimated = 0; /* file size is known, not estimated */
+ }
+ else if (memcmp(buffer, "\120\113", 2) == 0) /* PKZIP */
+ {
+ /* the uncompressed file size is give at byte 22 the file */
+
+ fseek(diskfile, 22L, 0); /* move to byte 22 */
+ fread(buffer, 1, 4L, diskfile); /* read 4 bytes */
+
+ /* have to worry about integer byte order */
+ finalsize = buffer[0];
+ finalsize |= buffer[1] << 8;
+ finalsize |= buffer[2] << 16;
+ finalsize |= buffer[3] << 24;
+
+ estimated = 0; /* file size is known, not estimated */
+ }
+ else if (memcmp(buffer, "\037\036", 2) == 0) /* PACK */
+ finalsize = 0; /* for most methods we can't determine final size */
+ else if (memcmp(buffer, "\037\235", 2) == 0) /* LZW */
+ finalsize = 0; /* for most methods we can't determine final size */
+ else if (memcmp(buffer, "\037\240", 2) == 0) /* LZH */
+ finalsize = 0; /* for most methods we can't determine final size */
+ else
+ {
+ /* not a compressed file; this should never happen */
+ fclose(diskfile);
+ return(1);
+ }
+
+ if (finalsize == 0) /* estimate uncompressed file size */
+ {
+ fseek(diskfile, 0, 2); /* move to end of the compressed file */
+ finalsize = ftell(diskfile); /* position = size of file */
+ finalsize = finalsize * 3; /* assume factor of 3 compression */
+ }
+
+ fseek(diskfile, 0, 0); /* move back to beginning of file */
+
+ /* create a memory file big enough (hopefully) for the uncompressed file */
+ status = mem_createmem(finalsize, hdl);
+
+ if (status && estimated)
+ {
+ /* memory allocation failed, so try a smaller estimated size */
+ finalsize = finalsize / 3;
+ status = mem_createmem(finalsize, hdl);
+ }
+
+ if (status)
+ {
+ fclose(diskfile);
+ ffpmsg("failed to create empty memory file (compress_open)");
+ return(status);
+ }
+
+ /* uncompress file into memory */
+ status = mem_uncompress2mem(filename, diskfile, *hdl);
+
+ fclose(diskfile);
+
+ if (status)
+ {
+ mem_close_free(*hdl); /* free up the memory */
+ ffpmsg("failed to uncompress file into memory (compress_open)");
+ return(status);
+ }
+
+ /* if we allocated too much memory initially, then free it */
+ if (*(memTable[*hdl].memsizeptr) >
+ (( (size_t) memTable[*hdl].fitsfilesize) + 256L) )
+ {
+ ptr = realloc(*(memTable[*hdl].memaddrptr),
+ memTable[*hdl].fitsfilesize);
+ if (!ptr)
+ {
+ ffpmsg("Failed to reduce size of allocated memory (compress_open)");
+ return(MEMORY_ALLOCATION);
+ }
+
+ *(memTable[*hdl].memaddrptr) = ptr;
+ *(memTable[*hdl].memsizeptr) = memTable[*hdl].fitsfilesize;
+ }
+
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int mem_compress_stdin_open(char *filename, int rwmode, int *hdl)
+/*
+ This routine reads the compressed input stream and creates an empty memory
+ buffer, then calls mem_uncompress2mem.
+*/
+{
+ int status;
+ char *ptr;
+
+ if (rwmode != READONLY)
+ {
+ ffpmsg(
+ "cannot open compressed input stream with WRITE access (mem_compress_stdin_open)");
+ return(READONLY_FILE);
+ }
+
+ /* create a memory file for the uncompressed file */
+ status = mem_createmem(28800, hdl);
+
+ if (status)
+ {
+ ffpmsg("failed to create empty memory file (compress_stdin_open)");
+ return(status);
+ }
+
+ /* uncompress file into memory */
+ status = mem_uncompress2mem(filename, stdin, *hdl);
+
+ if (status)
+ {
+ mem_close_free(*hdl); /* free up the memory */
+ ffpmsg("failed to uncompress stdin into memory (compress_stdin_open)");
+ return(status);
+ }
+
+ /* if we allocated too much memory initially, then free it */
+ if (*(memTable[*hdl].memsizeptr) >
+ (( (size_t) memTable[*hdl].fitsfilesize) + 256L) )
+ {
+ ptr = realloc(*(memTable[*hdl].memaddrptr),
+ memTable[*hdl].fitsfilesize);
+ if (!ptr)
+ {
+ ffpmsg("Failed to reduce size of allocated memory (compress_stdin_open)");
+ return(MEMORY_ALLOCATION);
+ }
+
+ *(memTable[*hdl].memaddrptr) = ptr;
+ *(memTable[*hdl].memsizeptr) = memTable[*hdl].fitsfilesize;
+ }
+
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int mem_iraf_open(char *filename, int rwmode, int *hdl)
+/*
+ This routine creates an empty memory buffer, then calls iraf2mem to
+ open the IRAF disk file and convert it to a FITS file in memeory.
+*/
+{
+ int status;
+ size_t filesize = 0;
+
+ /* create a memory file with size = 0 for the FITS converted IRAF file */
+ status = mem_createmem(filesize, hdl);
+ if (status)
+ {
+ ffpmsg("failed to create empty memory file (mem_iraf_open)");
+ return(status);
+ }
+
+ /* convert the iraf file into a FITS file in memory */
+ status = iraf2mem(filename, memTable[*hdl].memaddrptr,
+ memTable[*hdl].memsizeptr, &filesize, &status);
+
+ if (status)
+ {
+ mem_close_free(*hdl); /* free up the memory */
+ ffpmsg("failed to convert IRAF file into memory (mem_iraf_open)");
+ return(status);
+ }
+
+ memTable[*hdl].currentpos = 0; /* save starting position */
+ memTable[*hdl].fitsfilesize=filesize; /* and initial file size */
+
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int mem_rawfile_open(char *filename, int rwmode, int *hdl)
+/*
+ This routine creates an empty memory buffer, writes a minimal
+ image header, then copies the image data from the raw file into
+ memory. It will byteswap the pixel values if the raw array
+ is in little endian byte order.
+*/
+{
+ FILE *diskfile;
+ fitsfile *fptr;
+ short *sptr;
+ int status, endian, datatype, bytePerPix, naxis;
+ long dim[5] = {1,1,1,1,1}, ii, nvals, offset = 0;
+ size_t filesize = 0, datasize;
+ char rootfile[FLEN_FILENAME], *cptr = 0, *cptr2 = 0;
+ void *ptr;
+
+ if (rwmode != READONLY)
+ {
+ ffpmsg(
+ "cannot open raw binary file with WRITE access (mem_rawfile_open)");
+ ffpmsg(filename);
+ return(READONLY_FILE);
+ }
+
+ cptr = strchr(filename, '['); /* search for opening bracket [ */
+
+ if (!cptr)
+ {
+ ffpmsg("binary file name missing '[' character (mem_rawfile_open)");
+ ffpmsg(filename);
+ return(URL_PARSE_ERROR);
+ }
+
+ *rootfile = '\0';
+ strncat(rootfile, filename, cptr - filename); /* store the rootname */
+
+ cptr++;
+
+ while (*cptr == ' ')
+ cptr++; /* skip leading blanks */
+
+ /* Get the Data Type of the Image */
+
+ if (*cptr == 'b' || *cptr == 'B')
+ {
+ datatype = BYTE_IMG;
+ bytePerPix = 1;
+ }
+ else if (*cptr == 'i' || *cptr == 'I')
+ {
+ datatype = SHORT_IMG;
+ bytePerPix = 2;
+ }
+ else if (*cptr == 'u' || *cptr == 'U')
+ {
+ datatype = USHORT_IMG;
+ bytePerPix = 2;
+
+ }
+ else if (*cptr == 'j' || *cptr == 'J')
+ {
+ datatype = LONG_IMG;
+ bytePerPix = 4;
+ }
+ else if (*cptr == 'r' || *cptr == 'R' || *cptr == 'f' || *cptr == 'F')
+ {
+ datatype = FLOAT_IMG;
+ bytePerPix = 4;
+ }
+ else if (*cptr == 'd' || *cptr == 'D')
+ {
+ datatype = DOUBLE_IMG;
+ bytePerPix = 8;
+ }
+ else
+ {
+ ffpmsg("error in raw binary file datatype (mem_rawfile_open)");
+ ffpmsg(filename);
+ return(URL_PARSE_ERROR);
+ }
+
+ cptr++;
+
+ /* get Endian: Big or Little; default is same as the local machine */
+
+ if (*cptr == 'b' || *cptr == 'B')
+ {
+ endian = 0;
+ cptr++;
+ }
+ else if (*cptr == 'l' || *cptr == 'L')
+ {
+ endian = 1;
+ cptr++;
+ }
+ else
+ endian = BYTESWAPPED; /* byteswapped machines are little endian */
+
+ /* read each dimension (up to 5) */
+
+ naxis = 1;
+ dim[0] = strtol(cptr, &cptr2, 10);
+
+ if (cptr2 && *cptr2 == ',')
+ {
+ naxis = 2;
+ dim[1] = strtol(cptr2+1, &cptr, 10);
+
+ if (cptr && *cptr == ',')
+ {
+ naxis = 3;
+ dim[2] = strtol(cptr+1, &cptr2, 10);
+
+ if (cptr2 && *cptr2 == ',')
+ {
+ naxis = 4;
+ dim[3] = strtol(cptr2+1, &cptr, 10);
+
+ if (cptr && *cptr == ',')
+ naxis = 5;
+ dim[4] = strtol(cptr+1, &cptr2, 10);
+ }
+ }
+ }
+
+ cptr = maxvalue(cptr, cptr2);
+
+ if (*cptr == ':') /* read starting offset value */
+ offset = strtol(cptr+1, 0, 10);
+
+ nvals = dim[0] * dim[1] * dim[2] * dim[3] * dim[4];
+ datasize = nvals * bytePerPix;
+ filesize = nvals * bytePerPix + 2880;
+ filesize = ((filesize - 1) / 2880 + 1) * 2880;
+
+ /* open the raw binary disk file */
+ status = file_openfile(rootfile, READONLY, &diskfile);
+ if (status)
+ {
+ ffpmsg("failed to open raw binary file (mem_rawfile_open)");
+ ffpmsg(rootfile);
+ return(status);
+ }
+
+ /* create a memory file with corrct size for the FITS converted raw file */
+ status = mem_createmem(filesize, hdl);
+ if (status)
+ {
+ ffpmsg("failed to create memory file (mem_rawfile_open)");
+ fclose(diskfile);
+ return(status);
+ }
+
+ /* open this piece of memory as a new FITS file */
+ ffimem(&fptr, (void **) memTable[*hdl].memaddrptr, &filesize, 0, 0, &status);
+
+ /* write the required header keywords */
+ ffcrim(fptr, datatype, naxis, dim, &status);
+
+ /* close the FITS file, but keep the memory allocated */
+ ffclos(fptr, &status);
+
+ if (status > 0)
+ {
+ ffpmsg("failed to write basic image header (mem_rawfile_open)");
+ fclose(diskfile);
+ mem_close_free(*hdl); /* free up the memory */
+ return(status);
+ }
+
+ if (offset > 0)
+ fseek(diskfile, offset, 0); /* offset to start of the data */
+
+ /* read the raw data into memory */
+ ptr = *memTable[*hdl].memaddrptr + 2880;
+
+ if (fread((char *) ptr, 1, datasize, diskfile) != datasize)
+ status = READ_ERROR;
+
+ fclose(diskfile); /* close the raw binary disk file */
+
+ if (status)
+ {
+ mem_close_free(*hdl); /* free up the memory */
+ ffpmsg("failed to copy raw file data into memory (mem_rawfile_open)");
+ return(status);
+ }
+
+ if (datatype == USHORT_IMG) /* have to subtract 32768 from each unsigned */
+ { /* value to conform to FITS convention. More */
+ /* efficient way to do this is to just flip */
+ /* the most significant bit. */
+
+ sptr = (short *) ptr;
+
+ if (endian == BYTESWAPPED) /* working with native format */
+ {
+ for (ii = 0; ii < nvals; ii++, sptr++)
+ {
+ *sptr = ( *sptr ) ^ 0x8000;
+ }
+ }
+ else /* pixels are byteswapped WRT the native format */
+ {
+ for (ii = 0; ii < nvals; ii++, sptr++)
+ {
+ *sptr = ( *sptr ) ^ 0x80;
+ }
+ }
+ }
+
+ if (endian) /* swap the bytes if array is in little endian byte order */
+ {
+ if (datatype == SHORT_IMG || datatype == USHORT_IMG)
+ {
+ ffswap2( (short *) ptr, nvals);
+ }
+ else if (datatype == LONG_IMG || datatype == FLOAT_IMG)
+ {
+ ffswap4( (INT32BIT *) ptr, nvals);
+ }
+
+ else if (datatype == DOUBLE_IMG)
+ {
+ ffswap8( (double *) ptr, nvals);
+ }
+ }
+
+ memTable[*hdl].currentpos = 0; /* save starting position */
+ memTable[*hdl].fitsfilesize=filesize; /* and initial file size */
+
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int mem_uncompress2mem(char *filename, FILE *diskfile, int hdl)
+{
+/*
+ lower level routine to uncompress a file into memory. The file
+ has already been opened and the memory buffer has been allocated.
+*/
+
+ size_t finalsize;
+ int status;
+ /* uncompress file into memory */
+ status = 0;
+ uncompress2mem(filename, diskfile,
+ memTable[hdl].memaddrptr, /* pointer to memory address */
+ memTable[hdl].memsizeptr, /* pointer to size of memory */
+ realloc, /* reallocation function */
+ &finalsize, &status); /* returned file size nd status*/
+ memTable[hdl].currentpos = 0; /* save starting position */
+ memTable[hdl].fitsfilesize=finalsize; /* and initial file size */
+ return status;
+}
+/*--------------------------------------------------------------------------*/
+int mem_size(int handle, OFF_T *filesize)
+/*
+ return the size of the file; only called when the file is first opened
+*/
+{
+ *filesize = memTable[handle].fitsfilesize;
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int mem_close_free(int handle)
+/*
+ close the file and free the memory.
+*/
+{
+ free( *(memTable[handle].memaddrptr) );
+
+ memTable[handle].memaddrptr = 0;
+ memTable[handle].memaddr = 0;
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int mem_close_keep(int handle)
+/*
+ close the memory file but do not free the memory.
+*/
+{
+ memTable[handle].memaddrptr = 0;
+ memTable[handle].memaddr = 0;
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int mem_close_comp(int handle)
+/*
+ compress the memory file, writing it out to the fileptr (which might
+ be stdout)
+*/
+{
+ int status = 0;
+ size_t compsize;
+
+ /* compress file in memory to a .gz disk file */
+
+ if(compress2file_from_mem(memTable[handle].memaddr,
+ memTable[handle].fitsfilesize,
+ memTable[handle].fileptr,
+ &compsize, &status ) )
+ {
+ ffpmsg("failed to copy memory file to file (mem_close_comp)");
+ status = WRITE_ERROR;
+ }
+
+ free( memTable[handle].memaddr ); /* free the memory */
+ memTable[handle].memaddrptr = 0;
+ memTable[handle].memaddr = 0;
+
+ /* close the compressed disk file (except if it is 'stdout' */
+ if (memTable[handle].fileptr != stdout)
+ fclose(memTable[handle].fileptr);
+
+ return(status);
+}
+/*--------------------------------------------------------------------------*/
+int mem_seek(int handle, OFF_T offset)
+/*
+ seek to position relative to start of the file.
+*/
+{
+ if (offset > (OFF_T) memTable[handle].fitsfilesize )
+ return(END_OF_FILE);
+
+ memTable[handle].currentpos = offset;
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int mem_read(int hdl, void *buffer, long nbytes)
+/*
+ read bytes from the current position in the file
+*/
+{
+ if (memTable[hdl].currentpos + nbytes > memTable[hdl].fitsfilesize)
+ return(END_OF_FILE);
+
+ memcpy(buffer,
+ *(memTable[hdl].memaddrptr) + memTable[hdl].currentpos,
+ nbytes);
+
+ memTable[hdl].currentpos += nbytes;
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int mem_write(int hdl, void *buffer, long nbytes)
+/*
+ write bytes at the current position in the file
+*/
+{
+ size_t newsize;
+ char *ptr;
+
+ if ((size_t) (memTable[hdl].currentpos + nbytes) >
+ *(memTable[hdl].memsizeptr) )
+ {
+
+ if (!(memTable[hdl].mem_realloc))
+ {
+ ffpmsg("realloc function not defined (mem_write)");
+ return(WRITE_ERROR);
+ }
+
+ /*
+ Attempt to reallocate additional memory:
+ the memory buffer size is incremented by the larger of:
+ 1 FITS block (2880 bytes) or
+ the defined 'deltasize' parameter
+ */
+
+ newsize = maxvalue( (size_t)
+ (((memTable[hdl].currentpos + nbytes - 1) / 2880) + 1) * 2880,
+ *(memTable[hdl].memsizeptr) + memTable[hdl].deltasize);
+
+ /* call the realloc function */
+ ptr = (memTable[hdl].mem_realloc)(
+ *(memTable[hdl].memaddrptr),
+ newsize);
+ if (!ptr)
+ {
+ ffpmsg("Failed to reallocate memory (mem_write)");
+ return(MEMORY_ALLOCATION);
+ }
+
+ *(memTable[hdl].memaddrptr) = ptr;
+ *(memTable[hdl].memsizeptr) = newsize;
+ }
+
+ /* now copy the bytes from the buffer into memory */
+ memcpy( *(memTable[hdl].memaddrptr) + memTable[hdl].currentpos,
+ buffer,
+ nbytes);
+
+ memTable[hdl].currentpos += nbytes;
+ memTable[hdl].fitsfilesize =
+ maxvalue(memTable[hdl].fitsfilesize,
+ memTable[hdl].currentpos);
+ return(0);
+}
diff --git a/pkg/tbtables/cfitsio/drvrnet.c b/pkg/tbtables/cfitsio/drvrnet.c
new file mode 100644
index 00000000..1f06f03b
--- /dev/null
+++ b/pkg/tbtables/cfitsio/drvrnet.c
@@ -0,0 +1,2587 @@
+/* This file, drvrhttp.c contains driver routines for http, ftp and root
+ files. */
+
+/* This file was written by Bruce O'Neel at the ISDC, Switzerland */
+/* The FITSIO software is maintained by William Pence at the High Energy */
+/* Astrophysic Science Archive Research Center (HEASARC) at the NASA */
+/* Goddard Space Flight Center. */
+
+
+/* Notes on the drivers:
+
+ The ftp driver uses passive mode exclusivly. If your remote system can't
+ deal with passive mode then it'll fail. Since Netscape Navigator uses
+ passive mode as well there shouldn't be too many ftp servers which have
+ problems.
+
+
+ The http driver works properly with 301 and 302 redirects. For many more
+ gory details see http://www.w3c.org/Protocols/rfc2068/rfc2068. The only
+ catch to the 301/302 redirects is that they have to redirect to another
+ http:// url. If not, things would have to change a lot in cfitsio and this
+ was thought to be too difficult.
+
+ Redirects look like
+
+
+ <HTML><HEAD>
+ <TITLE>301 Moved Permanently</TITLE>
+ </HEAD><BODY>
+ <H1>Moved Permanently</H1>
+ The document has moved <A HREF="http://heasarc.gsfc.nasa.gov/FTP/software/ftools/release/other/image.fits.gz">here</A>.<P>
+ </BODY></HTML>
+
+ This redirect was from apache 1.2.5 but most of the other servers produce
+ something very similiar. The parser for the redirects finds the first
+ anchor <A> tag in the body and goes there. If that wasn't what was intended
+ by the remote system then hopefully the error stack, which includes notes
+ about the redirect will help the user fix the problem.
+
+
+
+ Root protocal doesn't have any real docs, so, the emperical docs are as
+ follows.
+
+ First, you must use a slightly modified rootd server. The modifications
+ include implimentation of the stat command which returns the size of the
+ remote file. Without that it's impossible for cfitsio to work properly
+ since fitsfiles don't include any information about the size of the files
+ in the headers. The rootd server closes the connections on any errors,
+ including reading beyond the end of the file or seeking beyond the end
+ of the file. The rootd:// driver doesn't reopen a closed connection, if
+ the connection is closed you're pretty much done.
+
+ The messages are of the form
+
+ <len><opcode><optional information>
+
+ All binary information is transfered in network format, so use htonl and
+ ntohl to convert back and forth.
+
+ <len> :== 4 byte length, in network format, the len doesn't include the
+ length of <len>
+ <opcode> :== one of the message opcodes below, 4 bytes, network format
+ <optional info> :== depends on opcode
+
+ The response is of the same form with the same opcode sent. Success is
+ indicated by <optional info> being 0.
+
+ Root is a NFSish protocol where each read/write includes the byte
+ offset to read or write to. As a result, seeks will always succeed
+ in the driver even if they would cause a fatal error when you try
+ to read because you're beyond the end of the file.
+
+ There is file locking on the host such that you need to possibly
+ create /usr/tmp/rootdtab on the host system. There is one file per
+ socket connection, though the rootd daemon can support multiple
+ files open at once.
+
+ The messages are sent in the following order:
+
+ ROOTD_USER - user name, <optional info> is the user name, trailing
+ null is sent though it's not required it seems. A ROOTD_AUTH
+ message is returned with any sort of error meaning that the user
+ name is wrong.
+
+ ROOTD_PASS - password, ones complemented, stored in <optional info>. Once
+ again the trailing null is sent. Once again a ROOTD_AUTH message is
+ returned
+
+ ROOTD_OPEN - <optional info> includes filename and one of
+ {create|update|read} as the file mode. ~ seems to be dealt with
+ as the username's login directory. A ROOTD_OPEN message is
+ returned.
+
+ Once the file is opened any of the following can be sent:
+
+ ROOTD_STAT - file status and size
+ returns a message where <optional info> is the file length in bytes
+
+ ROOTD_FLUSH - flushes the file, not sure this has any real effect
+ on the daemon since the daemon uses open/read/write/close rather
+ than the buffered fopen/fread/fwrite/fclose.
+
+ ROOTD_GET - on send <optional info> includes a text message of
+ offset and length to get. Return is a status message first with a
+ status value, then, the raw bytes for the length that you
+ requested. It's an error to seek or read past the end of the file,
+ and, the rootd daemon exits and won't respond anymore. Ie, don't
+ do this.
+
+ ROOTD_PUT - on send <optional info> includes a text message of
+ offset and length to put. Then send the raw bytes you want to
+ write. Then recieve a status message
+
+
+ When you are finished then you send the message:
+
+ ROOTD_CLOSE - closes the file
+
+ Once the file is closed then the socket is closed.
+
+$Id: drvrnet.c,v 1.6 2002/02/22 14:15:45 hodge Exp $
+
+$Log: drvrnet.c,v $
+Revision 1.6 2002/02/22 14:15:45 hodge
+Install latest version (2.401) of CFITSIO. OPR 45286
+
+Revision 1.56 2000/01/04 11:58:31 oneel
+Updates so that compressed network files are dealt with regardless of
+their file names and/or mime types.
+
+Revision 1.55 2000/01/04 10:52:40 oneel
+cfitsio 2.034
+
+Revision 1.51 1999/08/10 12:13:40 oneel
+Make the http code a bit less picky about the types of files it
+uncompresses. Now it also uncompresses files which end in .Z or .gz.
+
+Revision 1.50 1999/08/04 12:38:46 oneel
+Don's 2.0.32 patch with dal 1.3
+
+Revision 1.39 1998/12/02 15:31:33 oneel
+Updates to drvrnet.c so that less compiler warnings would be
+generated. Fixes the signal handling.
+
+Revision 1.38 1998/11/23 10:03:24 oneel
+Added in a useragent string, as suggested by:
+Tim Kimball · Data Systems Division ¦ kimball@stsci.edu · 410-338-4417
+Space Telescope Science Institute ¦ http://www.stsci.edu/~kimball/
+3700 San Martin Drive ¦ http://archive.stsci.edu/
+Baltimore MD 21218 USA ¦ http://faxafloi.stsci.edu:4547/
+
+
+ */
+
+#ifdef HAVE_NET_SERVICES
+#include <string.h>
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <setjmp.h>
+#include "fitsio2.h"
+
+static jmp_buf env; /* holds the jump buffer for setjmp/longjmp pairs */
+static void signal_handler(int sig);
+
+
+/* Network routine error codes */
+#define NET_OK 0
+#define NOT_INET_ADDRESS -1000
+#define UNKNOWN_INET_HOST -1001
+#define CONNECTION_ERROR -1002
+
+/* Network routine constants */
+#define NET_DEFAULT 0
+#define NET_OOB 1
+#define NET_PEEK 2
+
+#define NETTIMEOUT 180 /* in secs */
+
+/* local defines and variables */
+#define MAXLEN 1200
+#define SHORTLEN 100
+static char netoutfile[MAXLEN];
+
+
+#define ROOTD_USER 2000 /*user id follows */
+#define ROOTD_PASS 2001 /*passwd follows */
+#define ROOTD_AUTH 2002 /*authorization status (to client) */
+#define ROOTD_FSTAT 2003 /*filename follows */
+#define ROOTD_OPEN 2004 /*filename follows + mode */
+#define ROOTD_PUT 2005 /*offset, number of bytes and buffer */
+#define ROOTD_GET 2006 /*offset, number of bytes */
+#define ROOTD_FLUSH 2007 /*flush file */
+#define ROOTD_CLOSE 2008 /*close file */
+#define ROOTD_STAT 2009 /*return rootd statistics */
+#define ROOTD_ACK 2010 /*acknowledgement (all OK) */
+#define ROOTD_ERR 2011 /*error code and message follow */
+
+typedef struct /* structure containing disk file structure */
+{
+ int sock;
+ OFF_T currentpos;
+} rootdriver;
+
+static rootdriver handleTable[NIOBUF]; /* allocate diskfile handle tables */
+
+/* static prototypes */
+
+static int NET_TcpConnect(char *hostname, int port);
+static int NET_SendRaw(int sock, const void *buf, int length, int opt);
+static int NET_RecvRaw(int sock, void *buffer, int length);
+static int NET_ParseUrl(const char *url, char *proto, char *host, int *port,
+ char *fn);
+static int CreateSocketAddress(struct sockaddr_in *sockaddrPtr,
+ char *host,int port);
+static int ftp_status(FILE *ftp, char *statusstr);
+static int http_open_network(char *url, FILE **httpfile, char *contentencoding,
+ int *contentlength);
+static int ftp_open_network(char *url, FILE **ftpfile, FILE **command,
+ int *sock);
+
+static int root_send_buffer(int sock, int op, char *buffer, int buflen);
+static int root_recv_buffer(int sock, int *op, char *buffer,int buflen);
+static int root_openfile(char *filename, char *rwmode, int *sock);
+
+/***************************/
+/* Static variables */
+
+static int closehttpfile;
+static int closememfile;
+static int closefdiskfile;
+static int closediskfile;
+static int closefile;
+static int closeoutfile;
+static int closecommandfile;
+static int closeftpfile;
+static FILE *diskfile;
+static FILE *outfile;
+
+/*--------------------------------------------------------------------------*/
+/* This creates a memory file handle with a copy of the URL in filename. The
+ file is uncompressed if necessary */
+
+int http_open(char *filename, int rwmode, int *handle)
+{
+
+ FILE *httpfile;
+ char contentencoding[SHORTLEN];
+ char newfilename[MAXLEN];
+ char errorstr[MAXLEN];
+ char recbuf[MAXLEN];
+ long len;
+ int contentlength;
+ int status;
+ char firstchar;
+
+ closehttpfile = 0;
+ closememfile = 0;
+
+ /* don't do r/w files */
+ if (rwmode != 0) {
+ ffpmsg("Can't open http:// type file with READWRITE access");
+ ffpmsg(" Specify an outfile for r/w access (http_open)");
+ goto error;
+ }
+
+ /* do the signal handler bits */
+ if (setjmp(env) != 0) {
+ /* feels like the second time */
+ /* this means something bad happened */
+ ffpmsg("Timeout (http_open)");
+ goto error;
+ }
+
+ (void) signal(SIGALRM, signal_handler);
+
+ /* Open the network connection */
+
+ /* Does the file have a .Z or .gz in it */
+ /* Also, if file has a '?' in it (probably cgi script) */
+ if (strstr(filename,".Z") || strstr(filename,".gz") ||
+ strstr(filename,"?")) {
+ alarm(NETTIMEOUT);
+ if (http_open_network(filename,&httpfile,contentencoding,
+ &contentlength)) {
+ alarm(0);
+ ffpmsg("Unable to open http file (http_open):");
+ ffpmsg(filename);
+ goto error;
+ }
+ } else {
+ alarm(NETTIMEOUT);
+ /* Try the .gz one */
+ strcpy(newfilename,filename);
+ strcat(newfilename,".gz");
+
+ if (http_open_network(newfilename,&httpfile,contentencoding,
+ &contentlength)) {
+ alarm(0);
+ /* Now the .Z one */
+ strcpy(newfilename,filename);
+ strcat(newfilename,".Z");
+ alarm(NETTIMEOUT);
+ if (http_open_network(newfilename,&httpfile,contentencoding,
+ &contentlength)) {
+ alarm(0);
+ alarm(NETTIMEOUT);
+ if (http_open_network(filename,&httpfile,contentencoding,
+ &contentlength)) {
+ alarm(0);
+ ffpmsg("Unable to open http file (http_open)");
+ ffpmsg(filename);
+ goto error;
+ }
+ }
+ }
+ }
+
+ closehttpfile++;
+
+ /* Create the memory file */
+ if ((status = mem_create(filename,handle))) {
+ ffpmsg("Unable to create memory file (http_open)");
+ goto error;
+ }
+
+ closememfile++;
+
+ /* Now, what do we do with the file */
+ /* Check to see what the first character is */
+ firstchar = fgetc(httpfile);
+ ungetc(firstchar,httpfile);
+ if (!strcmp(contentencoding,"x-gzip") ||
+ !strcmp(contentencoding,"x-compress") ||
+ strstr(filename,".gz") ||
+ strstr(filename,".Z") ||
+ ('\037' == firstchar)) {
+ /* do the compress dance, which is the same as the gzip dance */
+ /* Using the cfitsio routine */
+
+ status = 0;
+ /* Ok, this is a tough case, let's be arbritary and say 10*NETTIMEOUT,
+ Given the choices for nettimeout above they'll probaby ^C before, but
+ it's always worth a shot*/
+
+ alarm(NETTIMEOUT*10);
+ status = mem_uncompress2mem(filename, httpfile, *handle);
+ alarm(0);
+ if (status) {
+ ffpmsg("Error writing compressed memory file (http_open)");
+ ffpmsg(filename);
+ goto error;
+ }
+
+ } else {
+ /* It's not compressed, bad choice, but we'll copy it anyway */
+ if (contentlength % 2880) {
+ sprintf(errorstr,"Content-Length not a multiple of 2880 (http_open) %d",
+ contentlength);
+ ffpmsg(errorstr);
+ }
+
+ /* write a memory file */
+ alarm(NETTIMEOUT);
+ while(0 != (len = fread(recbuf,1,MAXLEN,httpfile))) {
+ alarm(0); /* cancel alarm */
+ status = mem_write(*handle,recbuf,len);
+ if (status) {
+ ffpmsg("Error copying http file into memory (http_open)");
+ ffpmsg(filename);
+ goto error;
+ }
+ alarm(NETTIMEOUT); /* rearm the alarm */
+ }
+ }
+
+ fclose(httpfile);
+
+ signal(SIGALRM, SIG_DFL);
+ alarm(0);
+ return mem_seek(*handle,0);
+
+ error:
+ alarm(0); /* clear it */
+ if (closehttpfile) {
+ fclose(httpfile);
+ }
+ if (closememfile) {
+ mem_close_free(*handle);
+ }
+
+ signal(SIGALRM, SIG_DFL);
+ return (FILE_NOT_OPENED);
+}
+/*--------------------------------------------------------------------------*/
+/* This creates a memory file handle with a copy of the URL in filename. The
+ file must be compressed and is copied (still compressed) to disk first.
+ The compressed disk file is then uncompressed into memory (READONLY).
+*/
+
+int http_compress_open(char *url, int rwmode, int *handle)
+{
+ FILE *httpfile;
+ char contentencoding[SHORTLEN];
+ char recbuf[MAXLEN];
+ long len;
+ int contentlength;
+ int ii, flen, status;
+ char firstchar;
+
+ closehttpfile = 0;
+ closediskfile = 0;
+ closefdiskfile = 0;
+ closememfile = 0;
+
+ /* cfileio made a mistake, should set the netoufile first otherwise
+ we don't know where to write the output file */
+
+ flen = strlen(netoutfile);
+ if (!flen) {
+ ffpmsg
+ ("Output file not set, shouldn't have happened (http_compress_open)");
+ goto error;
+ }
+
+ if (rwmode != 0) {
+ ffpmsg("Can't open compressed http:// type file with READWRITE access");
+ ffpmsg(" Specify an UNCOMPRESSED outfile (http_compress_open)");
+ goto error;
+ }
+ /* do the signal handler bits */
+ if (setjmp(env) != 0) {
+ /* feels like the second time */
+ /* this means something bad happened */
+ ffpmsg("Timeout (http_open)");
+ goto error;
+ }
+
+ signal(SIGALRM, signal_handler);
+
+ /* Open the http connectin */
+ alarm(NETTIMEOUT);
+ if ((status = http_open_network(url,&httpfile,contentencoding,
+ &contentlength))) {
+ alarm(0);
+ ffpmsg("Unable to open http file (http_compress_open)");
+ ffpmsg(url);
+ goto error;
+ }
+
+ closehttpfile++;
+
+ /* Better be compressed */
+
+ firstchar = fgetc(httpfile);
+ ungetc(firstchar,httpfile);
+ if (!strcmp(contentencoding,"x-gzip") ||
+ !strcmp(contentencoding,"x-compress") ||
+ ('\037' == firstchar)) {
+
+ if (*netoutfile == '!')
+ {
+ /* user wants to clobber file, if it already exists */
+ for (ii = 0; ii < flen; ii++)
+ netoutfile[ii] = netoutfile[ii + 1]; /* remove '!' */
+
+ status = file_remove(netoutfile);
+ }
+
+ /* Create the new file */
+ if ((status = file_create(netoutfile,handle))) {
+ ffpmsg("Unable to create output disk file (http_compress_open):");
+ ffpmsg(netoutfile);
+ goto error;
+ }
+
+ closediskfile++;
+
+ /* write a file */
+ alarm(NETTIMEOUT);
+ while(0 != (len = fread(recbuf,1,MAXLEN,httpfile))) {
+ alarm(0);
+ status = file_write(*handle,recbuf,len);
+ if (status) {
+ ffpmsg("Error writing disk file (http_compres_open)");
+ ffpmsg(netoutfile);
+ goto error;
+ }
+ alarm(NETTIMEOUT);
+ }
+ file_close(*handle);
+ fclose(httpfile);
+ closehttpfile--;
+ closediskfile--;
+
+ /* File is on disk, let's uncompress it into memory */
+
+ if (NULL == (diskfile = fopen(netoutfile,"r"))) {
+ ffpmsg("Unable to reopen disk file (http_compress_open)");
+ ffpmsg(netoutfile);
+ goto error;
+ }
+ closefdiskfile++;
+
+ /* Create the memory handle to hold it */
+ if ((status = mem_create(url,handle))) {
+ ffpmsg("Unable to create memory file (http_compress_open)");
+ goto error;
+ }
+ closememfile++;
+
+ /* Uncompress it */
+ status = 0;
+ status = mem_uncompress2mem(url,diskfile,*handle);
+ fclose(diskfile);
+ closefdiskfile--;
+ if (status) {
+ ffpmsg("Error uncompressing disk file to memory (http_compress_open)");
+ ffpmsg(netoutfile);
+ goto error;
+ }
+
+ } else {
+ /* Opps, this should not have happened */
+ ffpmsg("Can only have compressed files here (http_compress_open)");
+ goto error;
+ }
+
+ signal(SIGALRM, SIG_DFL);
+ alarm(0);
+ return mem_seek(*handle,0);
+
+ error:
+ alarm(0); /* clear it */
+ if (closehttpfile) {
+ fclose(httpfile);
+ }
+ if (closefdiskfile) {
+ fclose(diskfile);
+ }
+ if (closememfile) {
+ mem_close_free(*handle);
+ }
+ if (closediskfile) {
+ file_close(*handle);
+ }
+
+ signal(SIGALRM, SIG_DFL);
+ return (FILE_NOT_OPENED);
+}
+
+/*--------------------------------------------------------------------------*/
+/* This creates a file handle with a copy of the URL in filename. The http
+ file is copied to disk first. If it's compressed then it is
+ uncompressed when copying to the disk */
+
+int http_file_open(char *url, int rwmode, int *handle)
+{
+ FILE *httpfile;
+ char contentencoding[SHORTLEN];
+ char errorstr[MAXLEN];
+ char recbuf[MAXLEN];
+ long len;
+ int contentlength;
+ int ii, flen, status;
+ char firstchar;
+
+ /* Check if output file is actually a memory file */
+ if (!strncmp(netoutfile, "mem:", 4) )
+ {
+ /* allow the memory file to be opened with write access */
+ return( http_open(url, READONLY, handle) );
+ }
+
+ closehttpfile = 0;
+ closefile = 0;
+ closeoutfile = 0;
+
+ /* cfileio made a mistake, we need to know where to write the file */
+ flen = strlen(netoutfile);
+ if (!flen) {
+ ffpmsg("Output file not set, shouldn't have happened (http_file_open)");
+ return (FILE_NOT_OPENED);
+ }
+
+ /* do the signal handler bits */
+ if (setjmp(env) != 0) {
+ /* feels like the second time */
+ /* this means something bad happened */
+ ffpmsg("Timeout (http_open)");
+ goto error;
+ }
+
+ signal(SIGALRM, signal_handler);
+
+ /* Open the network connection */
+ alarm(NETTIMEOUT);
+ if ((status = http_open_network(url,&httpfile,contentencoding,
+ &contentlength))) {
+ alarm(0);
+ ffpmsg("Unable to open http file (http_file_open)");
+ ffpmsg(url);
+ goto error;
+ }
+
+ closehttpfile++;
+
+ if (*netoutfile == '!')
+ {
+ /* user wants to clobber disk file, if it already exists */
+ for (ii = 0; ii < flen; ii++)
+ netoutfile[ii] = netoutfile[ii + 1]; /* remove '!' */
+
+ status = file_remove(netoutfile);
+ }
+
+ firstchar = fgetc(httpfile);
+ ungetc(firstchar,httpfile);
+ if (!strcmp(contentencoding,"x-gzip") ||
+ !strcmp(contentencoding,"x-compress") ||
+ ('\037' == firstchar)) {
+
+ /* to make this more cfitsioish we use the file driver calls to create
+ the disk file */
+
+ /* Create the output file */
+ if ((status = file_create(netoutfile,handle))) {
+ ffpmsg("Unable to create output file (http_file_open)");
+ ffpmsg(netoutfile);
+ goto error;
+ }
+
+ file_close(*handle);
+ if (NULL == (outfile = fopen(netoutfile,"w"))) {
+ ffpmsg("Unable to reopen the output file (http_file_open)");
+ ffpmsg(netoutfile);
+ goto error;
+ }
+ closeoutfile++;
+ status = 0;
+
+ /* Ok, this is a tough case, let's be arbritary and say 10*NETTIMEOUT,
+ Given the choices for nettimeout above they'll probaby ^C before, but
+ it's always worth a shot*/
+
+ alarm(NETTIMEOUT*10);
+ status = uncompress2file(url,httpfile,outfile,&status);
+ alarm(0);
+ if (status) {
+ ffpmsg("Error uncompressing http file to disk file (http_file_open)");
+ ffpmsg(url);
+ ffpmsg(netoutfile);
+ goto error;
+ }
+ fclose(outfile);
+ closeoutfile--;
+ } else {
+
+ /* Create the output file */
+ if ((status = file_create(netoutfile,handle))) {
+ ffpmsg("Unable to create output file (http_file_open)");
+ ffpmsg(netoutfile);
+ goto error;
+ }
+
+ /* Give a warning message. This could just be bad padding at the end
+ so don't treat it like an error. */
+ closefile++;
+
+ if (contentlength % 2880) {
+ sprintf(errorstr,
+ "Content-Length not a multiple of 2880 (http_file_open) %d",
+ contentlength);
+ ffpmsg(errorstr);
+ }
+
+ /* write a file */
+ alarm(NETTIMEOUT);
+ while(0 != (len = fread(recbuf,1,MAXLEN,httpfile))) {
+ alarm(0);
+ status = file_write(*handle,recbuf,len);
+ if (status) {
+ ffpmsg("Error copying http file to disk file (http_file_open)");
+ ffpmsg(url);
+ ffpmsg(netoutfile);
+ goto error;
+ }
+ }
+ file_close(*handle);
+ closefile--;
+ }
+
+ fclose(httpfile);
+ closehttpfile--;
+
+ signal(SIGALRM, SIG_DFL);
+ alarm(0);
+
+ return file_open(netoutfile,rwmode,handle);
+
+ error:
+ alarm(0); /* clear it */
+ if (closehttpfile) {
+ fclose(httpfile);
+ }
+ if (closeoutfile) {
+ fclose(outfile);
+ }
+ if (closefile) {
+ file_close(*handle);
+ }
+
+ signal(SIGALRM, SIG_DFL);
+ return (FILE_NOT_OPENED);
+}
+
+/*--------------------------------------------------------------------------*/
+/* This is the guts of the code to get a file via http.
+ url is the input url
+ httpfile is set to be the file connected to the socket which you can
+ read the file from
+ contentencoding is the mime type of the file, returned if the http server
+ returns it
+ contentlength is the lenght of the file, returned if the http server returns
+ it
+*/
+static int http_open_network(char *url, FILE **httpfile, char *contentencoding,
+ int *contentlength)
+{
+
+ int status;
+ int sock;
+ int tmpint;
+ char recbuf[MAXLEN];
+ char tmpstr[MAXLEN];
+ char tmpstr1[SHORTLEN];
+ char errorstr[MAXLEN];
+ char proto[SHORTLEN];
+ char host[SHORTLEN];
+ char fn[MAXLEN];
+ char turl[MAXLEN];
+ char *scratchstr;
+ int port;
+ float version;
+
+
+ /* Parse the URL apart again */
+ strcpy(turl,"http://");
+ strcat(turl,url);
+ if (NET_ParseUrl(turl,proto,host,&port,fn)) {
+ sprintf(errorstr,"URL Parse Error (http_open) %s",url);
+ ffpmsg(errorstr);
+ return (FILE_NOT_OPENED);
+ }
+
+ /* Connect to the remote host */
+ sock = NET_TcpConnect(host,port);
+ if (sock < 0) {
+ ffpmsg("Couldn't connect to host (http_open_network)");
+ return (FILE_NOT_OPENED);
+ }
+
+ /* Make the socket a stdio file */
+ if (NULL == (*httpfile = fdopen(sock,"r"))) {
+ ffpmsg ("fdopen failed to convert socket to file (http_open_network)");
+ close(sock);
+ return (FILE_NOT_OPENED);
+ }
+
+ /* Send the GET request to the remote server */
+ strcpy(tmpstr,"GET ");
+ strcat(tmpstr,fn);
+ strcat(tmpstr," http/1.0\n");
+ sprintf(tmpstr1,"User-Agent: HEASARC/CFITSIO/%-8.3f\n\n",ffvers(&version));
+ strcat(tmpstr,tmpstr1);
+ status = NET_SendRaw(sock,tmpstr,strlen(tmpstr),NET_DEFAULT);
+
+ /* read the header */
+ if (!(fgets(recbuf,MAXLEN,*httpfile))) {
+ sprintf (errorstr,"http header short (http_open_network) %s",recbuf);
+ ffpmsg(errorstr);
+ fclose(*httpfile);
+ return (FILE_NOT_OPENED);
+ }
+ *contentlength = 0;
+ contentencoding[0] = '\0';
+
+ /* Our choices are 200, ok, 301, temporary redirect, or 302 perm redirect */
+ sscanf(recbuf,"%s %d",tmpstr,&status);
+ if (status != 200){
+ if (status == 301 || status == 302) {
+ /* got a redirect */
+ if (status == 301) {
+ ffpmsg("Note: Web server replied with a temporary redirect from");
+ } else {
+ ffpmsg("Note: Web server replied with a redirect from");
+ }
+ ffpmsg(turl);
+ /* now, let's not write the most sophisticated parser here */
+
+ while (fgets(recbuf,MAXLEN,*httpfile)) {
+ scratchstr = strstr(recbuf,"<A HREF=\"");
+ if (scratchstr != NULL) {
+ /* Ok, we found the beginning of the anchor */
+ scratchstr += 9; /* skip the <A HREF=" bits */
+ scratchstr += 7; /* skip http://, we die if it's really ftp:// */
+ strcpy(turl,strtok(scratchstr,"\""));
+ sprintf(errorstr,"to %s\n",turl);
+ ffpmsg(errorstr);
+ fclose (*httpfile);
+ return
+ http_open_network(turl,httpfile,contentencoding,contentlength);
+ }
+ }
+ /* if we get here then we couldnt' decide the redirect */
+ ffpmsg("but we were unable to find the redirected url in the servers response");
+ }
+ sprintf(errorstr,
+ "(http_open_network) Status not 200, was %d\nLine was %s\n",
+ status,recbuf);
+ ffpmsg(errorstr);
+ fclose(*httpfile);
+ return (FILE_NOT_OPENED);
+ }
+
+ /* from here the first word holds the keyword we want */
+ /* so, read the rest of the header */
+ while (fgets(recbuf,MAXLEN,*httpfile)) {
+ /* Blank line ends the header */
+ if (*recbuf == '\r') break;
+ if (strlen(recbuf) > 3) {
+ recbuf[strlen(recbuf)-1] = '\0';
+ recbuf[strlen(recbuf)-1] = '\0';
+ }
+ sscanf(recbuf,"%s %d",tmpstr,&tmpint);
+ /* Did we get a content-length header ? */
+ if (!strcmp(tmpstr,"Content-Length:")) {
+ *contentlength = tmpint;
+ }
+ /* Did we get the content-encoding header ? */
+ if (!strcmp(tmpstr,"Content-Encoding:")) {
+ if (NULL != (scratchstr = strstr(recbuf,":"))) {
+ /* Found the : */
+ scratchstr++; /* skip the : */
+ scratchstr++; /* skip the extra space */
+ strcpy(contentencoding,scratchstr);
+ }
+ }
+ }
+
+ /* we're done, so return */
+ return 0;
+}
+
+
+/*--------------------------------------------------------------------------*/
+/* This creates a memory file handle with a copy of the URL in filename. The
+ file is uncompressed if necessary */
+
+int ftp_open(char *filename, int rwmode, int *handle)
+{
+
+ FILE *ftpfile;
+ FILE *command;
+ int sock;
+ char newfilename[MAXLEN];
+ char recbuf[MAXLEN];
+ long len;
+ int status;
+ char firstchar;
+
+ closememfile = 0;
+ closecommandfile = 0;
+ closeftpfile = 0;
+
+ /* don't do r/w files */
+ if (rwmode != 0) {
+ ffpmsg("Can't open ftp:// type file with READWRITE access");
+ ffpmsg("Specify an outfile for r/w access (ftp_open)");
+ return (FILE_NOT_OPENED);
+ }
+
+ /* do the signal handler bits */
+ if (setjmp(env) != 0) {
+ /* feels like the second time */
+ /* this means something bad happened */
+ ffpmsg("Timeout (http_open)");
+ goto error;
+ }
+
+ signal(SIGALRM, signal_handler);
+
+ /* Open the ftp connetion. ftpfile is connected to the file port,
+ command is connected to port 21. sock is the socket on port 21 */
+
+ alarm(NETTIMEOUT);
+ strcpy(newfilename,filename);
+ /* Does the file have a .Z or .gz in it */
+ if (strstr(newfilename,".Z") || strstr(newfilename,".gz")) {
+ alarm(NETTIMEOUT);
+ if (ftp_open_network(filename,&ftpfile,&command,&sock)) {
+
+ alarm(0);
+ ffpmsg("Unable to open ftp file (ftp_open)");
+ ffpmsg(filename);
+ goto error;
+ }
+ } else {
+ /* Try the .gz one */
+ strcpy(newfilename,filename);
+ strcat(newfilename,".gz");
+ alarm(NETTIMEOUT);
+ if (ftp_open_network(newfilename,&ftpfile,&command,&sock)) {
+
+ alarm(0);
+ strcpy(newfilename,filename);
+ strcat(newfilename,".Z");
+ alarm(NETTIMEOUT);
+ if (ftp_open_network(newfilename,&ftpfile,&command,&sock)) {
+
+ /* Now as given */
+ alarm(0);
+ strcpy(newfilename,filename);
+ alarm(NETTIMEOUT);
+ if (ftp_open_network(newfilename,&ftpfile,&command,&sock)) {
+ alarm(0);
+ ffpmsg("Unable to open ftp file (ftp_open)");
+ ffpmsg(newfilename);
+ goto error;
+ }
+ }
+ }
+ }
+
+ closeftpfile++;
+ closecommandfile++;
+
+ /* create the memory file */
+ if ((status = mem_create(filename,handle))) {
+ ffpmsg ("Could not create memory file to passive port (ftp_open)");
+ ffpmsg(filename);
+ goto error;
+ }
+ closememfile++;
+ /* This isn't quite right, it'll fail if the file has .gzabc at the end
+ for instance */
+
+ /* Decide if the file is compressed */
+ firstchar = fgetc(ftpfile);
+ ungetc(firstchar,ftpfile);
+
+ if (strstr(newfilename,".gz") ||
+ strstr(newfilename,".Z") ||
+ ('\037' == firstchar)) {
+
+ status = 0;
+ /* A bit arbritary really, the user will probably hit ^C */
+ alarm(NETTIMEOUT*10);
+ status = mem_uncompress2mem(filename, ftpfile, *handle);
+ alarm(0);
+ if (status) {
+ ffpmsg("Error writing compressed memory file (ftp_open)");
+ ffpmsg(filename);
+ goto error;
+ }
+ } else {
+ /* write a memory file */
+ alarm(NETTIMEOUT);
+ while(0 != (len = fread(recbuf,1,MAXLEN,ftpfile))) {
+ alarm(0);
+ status = mem_write(*handle,recbuf,len);
+ if (status) {
+ ffpmsg("Error writing memory file (http_open)");
+ ffpmsg(filename);
+ goto error;
+ }
+ alarm(NETTIMEOUT);
+ }
+ }
+
+ /* close and clean up */
+ fclose(ftpfile);
+ closeftpfile--;
+
+ NET_SendRaw(sock,"QUIT\n",5,NET_DEFAULT);
+ fclose(command);
+ closecommandfile--;
+
+ signal(SIGALRM, SIG_DFL);
+ alarm(0);
+
+ return mem_seek(*handle,0);
+
+ error:
+ alarm(0); /* clear it */
+ if (closecommandfile) {
+ fclose(command);
+ }
+ if (closeftpfile) {
+ fclose(ftpfile);
+ }
+ if (closememfile) {
+ mem_close_free(*handle);
+ }
+
+ signal(SIGALRM, SIG_DFL);
+ return (FILE_NOT_OPENED);
+}
+/*--------------------------------------------------------------------------*/
+/* This creates a file handle with a copy of the URL in filename. The
+ file must be uncompressed and is copied to disk first */
+
+int ftp_file_open(char *url, int rwmode, int *handle)
+{
+ FILE *ftpfile;
+ FILE *command;
+ char recbuf[MAXLEN];
+ long len;
+ int sock;
+ int ii, flen, status;
+ char firstchar;
+
+ /* Check if output file is actually a memory file */
+ if (!strncmp(netoutfile, "mem:", 4) )
+ {
+ /* allow the memory file to be opened with write access */
+ return( ftp_open(url, READONLY, handle) );
+ }
+
+ closeftpfile = 0;
+ closecommandfile = 0;
+ closefile = 0;
+ closeoutfile = 0;
+
+ /* cfileio made a mistake, need to know where to write the output file */
+ flen = strlen(netoutfile);
+ if (!flen)
+ {
+ ffpmsg("Output file not set, shouldn't have happened (ftp_file_open)");
+ return (FILE_NOT_OPENED);
+ }
+
+ /* do the signal handler bits */
+ if (setjmp(env) != 0) {
+ /* feels like the second time */
+ /* this means something bad happened */
+ ffpmsg("Timeout (http_open)");
+ goto error;
+ }
+
+ signal(SIGALRM, signal_handler);
+
+ /* open the network connection to url. ftpfile holds the connection to
+ the input file, command holds the connection to port 21, and sock is
+ the socket connected to port 21 */
+
+ alarm(NETTIMEOUT);
+ if ((status = ftp_open_network(url,&ftpfile,&command,&sock))) {
+ alarm(0);
+ ffpmsg("Unable to open http file (ftp_file_open)");
+ ffpmsg(url);
+ goto error;
+ }
+ closeftpfile++;
+ closecommandfile++;
+
+ if (*netoutfile == '!')
+ {
+ /* user wants to clobber file, if it already exists */
+ for (ii = 0; ii < flen; ii++)
+ netoutfile[ii] = netoutfile[ii + 1]; /* remove '!' */
+
+ status = file_remove(netoutfile);
+ }
+
+ /* Now, what do we do with the file */
+ firstchar = fgetc(ftpfile);
+ ungetc(firstchar,ftpfile);
+
+ if (strstr(url,".gz") ||
+ strstr(url,".Z") ||
+ ('\037' == firstchar)) {
+
+ /* to make this more cfitsioish we use the file driver calls to create
+ the file */
+ /* Create the output file */
+ if ((status = file_create(netoutfile,handle))) {
+ ffpmsg("Unable to create output file (ftp_file_open)");
+ ffpmsg(netoutfile);
+ goto error;
+ }
+
+ file_close(*handle);
+ if (NULL == (outfile = fopen(netoutfile,"w"))) {
+ ffpmsg("Unable to reopen the output file (ftp_file_open)");
+ ffpmsg(netoutfile);
+ goto error;
+ }
+ closeoutfile++;
+ status = 0;
+
+ /* Ok, this is a tough case, let's be arbritary and say 10*NETTIMEOUT,
+ Given the choices for nettimeout above they'll probaby ^C before, but
+ it's always worth a shot*/
+
+ alarm(NETTIMEOUT*10);
+ status = uncompress2file(url,ftpfile,outfile,&status);
+ alarm(0);
+ if (status) {
+ ffpmsg("Unable to uncompress the output file (ftp_file_open)");
+ ffpmsg(url);
+ ffpmsg(netoutfile);
+ goto error;
+ }
+ fclose(outfile);
+ closeoutfile--;
+
+ } else {
+
+ /* Create the output file */
+ if ((status = file_create(netoutfile,handle))) {
+ ffpmsg("Unable to create output file (ftp_file_open)");
+ ffpmsg(netoutfile);
+ goto error;
+ }
+ closefile++;
+
+ /* write a file */
+ alarm(NETTIMEOUT);
+ while(0 != (len = fread(recbuf,1,MAXLEN,ftpfile))) {
+ alarm(0);
+ status = file_write(*handle,recbuf,len);
+ if (status) {
+ ffpmsg("Error writing file (ftp_file_open)");
+ ffpmsg(url);
+ ffpmsg(netoutfile);
+ goto error;
+ }
+ alarm(NETTIMEOUT);
+ }
+ file_close(*handle);
+ }
+ fclose(ftpfile);
+ closeftpfile--;
+
+ NET_SendRaw(sock,"QUIT\n",5,NET_DEFAULT);
+ fclose(command);
+ closecommandfile--;
+
+ signal(SIGALRM, SIG_DFL);
+ alarm(0);
+
+ return file_open(netoutfile,rwmode,handle);
+
+ error:
+ alarm(0); /* clear it */
+ if (closeftpfile) {
+ fclose(ftpfile);
+ }
+ if (closecommandfile) {
+ fclose(command);
+ }
+ if (closeoutfile) {
+ fclose(outfile);
+ }
+ if (closefile) {
+ file_close(*handle);
+ }
+
+ signal(SIGALRM, SIG_DFL);
+ return (FILE_NOT_OPENED);
+}
+
+/*--------------------------------------------------------------------------*/
+/* This creates a memory handle with a copy of the URL in filename. The
+ file must be compressed and is copied to disk first */
+
+int ftp_compress_open(char *url, int rwmode, int *handle)
+{
+ FILE *ftpfile;
+ FILE *command;
+ char recbuf[MAXLEN];
+ long len;
+ int ii, flen, status;
+ int sock;
+ char firstchar;
+
+ closeftpfile = 0;
+ closecommandfile = 0;
+ closememfile = 0;
+ closefdiskfile = 0;
+ closediskfile = 0;
+
+ /* don't do r/w files */
+ if (rwmode != 0) {
+ ffpmsg("Compressed files must be r/o");
+ return (FILE_NOT_OPENED);
+ }
+
+ /* Need to know where to write the output file */
+ flen = strlen(netoutfile);
+ if (!flen)
+ {
+ ffpmsg(
+ "Output file not set, shouldn't have happened (ftp_compress_open)");
+ return (FILE_NOT_OPENED);
+ }
+
+ /* do the signal handler bits */
+ if (setjmp(env) != 0) {
+ /* feels like the second time */
+ /* this means something bad happened */
+ ffpmsg("Timeout (http_open)");
+ goto error;
+ }
+
+ signal(SIGALRM, signal_handler);
+
+ /* Open the network connection to url, ftpfile is connected to the file
+ port, command is connected to port 21. sock is for writing to port 21 */
+ alarm(NETTIMEOUT);
+ if ((status = ftp_open_network(url,&ftpfile,&command,&sock))) {
+ alarm(0);
+ ffpmsg("Unable to open ftp file (ftp_compress_open)");
+ ffpmsg(url);
+ goto error;
+ }
+ closeftpfile++;
+ closecommandfile++;
+
+ /* Now, what do we do with the file */
+ firstchar = fgetc(ftpfile);
+ ungetc(firstchar,ftpfile);
+
+ if (strstr(url,".gz") ||
+ strstr(url,".Z") ||
+ ('\037' == firstchar)) {
+
+ if (*netoutfile == '!')
+ {
+ /* user wants to clobber file, if it already exists */
+ for (ii = 0; ii < flen; ii++)
+ netoutfile[ii] = netoutfile[ii + 1]; /* remove '!' */
+
+ status = file_remove(netoutfile);
+ }
+
+ /* Create the output file */
+ if ((status = file_create(netoutfile,handle))) {
+ ffpmsg("Unable to create output file (ftp_compress_open)");
+ ffpmsg(netoutfile);
+ goto error;
+ }
+ closediskfile++;
+
+ /* write a file */
+ alarm(NETTIMEOUT);
+ while(0 != (len = fread(recbuf,1,MAXLEN,ftpfile))) {
+ alarm(0);
+ status = file_write(*handle,recbuf,len);
+ if (status) {
+ ffpmsg("Error writing file (ftp_compres_open)");
+ ffpmsg(url);
+ ffpmsg(netoutfile);
+ goto error;
+ }
+ alarm(NETTIMEOUT);
+ }
+
+ file_close(*handle);
+ closediskfile--;
+ fclose(ftpfile);
+ closeftpfile--;
+ /* Close down the ftp connection */
+ NET_SendRaw(sock,"QUIT\n",5,NET_DEFAULT);
+ fclose(command);
+ closecommandfile--;
+
+ /* File is on disk, let's uncompress it into memory */
+
+ if (NULL == (diskfile = fopen(netoutfile,"r"))) {
+ ffpmsg("Unable to reopen disk file (ftp_compress_open)");
+ ffpmsg(netoutfile);
+ return (FILE_NOT_OPENED);
+ }
+ closefdiskfile++;
+
+ if ((status = mem_create(url,handle))) {
+ ffpmsg("Unable to create memory file (ftp_compress_open)");
+ ffpmsg(url);
+ goto error;
+ }
+ closememfile++;
+
+ status = 0;
+ status = mem_uncompress2mem(url,diskfile,*handle);
+ fclose(diskfile);
+ closefdiskfile--;
+
+ if (status) {
+ ffpmsg("Error writing compressed memory file (ftp_compress_open)");
+ goto error;
+ }
+
+ } else {
+ /* Opps, this should not have happened */
+ ffpmsg("Can only compressed files here (ftp_compress_open)");
+ goto error;
+ }
+
+
+ signal(SIGALRM, SIG_DFL);
+ alarm(0);
+ return mem_seek(*handle,0);
+
+ error:
+ alarm(0); /* clear it */
+ if (closeftpfile) {
+ fclose(ftpfile);
+ }
+ if (closecommandfile) {
+ fclose(command);
+ }
+ if (closefdiskfile) {
+ fclose(diskfile);
+ }
+ if (closememfile) {
+ mem_close_free(*handle);
+ }
+ if (closediskfile) {
+ file_close(*handle);
+ }
+
+ signal(SIGALRM, SIG_DFL);
+ return (FILE_NOT_OPENED);
+}
+
+/*--------------------------------------------------------------------------*/
+/* Open a ftp connection to filename (really a URL), return ftpfile set to
+ the file connection, and command set to the control connection, with sock
+ also set to the control connection */
+
+int ftp_open_network(char *filename, FILE **ftpfile, FILE **command, int *sock)
+{
+ int status;
+ int sock1;
+ int tmpint;
+ char recbuf[MAXLEN];
+ char errorstr[MAXLEN];
+ char tmpstr[MAXLEN];
+ char proto[SHORTLEN];
+ char host[SHORTLEN];
+ char *newhost;
+ char *username;
+ char *password;
+ char fn[MAXLEN];
+ char *newfn;
+ char *passive;
+ char *tstr;
+ char ip[SHORTLEN];
+ char turl[MAXLEN];
+ int port;
+
+ /* parse the URL */
+ strcpy(turl,"ftp://");
+ strcat(turl,filename);
+ if (NET_ParseUrl(turl,proto,host,&port,fn)) {
+ sprintf(errorstr,"URL Parse Error (ftp_open) %s",filename);
+ ffpmsg(errorstr);
+ return (FILE_NOT_OPENED);
+ }
+#ifdef DEBUG
+ printf ("proto, %s, host, %s, port %d, fn %s\n",proto,host,port,fn);
+#endif
+
+ port = 21;
+ /* we might have a user name */
+ username = "anonymous";
+ password = "user@host.com";
+ /* is there an @ sign */
+ if (NULL != (newhost = strrchr(host,'@'))) {
+ *newhost = '\0'; /* make it a null, */
+ newhost++; /* Now newhost points to the host name and host points to the
+ user name, password combo */
+ username = host;
+ /* is there a : for a password */
+ if (NULL != strchr(username,':')) {
+ password = strchr(username,':');
+ *password = '\0';
+ password++;
+ }
+ } else {
+ newhost = host;
+ }
+
+#ifdef DEBUG
+ printf("User %s pass %s\n",username,password);
+#endif
+
+ /* Connect to the host on the required port */
+ *sock = NET_TcpConnect(newhost,port);
+ /* convert it to a stdio file */
+ if (NULL == (*command = fdopen(*sock,"r"))) {
+ ffpmsg ("fdopen failed to convert socket to stdio file (ftp_open)");
+ return (FILE_NOT_OPENED);
+
+ }
+
+ /* Wait for the 220 response */
+ if (ftp_status(*command,"220 ")) {
+ ffpmsg ("error connecting to remote server, no 220 seen (ftp_open)");
+ fclose(*command);
+ return (FILE_NOT_OPENED);
+ }
+
+ /* Send the user name and wait for the right response */
+ sprintf(tmpstr,"USER %s\n",username);
+ status = NET_SendRaw(*sock,tmpstr,strlen(tmpstr),NET_DEFAULT);
+
+ if (ftp_status(*command,"331 ")) {
+ ffpmsg ("USER error no 331 seen (ftp_open)");
+ fclose(*command);
+ return (FILE_NOT_OPENED);
+
+ }
+
+ /* Send the password and wait for the right response */
+ sprintf(tmpstr,"PASS %s\n",password);
+ status = NET_SendRaw(*sock,tmpstr,strlen(tmpstr),NET_DEFAULT);
+
+ if (ftp_status(*command,"230 ")) {
+ ffpmsg ("PASS error, no 230 seen (ftp_open)");
+ fclose(*command);
+ return (FILE_NOT_OPENED);
+ }
+
+
+ /* now do the cwd command */
+ newfn = strrchr(fn,'/');
+ if (newfn == NULL) {
+ strcpy(tmpstr,"CWD /\n");
+ newfn = fn;
+ } else {
+ *newfn = '\0';
+ newfn++;
+ if (strlen(fn) == 0) {
+ strcpy(tmpstr,"CWD /\n");
+ } else {
+ /* remove the leading slash */
+ if (fn[0] == '/') {
+ sprintf(tmpstr,"CWD %s\n",&fn[1]);
+ } else {
+ sprintf(tmpstr,"CWD %s\n",fn);
+ }
+ }
+ }
+
+#ifdef DEBUG
+ printf("CWD command is %s\n",tmpstr);
+#endif
+ status = NET_SendRaw(*sock,tmpstr,strlen(tmpstr),NET_DEFAULT);
+
+ if (ftp_status(*command,"250 ")) {
+ ffpmsg ("CWD error, no 250 seen (ftp_open)");
+ fclose(*command);
+ return (FILE_NOT_OPENED);
+ }
+
+ if (!strlen(newfn)) {
+ ffpmsg("Null file name (ftp_open)");
+ fclose(*command);
+ return (FILE_NOT_OPENED);
+ }
+
+ /* Send the retrieve command to see if the file exists*/
+ sprintf(tmpstr,"RETR %s\n",newfn);
+#ifdef DEBUG
+ printf ("Checking to see if %s, exists %d\n",tmpstr,strlen(newfn));
+#endif
+ status = NET_SendRaw(*sock,tmpstr,strlen(tmpstr),NET_DEFAULT);
+ /* We better get a 425 here, we haven't sent a PORT or PASV command
+ yet. If we don't get a 425 then we're hosed and the file
+ doesn't exist */
+ if (ftp_status(*command,"425 ")) {
+ ffpmsg("File doesn't exist on remote server (ftp_open)");
+ fclose(*command);
+ return (FILE_NOT_OPENED);
+ }
+ /* we're going to use passive mode here */
+
+ status = NET_SendRaw(*sock,"PASV\n",5,NET_DEFAULT);
+ if (!(fgets(recbuf,MAXLEN,*command))) {
+ ffpmsg ("PASV error (ftp_open)");
+ fclose(*command);
+ return (FILE_NOT_OPENED);
+ }
+
+ /* Passive mode response looks like
+ 227 Entering Passive Mode (129,194,67,8,210,80) */
+ if (recbuf[0] == '2' && recbuf[1] == '2' && recbuf[2] == '7') {
+ /* got a good passive mode response, find the opening ( */
+
+ if (!(passive = strchr(recbuf,'('))) {
+ ffpmsg ("PASV error (ftp_open)");
+ fclose(*command);
+ return (FILE_NOT_OPENED);
+ }
+
+ *passive = '\0';
+ passive++;
+ ip[0] = '\0';
+
+ /* Messy parsing of response from PASV *command */
+
+ if (!(tstr = strtok(passive,",)"))) {
+ ffpmsg ("PASV error (ftp_open)");
+ fclose(*command);
+ return (FILE_NOT_OPENED);
+ }
+ strcpy(ip,tstr);
+ strcat(ip,".");
+
+ if (!(tstr = strtok(NULL,",)"))) {
+ ffpmsg ("PASV error (ftp_open)");
+ fclose(*command);
+ return (FILE_NOT_OPENED);
+ }
+ strcat(ip,tstr);
+ strcat(ip,".");
+
+ if (!(tstr = strtok(NULL,",)"))) {
+ ffpmsg ("PASV error (ftp_open)");
+ fclose(*command);
+ return (FILE_NOT_OPENED);
+ }
+ strcat(ip,tstr);
+ strcat(ip,".");
+
+ if (!(tstr = strtok(NULL,",)"))) {
+ ffpmsg ("PASV error (ftp_open)");
+ fclose(*command);
+ return (FILE_NOT_OPENED);
+ }
+ strcat(ip,tstr);
+
+ /* Done the ip number, now do the port # */
+ if (!(tstr = strtok(NULL,",)"))) {
+ ffpmsg ("PASV error (ftp_open)");
+ fclose(*command);
+ return (FILE_NOT_OPENED);
+ }
+ sscanf(tstr,"%d",&port);
+ port *= 256;
+
+ if (!(tstr = strtok(NULL,",)"))) {
+ ffpmsg ("PASV error (ftp_open)");
+ fclose(*command);
+ return (FILE_NOT_OPENED);
+ }
+ sscanf(tstr,"%d",&tmpint);
+ port += tmpint;
+
+ /* Always use binary mode */
+ sprintf(tmpstr,"TYPE I\n");
+ status = NET_SendRaw(*sock,tmpstr,strlen(tmpstr),NET_DEFAULT);
+
+ if (ftp_status(*command,"200 ")) {
+ ffpmsg ("TYPE I error, 200 not seen (ftp_open)");
+ fclose(*command);
+ return (FILE_NOT_OPENED);
+ }
+
+ if (!strlen(newfn)) {
+ ffpmsg("Null file name (ftp_open)");
+ fclose(*command);
+ return (FILE_NOT_OPENED);
+ }
+
+ /* Send the retrieve command */
+ sprintf(tmpstr,"RETR %s\n",newfn);
+ status = NET_SendRaw(*sock,tmpstr,strlen(tmpstr),NET_DEFAULT);
+
+ /* COnnect to the data port */
+ sock1 = NET_TcpConnect(ip,port);
+ if (NULL == (*ftpfile = fdopen(sock1,"r"))) {
+ ffpmsg ("Could not connect to passive port (ftp_open)");
+ fclose(*command);
+ return (FILE_NOT_OPENED);
+ }
+
+ /* now we return */
+
+ return 0;
+ }
+
+ /* no passive mode */
+
+ NET_SendRaw(*sock,"QUIT\n",5,NET_DEFAULT);
+ fclose(*command);
+ return (FILE_NOT_OPENED);
+}
+
+/*--------------------------------------------------------------------------*/
+/* return a socket which results from connection to hostname on port port */
+static int NET_TcpConnect(char *hostname, int port)
+{
+ /* Connect to hostname on port */
+
+ struct sockaddr_in sockaddr;
+ int sock;
+ int stat;
+ int val = 1;
+
+ CreateSocketAddress(&sockaddr,hostname,port);
+ /* Create socket */
+ if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ ffpmsg("Can't create socket");
+ return CONNECTION_ERROR;
+ }
+
+ if ((stat = connect(sock, (struct sockaddr*) &sockaddr,
+ sizeof(sockaddr)))
+ < 0) {
+ close(sock);
+ perror("NET_Tcpconnect - Connection error");
+ ffpmsg("Can't connect to host, connection error");
+ return CONNECTION_ERROR;
+ }
+ setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val));
+ setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&val, sizeof(val));
+
+ val = 65536;
+ setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&val, sizeof(val));
+ setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&val, sizeof(val));
+ return sock;
+}
+
+/*--------------------------------------------------------------------------*/
+/* Write len bytes from buffer to socket sock */
+static int NET_SendRaw(int sock, const void *buffer, int length, int opt)
+{
+
+ char * buf = (char *) buffer;
+
+ int flag;
+ int n, nsent = 0;
+
+ switch (opt) {
+ case NET_DEFAULT:
+ flag = 0;
+ break;
+ case NET_OOB:
+ flag = MSG_OOB;
+ break;
+ case NET_PEEK:
+ default:
+ flag = 0;
+ break;
+ }
+
+ if (sock < 0) return -1;
+
+ for (n = 0; n < length; n += nsent) {
+ if ((nsent = send(sock, buf+n, length-n, flag)) <= 0) {
+ return nsent;
+ }
+#ifdef DEBUG
+ printf ("send raw, sent %d bytes\n",nsent);
+#endif
+ }
+#ifdef DEBUG
+ printf ("send raw end, sent %d bytes\n",n);
+#endif
+ return n;
+}
+
+/*--------------------------------------------------------------------------*/
+
+static int NET_RecvRaw(int sock, void *buffer, int length)
+{
+ /* Receive exactly length bytes into buffer. Returns number of bytes */
+ /* received. Returns -1 in case of error. */
+
+
+ int nrecv, n;
+ char *buf = (char *)buffer;
+
+ if (sock < 0) return -1;
+ for (n = 0; n < length; n += nrecv) {
+ while ((nrecv = recv(sock, buf+n, length-n, 0)) == -1 && errno == EINTR)
+ errno = 0; /* probably a SIGCLD that was caught */
+ if (nrecv < 0)
+ return nrecv;
+ else if (nrecv == 0)
+ break; /*/ EOF */
+ }
+
+ return n;
+}
+
+/*--------------------------------------------------------------------------*/
+/* Yet Another URL Parser
+ url - input url
+ proto - input protocol
+ host - output host
+ port - output port
+ fn - output filename
+*/
+
+static int NET_ParseUrl(const char *url, char *proto, char *host, int *port,
+ char *fn)
+{
+ /* parses urls into their bits */
+ /* returns 1 if error, else 0 */
+
+ char *urlcopy, *urlcopyorig;
+ char *ptrstr;
+ char *thost;
+ int isftp = 0;
+
+ /* figure out if there is a http: or ftp: */
+
+ urlcopyorig = urlcopy = (char *) malloc(strlen(url)+1);
+ strcpy(urlcopy,url);
+
+ /* set some defaults */
+ *port = 80;
+ strcpy(proto,"http:");
+ strcpy(host,"localhost");
+ strcpy(fn,"/");
+
+ ptrstr = strstr(urlcopy,"http:");
+ if (ptrstr == NULL) {
+ /* Nope, not http: */
+ ptrstr = strstr(urlcopy,"root:");
+ if (ptrstr == NULL) {
+ /* Nope, not root either */
+ ptrstr = strstr(urlcopy,"ftp:");
+ if (ptrstr != NULL) {
+ if (ptrstr == urlcopy) {
+ strcpy(proto,"ftp:");
+ *port = 21;
+ isftp++;
+ urlcopy += 4; /* move past ftp: */
+ } else {
+ /* not at the beginning, bad url */
+ free(urlcopyorig);
+ return 1;
+ }
+ }
+ } else {
+ if (ptrstr == urlcopy) {
+ urlcopy += 5; /* move past root: */
+ } else {
+ /* not at the beginning, bad url */
+ free(urlcopyorig);
+ return 1;
+ }
+ }
+ } else {
+ if (ptrstr == urlcopy) {
+ urlcopy += 5; /* move past http: */
+ } else {
+ free(urlcopyorig);
+ return 1;
+ }
+ }
+
+ /* got the protocol */
+ /* get the hostname */
+ if (urlcopy[0] == '/' && urlcopy[1] == '/') {
+ /* we have a hostname */
+ urlcopy += 2; /* move past the // */
+ }
+ /* do this only if http */
+ if (!strcmp(proto,"http:")) {
+ strcpy(host,urlcopy);
+ thost = host;
+ while (*urlcopy != '/' && *urlcopy != ':' && *urlcopy) {
+ thost++;
+ urlcopy++;
+ }
+ /* we should either be at the end of the string, have a /, or have a : */
+ *thost = '\0';
+ if (*urlcopy == ':') {
+ /* follows a port number */
+ urlcopy++;
+ sscanf(urlcopy,"%d",port);
+ while (*urlcopy != '/' && *urlcopy) urlcopy++; /* step to the */
+ }
+ } else {
+ /* do this for ftp */
+ strcpy(host,urlcopy);
+ thost = host;
+ while (*urlcopy != '/' && *urlcopy) {
+ thost++;
+ urlcopy++;
+ }
+ *thost = '\0';
+ /* Now, we should either be at the end of the string, or have a / */
+
+ }
+ /* Now the rest is a fn */
+
+ if (*urlcopy) {
+ strcpy(fn,urlcopy);
+ }
+ free(urlcopyorig);
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+/* Small helper functions to set the netoutfile static string */
+/* Called by cfileio after parsing the output file off of the input file url */
+
+int http_checkfile (char *urltype, char *infile, char *outfile1)
+{
+ char newinfile[MAXLEN];
+ FILE *httpfile;
+ char contentencoding[MAXLEN];
+ int contentlength;
+
+ /* default to http:// if there is no output file */
+
+ strcpy(urltype,"http://");
+
+ if (strlen(outfile1)) {
+ /* there is an output file */
+
+ /* don't copy the "file://" prefix, if present. */
+ if (!strncmp(outfile1, "file://", 7) )
+ strcpy(netoutfile,outfile1+7);
+ else
+ strcpy(netoutfile,outfile1);
+
+ if (!strncmp(outfile1, "mem:", 4) ) {
+ /* copy the file to memory, with READ and WRITE access
+ In this case, it makes no difference whether the http file
+ and or the output file are compressed or not. */
+
+ strcpy(urltype, "httpmem://"); /* use special driver */
+ return 0;
+ }
+
+ if (strstr(infile, "?")) {
+ /* file name contains a '?' so probably a cgi string; don't open it */
+ strcpy(urltype,"httpfile://");
+ return 0;
+ }
+
+ if (!http_open_network(infile,&httpfile,contentencoding,&contentlength)) {
+ fclose(httpfile);
+ /* It's there, we're happy */
+ if (strstr(infile,".gz") || (strstr(infile,".Z"))) {
+ /* It's compressed */
+ if (strstr(outfile1,".gz") || (strstr(outfile1,".Z"))) {
+ strcpy(urltype,"httpcompress://");
+ } else {
+ strcpy(urltype,"httpfile://");
+ }
+ } else {
+ strcpy(urltype,"httpfile://");
+ }
+ return 0;
+ }
+
+ /* Ok, let's try the .gz one */
+ strcpy(newinfile,infile);
+ strcat(newinfile,".gz");
+ if (!http_open_network(newinfile,&httpfile,contentencoding,
+ &contentlength)) {
+ fclose(httpfile);
+ strcpy(infile,newinfile);
+ /* It's there, we're happy, and, it's compressed */
+ /* It's compressed */
+ if (strstr(outfile1,".gz") || (strstr(outfile1,".Z"))) {
+ strcpy(urltype,"httpcompress://");
+ } else {
+ strcpy(urltype,"httpfile://");
+ }
+ return 0;
+ }
+
+ /* Ok, let's try the .Z one */
+ strcpy(newinfile,infile);
+ strcat(newinfile,".Z");
+ if (!http_open_network(newinfile,&httpfile,contentencoding,
+ &contentlength)) {
+ fclose(httpfile);
+ strcpy(infile,newinfile);
+ /* It's there, we're happy, and, it's compressed */
+ if (strstr(outfile1,".gz") || (strstr(outfile1,".Z"))) {
+ strcpy(urltype,"httpcompress://");
+ } else {
+ strcpy(urltype,"httpfile://");
+ }
+ return 0;
+ }
+
+ }
+ return 0;
+}
+/*--------------------------------------------------------------------------*/
+int ftp_checkfile (char *urltype, char *infile, char *outfile1)
+{
+ char newinfile[MAXLEN];
+ FILE *ftpfile;
+ FILE *command;
+ int sock;
+
+
+ /* default to ftp:// */
+
+ strcpy(urltype,"ftp://");
+
+ if (strlen(outfile1)) {
+ /* there is an output file */
+
+ /* don't copy the "file://" prefix, if present. */
+ if (!strncmp(outfile1, "file://", 7) )
+ strcpy(netoutfile,outfile1+7);
+ else
+ strcpy(netoutfile,outfile1);
+
+ if (!strncmp(outfile1, "mem:", 4) ) {
+ /* copy the file to memory, with READ and WRITE access
+ In this case, it makes no difference whether the ftp file
+ and or the output file are compressed or not. */
+
+ strcpy(urltype, "ftpmem://"); /* use special driver */
+ return 0;
+ }
+
+ if (!ftp_open_network(infile,&ftpfile,&command,&sock)) {
+ fclose(ftpfile);
+ fclose(command);
+ /* It's there, we're happy */
+ if (strstr(infile,".gz") || (strstr(infile,".Z"))) {
+ /* It's compressed */
+ if (strstr(outfile1,".gz") || (strstr(outfile1,".Z"))) {
+ strcpy(urltype,"ftpcompress://");
+ } else {
+ strcpy(urltype,"ftpfile://");
+ }
+ } else {
+ strcpy(urltype,"ftpfile://");
+ }
+ return 0;
+ }
+
+ /* Ok, let's try the .gz one */
+ strcpy(newinfile,infile);
+ strcat(newinfile,".gz");
+ if (!ftp_open_network(newinfile,&ftpfile,&command,&sock)) {
+ fclose(ftpfile);
+ fclose(command);
+ strcpy(infile,newinfile);
+ /* It's there, we're happy, and, it's compressed */
+ if (strstr(outfile1,".gz") || (strstr(outfile1,".Z"))) {
+ strcpy(urltype,"ftpcompress://");
+ } else {
+ strcpy(urltype,"ftpfile://");
+ }
+ return 0;
+ }
+
+ /* Ok, let's try the .Z one */
+ strcpy(newinfile,infile);
+ strcat(newinfile,".Z");
+ if (!ftp_open_network(newinfile,&ftpfile,&command,&sock)) {
+ fclose(ftpfile);
+ fclose(command);
+ strcpy(infile,newinfile);
+ if (strstr(outfile1,".gz") || (strstr(outfile1,".Z"))) {
+ strcpy(urltype,"ftpcompress://");
+ } else {
+ strcpy(urltype,"ftpfile://");
+ }
+ return 0;
+ }
+
+ }
+ return 0;
+}
+/*--------------------------------------------------------------------------*/
+/* A small helper function to wait for a particular status on the ftp
+ connectino */
+static int ftp_status(FILE *ftp, char *statusstr)
+{
+ /* read through until we find a string beginning with statusstr */
+ /* This needs a timeout */
+
+ char recbuf[MAXLEN];
+ int len;
+
+ len = strlen(statusstr);
+ while (1) {
+ if (!(fgets(recbuf,MAXLEN,ftp))) {
+ return 1; /* error reading */
+ }
+
+ recbuf[len] = '\0'; /* make it short */
+ if (!strcmp(recbuf,statusstr)) {
+ return 0; /* we're ok */
+ }
+ if (recbuf[0] > '3') {
+ /* oh well, some sort of error */
+ return 1;
+ }
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * CreateSocketAddress --
+ *
+ * This function initializes a sockaddr structure for a host and port.
+ *
+ * Results:
+ * 1 if the host was valid, 0 if the host could not be converted to
+ * an IP address.
+ *
+ * Side effects:
+ * Fills in the *sockaddrPtr structure.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+CreateSocketAddress(
+ struct sockaddr_in *sockaddrPtr, /* Socket address */
+ char *host, /* Host. NULL implies INADDR_ANY */
+ int port) /* Port number */
+{
+ struct hostent *hostent; /* Host database entry */
+ struct in_addr addr; /* For 64/32 bit madness */
+ char localhost[MAXLEN];
+
+ strcpy(localhost,host);
+
+ memset((void *) sockaddrPtr, '\0', sizeof(struct sockaddr_in));
+ sockaddrPtr->sin_family = AF_INET;
+ sockaddrPtr->sin_port = htons((unsigned short) (port & 0xFFFF));
+ if (host == NULL) {
+ addr.s_addr = INADDR_ANY;
+ } else {
+ addr.s_addr = inet_addr(localhost);
+ if (addr.s_addr == 0xFFFFFFFF) {
+ hostent = gethostbyname(localhost);
+ if (hostent != NULL) {
+ memcpy((void *) &addr,
+ (void *) hostent->h_addr_list[0],
+ (size_t) hostent->h_length);
+ } else {
+#ifdef EHOSTUNREACH
+ errno = EHOSTUNREACH;
+#else
+#ifdef ENXIO
+ errno = ENXIO;
+#endif
+#endif
+ return 0; /* error */
+ }
+ }
+ }
+
+ /*
+ * NOTE: On 64 bit machines the assignment below is rumored to not
+ * do the right thing. Please report errors related to this if you
+ * observe incorrect behavior on 64 bit machines such as DEC Alphas.
+ * Should we modify this code to do an explicit memcpy?
+ */
+
+ sockaddrPtr->sin_addr.s_addr = addr.s_addr;
+ return 1; /* Success. */
+}
+
+/* Signal handler for timeouts */
+
+static void signal_handler(int sig) {
+
+ switch (sig) {
+ case SIGALRM: /* process for alarm */
+ longjmp(env,sig);
+
+ default: {
+ /* Hmm, shouldn't have happend */
+ exit(sig);
+ }
+ }
+}
+
+/**************************************************************/
+
+/* Root driver */
+
+/*--------------------------------------------------------------------------*/
+int root_init(void)
+{
+ int ii;
+
+ for (ii = 0; ii < NIOBUF; ii++) /* initialize all empty slots in table */
+ {
+ handleTable[ii].sock = 0;
+ handleTable[ii].currentpos = 0;
+ }
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int root_setoptions(int options)
+{
+ /* do something with the options argument, to stop compiler warning */
+ options = 0;
+ return(options);
+}
+/*--------------------------------------------------------------------------*/
+int root_getoptions(int *options)
+{
+ *options = 0;
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int root_getversion(int *version)
+{
+ *version = 10;
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int root_shutdown(void)
+{
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int root_open(char *url, int rwmode, int *handle)
+{
+ int ii, status;
+ int sock;
+
+ *handle = -1;
+ for (ii = 0; ii < NIOBUF; ii++) /* find empty slot in table */
+ {
+ if (handleTable[ii].sock == 0)
+ {
+ *handle = ii;
+ break;
+ }
+ }
+
+ if (*handle == -1)
+ return(TOO_MANY_FILES); /* too many files opened */
+
+ /*open the file */
+ if (rwmode) {
+ status = root_openfile(url, "update", &sock);
+ } else {
+ status = root_openfile(url, "read", &sock);
+ }
+ if (status)
+ return(status);
+
+ handleTable[ii].sock = sock;
+ handleTable[ii].currentpos = 0;
+
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int root_create(char *filename, int *handle)
+{
+ int ii, status;
+ int sock;
+
+ *handle = -1;
+ for (ii = 0; ii < NIOBUF; ii++) /* find empty slot in table */
+ {
+ if (handleTable[ii].sock == 0)
+ {
+ *handle = ii;
+ break;
+ }
+ }
+
+ if (*handle == -1)
+ return(TOO_MANY_FILES); /* too many files opened */
+
+ /*open the file */
+ status = root_openfile(filename, "create", &sock);
+
+ if (status) {
+ ffpmsg("Unable to create file");
+ return(status);
+ }
+
+ handleTable[ii].sock = sock;
+ handleTable[ii].currentpos = 0;
+
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int root_size(int handle, OFF_T *filesize)
+/*
+ return the size of the file in bytes
+*/
+{
+
+ int sock;
+ int offset;
+ int status;
+ int op;
+
+ sock = handleTable[handle].sock;
+
+ status = root_send_buffer(sock,ROOTD_STAT,NULL,0);
+ status = root_recv_buffer(sock,&op,(char *)&offset, 4);
+ *filesize = (OFF_T) ntohl(offset);
+
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int root_close(int handle)
+/*
+ close the file
+*/
+{
+
+ int status;
+ int sock;
+
+ sock = handleTable[handle].sock;
+ status = root_send_buffer(sock,ROOTD_CLOSE,NULL,0);
+ close(sock);
+ handleTable[handle].sock = 0;
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int root_flush(int handle)
+/*
+ flush the file
+*/
+{
+ int status;
+ int sock;
+
+ sock = handleTable[handle].sock;
+ status = root_send_buffer(sock,ROOTD_FLUSH,NULL,0);
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int root_seek(int handle, OFF_T offset)
+/*
+ seek to position relative to start of the file
+*/
+{
+ handleTable[handle].currentpos = offset;
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int root_read(int hdl, void *buffer, long nbytes)
+/*
+ read bytes from the current position in the file
+*/
+{
+ char msg[SHORTLEN];
+ int op;
+ int status;
+ int astat;
+
+ /* we presume here that the file position will never be > 2**31 = 2.1GB */
+ sprintf(msg,"%ld %ld ",(long) handleTable[hdl].currentpos,nbytes);
+ status = root_send_buffer(handleTable[hdl].sock,ROOTD_GET,msg,strlen(msg));
+ if ((unsigned) status != strlen(msg)) {
+ return (READ_ERROR);
+ }
+ astat = 0;
+ status = root_recv_buffer(handleTable[hdl].sock,&op,(char *) &astat,4);
+ if (astat != 0) {
+ return (READ_ERROR);
+ }
+#ifdef DEBUG
+ printf("root_read, op %d astat %d\n",op,astat);
+#endif
+ status = NET_RecvRaw(handleTable[hdl].sock,buffer,nbytes);
+ if (status != nbytes) {
+ return (READ_ERROR);
+ }
+ handleTable[hdl].currentpos += nbytes;
+
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int root_write(int hdl, void *buffer, long nbytes)
+/*
+ write bytes at the current position in the file
+*/
+{
+
+ char msg[SHORTLEN];
+ int len;
+ int sock;
+ int status;
+ int astat;
+ int op;
+
+ sock = handleTable[hdl].sock;
+ /* we presume here that the file position will never be > 2**31 = 2.1GB */
+ sprintf(msg,"%ld %ld ",(long) handleTable[hdl].currentpos,nbytes);
+
+ len = strlen(msg);
+ status = root_send_buffer(sock,ROOTD_PUT,msg,len+1);
+ if (status != len+1) {
+ return (WRITE_ERROR);
+ }
+ status = NET_SendRaw(sock,buffer,nbytes,NET_DEFAULT);
+ if (status != nbytes) {
+ return (WRITE_ERROR);
+ }
+ astat = 0;
+ status = root_recv_buffer(handleTable[hdl].sock,&op,(char *) &astat,4);
+#ifdef DEBUG
+ printf("root_read, op %d astat %d\n",op,astat);
+#endif
+ if (astat != 0) {
+ return (WRITE_ERROR);
+ }
+ handleTable[hdl].currentpos += nbytes;
+ return(0);
+}
+
+/*--------------------------------------------------------------------------*/
+int root_openfile(char *url, char *rwmode, int *sock)
+ /*
+ lowest level routine to physically open a root file
+ */
+{
+
+ int status;
+ char recbuf[MAXLEN];
+ char errorstr[MAXLEN];
+ char proto[SHORTLEN];
+ char host[SHORTLEN];
+ char fn[MAXLEN];
+ char turl[MAXLEN];
+ int port;
+ int op;
+ int ii;
+ int authstat;
+
+
+ /* Parse the URL apart again */
+ strcpy(turl,"root://");
+ strcat(turl,url);
+ if (NET_ParseUrl(turl,proto,host,&port,fn)) {
+ sprintf(errorstr,"URL Parse Error (root_open) %s",url);
+ ffpmsg(errorstr);
+ return (FILE_NOT_OPENED);
+ }
+
+#ifdef DEBUG
+ printf("Connecting to %s on port %d\n",host,port);
+#endif
+ /* Connect to the remote host */
+ *sock = NET_TcpConnect(host,port);
+ if (*sock < 0) {
+ ffpmsg("Couldn't connect to host (http_open_network)");
+ return (FILE_NOT_OPENED);
+ }
+
+ /* get the username */
+ if (NULL != getenv("ROOTUSERNAME")) {
+ strcpy(recbuf,getenv("ROOTUSERNAME"));
+ } else {
+ printf("Username: ");
+ fgets(recbuf,MAXLEN,stdin);
+ recbuf[strlen(recbuf)-1] = '\0';
+ }
+
+ status = root_send_buffer(*sock, ROOTD_USER, recbuf,strlen(recbuf));
+ if (status < 0) {
+ ffpmsg("error talking to remote system on username ");
+ return (FILE_NOT_OPENED);
+ }
+
+ status = root_recv_buffer(*sock,&op,(char *)&authstat,4);
+ if (!status) {
+ ffpmsg("error talking to remote system on username");
+ return (FILE_NOT_OPENED);
+ }
+
+#ifdef DEBUG
+ printf("op is %d and authstat is %d\n",op,authstat);
+#endif
+
+ if (op != ROOTD_AUTH) {
+ ffpmsg("ERROR on ROOTD_USER");
+ ffpmsg(recbuf);
+ return (FILE_NOT_OPENED);
+ }
+
+
+ /* now the password */
+ if (NULL != getenv("ROOTPASSWORD")) {
+ strcpy(recbuf,getenv("ROOTPASSWORD"));
+ } else {
+ printf("Password: ");
+ fgets(recbuf,MAXLEN,stdin);
+ recbuf[strlen(recbuf)-1] = '\0';
+ }
+ /* ones complement the password */
+ for (ii=0;(unsigned) ii<strlen(recbuf);ii++) {
+ recbuf[ii] = ~recbuf[ii];
+ }
+
+ status = root_send_buffer(*sock, ROOTD_PASS, recbuf, strlen(recbuf));
+ if (status < 0) {
+ ffpmsg("error talking to remote system sending password");
+ return (FILE_NOT_OPENED);
+ }
+
+ status = root_recv_buffer(*sock,&op,(char *)&authstat,4);
+ if (status < 0) {
+ ffpmsg("error talking to remote system acking password");
+ return (FILE_NOT_OPENED);
+ }
+
+#ifdef DEBUG
+ printf("op is %d and authstat is %d\n",op,authstat);
+#endif
+ if (op != ROOTD_AUTH) {
+ ffpmsg("ERROR on ROOTD_PASS");
+ ffpmsg(recbuf);
+ return (FILE_NOT_OPENED);
+ }
+
+ /* now the file open request */
+ strcpy(recbuf,fn);
+ strcat(recbuf," ");
+ strcat(recbuf,rwmode);
+
+ status = root_send_buffer(*sock, ROOTD_OPEN, recbuf, strlen(recbuf));
+ if (status < 0) {
+ ffpmsg("error talking to remote system on open ");
+ return (FILE_NOT_OPENED);
+ }
+
+ status = root_recv_buffer(*sock,&op,(char *)&authstat,4);
+ if (status < 0) {
+ ffpmsg("error talking to remote system on open");
+ return (FILE_NOT_OPENED);
+ }
+
+#ifdef DEBUG
+ printf("op is %d and recbuf is %d\n",op,authstat);
+#endif
+
+ if ((op != ROOTD_OPEN) && (authstat != 0)) {
+ ffpmsg("ERROR on ROOTD_OPEN");
+ ffpmsg(recbuf);
+ return (FILE_NOT_OPENED);
+ }
+
+ return 0;
+
+}
+
+static int root_send_buffer(int sock, int op, char *buffer, int buflen)
+{
+ /* send a buffer, the form is
+ <len>
+ <op>
+ <buffer>
+
+ <len> includes the 4 bytes for the op, the length bytes (4) are implicit
+
+
+ if buffer is null don't send it, not everything needs something sent */
+
+ int len;
+ int status;
+
+ int hdr[2];
+
+ len = 4;
+
+ if (buffer != NULL) {
+ len += buflen;
+ }
+
+ hdr[0] = htonl(len);
+
+#ifdef DEBUG
+ printf("len sent is %x\n",hdr[0]);
+#endif
+
+ hdr[1] = htonl(op);
+#ifdef DEBUG
+ printf("op sent is %x\n",hdr[1]);
+#endif
+
+
+#ifdef DEBUG
+ printf("Sending op %d and length of %d\n",op,len);
+#endif
+
+ status = NET_SendRaw(sock,hdr,sizeof(hdr),NET_DEFAULT);
+ if (status < 0) {
+ return status;
+ }
+ if (buffer != NULL) {
+ status = NET_SendRaw(sock,buffer,buflen,NET_DEFAULT);
+ }
+ return status;
+}
+
+static int root_recv_buffer(int sock, int *op, char *buffer, int buflen)
+{
+ /* recv a buffer, the form is
+ <len>
+ <op>
+ <buffer>
+
+ */
+
+ int recv1 = 0;
+ int len;
+ int status;
+ char recbuf[MAXLEN];
+
+ status = NET_RecvRaw(sock,&len,4);
+#ifdef DEBUG
+ printf("Recv: status from rec is %d\n",status);
+#endif
+ if (status < 0) {
+ return status;
+ }
+ recv1 += status;
+
+ len = ntohl(len);
+#ifdef DEBUG
+ printf ("Recv: length is %d\n",len);
+#endif
+
+ /* ok, have the length, recive the operation */
+ len -= 4;
+ status = NET_RecvRaw(sock,op,4);
+ if (status < 0) {
+ return status;
+ }
+
+ recv1 += status;
+
+ *op = ntohl(*op);
+#ifdef DEBUG
+ printf ("Recv: Operation is %d\n",*op);
+#endif
+
+ if (len > MAXLEN) {
+ len = MAXLEN;
+ }
+
+ if (len > 0) { /* Get the rest of the message */
+ status = NET_RecvRaw(sock,recbuf,len);
+ if (len > buflen) {
+ len = buflen;
+ }
+ memcpy(buffer,recbuf,len);
+ if (status < 0) {
+ return status;
+ }
+ }
+
+ recv1 += status;
+ return recv1;
+
+}
+#endif
diff --git a/pkg/tbtables/cfitsio/drvrsmem.c b/pkg/tbtables/cfitsio/drvrsmem.c
new file mode 100644
index 00000000..3c2b4032
--- /dev/null
+++ b/pkg/tbtables/cfitsio/drvrsmem.c
@@ -0,0 +1,953 @@
+/* S H A R E D M E M O R Y D R I V E R
+ =======================================
+
+ by Jerzy.Borkowski@obs.unige.ch
+
+09-Mar-98 : initial version 1.0 released
+23-Mar-98 : shared_malloc now accepts new handle as an argument
+23-Mar-98 : shmem://0, shmem://1, etc changed to shmem://h0, etc due to bug
+ in url parser.
+10-Apr-98 : code cleanup
+13-May-99 : delayed initialization added, global table deleted on exit when
+ no shmem segments remain, and last process terminates
+*/
+
+#ifdef HAVE_SHMEM_SERVICES
+#include "fitsio2.h" /* drvrsmem.h is included by it */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+
+static int shared_kbase = 0; /* base for shared memory handles */
+static int shared_maxseg = 0; /* max number of shared memory blocks */
+static int shared_range = 0; /* max number of tried entries */
+static int shared_fd = SHARED_INVALID; /* handle of global access lock file */
+static int shared_gt_h = SHARED_INVALID; /* handle of global table segment */
+static SHARED_LTAB *shared_lt = NULL; /* local table pointer */
+static SHARED_GTAB *shared_gt = NULL; /* global table pointer */
+static int shared_create_mode = 0666; /* permission flags for created objects */
+static int shared_debug = 1; /* simple debugging tool, set to 0 to disable messages */
+static int shared_init_called = 0; /* flag whether shared_init() has been called, used for delayed init */
+
+ /* static support routines prototypes */
+
+static int shared_clear_entry(int idx); /* unconditionally clear entry */
+static int shared_destroy_entry(int idx); /* unconditionally destroy sema & shseg and clear entry */
+static int shared_mux(int idx, int mode); /* obtain exclusive access to specified segment */
+static int shared_demux(int idx, int mode); /* free exclusive access to specified segment */
+
+static int shared_process_count(int sem); /* valid only for time of invocation */
+static int shared_delta_process(int sem, int delta); /* change number of processes hanging on segment */
+static int shared_attach_process(int sem);
+static int shared_detach_process(int sem);
+static int shared_get_free_entry(int newhandle); /* get free entry in shared_key, or -1, entry is set rw locked */
+static int shared_get_hash(long size, int idx);/* return hash value for malloc */
+static long shared_adjust_size(long size); /* size must be >= 0 !!! */
+static int shared_check_locked_index(int idx); /* verify that given idx is valid */
+static int shared_map(int idx); /* map all tables for given idx, check for validity */
+static int shared_validate(int idx, int mode); /* use intrnally inside crit.sect !!! */
+
+ /* support routines - initialization */
+
+
+static int shared_clear_entry(int idx) /* unconditionally clear entry */
+ { if ((idx < 0) || (idx >= shared_maxseg)) return(SHARED_BADARG);
+ shared_gt[idx].key = SHARED_INVALID; /* clear entries in global table */
+ shared_gt[idx].handle = SHARED_INVALID;
+ shared_gt[idx].sem = SHARED_INVALID;
+ shared_gt[idx].semkey = SHARED_INVALID;
+ shared_gt[idx].nprocdebug = 0;
+ shared_gt[idx].size = 0;
+ shared_gt[idx].attr = 0;
+
+ return(SHARED_OK);
+ }
+
+static int shared_destroy_entry(int idx) /* unconditionally destroy sema & shseg and clear entry */
+ { int r, r2;
+ union semun filler;
+
+ if ((idx < 0) || (idx >= shared_maxseg)) return(SHARED_BADARG);
+ r2 = r = SHARED_OK;
+ filler.val = 0; /* this is to make cc happy (warning otherwise) */
+ if (SHARED_INVALID != shared_gt[idx].sem) r = semctl(shared_gt[idx].sem, 0, IPC_RMID, filler); /* destroy semaphore */
+ if (SHARED_INVALID != shared_gt[idx].handle) r2 = shmctl(shared_gt[idx].handle, IPC_RMID, 0); /* destroy shared memory segment */
+ if (SHARED_OK == r) r = r2; /* accumulate error code in r, free r2 */
+ r2 = shared_clear_entry(idx);
+ return((SHARED_OK == r) ? r2 : r);
+ }
+
+void shared_cleanup(void) /* this must (should) be called during exit/abort */
+ { int i, j, r, oktodelete, filelocked, segmentspresent;
+ flock_t flk;
+ struct shmid_ds ds;
+
+ if (shared_debug) printf("shared_cleanup:");
+ if (NULL != shared_lt)
+ { if (shared_debug) printf(" deleting segments:");
+ for (i=0; i<shared_maxseg; i++)
+ { if (0 == shared_lt[i].tcnt) continue; /* we're not using this segment, skip this ... */
+ if (-1 != shared_lt[i].lkcnt) continue; /* seg not R/W locked by us, skip this ... */
+
+ r = shared_destroy_entry(i); /* destroy unconditionally sema & segment */
+ if (shared_debug)
+ { if (SHARED_OK == r) printf(" [%d]", i);
+ else printf(" [error on %d !!!!]", i);
+
+ }
+ }
+ free((void *)shared_lt); /* free local table */
+ shared_lt = NULL;
+ }
+ if (NULL != shared_gt) /* detach global index table */
+ { oktodelete = 0;
+ filelocked = 0;
+ if (shared_debug) printf(" detaching globalsharedtable");
+ if (SHARED_INVALID != shared_fd)
+
+ flk.l_type = F_WRLCK; /* lock whole lock file */
+ flk.l_whence = 0;
+ flk.l_start = 0;
+ flk.l_len = shared_maxseg;
+ if (-1 != fcntl(shared_fd, F_SETLK, &flk))
+ { filelocked = 1; /* success, scan global table, to see if there are any segs */
+ segmentspresent = 0; /* assume, there are no segs in the system */
+ for (j=0; j<shared_maxseg; j++)
+ { if (SHARED_INVALID != shared_gt[j].key)
+ { segmentspresent = 1; /* yes, there is at least one */
+ break;
+ }
+ }
+ if (0 == segmentspresent) /* if there are no segs ... */
+ if (0 == shmctl(shared_gt_h, IPC_STAT, &ds)) /* get number of processes attached to table */
+ { if (ds.shm_nattch <= 1) oktodelete = 1; /* if only one (we), then it is safe (but see text 4 lines later) to unlink */
+ }
+ }
+ shmdt((char *)shared_gt); /* detach global table */
+ if (oktodelete) /* delete global table from system, if no shm seg present */
+ { shmctl(shared_gt_h, IPC_RMID, 0); /* there is a race condition here - time window between shmdt and shmctl */
+ shared_gt_h = SHARED_INVALID;
+ }
+ shared_gt = NULL;
+ if (filelocked) /* if we locked, we need to unlock */
+ { flk.l_type = F_UNLCK;
+ flk.l_whence = 0;
+ flk.l_start = 0;
+ flk.l_len = shared_maxseg;
+ fcntl(shared_fd, F_SETLK, &flk);
+ }
+ }
+ shared_gt_h = SHARED_INVALID;
+
+ if (SHARED_INVALID != shared_fd) /* close lock file */
+ { if (shared_debug) printf(" closing lockfile");
+ close(shared_fd);
+ shared_fd = SHARED_INVALID;
+ }
+
+
+ shared_kbase = 0;
+ shared_maxseg = 0;
+ shared_range = 0;
+ shared_init_called = 0;
+
+ if (shared_debug) printf(" <<done>>\n");
+ return;
+ }
+
+
+int shared_init(int debug_msgs) /* initialize shared memory stuff, you have to call this routine once */
+ { int i;
+ char buf[1000], *p;
+ mode_t oldumask;
+
+ shared_init_called = 1; /* tell everybody no need to call us for the 2nd time */
+ shared_debug = debug_msgs; /* set required debug mode */
+
+ if (shared_debug) printf("shared_init:");
+
+ shared_kbase = 0; /* adapt to current env. settings */
+ if (NULL != (p = getenv(SHARED_ENV_KEYBASE))) shared_kbase = atoi(p);
+ if (0 == shared_kbase) shared_kbase = SHARED_KEYBASE;
+ if (shared_debug) printf(" keybase=%d", shared_kbase);
+
+ shared_maxseg = 0;
+ if (NULL != (p = getenv(SHARED_ENV_MAXSEG))) shared_maxseg = atoi(p);
+ if (0 == shared_maxseg) shared_maxseg = SHARED_MAXSEG;
+ if (shared_debug) printf(" maxseg=%d", shared_maxseg);
+
+ shared_range = 3 * shared_maxseg;
+
+ if (SHARED_INVALID == shared_fd) /* create rw locking file (this file is never deleted) */
+ { if (shared_debug) printf(" lockfileinit=");
+ sprintf(buf, "%s.%d.%d", SHARED_FDNAME, shared_kbase, shared_maxseg);
+ oldumask = umask(0);
+
+ shared_fd = open(buf, O_TRUNC | O_EXCL | O_CREAT | O_RDWR, shared_create_mode);
+ umask(oldumask);
+ if (SHARED_INVALID == shared_fd) /* or just open rw locking file, in case it already exists */
+ { shared_fd = open(buf, O_TRUNC | O_RDWR, shared_create_mode);
+ if (SHARED_INVALID == shared_fd) return(SHARED_NOFILE);
+ if (shared_debug) printf("slave");
+
+ }
+ else
+ { if (shared_debug) printf("master");
+ }
+ }
+
+ if (SHARED_INVALID == shared_gt_h) /* global table not attached, try to create it in shared memory */
+ { if (shared_debug) printf(" globalsharedtableinit=");
+ shared_gt_h = shmget(shared_kbase, shared_maxseg * sizeof(SHARED_GTAB), IPC_CREAT | IPC_EXCL | shared_create_mode); /* try open as a master */
+ if (SHARED_INVALID == shared_gt_h) /* if failed, try to open as a slave */
+ { shared_gt_h = shmget(shared_kbase, shared_maxseg * sizeof(SHARED_GTAB), shared_create_mode);
+ if (SHARED_INVALID == shared_gt_h) return(SHARED_IPCERR); /* means deleted ID residing in system, shared mem unusable ... */
+ shared_gt = (SHARED_GTAB *)shmat(shared_gt_h, 0, 0); /* attach segment */
+ if (((SHARED_GTAB *)SHARED_INVALID) == shared_gt) return(SHARED_IPCERR);
+ if (shared_debug) printf("slave");
+ }
+ else
+ { shared_gt = (SHARED_GTAB *)shmat(shared_gt_h, 0, 0); /* attach segment */
+ if (((SHARED_GTAB *)SHARED_INVALID) == shared_gt) return(SHARED_IPCERR);
+ for (i=0; i<shared_maxseg; i++) shared_clear_entry(i); /* since we are master, init data */
+ if (shared_debug) printf("master");
+ }
+ }
+
+ if (NULL == shared_lt) /* initialize local table */
+ { if (shared_debug) printf(" localtableinit=");
+ if (NULL == (shared_lt = (SHARED_LTAB *)malloc(shared_maxseg * sizeof(SHARED_LTAB)))) return(SHARED_NOMEM);
+ for (i=0; i<shared_maxseg; i++)
+ { shared_lt[i].p = NULL; /* not mapped */
+ shared_lt[i].tcnt = 0; /* unused (or zero threads using this seg) */
+ shared_lt[i].lkcnt = 0; /* segment is unlocked */
+ shared_lt[i].seekpos = 0L; /* r/w pointer at the beginning of file */
+ }
+ if (shared_debug) printf("ok");
+ }
+
+ atexit(shared_cleanup); /* we want shared_cleanup to be called at exit or abort */
+
+ if (shared_debug) printf(" <<done>>\n");
+ return(SHARED_OK);
+ }
+
+
+int shared_recover(int id) /* try to recover dormant segments after applic crash */
+ { int i, r, r2;
+
+ if (NULL == shared_gt) return(SHARED_NOTINIT); /* not initialized */
+ if (NULL == shared_lt) return(SHARED_NOTINIT); /* not initialized */
+ r = SHARED_OK;
+ for (i=0; i<shared_maxseg; i++)
+ { if (-1 != id) if (i != id) continue;
+ if (shared_lt[i].tcnt) continue; /* somebody (we) is using it */
+ if (SHARED_INVALID == shared_gt[i].key) continue; /* unused slot */
+ if (shared_mux(i, SHARED_NOWAIT | SHARED_RDWRITE)) continue; /* acquire exclusive access to segment, but do not wait */
+ r2 = shared_process_count(shared_gt[i].sem);
+ if ((shared_gt[i].nprocdebug > r2) || (0 == r2))
+ { if (shared_debug) printf("Bogus handle=%d nproc=%d sema=%d:", i, shared_gt[i].nprocdebug, r2);
+ r = shared_destroy_entry(i);
+ if (shared_debug)
+ { printf("%s", r ? "error couldn't clear handle" : "handle cleared");
+ }
+ }
+ shared_demux(i, SHARED_RDWRITE);
+ }
+ return(r); /* table full */
+ }
+
+ /* API routines - mutexes and locking */
+
+static int shared_mux(int idx, int mode) /* obtain exclusive access to specified segment */
+ { flock_t flk;
+
+ int r;
+
+ if (0 == shared_init_called) /* delayed initialization */
+ { if (SHARED_OK != (r = shared_init(0))) return(r);
+
+ }
+ if (SHARED_INVALID == shared_fd) return(SHARED_NOTINIT);
+ if ((idx < 0) || (idx >= shared_maxseg)) return(SHARED_BADARG);
+ flk.l_type = ((mode & SHARED_RDWRITE) ? F_WRLCK : F_RDLCK);
+ flk.l_whence = 0;
+ flk.l_start = idx;
+ flk.l_len = 1;
+ if (shared_debug) printf(" [mux (%d): ", idx);
+ if (-1 == fcntl(shared_fd, ((mode & SHARED_NOWAIT) ? F_SETLK : F_SETLKW), &flk))
+ { switch (errno)
+ { case EAGAIN: ;
+
+ case EACCES: if (shared_debug) printf("again]");
+ return(SHARED_AGAIN);
+ default: if (shared_debug) printf("err]");
+ return(SHARED_IPCERR);
+ }
+ }
+ if (shared_debug) printf("ok]");
+ return(SHARED_OK);
+ }
+
+
+
+static int shared_demux(int idx, int mode) /* free exclusive access to specified segment */
+ { flock_t flk;
+
+ if (SHARED_INVALID == shared_fd) return(SHARED_NOTINIT);
+ if ((idx < 0) || (idx >= shared_maxseg)) return(SHARED_BADARG);
+ flk.l_type = F_UNLCK;
+ flk.l_whence = 0;
+ flk.l_start = idx;
+ flk.l_len = 1;
+ if (shared_debug) printf(" [demux (%d): ", idx);
+ if (-1 == fcntl(shared_fd, F_SETLKW, &flk))
+ { switch (errno)
+ { case EAGAIN: ;
+ case EACCES: if (shared_debug) printf("again]");
+ return(SHARED_AGAIN);
+ default: if (shared_debug) printf("err]");
+ return(SHARED_IPCERR);
+ }
+
+ }
+ if (shared_debug) printf("mode=%d ok]", mode);
+ return(SHARED_OK);
+ }
+
+
+
+static int shared_process_count(int sem) /* valid only for time of invocation */
+ { union semun su;
+
+ su.val = 0; /* to force compiler not to give warning messages */
+ return(semctl(sem, 0, GETVAL, su)); /* su is unused here */
+ }
+
+
+static int shared_delta_process(int sem, int delta) /* change number of processes hanging on segment */
+ { struct sembuf sb;
+
+ if (SHARED_INVALID == sem) return(SHARED_BADARG); /* semaphore not attached */
+ sb.sem_num = 0;
+ sb.sem_op = delta;
+ sb.sem_flg = SEM_UNDO;
+ return((-1 == semop(sem, &sb, 1)) ? SHARED_IPCERR : SHARED_OK);
+ }
+
+
+static int shared_attach_process(int sem)
+ { if (shared_debug) printf(" [attach process]");
+ return(shared_delta_process(sem, 1));
+ }
+
+
+static int shared_detach_process(int sem)
+ { if (shared_debug) printf(" [detach process]");
+ return(shared_delta_process(sem, -1));
+ }
+
+ /* API routines - hashing and searching */
+
+
+static int shared_get_free_entry(int newhandle) /* get newhandle, or -1, entry is set rw locked */
+ {
+ if (NULL == shared_gt) return(-1); /* not initialized */
+ if (NULL == shared_lt) return(-1); /* not initialized */
+ if (newhandle < 0) return(-1);
+ if (newhandle >= shared_maxseg) return(-1);
+ if (shared_lt[newhandle].tcnt) return(-1); /* somebody (we) is using it */
+ if (shared_mux(newhandle, SHARED_NOWAIT | SHARED_RDWRITE)) return(-1); /* used by others */
+ if (SHARED_INVALID == shared_gt[newhandle].key) return(newhandle); /* we have found free slot, lock it and return index */
+ shared_demux(newhandle, SHARED_RDWRITE);
+ if (shared_debug) printf("[free_entry - ERROR - entry unusable]");
+ return(-1); /* table full */
+ }
+
+
+static int shared_get_hash(long size, int idx) /* return hash value for malloc */
+ { static int counter = 0;
+ int hash;
+
+ hash = (counter + size * idx) % shared_range;
+ counter = (counter + 1) % shared_range;
+ return(hash);
+ }
+
+
+static long shared_adjust_size(long size) /* size must be >= 0 !!! */
+ { return(((size + sizeof(BLKHEAD) + SHARED_GRANUL - 1) / SHARED_GRANUL) * SHARED_GRANUL); }
+
+
+ /* API routines - core : malloc/realloc/free/attach/detach/lock/unlock */
+
+int shared_malloc(long size, int mode, int newhandle) /* return idx or SHARED_INVALID */
+ { int h, i, r, idx, key;
+ union semun filler;
+ BLKHEAD *bp;
+
+ if (0 == shared_init_called) /* delayed initialization */
+ { if (SHARED_OK != (r = shared_init(0))) return(r);
+ }
+ if (shared_debug) printf("malloc (size = %ld, mode = %d):", size, mode);
+ if (size < 0) return(SHARED_INVALID);
+ if (-1 == (idx = shared_get_free_entry(newhandle))) return(SHARED_INVALID);
+ if (shared_debug) printf(" idx=%d", idx);
+ for (i = 0; ; i++)
+ { if (i >= shared_range) /* table full, signal error & exit */
+ { shared_demux(idx, SHARED_RDWRITE);
+ return(SHARED_INVALID);
+ }
+ key = shared_kbase + ((i + shared_get_hash(size, idx)) % shared_range);
+ if (shared_debug) printf(" key=%d", key);
+ h = shmget(key, shared_adjust_size(size), IPC_CREAT | IPC_EXCL | shared_create_mode);
+ if (shared_debug) printf(" handle=%d", h);
+ if (SHARED_INVALID == h) continue; /* segment already accupied */
+ bp = (BLKHEAD *)shmat(h, 0, 0); /* try attach */
+ if (shared_debug) printf(" p=%p", bp);
+ if (((BLKHEAD *)SHARED_INVALID) == bp) /* cannot attach, delete segment, try with another key */
+ { shmctl(h, IPC_RMID, 0);
+ continue;
+ } /* now create semaphor counting number of processes attached */
+ if (SHARED_INVALID == (shared_gt[idx].sem = semget(key, 1, IPC_CREAT | IPC_EXCL | shared_create_mode)))
+ { shmdt((void *)bp); /* cannot create segment, delete everything */
+ shmctl(h, IPC_RMID, 0);
+ continue; /* try with another key */
+ }
+ if (shared_debug) printf(" sem=%d", shared_gt[idx].sem);
+ if (shared_attach_process(shared_gt[idx].sem)) /* try attach process */
+ { semctl(shared_gt[idx].sem, 0, IPC_RMID, filler); /* destroy semaphore */
+ shmdt((char *)bp); /* detach shared mem segment */
+ shmctl(h, IPC_RMID, 0); /* destroy shared mem segment */
+ continue; /* try with another key */
+ }
+ bp->s.tflag = BLOCK_SHARED; /* fill in data in segment's header (this is really not necessary) */
+ bp->s.ID[0] = SHARED_ID_0;
+ bp->s.ID[1] = SHARED_ID_1;
+ bp->s.handle = idx; /* used in yorick */
+ if (mode & SHARED_RESIZE)
+ { if (shmdt((char *)bp)) r = SHARED_IPCERR; /* if segment is resizable, then detach segment */
+ shared_lt[idx].p = NULL;
+ }
+ else { shared_lt[idx].p = bp; }
+ shared_lt[idx].tcnt = 1; /* one thread using segment */
+ shared_lt[idx].lkcnt = 0; /* no locks at the moment */
+ shared_lt[idx].seekpos = 0L; /* r/w pointer positioned at beg of block */
+ shared_gt[idx].handle = h; /* fill in data in global table */
+ shared_gt[idx].size = size;
+ shared_gt[idx].attr = mode;
+ shared_gt[idx].semkey = key;
+ shared_gt[idx].key = key;
+ shared_gt[idx].nprocdebug = 0;
+
+ break;
+ }
+ shared_demux(idx, SHARED_RDWRITE); /* hope this will not fail */
+ return(idx);
+ }
+
+
+int shared_attach(int idx)
+ { int r, r2;
+
+ if (SHARED_OK != (r = shared_mux(idx, SHARED_RDWRITE | SHARED_WAIT))) return(r);
+ if (SHARED_OK != (r = shared_map(idx)))
+ { shared_demux(idx, SHARED_RDWRITE);
+ return(r);
+ }
+ if (shared_attach_process(shared_gt[idx].sem)) /* try attach process */
+ { shmdt((char *)(shared_lt[idx].p)); /* cannot attach process, detach everything */
+ shared_lt[idx].p = NULL;
+ shared_demux(idx, SHARED_RDWRITE);
+ return(SHARED_BADARG);
+ }
+ shared_lt[idx].tcnt++; /* one more thread is using segment */
+ if (shared_gt[idx].attr & SHARED_RESIZE) /* if resizeable, detach and return special pointer */
+ { if (shmdt((char *)(shared_lt[idx].p))) r = SHARED_IPCERR; /* if segment is resizable, then detach segment */
+ shared_lt[idx].p = NULL;
+ }
+ shared_lt[idx].seekpos = 0L; /* r/w pointer positioned at beg of block */
+ r2 = shared_demux(idx, SHARED_RDWRITE);
+ return(r ? r : r2);
+ }
+
+
+
+static int shared_check_locked_index(int idx) /* verify that given idx is valid */
+ { int r;
+
+ if (0 == shared_init_called) /* delayed initialization */
+ { if (SHARED_OK != (r = shared_init(0))) return(r);
+
+ }
+ if ((idx < 0) || (idx >= shared_maxseg)) return(SHARED_BADARG);
+ if (NULL == shared_lt[idx].p) return(SHARED_BADARG); /* NULL pointer, not attached ?? */
+ if (0 == shared_lt[idx].lkcnt) return(SHARED_BADARG); /* not locked ?? */
+ if ((SHARED_ID_0 != (shared_lt[idx].p)->s.ID[0]) || (SHARED_ID_1 != (shared_lt[idx].p)->s.ID[1]) ||
+ (BLOCK_SHARED != (shared_lt[idx].p)->s.tflag)) /* invalid data in segment */
+ return(SHARED_BADARG);
+ return(SHARED_OK);
+ }
+
+
+
+static int shared_map(int idx) /* map all tables for given idx, check for validity */
+ { int h; /* have to obtain excl. access before calling shared_map */
+ BLKHEAD *bp;
+
+ if ((idx < 0) || (idx >= shared_maxseg)) return(SHARED_BADARG);
+ if (SHARED_INVALID == shared_gt[idx].key) return(SHARED_BADARG);
+ if (SHARED_INVALID == (h = shmget(shared_gt[idx].key, 1, shared_create_mode))) return(SHARED_BADARG);
+ if (((BLKHEAD *)SHARED_INVALID) == (bp = (BLKHEAD *)shmat(h, 0, 0))) return(SHARED_BADARG);
+ if ((SHARED_ID_0 != bp->s.ID[0]) || (SHARED_ID_1 != bp->s.ID[1]) || (BLOCK_SHARED != bp->s.tflag) || (h != shared_gt[idx].handle))
+ { shmdt((char *)bp); /* invalid segment, detach everything */
+ return(SHARED_BADARG);
+
+ }
+ if (shared_gt[idx].sem != semget(shared_gt[idx].semkey, 1, shared_create_mode)) /* check if sema is still there */
+ { shmdt((char *)bp); /* cannot attach semaphore, detach everything */
+ return(SHARED_BADARG);
+ }
+ shared_lt[idx].p = bp; /* store pointer to shmem data */
+ return(SHARED_OK);
+ }
+
+
+static int shared_validate(int idx, int mode) /* use intrnally inside crit.sect !!! */
+ { int r;
+
+ if (SHARED_OK != (r = shared_mux(idx, mode))) return(r); /* idx checked by shared_mux */
+ if (NULL == shared_lt[idx].p)
+ if (SHARED_OK != (r = shared_map(idx)))
+ { shared_demux(idx, mode);
+ return(r);
+ }
+ if ((SHARED_ID_0 != (shared_lt[idx].p)->s.ID[0]) || (SHARED_ID_1 != (shared_lt[idx].p)->s.ID[1]) || (BLOCK_SHARED != (shared_lt[idx].p)->s.tflag))
+ { shared_demux(idx, mode);
+ return(r);
+ }
+ return(SHARED_OK);
+ }
+
+
+SHARED_P shared_realloc(int idx, long newsize) /* realloc shared memory segment */
+ { int h, key, i, r;
+ BLKHEAD *bp;
+ long transfersize;
+
+ r = SHARED_OK;
+ if (newsize < 0) return(NULL);
+ if (shared_check_locked_index(idx)) return(NULL);
+ if (0 == (shared_gt[idx].attr & SHARED_RESIZE)) return(NULL);
+ if (-1 != shared_lt[idx].lkcnt) return(NULL); /* check for RW lock */
+ if (shared_adjust_size(shared_gt[idx].size) == shared_adjust_size(newsize))
+ { shared_gt[idx].size = newsize;
+
+ return((SHARED_P)((shared_lt[idx].p) + 1));
+ }
+ for (i = 0; ; i++)
+ { if (i >= shared_range) return(NULL); /* table full, signal error & exit */
+ key = shared_kbase + ((i + shared_get_hash(newsize, idx)) % shared_range);
+ h = shmget(key, shared_adjust_size(newsize), IPC_CREAT | IPC_EXCL | shared_create_mode);
+ if (SHARED_INVALID == h) continue; /* segment already accupied */
+ bp = (BLKHEAD *)shmat(h, 0, 0); /* try attach */
+ if (((BLKHEAD *)SHARED_INVALID) == bp) /* cannot attach, delete segment, try with another key */
+ { shmctl(h, IPC_RMID, 0);
+ continue;
+ }
+ *bp = *(shared_lt[idx].p); /* copy header, then data */
+ transfersize = ((newsize < shared_gt[idx].size) ? newsize : shared_gt[idx].size);
+ if (transfersize > 0)
+ memcpy((void *)(bp + 1), (void *)((shared_lt[idx].p) + 1), transfersize);
+ if (shmdt((char *)(shared_lt[idx].p))) r = SHARED_IPCERR; /* try to detach old segment */
+ if (shmctl(shared_gt[idx].handle, IPC_RMID, 0)) if (SHARED_OK == r) r = SHARED_IPCERR; /* destroy old shared memory segment */
+ shared_gt[idx].size = newsize; /* signal new size */
+ shared_gt[idx].handle = h; /* signal new handle */
+ shared_gt[idx].key = key; /* signal new key */
+ shared_lt[idx].p = bp;
+ break;
+ }
+ return((SHARED_P)(bp + 1));
+ }
+
+
+int shared_free(int idx) /* detach segment, if last process & !PERSIST, destroy segment */
+ { int cnt, r, r2;
+
+ if (SHARED_OK != (r = shared_validate(idx, SHARED_RDWRITE | SHARED_WAIT))) return(r);
+ if (SHARED_OK != (r = shared_detach_process(shared_gt[idx].sem))) /* update number of processes using segment */
+ { shared_demux(idx, SHARED_RDWRITE);
+ return(r);
+ }
+ shared_lt[idx].tcnt--; /* update number of threads using segment */
+ if (shared_lt[idx].tcnt > 0) return(shared_demux(idx, SHARED_RDWRITE)); /* if more threads are using segment we are done */
+ if (shmdt((char *)(shared_lt[idx].p))) /* if, we are the last thread, try to detach segment */
+ { shared_demux(idx, SHARED_RDWRITE);
+ return(SHARED_IPCERR);
+ }
+ shared_lt[idx].p = NULL; /* clear entry in local table */
+ shared_lt[idx].seekpos = 0L; /* r/w pointer positioned at beg of block */
+ if (-1 == (cnt = shared_process_count(shared_gt[idx].sem))) /* get number of processes hanging on segment */
+ { shared_demux(idx, SHARED_RDWRITE);
+ return(SHARED_IPCERR);
+ }
+ if ((0 == cnt) && (0 == (shared_gt[idx].attr & SHARED_PERSIST))) r = shared_destroy_entry(idx); /* no procs on seg, destroy it */
+ r2 = shared_demux(idx, SHARED_RDWRITE);
+ return(r ? r : r2);
+ }
+
+
+SHARED_P shared_lock(int idx, int mode) /* lock given segment for exclusive access */
+ { int r;
+
+ if (shared_mux(idx, mode)) return(NULL); /* idx checked by shared_mux */
+ if (0 != shared_lt[idx].lkcnt) /* are we already locked ?? */
+ if (SHARED_OK != (r = shared_map(idx)))
+ { shared_demux(idx, mode);
+ return(NULL);
+ }
+ if (NULL == shared_lt[idx].p) /* stupid pointer ?? */
+ if (SHARED_OK != (r = shared_map(idx)))
+ { shared_demux(idx, mode);
+ return(NULL);
+ }
+ if ((SHARED_ID_0 != (shared_lt[idx].p)->s.ID[0]) || (SHARED_ID_1 != (shared_lt[idx].p)->s.ID[1]) || (BLOCK_SHARED != (shared_lt[idx].p)->s.tflag))
+ { shared_demux(idx, mode);
+ return(NULL);
+ }
+ if (mode & SHARED_RDWRITE)
+ { shared_lt[idx].lkcnt = -1;
+
+ shared_gt[idx].nprocdebug++;
+ }
+
+ else shared_lt[idx].lkcnt++;
+ shared_lt[idx].seekpos = 0L; /* r/w pointer positioned at beg of block */
+ return((SHARED_P)((shared_lt[idx].p) + 1));
+ }
+
+
+int shared_unlock(int idx) /* unlock given segment, assumes seg is locked !! */
+ { int r, r2, mode;
+
+ if (SHARED_OK != (r = shared_check_locked_index(idx))) return(r);
+ if (shared_lt[idx].lkcnt > 0)
+ { shared_lt[idx].lkcnt--; /* unlock read lock */
+ mode = SHARED_RDONLY;
+ }
+ else
+ { shared_lt[idx].lkcnt = 0; /* unlock write lock */
+ shared_gt[idx].nprocdebug--;
+ mode = SHARED_RDWRITE;
+ }
+ if (0 == shared_lt[idx].lkcnt) if (shared_gt[idx].attr & SHARED_RESIZE)
+ { if (shmdt((char *)(shared_lt[idx].p))) r = SHARED_IPCERR; /* segment is resizable, then detach segment */
+ shared_lt[idx].p = NULL; /* signal detachment in local table */
+ }
+ r2 = shared_demux(idx, mode); /* unlock segment, rest is only parameter checking */
+ return(r ? r : r2);
+ }
+
+ /* API routines - support and info routines */
+
+
+int shared_attr(int idx) /* get the attributes of the shared memory segment */
+ { int r;
+
+ if (shared_check_locked_index(idx)) return(SHARED_INVALID);
+ r = shared_gt[idx].attr;
+ return(r);
+ }
+
+
+int shared_set_attr(int idx, int newattr) /* get the attributes of the shared memory segment */
+ { int r;
+
+ if (shared_check_locked_index(idx)) return(SHARED_INVALID);
+ if (-1 != shared_lt[idx].lkcnt) return(SHARED_INVALID); /* ADDED - check for RW lock */
+ r = shared_gt[idx].attr;
+ shared_gt[idx].attr = newattr;
+ return(r);
+
+ }
+
+
+int shared_set_debug(int mode) /* set/reset debug mode */
+ { int r = shared_debug;
+
+ shared_debug = mode;
+ return(r);
+ }
+
+
+int shared_set_createmode(int mode) /* set/reset debug mode */
+ { int r = shared_create_mode;
+
+ shared_create_mode = mode;
+ return(r);
+ }
+
+
+
+
+int shared_list(int id)
+ { int i, r;
+
+ if (NULL == shared_gt) return(SHARED_NOTINIT); /* not initialized */
+ if (NULL == shared_lt) return(SHARED_NOTINIT); /* not initialized */
+ if (shared_debug) printf("shared_list:");
+ r = SHARED_OK;
+ printf(" Idx Key Nproc Size Flags\n");
+ printf("==============================================\n");
+ for (i=0; i<shared_maxseg; i++)
+ { if (-1 != id) if (i != id) continue;
+ if (SHARED_INVALID == shared_gt[i].key) continue; /* unused slot */
+ switch (shared_mux(i, SHARED_NOWAIT | SHARED_RDONLY)) /* acquire exclusive access to segment, but do not wait */
+
+ { case SHARED_AGAIN:
+ printf("!%3d %08lx %4d %8d", i, (unsigned long int)shared_gt[i].key,
+ shared_gt[i].nprocdebug, shared_gt[i].size);
+ if (SHARED_RESIZE & shared_gt[i].attr) printf(" RESIZABLE");
+ if (SHARED_PERSIST & shared_gt[i].attr) printf(" PERSIST");
+ printf("\n");
+ break;
+ case SHARED_OK:
+ printf(" %3d %08lx %4d %8d", i, (unsigned long int)shared_gt[i].key,
+
+ shared_gt[i].nprocdebug, shared_gt[i].size);
+ if (SHARED_RESIZE & shared_gt[i].attr) printf(" RESIZABLE");
+ if (SHARED_PERSIST & shared_gt[i].attr) printf(" PERSIST");
+ printf("\n");
+ shared_demux(i, SHARED_RDONLY);
+ break;
+ default:
+ continue;
+ }
+ }
+ if (shared_debug) printf(" done\n");
+ return(r); /* table full */
+ }
+
+
+int shared_uncond_delete(int id)
+ { int i, r;
+
+ if (NULL == shared_gt) return(SHARED_NOTINIT); /* not initialized */
+ if (NULL == shared_lt) return(SHARED_NOTINIT); /* not initialized */
+ if (shared_debug) printf("shared_uncond_delete:");
+ r = SHARED_OK;
+ for (i=0; i<shared_maxseg; i++)
+ { if (-1 != id) if (i != id) continue;
+ if (shared_attach(i))
+ { if (-1 != id) printf("no such handle\n");
+ continue;
+ }
+ printf("handle %d:", i);
+ if (NULL == shared_lock(i, SHARED_RDWRITE | SHARED_NOWAIT))
+ { printf(" cannot lock in RW mode, not deleted\n");
+ continue;
+ }
+ if (shared_set_attr(i, SHARED_RESIZE) >= SHARED_ERRBASE)
+ { printf(" cannot clear PERSIST attribute");
+ }
+ if (shared_free(i))
+ { printf(" delete failed\n");
+ }
+ else
+ { printf(" deleted\n");
+ }
+ }
+ if (shared_debug) printf(" done\n");
+ return(r); /* table full */
+ }
+
+
+/************************* CFITSIO DRIVER FUNCTIONS ***************************/
+
+int smem_init(void)
+ { return(0);
+ }
+
+int smem_shutdown(void)
+
+ { if (shared_init_called) shared_cleanup();
+ return(0);
+ }
+
+int smem_setoptions(int option)
+ { option = 0;
+ return(0);
+ }
+
+
+int smem_getoptions(int *options)
+ { if (NULL == options) return(SHARED_NULPTR);
+ *options = 0;
+ return(0);
+ }
+
+int smem_getversion(int *version)
+ { if (NULL == version) return(SHARED_NULPTR);
+ *version = 10;
+ return(0);
+ }
+
+
+int smem_open(char *filename, int rwmode, int *driverhandle)
+ { int h, nitems, r;
+ DAL_SHM_SEGHEAD *sp;
+
+
+ if (NULL == filename) return(SHARED_NULPTR);
+ if (NULL == driverhandle) return(SHARED_NULPTR);
+ nitems = sscanf(filename, "h%d", &h);
+ if (1 != nitems) return(SHARED_BADARG);
+
+ if (SHARED_OK != (r = shared_attach(h))) return(r);
+
+ if (NULL == (sp = (DAL_SHM_SEGHEAD *)shared_lock(h,
+ ((READWRITE == rwmode) ? SHARED_RDWRITE : SHARED_RDONLY))))
+ { shared_free(h);
+ return(SHARED_BADARG);
+ }
+
+ if ((h != sp->h) || (DAL_SHM_SEGHEAD_ID != sp->ID))
+ { shared_unlock(h);
+ shared_free(h);
+
+ return(SHARED_BADARG);
+ }
+
+ *driverhandle = h;
+ return(0);
+ }
+
+
+int smem_create(char *filename, int *driverhandle)
+ { DAL_SHM_SEGHEAD *sp;
+ int h, sz, nitems;
+
+ if (NULL == filename) return(SHARED_NULPTR); /* currently ignored */
+ if (NULL == driverhandle) return(SHARED_NULPTR);
+ nitems = sscanf(filename, "h%d", &h);
+ if (1 != nitems) return(SHARED_BADARG);
+
+ if (SHARED_INVALID == (h = shared_malloc(sz = 2880 + sizeof(DAL_SHM_SEGHEAD),
+ SHARED_RESIZE | SHARED_PERSIST, h)))
+ return(SHARED_NOMEM);
+
+ if (NULL == (sp = (DAL_SHM_SEGHEAD *)shared_lock(h, SHARED_RDWRITE)))
+ { shared_free(h);
+ return(SHARED_BADARG);
+ }
+
+ sp->ID = DAL_SHM_SEGHEAD_ID;
+ sp->h = h;
+ sp->size = sz;
+ sp->nodeidx = -1;
+
+ *driverhandle = h;
+
+ return(0);
+ }
+
+
+int smem_close(int driverhandle)
+ { int r;
+
+ if (SHARED_OK != (r = shared_unlock(driverhandle))) return(r);
+ return(shared_free(driverhandle));
+ }
+
+int smem_remove(char *filename)
+ { int nitems, h, r;
+
+ if (NULL == filename) return(SHARED_NULPTR);
+ nitems = sscanf(filename, "h%d", &h);
+ if (1 != nitems) return(SHARED_BADARG);
+
+ if (0 == shared_check_locked_index(h)) /* are we locked ? */
+
+ { if (-1 != shared_lt[h].lkcnt) /* are we locked RO ? */
+ { if (SHARED_OK != (r = shared_unlock(h))) return(r); /* yes, so relock in RW */
+ if (NULL == shared_lock(h, SHARED_RDWRITE)) return(SHARED_BADARG);
+ }
+
+ }
+ else /* not locked */
+ { if (SHARED_OK != (r = smem_open(filename, READWRITE, &h)))
+ return(r); /* so open in RW mode */
+ }
+
+ shared_set_attr(h, SHARED_RESIZE); /* delete PERSIST attribute */
+ return(smem_close(h)); /* detach segment (this will delete it) */
+ }
+
+int smem_size(int driverhandle, OFF_T *size)
+ {
+ if (NULL == size) return(SHARED_NULPTR);
+ if (shared_check_locked_index(driverhandle)) return(SHARED_INVALID);
+ *size = (OFF_T) (shared_gt[driverhandle].size - sizeof(DAL_SHM_SEGHEAD));
+ return(0);
+ }
+
+int smem_flush(int driverhandle)
+ {
+ if (shared_check_locked_index(driverhandle)) return(SHARED_INVALID);
+ return(0);
+ }
+
+int smem_seek(int driverhandle, OFF_T offset)
+ {
+ if (offset < 0) return(SHARED_BADARG);
+ if (shared_check_locked_index(driverhandle)) return(SHARED_INVALID);
+ shared_lt[driverhandle].seekpos = offset;
+ return(0);
+ }
+
+int smem_read(int driverhandle, void *buffer, long nbytes)
+ {
+ if (NULL == buffer) return(SHARED_NULPTR);
+ if (shared_check_locked_index(driverhandle)) return(SHARED_INVALID);
+ if (nbytes < 0) return(SHARED_BADARG);
+ if ((shared_lt[driverhandle].seekpos + nbytes) > shared_gt[driverhandle].size)
+ return(SHARED_BADARG); /* read beyond EOF */
+
+ memcpy(buffer,
+ ((char *)(((DAL_SHM_SEGHEAD *)(shared_lt[driverhandle].p + 1)) + 1)) +
+ shared_lt[driverhandle].seekpos,
+ nbytes);
+
+ shared_lt[driverhandle].seekpos += nbytes;
+ return(0);
+ }
+
+int smem_write(int driverhandle, void *buffer, long nbytes)
+ {
+ if (NULL == buffer) return(SHARED_NULPTR);
+ if (shared_check_locked_index(driverhandle)) return(SHARED_INVALID);
+ if (-1 != shared_lt[driverhandle].lkcnt) return(SHARED_INVALID); /* are we locked RW ? */
+
+ if (nbytes < 0) return(SHARED_BADARG);
+ if ((unsigned long)(shared_lt[driverhandle].seekpos + nbytes) > (unsigned long)(shared_gt[driverhandle].size - sizeof(DAL_SHM_SEGHEAD)))
+ { /* need to realloc shmem */
+ if (NULL == shared_realloc(driverhandle, shared_lt[driverhandle].seekpos + nbytes + sizeof(DAL_SHM_SEGHEAD)))
+ return(SHARED_NOMEM);
+ }
+
+ memcpy(((char *)(((DAL_SHM_SEGHEAD *)(shared_lt[driverhandle].p + 1)) + 1)) +
+ shared_lt[driverhandle].seekpos,
+ buffer,
+ nbytes);
+
+ shared_lt[driverhandle].seekpos += nbytes;
+ return(0);
+ }
+#endif
diff --git a/pkg/tbtables/cfitsio/drvrsmem.h b/pkg/tbtables/cfitsio/drvrsmem.h
new file mode 100644
index 00000000..9b876013
--- /dev/null
+++ b/pkg/tbtables/cfitsio/drvrsmem.h
@@ -0,0 +1,179 @@
+/* S H A R E D M E M O R Y D R I V E R
+ =======================================
+
+ by Jerzy.Borkowski@obs.unige.ch
+
+09-Mar-98 : initial version 1.0 released
+23-Mar-98 : shared_malloc now accepts new handle as an argument
+*/
+
+
+#include <sys/ipc.h> /* this is necessary for Solaris/Linux */
+#include <sys/shm.h>
+#include <sys/sem.h>
+
+#ifdef _AIX
+#include <fcntl.h>
+#else
+#include <sys/fcntl.h>
+#endif
+
+ /* configuration parameters */
+
+#define SHARED_MAXSEG (16) /* maximum number of shared memory blocks */
+
+#define SHARED_KEYBASE (14011963) /* base for shared memory keys, may be overriden by getenv */
+#define SHARED_FDNAME ("/tmp/.shmem-lockfile") /* template for lock file name */
+
+#define SHARED_ENV_KEYBASE ("SHMEM_LIB_KEYBASE") /* name of environment variable */
+#define SHARED_ENV_MAXSEG ("SHMEM_LIB_MAXSEG") /* name of environment variable */
+
+ /* useful constants */
+
+#define SHARED_RDONLY (0) /* flag for shared_(un)lock, lock for read */
+#define SHARED_RDWRITE (1) /* flag for shared_(un)lock, lock for write */
+#define SHARED_WAIT (0) /* flag for shared_lock, block if cannot lock immediate */
+#define SHARED_NOWAIT (2) /* flag for shared_lock, fail if cannot lock immediate */
+#define SHARED_NOLOCK (0x100) /* flag for shared_validate function */
+
+#define SHARED_RESIZE (4) /* flag for shared_malloc, object is resizeable */
+#define SHARED_PERSIST (8) /* flag for shared_malloc, object is not deleted after last proc detaches */
+
+#define SHARED_INVALID (-1) /* invalid handle for semaphore/shared memory */
+
+#define SHARED_EMPTY (0) /* entries for shared_used table */
+#define SHARED_USED (1)
+
+#define SHARED_GRANUL (16384) /* granularity of shared_malloc allocation = phys page size, system dependent */
+
+
+
+ /* checkpoints in shared memory segments - might be omitted */
+
+#define SHARED_ID_0 ('J') /* first byte of identifier in BLKHEAD */
+#define SHARED_ID_1 ('B') /* second byte of identifier in BLKHEAD */
+
+#define BLOCK_REG (0) /* value for tflag member of BLKHEAD */
+#define BLOCK_SHARED (1) /* value for tflag member of BLKHEAD */
+
+ /* generic error codes */
+
+#define SHARED_OK (0)
+
+#define SHARED_ERR_MIN_IDX SHARED_BADARG
+#define SHARED_ERR_MAX_IDX SHARED_NORESIZE
+
+
+#define DAL_SHM_FREE (0)
+#define DAL_SHM_USED (1)
+
+#define DAL_SHM_ID0 ('D')
+#define DAL_SHM_ID1 ('S')
+#define DAL_SHM_ID2 ('M')
+
+#define DAL_SHM_SEGHEAD_ID (0x19630114)
+
+
+
+ /* data types */
+
+/* BLKHEAD object is placed at the beginning of every memory segment (both
+ shared and regular) to allow automatic recognition of segments type */
+
+typedef union
+ { struct BLKHEADstruct
+ { char ID[2]; /* ID = 'JB', just as a checkpoint */
+ char tflag; /* is it shared memory or regular one ? */
+ int handle; /* this is not necessary, used only for non-resizeable objects via ptr */
+ } s;
+ double d; /* for proper alignment on every machine */
+ } BLKHEAD;
+
+typedef void *SHARED_P; /* generic type of shared memory pointer */
+
+typedef struct SHARED_GTABstruct /* data type used in global table */
+ { int sem; /* access semaphore (1 field): process count */
+ int semkey; /* key value used to generate semaphore handle */
+ int key; /* key value used to generate shared memory handle (realloc changes it) */
+ int handle; /* handle of shared memory segment */
+ int size; /* size of shared memory segment */
+ int nprocdebug; /* attached proc counter, helps remove zombie segments */
+ char attr; /* attributes of shared memory object */
+ } SHARED_GTAB;
+
+typedef struct SHARED_LTABstruct /* data type used in local table */
+ { BLKHEAD *p; /* pointer to segment (may be null) */
+ int tcnt; /* number of threads in this process attached to segment */
+ int lkcnt; /* >=0 <- number of read locks, -1 - write lock */
+ long seekpos; /* current pointer position, read/write/seek operations change it */
+ } SHARED_LTAB;
+
+
+ /* system dependent definitions */
+
+#ifndef HAVE_FLOCK_T
+typedef struct flock flock_t;
+#define HAVE_FLOCK_T
+#endif
+
+#ifndef HAVE_UNION_SEMUN
+union semun
+ { int val;
+ struct semid_ds *buf;
+ unsigned short *array;
+ };
+#define HAVE_UNION_SEMUN
+#endif
+
+
+typedef struct DAL_SHM_SEGHEAD_STRUCT DAL_SHM_SEGHEAD;
+
+struct DAL_SHM_SEGHEAD_STRUCT
+ { int ID; /* ID for debugging */
+ int h; /* handle of sh. mem */
+ int size; /* size of data area */
+ int nodeidx; /* offset of root object (node struct typically) */
+ };
+
+ /* API routines */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void shared_cleanup(void); /* must be called at exit/abort */
+int shared_init(int debug_msgs); /* must be called before any other shared memory routine */
+int shared_recover(int id); /* try to recover dormant segment(s) after applic crash */
+int shared_malloc(long size, int mode, int newhandle); /* allocate n-bytes of shared memory */
+int shared_attach(int idx); /* attach to segment given index to table */
+int shared_free(int idx); /* release shared memory */
+SHARED_P shared_lock(int idx, int mode); /* lock segment for reading */
+SHARED_P shared_realloc(int idx, long newsize); /* reallocate n-bytes of shared memory (ON LOCKED SEGMENT ONLY) */
+int shared_size(int idx); /* get size of attached shared memory segment (ON LOCKED SEGMENT ONLY) */
+int shared_attr(int idx); /* get attributes of attached shared memory segment (ON LOCKED SEGMENT ONLY) */
+int shared_set_attr(int idx, int newattr); /* set attributes of attached shared memory segment (ON LOCKED SEGMENT ONLY) */
+int shared_unlock(int idx); /* unlock segment (ON LOCKED SEGMENT ONLY) */
+int shared_set_debug(int debug_msgs); /* set/reset debug mode */
+int shared_set_createmode(int mode); /* set/reset debug mode */
+int shared_list(int id); /* list segment(s) */
+int shared_uncond_delete(int id); /* uncondintionally delete (NOWAIT operation) segment(s) */
+int shared_getaddr(int id, char **address); /* get starting address of FITS file in segment */
+
+int smem_init(void);
+int smem_shutdown(void);
+int smem_setoptions(int options);
+int smem_getoptions(int *options);
+int smem_getversion(int *version);
+int smem_open(char *filename, int rwmode, int *driverhandle);
+int smem_create(char *filename, int *driverhandle);
+int smem_close(int driverhandle);
+int smem_remove(char *filename);
+int smem_size(int driverhandle, OFF_T *size);
+int smem_flush(int driverhandle);
+int smem_seek(int driverhandle, OFF_T offset);
+int smem_read(int driverhandle, void *buffer, long nbytes);
+int smem_write(int driverhandle, void *buffer, long nbytes);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/pkg/tbtables/cfitsio/editcol.c b/pkg/tbtables/cfitsio/editcol.c
new file mode 100644
index 00000000..57e7622f
--- /dev/null
+++ b/pkg/tbtables/cfitsio/editcol.c
@@ -0,0 +1,2068 @@
+/* This file, editcol.c, contains the set of FITSIO routines that */
+/* insert or delete rows or columns in a table or resize an image */
+
+/* The FITSIO software was written by William Pence at the High Energy */
+/* Astrophysic Science Archive Research Center (HEASARC) at the NASA */
+/* Goddard Space Flight Center. */
+
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include "fitsio2.h"
+/*--------------------------------------------------------------------------*/
+int ffrsim(fitsfile *fptr, /* I - FITS file pointer */
+ int bitpix, /* I - bits per pixel */
+ int naxis, /* I - number of axes in the array */
+ long *naxes, /* I - size of each axis */
+ int *status) /* IO - error status */
+/*
+ resize an existing primary array or IMAGE extension.
+*/
+{
+ int ii, simple, obitpix, onaxis, extend, nmodify;
+ long onaxes[99], pcount, gcount, nblocks, longval;
+ long longbitpix;
+ OFF_T newsize, oldsize;
+ char comment[FLEN_COMMENT], keyname[FLEN_KEYWORD], message[FLEN_ERRMSG];
+
+ if (*status > 0)
+ return(*status);
+
+ /* reset position to the correct HDU if necessary */
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ {
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+ }
+ /* rescan header if data structure is undefined */
+ else if ((fptr->Fptr)->datastart == DATA_UNDEFINED)
+ if ( ffrdef(fptr, status) > 0)
+ return(*status);
+
+ /* get current image size parameters */
+ if (ffghpr(fptr, 99, &simple, &obitpix, &onaxis, onaxes, &pcount,
+ &gcount, &extend, status) > 0)
+ return(*status);
+
+ longbitpix = bitpix;
+
+ /* test for the 2 special cases that represent unsigned integers */
+ if (longbitpix == USHORT_IMG)
+ longbitpix = SHORT_IMG;
+ else if (longbitpix == ULONG_IMG)
+ longbitpix = LONG_IMG;
+
+ /* test that the new values are legal */
+
+ if (longbitpix != BYTE_IMG && longbitpix != SHORT_IMG &&
+ longbitpix != LONG_IMG && longbitpix != LONGLONG_IMG &&
+ longbitpix != FLOAT_IMG && longbitpix != DOUBLE_IMG)
+ {
+ sprintf(message,
+ "Illegal value for BITPIX keyword: %d", bitpix);
+ ffpmsg(message);
+ return(*status = BAD_BITPIX);
+ }
+
+ if (naxis < 0 || naxis > 999)
+ {
+ sprintf(message,
+ "Illegal value for NAXIS keyword: %d", naxis);
+ ffpmsg(message);
+ return(*status = BAD_NAXIS);
+ }
+
+ if (naxis == 0)
+ newsize = 0;
+ else
+ newsize = 1;
+
+ for (ii = 0; ii < naxis; ii++)
+ {
+ if (naxes[ii] < 0)
+ {
+ sprintf(message,
+ "Illegal value for NAXIS%d keyword: %ld", ii + 1, naxes[ii]);
+ ffpmsg(message);
+ return(*status = BAD_NAXES);
+ }
+
+ newsize *= naxes[ii]; /* compute new image size, in pixels */
+ }
+
+ /* compute size of old image, in bytes */
+
+ if (onaxis == 0)
+ oldsize = 0;
+ else
+ {
+ oldsize = 1;
+ for (ii = 0; ii < onaxis; ii++)
+ oldsize *= onaxes[ii];
+ oldsize = (oldsize + pcount) * gcount * (abs(obitpix) / 8);
+ }
+
+ oldsize = (oldsize + 2879) / 2880; /* old size, in blocks */
+
+ newsize = (newsize + pcount) * gcount * (abs(longbitpix) / 8);
+ newsize = (newsize + 2879) / 2880; /* new size, in blocks */
+
+ if (newsize > oldsize) /* have to insert new blocks for image */
+ {
+ nblocks = newsize - oldsize;
+ if (ffiblk(fptr, nblocks, 1, status) > 0)
+ return(*status);
+ }
+ else if (oldsize > newsize) /* have to delete blocks from image */
+ {
+ nblocks = oldsize - newsize;
+ if (ffdblk(fptr, nblocks, status) > 0)
+ return(*status);
+ }
+
+ /* now update the header keywords */
+
+ strcpy(comment,"&"); /* special value to leave comments unchanged */
+
+ if (longbitpix != obitpix)
+ { /* update BITPIX value */
+ ffmkyj(fptr, "BITPIX", longbitpix, comment, status);
+ }
+
+ if (naxis != onaxis)
+ { /* update NAXIS value */
+ longval = naxis;
+ ffmkyj(fptr, "NAXIS", longval, comment, status);
+ }
+
+ /* modify the existing NAXISn keywords */
+ nmodify = minvalue(naxis, onaxis);
+ for (ii = 0; ii < nmodify; ii++)
+ {
+ ffkeyn("NAXIS", ii+1, keyname, status);
+ ffmkyj(fptr, keyname, naxes[ii], comment, status);
+ }
+
+ if (naxis > onaxis) /* insert additional NAXISn keywords */
+ {
+ strcpy(comment,"length of data axis");
+ for (ii = onaxis; ii < naxis; ii++)
+ {
+ ffkeyn("NAXIS", ii+1, keyname, status);
+ ffikyj(fptr, keyname, naxes[ii], comment, status);
+ }
+ }
+ else if (onaxis > naxis) /* delete old NAXISn keywords */
+ {
+ for (ii = naxis; ii < onaxis; ii++)
+ {
+ ffkeyn("NAXIS", ii+1, keyname, status);
+ ffdkey(fptr, keyname, status);
+ }
+ }
+
+ /* Update the BSCALE and BZERO keywords, if an unsigned integer image */
+ if (bitpix == USHORT_IMG)
+ {
+ strcpy(comment, "offset data range to that of unsigned short");
+ ffukyg(fptr, "BZERO", 32768., 0, comment, status);
+ strcpy(comment, "default scaling factor");
+ ffukyg(fptr, "BSCALE", 1.0, 0, comment, status);
+ }
+ else if (bitpix == ULONG_IMG)
+ {
+ strcpy(comment, "offset data range to that of unsigned long");
+ ffukyg(fptr, "BZERO", 2147483648., 0, comment, status);
+ strcpy(comment, "default scaling factor");
+ ffukyg(fptr, "BSCALE", 1.0, 0, comment, status);
+ }
+
+ /* re-read the header, to make sure structures are updated */
+ ffrdef(fptr, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffirow(fitsfile *fptr, /* I - FITS file pointer */
+ long firstrow, /* I - insert space AFTER this row */
+ /* 0 = insert space at beginning of table */
+ long nrows, /* I - number of rows to insert */
+ int *status) /* IO - error status */
+/*
+ insert NROWS blank rows immediated after row firstrow (1 = first row).
+ Set firstrow = 0 to insert space at the beginning of the table.
+*/
+{
+ int tstatus;
+ long naxis1, naxis2;
+ OFF_T datasize, firstbyte, nshift, nbytes;
+ long freespace, nblock;
+
+ if (*status > 0)
+ return(*status);
+
+ /* reset position to the correct HDU if necessary */
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ {
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+ }
+ /* rescan header if data structure is undefined */
+ else if ((fptr->Fptr)->datastart == DATA_UNDEFINED)
+ if ( ffrdef(fptr, status) > 0)
+ return(*status);
+
+ if ((fptr->Fptr)->hdutype == IMAGE_HDU)
+ {
+ ffpmsg("Can only add rows to TABLE or BINTABLE extension (ffirow)");
+ return(*status = NOT_TABLE);
+ }
+
+ if (nrows < 0 )
+ return(*status = NEG_BYTES);
+ else if (nrows == 0)
+ return(*status); /* no op, so just return */
+
+ /* get the current size of the table */
+ /* use internal structure since NAXIS2 keyword may not be up to date */
+ naxis1 = (long) (fptr->Fptr)->rowlength;
+ naxis2 = (fptr->Fptr)->numrows;
+
+ if (firstrow > naxis2)
+ {
+ ffpmsg(
+ "Insert position greater than the number of rows in the table (ffirow)");
+ return(*status = BAD_ROW_NUM);
+ }
+ else if (firstrow < 0)
+ {
+ ffpmsg("Insert position is less than 0 (ffirow)");
+ return(*status = BAD_ROW_NUM);
+ }
+
+ /* current data size */
+ datasize = (fptr->Fptr)->heapstart + (fptr->Fptr)->heapsize;
+ freespace = ( ( (datasize + 2879) / 2880) * 2880) - datasize;
+ nshift = (OFF_T)naxis1 * nrows; /* no. of bytes to add to table */
+
+ if ( (freespace - nshift) < 0) /* not enough existing space? */
+ {
+ nblock = (nshift - freespace + 2879) / 2880; /* number of blocks */
+ ffiblk(fptr, nblock, 1, status); /* insert the blocks */
+ }
+
+ firstbyte = (OFF_T)naxis1 * firstrow; /* relative insert position */
+ nbytes = datasize - firstbyte; /* no. of bytes to shift down */
+ firstbyte += ((fptr->Fptr)->datastart); /* absolute insert position */
+
+ ffshft(fptr, firstbyte, nbytes, nshift, status); /* shift rows and heap */
+
+ /* update the heap starting address */
+ (fptr->Fptr)->heapstart += nshift;
+
+ /* update the THEAP keyword if it exists */
+ tstatus = 0;
+ ffmkyj(fptr, "THEAP", (long)(fptr->Fptr)->heapstart, "&", &tstatus);
+
+ /* update the NAXIS2 keyword */
+ ffmkyj(fptr, "NAXIS2", naxis2 + nrows, "&", status);
+ ((fptr->Fptr)->numrows) += nrows;
+ ((fptr->Fptr)->origrows) += nrows;
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffdrow(fitsfile *fptr, /* I - FITS file pointer */
+ long firstrow, /* I - first row to delete (1 = first) */
+ long nrows, /* I - number of rows to delete */
+ int *status) /* IO - error status */
+/*
+ delete NROWS rows from table starting with firstrow (1 = first row of table).
+*/
+{
+ int tstatus;
+ long naxis1, naxis2;
+ OFF_T datasize, firstbyte, nbytes, nshift;
+ long freespace, nblock;
+ char comm[FLEN_COMMENT];
+
+ if (*status > 0)
+ return(*status);
+
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ {
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+ }
+ /* rescan header if data structure is undefined */
+ else if ((fptr->Fptr)->datastart == DATA_UNDEFINED)
+ if ( ffrdef(fptr, status) > 0)
+ return(*status);
+
+ if ((fptr->Fptr)->hdutype == IMAGE_HDU)
+ {
+ ffpmsg("Can only delete rows in TABLE or BINTABLE extension (ffdrow)");
+ return(*status = NOT_TABLE);
+ }
+
+ if (nrows < 0 )
+ return(*status = NEG_BYTES);
+ else if (nrows == 0)
+ return(*status); /* no op, so just return */
+
+ ffgkyj(fptr, "NAXIS1", &naxis1, comm, status); /* get the current */
+
+ /* ffgkyj(fptr, "NAXIS2", &naxis2, comm, status);*/ /* size of the table */
+
+ /* the NAXIS2 keyword may not be up to date, so use the structure value */
+ naxis2 = (fptr->Fptr)->numrows;
+
+ if (firstrow > naxis2)
+ {
+ ffpmsg(
+ "Delete position greater than the number of rows in the table (ffdrow)");
+ return(*status = BAD_ROW_NUM);
+ }
+ else if (firstrow < 1)
+ {
+ ffpmsg("Delete position is less than 1 (ffdrow)");
+ return(*status = BAD_ROW_NUM);
+ }
+ else if (firstrow + nrows - 1 > naxis2)
+ {
+ ffpmsg("No. of rows to delete exceeds size of table (ffdrow)");
+ return(*status = BAD_ROW_NUM);
+ }
+
+ nshift = (OFF_T)naxis1 * nrows; /* no. of bytes to delete from table */
+ /* cur size of data */
+ datasize = (fptr->Fptr)->heapstart + (fptr->Fptr)->heapsize;
+
+ firstbyte = (OFF_T)naxis1 * (firstrow + nrows - 1); /* relative del pos */
+ nbytes = datasize - firstbyte; /* no. of bytes to shift up */
+ firstbyte += ((fptr->Fptr)->datastart); /* absolute delete position */
+
+ ffshft(fptr, firstbyte, nbytes, nshift * (-1), status); /* shift data */
+
+ freespace = ( ( (datasize + 2879) / 2880) * 2880) - datasize;
+ nblock = (nshift + freespace) / 2880; /* number of blocks */
+
+ /* delete integral number blocks */
+ if (nblock > 0)
+ ffdblk(fptr, nblock, status);
+
+ /* update the heap starting address */
+ (fptr->Fptr)->heapstart -= nshift;
+
+ /* update the THEAP keyword if it exists */
+ tstatus = 0;
+ ffmkyj(fptr, "THEAP", (long)(fptr->Fptr)->heapstart, "&", &tstatus);
+
+ /* update the NAXIS2 keyword */
+ ffmkyj(fptr, "NAXIS2", naxis2 - nrows, "&", status);
+ ((fptr->Fptr)->numrows) -= nrows;
+ ((fptr->Fptr)->origrows) -= nrows;
+
+ /* Update the heap data, if any. This will remove any orphaned data */
+ /* that was only pointed to by the rows that have been deleted */
+ ffcmph(fptr, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffdrrg(fitsfile *fptr, /* I - FITS file pointer to table */
+ char *ranges, /* I - ranges of rows to delete (1 = first) */
+ int *status) /* IO - error status */
+/*
+ delete the ranges of rows from the table (1 = first row of table).
+
+The 'ranges' parameter typically looks like:
+ '10-20, 30 - 40, 55' or '50-'
+and gives a list of rows or row ranges separated by commas.
+*/
+{
+ char *cptr;
+ int nranges, nranges2, ii;
+ long *minrow, *maxrow, naxis2, nrows, *rowarray, jj, kk;
+
+ if (*status > 0)
+ return(*status);
+
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ {
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+ }
+ /* rescan header if data structure is undefined */
+ else if ((fptr->Fptr)->datastart == DATA_UNDEFINED)
+ if ( ffrdef(fptr, status) > 0)
+ return(*status);
+
+ if ((fptr->Fptr)->hdutype == IMAGE_HDU)
+ {
+ ffpmsg("Can only delete rows in TABLE or BINTABLE extension (ffdrrg)");
+ return(*status = NOT_TABLE);
+ }
+
+ /* the NAXIS2 keyword may not be up to date, so use the structure value */
+ naxis2 = (fptr->Fptr)->numrows;
+
+ /* find how many ranges were specified ( = no. of commas in string + 1) */
+ cptr = ranges;
+ for (nranges = 1; (cptr = strchr(cptr, ',')); nranges++)
+ cptr++;
+
+ minrow = calloc(nranges, sizeof(long));
+ maxrow = calloc(nranges, sizeof(long));
+
+ if (!minrow || !maxrow) {
+ *status = MEMORY_ALLOCATION;
+ ffpmsg("failed to allocate memory for row ranges (ffdrrg)");
+ if (maxrow) free(maxrow);
+ if (minrow) free(minrow);
+ return(*status);
+ }
+
+ /* parse range list into array of range min and max values */
+ ffrwrg(ranges, naxis2, nranges, &nranges2, minrow, maxrow, status);
+ if (*status > 0 || nranges2 == 0) {
+ free(maxrow);
+ free(minrow);
+ return(*status);
+ }
+
+ /* determine total number or rows to delete */
+ nrows = 0;
+ for (ii = 0; ii < nranges2; ii++) {
+ nrows = nrows + maxrow[ii] - minrow[ii] + 1;
+ }
+
+ rowarray = calloc(nrows, sizeof(long));
+ if (!rowarray) {
+ *status = MEMORY_ALLOCATION;
+ ffpmsg("failed to allocate memory for row array (ffdrrg)");
+ return(*status);
+ }
+
+ for (kk = 0, ii = 0; ii < nranges2; ii++) {
+ for (jj = minrow[ii]; jj <= maxrow[ii]; jj++) {
+ rowarray[kk] = jj;
+ kk++;
+ }
+ }
+
+ /* delete the rows */
+ ffdrws(fptr, rowarray, nrows, status);
+
+ free(rowarray);
+ free(maxrow);
+ free(minrow);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffdrws(fitsfile *fptr, /* I - FITS file pointer */
+ long *rownum, /* I - list of rows to delete (1 = first) */
+ long nrows, /* I - number of rows to delete */
+ int *status) /* IO - error status */
+/*
+ delete the list of rows from the table (1 = first row of table).
+*/
+{
+ OFF_T insertpos, nextrowpos;
+ long naxis1, naxis2, ii, nextrow;
+ char comm[FLEN_COMMENT];
+ unsigned char *buffer;
+
+ if (*status > 0)
+ return(*status);
+
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+
+ /* rescan header if data structure is undefined */
+ if ((fptr->Fptr)->datastart == DATA_UNDEFINED)
+ if ( ffrdef(fptr, status) > 0)
+ return(*status);
+
+ if ((fptr->Fptr)->hdutype == IMAGE_HDU)
+ {
+ ffpmsg("Can only delete rows in TABLE or BINTABLE extension (ffdrws)");
+ return(*status = NOT_TABLE);
+ }
+
+ if (nrows < 0 )
+ return(*status = NEG_BYTES);
+ else if (nrows == 0)
+ return(*status); /* no op, so just return */
+
+ ffgkyj(fptr, "NAXIS1", &naxis1, comm, status); /* row width */
+ ffgkyj(fptr, "NAXIS2", &naxis2, comm, status); /* number of rows */
+
+ /* check that input row list is in ascending order */
+ for (ii = 1; ii < nrows; ii++)
+ {
+ if (rownum[ii - 1] >= rownum[ii])
+ {
+ ffpmsg("row numbers are not in increasing order (ffdrws)");
+ return(*status = BAD_ROW_NUM);
+ }
+ }
+
+ if (rownum[0] < 1)
+ {
+ ffpmsg("first row to delete is less than 1 (ffdrws)");
+ return(*status = BAD_ROW_NUM);
+ }
+ else if (rownum[nrows - 1] > naxis2)
+ {
+ ffpmsg("last row to delete exceeds size of table (ffdrws)");
+ return(*status = BAD_ROW_NUM);
+ }
+
+ buffer = (unsigned char *) malloc(naxis1); /* buffer for one row */
+
+ if (!buffer)
+ {
+ ffpmsg("malloc failed (ffdrws)");
+ return(*status = MEMORY_ALLOCATION);
+ }
+
+ /* byte location to start of first row to delete, and the next row */
+ insertpos = (fptr->Fptr)->datastart + ((rownum[0] - 1) * naxis1);
+ nextrowpos = insertpos + naxis1;
+ nextrow = rownum[0] + 1;
+
+ /* work through the list of rows to delete */
+ for (ii = 1; ii < nrows; nextrow++, nextrowpos += naxis1)
+ {
+ if (nextrow < rownum[ii])
+ { /* keep this row, so copy it to the new position */
+
+ ffmbyt(fptr, nextrowpos, REPORT_EOF, status);
+ ffgbyt(fptr, naxis1, buffer, status); /* read the bytes */
+
+ ffmbyt(fptr, insertpos, IGNORE_EOF, status);
+ ffpbyt(fptr, naxis1, buffer, status); /* write the bytes */
+
+ if (*status > 0)
+ {
+ ffpmsg("error while copying good rows in table (ffdrws)");
+ free(buffer);
+ return(*status);
+ }
+ insertpos += naxis1;
+ }
+ else
+ { /* skip over this row since it is in the list */
+ ii++;
+ }
+ }
+
+ /* finished with all the rows to delete; copy remaining rows */
+ while(nextrow <= naxis2)
+ {
+ ffmbyt(fptr, nextrowpos, REPORT_EOF, status);
+ ffgbyt(fptr, naxis1, buffer, status); /* read the bytes */
+
+ ffmbyt(fptr, insertpos, IGNORE_EOF, status);
+ ffpbyt(fptr, naxis1, buffer, status); /* write the bytes */
+
+ if (*status > 0)
+ {
+ ffpmsg("failed to copy remaining rows in table (ffdrws)");
+ free(buffer);
+ return(*status);
+ }
+ insertpos += naxis1;
+ nextrowpos += naxis1;
+ nextrow++;
+ }
+ free(buffer);
+
+ /* now delete the empty rows at the end of the table */
+ ffdrow(fptr, naxis2 - nrows + 1, nrows, status);
+
+ /* Update the heap data, if any. This will remove any orphaned data */
+ /* that was only pointed to by the rows that have been deleted */
+ ffcmph(fptr, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffrwrg(
+ char *rowlist, /* I - list of rows and row ranges */
+ long maxrows, /* I - number of rows in the table */
+ int maxranges, /* I - max number of ranges to be returned */
+ int *numranges, /* O - number ranges returned */
+ long *minrow, /* O - first row in each range */
+ long *maxrow, /* O - last row in each range */
+ int *status) /* IO - status value */
+{
+/*
+ parse the input list of row ranges, returning the number of ranges,
+ and the min and max row value in each range.
+
+ The only characters allowed in the input rowlist are
+ decimal digits, minus sign, and comma (and non-significant spaces)
+
+ Example:
+
+ list = "10-20, 30-35,50"
+
+ would return numranges = 3, minrow[] = {10, 30, 50}, maxrow[] = {20, 35, 50}
+
+ error is returned if min value of range is > max value of range or if the
+ ranges are not monotonically increasing.
+*/
+ char *next;
+ long minval, maxval;
+
+ if (*status > 0)
+ return(*status);
+
+ if (maxrows <= 0 ) {
+ *status = RANGE_PARSE_ERROR;
+ ffpmsg("Input maximum range value is <= 0 (fits_parse_ranges)");
+ return(*status);
+ }
+
+ next = rowlist;
+ *numranges = 0;
+
+ while (*next == ' ')next++; /* skip spaces */
+
+ while (*next != '\0') {
+
+ /* find min value of next range; *next must be '-' or a digit */
+ if (*next == '-') {
+ minval = 1; /* implied minrow value = 1 */
+ } else if ( isdigit((int) *next) ) {
+ minval = strtol(next, &next, 10);
+ } else {
+ *status = RANGE_PARSE_ERROR;
+ ffpmsg("Syntax error in this row range list:");
+ ffpmsg(rowlist);
+ return(*status);
+ }
+
+ while (*next == ' ')next++; /* skip spaces */
+
+ /* find max value of next range; *next must be '-', or ',' */
+ if (*next == '-') {
+ next++;
+ while (*next == ' ')next++; /* skip spaces */
+
+ if ( isdigit((int) *next) ) {
+ maxval = strtol(next, &next, 10);
+ } else if (*next == ',' || *next == '\0') {
+ maxval = maxrows; /* implied max value */
+ } else {
+ *status = RANGE_PARSE_ERROR;
+ ffpmsg("Syntax error in this row range list:");
+ ffpmsg(rowlist);
+ return(*status);
+ }
+ } else if (*next == ',' || *next == '\0') {
+ maxval = minval; /* only a single integer in this range */
+ } else {
+ *status = RANGE_PARSE_ERROR;
+ ffpmsg("Syntax error in this row range list:");
+ ffpmsg(rowlist);
+ return(*status);
+ }
+
+ if (*numranges + 1 > maxranges) {
+ *status = RANGE_PARSE_ERROR;
+ ffpmsg("Overflowed maximum number of ranges (fits_parse_ranges)");
+ return(*status);
+ }
+
+ if (minval < 1 ) {
+ *status = RANGE_PARSE_ERROR;
+ ffpmsg("Syntax error in this row range list: row number < 1");
+ ffpmsg(rowlist);
+ return(*status);
+ }
+
+ if (maxval < minval) {
+ *status = RANGE_PARSE_ERROR;
+ ffpmsg("Syntax error in this row range list: min > max");
+ ffpmsg(rowlist);
+ return(*status);
+ }
+
+ if (*numranges > 0) {
+ if (minval <= maxrow[(*numranges) - 1]) {
+ *status = RANGE_PARSE_ERROR;
+ ffpmsg("Syntax error in this row range list. Range minimum is");
+ ffpmsg(" less than or equal to previous range maximum");
+ ffpmsg(rowlist);
+ return(*status);
+ }
+ }
+
+ if (minval <= maxrows) { /* ignore range if greater than maxrows */
+ if (maxval > maxrows)
+ maxval = maxrows;
+
+ minrow[*numranges] = minval;
+ maxrow[*numranges] = maxval;
+
+ (*numranges)++;
+ }
+
+ while (*next == ' ')next++; /* skip spaces */
+ if (*next == ',') {
+ next++;
+ while (*next == ' ')next++; /* skip more spaces */
+ }
+ }
+
+ if (*numranges == 0) { /* a null string was entered */
+ minrow[0] = 1;
+ maxrow[0] = maxrows;
+ *numranges = 1;
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fficol(fitsfile *fptr, /* I - FITS file pointer */
+ int numcol, /* I - position for new col. (1 = 1st) */
+ char *ttype, /* I - name of column (TTYPE keyword) */
+ char *tform, /* I - format of column (TFORM keyword) */
+ int *status) /* IO - error status */
+/*
+ Insert a new column into an existing table at position numcol. If
+ numcol is greater than the number of existing columns in the table
+ then the new column will be appended as the last column in the table.
+*/
+{
+ char *name, *format;
+
+ name = ttype;
+ format = tform;
+
+ fficls(fptr, numcol, 1, &name, &format, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fficls(fitsfile *fptr, /* I - FITS file pointer */
+ int fstcol, /* I - position for first new col. (1 = 1st) */
+ int ncols, /* I - number of columns to insert */
+ char **ttype, /* I - array of column names(TTYPE keywords) */
+ char **tform, /* I - array of formats of column (TFORM) */
+ int *status) /* IO - error status */
+/*
+ Insert 1 or more new columns into an existing table at position numcol. If
+ fstcol is greater than the number of existing columns in the table
+ then the new column will be appended as the last column in the table.
+*/
+{
+ int colnum, datacode, decims, tfields, tstatus, ii;
+ OFF_T datasize, firstbyte, nbytes, nadd;
+ long width, firstcol, delbyte, repeat, naxis1, naxis2, freespace;
+ long nblock, tbcol;
+ char tfm[FLEN_VALUE], keyname[FLEN_KEYWORD], comm[FLEN_COMMENT], *cptr;
+ tcolumn *colptr;
+
+ if (*status > 0)
+ return(*status);
+
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ {
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+ }
+ /* rescan header if data structure is undefined */
+ else if ((fptr->Fptr)->datastart == DATA_UNDEFINED)
+ if ( ffrdef(fptr, status) > 0)
+ return(*status);
+
+ if ((fptr->Fptr)->hdutype == IMAGE_HDU)
+ {
+ ffpmsg("Can only add columns to TABLE or BINTABLE extension (fficol)");
+ return(*status = NOT_TABLE);
+ }
+
+ /* is the column number valid? */
+ tfields = (fptr->Fptr)->tfield;
+ if (fstcol < 1 )
+ return(*status = BAD_COL_NUM);
+ else if (fstcol > tfields)
+ colnum = tfields + 1; /* append as last column */
+ else
+ colnum = fstcol;
+
+ /* parse the tform value and calc number of bytes to add to each row */
+ delbyte = 0;
+ for (ii = 0; ii < ncols; ii++)
+ {
+ strcpy(tfm, tform[ii]);
+ ffupch(tfm); /* make sure format is in upper case */
+
+ if ((fptr->Fptr)->hdutype == ASCII_TBL)
+ {
+ ffasfm(tfm, &datacode, &width, &decims, status);
+ delbyte += width + 1; /* add one space between the columns */
+ }
+ else
+ {
+ ffbnfm(tfm, &datacode, &repeat, &width, status);
+
+ if (datacode < 0) /* variable length array column */
+ delbyte += 8;
+ else if (datacode == 1) /* bit column; round up */
+ delbyte += (repeat + 7) / 8; /* to multiple of 8 bits */
+ else if (datacode == 16) /* ASCII string column */
+ delbyte += repeat;
+ else /* numerical data type */
+ delbyte += (datacode / 10) * repeat;
+ }
+ }
+
+ if (*status > 0)
+ return(*status);
+
+ /* get the current size of the table */
+ /* use internal structure since NAXIS2 keyword may not be up to date */
+ naxis1 = (long) (fptr->Fptr)->rowlength;
+ naxis2 = (fptr->Fptr)->numrows;
+
+ /* current size of data */
+ datasize = (fptr->Fptr)->heapstart + (fptr->Fptr)->heapsize;
+ freespace = ( ( (datasize + 2879) / 2880) * 2880) - datasize;
+ nadd = (OFF_T)delbyte * naxis2; /* no. of bytes to add to table */
+
+ if ( (freespace - nadd) < 0) /* not enough existing space? */
+ {
+ nblock = (nadd - freespace + 2879) / 2880; /* number of blocks */
+ if (ffiblk(fptr, nblock, 1, status) > 0) /* insert the blocks */
+ return(*status);
+ }
+
+ /* shift heap down (if it exists) */
+ if ((fptr->Fptr)->heapsize > 0)
+ {
+ nbytes = (fptr->Fptr)->heapsize; /* no. of bytes to shift down */
+
+ /* absolute heap pos */
+ firstbyte = (fptr->Fptr)->datastart + (fptr->Fptr)->heapstart;
+
+ if (ffshft(fptr, firstbyte, nbytes, nadd, status) > 0) /* move heap */
+ return(*status);
+ }
+
+ /* update the heap starting address */
+ (fptr->Fptr)->heapstart += nadd;
+
+ /* update the THEAP keyword if it exists */
+ tstatus = 0;
+ ffmkyj(fptr, "THEAP", (long)(fptr->Fptr)->heapstart, "&", &tstatus);
+
+ /* calculate byte position in the row where to insert the new column */
+ if (colnum > tfields)
+ firstcol = naxis1;
+ else
+ {
+ colptr = (fptr->Fptr)->tableptr;
+ colptr += (colnum - 1);
+ firstcol = colptr->tbcol;
+ }
+
+ /* insert delbyte bytes in every row, at byte position firstcol */
+ ffcins(fptr, naxis1, naxis2, delbyte, firstcol, status);
+
+ if ((fptr->Fptr)->hdutype == ASCII_TBL)
+ {
+ /* adjust the TBCOL values of the existing columns */
+ for(ii = 0; ii < tfields; ii++)
+ {
+ ffkeyn("TBCOL", ii + 1, keyname, status);
+ ffgkyj(fptr, keyname, &tbcol, comm, status);
+ if (tbcol > firstcol)
+ {
+ tbcol += delbyte;
+ ffmkyj(fptr, keyname, tbcol, "&", status);
+ }
+ }
+ }
+
+ /* update the mandatory keywords */
+ ffmkyj(fptr, "TFIELDS", tfields + ncols, "&", status);
+ ffmkyj(fptr, "NAXIS1", naxis1 + delbyte, "&", status);
+
+ /* increment the index value on any existing column keywords */
+ if(colnum <= tfields)
+ ffkshf(fptr, colnum, tfields, ncols, status);
+
+ /* add the required keywords for the new columns */
+ for (ii = 0; ii < ncols; ii++, colnum++)
+ {
+ strcpy(comm, "label for field");
+ ffkeyn("TTYPE", colnum, keyname, status);
+ ffpkys(fptr, keyname, ttype[ii], comm, status);
+
+ strcpy(comm, "format of field");
+ strcpy(tfm, tform[ii]);
+ ffupch(tfm); /* make sure format is in upper case */
+ ffkeyn("TFORM", colnum, keyname, status);
+
+ if (abs(datacode) == TSBYTE)
+ {
+ /* Replace the 'S' with an 'B' in the TFORMn code */
+ cptr = tfm;
+ while (*cptr != 'S')
+ cptr++;
+
+ *cptr = 'B';
+ ffpkys(fptr, keyname, tfm, comm, status);
+
+ /* write the TZEROn and TSCALn keywords */
+ ffkeyn("TZERO", colnum, keyname, status);
+ strcpy(comm, "offset for signed bytes");
+
+ ffpkyg(fptr, keyname, -128., 0, comm, status);
+
+ ffkeyn("TSCAL", colnum, keyname, status);
+ strcpy(comm, "data are not scaled");
+ ffpkyg(fptr, keyname, 1., 0, comm, status);
+ }
+ else if (abs(datacode) == TUSHORT)
+ {
+ /* Replace the 'U' with an 'I' in the TFORMn code */
+ cptr = tfm;
+ while (*cptr != 'U')
+ cptr++;
+
+ *cptr = 'I';
+ ffpkys(fptr, keyname, tfm, comm, status);
+
+ /* write the TZEROn and TSCALn keywords */
+ ffkeyn("TZERO", colnum, keyname, status);
+ strcpy(comm, "offset for unsigned integers");
+
+ ffpkyg(fptr, keyname, 32768., 0, comm, status);
+
+ ffkeyn("TSCAL", colnum, keyname, status);
+ strcpy(comm, "data are not scaled");
+ ffpkyg(fptr, keyname, 1., 0, comm, status);
+ }
+ else if (abs(datacode) == TULONG)
+ {
+ /* Replace the 'V' with an 'J' in the TFORMn code */
+ cptr = tfm;
+ while (*cptr != 'V')
+ cptr++;
+
+ *cptr = 'J';
+ ffpkys(fptr, keyname, tfm, comm, status);
+
+ /* write the TZEROn and TSCALn keywords */
+ ffkeyn("TZERO", colnum, keyname, status);
+ strcpy(comm, "offset for unsigned integers");
+
+ ffpkyg(fptr, keyname, 2147483648., 0, comm, status);
+
+ ffkeyn("TSCAL", colnum, keyname, status);
+ strcpy(comm, "data are not scaled");
+ ffpkyg(fptr, keyname, 1., 0, comm, status);
+ }
+ else
+ {
+ ffpkys(fptr, keyname, tfm, comm, status);
+ }
+
+ if ((fptr->Fptr)->hdutype == ASCII_TBL) /* write the TBCOL keyword */
+ {
+ if (colnum == tfields + 1)
+ tbcol = firstcol + 2; /* allow space between preceding col */
+ else
+ tbcol = firstcol + 1;
+
+ strcpy(comm, "beginning column of field");
+ ffkeyn("TBCOL", colnum, keyname, status);
+ ffpkyj(fptr, keyname, tbcol, comm, status);
+
+ /* increment the column starting position for the next column */
+ ffasfm(tfm, &datacode, &width, &decims, status);
+ firstcol += width + 1; /* add one space between the columns */
+ }
+ }
+ ffrdef(fptr, status); /* initialize the new table structure */
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffmvec(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - position of col to be modified */
+ long newveclen, /* I - new vector length of column (TFORM) */
+ int *status) /* IO - error status */
+/*
+ Modify the vector length of a column in a binary table, larger or smaller.
+ E.g., change a column from TFORMn = '1E' to '20E'.
+*/
+{
+ int datacode, tfields, tstatus;
+ OFF_T datasize, size, firstbyte, nbytes, nadd, ndelete;
+ long width, delbyte, repeat, naxis1, naxis2, freespace;
+ long nblock, firstcol;
+ char tfm[FLEN_VALUE], keyname[FLEN_KEYWORD], tcode[2];
+ tcolumn *colptr;
+
+ if (*status > 0)
+ return(*status);
+
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ {
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+ }
+ /* rescan header if data structure is undefined */
+ else if ((fptr->Fptr)->datastart == DATA_UNDEFINED)
+ if ( ffrdef(fptr, status) > 0)
+ return(*status);
+
+ if ((fptr->Fptr)->hdutype != BINARY_TBL)
+ {
+ ffpmsg(
+ "Can only change vector length of a column in BINTABLE extension (ffmvec)");
+ return(*status = NOT_TABLE);
+ }
+
+ /* is the column number valid? */
+ tfields = (fptr->Fptr)->tfield;
+ if (colnum < 1 || colnum > tfields)
+ return(*status = BAD_COL_NUM);
+
+ /* look up the current vector length and element width */
+
+ colptr = (fptr->Fptr)->tableptr;
+ colptr += (colnum - 1);
+
+ datacode = colptr->tdatatype; /* datatype of the column */
+ repeat = (long) colptr->trepeat; /* field repeat count */
+ width = colptr->twidth; /* width of a single element in chars */
+
+ if (datacode < 0)
+ {
+ ffpmsg(
+ "Can't modify vector length of variable length column (ffmvec)");
+ return(*status = BAD_TFORM);
+ }
+
+ if (repeat == newveclen)
+ return(*status); /* column already has the desired vector length */
+
+ if (datacode == TSTRING)
+ width = 1; /* width was equal to width of unit string */
+
+ naxis1 = (long) (fptr->Fptr)->rowlength; /* current width of the table */
+ naxis2 = (fptr->Fptr)->numrows;
+
+ delbyte = (newveclen - repeat) * width; /* no. of bytes to insert */
+ if (datacode == TBIT) /* BIT column is a special case */
+ delbyte = ((newveclen + 1) / 8) - ((repeat + 1) / 8);
+
+ if (delbyte > 0) /* insert space for more elements */
+ {
+ /* current size of data */
+ datasize = (fptr->Fptr)->heapstart + (fptr->Fptr)->heapsize;
+ freespace = ( ( (datasize + 2879) / 2880) * 2880) - datasize;
+
+ nadd = (OFF_T)delbyte * naxis2; /* no. of bytes to add to table */
+
+ if ( (freespace - nadd) < 0) /* not enough existing space? */
+ {
+ nblock = (nadd - freespace + 2879) / 2880; /* number of blocks */
+ if (ffiblk(fptr, nblock, 1, status) > 0) /* insert the blocks */
+ return(*status);
+ }
+
+ /* shift heap down (if it exists) */
+ if ((fptr->Fptr)->heapsize > 0)
+ {
+ nbytes = (fptr->Fptr)->heapsize; /* no. of bytes to shift down */
+
+ /* absolute heap pos */
+ firstbyte = (fptr->Fptr)->datastart + (fptr->Fptr)->heapstart;
+
+ if (ffshft(fptr, firstbyte, nbytes, nadd, status) > 0) /* move heap */
+ return(*status);
+ }
+
+ /* update the heap starting address */
+ (fptr->Fptr)->heapstart += nadd;
+
+ /* update the THEAP keyword if it exists */
+ tstatus = 0;
+ ffmkyj(fptr, "THEAP", (long)(fptr->Fptr)->heapstart, "&", &tstatus);
+
+ firstcol = colptr->tbcol + (repeat * width); /* insert position */
+
+ /* insert delbyte bytes in every row, at byte position firstcol */
+ ffcins(fptr, naxis1, naxis2, delbyte, firstcol, status);
+ }
+ else if (delbyte < 0)
+ {
+ /* current size of table */
+ size = (fptr->Fptr)->heapstart + (fptr->Fptr)->heapsize;
+ freespace = ((size + 2879) / 2880) * 2880 - size - ((OFF_T)delbyte * naxis2);
+ nblock = freespace / 2880; /* number of empty blocks to delete */
+ firstcol = colptr->tbcol + (newveclen * width); /* delete position */
+
+ /* delete elements from the vector */
+ ffcdel(fptr, naxis1, naxis2, -delbyte, firstcol, status);
+
+ /* abs heap pos */
+ firstbyte = (fptr->Fptr)->datastart + (fptr->Fptr)->heapstart;
+ ndelete = (OFF_T)delbyte * naxis2; /* size of shift (negative) */
+
+ /* shift heap up (if it exists) */
+ if ((fptr->Fptr)->heapsize > 0)
+ {
+ nbytes = (fptr->Fptr)->heapsize; /* no. of bytes to shift up */
+ if (ffshft(fptr, firstbyte, nbytes, ndelete, status) > 0)
+ return(*status);
+ }
+
+ /* delete the empty blocks at the end of the HDU */
+ if (nblock > 0)
+ ffdblk(fptr, nblock, status);
+
+ /* update the heap starting address */
+ (fptr->Fptr)->heapstart += ndelete; /* ndelete is negative */
+
+ /* update the THEAP keyword if it exists */
+ tstatus = 0;
+ ffmkyj(fptr, "THEAP", (long)(fptr->Fptr)->heapstart, "&", &tstatus);
+ }
+
+ /* construct the new TFORM keyword for the column */
+ if (datacode == TBIT)
+ strcpy(tcode,"X");
+ else if (datacode == TBYTE)
+ strcpy(tcode,"B");
+ else if (datacode == TLOGICAL)
+ strcpy(tcode,"L");
+ else if (datacode == TSTRING)
+ strcpy(tcode,"A");
+ else if (datacode == TSHORT)
+ strcpy(tcode,"I");
+ else if (datacode == TLONG)
+ strcpy(tcode,"J");
+ else if (datacode == TFLOAT)
+ strcpy(tcode,"E");
+ else if (datacode == TDOUBLE)
+ strcpy(tcode,"D");
+ else if (datacode == TCOMPLEX)
+ strcpy(tcode,"C");
+ else if (datacode == TDBLCOMPLEX)
+ strcpy(tcode,"M");
+
+ sprintf(tfm,"%ld%s",newveclen,tcode); /* TFORM value */
+ ffkeyn("TFORM", colnum, keyname, status); /* Keyword name */
+ ffmkys(fptr, keyname, tfm, "&", status); /* modify TFORM keyword */
+
+ ffmkyj(fptr, "NAXIS1", naxis1 + delbyte, "&", status); /* modify NAXIS1 */
+
+ ffrdef(fptr, status); /* reinitialize the new table structure */
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffcpcl(fitsfile *infptr, /* I - FITS file pointer to input file */
+ fitsfile *outfptr, /* I - FITS file pointer to output file */
+ int incol, /* I - number of input column */
+ int outcol, /* I - number for output column */
+ int create_col, /* I - create new col if TRUE, else overwrite */
+ int *status) /* IO - error status */
+/*
+ copy a column from infptr and insert it in the outfptr table.
+*/
+{
+ int tstatus, colnum, typecode, anynull;
+ long tfields, repeat, width, nrows, outrows;
+ long inloop, outloop, maxloop, ndone, ntodo, npixels;
+ long firstrow, firstelem, ii;
+ char keyname[FLEN_KEYWORD], ttype[FLEN_VALUE], tform[FLEN_VALUE];
+ char ttype_comm[FLEN_COMMENT],tform_comm[FLEN_COMMENT];
+ char *lvalues = 0, nullflag, **strarray = 0;
+ char nulstr[] = {'\5', '\0'}; /* unique null string value */
+ double dnull = 0.l, *dvalues = 0;
+ float fnull = 0., *fvalues = 0;
+
+ if (*status > 0)
+ return(*status);
+
+ if (infptr->HDUposition != (infptr->Fptr)->curhdu)
+ {
+ ffmahd(infptr, (infptr->HDUposition) + 1, NULL, status);
+ }
+ else if ((infptr->Fptr)->datastart == DATA_UNDEFINED)
+ ffrdef(infptr, status); /* rescan header */
+
+ if (outfptr->HDUposition != (outfptr->Fptr)->curhdu)
+ {
+ ffmahd(outfptr, (outfptr->HDUposition) + 1, NULL, status);
+ }
+ else if ((outfptr->Fptr)->datastart == DATA_UNDEFINED)
+ ffrdef(outfptr, status); /* rescan header */
+
+ if (*status > 0)
+ return(*status);
+
+ if ((infptr->Fptr)->hdutype == IMAGE_HDU || (outfptr->Fptr)->hdutype == IMAGE_HDU)
+ {
+ ffpmsg
+ ("Can not copy columns to or from IMAGE HDUs (ffcpcl)");
+ return(*status = NOT_TABLE);
+ }
+
+ if ( (infptr->Fptr)->hdutype == BINARY_TBL && (outfptr->Fptr)->hdutype == ASCII_TBL)
+ {
+ ffpmsg
+ ("Copying from Binary table to ASCII table is not supported (ffcpcl)");
+ return(*status = NOT_BTABLE);
+ }
+
+ /* get the datatype and vector repeat length of the column */
+ ffgtcl(infptr, incol, &typecode, &repeat, &width, status);
+
+ if (typecode < 0)
+ {
+ ffpmsg("Variable-length columns are not supported (ffcpcl)");
+ return(*status = BAD_TFORM);
+ }
+
+ if (create_col) /* insert new column in output table? */
+ {
+ tstatus = 0;
+ ffkeyn("TTYPE", incol, keyname, &tstatus);
+ ffgkys(infptr, keyname, ttype, ttype_comm, &tstatus);
+ ffkeyn("TFORM", incol, keyname, &tstatus);
+
+ if (ffgkys(infptr, keyname, tform, tform_comm, &tstatus) )
+ {
+ ffpmsg
+ ("Could not find TTYPE and TFORM keywords in input table (ffcpcl)");
+ return(*status = NO_TFORM);
+ }
+
+ if ((infptr->Fptr)->hdutype == ASCII_TBL && (outfptr->Fptr)->hdutype == BINARY_TBL)
+ {
+ /* convert from ASCII table to BINARY table format string */
+ if (typecode == TSTRING)
+ ffnkey(width, "A", tform, status);
+
+ else if (typecode == TLONG)
+ strcpy(tform, "1J");
+
+ else if (typecode == TSHORT)
+ strcpy(tform, "1I");
+
+ else if (typecode == TFLOAT)
+ strcpy(tform,"1E");
+
+ else if (typecode == TDOUBLE)
+ strcpy(tform,"1D");
+ }
+
+ if (ffgkyj(outfptr, "TFIELDS", &tfields, 0, &tstatus))
+ {
+ ffpmsg
+ ("Could not read TFIELDS keyword in output table (ffcpcl)");
+ return(*status = NO_TFIELDS);
+ }
+
+ colnum = minvalue((int) tfields + 1, outcol); /* output col. number */
+
+ /* create the empty column */
+ if (fficol(outfptr, colnum, ttype, tform, status) > 0)
+ {
+ ffpmsg
+ ("Could not append new column to output file (ffcpcl)");
+ return(*status);
+ }
+
+ /* copy the comment strings from the input file for TTYPE and TFORM */
+ tstatus = 0;
+ ffkeyn("TTYPE", colnum, keyname, &tstatus);
+ ffmcom(outfptr, keyname, ttype_comm, &tstatus);
+ ffkeyn("TFORM", colnum, keyname, &tstatus);
+ ffmcom(outfptr, keyname, tform_comm, &tstatus);
+
+ /* copy other column-related keywords if they exist */
+
+ ffcpky(infptr, outfptr, incol, colnum, "TUNIT", status);
+ ffcpky(infptr, outfptr, incol, colnum, "TSCAL", status);
+ ffcpky(infptr, outfptr, incol, colnum, "TZERO", status);
+ ffcpky(infptr, outfptr, incol, colnum, "TDISP", status);
+ ffcpky(infptr, outfptr, incol, colnum, "TLMIN", status);
+ ffcpky(infptr, outfptr, incol, colnum, "TLMAX", status);
+ ffcpky(infptr, outfptr, incol, colnum, "TDIM", status);
+
+ /* WCS keywords */
+ ffcpky(infptr, outfptr, incol, colnum, "TCTYP", status);
+ ffcpky(infptr, outfptr, incol, colnum, "TCUNI", status);
+ ffcpky(infptr, outfptr, incol, colnum, "TCRVL", status);
+ ffcpky(infptr, outfptr, incol, colnum, "TCRPX", status);
+ ffcpky(infptr, outfptr, incol, colnum, "TCDLT", status);
+ ffcpky(infptr, outfptr, incol, colnum, "TCROT", status);
+
+ if ((infptr->Fptr)->hdutype == ASCII_TBL && (outfptr->Fptr)->hdutype == BINARY_TBL)
+ {
+ /* binary tables only have TNULLn keyword for integer columns */
+ if (typecode == TLONG || typecode == TSHORT)
+ {
+ /* check if null string is defined; replace with integer */
+ ffkeyn("TNULL", incol, keyname, &tstatus);
+ if (ffgkys(infptr, keyname, ttype, 0, &tstatus) <= 0)
+ {
+ ffkeyn("TNULL", colnum, keyname, &tstatus);
+ if (typecode == TLONG)
+ ffpkyj(outfptr, keyname, -9999999L, "Null value", status);
+ else
+ ffpkyj(outfptr, keyname, -32768L, "Null value", status);
+ }
+ }
+ }
+ else
+ {
+ ffcpky(infptr, outfptr, incol, colnum, "TNULL", status);
+ }
+
+ /* rescan header to recognize the new keywords */
+ if (ffrdef(outfptr, status) )
+ return(*status);
+ }
+ else
+ {
+ colnum = outcol;
+ }
+
+ ffgkyj(infptr, "NAXIS2", &nrows, 0, status); /* no. of input rows */
+ ffgkyj(outfptr, "NAXIS2", &outrows, 0, status); /* no. of output rows */
+ nrows = minvalue(nrows, outrows);
+
+ if (typecode == TBIT)
+ repeat = (repeat - 1) / 8 + 1; /* convert from bits to bytes */
+ else if (typecode == TSTRING && (infptr->Fptr)->hdutype == BINARY_TBL)
+ repeat = repeat / width; /* convert from chars to unit strings */
+
+ /* get optimum number of rows to copy at one time */
+ ffgrsz(infptr, &inloop, status);
+ ffgrsz(outfptr, &outloop, status);
+
+ /* adjust optimum number, since 2 tables are open at once */
+ maxloop = minvalue(inloop, outloop); /* smallest of the 2 tables */
+ maxloop = maxvalue(1, maxloop / 2); /* at least 1 row */
+ maxloop = minvalue(maxloop, nrows); /* max = nrows to be copied */
+ maxloop *= repeat; /* mult by no of elements in a row */
+
+ /* allocate memory for arrays */
+ if (typecode == TLOGICAL)
+ {
+ lvalues = (char *) calloc(maxloop, sizeof(char) );
+ if (!lvalues)
+ {
+ ffpmsg
+ ("malloc failed to get memory for logicals (ffcpcl)");
+ return(*status = ARRAY_TOO_BIG);
+ }
+ }
+ else if (typecode == TSTRING)
+ {
+ /* allocate array of pointers */
+ strarray = (char **) calloc(maxloop, sizeof(strarray));
+
+ /* allocate space for each string */
+ for (ii = 0; ii < maxloop; ii++)
+ strarray[ii] = (char *) calloc(width+1, sizeof(char));
+ }
+ else if (typecode == TCOMPLEX)
+ {
+ fvalues = (float *) calloc(maxloop * 2, sizeof(float) );
+ if (!fvalues)
+ {
+ ffpmsg
+ ("malloc failed to get memory for complex (ffcpcl)");
+ return(*status = ARRAY_TOO_BIG);
+ }
+ fnull = 0.;
+ }
+ else if (typecode == TDBLCOMPLEX)
+ {
+ dvalues = (double *) calloc(maxloop * 2, sizeof(double) );
+ if (!dvalues)
+ {
+ ffpmsg
+ ("malloc failed to get memory for dbl complex (ffcpcl)");
+ return(*status = ARRAY_TOO_BIG);
+ }
+ dnull = 0.;
+ }
+ else /* numerical datatype; read them all as doubles */
+ {
+ dvalues = (double *) calloc(maxloop, sizeof(double) );
+ if (!dvalues)
+ {
+ ffpmsg
+ ("malloc failed to get memory for doubles (ffcpcl)");
+ return(*status = ARRAY_TOO_BIG);
+ }
+ dnull = -9.99991999E31; /* use an unlikely value for nulls */
+ }
+
+ npixels = nrows * repeat; /* total no. of pixels to copy */
+ ntodo = minvalue(npixels, maxloop); /* no. to copy per iteration */
+ ndone = 0; /* total no. of pixels that have been copied */
+
+ while (ntodo) /* iterate through the table */
+ {
+ firstrow = ndone / repeat + 1;
+ firstelem = ndone - ((firstrow - 1) * repeat) + 1;
+
+ /* read from input table */
+ if (typecode == TLOGICAL)
+ ffgcl(infptr, incol, firstrow, firstelem, ntodo,
+ lvalues, status);
+ else if (typecode == TSTRING)
+ ffgcvs(infptr, incol, firstrow, firstelem, ntodo,
+ nulstr, strarray, &anynull, status);
+
+ else if (typecode == TCOMPLEX)
+ ffgcvc(infptr, incol, firstrow, firstelem, ntodo, fnull,
+ fvalues, &anynull, status);
+
+ else if (typecode == TDBLCOMPLEX)
+ ffgcvm(infptr, incol, firstrow, firstelem, ntodo, dnull,
+ dvalues, &anynull, status);
+
+ else /* all numerical types */
+ ffgcvd(infptr, incol, firstrow, firstelem, ntodo, dnull,
+ dvalues, &anynull, status);
+
+ if (*status > 0)
+ {
+ ffpmsg("Error reading input copy of column (ffcpcl)");
+ break;
+ }
+
+ /* write to output table */
+ if (typecode == TLOGICAL)
+ {
+ nullflag = 2;
+ ffpcnl(outfptr, colnum, firstrow, firstelem, ntodo,
+ lvalues, nullflag, status);
+ }
+
+ else if (typecode == TSTRING)
+ {
+ if (anynull)
+ ffpcns(outfptr, colnum, firstrow, firstelem, ntodo,
+ strarray, nulstr, status);
+ else
+ ffpcls(outfptr, colnum, firstrow, firstelem, ntodo,
+ strarray, status);
+ }
+
+ else if (typecode == TCOMPLEX)
+ { /* doesn't support writing nulls */
+ ffpclc(outfptr, colnum, firstrow, firstelem, ntodo,
+ fvalues, status);
+ }
+
+ else if (typecode == TDBLCOMPLEX)
+ { /* doesn't support writing nulls */
+ ffpclm(outfptr, colnum, firstrow, firstelem, ntodo,
+ dvalues, status);
+ }
+
+ else /* all other numerical types */
+ {
+ if (anynull)
+ ffpcnd(outfptr, colnum, firstrow, firstelem, ntodo,
+ dvalues, dnull, status);
+ else
+ ffpcld(outfptr, colnum, firstrow, firstelem, ntodo,
+ dvalues, status);
+ }
+
+ if (*status > 0)
+ {
+ ffpmsg("Error writing output copy of column (ffcpcl)");
+ break;
+ }
+
+ npixels -= ntodo;
+ ndone += ntodo;
+ ntodo = minvalue(npixels, maxloop);
+ }
+
+ /* free the previously allocated memory */
+ if (typecode == TLOGICAL)
+ {
+ free(lvalues);
+ }
+ else if (typecode == TSTRING)
+ {
+ for (ii = 0; ii < maxloop; ii++)
+ free(strarray[ii]);
+
+ free(strarray);
+ }
+ else
+ {
+ free(dvalues);
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffcpky(fitsfile *infptr, /* I - FITS file pointer to input file */
+ fitsfile *outfptr, /* I - FITS file pointer to output file */
+ int incol, /* I - input index number */
+ int outcol, /* I - output index number */
+ char *rootname, /* I - root name of the keyword to be copied */
+ int *status) /* IO - error status */
+/*
+ copy an indexed keyword from infptr to outfptr.
+*/
+{
+ int tstatus = 0;
+ char keyname[FLEN_KEYWORD];
+ char value[FLEN_VALUE], comment[FLEN_COMMENT], card[FLEN_CARD];
+
+ ffkeyn(rootname, incol, keyname, &tstatus);
+ if (ffgkey(infptr, keyname, value, comment, &tstatus) <= 0)
+ {
+ ffkeyn(rootname, outcol, keyname, &tstatus);
+ ffmkky(keyname, value, comment, card, status);
+ ffprec(outfptr, card, status);
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffdcol(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - column to delete (1 = 1st) */
+ int *status) /* IO - error status */
+/*
+ Delete a column from a table.
+*/
+{
+ int ii, tstatus;
+ OFF_T firstbyte, size, ndelete, nbytes;
+ long delbyte, nspace, naxis1, naxis2, firstcol;
+ long freespace, nblock, tbcol;
+ char keyname[FLEN_KEYWORD], comm[FLEN_COMMENT];
+ tcolumn *colptr, *nextcol;
+
+ if (*status > 0)
+ return(*status);
+
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ {
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+ }
+ /* rescan header if data structure is undefined */
+ else if ((fptr->Fptr)->datastart == DATA_UNDEFINED)
+ if ( ffrdef(fptr, status) > 0)
+ return(*status);
+
+ if ((fptr->Fptr)->hdutype == IMAGE_HDU)
+ {
+ ffpmsg
+ ("Can only delete column from TABLE or BINTABLE extension (ffdcol)");
+ return(*status = NOT_TABLE);
+ }
+
+ if (colnum < 1 || colnum > (fptr->Fptr)->tfield )
+ return(*status = BAD_COL_NUM);
+
+ colptr = (fptr->Fptr)->tableptr;
+ colptr += (colnum - 1);
+ firstcol = colptr->tbcol; /* starting byte position of the column */
+
+ /* use column width to determine how many bytes to delete in each row */
+ if ((fptr->Fptr)->hdutype == ASCII_TBL)
+ {
+ delbyte = colptr->twidth; /* width of ASCII column */
+
+ if (colnum < (fptr->Fptr)->tfield) /* check for space between next column */
+ {
+ nextcol = colptr + 1;
+ nspace = (nextcol->tbcol) - (colptr->tbcol) - delbyte;
+ if (nspace > 0)
+ delbyte++;
+ }
+ else if (colnum > 1) /* check for space between last 2 columns */
+ {
+ nextcol = colptr - 1;
+ nspace = (colptr->tbcol) - (nextcol->tbcol) - (nextcol->twidth);
+ if (nspace > 0)
+ {
+ delbyte++;
+ firstcol--; /* delete the leading space */
+ }
+ }
+ }
+ else /* a binary table */
+ {
+ if (colnum < (fptr->Fptr)->tfield)
+ {
+ nextcol = colptr + 1;
+ delbyte = (nextcol->tbcol) - (colptr->tbcol);
+ }
+ else
+ {
+ delbyte = ((fptr->Fptr)->rowlength) - (colptr->tbcol);
+ }
+ }
+
+ naxis1 = (long) (fptr->Fptr)->rowlength; /* current width of the table */
+ naxis2 = (fptr->Fptr)->numrows;
+
+ /* current size of table */
+ size = (fptr->Fptr)->heapstart + (fptr->Fptr)->heapsize;
+ freespace = ((OFF_T)delbyte * naxis2) + ((size + 2879) / 2880) * 2880 - size;
+ nblock = freespace / 2880; /* number of empty blocks to delete */
+
+ ffcdel(fptr, naxis1, naxis2, delbyte, firstcol, status); /* delete col */
+
+ /* absolute heap position */
+ firstbyte = (fptr->Fptr)->datastart + (fptr->Fptr)->heapstart;
+ ndelete = (OFF_T)delbyte * naxis2; /* size of shift */
+
+ /* shift heap up (if it exists) */
+ if ((fptr->Fptr)->heapsize > 0)
+ {
+ nbytes = (fptr->Fptr)->heapsize; /* no. of bytes to shift up */
+
+ if (ffshft(fptr, firstbyte, nbytes, -ndelete, status) > 0) /* mv heap */
+ return(*status);
+ }
+
+ /* delete the empty blocks at the end of the HDU */
+ if (nblock > 0)
+ ffdblk(fptr, nblock, status);
+
+ /* update the heap starting address */
+ (fptr->Fptr)->heapstart -= ndelete;
+
+ /* update the THEAP keyword if it exists */
+ tstatus = 0;
+ ffmkyj(fptr, "THEAP", (long)(fptr->Fptr)->heapstart, "&", &tstatus);
+
+ if ((fptr->Fptr)->hdutype == ASCII_TBL)
+ {
+ /* adjust the TBCOL values of the remaining columns */
+ for (ii = 1; ii <= (fptr->Fptr)->tfield; ii++)
+ {
+ ffkeyn("TBCOL", ii, keyname, status);
+ ffgkyj(fptr, keyname, &tbcol, comm, status);
+ if (tbcol > firstcol)
+ {
+ tbcol = tbcol - delbyte;
+ ffmkyj(fptr, keyname, tbcol, "&", status);
+ }
+ }
+ }
+
+ /* update the mandatory keywords */
+ ffmkyj(fptr, "TFIELDS", ((fptr->Fptr)->tfield) - 1, "&", status);
+ ffmkyj(fptr, "NAXIS1", naxis1 - delbyte, "&", status);
+ /*
+ delete the index keywords starting with 'T' associated with the
+ deleted column and subtract 1 from index of all higher keywords
+ */
+ ffkshf(fptr, colnum, (fptr->Fptr)->tfield, -1, status);
+
+ ffrdef(fptr, status); /* initialize the new table structure */
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffcins(fitsfile *fptr, /* I - FITS file pointer */
+ long naxis1, /* I - width of the table, in bytes */
+ long naxis2, /* I - number of rows in the table */
+ long ninsert, /* I - number of bytes to insert in each row */
+ long bytepos, /* I - rel. position in row to insert bytes */
+ int *status) /* IO - error status */
+/*
+ Insert 'ninsert' bytes into each row of the table at position 'bytepos'.
+*/
+{
+ unsigned char buffer[10000], cfill;
+ long newlen, fbyte, nbytes, ii, irow, nseg;
+
+ if (*status > 0)
+ return(*status);
+
+ if (naxis2 == 0)
+ return(*status); /* just return if there are 0 rows in the table */
+
+ /* select appropriate fill value */
+ if ((fptr->Fptr)->hdutype == ASCII_TBL)
+ cfill = 32; /* ASCII tables use blank fill */
+ else
+ cfill = 0; /* primary array and binary tables use zero fill */
+
+ newlen = naxis1 + ninsert;
+
+ if (newlen <= 10000)
+ {
+ /*******************************************************************
+ CASE #1: optimal case where whole new row fits in the work buffer
+ *******************************************************************/
+
+ for (ii = 0; ii < ninsert; ii++)
+ buffer[ii] = cfill; /* initialize buffer with fill value */
+
+ /* first move the trailing bytes (if any) in the last row */
+ fbyte = bytepos + 1;
+ nbytes = naxis1 - bytepos;
+ ffgtbb(fptr, naxis2, fbyte, nbytes, &buffer[ninsert], status);
+ (fptr->Fptr)->rowlength = (OFF_T) newlen; /* new row length */
+
+ /* write the row (with leading fill bytes) in the new place */
+ nbytes += ninsert;
+ ffptbb(fptr, naxis2, fbyte, nbytes, buffer, status);
+ (fptr->Fptr)->rowlength = (OFF_T) naxis1; /* reset to orig. value */
+
+ /* now move the rest of the rows */
+ for (irow = naxis2 - 1; irow > 0; irow--)
+ {
+ /* read the row to be shifted (work backwards thru the table) */
+ ffgtbb(fptr, irow, fbyte, naxis1, &buffer[ninsert], status);
+ (fptr->Fptr)->rowlength = (OFF_T) newlen; /* new row length */
+
+ /* write the row (with the leading fill bytes) in the new place */
+ ffptbb(fptr, irow, fbyte, newlen, buffer, status);
+ (fptr->Fptr)->rowlength = (OFF_T) naxis1; /* reset to orig value */
+ }
+ }
+ else
+ {
+ /*****************************************************************
+ CASE #2: whole row doesn't fit in work buffer; move row in pieces
+ ******************************************************************
+ first copy the data, then go back and write fill into the new column
+ start by copying the trailing bytes (if any) in the last row. */
+
+ nbytes = naxis1 - bytepos;
+ nseg = (nbytes + 9999) / 10000;
+ fbyte = (nseg - 1) * 10000 + bytepos + 1;
+ nbytes = naxis1 - fbyte + 1;
+
+ for (ii = 0; ii < nseg; ii++)
+ {
+ ffgtbb(fptr, naxis2, fbyte, nbytes, buffer, status);
+ (fptr->Fptr)->rowlength = (OFF_T) newlen; /* new row length */
+
+ ffptbb(fptr, naxis2, fbyte + ninsert, nbytes, buffer, status);
+ (fptr->Fptr)->rowlength = (OFF_T) naxis1; /* reset to orig value */
+
+ fbyte -= 10000;
+ nbytes = 10000;
+ }
+
+ /* now move the rest of the rows */
+ nseg = (naxis1 + 9999) / 10000;
+ for (irow = naxis2 - 1; irow > 0; irow--)
+ {
+ fbyte = (nseg - 1) * 10000 + bytepos + 1;
+ nbytes = naxis1 - (nseg - 1) * 10000;
+ for (ii = 0; ii < nseg; ii++)
+ {
+ /* read the row to be shifted (work backwards thru the table) */
+ ffgtbb(fptr, irow, fbyte, nbytes, buffer, status);
+ (fptr->Fptr)->rowlength = (OFF_T) newlen; /* new row length */
+
+ /* write the row in the new place */
+ ffptbb(fptr, irow, fbyte + ninsert, nbytes, buffer, status);
+ (fptr->Fptr)->rowlength = (OFF_T) naxis1; /* reset to orig value */
+
+ fbyte -= 10000;
+ nbytes = 10000;
+ }
+ }
+
+ /* now write the fill values into the new column */
+ nbytes = minvalue(ninsert, 10000);
+ memset(buffer, cfill, nbytes); /* initialize with fill value */
+
+ nseg = (ninsert + 9999) / 10000;
+ (fptr->Fptr)->rowlength = (OFF_T) newlen; /* new row length */
+
+ for (irow = 1; irow <= naxis2; irow++)
+ {
+ fbyte = bytepos + 1;
+ nbytes = ninsert - ((nseg - 1) * 10000);
+ for (ii = 0; ii < nseg; ii++)
+ {
+ ffptbb(fptr, irow, fbyte, nbytes, buffer, status);
+ fbyte += nbytes;
+ nbytes = 10000;
+ }
+ }
+ (fptr->Fptr)->rowlength = (OFF_T) naxis1; /* reset to orig value */
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffcdel(fitsfile *fptr, /* I - FITS file pointer */
+ long naxis1, /* I - width of the table, in bytes */
+ long naxis2, /* I - number of rows in the table */
+ long ndelete, /* I - number of bytes to delete in each row */
+ long bytepos, /* I - rel. position in row to delete bytes */
+ int *status) /* IO - error status */
+/*
+ delete 'ndelete' bytes from each row of the table at position 'bytepos'.
+*/
+{
+ unsigned char buffer[10000];
+ long newlen, i1, i2, ii, remain, nbytes, irow, nseg;
+
+ if (*status > 0)
+ return(*status);
+
+ if (naxis2 == 0)
+ return(*status); /* just return if there are 0 rows in the table */
+
+ newlen = naxis1 - ndelete;
+
+ if (newlen <= 10000)
+ {
+ /*******************************************************************
+ CASE #1: optimal case where whole new row fits in the work buffer
+ *******************************************************************/
+ i1 = bytepos + 1;
+ i2 = i1 + ndelete;
+ for (irow = 1; irow < naxis2; irow++)
+ {
+ ffgtbb(fptr, irow, i2, newlen, buffer, status); /* read row */
+ (fptr->Fptr)->rowlength = (OFF_T) newlen; /* new row length */
+
+ ffptbb(fptr, irow, i1, newlen, buffer, status); /* write row */
+ (fptr->Fptr)->rowlength = (OFF_T) naxis1; /* reset to orig value */
+ }
+
+ /* now do the last row */
+ remain = naxis1 - (bytepos + ndelete);
+
+ if (remain > 0)
+ {
+ ffgtbb(fptr, naxis2, i2, remain, buffer, status); /* read row */
+ (fptr->Fptr)->rowlength = (OFF_T) newlen; /* new row length */
+
+ ffptbb(fptr, naxis2, i1, remain, buffer, status); /* write row */
+ (fptr->Fptr)->rowlength = (OFF_T) naxis1; /* reset to orig value */
+ }
+ }
+ else
+ {
+ /*****************************************************************
+ CASE #2: whole row doesn't fit in work buffer; move row in pieces
+ ******************************************************************/
+
+ nseg = (newlen + 9999) / 10000;
+ for (irow = 1; irow < naxis2; irow++)
+ {
+ i1 = bytepos + 1;
+ i2 = i1 + ndelete;
+
+ nbytes = newlen - (nseg - 1) * 10000;
+ for (ii = 0; ii < nseg; ii++)
+ {
+ ffgtbb(fptr, irow, i2, nbytes, buffer, status); /* read bytes */
+ (fptr->Fptr)->rowlength = (OFF_T) newlen; /* new row length */
+
+ ffptbb(fptr, irow, i1, nbytes, buffer, status); /* rewrite bytes */
+ (fptr->Fptr)->rowlength = (OFF_T) naxis1; /* reset to orig value */
+
+ i1 += nbytes;
+ i2 += nbytes;
+ nbytes = 10000;
+ }
+ }
+
+ /* now do the last row */
+ remain = naxis1 - (bytepos + ndelete);
+
+ if (remain > 0)
+ {
+ nseg = (remain + 9999) / 10000;
+ i1 = bytepos + 1;
+ i2 = i1 + ndelete;
+ nbytes = remain - (nseg - 1) * 10000;
+ for (ii = 0; ii < nseg; ii++)
+ {
+ ffgtbb(fptr, naxis2, i2, nbytes, buffer, status);
+ (fptr->Fptr)->rowlength = (OFF_T) newlen; /* new row length */
+
+ ffptbb(fptr, naxis2, i1, nbytes, buffer, status); /* write row */
+ (fptr->Fptr)->rowlength = (OFF_T) naxis1; /* reset to orig value */
+
+ i1 += nbytes;
+ i2 += nbytes;
+ nbytes = 10000;
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffkshf(fitsfile *fptr, /* I - FITS file pointer */
+ int colmin, /* I - starting col. to be incremented; 1 = 1st */
+ int colmax, /* I - last column to be incremented */
+ int incre, /* I - shift index number by this amount */
+ int *status) /* IO - error status */
+/*
+ shift the index value on any existing column keywords
+ This routine will modify the name of any keyword that begins with 'T'
+ and has an index number in the range COLMIN - COLMAX, inclusive.
+
+ if incre is positive, then the index values will be incremented.
+ if incre is negative, then the kewords with index = COLMIN
+ will be deleted and the index of higher numbered keywords will
+ be decremented.
+*/
+{
+ int nkeys, nmore, nrec, tstatus, i1;
+ long ivalue;
+ char rec[FLEN_CARD], q[FLEN_KEYWORD], newkey[FLEN_KEYWORD];
+
+ ffghsp(fptr, &nkeys, &nmore, status); /* get number of keywords */
+
+ /* go thru header starting with the 9th keyword looking for 'TxxxxNNN' */
+
+ for (nrec = 9; nrec <= nkeys; nrec++)
+ {
+ ffgrec(fptr, nrec, rec, status);
+
+ if (rec[0] == 'T')
+ {
+ i1 = 0;
+ strncpy(q, &rec[1], 4);
+ if (!strncmp(q, "BCOL", 4) || !strncmp(q, "FORM", 4) ||
+ !strncmp(q, "TYPE", 4) || !strncmp(q, "SCAL", 4) ||
+ !strncmp(q, "UNIT", 4) || !strncmp(q, "NULL", 4) ||
+ !strncmp(q, "ZERO", 4) || !strncmp(q, "DISP", 4) ||
+ !strncmp(q, "LMIN", 4) || !strncmp(q, "LMAX", 4) ||
+ !strncmp(q, "DMIN", 4) || !strncmp(q, "DMAX", 4) ||
+ !strncmp(q, "CTYP", 4) || !strncmp(q, "CRPX", 4) ||
+ !strncmp(q, "CRVL", 4) || !strncmp(q, "CDLT", 4) ||
+ !strncmp(q, "CROT", 4) || !strncmp(q, "CUNI", 4) )
+ i1 = 5;
+ else if (!strncmp(rec, "TDIM", 4) )
+ i1 = 4;
+
+ if (i1)
+ {
+ /* try reading the index number suffix */
+ q[0] = '\0';
+ strncat(q, &rec[i1], 8 - i1);
+
+ tstatus = 0;
+ ffc2ii(q, &ivalue, &tstatus);
+
+ if (tstatus == 0 && ivalue >= colmin && ivalue <= colmax)
+ {
+ if (incre <= 0 && ivalue == colmin)
+ {
+ ffdrec(fptr, nrec, status); /* delete keyword */
+ nkeys = nkeys - 1;
+ nrec = nrec - 1;
+ }
+ else
+ {
+ ivalue = ivalue + incre;
+ q[0] = '\0';
+ strncat(q, rec, i1);
+
+ ffkeyn(q, ivalue, newkey, status);
+ strncpy(rec, " ", 8); /* erase old keyword name */
+ i1 = strlen(newkey);
+ strncpy(rec, newkey, i1); /* overwrite new keyword name */
+ ffmrec(fptr, nrec, rec, status); /* modify the record */
+ }
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffshft(fitsfile *fptr, /* I - FITS file pointer */
+ OFF_T firstbyte, /* I - position of first byte in block to shift */
+ OFF_T nbytes, /* I - size of block of bytes to shift */
+ OFF_T nshift, /* I - size of shift in bytes (+ or -) */
+ int *status) /* IO - error status */
+/*
+ Shift block of bytes by nshift bytes (positive or negative).
+ A positive nshift value moves the block down further in the file, while a
+ negative value shifts the block towards the beginning of the file.
+*/
+{
+#define shftbuffsize 100000
+ long ntomov;
+ OFF_T ptr, ntodo;
+ char buffer[shftbuffsize];
+
+ if (*status > 0)
+ return(*status);
+
+ ntodo = nbytes; /* total number of bytes to shift */
+
+ if (nshift > 0)
+ /* start at the end of the block and work backwards */
+ ptr = firstbyte + nbytes;
+ else
+ /* start at the beginning of the block working forwards */
+ ptr = firstbyte;
+
+ while (ntodo)
+ {
+ /* number of bytes to move at one time */
+ ntomov = minvalue(ntodo, shftbuffsize);
+
+ if (nshift > 0) /* if moving block down ... */
+ ptr -= ntomov;
+
+ /* move to position and read the bytes to be moved */
+ ffmbyt(fptr, ptr, REPORT_EOF, status);
+ ffgbyt(fptr, ntomov, buffer, status);
+
+ /* move by shift amount and write the bytes */
+ ffmbyt(fptr, ptr + nshift, IGNORE_EOF, status);
+ if (ffpbyt(fptr, ntomov, buffer, status) > 0)
+ {
+ ffpmsg("Error while shifting block (ffshft)");
+ return(*status);
+ }
+
+ ntodo -= ntomov;
+ if (nshift < 0) /* if moving block up ... */
+ ptr += ntomov;
+ }
+
+ /* now overwrite the old data with fill */
+ if ((fptr->Fptr)->hdutype == ASCII_TBL)
+ memset(buffer, 32, shftbuffsize); /* fill ASCII tables with spaces */
+ else
+ memset(buffer, 0, shftbuffsize); /* fill other HDUs with zeros */
+
+
+ if (nshift < 0)
+ {
+ ntodo = -nshift;
+ /* point to the end of the shifted block */
+ ptr = firstbyte + nbytes + nshift;
+ }
+ else
+ {
+ ntodo = nshift;
+ /* point to original beginning of the block */
+ ptr = firstbyte;
+ }
+
+ ffmbyt(fptr, ptr, REPORT_EOF, status);
+
+ while (ntodo)
+ {
+ ntomov = minvalue(ntodo, shftbuffsize);
+ ffpbyt(fptr, ntomov, buffer, status);
+ ntodo -= ntomov;
+ }
+ return(*status);
+}
diff --git a/pkg/tbtables/cfitsio/edithdu.c b/pkg/tbtables/cfitsio/edithdu.c
new file mode 100644
index 00000000..5baac075
--- /dev/null
+++ b/pkg/tbtables/cfitsio/edithdu.c
@@ -0,0 +1,793 @@
+/* This file, edithdu.c, contains the FITSIO routines related to */
+/* copying, inserting, or deleting HDUs in a FITS file */
+
+/* The FITSIO software was written by William Pence at the High Energy */
+/* Astrophysic Science Archive Research Center (HEASARC) at the NASA */
+/* Goddard Space Flight Center. */
+
+#include <string.h>
+#include <stdlib.h>
+#include "fitsio2.h"
+/*--------------------------------------------------------------------------*/
+int ffcopy(fitsfile *infptr, /* I - FITS file pointer to input file */
+ fitsfile *outfptr, /* I - FITS file pointer to output file */
+ int morekeys, /* I - reserve space in output header */
+ int *status) /* IO - error status */
+/*
+ copy the CHDU from infptr to the CHDU of outfptr.
+ This will also allocate space in the output header for MOREKY keywords
+*/
+{
+ if (*status > 0)
+ return(*status);
+
+ if (infptr == outfptr)
+ return(*status = SAME_FILE);
+
+ if (ffcphd(infptr, outfptr, status) ) /* copy the header keywords */
+ return(*status);
+
+ if (morekeys > 0)
+ ffhdef(outfptr, morekeys, status); /* reserve space for more keywords */
+
+ ffcpdt(infptr, outfptr, status); /* now copy the data unit */
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffcpfl(fitsfile *infptr, /* I - FITS file pointer to input file */
+ fitsfile *outfptr, /* I - FITS file pointer to output file */
+ int previous, /* I - copy any previous HDUs? */
+ int current, /* I - copy the current HDU? */
+ int following, /* I - copy any following HDUs? */
+ int *status) /* IO - error status */
+/*
+ copy all or part of the input file to the output file.
+*/
+{
+ int hdunum, ii;
+
+ if (*status > 0)
+ return(*status);
+
+ if (infptr == outfptr)
+ return(*status = SAME_FILE);
+
+ ffghdn(infptr, &hdunum);
+
+ if (previous) { /* copy any previous HDUs */
+ for (ii=1; ii < hdunum; ii++) {
+ ffmahd(infptr, ii, NULL, status);
+ ffcopy(infptr, outfptr, 0, status);
+ }
+ }
+
+ if (current && (*status <= 0) ) { /* copy current HDU */
+ ffmahd(infptr, hdunum, NULL, status);
+ ffcopy(infptr, outfptr, 0, status);
+ }
+
+ if (following && (*status <= 0) ) { /* copy any remaining HDUs */
+ ii = hdunum + 1;
+ while (1)
+ {
+ if (ffmahd(infptr, ii, NULL, status) ) {
+ /* reset expected end of file status */
+ if (*status == END_OF_FILE)
+ *status = 0;
+ break;
+ }
+
+ if (ffcopy(infptr, outfptr, 0, status))
+ break; /* quit on unexpected error */
+
+ ii++;
+ }
+ }
+
+ ffmahd(infptr, hdunum, NULL, status); /* restore initial position */
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffcphd(fitsfile *infptr, /* I - FITS file pointer to input file */
+ fitsfile *outfptr, /* I - FITS file pointer to output file */
+ int *status) /* IO - error status */
+/*
+ copy the header keywords from infptr to outfptr.
+*/
+{
+ int nkeys, ii, inPrim = 0, outPrim = 0;
+ long naxis, naxes[1];
+ char *card, comm[FLEN_COMMENT];
+ char *tmpbuff = NULL;
+
+ if (*status > 0)
+ return(*status);
+
+ if (infptr == outfptr)
+ return(*status = SAME_FILE);
+
+ /* set the input pointer to the correct HDU */
+ if (infptr->HDUposition != (infptr->Fptr)->curhdu)
+ ffmahd(infptr, (infptr->HDUposition) + 1, NULL, status);
+
+ if (ffghsp(infptr, &nkeys, NULL, status) > 0) /* get no. of keywords */
+ return(*status);
+
+ /* create a memory buffer to hold the header records */
+ tmpbuff = (char*) malloc(nkeys*FLEN_CARD*sizeof(char));
+ if (!tmpbuff)
+ return(*status = MEMORY_ALLOCATION);
+
+ /* read all of the header records in the input HDU */
+ for (ii = 0; ii < nkeys; ii++)
+ ffgrec(infptr, ii+1, tmpbuff + (ii * FLEN_CARD), status);
+
+ if (infptr->HDUposition == 0) /* set flag if this is the Primary HDU */
+ inPrim = 1;
+
+ /* if input is an image hdu, get the number of axes */
+ naxis = -1; /* negative if HDU is a table */
+ if ((infptr->Fptr)->hdutype == IMAGE_HDU)
+ ffgkyj(infptr, "NAXIS", &naxis, NULL, status);
+
+ /* set the output pointer to the correct HDU */
+ if (outfptr->HDUposition != (outfptr->Fptr)->curhdu)
+ ffmahd(outfptr, (outfptr->HDUposition) + 1, NULL, status);
+
+ /* check if output header is empty; if not create new empty HDU */
+ if ((outfptr->Fptr)->headend !=
+ (outfptr->Fptr)->headstart[(outfptr->Fptr)->curhdu] )
+ ffcrhd(outfptr, status);
+
+ if (outfptr->HDUposition == 0)
+ {
+ if (naxis < 0)
+ {
+ /* the input HDU is a table, so we have to create */
+ /* a dummy Primary array before copying it to the output */
+ ffcrim(outfptr, 8, 0, naxes, status);
+ ffcrhd(outfptr, status); /* create new empty HDU */
+ }
+ else
+ {
+ /* set flag that this is the Primary HDU */
+ outPrim = 1;
+ }
+ }
+
+ if (*status > 0) /* check for errors before proceeding */
+ {
+ free(tmpbuff);
+ return(*status);
+ }
+ if ( inPrim == 1 && outPrim == 0 )
+ {
+ /* copying from primary array to image extension */
+ strcpy(comm, "IMAGE extension");
+ ffpkys(outfptr, "XTENSION", "IMAGE", comm, status);
+
+ /* copy BITPIX through NAXISn keywords */
+ for (ii = 1; ii < 3 + naxis; ii++)
+ {
+ card = tmpbuff + (ii * FLEN_CARD);
+ ffprec(outfptr, card, status);
+ }
+
+ strcpy(comm, "number of random group parameters");
+ ffpkyj(outfptr, "PCOUNT", 0, comm, status);
+
+ strcpy(comm, "number of random groups");
+ ffpkyj(outfptr, "GCOUNT", 1, comm, status);
+
+
+ /* copy remaining keywords, excluding EXTEND, and reference COMMENT keywords */
+ for (ii = 3 + naxis ; ii < nkeys; ii++)
+ {
+ card = tmpbuff+(ii * FLEN_CARD);
+ if (FSTRNCMP(card, "EXTEND ", 8) &&
+ FSTRNCMP(card, "COMMENT FITS (Flexible Image Transport System) format is", 58) &&
+ FSTRNCMP(card, "COMMENT and Astrophysics', volume 376, page 3", 47) )
+ {
+ ffprec(outfptr, card, status);
+ }
+ }
+ }
+ else if ( inPrim == 0 && outPrim == 1 )
+ {
+ /* copying between image extension and primary array */
+ strcpy(comm, "file does conform to FITS standard");
+ ffpkyl(outfptr, "SIMPLE", TRUE, comm, status);
+
+ /* copy BITPIX through NAXISn keywords */
+ for (ii = 1; ii < 3 + naxis; ii++)
+ {
+ card = tmpbuff + (ii * FLEN_CARD);
+ ffprec(outfptr, card, status);
+ }
+
+ /* add the EXTEND keyword */
+ strcpy(comm, "FITS dataset may contain extensions");
+ ffpkyl(outfptr, "EXTEND", TRUE, comm, status);
+
+ /* write standard block of self-documentating comments */
+ ffprec(outfptr,
+ "COMMENT FITS (Flexible Image Transport System) format is defined in 'Astronomy",
+ status);
+ ffprec(outfptr,
+ "COMMENT and Astrophysics', volume 376, page 359; bibcode: 2001A&A...376..359H",
+ status);
+
+ /* copy remaining keywords, excluding pcount, gcount */
+ for (ii = 3 + naxis; ii < nkeys; ii++)
+ {
+ card = tmpbuff+(ii * FLEN_CARD);
+ if (FSTRNCMP(card, "PCOUNT ", 8) && FSTRNCMP(card, "GCOUNT ", 8))
+ {
+ ffprec(outfptr, card, status);
+ }
+ }
+ }
+ else
+ {
+ /* input and output HDUs are same type; simply copy all keywords */
+ for (ii = 0; ii < nkeys; ii++)
+ {
+ card = tmpbuff+(ii * FLEN_CARD);
+ ffprec(outfptr, card, status);
+ }
+ }
+
+ free(tmpbuff);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffcpdt(fitsfile *infptr, /* I - FITS file pointer to input file */
+ fitsfile *outfptr, /* I - FITS file pointer to output file */
+ int *status) /* IO - error status */
+{
+/*
+ copy the data unit from the CHDU of infptr to the CHDU of outfptr.
+ This will overwrite any data already in the outfptr CHDU.
+*/
+ long nb, ii;
+ OFF_T indatastart, indataend, outdatastart;
+ char buffer[2880];
+
+ if (*status > 0)
+ return(*status);
+
+ if (infptr == outfptr)
+ return(*status = SAME_FILE);
+
+ ffghof(infptr, NULL, &indatastart, &indataend, status);
+ ffghof(outfptr, NULL, &outdatastart, NULL, status);
+
+ /* Calculate the number of blocks to be copied */
+ nb = (indataend - indatastart) / 2880;
+
+ if (nb > 0)
+ {
+ if (infptr->Fptr == outfptr->Fptr)
+ {
+ /* copying between 2 HDUs in the SAME file */
+ for (ii = 0; ii < nb; ii++)
+ {
+ ffmbyt(infptr, indatastart, REPORT_EOF, status);
+ ffgbyt(infptr, 2880L, buffer, status); /* read input block */
+
+ ffmbyt(outfptr, outdatastart, IGNORE_EOF, status);
+ ffpbyt(outfptr, 2880L, buffer, status); /* write output block */
+
+ indatastart += 2880; /* move address */
+ outdatastart += 2880; /* move address */
+ }
+ }
+ else
+ {
+ /* copying between HDUs in separate files */
+ /* move to the initial copy position in each of the files */
+ ffmbyt(infptr, indatastart, REPORT_EOF, status);
+ ffmbyt(outfptr, outdatastart, IGNORE_EOF, status);
+
+ for (ii = 0; ii < nb; ii++)
+ {
+ ffgbyt(infptr, 2880L, buffer, status); /* read input block */
+ ffpbyt(outfptr, 2880L, buffer, status); /* write output block */
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffiimg(fitsfile *fptr, /* I - FITS file pointer */
+ int bitpix, /* I - bits per pixel */
+ int naxis, /* I - number of axes in the array */
+ long *naxes, /* I - size of each axis */
+ int *status) /* IO - error status */
+/*
+ insert an IMAGE extension following the current HDU
+*/
+{
+ int bytlen, nexthdu, maxhdu, ii, onaxis;
+ long nblocks;
+ OFF_T npixels, newstart, datasize;
+ char errmsg[FLEN_ERRMSG], card[FLEN_CARD], naxiskey[FLEN_KEYWORD];
+
+ if (*status > 0)
+ return(*status);
+
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+
+ maxhdu = (fptr->Fptr)->maxhdu;
+
+ if (*status != PREPEND_PRIMARY)
+ {
+ /* if the current header is completely empty ... */
+ if (( (fptr->Fptr)->headend == (fptr->Fptr)->headstart[(fptr->Fptr)->curhdu])
+ /* or, if we are at the end of the file, ... */
+ || ( (((fptr->Fptr)->curhdu) == maxhdu ) &&
+ ((fptr->Fptr)->headstart[maxhdu + 1] >= (fptr->Fptr)->logfilesize ) ) )
+ {
+ /* then simply append new image extension */
+ ffcrim(fptr, bitpix, naxis, naxes, status);
+ return(*status);
+ }
+ }
+
+ if (bitpix == 8)
+ bytlen = 1;
+ else if (bitpix == 16)
+ bytlen = 2;
+ else if (bitpix == 32 || bitpix == -32)
+ bytlen = 4;
+ else if (bitpix == -64)
+ bytlen = 8;
+ else
+ {
+ sprintf(errmsg,
+ "Illegal value for BITPIX keyword: %d", bitpix);
+ ffpmsg(errmsg);
+ return(*status = BAD_BITPIX); /* illegal bitpix value */
+ }
+ if (naxis < 0 || naxis > 999)
+ {
+ sprintf(errmsg,
+ "Illegal value for NAXIS keyword: %d", naxis);
+ ffpmsg(errmsg);
+ return(*status = BAD_NAXIS);
+ }
+
+ for (ii = 0; ii < naxis; ii++)
+ {
+ if (naxes[ii] < 0)
+ {
+ sprintf(errmsg,
+ "Illegal value for NAXIS%d keyword: %ld", ii + 1, naxes[ii]);
+ ffpmsg(errmsg);
+ return(*status = BAD_NAXES);
+ }
+ }
+
+ /* calculate number of pixels in the image */
+ if (naxis == 0)
+ npixels = 0;
+ else
+ npixels = naxes[0];
+
+ for (ii = 1; ii < naxis; ii++)
+ npixels = npixels * naxes[ii];
+
+ datasize = npixels * bytlen; /* size of image in bytes */
+ nblocks = ((datasize + 2879) / 2880) + 1; /* +1 for the header */
+
+ if ((fptr->Fptr)->writemode == READWRITE) /* must have write access */
+ { /* close the CHDU */
+ ffrdef(fptr, status); /* scan header to redefine structure */
+ ffpdfl(fptr, status); /* insure correct data file values */
+ }
+ else
+ return(*status = READONLY_FILE);
+
+ if (*status == PREPEND_PRIMARY)
+ {
+ /* inserting a new primary array; the current primary */
+ /* array must be transformed into an image extension. */
+
+ *status = 0;
+ ffmahd(fptr, 1, NULL, status); /* move to the primary array */
+
+ ffgidm(fptr, &onaxis, status);
+ if (onaxis > 0)
+ ffkeyn("NAXIS",onaxis, naxiskey, status);
+ else
+ strcpy(naxiskey, "NAXIS");
+
+ ffgcrd(fptr, naxiskey, card, status); /* read last NAXIS keyword */
+
+ ffikyj(fptr, "PCOUNT", 0L, "required keyword", status); /* add PCOUNT and */
+ ffikyj(fptr, "GCOUNT", 1L, "required keyword", status); /* GCOUNT keywords */
+
+ if (*status > 0)
+ return(*status);
+
+ if (ffdkey(fptr, "EXTEND", status) ) /* delete the EXTEND keyword */
+ *status = 0;
+
+ /* redefine internal structure for this HDU */
+ ffrdef(fptr, status);
+
+
+ /* insert space for the primary array */
+ if (ffiblk(fptr, nblocks, -1, status) > 0) /* insert the blocks */
+ return(*status);
+
+ nexthdu = 0; /* number of the new hdu */
+ newstart = 0; /* starting addr of HDU */
+ }
+ else
+ {
+ nexthdu = ((fptr->Fptr)->curhdu) + 1; /* number of the next (new) hdu */
+ newstart = (fptr->Fptr)->headstart[nexthdu]; /* save starting addr of HDU */
+
+ (fptr->Fptr)->hdutype = IMAGE_HDU; /* so that correct fill value is used */
+ /* ffiblk also increments headstart for all following HDUs */
+ if (ffiblk(fptr, nblocks, 1, status) > 0) /* insert the blocks */
+ return(*status);
+ }
+
+ ((fptr->Fptr)->maxhdu)++; /* increment known number of HDUs in the file */
+ for (ii = (fptr->Fptr)->maxhdu; ii > (fptr->Fptr)->curhdu; ii--)
+ (fptr->Fptr)->headstart[ii + 1] = (fptr->Fptr)->headstart[ii]; /* incre start addr */
+
+ if (nexthdu == 0)
+ (fptr->Fptr)->headstart[1] = nblocks * 2880; /* start of the old Primary array */
+
+ (fptr->Fptr)->headstart[nexthdu] = newstart; /* set starting addr of HDU */
+
+ /* set default parameters for this new empty HDU */
+ (fptr->Fptr)->curhdu = nexthdu; /* we are now located at the next HDU */
+ fptr->HDUposition = nexthdu; /* we are now located at the next HDU */
+ (fptr->Fptr)->nextkey = (fptr->Fptr)->headstart[nexthdu];
+ (fptr->Fptr)->headend = (fptr->Fptr)->headstart[nexthdu];
+ (fptr->Fptr)->datastart = ((fptr->Fptr)->headstart[nexthdu]) + 2880;
+ (fptr->Fptr)->hdutype = IMAGE_HDU; /* might need to be reset... */
+
+ /* write the required header keywords */
+ ffphpr(fptr, TRUE, bitpix, naxis, naxes, 0, 1, TRUE, status);
+
+ /* redefine internal structure for this HDU */
+ ffrdef(fptr, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffitab(fitsfile *fptr, /* I - FITS file pointer */
+ long naxis1, /* I - width of row in the table */
+ long naxis2, /* I - number of rows in the table */
+ int tfields, /* I - number of columns in the table */
+ char **ttype, /* I - name of each column */
+ long *tbcol, /* I - byte offset in row to each column */
+ char **tform, /* I - value of TFORMn keyword for each column */
+ char **tunit, /* I - value of TUNITn keyword for each column */
+ char *extnm, /* I - value of EXTNAME keyword, if any */
+ int *status) /* IO - error status */
+/*
+ insert an ASCII table extension following the current HDU
+*/
+{
+ int nexthdu, maxhdu, ii, nunit, nhead, ncols, gotmem = 0;
+ long nblocks, rowlen;
+ OFF_T datasize, newstart;
+ char errmsg[81];
+
+ if (*status > 0)
+ return(*status);
+
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+
+ maxhdu = (fptr->Fptr)->maxhdu;
+ /* if the current header is completely empty ... */
+ if (( (fptr->Fptr)->headend == (fptr->Fptr)->headstart[(fptr->Fptr)->curhdu] )
+ /* or, if we are at the end of the file, ... */
+ || ( (((fptr->Fptr)->curhdu) == maxhdu ) &&
+ ((fptr->Fptr)->headstart[maxhdu + 1] >= (fptr->Fptr)->logfilesize ) ) )
+ {
+ /* then simply append new image extension */
+ ffcrtb(fptr, ASCII_TBL, naxis2, tfields, ttype, tform, tunit,
+ extnm, status);
+ return(*status);
+ }
+
+ if (naxis1 < 0)
+ return(*status = NEG_WIDTH);
+ else if (naxis2 < 0)
+ return(*status = NEG_ROWS);
+ else if (tfields < 0 || tfields > 999)
+ {
+ sprintf(errmsg,
+ "Illegal value for TFIELDS keyword: %d", tfields);
+ ffpmsg(errmsg);
+ return(*status = BAD_TFIELDS);
+ }
+
+ /* count number of optional TUNIT keywords to be written */
+ nunit = 0;
+ for (ii = 0; ii < tfields; ii++)
+ {
+ if (tunit && *tunit && *tunit[ii])
+ nunit++;
+ }
+
+ if (extnm && *extnm)
+ nunit++; /* add one for the EXTNAME keyword */
+
+ rowlen = naxis1;
+
+ if (!tbcol || !tbcol[0] || (!naxis1 && tfields)) /* spacing not defined? */
+ {
+ /* allocate mem for tbcol; malloc may have problems allocating small */
+ /* arrays, so allocate at least 20 bytes */
+
+ ncols = maxvalue(5, tfields);
+ tbcol = (long *) calloc(ncols, sizeof(long));
+
+ if (tbcol)
+ {
+ gotmem = 1;
+
+ /* calculate width of a row and starting position of each column. */
+ /* Each column will be separated by 1 blank space */
+ ffgabc(tfields, tform, 1, &rowlen, tbcol, status);
+ }
+ }
+
+ nhead = (9 + (3 * tfields) + nunit + 35) / 36; /* no. of header blocks */
+ datasize = (OFF_T)rowlen * naxis2; /* size of table in bytes */
+ nblocks = ((datasize + 2879) / 2880) + nhead; /* size of HDU */
+
+ if ((fptr->Fptr)->writemode == READWRITE) /* must have write access */
+ { /* close the CHDU */
+ ffrdef(fptr, status); /* scan header to redefine structure */
+ ffpdfl(fptr, status); /* insure correct data file values */
+ }
+ else
+ return(*status = READONLY_FILE);
+
+ nexthdu = ((fptr->Fptr)->curhdu) + 1; /* number of the next (new) hdu */
+ newstart = (fptr->Fptr)->headstart[nexthdu]; /* save starting addr of HDU */
+
+ (fptr->Fptr)->hdutype = ASCII_TBL; /* so that correct fill value is used */
+ /* ffiblk also increments headstart for all following HDUs */
+ if (ffiblk(fptr, nblocks, 1, status) > 0) /* insert the blocks */
+ {
+ if (gotmem)
+ free(tbcol);
+ return(*status);
+ }
+
+ ((fptr->Fptr)->maxhdu)++; /* increment known number of HDUs in the file */
+ for (ii = (fptr->Fptr)->maxhdu; ii > (fptr->Fptr)->curhdu; ii--)
+ (fptr->Fptr)->headstart[ii + 1] = (fptr->Fptr)->headstart[ii]; /* incre start addr */
+
+ (fptr->Fptr)->headstart[nexthdu] = newstart; /* set starting addr of HDU */
+
+ /* set default parameters for this new empty HDU */
+ (fptr->Fptr)->curhdu = nexthdu; /* we are now located at the next HDU */
+ fptr->HDUposition = nexthdu; /* we are now located at the next HDU */
+ (fptr->Fptr)->nextkey = (fptr->Fptr)->headstart[nexthdu];
+ (fptr->Fptr)->headend = (fptr->Fptr)->headstart[nexthdu];
+ (fptr->Fptr)->datastart = ((fptr->Fptr)->headstart[nexthdu]) + (nhead * 2880);
+ (fptr->Fptr)->hdutype = ASCII_TBL; /* might need to be reset... */
+
+ /* write the required header keywords */
+
+ ffphtb(fptr, rowlen, naxis2, tfields, ttype, tbcol, tform, tunit,
+ extnm, status);
+
+ if (gotmem)
+ free(tbcol);
+
+ /* redefine internal structure for this HDU */
+
+ ffrdef(fptr, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffibin(fitsfile *fptr, /* I - FITS file pointer */
+ long naxis2, /* I - number of rows in the table */
+ int tfields, /* I - number of columns in the table */
+ char **ttype, /* I - name of each column */
+ char **tform, /* I - value of TFORMn keyword for each column */
+ char **tunit, /* I - value of TUNITn keyword for each column */
+ char *extnm, /* I - value of EXTNAME keyword, if any */
+ long pcount, /* I - size of special data area (heap) */
+ int *status) /* IO - error status */
+/*
+ insert a Binary table extension following the current HDU
+*/
+{
+ int nexthdu, maxhdu, ii, nunit, nhead, datacode;
+ long naxis1, nblocks, repeat, width;
+ OFF_T datasize, newstart;
+ char errmsg[81];
+
+ if (*status > 0)
+ return(*status);
+
+
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+
+ maxhdu = (fptr->Fptr)->maxhdu;
+ /* if the current header is completely empty ... */
+ if (( (fptr->Fptr)->headend == (fptr->Fptr)->headstart[(fptr->Fptr)->curhdu] )
+ /* or, if we are at the end of the file, ... */
+ || ( (((fptr->Fptr)->curhdu) == maxhdu ) &&
+ ((fptr->Fptr)->headstart[maxhdu + 1] >= (fptr->Fptr)->logfilesize ) ) )
+ {
+ /* then simply append new image extension */
+ ffcrtb(fptr, BINARY_TBL, naxis2, tfields, ttype, tform, tunit,
+ extnm, status);
+ return(*status);
+ }
+
+ if (naxis2 < 0)
+ return(*status = NEG_ROWS);
+ else if (tfields < 0 || tfields > 999)
+ {
+ sprintf(errmsg,
+ "Illegal value for TFIELDS keyword: %d", tfields);
+ ffpmsg(errmsg);
+ return(*status = BAD_TFIELDS);
+ }
+
+ /* count number of optional TUNIT keywords to be written */
+ nunit = 0;
+ for (ii = 0; ii < tfields; ii++)
+ {
+ if (tunit && *tunit && *tunit[ii])
+ nunit++;
+ }
+
+ if (extnm && *extnm)
+ nunit++; /* add one for the EXTNAME keyword */
+
+ nhead = (9 + (2 * tfields) + nunit + 35) / 36; /* no. of header blocks */
+
+ /* calculate total width of the table */
+ naxis1 = 0;
+ for (ii = 0; ii < tfields; ii++)
+ {
+ ffbnfm(tform[ii], &datacode, &repeat, &width, status);
+
+ if (datacode == TBIT)
+ naxis1 = naxis1 + ((repeat + 7) / 8);
+ else if (datacode == TSTRING)
+ naxis1 += repeat;
+ else
+ naxis1 = naxis1 + (repeat * width);
+ }
+
+ datasize = ((OFF_T)naxis1 * naxis2) + pcount; /* size of table in bytes */
+ nblocks = ((datasize + 2879) / 2880) + nhead; /* size of HDU */
+
+ if ((fptr->Fptr)->writemode == READWRITE) /* must have write access */
+ { /* close the CHDU */
+ ffrdef(fptr, status); /* scan header to redefine structure */
+ ffpdfl(fptr, status); /* insure correct data file values */
+ }
+ else
+ return(*status = READONLY_FILE);
+
+ nexthdu = ((fptr->Fptr)->curhdu) + 1; /* number of the next (new) hdu */
+ newstart = (fptr->Fptr)->headstart[nexthdu]; /* save starting addr of HDU */
+
+ (fptr->Fptr)->hdutype = BINARY_TBL; /* so that correct fill value is used */
+
+ /* ffiblk also increments headstart for all following HDUs */
+ if (ffiblk(fptr, nblocks, 1, status) > 0) /* insert the blocks */
+ return(*status);
+
+ ((fptr->Fptr)->maxhdu)++; /* increment known number of HDUs in the file */
+ for (ii = (fptr->Fptr)->maxhdu; ii > (fptr->Fptr)->curhdu; ii--)
+ (fptr->Fptr)->headstart[ii + 1] = (fptr->Fptr)->headstart[ii]; /* incre start addr */
+
+ (fptr->Fptr)->headstart[nexthdu] = newstart; /* set starting addr of HDU */
+
+ /* set default parameters for this new empty HDU */
+ (fptr->Fptr)->curhdu = nexthdu; /* we are now located at the next HDU */
+ fptr->HDUposition = nexthdu; /* we are now located at the next HDU */
+ (fptr->Fptr)->nextkey = (fptr->Fptr)->headstart[nexthdu];
+ (fptr->Fptr)->headend = (fptr->Fptr)->headstart[nexthdu];
+ (fptr->Fptr)->datastart = ((fptr->Fptr)->headstart[nexthdu]) + (nhead * 2880);
+ (fptr->Fptr)->hdutype = BINARY_TBL; /* might need to be reset... */
+
+ /* write the required header keywords. This will write PCOUNT = 0 */
+ /* so that the variable length data will be written at the right place */
+ ffphbn(fptr, naxis2, tfields, ttype, tform, tunit, extnm, pcount,
+ status);
+
+ /* redefine internal structure for this HDU (with PCOUNT = 0) */
+ ffrdef(fptr, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffdhdu(fitsfile *fptr, /* I - FITS file pointer */
+ int *hdutype, /* O - type of the new CHDU after deletion */
+ int *status) /* IO - error status */
+/*
+ Delete the CHDU. If the CHDU is the primary array, then replace the HDU
+ with an empty primary array with no data. Return the
+ type of the new CHDU after the old CHDU is deleted.
+*/
+{
+ int tmptype = 0;
+ long nblocks, ii, naxes[1];
+
+ if (*status > 0)
+ return(*status);
+
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+
+ if ((fptr->Fptr)->curhdu == 0) /* replace primary array with null image */
+ {
+ /* ignore any existing keywords */
+ (fptr->Fptr)->headend = 0;
+ (fptr->Fptr)->nextkey = 0;
+
+ /* write default primary array header */
+ ffphpr(fptr,1,8,0,naxes,0,1,1,status);
+
+ /* calc number of blocks to delete (leave just 1 block) */
+ nblocks = ( (fptr->Fptr)->headstart[(fptr->Fptr)->curhdu + 1] -
+ 2880 ) / 2880;
+
+ /* ffdblk also updates the starting address of all following HDUs */
+ if (nblocks > 0)
+ {
+ if (ffdblk(fptr, nblocks, status) > 0) /* delete the HDU */
+ return(*status);
+ }
+
+ /* this might not be necessary, but is doesn't hurt */
+ (fptr->Fptr)->datastart = DATA_UNDEFINED;
+
+ ffrdef(fptr, status); /* reinitialize the primary array */
+ }
+ else
+ {
+
+ /* calc number of blocks to delete */
+ nblocks = ( (fptr->Fptr)->headstart[(fptr->Fptr)->curhdu + 1] -
+ (fptr->Fptr)->headstart[(fptr->Fptr)->curhdu] ) / 2880;
+
+ /* ffdblk also updates the starting address of all following HDUs */
+ if (ffdblk(fptr, nblocks, status) > 0) /* delete the HDU */
+ return(*status);
+
+ /* delete the CHDU from the list of HDUs */
+ for (ii = (fptr->Fptr)->curhdu + 1; ii <= (fptr->Fptr)->maxhdu; ii++)
+ (fptr->Fptr)->headstart[ii] = (fptr->Fptr)->headstart[ii + 1];
+
+ (fptr->Fptr)->headstart[(fptr->Fptr)->maxhdu + 1] = 0;
+ ((fptr->Fptr)->maxhdu)--; /* decrement the known number of HDUs */
+
+ if (ffrhdu(fptr, &tmptype, status) > 0) /* initialize next HDU */
+ {
+ /* failed (end of file?), so move back one HDU */
+ *status = 0;
+ ffcmsg(); /* clear extraneous error messages */
+ ffgext(fptr, ((fptr->Fptr)->curhdu) - 1, &tmptype, status);
+ }
+ }
+
+ if (hdutype)
+ *hdutype = tmptype;
+
+ return(*status);
+}
+
diff --git a/pkg/tbtables/cfitsio/eval.l b/pkg/tbtables/cfitsio/eval.l
new file mode 100644
index 00000000..4b9e0deb
--- /dev/null
+++ b/pkg/tbtables/cfitsio/eval.l
@@ -0,0 +1,512 @@
+%{
+/************************************************************************/
+/* */
+/* CFITSIO Lexical Parser */
+/* */
+/* This file is one of 3 files containing code which parses an */
+/* arithmetic expression and evaluates it in the context of an input */
+/* FITS file table extension. The CFITSIO lexical parser is divided */
+/* into the following 3 parts/files: the CFITSIO "front-end", */
+/* eval_f.c, contains the interface between the user/CFITSIO and the */
+/* real core of the parser; the FLEX interpreter, eval_l.c, takes the */
+/* input string and parses it into tokens and identifies the FITS */
+/* information required to evaluate the expression (ie, keywords and */
+/* columns); and, the BISON grammar and evaluation routines, eval_y.c, */
+/* receives the FLEX output and determines and performs the actual */
+/* operations. The files eval_l.c and eval_y.c are produced from */
+/* running flex and bison on the files eval.l and eval.y, respectively. */
+/* (flex and bison are available from any GNU archive: see www.gnu.org) */
+/* */
+/* The grammar rules, rather than evaluating the expression in situ, */
+/* builds a tree, or Nodal, structure mapping out the order of */
+/* operations and expression dependencies. This "compilation" process */
+/* allows for much faster processing of multiple rows. This technique */
+/* was developed by Uwe Lammers of the XMM Science Analysis System, */
+/* although the CFITSIO implementation is entirely code original. */
+/* */
+/* */
+/* Modification History: */
+/* */
+/* Kent Blackburn c1992 Original parser code developed for the */
+/* FTOOLS software package, in particular, */
+/* the fselect task. */
+/* Kent Blackburn c1995 BIT column support added */
+/* Peter D Wilson Feb 1998 Vector column support added */
+/* Peter D Wilson May 1998 Ported to CFITSIO library. User */
+/* interface routines written, in essence */
+/* making fselect, fcalc, and maketime */
+/* capabilities available to all tools */
+/* via single function calls. */
+/* Peter D Wilson Jun 1998 Major rewrite of parser core, so as to */
+/* create a run-time evaluation tree, */
+/* inspired by the work of Uwe Lammers, */
+/* resulting in a speed increase of */
+/* 10-100 times. */
+/* Peter D Wilson Jul 1998 gtifilter(a,b,c,d) function added */
+/* Peter D Wilson Aug 1998 regfilter(a,b,c,d) function added */
+/* Peter D Wilson Jul 1999 Make parser fitsfile-independent, */
+/* allowing a purely vector-based usage */
+/* */
+/************************************************************************/
+
+#include <math.h>
+#include <string.h>
+#include <ctype.h>
+#ifdef sparc
+#include <malloc.h>
+#else
+#include <stdlib.h>
+#endif
+#include "eval_defs.h"
+
+ParseData gParse; /* Global structure holding all parser information */
+
+/***** Internal functions *****/
+
+ int yyGetVariable( char *varName, YYSTYPE *varVal );
+
+static int find_variable( char *varName );
+static int expr_read( char *buf, int nbytes );
+
+/***** Definitions *****/
+
+#define YY_NO_UNPUT /* Don't include YYUNPUT function */
+#define YY_NEVER_INTERACTIVE 1
+
+#define MAXCHR 256
+#define MAXBIT 128
+
+#define OCT_0 "000"
+#define OCT_1 "001"
+#define OCT_2 "010"
+#define OCT_3 "011"
+#define OCT_4 "100"
+#define OCT_5 "101"
+#define OCT_6 "110"
+#define OCT_7 "111"
+#define OCT_X "xxx"
+
+#define HEX_0 "0000"
+#define HEX_1 "0001"
+#define HEX_2 "0010"
+#define HEX_3 "0011"
+#define HEX_4 "0100"
+#define HEX_5 "0101"
+#define HEX_6 "0110"
+#define HEX_7 "0111"
+#define HEX_8 "1000"
+#define HEX_9 "1001"
+#define HEX_A "1010"
+#define HEX_B "1011"
+#define HEX_C "1100"
+#define HEX_D "1101"
+#define HEX_E "1110"
+#define HEX_F "1111"
+#define HEX_X "xxxx"
+
+/*
+ MJT - 13 June 1996
+ read from buffer instead of stdin
+ (as per old ftools.skel)
+*/
+#undef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+ if ( (result = expr_read( (char *) buf, max_size )) < 0 ) \
+ YY_FATAL_ERROR( "read() in flex scanner failed" );
+
+%}
+bit ([bB][01xX]+)
+oct ([oO][01234567xX]+)
+hex ([hH][0123456789aAbBcCdDeEfFxX]+)
+integer [0-9]+
+boolean (t|f|T|F)
+real ([0-9]*"."[0-9]+)|([0-9]*"."*[0-9]+[eEdD][+-]?[0-9]+)|([0-9]*".")
+constant ("#"[a-zA-Z0-9_]+)|("#""$"[^\n]*"$")
+string ([\"][^\"\n]*[\"])|([\'][^\'\n]*[\'])
+variable ([a-zA-Z_][a-zA-Z0-9_]*)|("$"[^$\n]*"$")
+function [a-zA-Z][a-zA-Z0-9]+"("
+intcast ("(int)"|"(INT)")
+fltcast ("(float)"|"(FLOAT)"|"(double)"|"(DOUBLE)")
+power ("^"|"**")
+not ("!"|".not."|".NOT."|"not."|"NOT.")
+or ("||"|".or."|".OR."|"or."|"OR.")
+and ("&&"|".and."|".AND."|"and."|"AND.")
+equal ("=="|".eq."|".EQ."|"eq."|"EQ.")
+not_equal ("!="|".ne."|".NE."|"ne."|"NE.")
+greater (">"|".gt."|".GT."|"gt."|"GT.")
+lesser ("<"|".lt."|".LT."|"lt."|"LT.")
+greater_eq (">="|"=>"|".ge."|".GE."|"ge."|"GE.")
+lesser_eq ("<="|"=<"|".le."|".LE."|"le."|"LE.")
+nl \n
+
+%%
+
+[ \t]+ ;
+{bit} {
+ int len;
+ len = strlen(yytext);
+ while (yytext[len] == ' ')
+ len--;
+ len = len - 1;
+ strncpy(yylval.str,&yytext[1],len);
+ yylval.str[len] = '\0';
+ return( BITSTR );
+ }
+{oct} {
+ int len;
+ char tmpstring[256];
+ char bitstring[256];
+ len = strlen(yytext);
+ while (yytext[len] == ' ')
+ len--;
+ len = len - 1;
+ strncpy(tmpstring,&yytext[1],len);
+ tmpstring[len] = '\0';
+ bitstring[0] = '\0';
+ len = 0;
+ while ( tmpstring[len] != '\0')
+ {
+ switch ( tmpstring[len] )
+ {
+ case '0':
+ strcat(bitstring,OCT_0);
+ break;
+ case '1':
+ strcat(bitstring,OCT_1);
+ break;
+ case '2':
+ strcat(bitstring,OCT_2);
+ break;
+ case '3':
+ strcat(bitstring,OCT_3);
+ break;
+ case '4':
+ strcat(bitstring,OCT_4);
+ break;
+ case '5':
+ strcat(bitstring,OCT_5);
+ break;
+ case '6':
+ strcat(bitstring,OCT_6);
+ break;
+ case '7':
+ strcat(bitstring,OCT_7);
+ break;
+ case 'x':
+ case 'X':
+ strcat(bitstring,OCT_X);
+ break;
+ }
+ len++;
+ }
+ strcpy( yylval.str, bitstring );
+ return( BITSTR );
+ }
+{hex} {
+ int len;
+ char tmpstring[256];
+ char bitstring[256];
+ len = strlen(yytext);
+ while (yytext[len] == ' ')
+ len--;
+ len = len - 1;
+ strncpy(tmpstring,&yytext[1],len);
+ tmpstring[len] = '\0';
+ bitstring[0] = '\0';
+ len = 0;
+ while ( tmpstring[len] != '\0')
+ {
+ switch ( tmpstring[len] )
+ {
+ case '0':
+ strcat(bitstring,HEX_0);
+ break;
+ case '1':
+ strcat(bitstring,HEX_1);
+ break;
+ case '2':
+ strcat(bitstring,HEX_2);
+ break;
+ case '3':
+ strcat(bitstring,HEX_3);
+ break;
+ case '4':
+ strcat(bitstring,HEX_4);
+ break;
+ case '5':
+ strcat(bitstring,HEX_5);
+ break;
+ case '6':
+ strcat(bitstring,HEX_6);
+ break;
+ case '7':
+ strcat(bitstring,HEX_7);
+ break;
+ case '8':
+ strcat(bitstring,HEX_8);
+ break;
+ case '9':
+ strcat(bitstring,HEX_9);
+ break;
+ case 'a':
+ case 'A':
+ strcat(bitstring,HEX_A);
+ break;
+ case 'b':
+ case 'B':
+ strcat(bitstring,HEX_B);
+ break;
+ case 'c':
+ case 'C':
+ strcat(bitstring,HEX_C);
+ break;
+ case 'd':
+ case 'D':
+ strcat(bitstring,HEX_D);
+ break;
+ case 'e':
+ case 'E':
+ strcat(bitstring,HEX_E);
+ break;
+ case 'f':
+ case 'F':
+ strcat(bitstring,HEX_F);
+ break;
+ case 'x':
+ case 'X':
+ strcat(bitstring,HEX_X);
+ break;
+ }
+ len++;
+ }
+
+ strcpy( yylval.str, bitstring );
+ return( BITSTR );
+ }
+{integer} {
+ yylval.lng = atol(yytext);
+ return( LONG );
+ }
+{boolean} {
+ if ((yytext[0] == 't') || (yytext[0] == 'T'))
+ yylval.log = 1;
+ else
+ yylval.log = 0;
+ return( BOOLEAN );
+ }
+{real} {
+ yylval.dbl = atof(yytext);
+ return( DOUBLE );
+ }
+{constant} {
+ if( !strcasecmp(yytext,"#PI") ) {
+ yylval.dbl = (double)(4) * atan((double)(1));
+ return( DOUBLE );
+ } else if( !strcasecmp(yytext,"#E") ) {
+ yylval.dbl = exp((double)(1));
+ return( DOUBLE );
+ } else if( !strcasecmp(yytext,"#DEG") ) {
+ yylval.dbl = ((double)4)*atan((double)1)/((double)180);
+ return( DOUBLE );
+ } else if( !strcasecmp(yytext,"#ROW") ) {
+ return( ROWREF );
+ } else if( !strcasecmp(yytext,"#NULL") ) {
+ return( NULLREF );
+ } else if( !strcasecmp(yytext,"#SNULL") ) {
+ return( SNULLREF );
+ } else {
+ int len;
+ if (yytext[1] == '$') {
+ len = strlen(yytext) - 3;
+ yylval.str[0] = '#';
+ strncpy(yylval.str+1,&yytext[2],len);
+ yylval.str[len+1] = '\0';
+ yytext = yylval.str;
+ }
+ return( (*gParse.getData)(yytext, &yylval) );
+ }
+ }
+{string} {
+ int len;
+ len = strlen(yytext) - 2;
+ strncpy(yylval.str,&yytext[1],len);
+ yylval.str[len] = '\0';
+ return( STRING );
+ }
+{variable} {
+ int len,type;
+
+ if (yytext[0] == '$') {
+ len = strlen(yytext) - 2;
+ strncpy(yylval.str,&yytext[1],len);
+ yylval.str[len] = '\0';
+ yytext = yylval.str;
+ }
+ type = yyGetVariable(yytext, &yylval);
+ return( type );
+ }
+{function} {
+ char *fname;
+ int len=0;
+ fname = &yylval.str[0];
+ while( (fname[len]=toupper(yytext[len])) ) len++;
+
+ if( FSTRCMP(fname,"BOX(")==0
+ || FSTRCMP(fname,"CIRCLE(")==0
+ || FSTRCMP(fname,"ELLIPSE(")==0
+ || FSTRCMP(fname,"NEAR(")==0
+ || FSTRCMP(fname,"ISNULL(")==0
+ )
+ /* Return type is always boolean */
+ return( BFUNCTION );
+
+ else if( FSTRCMP(fname,"GTIFILTER(")==0 )
+ return( GTIFILTER );
+
+ else if( FSTRCMP(fname,"REGFILTER(")==0 )
+ return( REGFILTER );
+
+ else
+ return( FUNCTION );
+ }
+{intcast} { return( INTCAST ); }
+{fltcast} { return( FLTCAST ); }
+{power} { return( POWER ); }
+{not} { return( NOT ); }
+{or} { return( OR ); }
+{and} { return( AND ); }
+{equal} { return( EQ ); }
+{not_equal} { return( NE ); }
+{greater} { return( GT ); }
+{lesser} { return( LT ); }
+{greater_eq} { return( GTE ); }
+{lesser_eq} { return( LTE ); }
+{nl} { return( '\n' ); }
+. { return( yytext[0] ); }
+%%
+
+int yywrap()
+{
+ /* MJT -- 13 June 1996
+ Supplied for compatibility with
+ pre-2.5.1 versions of flex which
+ do not recognize %option noyywrap
+ */
+ return(1);
+}
+
+/*
+ expr_read is lifted from old ftools.skel.
+ Now we can use any version of flex with
+ no .skel file necessary! MJT - 13 June 1996
+
+ keep a memory of how many bytes have been
+ read previously, so that an unlimited-sized
+ buffer can be supported. PDW - 28 Feb 1998
+*/
+
+static int expr_read(char *buf, int nbytes)
+{
+ int n;
+
+ n = 0;
+ if( !gParse.is_eobuf ) {
+ do {
+ buf[n++] = gParse.expr[gParse.index++];
+ } while ((n<nbytes)&&(gParse.expr[gParse.index] != '\0'));
+ if( gParse.expr[gParse.index] == '\0' ) gParse.is_eobuf = 1;
+ }
+ buf[n] = '\0';
+ return(n);
+}
+
+int yyGetVariable( char *varName, YYSTYPE *thelval )
+{
+ int varNum, type;
+ char errMsg[MAXVARNAME+25];
+
+ varNum = find_variable( varName );
+ if( varNum<0 ) {
+ if( gParse.getData ) {
+ type = (*gParse.getData)( varName, thelval );
+ } else {
+ type = pERROR;
+ gParse.status = PARSE_SYNTAX_ERR;
+ strcpy (errMsg,"Unable to find data: ");
+ strncat(errMsg, varName, MAXVARNAME);
+ ffpmsg (errMsg);
+ }
+ } else {
+ /* Convert variable type into expression type */
+ switch( gParse.varData[ varNum ].type ) {
+ case LONG:
+ case DOUBLE: type = COLUMN; break;
+ case BOOLEAN: type = BCOLUMN; break;
+ case STRING: type = SCOLUMN; break;
+ case BITSTR: type = BITCOL; break;
+ default:
+ type = pERROR;
+ gParse.status = PARSE_SYNTAX_ERR;
+ strcpy (errMsg,"Bad datatype for data: ");
+ strncat(errMsg, varName, MAXVARNAME);
+ ffpmsg (errMsg);
+ break;
+ }
+ thelval->lng = varNum;
+ }
+ return( type );
+}
+
+static int find_variable(char *varName)
+{
+ int i;
+
+ if( gParse.nCols )
+ for( i=0; i<gParse.nCols; i++ ) {
+ if( ! strncasecmp(gParse.varData[i].name,varName,MAXVARNAME) ) {
+ return( i );
+ }
+ }
+ return( -1 );
+}
+
+#if defined(vms) || defined(__vms) || defined(WIN32) || defined(__WIN32__) || defined(macintosh)
+
+/* ================================================================== */
+/* A hack for nonunix machines, which lack strcasecmp and strncasecmp */
+/* ================================================================== */
+
+int strcasecmp(const char *s1, const char *s2)
+{
+ char c1, c2;
+
+ for (;;) {
+ c1 = toupper( *s1 );
+ c2 = toupper( *s2 );
+
+ if (c1 < c2) return(-1);
+ if (c1 > c2) return(1);
+ if (c1 == 0) return(0);
+ s1++;
+ s2++;
+ }
+}
+
+int strncasecmp(const char *s1, const char *s2, size_t n)
+{
+ char c1, c2;
+
+ for (; n-- ;) {
+ c1 = toupper( *s1 );
+ c2 = toupper( *s2 );
+
+ if (c1 < c2) return(-1);
+ if (c1 > c2) return(1);
+ if (c1 == 0) return(0);
+ s1++;
+ s2++;
+ }
+ return(0);
+}
+
+#endif
diff --git a/pkg/tbtables/cfitsio/eval.y b/pkg/tbtables/cfitsio/eval.y
new file mode 100644
index 00000000..238ab788
--- /dev/null
+++ b/pkg/tbtables/cfitsio/eval.y
@@ -0,0 +1,5227 @@
+%{
+/************************************************************************/
+/* */
+/* CFITSIO Lexical Parser */
+/* */
+/* This file is one of 3 files containing code which parses an */
+/* arithmetic expression and evaluates it in the context of an input */
+/* FITS file table extension. The CFITSIO lexical parser is divided */
+/* into the following 3 parts/files: the CFITSIO "front-end", */
+/* eval_f.c, contains the interface between the user/CFITSIO and the */
+/* real core of the parser; the FLEX interpreter, eval_l.c, takes the */
+/* input string and parses it into tokens and identifies the FITS */
+/* information required to evaluate the expression (ie, keywords and */
+/* columns); and, the BISON grammar and evaluation routines, eval_y.c, */
+/* receives the FLEX output and determines and performs the actual */
+/* operations. The files eval_l.c and eval_y.c are produced from */
+/* running flex and bison on the files eval.l and eval.y, respectively. */
+/* (flex and bison are available from any GNU archive: see www.gnu.org) */
+/* */
+/* The grammar rules, rather than evaluating the expression in situ, */
+/* builds a tree, or Nodal, structure mapping out the order of */
+/* operations and expression dependencies. This "compilation" process */
+/* allows for much faster processing of multiple rows. This technique */
+/* was developed by Uwe Lammers of the XMM Science Analysis System, */
+/* although the CFITSIO implementation is entirely code original. */
+/* */
+/* */
+/* Modification History: */
+/* */
+/* Kent Blackburn c1992 Original parser code developed for the */
+/* FTOOLS software package, in particular, */
+/* the fselect task. */
+/* Kent Blackburn c1995 BIT column support added */
+/* Peter D Wilson Feb 1998 Vector column support added */
+/* Peter D Wilson May 1998 Ported to CFITSIO library. User */
+/* interface routines written, in essence */
+/* making fselect, fcalc, and maketime */
+/* capabilities available to all tools */
+/* via single function calls. */
+/* Peter D Wilson Jun 1998 Major rewrite of parser core, so as to */
+/* create a run-time evaluation tree, */
+/* inspired by the work of Uwe Lammers, */
+/* resulting in a speed increase of */
+/* 10-100 times. */
+/* Peter D Wilson Jul 1998 gtifilter(a,b,c,d) function added */
+/* Peter D Wilson Aug 1998 regfilter(a,b,c,d) function added */
+/* Peter D Wilson Jul 1999 Make parser fitsfile-independent, */
+/* allowing a purely vector-based usage */
+/* Craig B Markwardt Jun 2004 Add MEDIAN() function */
+/* Craig B Markwardt Jun 2004 Add SUM(), and MIN/MAX() for bit arrays */
+/* Craig B Markwardt Jun 2004 Allow subscripting of nX bit arrays */
+/* Craig B Markwardt Jun 2004 Implement statistical functions */
+/* NVALID(), AVERAGE(), and STDDEV() */
+/* for integer and floating point vectors */
+/* Craig B Markwardt Jun 2004 Use NULL values for range errors instead*/
+/* of throwing a parse error */
+/* Craig B Markwardt Oct 2004 Add ACCUM() and SEQDIFF() functions */
+/* */
+/************************************************************************/
+
+#define APPROX 1.0e-7
+#include "eval_defs.h"
+#include "region.h"
+#include <time.h>
+
+#include <stdlib.h>
+
+#ifndef alloca
+#define alloca malloc
+#endif
+
+ /* Shrink the initial stack depth to keep local data <32K (mac limit) */
+ /* yacc will allocate more space if needed, though. */
+#define YYINITDEPTH 100
+
+/***************************************************************/
+/* Replace Bison's BACKUP macro with one that fixes a bug -- */
+/* must update state after popping the stack -- and allows */
+/* popping multiple terms at one time. */
+/***************************************************************/
+
+#define YYNEWBACKUP(token, value) \
+ do \
+ if (yychar == YYEMPTY ) \
+ { yychar = (token); \
+ memcpy( &yylval, &(value), sizeof(value) ); \
+ yychar1 = YYTRANSLATE (yychar); \
+ while (yylen--) YYPOPSTACK; \
+ yystate = *yyssp; \
+ goto yybackup; \
+ } \
+ else \
+ { yyerror ("syntax error: cannot back up"); YYERROR; } \
+ while (0)
+
+/***************************************************************/
+/* Useful macros for accessing/testing Nodes */
+/***************************************************************/
+
+#define TEST(a) if( (a)<0 ) YYERROR
+#define SIZE(a) gParse.Nodes[ a ].value.nelem
+#define TYPE(a) gParse.Nodes[ a ].type
+#define PROMOTE(a,b) if( TYPE(a) > TYPE(b) ) \
+ b = New_Unary( TYPE(a), 0, b ); \
+ else if( TYPE(a) < TYPE(b) ) \
+ a = New_Unary( TYPE(b), 0, a );
+
+/***** Internal functions *****/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static int Alloc_Node ( void );
+static void Free_Last_Node( void );
+static void Evaluate_Node ( int thisNode );
+
+static int New_Const ( int returnType, void *value, long len );
+static int New_Column( int ColNum );
+static int New_Offset( int ColNum, int offset );
+static int New_Unary ( int returnType, int Op, int Node1 );
+static int New_BinOp ( int returnType, int Node1, int Op, int Node2 );
+static int New_Func ( int returnType, funcOp Op, int nNodes,
+ int Node1, int Node2, int Node3, int Node4,
+ int Node5, int Node6, int Node7 );
+static int New_Deref ( int Var, int nDim,
+ int Dim1, int Dim2, int Dim3, int Dim4, int Dim5 );
+static int New_GTI ( char *fname, int Node1, char *start, char *stop );
+static int New_REG ( char *fname, int NodeX, int NodeY, char *colNames );
+static int New_Vector( int subNode );
+static int Close_Vec ( int vecNode );
+static int Locate_Col( Node *this );
+static int Test_Dims ( int Node1, int Node2 );
+static void Copy_Dims ( int Node1, int Node2 );
+
+static void Allocate_Ptrs( Node *this );
+static void Do_Unary ( Node *this );
+static void Do_Offset ( Node *this );
+static void Do_BinOp_bit ( Node *this );
+static void Do_BinOp_str ( Node *this );
+static void Do_BinOp_log ( Node *this );
+static void Do_BinOp_lng ( Node *this );
+static void Do_BinOp_dbl ( Node *this );
+static void Do_Func ( Node *this );
+static void Do_Deref ( Node *this );
+static void Do_GTI ( Node *this );
+static void Do_REG ( Node *this );
+static void Do_Vector ( Node *this );
+
+static long Search_GTI ( double evtTime, long nGTI, double *start,
+ double *stop, int ordered );
+
+static char saobox (double xcen, double ycen, double xwid, double ywid,
+ double rot, double xcol, double ycol);
+static char ellipse(double xcen, double ycen, double xrad, double yrad,
+ double rot, double xcol, double ycol);
+static char circle (double xcen, double ycen, double rad,
+ double xcol, double ycol);
+static char bnear (double x, double y, double tolerance);
+static char bitcmp (char *bitstrm1, char *bitstrm2);
+static char bitlgte(char *bits1, int oper, char *bits2);
+
+static void bitand(char *result, char *bitstrm1, char *bitstrm2);
+static void bitor (char *result, char *bitstrm1, char *bitstrm2);
+static void bitnot(char *result, char *bits);
+
+static void yyerror(char *msg);
+
+#ifdef __cplusplus
+ }
+#endif
+
+%}
+
+%union {
+ int Node; /* Index of Node */
+ double dbl; /* real value */
+ long lng; /* integer value */
+ char log; /* logical value */
+ char str[256]; /* string value */
+}
+
+%token <log> BOOLEAN /* First 3 must be in order of */
+%token <lng> LONG /* increasing promotion for later use */
+%token <dbl> DOUBLE
+%token <str> STRING
+%token <str> BITSTR
+%token <str> FUNCTION
+%token <str> BFUNCTION
+%token <str> GTIFILTER
+%token <str> REGFILTER
+%token <lng> COLUMN
+%token <lng> BCOLUMN
+%token <lng> SCOLUMN
+%token <lng> BITCOL
+%token <lng> ROWREF
+%token <lng> NULLREF
+%token <lng> SNULLREF
+
+%type <Node> expr
+%type <Node> bexpr
+%type <Node> sexpr
+%type <Node> bits
+%type <Node> vector
+%type <Node> bvector
+
+%left ',' '=' ':' '{' '}'
+%right '?'
+%left OR
+%left AND
+%left EQ NE '~'
+%left GT LT LTE GTE
+%left '+' '-' '%'
+%left '*' '/'
+%left '|' '&'
+%right POWER
+%left NOT
+%left INTCAST FLTCAST
+%left UMINUS
+%left '['
+
+%right ACCUM DIFF
+
+%%
+
+lines: /* nothing ; was | lines line */
+ | lines line
+ ;
+
+line: '\n' {}
+ | expr '\n'
+ { if( $1<0 ) {
+ yyerror("Couldn't build node structure: out of memory?");
+ YYERROR; }
+ gParse.resultNode = $1;
+ }
+ | bexpr '\n'
+ { if( $1<0 ) {
+ yyerror("Couldn't build node structure: out of memory?");
+ YYERROR; }
+ gParse.resultNode = $1;
+ }
+ | sexpr '\n'
+ { if( $1<0 ) {
+ yyerror("Couldn't build node structure: out of memory?");
+ YYERROR; }
+ gParse.resultNode = $1;
+ }
+ | bits '\n'
+ { if( $1<0 ) {
+ yyerror("Couldn't build node structure: out of memory?");
+ YYERROR; }
+ gParse.resultNode = $1;
+ }
+ | error '\n' { yyerrok; }
+ ;
+
+bvector: '{' bexpr
+ { $$ = New_Vector( $2 ); TEST($$); }
+ | bvector ',' bexpr
+ {
+ if( gParse.Nodes[$1].nSubNodes >= MAXSUBS ) {
+ $1 = Close_Vec( $1 ); TEST($1);
+ $$ = New_Vector( $1 ); TEST($$);
+ } else {
+ $$ = $1;
+ }
+ gParse.Nodes[$$].SubNodes[ gParse.Nodes[$$].nSubNodes++ ]
+ = $3;
+ }
+ ;
+
+vector: '{' expr
+ { $$ = New_Vector( $2 ); TEST($$); }
+ | vector ',' expr
+ {
+ if( TYPE($1) < TYPE($3) )
+ TYPE($1) = TYPE($3);
+ if( gParse.Nodes[$1].nSubNodes >= MAXSUBS ) {
+ $1 = Close_Vec( $1 ); TEST($1);
+ $$ = New_Vector( $1 ); TEST($$);
+ } else {
+ $$ = $1;
+ }
+ gParse.Nodes[$$].SubNodes[ gParse.Nodes[$$].nSubNodes++ ]
+ = $3;
+ }
+ | vector ',' bexpr
+ {
+ if( gParse.Nodes[$1].nSubNodes >= MAXSUBS ) {
+ $1 = Close_Vec( $1 ); TEST($1);
+ $$ = New_Vector( $1 ); TEST($$);
+ } else {
+ $$ = $1;
+ }
+ gParse.Nodes[$$].SubNodes[ gParse.Nodes[$$].nSubNodes++ ]
+ = $3;
+ }
+ | bvector ',' expr
+ {
+ TYPE($1) = TYPE($3);
+ if( gParse.Nodes[$1].nSubNodes >= MAXSUBS ) {
+ $1 = Close_Vec( $1 ); TEST($1);
+ $$ = New_Vector( $1 ); TEST($$);
+ } else {
+ $$ = $1;
+ }
+ gParse.Nodes[$$].SubNodes[ gParse.Nodes[$$].nSubNodes++ ]
+ = $3;
+ }
+ ;
+
+expr: vector '}'
+ { $$ = Close_Vec( $1 ); TEST($$); }
+ ;
+
+bexpr: bvector '}'
+ { $$ = Close_Vec( $1 ); TEST($$); }
+ ;
+
+bits: BITSTR
+ {
+ $$ = New_Const( BITSTR, $1, strlen($1)+1 ); TEST($$);
+ SIZE($$) = strlen($1);
+ }
+ | BITCOL
+ { $$ = New_Column( $1 ); TEST($$); }
+ | BITCOL '{' expr '}'
+ {
+ if( TYPE($3) != LONG
+ || gParse.Nodes[$3].operation != CONST_OP ) {
+ yyerror("Offset argument must be a constant integer");
+ YYERROR;
+ }
+ $$ = New_Offset( $1, $3 ); TEST($$);
+ }
+ | bits '&' bits
+ { $$ = New_BinOp( BITSTR, $1, '&', $3 ); TEST($$);
+ SIZE($$) = ( SIZE($1)>SIZE($3) ? SIZE($1) : SIZE($3) ); }
+ | bits '|' bits
+ { $$ = New_BinOp( BITSTR, $1, '|', $3 ); TEST($$);
+ SIZE($$) = ( SIZE($1)>SIZE($3) ? SIZE($1) : SIZE($3) ); }
+ | bits '+' bits
+ { $$ = New_BinOp( BITSTR, $1, '+', $3 ); TEST($$);
+ SIZE($$) = SIZE($1) + SIZE($3); }
+ | bits '[' expr ']'
+ { $$ = New_Deref( $1, 1, $3, 0, 0, 0, 0 ); TEST($$); }
+ | bits '[' expr ',' expr ']'
+ { $$ = New_Deref( $1, 2, $3, $5, 0, 0, 0 ); TEST($$); }
+ | bits '[' expr ',' expr ',' expr ']'
+ { $$ = New_Deref( $1, 3, $3, $5, $7, 0, 0 ); TEST($$); }
+ | bits '[' expr ',' expr ',' expr ',' expr ']'
+ { $$ = New_Deref( $1, 4, $3, $5, $7, $9, 0 ); TEST($$); }
+ | bits '[' expr ',' expr ',' expr ',' expr ',' expr ']'
+ { $$ = New_Deref( $1, 5, $3, $5, $7, $9, $11 ); TEST($$); }
+ | NOT bits
+ { $$ = New_Unary( BITSTR, NOT, $2 ); TEST($$); }
+
+ | '(' bits ')'
+ { $$ = $2; }
+ ;
+
+expr: LONG
+ { $$ = New_Const( LONG, &($1), sizeof(long) ); TEST($$); }
+ | DOUBLE
+ { $$ = New_Const( DOUBLE, &($1), sizeof(double) ); TEST($$); }
+ | COLUMN
+ { $$ = New_Column( $1 ); TEST($$); }
+ | COLUMN '{' expr '}'
+ {
+ if( TYPE($3) != LONG
+ || gParse.Nodes[$3].operation != CONST_OP ) {
+ yyerror("Offset argument must be a constant integer");
+ YYERROR;
+ }
+ $$ = New_Offset( $1, $3 ); TEST($$);
+ }
+ | ROWREF
+ { $$ = New_Func( LONG, row_fct, 0, 0, 0, 0, 0, 0, 0, 0 ); }
+ | NULLREF
+ { $$ = New_Func( LONG, null_fct, 0, 0, 0, 0, 0, 0, 0, 0 ); }
+ | expr '%' expr
+ { PROMOTE($1,$3); $$ = New_BinOp( TYPE($1), $1, '%', $3 );
+ TEST($$); }
+ | expr '+' expr
+ { PROMOTE($1,$3); $$ = New_BinOp( TYPE($1), $1, '+', $3 );
+ TEST($$); }
+ | expr '-' expr
+ { PROMOTE($1,$3); $$ = New_BinOp( TYPE($1), $1, '-', $3 );
+ TEST($$); }
+ | expr '*' expr
+ { PROMOTE($1,$3); $$ = New_BinOp( TYPE($1), $1, '*', $3 );
+ TEST($$); }
+ | expr '/' expr
+ { PROMOTE($1,$3); $$ = New_BinOp( TYPE($1), $1, '/', $3 );
+ TEST($$); }
+ | expr POWER expr
+ { PROMOTE($1,$3); $$ = New_BinOp( TYPE($1), $1, POWER, $3 );
+ TEST($$); }
+ | '+' expr %prec UMINUS
+ { $$ = $2; }
+ | '-' expr %prec UMINUS
+ { $$ = New_Unary( TYPE($2), UMINUS, $2 ); TEST($$); }
+ | '(' expr ')'
+ { $$ = $2; }
+ | expr '*' bexpr
+ { $3 = New_Unary( TYPE($1), 0, $3 );
+ $$ = New_BinOp( TYPE($1), $1, '*', $3 );
+ TEST($$); }
+ | bexpr '*' expr
+ { $1 = New_Unary( TYPE($3), 0, $1 );
+ $$ = New_BinOp( TYPE($3), $1, '*', $3 );
+ TEST($$); }
+ | bexpr '?' expr ':' expr
+ {
+ PROMOTE($3,$5);
+ if( ! Test_Dims($3,$5) ) {
+ yyerror("Incompatible dimensions in '?:' arguments");
+ YYERROR;
+ }
+ $$ = New_Func( 0, ifthenelse_fct, 3, $3, $5, $1,
+ 0, 0, 0, 0 );
+ TEST($$);
+ if( SIZE($3)<SIZE($5) ) Copy_Dims($$, $5);
+ TYPE($1) = TYPE($3);
+ if( ! Test_Dims($1,$$) ) {
+ yyerror("Incompatible dimensions in '?:' condition");
+ YYERROR;
+ }
+ TYPE($1) = BOOLEAN;
+ if( SIZE($$)<SIZE($1) ) Copy_Dims($$, $1);
+ }
+ | bexpr '?' bexpr ':' expr
+ {
+ PROMOTE($3,$5);
+ if( ! Test_Dims($3,$5) ) {
+ yyerror("Incompatible dimensions in '?:' arguments");
+ YYERROR;
+ }
+ $$ = New_Func( 0, ifthenelse_fct, 3, $3, $5, $1,
+ 0, 0, 0, 0 );
+ TEST($$);
+ if( SIZE($3)<SIZE($5) ) Copy_Dims($$, $5);
+ TYPE($1) = TYPE($3);
+ if( ! Test_Dims($1,$$) ) {
+ yyerror("Incompatible dimensions in '?:' condition");
+ YYERROR;
+ }
+ TYPE($1) = BOOLEAN;
+ if( SIZE($$)<SIZE($1) ) Copy_Dims($$, $1);
+ }
+ | bexpr '?' expr ':' bexpr
+ {
+ PROMOTE($3,$5);
+ if( ! Test_Dims($3,$5) ) {
+ yyerror("Incompatible dimensions in '?:' arguments");
+ YYERROR;
+ }
+ $$ = New_Func( 0, ifthenelse_fct, 3, $3, $5, $1,
+ 0, 0, 0, 0 );
+ TEST($$);
+ if( SIZE($3)<SIZE($5) ) Copy_Dims($$, $5);
+ TYPE($1) = TYPE($3);
+ if( ! Test_Dims($1,$$) ) {
+ yyerror("Incompatible dimensions in '?:' condition");
+ YYERROR;
+ }
+ TYPE($1) = BOOLEAN;
+ if( SIZE($$)<SIZE($1) ) Copy_Dims($$, $1);
+ }
+ | FUNCTION ')'
+ { if (FSTRCMP($1,"RANDOM(") == 0) {
+ srand( (unsigned int) time(NULL) );
+ $$ = New_Func( DOUBLE, rnd_fct, 0, 0, 0, 0, 0, 0, 0, 0 );
+ } else {
+ yyerror("Function() not supported");
+ YYERROR;
+ }
+ TEST($$);
+ }
+ | FUNCTION bexpr ')'
+ { if (FSTRCMP($1,"SUM(") == 0) {
+ $$ = New_Func( LONG, sum_fct, 1, $2, 0, 0, 0, 0, 0, 0 );
+ } else if (FSTRCMP($1,"NELEM(") == 0) {
+ $$ = New_Const( LONG, &( SIZE($2) ), sizeof(long) );
+ } else if (FSTRCMP($1,"ACCUM(") == 0) {
+ long zero = 0;
+ $$ = New_BinOp( LONG , $2, ACCUM, New_Const( LONG, &zero, sizeof(zero) ));
+ } else {
+ yyerror("Function(bool) not supported");
+ YYERROR;
+ }
+ TEST($$);
+ }
+ | FUNCTION sexpr ')'
+ { if (FSTRCMP($1,"NELEM(") == 0) {
+ $$ = New_Const( LONG, &( SIZE($2) ), sizeof(long) );
+ } else if (FSTRCMP($1,"NVALID(") == 0) {
+ $$ = New_Func( LONG, nonnull_fct, 1, $2,
+ 0, 0, 0, 0, 0, 0 );
+ } else {
+ yyerror("Function(str) not supported");
+ YYERROR;
+ }
+ TEST($$);
+ }
+ | FUNCTION bits ')'
+ { if (FSTRCMP($1,"NELEM(") == 0) {
+ $$ = New_Const( LONG, &( SIZE($2) ), sizeof(long) );
+ } else if (FSTRCMP($1,"NVALID(") == 0) { /* Bit arrays do not have NULL */
+ $$ = New_Const( LONG, &( SIZE($2) ), sizeof(long) );
+ } else if (FSTRCMP($1,"SUM(") == 0) {
+ $$ = New_Func( LONG, sum_fct, 1, $2,
+ 0, 0, 0, 0, 0, 0 );
+ } else if (FSTRCMP($1,"MIN(") == 0) {
+ $$ = New_Func( TYPE($2), /* Force 1D result */
+ min1_fct, 1, $2, 0, 0, 0, 0, 0, 0 );
+ SIZE($$) = 1;
+ } else if (FSTRCMP($1,"ACCUM(") == 0) {
+ long zero = 0;
+ $$ = New_BinOp( LONG , $2, ACCUM, New_Const( LONG, &zero, sizeof(zero) ));
+ } else if (FSTRCMP($1,"MAX(") == 0) {
+ $$ = New_Func( TYPE($2), /* Force 1D result */
+ max1_fct, 1, $2, 0, 0, 0, 0, 0, 0 );
+ SIZE($$) = 1;
+ } else {
+ yyerror("Function(bits) not supported");
+ YYERROR;
+ }
+ TEST($$);
+ }
+ | FUNCTION expr ')'
+ { if (FSTRCMP($1,"SUM(") == 0)
+ $$ = New_Func( TYPE($2), sum_fct, 1, $2,
+ 0, 0, 0, 0, 0, 0 );
+ else if (FSTRCMP($1,"AVERAGE(") == 0)
+ $$ = New_Func( DOUBLE, average_fct, 1, $2,
+ 0, 0, 0, 0, 0, 0 );
+ else if (FSTRCMP($1,"STDDEV(") == 0)
+ $$ = New_Func( DOUBLE, stddev_fct, 1, $2,
+ 0, 0, 0, 0, 0, 0 );
+ else if (FSTRCMP($1,"MEDIAN(") == 0)
+ $$ = New_Func( TYPE($2), median_fct, 1, $2,
+ 0, 0, 0, 0, 0, 0 );
+ else if (FSTRCMP($1,"NELEM(") == 0)
+ $$ = New_Const( LONG, &( SIZE($2) ), sizeof(long) );
+ else if (FSTRCMP($1,"NVALID(") == 0)
+ $$ = New_Func( LONG, nonnull_fct, 1, $2,
+ 0, 0, 0, 0, 0, 0 );
+ else if ((FSTRCMP($1,"ACCUM(") == 0) && (TYPE($2) == LONG)) {
+ long zero = 0;
+ $$ = New_BinOp( LONG , $2, ACCUM, New_Const( LONG, &zero, sizeof(zero) ));
+ } else if ((FSTRCMP($1,"ACCUM(") == 0) && (TYPE($2) == DOUBLE)) {
+ double zero = 0;
+ $$ = New_BinOp( DOUBLE , $2, ACCUM, New_Const( DOUBLE, &zero, sizeof(zero) ));
+ } else if ((FSTRCMP($1,"SEQDIFF(") == 0) && (TYPE($2) == LONG)) {
+ long zero = 0;
+ $$ = New_BinOp( LONG , $2, DIFF, New_Const( LONG, &zero, sizeof(zero) ));
+ } else if ((FSTRCMP($1,"SEQDIFF(") == 0) && (TYPE($2) == DOUBLE)) {
+ double zero = 0;
+ $$ = New_BinOp( DOUBLE , $2, DIFF, New_Const( DOUBLE, &zero, sizeof(zero) ));
+ } else if (FSTRCMP($1,"ABS(") == 0)
+ $$ = New_Func( 0, abs_fct, 1, $2, 0, 0, 0, 0, 0, 0 );
+ else if (FSTRCMP($1,"MIN(") == 0)
+ $$ = New_Func( TYPE($2), /* Force 1D result */
+ min1_fct, 1, $2, 0, 0, 0, 0, 0, 0 );
+ else if (FSTRCMP($1,"MAX(") == 0)
+ $$ = New_Func( TYPE($2), /* Force 1D result */
+ max1_fct, 1, $2, 0, 0, 0, 0, 0, 0 );
+ else { /* These all take DOUBLE arguments */
+ if( TYPE($2) != DOUBLE ) $2 = New_Unary( DOUBLE, 0, $2 );
+ if (FSTRCMP($1,"SIN(") == 0)
+ $$ = New_Func( 0, sin_fct, 1, $2, 0, 0, 0, 0, 0, 0 );
+ else if (FSTRCMP($1,"COS(") == 0)
+ $$ = New_Func( 0, cos_fct, 1, $2, 0, 0, 0, 0, 0, 0 );
+ else if (FSTRCMP($1,"TAN(") == 0)
+ $$ = New_Func( 0, tan_fct, 1, $2, 0, 0, 0, 0, 0, 0 );
+ else if (FSTRCMP($1,"ARCSIN(") == 0
+ || FSTRCMP($1,"ASIN(") == 0)
+ $$ = New_Func( 0, asin_fct, 1, $2, 0, 0, 0, 0, 0, 0 );
+ else if (FSTRCMP($1,"ARCCOS(") == 0
+ || FSTRCMP($1,"ACOS(") == 0)
+ $$ = New_Func( 0, acos_fct, 1, $2, 0, 0, 0, 0, 0, 0 );
+ else if (FSTRCMP($1,"ARCTAN(") == 0
+ || FSTRCMP($1,"ATAN(") == 0)
+ $$ = New_Func( 0, atan_fct, 1, $2, 0, 0, 0, 0, 0, 0 );
+ else if (FSTRCMP($1,"SINH(") == 0)
+ $$ = New_Func( 0, sinh_fct, 1, $2, 0, 0, 0, 0, 0, 0 );
+ else if (FSTRCMP($1,"COSH(") == 0)
+ $$ = New_Func( 0, cosh_fct, 1, $2, 0, 0, 0, 0, 0, 0 );
+ else if (FSTRCMP($1,"TANH(") == 0)
+ $$ = New_Func( 0, tanh_fct, 1, $2, 0, 0, 0, 0, 0, 0 );
+ else if (FSTRCMP($1,"EXP(") == 0)
+ $$ = New_Func( 0, exp_fct, 1, $2, 0, 0, 0, 0, 0, 0 );
+ else if (FSTRCMP($1,"LOG(") == 0)
+ $$ = New_Func( 0, log_fct, 1, $2, 0, 0, 0, 0, 0, 0 );
+ else if (FSTRCMP($1,"LOG10(") == 0)
+ $$ = New_Func( 0, log10_fct, 1, $2, 0, 0, 0, 0, 0, 0 );
+ else if (FSTRCMP($1,"SQRT(") == 0)
+ $$ = New_Func( 0, sqrt_fct, 1, $2, 0, 0, 0, 0, 0, 0 );
+ else if (FSTRCMP($1,"FLOOR(") == 0)
+ $$ = New_Func( 0, floor_fct, 1, $2, 0, 0, 0, 0, 0, 0 );
+ else if (FSTRCMP($1,"CEIL(") == 0)
+ $$ = New_Func( 0, ceil_fct, 1, $2, 0, 0, 0, 0, 0, 0 );
+ else {
+ yyerror("Function(expr) not supported");
+ YYERROR;
+ }
+ }
+ TEST($$);
+ }
+ | FUNCTION expr ',' expr ')'
+ {
+ if (FSTRCMP($1,"DEFNULL(") == 0) {
+ if( SIZE($2)>=SIZE($4) && Test_Dims( $2, $4 ) ) {
+ PROMOTE($2,$4);
+ $$ = New_Func( 0, defnull_fct, 2, $2, $4, 0,
+ 0, 0, 0, 0 );
+ TEST($$);
+ } else {
+ yyerror("Dimensions of DEFNULL arguments "
+ "are not compatible");
+ YYERROR;
+ }
+ } else if (FSTRCMP($1,"ARCTAN2(") == 0) {
+ if( TYPE($2) != DOUBLE ) $2 = New_Unary( DOUBLE, 0, $2 );
+ if( TYPE($4) != DOUBLE ) $4 = New_Unary( DOUBLE, 0, $4 );
+ if( Test_Dims( $2, $4 ) ) {
+ $$ = New_Func( 0, atan2_fct, 2, $2, $4, 0, 0, 0, 0, 0 );
+ TEST($$);
+ if( SIZE($2)<SIZE($4) ) Copy_Dims($$, $4);
+ } else {
+ yyerror("Dimensions of arctan2 arguments "
+ "are not compatible");
+ YYERROR;
+ }
+ } else if (FSTRCMP($1,"MIN(") == 0) {
+ PROMOTE( $2, $4 );
+ if( Test_Dims( $2, $4 ) ) {
+ $$ = New_Func( 0, min2_fct, 2, $2, $4, 0, 0, 0, 0, 0 );
+ TEST($$);
+ if( SIZE($2)<SIZE($4) ) Copy_Dims($$, $4);
+ } else {
+ yyerror("Dimensions of min(a,b) arguments "
+ "are not compatible");
+ YYERROR;
+ }
+ } else if (FSTRCMP($1,"MAX(") == 0) {
+ PROMOTE( $2, $4 );
+ if( Test_Dims( $2, $4 ) ) {
+ $$ = New_Func( 0, max2_fct, 2, $2, $4, 0, 0, 0, 0, 0 );
+ TEST($$);
+ if( SIZE($2)<SIZE($4) ) Copy_Dims($$, $4);
+ } else {
+ yyerror("Dimensions of max(a,b) arguments "
+ "are not compatible");
+ YYERROR;
+ }
+ } else {
+ yyerror("Function(expr,expr) not supported");
+ YYERROR;
+ }
+ }
+ | expr '[' expr ']'
+ { $$ = New_Deref( $1, 1, $3, 0, 0, 0, 0 ); TEST($$); }
+ | expr '[' expr ',' expr ']'
+ { $$ = New_Deref( $1, 2, $3, $5, 0, 0, 0 ); TEST($$); }
+ | expr '[' expr ',' expr ',' expr ']'
+ { $$ = New_Deref( $1, 3, $3, $5, $7, 0, 0 ); TEST($$); }
+ | expr '[' expr ',' expr ',' expr ',' expr ']'
+ { $$ = New_Deref( $1, 4, $3, $5, $7, $9, 0 ); TEST($$); }
+ | expr '[' expr ',' expr ',' expr ',' expr ',' expr ']'
+ { $$ = New_Deref( $1, 5, $3, $5, $7, $9, $11 ); TEST($$); }
+ | INTCAST expr
+ { $$ = New_Unary( LONG, INTCAST, $2 ); TEST($$); }
+ | INTCAST bexpr
+ { $$ = New_Unary( LONG, INTCAST, $2 ); TEST($$); }
+ | FLTCAST expr
+ { $$ = New_Unary( DOUBLE, FLTCAST, $2 ); TEST($$); }
+ | FLTCAST bexpr
+ { $$ = New_Unary( DOUBLE, FLTCAST, $2 ); TEST($$); }
+ ;
+
+bexpr: BOOLEAN
+ { $$ = New_Const( BOOLEAN, &($1), sizeof(char) ); TEST($$); }
+ | BCOLUMN
+ { $$ = New_Column( $1 ); TEST($$); }
+ | BCOLUMN '{' expr '}'
+ {
+ if( TYPE($3) != LONG
+ || gParse.Nodes[$3].operation != CONST_OP ) {
+ yyerror("Offset argument must be a constant integer");
+ YYERROR;
+ }
+ $$ = New_Offset( $1, $3 ); TEST($$);
+ }
+ | bits EQ bits
+ { $$ = New_BinOp( BOOLEAN, $1, EQ, $3 ); TEST($$);
+ SIZE($$) = 1; }
+ | bits NE bits
+ { $$ = New_BinOp( BOOLEAN, $1, NE, $3 ); TEST($$);
+ SIZE($$) = 1; }
+ | bits LT bits
+ { $$ = New_BinOp( BOOLEAN, $1, LT, $3 ); TEST($$);
+ SIZE($$) = 1; }
+ | bits LTE bits
+ { $$ = New_BinOp( BOOLEAN, $1, LTE, $3 ); TEST($$);
+ SIZE($$) = 1; }
+ | bits GT bits
+ { $$ = New_BinOp( BOOLEAN, $1, GT, $3 ); TEST($$);
+ SIZE($$) = 1; }
+ | bits GTE bits
+ { $$ = New_BinOp( BOOLEAN, $1, GTE, $3 ); TEST($$);
+ SIZE($$) = 1; }
+ | expr GT expr
+ { PROMOTE($1,$3); $$ = New_BinOp( BOOLEAN, $1, GT, $3 );
+ TEST($$); }
+ | expr LT expr
+ { PROMOTE($1,$3); $$ = New_BinOp( BOOLEAN, $1, LT, $3 );
+ TEST($$); }
+ | expr GTE expr
+ { PROMOTE($1,$3); $$ = New_BinOp( BOOLEAN, $1, GTE, $3 );
+ TEST($$); }
+ | expr LTE expr
+ { PROMOTE($1,$3); $$ = New_BinOp( BOOLEAN, $1, LTE, $3 );
+ TEST($$); }
+ | expr '~' expr
+ { PROMOTE($1,$3); $$ = New_BinOp( BOOLEAN, $1, '~', $3 );
+ TEST($$); }
+ | expr EQ expr
+ { PROMOTE($1,$3); $$ = New_BinOp( BOOLEAN, $1, EQ, $3 );
+ TEST($$); }
+ | expr NE expr
+ { PROMOTE($1,$3); $$ = New_BinOp( BOOLEAN, $1, NE, $3 );
+ TEST($$); }
+ | sexpr EQ sexpr
+ { $$ = New_BinOp( BOOLEAN, $1, EQ, $3 ); TEST($$);
+ SIZE($$) = 1; }
+ | sexpr NE sexpr
+ { $$ = New_BinOp( BOOLEAN, $1, NE, $3 ); TEST($$);
+ SIZE($$) = 1; }
+ | sexpr GT sexpr
+ { $$ = New_BinOp( BOOLEAN, $1, GT, $3 ); TEST($$);
+ SIZE($$) = 1; }
+ | sexpr GTE sexpr
+ { $$ = New_BinOp( BOOLEAN, $1, GTE, $3 ); TEST($$);
+ SIZE($$) = 1; }
+ | sexpr LT sexpr
+ { $$ = New_BinOp( BOOLEAN, $1, LT, $3 ); TEST($$);
+ SIZE($$) = 1; }
+ | sexpr LTE sexpr
+ { $$ = New_BinOp( BOOLEAN, $1, LTE, $3 ); TEST($$);
+ SIZE($$) = 1; }
+ | bexpr AND bexpr
+ { $$ = New_BinOp( BOOLEAN, $1, AND, $3 ); TEST($$); }
+ | bexpr OR bexpr
+ { $$ = New_BinOp( BOOLEAN, $1, OR, $3 ); TEST($$); }
+ | bexpr EQ bexpr
+ { $$ = New_BinOp( BOOLEAN, $1, EQ, $3 ); TEST($$); }
+ | bexpr NE bexpr
+ { $$ = New_BinOp( BOOLEAN, $1, NE, $3 ); TEST($$); }
+
+ | expr '=' expr ':' expr
+ { PROMOTE($1,$3); PROMOTE($1,$5); PROMOTE($3,$5);
+ $3 = New_BinOp( BOOLEAN, $3, LTE, $1 );
+ $5 = New_BinOp( BOOLEAN, $1, LTE, $5 );
+ $$ = New_BinOp( BOOLEAN, $3, AND, $5 );
+ TEST($$); }
+
+ | bexpr '?' bexpr ':' bexpr
+ {
+ if( ! Test_Dims($3,$5) ) {
+ yyerror("Incompatible dimensions in '?:' arguments");
+ YYERROR;
+ }
+ $$ = New_Func( 0, ifthenelse_fct, 3, $3, $5, $1,
+ 0, 0, 0, 0 );
+ TEST($$);
+ if( SIZE($3)<SIZE($5) ) Copy_Dims($$, $5);
+ if( ! Test_Dims($1,$$) ) {
+ yyerror("Incompatible dimensions in '?:' condition");
+ YYERROR;
+ }
+ if( SIZE($$)<SIZE($1) ) Copy_Dims($$, $1);
+ }
+
+ | BFUNCTION expr ')'
+ {
+ if (FSTRCMP($1,"ISNULL(") == 0) {
+ $$ = New_Func( 0, isnull_fct, 1, $2, 0, 0,
+ 0, 0, 0, 0 );
+ TEST($$);
+ /* Use expression's size, but return BOOLEAN */
+ TYPE($$) = BOOLEAN;
+ } else {
+ yyerror("Boolean Function(expr) not supported");
+ YYERROR;
+ }
+ }
+ | BFUNCTION bexpr ')'
+ {
+ if (FSTRCMP($1,"ISNULL(") == 0) {
+ $$ = New_Func( 0, isnull_fct, 1, $2, 0, 0,
+ 0, 0, 0, 0 );
+ TEST($$);
+ /* Use expression's size, but return BOOLEAN */
+ TYPE($$) = BOOLEAN;
+ } else {
+ yyerror("Boolean Function(expr) not supported");
+ YYERROR;
+ }
+ }
+ | BFUNCTION sexpr ')'
+ {
+ if (FSTRCMP($1,"ISNULL(") == 0) {
+ $$ = New_Func( BOOLEAN, isnull_fct, 1, $2, 0, 0,
+ 0, 0, 0, 0 );
+ TEST($$);
+ } else {
+ yyerror("Boolean Function(expr) not supported");
+ YYERROR;
+ }
+ }
+ | FUNCTION bexpr ',' bexpr ')'
+ {
+ if (FSTRCMP($1,"DEFNULL(") == 0) {
+ if( SIZE($2)>=SIZE($4) && Test_Dims( $2, $4 ) ) {
+ $$ = New_Func( 0, defnull_fct, 2, $2, $4, 0,
+ 0, 0, 0, 0 );
+ TEST($$);
+ } else {
+ yyerror("Dimensions of DEFNULL arguments are not compatible");
+ YYERROR;
+ }
+ } else {
+ yyerror("Boolean Function(expr,expr) not supported");
+ YYERROR;
+ }
+ }
+ | BFUNCTION expr ',' expr ',' expr ')'
+ {
+ if( SIZE($2)>1 || SIZE($4)>1 || SIZE($6)>1 ) {
+ yyerror("Cannot use array as function argument");
+ YYERROR;
+ }
+ if( TYPE($2) != DOUBLE ) $2 = New_Unary( DOUBLE, 0, $2 );
+ if( TYPE($4) != DOUBLE ) $4 = New_Unary( DOUBLE, 0, $4 );
+ if( TYPE($6) != DOUBLE ) $6 = New_Unary( DOUBLE, 0, $6 );
+ if (FSTRCMP($1,"NEAR(") == 0)
+ $$ = New_Func( BOOLEAN, near_fct, 3, $2, $4, $6,
+ 0, 0, 0, 0 );
+ else {
+ yyerror("Boolean Function not supported");
+ YYERROR;
+ }
+ TEST($$);
+ }
+ | BFUNCTION expr ',' expr ',' expr ',' expr ',' expr ')'
+ {
+ if( SIZE($2)>1 || SIZE($4)>1 || SIZE($6)>1 || SIZE($8)>1
+ || SIZE($10)>1 ) {
+ yyerror("Cannot use array as function argument");
+ YYERROR;
+ }
+ if( TYPE($2) != DOUBLE ) $2 = New_Unary( DOUBLE, 0, $2 );
+ if( TYPE($4) != DOUBLE ) $4 = New_Unary( DOUBLE, 0, $4 );
+ if( TYPE($6) != DOUBLE ) $6 = New_Unary( DOUBLE, 0, $6 );
+ if( TYPE($8) != DOUBLE ) $8 = New_Unary( DOUBLE, 0, $8 );
+ if( TYPE($10)!= DOUBLE ) $10= New_Unary( DOUBLE, 0, $10);
+ if (FSTRCMP($1,"CIRCLE(") == 0)
+ $$ = New_Func( BOOLEAN, circle_fct, 5, $2, $4, $6, $8,
+ $10, 0, 0 );
+ else {
+ yyerror("Boolean Function not supported");
+ YYERROR;
+ }
+ TEST($$);
+ }
+ | BFUNCTION expr ',' expr ',' expr ',' expr ',' expr ',' expr ',' expr ')'
+ {
+ if( SIZE($2)>1 || SIZE($4)>1 || SIZE($6)>1 || SIZE($8)>1
+ || SIZE($10)>1 || SIZE($12)>1 || SIZE($14)>1 ) {
+ yyerror("Cannot use array as function argument");
+ YYERROR;
+ }
+ if( TYPE($2) != DOUBLE ) $2 = New_Unary( DOUBLE, 0, $2 );
+ if( TYPE($4) != DOUBLE ) $4 = New_Unary( DOUBLE, 0, $4 );
+ if( TYPE($6) != DOUBLE ) $6 = New_Unary( DOUBLE, 0, $6 );
+ if( TYPE($8) != DOUBLE ) $8 = New_Unary( DOUBLE, 0, $8 );
+ if( TYPE($10)!= DOUBLE ) $10= New_Unary( DOUBLE, 0, $10);
+ if( TYPE($12)!= DOUBLE ) $12= New_Unary( DOUBLE, 0, $12);
+ if( TYPE($14)!= DOUBLE ) $14= New_Unary( DOUBLE, 0, $14);
+ if (FSTRCMP($1,"BOX(") == 0)
+ $$ = New_Func( BOOLEAN, box_fct, 7, $2, $4, $6, $8,
+ $10, $12, $14 );
+ else if (FSTRCMP($1,"ELLIPSE(") == 0)
+ $$ = New_Func( BOOLEAN, elps_fct, 7, $2, $4, $6, $8,
+ $10, $12, $14 );
+ else {
+ yyerror("SAO Image Function not supported");
+ YYERROR;
+ }
+ TEST($$);
+ }
+
+ | GTIFILTER ')'
+ { /* Use defaults for all elements */
+ $$ = New_GTI( "", -99, "*START*", "*STOP*" );
+ TEST($$); }
+ | GTIFILTER STRING ')'
+ { /* Use defaults for all except filename */
+ $$ = New_GTI( $2, -99, "*START*", "*STOP*" );
+ TEST($$); }
+ | GTIFILTER STRING ',' expr ')'
+ { $$ = New_GTI( $2, $4, "*START*", "*STOP*" );
+ TEST($$); }
+ | GTIFILTER STRING ',' expr ',' STRING ',' STRING ')'
+ { $$ = New_GTI( $2, $4, $6, $8 );
+ TEST($$); }
+
+ | REGFILTER STRING ')'
+ { /* Use defaults for all except filename */
+ $$ = New_REG( $2, -99, -99, "" );
+ TEST($$); }
+ | REGFILTER STRING ',' expr ',' expr ')'
+ { $$ = New_REG( $2, $4, $6, "" );
+ TEST($$); }
+ | REGFILTER STRING ',' expr ',' expr ',' STRING ')'
+ { $$ = New_REG( $2, $4, $6, $8 );
+ TEST($$); }
+
+ | bexpr '[' expr ']'
+ { $$ = New_Deref( $1, 1, $3, 0, 0, 0, 0 ); TEST($$); }
+ | bexpr '[' expr ',' expr ']'
+ { $$ = New_Deref( $1, 2, $3, $5, 0, 0, 0 ); TEST($$); }
+ | bexpr '[' expr ',' expr ',' expr ']'
+ { $$ = New_Deref( $1, 3, $3, $5, $7, 0, 0 ); TEST($$); }
+ | bexpr '[' expr ',' expr ',' expr ',' expr ']'
+ { $$ = New_Deref( $1, 4, $3, $5, $7, $9, 0 ); TEST($$); }
+ | bexpr '[' expr ',' expr ',' expr ',' expr ',' expr ']'
+ { $$ = New_Deref( $1, 5, $3, $5, $7, $9, $11 ); TEST($$); }
+ | NOT bexpr
+ { $$ = New_Unary( BOOLEAN, NOT, $2 ); TEST($$); }
+ | '(' bexpr ')'
+ { $$ = $2; }
+ ;
+
+sexpr: STRING
+ { $$ = New_Const( STRING, $1, strlen($1)+1 ); TEST($$);
+ SIZE($$) = strlen($1); }
+ | SCOLUMN
+ { $$ = New_Column( $1 ); TEST($$); }
+ | SCOLUMN '{' expr '}'
+ {
+ if( TYPE($3) != LONG
+ || gParse.Nodes[$3].operation != CONST_OP ) {
+ yyerror("Offset argument must be a constant integer");
+ YYERROR;
+ }
+ $$ = New_Offset( $1, $3 ); TEST($$);
+ }
+ | SNULLREF
+ { $$ = New_Func( STRING, null_fct, 0, 0, 0, 0, 0, 0, 0, 0 ); }
+ | '(' sexpr ')'
+ { $$ = $2; }
+ | sexpr '+' sexpr
+ { $$ = New_BinOp( STRING, $1, '+', $3 ); TEST($$);
+ SIZE($$) = SIZE($1) + SIZE($3); }
+ | bexpr '?' sexpr ':' sexpr
+ {
+ if( SIZE($1)!=1 ) {
+ yyerror("Cannot have a vector string column");
+ YYERROR;
+ }
+ $$ = New_Func( 0, ifthenelse_fct, 3, $3, $5, $1,
+ 0, 0, 0, 0 );
+ TEST($$);
+ if( SIZE($3)<SIZE($5) ) Copy_Dims($$, $5);
+ }
+
+ | FUNCTION sexpr ',' sexpr ')'
+ {
+ if (FSTRCMP($1,"DEFNULL(") == 0) {
+ $$ = New_Func( 0, defnull_fct, 2, $2, $4, 0,
+ 0, 0, 0, 0 );
+ TEST($$);
+ if( SIZE($4)>SIZE($2) ) SIZE($$) = SIZE($4);
+ }
+ }
+ ;
+
+%%
+
+/*************************************************************************/
+/* Start of "New" routines which build the expression Nodal structure */
+/*************************************************************************/
+
+static int Alloc_Node( void )
+{
+ /* Use this for allocation to guarantee *Nodes */
+ Node *newNodePtr; /* survives on failure, making it still valid */
+ /* while working our way out of this error */
+
+ if( gParse.nNodes == gParse.nNodesAlloc ) {
+ if( gParse.Nodes ) {
+ gParse.nNodesAlloc += gParse.nNodesAlloc;
+ newNodePtr = (Node *)realloc( gParse.Nodes,
+ sizeof(Node)*gParse.nNodesAlloc );
+ } else {
+ gParse.nNodesAlloc = 100;
+ newNodePtr = (Node *)malloc ( sizeof(Node)*gParse.nNodesAlloc );
+ }
+
+ if( newNodePtr ) {
+ gParse.Nodes = newNodePtr;
+ } else {
+ gParse.status = MEMORY_ALLOCATION;
+ return( -1 );
+ }
+ }
+
+ return ( gParse.nNodes++ );
+}
+
+static void Free_Last_Node( void )
+{
+ if( gParse.nNodes ) gParse.nNodes--;
+}
+
+static int New_Const( int returnType, void *value, long len )
+{
+ Node *this;
+ int n;
+
+ n = Alloc_Node();
+ if( n>=0 ) {
+ this = gParse.Nodes + n;
+ this->operation = CONST_OP; /* Flag a constant */
+ this->DoOp = NULL;
+ this->nSubNodes = 0;
+ this->type = returnType;
+ memcpy( &(this->value.data), value, len );
+ this->value.undef = NULL;
+ this->value.nelem = 1;
+ this->value.naxis = 1;
+ this->value.naxes[0] = 1;
+ }
+ return(n);
+}
+
+static int New_Column( int ColNum )
+{
+ Node *this;
+ int n, i;
+
+ n = Alloc_Node();
+ if( n>=0 ) {
+ this = gParse.Nodes + n;
+ this->operation = -ColNum;
+ this->DoOp = NULL;
+ this->nSubNodes = 0;
+ this->type = gParse.varData[ColNum].type;
+ this->value.nelem = gParse.varData[ColNum].nelem;
+ this->value.naxis = gParse.varData[ColNum].naxis;
+ for( i=0; i<gParse.varData[ColNum].naxis; i++ )
+ this->value.naxes[i] = gParse.varData[ColNum].naxes[i];
+ }
+ return(n);
+}
+
+static int New_Offset( int ColNum, int offsetNode )
+{
+ Node *this;
+ int n, i, colNode;
+
+ colNode = New_Column( ColNum );
+ if( colNode<0 ) return(-1);
+
+ n = Alloc_Node();
+ if( n>=0 ) {
+ this = gParse.Nodes + n;
+ this->operation = '{';
+ this->DoOp = Do_Offset;
+ this->nSubNodes = 2;
+ this->SubNodes[0] = colNode;
+ this->SubNodes[1] = offsetNode;
+ this->type = gParse.varData[ColNum].type;
+ this->value.nelem = gParse.varData[ColNum].nelem;
+ this->value.naxis = gParse.varData[ColNum].naxis;
+ for( i=0; i<gParse.varData[ColNum].naxis; i++ )
+ this->value.naxes[i] = gParse.varData[ColNum].naxes[i];
+ }
+ return(n);
+}
+
+static int New_Unary( int returnType, int Op, int Node1 )
+{
+ Node *this, *that;
+ int i,n;
+
+ if( Node1<0 ) return(-1);
+ that = gParse.Nodes + Node1;
+
+ if( !Op ) Op = returnType;
+
+ if( (Op==DOUBLE || Op==FLTCAST) && that->type==DOUBLE ) return( Node1 );
+ if( (Op==LONG || Op==INTCAST) && that->type==LONG ) return( Node1 );
+ if( (Op==BOOLEAN ) && that->type==BOOLEAN ) return( Node1 );
+
+ n = Alloc_Node();
+ if( n>=0 ) {
+ this = gParse.Nodes + n;
+ this->operation = Op;
+ this->DoOp = Do_Unary;
+ this->nSubNodes = 1;
+ this->SubNodes[0] = Node1;
+ this->type = returnType;
+
+ that = gParse.Nodes + Node1; /* Reset in case .Nodes mv'd */
+ this->value.nelem = that->value.nelem;
+ this->value.naxis = that->value.naxis;
+ for( i=0; i<that->value.naxis; i++ )
+ this->value.naxes[i] = that->value.naxes[i];
+
+ if( that->operation==CONST_OP ) this->DoOp( this );
+ }
+ return( n );
+}
+
+static int New_BinOp( int returnType, int Node1, int Op, int Node2 )
+{
+ Node *this,*that1,*that2;
+ int n,i,constant;
+
+ if( Node1<0 || Node2<0 ) return(-1);
+
+ n = Alloc_Node();
+ if( n>=0 ) {
+ this = gParse.Nodes + n;
+ this->operation = Op;
+ this->nSubNodes = 2;
+ this->SubNodes[0]= Node1;
+ this->SubNodes[1]= Node2;
+ this->type = returnType;
+
+ that1 = gParse.Nodes + Node1;
+ that2 = gParse.Nodes + Node2;
+ constant = (that1->operation==CONST_OP
+ && that2->operation==CONST_OP);
+ if( that1->type!=STRING && that1->type!=BITSTR )
+ if( !Test_Dims( Node1, Node2 ) ) {
+ Free_Last_Node();
+ yyerror("Array sizes/dims do not match for binary operator");
+ return(-1);
+ }
+ if( that1->value.nelem == 1 ) that1 = that2;
+
+ this->value.nelem = that1->value.nelem;
+ this->value.naxis = that1->value.naxis;
+ for( i=0; i<that1->value.naxis; i++ )
+ this->value.naxes[i] = that1->value.naxes[i];
+
+ if ( Op == ACCUM && that1->type == BITSTR ) {
+ /* ACCUM is rank-reducing on bit strings */
+ this->value.nelem = 1;
+ this->value.naxis = 1;
+ this->value.naxes[0] = 1;
+ }
+
+ /* Both subnodes should be of same time */
+ switch( that1->type ) {
+ case BITSTR: this->DoOp = Do_BinOp_bit; break;
+ case STRING: this->DoOp = Do_BinOp_str; break;
+ case BOOLEAN: this->DoOp = Do_BinOp_log; break;
+ case LONG: this->DoOp = Do_BinOp_lng; break;
+ case DOUBLE: this->DoOp = Do_BinOp_dbl; break;
+ }
+ if( constant ) this->DoOp( this );
+ }
+ return( n );
+}
+
+static int New_Func( int returnType, funcOp Op, int nNodes,
+ int Node1, int Node2, int Node3, int Node4,
+ int Node5, int Node6, int Node7 )
+/* If returnType==0 , use Node1's type and vector sizes as returnType, */
+/* else return a single value of type returnType */
+{
+ Node *this, *that;
+ int i,n,constant;
+
+ if( Node1<0 || Node2<0 || Node3<0 || Node4<0 ||
+ Node5<0 || Node6<0 || Node7<0 ) return(-1);
+
+ n = Alloc_Node();
+ if( n>=0 ) {
+ this = gParse.Nodes + n;
+ this->operation = (int)Op;
+ this->DoOp = Do_Func;
+ this->nSubNodes = nNodes;
+ this->SubNodes[0] = Node1;
+ this->SubNodes[1] = Node2;
+ this->SubNodes[2] = Node3;
+ this->SubNodes[3] = Node4;
+ this->SubNodes[4] = Node5;
+ this->SubNodes[5] = Node6;
+ this->SubNodes[6] = Node7;
+ i = constant = nNodes; /* Functions with zero params are not const */
+ while( i-- )
+ constant = ( constant &&
+ gParse.Nodes[ this->SubNodes[i] ].operation==CONST_OP );
+
+ if( returnType ) {
+ this->type = returnType;
+ this->value.nelem = 1;
+ this->value.naxis = 1;
+ this->value.naxes[0] = 1;
+ } else {
+ that = gParse.Nodes + Node1;
+ this->type = that->type;
+ this->value.nelem = that->value.nelem;
+ this->value.naxis = that->value.naxis;
+ for( i=0; i<that->value.naxis; i++ )
+ this->value.naxes[i] = that->value.naxes[i];
+ }
+ if( constant ) this->DoOp( this );
+ }
+ return( n );
+}
+
+static int New_Deref( int Var, int nDim,
+ int Dim1, int Dim2, int Dim3, int Dim4, int Dim5 )
+{
+ int n, idx, constant;
+ long elem=0;
+ Node *this, *theVar, *theDim[MAXDIMS];
+
+ if( Var<0 || Dim1<0 || Dim2<0 || Dim3<0 || Dim4<0 || Dim5<0 ) return(-1);
+
+ theVar = gParse.Nodes + Var;
+ if( theVar->operation==CONST_OP || theVar->value.nelem==1 ) {
+ yyerror("Cannot index a scalar value");
+ return(-1);
+ }
+
+ n = Alloc_Node();
+ if( n>=0 ) {
+ this = gParse.Nodes + n;
+ this->nSubNodes = nDim+1;
+ theVar = gParse.Nodes + (this->SubNodes[0]=Var);
+ theDim[0] = gParse.Nodes + (this->SubNodes[1]=Dim1);
+ theDim[1] = gParse.Nodes + (this->SubNodes[2]=Dim2);
+ theDim[2] = gParse.Nodes + (this->SubNodes[3]=Dim3);
+ theDim[3] = gParse.Nodes + (this->SubNodes[4]=Dim4);
+ theDim[4] = gParse.Nodes + (this->SubNodes[5]=Dim5);
+ constant = theVar->operation==CONST_OP;
+ for( idx=0; idx<nDim; idx++ )
+ constant = (constant && theDim[idx]->operation==CONST_OP);
+
+ for( idx=0; idx<nDim; idx++ )
+ if( theDim[idx]->value.nelem>1 ) {
+ Free_Last_Node();
+ yyerror("Cannot use an array as an index value");
+ return(-1);
+ } else if( theDim[idx]->type!=LONG ) {
+ Free_Last_Node();
+ yyerror("Index value must be an integer type");
+ return(-1);
+ }
+
+ this->operation = '[';
+ this->DoOp = Do_Deref;
+ this->type = theVar->type;
+
+ if( theVar->value.naxis == nDim ) { /* All dimensions specified */
+ this->value.nelem = 1;
+ this->value.naxis = 1;
+ this->value.naxes[0] = 1;
+ } else if( nDim==1 ) { /* Dereference only one dimension */
+ elem=1;
+ this->value.naxis = theVar->value.naxis-1;
+ for( idx=0; idx<this->value.naxis; idx++ ) {
+ elem *= ( this->value.naxes[idx] = theVar->value.naxes[idx] );
+ }
+ this->value.nelem = elem;
+ } else {
+ Free_Last_Node();
+ yyerror("Must specify just one or all indices for vector");
+ return(-1);
+ }
+ if( constant ) this->DoOp( this );
+ }
+ return(n);
+}
+
+extern int yyGetVariable( char *varName, YYSTYPE *varVal );
+
+static int New_GTI( char *fname, int Node1, char *start, char *stop )
+{
+ fitsfile *fptr;
+ Node *this, *that0, *that1;
+ int type,i,n, startCol, stopCol, Node0;
+ int hdutype, hdunum, evthdu, samefile, extvers, movetotype, tstat;
+ char extname[100];
+ long nrows;
+ double timeZeroI[2], timeZeroF[2], dt, timeSpan;
+ char xcol[20], xexpr[20];
+ YYSTYPE colVal;
+
+ if( Node1==-99 ) {
+ type = yyGetVariable( "TIME", &colVal );
+ if( type==COLUMN ) {
+ Node1 = New_Column( (int)colVal.lng );
+ } else {
+ yyerror("Could not build TIME column for GTIFILTER");
+ return(-1);
+ }
+ }
+ Node1 = New_Unary( DOUBLE, 0, Node1 );
+ Node0 = Alloc_Node(); /* This will hold the START/STOP times */
+ if( Node1<0 || Node0<0 ) return(-1);
+
+ /* Record current HDU number in case we need to move within this file */
+
+ fptr = gParse.def_fptr;
+ ffghdn( fptr, &evthdu );
+
+ /* Look for TIMEZERO keywords in current extension */
+
+ tstat = 0;
+ if( ffgkyd( fptr, "TIMEZERO", timeZeroI, NULL, &tstat ) ) {
+ tstat = 0;
+ if( ffgkyd( fptr, "TIMEZERI", timeZeroI, NULL, &tstat ) ) {
+ timeZeroI[0] = timeZeroF[0] = 0.0;
+ } else if( ffgkyd( fptr, "TIMEZERF", timeZeroF, NULL, &tstat ) ) {
+ timeZeroF[0] = 0.0;
+ }
+ } else {
+ timeZeroF[0] = 0.0;
+ }
+
+ /* Resolve filename parameter */
+
+ switch( fname[0] ) {
+ case '\0':
+ samefile = 1;
+ hdunum = 1;
+ break;
+ case '[':
+ samefile = 1;
+ i = 1;
+ while( fname[i] != '\0' && fname[i] != ']' ) i++;
+ if( fname[i] ) {
+ fname[i] = '\0';
+ fname++;
+ ffexts( fname, &hdunum, extname, &extvers, &movetotype,
+ xcol, xexpr, &gParse.status );
+ if( *extname ) {
+ ffmnhd( fptr, movetotype, extname, extvers, &gParse.status );
+ ffghdn( fptr, &hdunum );
+ } else if( hdunum ) {
+ ffmahd( fptr, ++hdunum, &hdutype, &gParse.status );
+ } else if( !gParse.status ) {
+ yyerror("Cannot use primary array for GTI filter");
+ return( -1 );
+ }
+ } else {
+ yyerror("File extension specifier lacks closing ']'");
+ return( -1 );
+ }
+ break;
+ case '+':
+ samefile = 1;
+ hdunum = atoi( fname ) + 1;
+ if( hdunum>1 )
+ ffmahd( fptr, hdunum, &hdutype, &gParse.status );
+ else {
+ yyerror("Cannot use primary array for GTI filter");
+ return( -1 );
+ }
+ break;
+ default:
+ samefile = 0;
+ if( ! ffopen( &fptr, fname, READONLY, &gParse.status ) )
+ ffghdn( fptr, &hdunum );
+ break;
+ }
+ if( gParse.status ) return(-1);
+
+ /* If at primary, search for GTI extension */
+
+ if( hdunum==1 ) {
+ while( 1 ) {
+ hdunum++;
+ if( ffmahd( fptr, hdunum, &hdutype, &gParse.status ) ) break;
+ if( hdutype==IMAGE_HDU ) continue;
+ tstat = 0;
+ if( ffgkys( fptr, "EXTNAME", extname, NULL, &tstat ) ) continue;
+ ffupch( extname );
+ if( strstr( extname, "GTI" ) ) break;
+ }
+ if( gParse.status ) {
+ if( gParse.status==END_OF_FILE )
+ yyerror("GTI extension not found in this file");
+ return(-1);
+ }
+ }
+
+ /* Locate START/STOP Columns */
+
+ ffgcno( fptr, CASEINSEN, start, &startCol, &gParse.status );
+ ffgcno( fptr, CASEINSEN, stop, &stopCol, &gParse.status );
+ if( gParse.status ) return(-1);
+
+ /* Look for TIMEZERO keywords in GTI extension */
+
+ tstat = 0;
+ if( ffgkyd( fptr, "TIMEZERO", timeZeroI+1, NULL, &tstat ) ) {
+ tstat = 0;
+ if( ffgkyd( fptr, "TIMEZERI", timeZeroI+1, NULL, &tstat ) ) {
+ timeZeroI[1] = timeZeroF[1] = 0.0;
+ } else if( ffgkyd( fptr, "TIMEZERF", timeZeroF+1, NULL, &tstat ) ) {
+ timeZeroF[1] = 0.0;
+ }
+ } else {
+ timeZeroF[1] = 0.0;
+ }
+
+ n = Alloc_Node();
+ if( n >= 0 ) {
+ this = gParse.Nodes + n;
+ this->nSubNodes = 2;
+ this->SubNodes[1] = Node1;
+ this->operation = (int)gtifilt_fct;
+ this->DoOp = Do_GTI;
+ this->type = BOOLEAN;
+ that1 = gParse.Nodes + Node1;
+ this->value.nelem = that1->value.nelem;
+ this->value.naxis = that1->value.naxis;
+ for( i=0; i < that1->value.naxis; i++ )
+ this->value.naxes[i] = that1->value.naxes[i];
+
+ /* Init START/STOP node to be treated as a "constant" */
+
+ this->SubNodes[0] = Node0;
+ that0 = gParse.Nodes + Node0;
+ that0->operation = CONST_OP;
+ that0->DoOp = NULL;
+ that0->value.data.ptr= NULL;
+
+ /* Read in START/STOP times */
+
+ if( ffgkyj( fptr, "NAXIS2", &nrows, NULL, &gParse.status ) )
+ return(-1);
+ that0->value.nelem = nrows;
+ if( nrows ) {
+
+ that0->value.data.dblptr = (double*)malloc( 2*nrows*sizeof(double) );
+ if( !that0->value.data.dblptr ) {
+ gParse.status = MEMORY_ALLOCATION;
+ return(-1);
+ }
+
+ ffgcvd( fptr, startCol, 1L, 1L, nrows, 0.0,
+ that0->value.data.dblptr, &i, &gParse.status );
+ ffgcvd( fptr, stopCol, 1L, 1L, nrows, 0.0,
+ that0->value.data.dblptr+nrows, &i, &gParse.status );
+ if( gParse.status ) {
+ free( that0->value.data.dblptr );
+ return(-1);
+ }
+
+ /* Test for fully time-ordered GTI... both START && STOP */
+
+ that0->type = 1; /* Assume yes */
+ i = nrows;
+ while( --i )
+ if( that0->value.data.dblptr[i-1]
+ >= that0->value.data.dblptr[i]
+ || that0->value.data.dblptr[i-1+nrows]
+ >= that0->value.data.dblptr[i+nrows] ) {
+ that0->type = 0;
+ break;
+ }
+
+ /* Handle TIMEZERO offset, if any */
+
+ dt = (timeZeroI[1] - timeZeroI[0]) + (timeZeroF[1] - timeZeroF[0]);
+ timeSpan = that0->value.data.dblptr[nrows+nrows-1]
+ - that0->value.data.dblptr[0];
+
+ if( fabs( dt / timeSpan ) > 1e-12 ) {
+ for( i=0; i<(nrows+nrows); i++ )
+ that0->value.data.dblptr[i] += dt;
+ }
+ }
+ if( gParse.Nodes[Node1].operation==CONST_OP )
+ this->DoOp( this );
+ }
+
+ if( samefile )
+ ffmahd( fptr, evthdu, &hdutype, &gParse.status );
+ else
+ ffclos( fptr, &gParse.status );
+
+ return( n );
+}
+
+static int New_REG( char *fname, int NodeX, int NodeY, char *colNames )
+{
+ Node *this, *that0;
+ int type, n, Node0;
+ int Xcol, Ycol, tstat;
+ WCSdata wcs;
+ SAORegion *Rgn;
+ char *cX, *cY;
+ YYSTYPE colVal;
+
+ if( NodeX==-99 ) {
+ type = yyGetVariable( "X", &colVal );
+ if( type==COLUMN ) {
+ NodeX = New_Column( (int)colVal.lng );
+ } else {
+ yyerror("Could not build X column for REGFILTER");
+ return(-1);
+ }
+ }
+ if( NodeY==-99 ) {
+ type = yyGetVariable( "Y", &colVal );
+ if( type==COLUMN ) {
+ NodeY = New_Column( (int)colVal.lng );
+ } else {
+ yyerror("Could not build Y column for REGFILTER");
+ return(-1);
+ }
+ }
+ NodeX = New_Unary( DOUBLE, 0, NodeX );
+ NodeY = New_Unary( DOUBLE, 0, NodeY );
+ Node0 = Alloc_Node(); /* This will hold the Region Data */
+ if( NodeX<0 || NodeY<0 || Node0<0 ) return(-1);
+
+ n = Alloc_Node();
+ if( n >= 0 ) {
+ this = gParse.Nodes + n;
+ this->nSubNodes = 3;
+ this->SubNodes[0] = Node0;
+ this->SubNodes[1] = NodeX;
+ this->SubNodes[2] = NodeY;
+ this->operation = (int)regfilt_fct;
+ this->DoOp = Do_REG;
+ this->type = BOOLEAN;
+ this->value.nelem = 1;
+ this->value.naxis = 1;
+ this->value.naxes[0] = 1;
+
+ /* Init Region node to be treated as a "constant" */
+
+ that0 = gParse.Nodes + Node0;
+ that0->operation = CONST_OP;
+ that0->DoOp = NULL;
+
+ /* Identify what columns to use for WCS information */
+
+ Xcol = Ycol = 0;
+ if( *colNames ) {
+ /* Use the column names in this string for WCS info */
+ while( *colNames==' ' ) colNames++;
+ cX = cY = colNames;
+ while( *cY && *cY!=' ' && *cY!=',' ) cY++;
+ if( *cY )
+ *(cY++) = '\0';
+ while( *cY==' ' ) cY++;
+ if( !*cY ) {
+ yyerror("Could not extract valid pair of column names from REGFILTER");
+ Free_Last_Node();
+ return( -1 );
+ }
+ fits_get_colnum( gParse.def_fptr, CASEINSEN, cX, &Xcol,
+ &gParse.status );
+ fits_get_colnum( gParse.def_fptr, CASEINSEN, cY, &Ycol,
+ &gParse.status );
+ if( gParse.status ) {
+ yyerror("Could not locate columns indicated for WCS info");
+ Free_Last_Node();
+ return( -1 );
+ }
+
+ } else {
+ /* Try to find columns used in X/Y expressions */
+ Xcol = Locate_Col( gParse.Nodes + NodeX );
+ Ycol = Locate_Col( gParse.Nodes + NodeY );
+ if( Xcol<0 || Ycol<0 ) {
+ yyerror("Found multiple X/Y column references in REGFILTER");
+ Free_Last_Node();
+ return( -1 );
+ }
+ }
+
+ /* Now, get the WCS info, if it exists, from the indicated columns */
+ wcs.exists = 0;
+ if( Xcol>0 && Ycol>0 ) {
+ tstat = 0;
+ ffgtcs( gParse.def_fptr, Xcol, Ycol,
+ &wcs.xrefval, &wcs.yrefval,
+ &wcs.xrefpix, &wcs.yrefpix,
+ &wcs.xinc, &wcs.yinc,
+ &wcs.rot, wcs.type,
+ &tstat );
+ if( tstat==NO_WCS_KEY ) {
+ wcs.exists = 0;
+ } else if( tstat ) {
+ gParse.status = tstat;
+ Free_Last_Node();
+ return( -1 );
+ } else {
+ wcs.exists = 1;
+ }
+ }
+
+ /* Read in Region file */
+
+ fits_read_rgnfile( fname, &wcs, &Rgn, &gParse.status );
+ if( gParse.status ) {
+ Free_Last_Node();
+ return( -1 );
+ }
+
+ that0->value.data.ptr = Rgn;
+
+ if( gParse.Nodes[NodeX].operation==CONST_OP
+ && gParse.Nodes[NodeY].operation==CONST_OP )
+ this->DoOp( this );
+ }
+
+ return( n );
+}
+
+static int New_Vector( int subNode )
+{
+ Node *this, *that;
+ int n;
+
+ n = Alloc_Node();
+ if( n >= 0 ) {
+ this = gParse.Nodes + n;
+ that = gParse.Nodes + subNode;
+ this->type = that->type;
+ this->nSubNodes = 1;
+ this->SubNodes[0] = subNode;
+ this->operation = '{';
+ this->DoOp = Do_Vector;
+ }
+
+ return( n );
+}
+
+static int Close_Vec( int vecNode )
+{
+ Node *this;
+ int n, nelem=0;
+
+ this = gParse.Nodes + vecNode;
+ for( n=0; n < this->nSubNodes; n++ ) {
+ if( TYPE( this->SubNodes[n] ) != this->type ) {
+ this->SubNodes[n] = New_Unary( this->type, 0, this->SubNodes[n] );
+ if( this->SubNodes[n]<0 ) return(-1);
+ }
+ nelem += SIZE(this->SubNodes[n]);
+ }
+ this->value.naxis = 1;
+ this->value.nelem = nelem;
+ this->value.naxes[0] = nelem;
+
+ return( vecNode );
+}
+
+static int Locate_Col( Node *this )
+/* Locate the TABLE column number of any columns in "this" calculation. */
+/* Return ZERO if none found, or negative if more than 1 found. */
+{
+ Node *that;
+ int i, col=0, newCol, nfound=0;
+
+ if( this->nSubNodes==0
+ && this->operation<=0 && this->operation!=CONST_OP )
+ return gParse.colData[ - this->operation].colnum;
+
+ for( i=0; i<this->nSubNodes; i++ ) {
+ that = gParse.Nodes + this->SubNodes[i];
+ if( that->operation>0 ) {
+ newCol = Locate_Col( that );
+ if( newCol<=0 ) {
+ nfound += -newCol;
+ } else {
+ if( !nfound ) {
+ col = newCol;
+ nfound++;
+ } else if( col != newCol ) {
+ nfound++;
+ }
+ }
+ } else if( that->operation!=CONST_OP ) {
+ /* Found a Column */
+ newCol = gParse.colData[- that->operation].colnum;
+ if( !nfound ) {
+ col = newCol;
+ nfound++;
+ } else if( col != newCol ) {
+ nfound++;
+ }
+ }
+ }
+ if( nfound!=1 )
+ return( - nfound );
+ else
+ return( col );
+}
+
+static int Test_Dims( int Node1, int Node2 )
+{
+ Node *that1, *that2;
+ int valid, i;
+
+ if( Node1<0 || Node2<0 ) return(0);
+
+ that1 = gParse.Nodes + Node1;
+ that2 = gParse.Nodes + Node2;
+
+ if( that1->value.nelem==1 || that2->value.nelem==1 )
+ valid = 1;
+ else if( that1->type==that2->type
+ && that1->value.nelem==that2->value.nelem
+ && that1->value.naxis==that2->value.naxis ) {
+ valid = 1;
+ for( i=0; i<that1->value.naxis; i++ ) {
+ if( that1->value.naxes[i]!=that2->value.naxes[i] )
+ valid = 0;
+ }
+ } else
+ valid = 0;
+ return( valid );
+}
+
+static void Copy_Dims( int Node1, int Node2 )
+{
+ Node *that1, *that2;
+ int i;
+
+ if( Node1<0 || Node2<0 ) return;
+
+ that1 = gParse.Nodes + Node1;
+ that2 = gParse.Nodes + Node2;
+
+ that1->value.nelem = that2->value.nelem;
+ that1->value.naxis = that2->value.naxis;
+ for( i=0; i<that2->value.naxis; i++ )
+ that1->value.naxes[i] = that2->value.naxes[i];
+}
+
+/********************************************************************/
+/* Routines for actually evaluating the expression start here */
+/********************************************************************/
+
+void Evaluate_Parser( long firstRow, long nRows )
+ /***********************************************************************/
+ /* Reset the parser for processing another batch of data... */
+ /* firstRow: Row number of the first element to evaluate */
+ /* nRows: Number of rows to be processed */
+ /* Initialize each COLUMN node so that its UNDEF and DATA pointers */
+ /* point to the appropriate column arrays. */
+ /* Finally, call Evaluate_Node for final node. */
+ /***********************************************************************/
+{
+ int i, column;
+ long offset, rowOffset;
+
+ gParse.firstRow = firstRow;
+ gParse.nRows = nRows;
+
+ /* Reset Column Nodes' pointers to point to right data and UNDEF arrays */
+
+ rowOffset = firstRow - gParse.firstDataRow;
+ for( i=0; i<gParse.nNodes; i++ ) {
+ if( gParse.Nodes[i].operation > 0
+ || gParse.Nodes[i].operation == CONST_OP ) continue;
+
+ column = -gParse.Nodes[i].operation;
+ offset = gParse.varData[column].nelem * rowOffset;
+
+ gParse.Nodes[i].value.undef = gParse.varData[column].undef + offset;
+
+ switch( gParse.Nodes[i].type ) {
+ case BITSTR:
+ gParse.Nodes[i].value.data.strptr =
+ (char**)gParse.varData[column].data + rowOffset;
+ gParse.Nodes[i].value.undef = NULL;
+ break;
+ case STRING:
+ gParse.Nodes[i].value.data.strptr =
+ (char**)gParse.varData[column].data + rowOffset;
+ gParse.Nodes[i].value.undef = gParse.varData[column].undef + rowOffset;
+ break;
+ case BOOLEAN:
+ gParse.Nodes[i].value.data.logptr =
+ (char*)gParse.varData[column].data + offset;
+ break;
+ case LONG:
+ gParse.Nodes[i].value.data.lngptr =
+ (long*)gParse.varData[column].data + offset;
+ break;
+ case DOUBLE:
+ gParse.Nodes[i].value.data.dblptr =
+ (double*)gParse.varData[column].data + offset;
+ break;
+ }
+ }
+
+ Evaluate_Node( gParse.resultNode );
+}
+
+static void Evaluate_Node( int thisNode )
+ /**********************************************************************/
+ /* Recursively evaluate thisNode's subNodes, then call one of the */
+ /* Do_<Action> functions pointed to by thisNode's DoOp element. */
+ /**********************************************************************/
+{
+ Node *this;
+ int i;
+
+ if( gParse.status ) return;
+
+ this = gParse.Nodes + thisNode;
+ if( this->operation>0 ) { /* <=0 indicate constants and columns */
+ i = this->nSubNodes;
+ while( i-- ) {
+ Evaluate_Node( this->SubNodes[i] );
+ if( gParse.status ) return;
+ }
+ this->DoOp( this );
+ }
+}
+
+static void Allocate_Ptrs( Node *this )
+{
+ long elem, row, size;
+
+ if( this->type==BITSTR || this->type==STRING ) {
+
+ this->value.data.strptr = (char**)malloc( gParse.nRows
+ * sizeof(char*) );
+ if( this->value.data.strptr ) {
+ this->value.data.strptr[0] = (char*)malloc( gParse.nRows
+ * (this->value.nelem+2)
+ * sizeof(char) );
+ if( this->value.data.strptr[0] ) {
+ row = 0;
+ while( (++row)<gParse.nRows ) {
+ this->value.data.strptr[row] =
+ this->value.data.strptr[row-1] + this->value.nelem+1;
+ }
+ if( this->type==STRING ) {
+ this->value.undef = this->value.data.strptr[row-1]
+ + this->value.nelem+1;
+ } else {
+ this->value.undef = NULL; /* BITSTRs don't use undef array */
+ }
+ } else {
+ gParse.status = MEMORY_ALLOCATION;
+ free( this->value.data.strptr );
+ }
+ } else {
+ gParse.status = MEMORY_ALLOCATION;
+ }
+
+ } else {
+
+ elem = this->value.nelem * gParse.nRows;
+ switch( this->type ) {
+ case DOUBLE: size = sizeof( double ); break;
+ case LONG: size = sizeof( long ); break;
+ case BOOLEAN: size = sizeof( char ); break;
+ default: size = 1; break;
+ }
+
+ this->value.data.ptr = malloc( elem*(size+1) );
+
+ if( this->value.data.ptr==NULL ) {
+ gParse.status = MEMORY_ALLOCATION;
+ } else {
+ this->value.undef = (char *)this->value.data.ptr + elem*size;
+ }
+ }
+}
+
+static void Do_Unary( Node *this )
+{
+ Node *that;
+ long elem;
+
+ that = gParse.Nodes + this->SubNodes[0];
+
+ if( that->operation==CONST_OP ) { /* Operating on a constant! */
+ switch( this->operation ) {
+ case DOUBLE:
+ case FLTCAST:
+ if( that->type==LONG )
+ this->value.data.dbl = (double)that->value.data.lng;
+ else if( that->type==BOOLEAN )
+ this->value.data.dbl = ( that->value.data.log ? 1.0 : 0.0 );
+ break;
+ case LONG:
+ case INTCAST:
+ if( that->type==DOUBLE )
+ this->value.data.lng = (long)that->value.data.dbl;
+ else if( that->type==BOOLEAN )
+ this->value.data.lng = ( that->value.data.log ? 1L : 0L );
+ break;
+ case BOOLEAN:
+ if( that->type==DOUBLE )
+ this->value.data.log = ( that->value.data.dbl != 0.0 );
+ else if( that->type==LONG )
+ this->value.data.log = ( that->value.data.lng != 0L );
+ break;
+ case UMINUS:
+ if( that->type==DOUBLE )
+ this->value.data.dbl = - that->value.data.dbl;
+ else if( that->type==LONG )
+ this->value.data.lng = - that->value.data.lng;
+ break;
+ case NOT:
+ if( that->type==BOOLEAN )
+ this->value.data.log = ( ! that->value.data.log );
+ else if( that->type==BITSTR )
+ bitnot( this->value.data.str, that->value.data.str );
+ break;
+ }
+ this->operation = CONST_OP;
+
+ } else {
+
+ Allocate_Ptrs( this );
+
+ if( !gParse.status ) {
+
+ if( this->type!=BITSTR ) {
+ elem = gParse.nRows;
+ if( this->type!=STRING )
+ elem *= this->value.nelem;
+ while( elem-- )
+ this->value.undef[elem] = that->value.undef[elem];
+ }
+
+ elem = gParse.nRows * this->value.nelem;
+
+ switch( this->operation ) {
+
+ case BOOLEAN:
+ if( that->type==DOUBLE )
+ while( elem-- )
+ this->value.data.logptr[elem] =
+ ( that->value.data.dblptr[elem] != 0.0 );
+ else if( that->type==LONG )
+ while( elem-- )
+ this->value.data.logptr[elem] =
+ ( that->value.data.lngptr[elem] != 0L );
+ break;
+
+ case DOUBLE:
+ case FLTCAST:
+ if( that->type==LONG )
+ while( elem-- )
+ this->value.data.dblptr[elem] =
+ (double)that->value.data.lngptr[elem];
+ else if( that->type==BOOLEAN )
+ while( elem-- )
+ this->value.data.dblptr[elem] =
+ ( that->value.data.logptr[elem] ? 1.0 : 0.0 );
+ break;
+
+ case LONG:
+ case INTCAST:
+ if( that->type==DOUBLE )
+ while( elem-- )
+ this->value.data.lngptr[elem] =
+ (long)that->value.data.dblptr[elem];
+ else if( that->type==BOOLEAN )
+ while( elem-- )
+ this->value.data.lngptr[elem] =
+ ( that->value.data.logptr[elem] ? 1L : 0L );
+ break;
+
+ case UMINUS:
+ if( that->type==DOUBLE ) {
+ while( elem-- )
+ this->value.data.dblptr[elem] =
+ - that->value.data.dblptr[elem];
+ } else if( that->type==LONG ) {
+ while( elem-- )
+ this->value.data.lngptr[elem] =
+ - that->value.data.lngptr[elem];
+ }
+ break;
+
+ case NOT:
+ if( that->type==BOOLEAN ) {
+ while( elem-- )
+ this->value.data.logptr[elem] =
+ ( ! that->value.data.logptr[elem] );
+ } else if( that->type==BITSTR ) {
+ elem = gParse.nRows;
+ while( elem-- )
+ bitnot( this->value.data.strptr[elem],
+ that->value.data.strptr[elem] );
+ }
+ break;
+ }
+ }
+ }
+
+ if( that->operation>0 ) {
+ free( that->value.data.ptr );
+ }
+}
+
+static void Do_Offset( Node *this )
+{
+ Node *col;
+ long fRow, nRowOverlap, nRowReload, rowOffset;
+ long nelem, elem, offset, nRealElem;
+ int status;
+
+ col = gParse.Nodes + this->SubNodes[0];
+ rowOffset = gParse.Nodes[ this->SubNodes[1] ].value.data.lng;
+
+ Allocate_Ptrs( this );
+
+ fRow = gParse.firstRow + rowOffset;
+ if( this->type==STRING || this->type==BITSTR )
+ nRealElem = 1;
+ else
+ nRealElem = this->value.nelem;
+
+ nelem = nRealElem;
+
+ if( fRow < gParse.firstDataRow ) {
+
+ /* Must fill in data at start of array */
+
+ nRowReload = gParse.firstDataRow - fRow;
+ if( nRowReload > gParse.nRows ) nRowReload = gParse.nRows;
+ nRowOverlap = gParse.nRows - nRowReload;
+
+ offset = 0;
+
+ /* NULLify any values falling out of bounds */
+
+ while( fRow<1 && nRowReload>0 ) {
+ if( this->type == BITSTR ) {
+ nelem = this->value.nelem;
+ this->value.data.strptr[offset][ nelem ] = '\0';
+ while( nelem-- ) this->value.data.strptr[offset][nelem] = '0';
+ offset++;
+ } else {
+ while( nelem-- )
+ this->value.undef[offset++] = 1;
+ }
+ nelem = nRealElem;
+ fRow++;
+ nRowReload--;
+ }
+
+ } else if( fRow + gParse.nRows > gParse.firstDataRow + gParse.nDataRows ) {
+
+ /* Must fill in data at end of array */
+
+ nRowReload = (fRow+gParse.nRows) - (gParse.firstDataRow+gParse.nDataRows);
+ if( nRowReload>gParse.nRows ) {
+ nRowReload = gParse.nRows;
+ } else {
+ fRow = gParse.firstDataRow + gParse.nDataRows;
+ }
+ nRowOverlap = gParse.nRows - nRowReload;
+
+ offset = nRowOverlap * nelem;
+
+ /* NULLify any values falling out of bounds */
+
+ elem = gParse.nRows * nelem;
+ while( fRow+nRowReload>gParse.totalRows && nRowReload>0 ) {
+ if( this->type == BITSTR ) {
+ nelem = this->value.nelem;
+ elem--;
+ this->value.data.strptr[elem][ nelem ] = '\0';
+ while( nelem-- ) this->value.data.strptr[elem][nelem] = '0';
+ } else {
+ while( nelem-- )
+ this->value.undef[--elem] = 1;
+ }
+ nelem = nRealElem;
+ nRowReload--;
+ }
+
+ } else {
+
+ nRowReload = 0;
+ nRowOverlap = gParse.nRows;
+ offset = 0;
+
+ }
+
+ if( nRowReload>0 ) {
+ switch( this->type ) {
+ case BITSTR:
+ case STRING:
+ status = (*gParse.loadData)( -col->operation, fRow, nRowReload,
+ this->value.data.strptr+offset,
+ this->value.undef+offset );
+ break;
+ case BOOLEAN:
+ status = (*gParse.loadData)( -col->operation, fRow, nRowReload,
+ this->value.data.logptr+offset,
+ this->value.undef+offset );
+ break;
+ case LONG:
+ status = (*gParse.loadData)( -col->operation, fRow, nRowReload,
+ this->value.data.lngptr+offset,
+ this->value.undef+offset );
+ break;
+ case DOUBLE:
+ status = (*gParse.loadData)( -col->operation, fRow, nRowReload,
+ this->value.data.dblptr+offset,
+ this->value.undef+offset );
+ break;
+ }
+ }
+
+ /* Now copy over the overlapping region, if any */
+
+ if( nRowOverlap <= 0 ) return;
+
+ if( rowOffset>0 )
+ elem = nRowOverlap * nelem;
+ else
+ elem = gParse.nRows * nelem;
+
+ offset = nelem * rowOffset;
+ while( nRowOverlap-- && !gParse.status ) {
+ while( nelem-- && !gParse.status ) {
+ elem--;
+ if( this->type != BITSTR )
+ this->value.undef[elem] = col->value.undef[elem+offset];
+ switch( this->type ) {
+ case BITSTR:
+ strcpy( this->value.data.strptr[elem ],
+ col->value.data.strptr[elem+offset] );
+ break;
+ case STRING:
+ strcpy( this->value.data.strptr[elem ],
+ col->value.data.strptr[elem+offset] );
+ break;
+ case BOOLEAN:
+ this->value.data.logptr[elem] = col->value.data.logptr[elem+offset];
+ break;
+ case LONG:
+ this->value.data.lngptr[elem] = col->value.data.lngptr[elem+offset];
+ break;
+ case DOUBLE:
+ this->value.data.dblptr[elem] = col->value.data.dblptr[elem+offset];
+ break;
+ }
+ }
+ nelem = nRealElem;
+ }
+}
+
+static void Do_BinOp_bit( Node *this )
+{
+ Node *that1, *that2;
+ char *sptr1=NULL, *sptr2=NULL;
+ int const1, const2;
+ long rows;
+
+ that1 = gParse.Nodes + this->SubNodes[0];
+ that2 = gParse.Nodes + this->SubNodes[1];
+
+ const1 = ( that1->operation==CONST_OP );
+ const2 = ( that2->operation==CONST_OP );
+ sptr1 = ( const1 ? that1->value.data.str : NULL );
+ sptr2 = ( const2 ? that2->value.data.str : NULL );
+
+ if( const1 && const2 ) {
+ switch( this->operation ) {
+ case NE:
+ this->value.data.log = !bitcmp( sptr1, sptr2 );
+ break;
+ case EQ:
+ this->value.data.log = bitcmp( sptr1, sptr2 );
+ break;
+ case GT:
+ case LT:
+ case LTE:
+ case GTE:
+ this->value.data.log = bitlgte( sptr1, this->operation, sptr2 );
+ break;
+ case '|':
+ bitor( this->value.data.str, sptr1, sptr2 );
+ break;
+ case '&':
+ bitand( this->value.data.str, sptr1, sptr2 );
+ break;
+ case '+':
+ strcpy( this->value.data.str, sptr1 );
+ strcat( this->value.data.str, sptr2 );
+ break;
+ case ACCUM:
+ this->value.data.lng = 0;
+ while( *sptr1 ) {
+ if ( *sptr1 == '1' ) this->value.data.lng ++;
+ sptr1 ++;
+ }
+ break;
+
+ }
+ this->operation = CONST_OP;
+
+ } else {
+
+ Allocate_Ptrs( this );
+
+ if( !gParse.status ) {
+ rows = gParse.nRows;
+ switch( this->operation ) {
+
+ /* BITSTR comparisons */
+
+ case NE:
+ case EQ:
+ case GT:
+ case LT:
+ case LTE:
+ case GTE:
+ while( rows-- ) {
+ if( !const1 )
+ sptr1 = that1->value.data.strptr[rows];
+ if( !const2 )
+ sptr2 = that2->value.data.strptr[rows];
+ switch( this->operation ) {
+ case NE: this->value.data.logptr[rows] =
+ !bitcmp( sptr1, sptr2 );
+ break;
+ case EQ: this->value.data.logptr[rows] =
+ bitcmp( sptr1, sptr2 );
+ break;
+ case GT:
+ case LT:
+ case LTE:
+ case GTE: this->value.data.logptr[rows] =
+ bitlgte( sptr1, this->operation, sptr2 );
+ break;
+ }
+ this->value.undef[rows] = 0;
+ }
+ break;
+
+ /* BITSTR AND/ORs ... no UNDEFS in or out */
+
+ case '|':
+ case '&':
+ case '+':
+ while( rows-- ) {
+ if( !const1 )
+ sptr1 = that1->value.data.strptr[rows];
+ if( !const2 )
+ sptr2 = that2->value.data.strptr[rows];
+ if( this->operation=='|' )
+ bitor( this->value.data.strptr[rows], sptr1, sptr2 );
+ else if( this->operation=='&' )
+ bitand( this->value.data.strptr[rows], sptr1, sptr2 );
+ else {
+ strcpy( this->value.data.strptr[rows], sptr1 );
+ strcat( this->value.data.strptr[rows], sptr2 );
+ }
+ }
+ break;
+
+ /* Accumulate 1 bits */
+ case ACCUM:
+ {
+ long i, previous, curr;
+
+ previous = that2->value.data.lng;
+
+ /* Cumulative sum of this chunk */
+ for (i=0; i<rows; i++) {
+ sptr1 = that1->value.data.strptr[i];
+ for (curr = 0; *sptr1; sptr1 ++) {
+ if ( *sptr1 == '1' ) curr ++;
+ }
+ previous += curr;
+ this->value.data.lngptr[i] = previous;
+ this->value.undef[i] = 0;
+ }
+
+ /* Store final cumulant for next pass */
+ that2->value.data.lng = previous;
+ }
+ }
+ }
+ }
+
+ if( that1->operation>0 ) {
+ free( that1->value.data.strptr[0] );
+ free( that1->value.data.strptr );
+ }
+ if( that2->operation>0 ) {
+ free( that2->value.data.strptr[0] );
+ free( that2->value.data.strptr );
+ }
+}
+
+static void Do_BinOp_str( Node *this )
+{
+ Node *that1, *that2;
+ char *sptr1, *sptr2, null1=0, null2=0;
+ int const1, const2, val;
+ long rows;
+
+ that1 = gParse.Nodes + this->SubNodes[0];
+ that2 = gParse.Nodes + this->SubNodes[1];
+
+ const1 = ( that1->operation==CONST_OP );
+ const2 = ( that2->operation==CONST_OP );
+ sptr1 = ( const1 ? that1->value.data.str : NULL );
+ sptr2 = ( const2 ? that2->value.data.str : NULL );
+
+ if( const1 && const2 ) { /* Result is a constant */
+ switch( this->operation ) {
+
+ /* Compare Strings */
+
+ case NE:
+ case EQ:
+ val = ( FSTRCMP( sptr1, sptr2 ) == 0 );
+ this->value.data.log = ( this->operation==EQ ? val : !val );
+ break;
+ case GT:
+ this->value.data.log = ( FSTRCMP( sptr1, sptr2 ) > 0 );
+ break;
+ case LT:
+ this->value.data.log = ( FSTRCMP( sptr1, sptr2 ) < 0 );
+ break;
+ case GTE:
+ this->value.data.log = ( FSTRCMP( sptr1, sptr2 ) >= 0 );
+ break;
+ case LTE:
+ this->value.data.log = ( FSTRCMP( sptr1, sptr2 ) <= 0 );
+ break;
+
+ /* Concat Strings */
+
+ case '+':
+ strcpy( this->value.data.str, sptr1 );
+ strcat( this->value.data.str, sptr2 );
+ break;
+ }
+ this->operation = CONST_OP;
+
+ } else { /* Not a constant */
+
+ Allocate_Ptrs( this );
+
+ if( !gParse.status ) {
+
+ rows = gParse.nRows;
+ switch( this->operation ) {
+
+ /* Compare Strings */
+
+ case NE:
+ case EQ:
+ while( rows-- ) {
+ if( !const1 ) null1 = that1->value.undef[rows];
+ if( !const2 ) null2 = that2->value.undef[rows];
+ this->value.undef[rows] = (null1 || null2);
+ if( ! this->value.undef[rows] ) {
+ if( !const1 ) sptr1 = that1->value.data.strptr[rows];
+ if( !const2 ) sptr2 = that2->value.data.strptr[rows];
+ val = ( FSTRCMP( sptr1, sptr2 ) == 0 );
+ this->value.data.logptr[rows] =
+ ( this->operation==EQ ? val : !val );
+ }
+ }
+ break;
+
+ case GT:
+ case LT:
+ while( rows-- ) {
+ if( !const1 ) null1 = that1->value.undef[rows];
+ if( !const2 ) null2 = that2->value.undef[rows];
+ this->value.undef[rows] = (null1 || null2);
+ if( ! this->value.undef[rows] ) {
+ if( !const1 ) sptr1 = that1->value.data.strptr[rows];
+ if( !const2 ) sptr2 = that2->value.data.strptr[rows];
+ val = ( FSTRCMP( sptr1, sptr2 ) );
+ this->value.data.logptr[rows] =
+ ( this->operation==GT ? val>0 : val<0 );
+ }
+ }
+ break;
+
+ case GTE:
+ case LTE:
+ while( rows-- ) {
+ if( !const1 ) null1 = that1->value.undef[rows];
+ if( !const2 ) null2 = that2->value.undef[rows];
+ this->value.undef[rows] = (null1 || null2);
+ if( ! this->value.undef[rows] ) {
+ if( !const1 ) sptr1 = that1->value.data.strptr[rows];
+ if( !const2 ) sptr2 = that2->value.data.strptr[rows];
+ val = ( FSTRCMP( sptr1, sptr2 ) );
+ this->value.data.logptr[rows] =
+ ( this->operation==GTE ? val>=0 : val<=0 );
+ }
+ }
+ break;
+
+ /* Concat Strings */
+
+ case '+':
+ while( rows-- ) {
+ if( !const1 ) null1 = that1->value.undef[rows];
+ if( !const2 ) null2 = that2->value.undef[rows];
+ this->value.undef[rows] = (null1 || null2);
+ if( ! this->value.undef[rows] ) {
+ if( !const1 ) sptr1 = that1->value.data.strptr[rows];
+ if( !const2 ) sptr2 = that2->value.data.strptr[rows];
+ strcpy( this->value.data.strptr[rows], sptr1 );
+ strcat( this->value.data.strptr[rows], sptr2 );
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ if( that1->operation>0 ) {
+ free( that1->value.data.strptr[0] );
+ free( that1->value.data.strptr );
+ }
+ if( that2->operation>0 ) {
+ free( that2->value.data.strptr[0] );
+ free( that2->value.data.strptr );
+ }
+}
+
+static void Do_BinOp_log( Node *this )
+{
+ Node *that1, *that2;
+ int vector1, vector2;
+ char val1=0, val2=0, null1=0, null2=0;
+ long rows, nelem, elem;
+
+ that1 = gParse.Nodes + this->SubNodes[0];
+ that2 = gParse.Nodes + this->SubNodes[1];
+
+ vector1 = ( that1->operation!=CONST_OP );
+ if( vector1 )
+ vector1 = that1->value.nelem;
+ else {
+ val1 = that1->value.data.log;
+ }
+
+ vector2 = ( that2->operation!=CONST_OP );
+ if( vector2 )
+ vector2 = that2->value.nelem;
+ else {
+ val2 = that2->value.data.log;
+ }
+
+ if( !vector1 && !vector2 ) { /* Result is a constant */
+ switch( this->operation ) {
+ case OR:
+ this->value.data.log = (val1 || val2);
+ break;
+ case AND:
+ this->value.data.log = (val1 && val2);
+ break;
+ case EQ:
+ this->value.data.log = ( (val1 && val2) || (!val1 && !val2) );
+ break;
+ case NE:
+ this->value.data.log = ( (val1 && !val2) || (!val1 && val2) );
+ break;
+ case ACCUM:
+ this->value.data.lng = val1;
+ break;
+ }
+ this->operation=CONST_OP;
+ } else if (this->operation == ACCUM) {
+ long i, previous, curr;
+ rows = gParse.nRows;
+ nelem = this->value.nelem;
+ elem = this->value.nelem * rows;
+
+ Allocate_Ptrs( this );
+
+ if( !gParse.status ) {
+ previous = that2->value.data.lng;
+
+ /* Cumulative sum of this chunk */
+ for (i=0; i<elem; i++) {
+ if (!that1->value.undef[i]) {
+ curr = that1->value.data.logptr[i];
+ previous += curr;
+ }
+ this->value.data.lngptr[i] = previous;
+ this->value.undef[i] = 0;
+ }
+
+ /* Store final cumulant for next pass */
+ that2->value.data.lng = previous;
+ }
+
+ } else {
+ rows = gParse.nRows;
+ nelem = this->value.nelem;
+ elem = this->value.nelem * rows;
+
+ Allocate_Ptrs( this );
+
+ if( !gParse.status ) {
+
+ if (this->operation == ACCUM) {
+ long i, previous, curr;
+
+ previous = that2->value.data.lng;
+
+ /* Cumulative sum of this chunk */
+ for (i=0; i<elem; i++) {
+ if (!that1->value.undef[i]) {
+ curr = that1->value.data.logptr[i];
+ previous += curr;
+ }
+ this->value.data.lngptr[i] = previous;
+ this->value.undef[i] = 0;
+ }
+
+ /* Store final cumulant for next pass */
+ that2->value.data.lng = previous;
+ }
+
+ while( rows-- ) {
+ while( nelem-- ) {
+ elem--;
+
+ if( vector1>1 ) {
+ val1 = that1->value.data.logptr[elem];
+ null1 = that1->value.undef[elem];
+ } else if( vector1 ) {
+ val1 = that1->value.data.logptr[rows];
+ null1 = that1->value.undef[rows];
+ }
+
+ if( vector2>1 ) {
+ val2 = that2->value.data.logptr[elem];
+ null2 = that2->value.undef[elem];
+ } else if( vector2 ) {
+ val2 = that2->value.data.logptr[rows];
+ null2 = that2->value.undef[rows];
+ }
+
+ this->value.undef[elem] = (null1 || null2);
+ switch( this->operation ) {
+
+ case OR:
+ /* This is more complicated than others to suppress UNDEFs */
+ /* in those cases where the other argument is DEF && TRUE */
+
+ if( !null1 && !null2 ) {
+ this->value.data.logptr[elem] = (val1 || val2);
+ } else if( (null1 && !null2 && val2)
+ || ( !null1 && null2 && val1 ) ) {
+ this->value.data.logptr[elem] = 1;
+ this->value.undef[elem] = 0;
+ }
+ break;
+
+ case AND:
+ /* This is more complicated than others to suppress UNDEFs */
+ /* in those cases where the other argument is DEF && FALSE */
+
+ if( !null1 && !null2 ) {
+ this->value.data.logptr[elem] = (val1 && val2);
+ } else if( (null1 && !null2 && !val2)
+ || ( !null1 && null2 && !val1 ) ) {
+ this->value.data.logptr[elem] = 0;
+ this->value.undef[elem] = 0;
+ }
+ break;
+
+ case EQ:
+ this->value.data.logptr[elem] =
+ ( (val1 && val2) || (!val1 && !val2) );
+ break;
+
+ case NE:
+ this->value.data.logptr[elem] =
+ ( (val1 && !val2) || (!val1 && val2) );
+ break;
+ }
+ }
+ nelem = this->value.nelem;
+ }
+ }
+ }
+
+ if( that1->operation>0 ) {
+ free( that1->value.data.ptr );
+ }
+ if( that2->operation>0 ) {
+ free( that2->value.data.ptr );
+ }
+}
+
+static void Do_BinOp_lng( Node *this )
+{
+ Node *that1, *that2;
+ int vector1, vector2;
+ long val1=0, val2=0;
+ char null1=0, null2=0;
+ long rows, nelem, elem;
+
+ that1 = gParse.Nodes + this->SubNodes[0];
+ that2 = gParse.Nodes + this->SubNodes[1];
+
+ vector1 = ( that1->operation!=CONST_OP );
+ if( vector1 )
+ vector1 = that1->value.nelem;
+ else {
+ val1 = that1->value.data.lng;
+ }
+
+ vector2 = ( that2->operation!=CONST_OP );
+ if( vector2 )
+ vector2 = that2->value.nelem;
+ else {
+ val2 = that2->value.data.lng;
+ }
+
+ if( !vector1 && !vector2 ) { /* Result is a constant */
+
+ switch( this->operation ) {
+ case '~': /* Treat as == for LONGS */
+ case EQ: this->value.data.log = (val1 == val2); break;
+ case NE: this->value.data.log = (val1 != val2); break;
+ case GT: this->value.data.log = (val1 > val2); break;
+ case LT: this->value.data.log = (val1 < val2); break;
+ case LTE: this->value.data.log = (val1 <= val2); break;
+ case GTE: this->value.data.log = (val1 >= val2); break;
+
+ case '+': this->value.data.lng = (val1 + val2); break;
+ case '-': this->value.data.lng = (val1 - val2); break;
+ case '*': this->value.data.lng = (val1 * val2); break;
+
+ case '%':
+ if( val2 ) this->value.data.lng = (val1 % val2);
+ else yyerror("Divide by Zero");
+ break;
+ case '/':
+ if( val2 ) this->value.data.lng = (val1 / val2);
+ else yyerror("Divide by Zero");
+ break;
+ case POWER:
+ this->value.data.lng = (long)pow((double)val1,(double)val2);
+ break;
+ case ACCUM:
+ this->value.data.lng = val1;
+ break;
+ case DIFF:
+ this->value.data.lng = 0;
+ break;
+ }
+ this->operation=CONST_OP;
+
+ } else if ((this->operation == ACCUM) || (this->operation == DIFF)) {
+ long i, previous, curr;
+ int undef;
+ rows = gParse.nRows;
+ nelem = this->value.nelem;
+ elem = this->value.nelem * rows;
+
+ Allocate_Ptrs( this );
+
+ if( !gParse.status ) {
+ previous = that2->value.data.lng;
+ undef = (int) that2->value.undef;
+
+ if (this->operation == ACCUM) {
+ /* Cumulative sum of this chunk */
+ for (i=0; i<elem; i++) {
+ if (!that1->value.undef[i]) {
+ curr = that1->value.data.lngptr[i];
+ previous += curr;
+ }
+ this->value.data.lngptr[i] = previous;
+ this->value.undef[i] = 0;
+ }
+ } else {
+ /* Sequential difference for this chunk */
+ for (i=0; i<elem; i++) {
+ curr = that1->value.data.lngptr[i];
+ if (that1->value.undef[i] || undef) {
+ /* Either this, or previous, value was undefined */
+ this->value.data.lngptr[i] = 0;
+ this->value.undef[i] = 1;
+ } else {
+ /* Both defined, we are okay! */
+ this->value.data.lngptr[i] = curr - previous;
+ this->value.undef[i] = 0;
+ }
+
+ previous = curr;
+ undef = that1->value.undef[i];
+ }
+ }
+
+ /* Store final cumulant for next pass */
+ that2->value.data.lng = previous;
+ that2->value.undef = (char *) undef; /* XXX evil, but no harm here */
+ }
+
+ } else {
+
+ rows = gParse.nRows;
+ nelem = this->value.nelem;
+ elem = this->value.nelem * rows;
+
+ Allocate_Ptrs( this );
+
+ while( rows-- && !gParse.status ) {
+ while( nelem-- && !gParse.status ) {
+ elem--;
+
+ if( vector1>1 ) {
+ val1 = that1->value.data.lngptr[elem];
+ null1 = that1->value.undef[elem];
+ } else if( vector1 ) {
+ val1 = that1->value.data.lngptr[rows];
+ null1 = that1->value.undef[rows];
+ }
+
+ if( vector2>1 ) {
+ val2 = that2->value.data.lngptr[elem];
+ null2 = that2->value.undef[elem];
+ } else if( vector2 ) {
+ val2 = that2->value.data.lngptr[rows];
+ null2 = that2->value.undef[rows];
+ }
+
+ this->value.undef[elem] = (null1 || null2);
+ switch( this->operation ) {
+ case '~': /* Treat as == for LONGS */
+ case EQ: this->value.data.logptr[elem] = (val1 == val2); break;
+ case NE: this->value.data.logptr[elem] = (val1 != val2); break;
+ case GT: this->value.data.logptr[elem] = (val1 > val2); break;
+ case LT: this->value.data.logptr[elem] = (val1 < val2); break;
+ case LTE: this->value.data.logptr[elem] = (val1 <= val2); break;
+ case GTE: this->value.data.logptr[elem] = (val1 >= val2); break;
+
+ case '+': this->value.data.lngptr[elem] = (val1 + val2); break;
+ case '-': this->value.data.lngptr[elem] = (val1 - val2); break;
+ case '*': this->value.data.lngptr[elem] = (val1 * val2); break;
+
+ case '%':
+ if( val2 ) this->value.data.lngptr[elem] = (val1 % val2);
+ else {
+ this->value.data.lngptr[elem] = 0;
+ this->value.undef[elem] = 1;
+ }
+ break;
+ case '/':
+ if( val2 ) this->value.data.lngptr[elem] = (val1 / val2);
+ else {
+ this->value.data.lngptr[elem] = 0;
+ this->value.undef[elem] = 1;
+ }
+ break;
+ case POWER:
+ this->value.data.lngptr[elem] = (long)pow((double)val1,(double)val2);
+ break;
+ }
+ }
+ nelem = this->value.nelem;
+ }
+ }
+
+ if( that1->operation>0 ) {
+ free( that1->value.data.ptr );
+ }
+ if( that2->operation>0 ) {
+ free( that2->value.data.ptr );
+ }
+}
+
+static void Do_BinOp_dbl( Node *this )
+{
+ Node *that1, *that2;
+ int vector1, vector2;
+ double val1=0.0, val2=0.0;
+ char null1=0, null2=0;
+ long rows, nelem, elem;
+
+ that1 = gParse.Nodes + this->SubNodes[0];
+ that2 = gParse.Nodes + this->SubNodes[1];
+
+ vector1 = ( that1->operation!=CONST_OP );
+ if( vector1 )
+ vector1 = that1->value.nelem;
+ else {
+ val1 = that1->value.data.dbl;
+ }
+
+ vector2 = ( that2->operation!=CONST_OP );
+ if( vector2 )
+ vector2 = that2->value.nelem;
+ else {
+ val2 = that2->value.data.dbl;
+ }
+
+ if( !vector1 && !vector2 ) { /* Result is a constant */
+
+ switch( this->operation ) {
+ case '~': this->value.data.log = ( fabs(val1-val2) < APPROX ); break;
+ case EQ: this->value.data.log = (val1 == val2); break;
+ case NE: this->value.data.log = (val1 != val2); break;
+ case GT: this->value.data.log = (val1 > val2); break;
+ case LT: this->value.data.log = (val1 < val2); break;
+ case LTE: this->value.data.log = (val1 <= val2); break;
+ case GTE: this->value.data.log = (val1 >= val2); break;
+
+ case '+': this->value.data.dbl = (val1 + val2); break;
+ case '-': this->value.data.dbl = (val1 - val2); break;
+ case '*': this->value.data.dbl = (val1 * val2); break;
+
+ case '%':
+ if( val2 ) this->value.data.dbl = val1 - val2*((int)(val1/val2));
+ else yyerror("Divide by Zero");
+ break;
+ case '/':
+ if( val2 ) this->value.data.dbl = (val1 / val2);
+ else yyerror("Divide by Zero");
+ break;
+ case POWER:
+ this->value.data.dbl = (double)pow(val1,val2);
+ break;
+ case ACCUM:
+ this->value.data.dbl = val1;
+ break;
+ case DIFF:
+ this->value.data.dbl = 0;
+ break;
+ }
+ this->operation=CONST_OP;
+
+ } else if ((this->operation == ACCUM) || (this->operation == DIFF)) {
+ long i;
+ int undef;
+ double previous, curr;
+ rows = gParse.nRows;
+ nelem = this->value.nelem;
+ elem = this->value.nelem * rows;
+
+ Allocate_Ptrs( this );
+
+ if( !gParse.status ) {
+ previous = that2->value.data.dbl;
+ undef = (int) that2->value.undef;
+
+ if (this->operation == ACCUM) {
+ /* Cumulative sum of this chunk */
+ for (i=0; i<elem; i++) {
+ if (!that1->value.undef[i]) {
+ curr = that1->value.data.dblptr[i];
+ previous += curr;
+ }
+ this->value.data.dblptr[i] = previous;
+ this->value.undef[i] = 0;
+ }
+ } else {
+ /* Sequential difference for this chunk */
+ for (i=0; i<elem; i++) {
+ curr = that1->value.data.dblptr[i];
+ if (that1->value.undef[i] || undef) {
+ /* Either this, or previous, value was undefined */
+ this->value.data.dblptr[i] = 0;
+ this->value.undef[i] = 1;
+ } else {
+ /* Both defined, we are okay! */
+ this->value.data.dblptr[i] = curr - previous;
+ this->value.undef[i] = 0;
+ }
+
+ previous = curr;
+ undef = that1->value.undef[i];
+ }
+ }
+
+ /* Store final cumulant for next pass */
+ that2->value.data.dbl = previous;
+ that2->value.undef = (char *) undef; /* XXX evil, but no harm here */
+ }
+
+ } else {
+
+ rows = gParse.nRows;
+ nelem = this->value.nelem;
+ elem = this->value.nelem * rows;
+
+ Allocate_Ptrs( this );
+
+ while( rows-- && !gParse.status ) {
+ while( nelem-- && !gParse.status ) {
+ elem--;
+
+ if( vector1>1 ) {
+ val1 = that1->value.data.dblptr[elem];
+ null1 = that1->value.undef[elem];
+ } else if( vector1 ) {
+ val1 = that1->value.data.dblptr[rows];
+ null1 = that1->value.undef[rows];
+ }
+
+ if( vector2>1 ) {
+ val2 = that2->value.data.dblptr[elem];
+ null2 = that2->value.undef[elem];
+ } else if( vector2 ) {
+ val2 = that2->value.data.dblptr[rows];
+ null2 = that2->value.undef[rows];
+ }
+
+ this->value.undef[elem] = (null1 || null2);
+ switch( this->operation ) {
+ case '~': this->value.data.logptr[elem] =
+ ( fabs(val1-val2) < APPROX ); break;
+ case EQ: this->value.data.logptr[elem] = (val1 == val2); break;
+ case NE: this->value.data.logptr[elem] = (val1 != val2); break;
+ case GT: this->value.data.logptr[elem] = (val1 > val2); break;
+ case LT: this->value.data.logptr[elem] = (val1 < val2); break;
+ case LTE: this->value.data.logptr[elem] = (val1 <= val2); break;
+ case GTE: this->value.data.logptr[elem] = (val1 >= val2); break;
+
+ case '+': this->value.data.dblptr[elem] = (val1 + val2); break;
+ case '-': this->value.data.dblptr[elem] = (val1 - val2); break;
+ case '*': this->value.data.dblptr[elem] = (val1 * val2); break;
+
+ case '%':
+ if( val2 ) this->value.data.dblptr[elem] =
+ val1 - val2*((int)(val1/val2));
+ else {
+ this->value.data.dblptr[elem] = 0.0;
+ this->value.undef[elem] = 1;
+ }
+ break;
+ case '/':
+ if( val2 ) this->value.data.dblptr[elem] = (val1 / val2);
+ else {
+ this->value.data.dblptr[elem] = 0.0;
+ this->value.undef[elem] = 1;
+ }
+ break;
+ case POWER:
+ this->value.data.dblptr[elem] = (double)pow(val1,val2);
+ break;
+ }
+ }
+ nelem = this->value.nelem;
+ }
+ }
+
+ if( that1->operation>0 ) {
+ free( that1->value.data.ptr );
+ }
+ if( that2->operation>0 ) {
+ free( that2->value.data.ptr );
+ }
+}
+
+/*
+ * This Quickselect routine is based on the algorithm described in
+ * "Numerical recipes in C", Second Edition,
+ * Cambridge University Press, 1992, Section 8.5, ISBN 0-521-43108-5
+ * This code by Nicolas Devillard - 1998. Public domain.
+ * http://ndevilla.free.fr/median/median/src/quickselect.c
+ */
+
+#define ELEM_SWAP(a,b) { register long t=(a);(a)=(b);(b)=t; }
+
+/*
+ * qselect_median_lng - select the median value of a long array
+ *
+ * This routine selects the median value of the long integer array
+ * arr[]. If there are an even number of elements, the "lower median"
+ * is selected.
+ *
+ * The array arr[] is scrambled, so users must operate on a scratch
+ * array if they wish the values to be preserved.
+ *
+ * long arr[] - array of values
+ * int n - number of elements in arr
+ *
+ * RETURNS: the lower median value of arr[]
+ *
+ */
+long qselect_median_lng(long arr[], int n)
+{
+ int low, high ;
+ int median;
+ int middle, ll, hh;
+
+ low = 0 ; high = n-1 ; median = (low + high) / 2;
+ for (;;) {
+
+ if (high <= low) { /* One element only */
+ return arr[median];
+ }
+
+ if (high == low + 1) { /* Two elements only */
+ if (arr[low] > arr[high])
+ ELEM_SWAP(arr[low], arr[high]) ;
+ return arr[median];
+ }
+
+ /* Find median of low, middle and high items; swap into position low */
+ middle = (low + high) / 2;
+ if (arr[middle] > arr[high]) ELEM_SWAP(arr[middle], arr[high]) ;
+ if (arr[low] > arr[high]) ELEM_SWAP(arr[low], arr[high]) ;
+ if (arr[middle] > arr[low]) ELEM_SWAP(arr[middle], arr[low]) ;
+
+ /* Swap low item (now in position middle) into position (low+1) */
+ ELEM_SWAP(arr[middle], arr[low+1]) ;
+
+ /* Nibble from each end towards middle, swapping items when stuck */
+ ll = low + 1;
+ hh = high;
+ for (;;) {
+ do ll++; while (arr[low] > arr[ll]) ;
+ do hh--; while (arr[hh] > arr[low]) ;
+
+ if (hh < ll)
+ break;
+
+ ELEM_SWAP(arr[ll], arr[hh]) ;
+ }
+
+ /* Swap middle item (in position low) back into correct position */
+ ELEM_SWAP(arr[low], arr[hh]) ;
+
+ /* Re-set active partition */
+ if (hh <= median)
+ low = ll;
+ if (hh >= median)
+ high = hh - 1;
+ }
+}
+
+#undef ELEM_SWAP
+
+#define ELEM_SWAP(a,b) { register double t=(a);(a)=(b);(b)=t; }
+
+/*
+ * qselect_median_dbl - select the median value of a double array
+ *
+ * This routine selects the median value of the double array
+ * arr[]. If there are an even number of elements, the "lower median"
+ * is selected.
+ *
+ * The array arr[] is scrambled, so users must operate on a scratch
+ * array if they wish the values to be preserved.
+ *
+ * double arr[] - array of values
+ * int n - number of elements in arr
+ *
+ * RETURNS: the lower median value of arr[]
+ *
+ */
+double qselect_median_dbl(double arr[], int n)
+{
+ int low, high ;
+ int median;
+ int middle, ll, hh;
+
+ low = 0 ; high = n-1 ; median = (low + high) / 2;
+ for (;;) {
+ if (high <= low) { /* One element only */
+ return arr[median] ;
+ }
+
+ if (high == low + 1) { /* Two elements only */
+ if (arr[low] > arr[high])
+ ELEM_SWAP(arr[low], arr[high]) ;
+ return arr[median] ;
+ }
+
+ /* Find median of low, middle and high items; swap into position low */
+ middle = (low + high) / 2;
+ if (arr[middle] > arr[high]) ELEM_SWAP(arr[middle], arr[high]) ;
+ if (arr[low] > arr[high]) ELEM_SWAP(arr[low], arr[high]) ;
+ if (arr[middle] > arr[low]) ELEM_SWAP(arr[middle], arr[low]) ;
+
+ /* Swap low item (now in position middle) into position (low+1) */
+ ELEM_SWAP(arr[middle], arr[low+1]) ;
+
+ /* Nibble from each end towards middle, swapping items when stuck */
+ ll = low + 1;
+ hh = high;
+ for (;;) {
+ do ll++; while (arr[low] > arr[ll]) ;
+ do hh--; while (arr[hh] > arr[low]) ;
+
+ if (hh < ll)
+ break;
+
+ ELEM_SWAP(arr[ll], arr[hh]) ;
+ }
+
+ /* Swap middle item (in position low) back into correct position */
+ ELEM_SWAP(arr[low], arr[hh]) ;
+
+ /* Re-set active partition */
+ if (hh <= median)
+ low = ll;
+ if (hh >= median)
+ high = hh - 1;
+ }
+}
+
+#undef ELEM_SWAP
+
+static void Do_Func( Node *this )
+{
+ Node *theParams[MAXSUBS];
+ int vector[MAXSUBS], allConst;
+ lval pVals[MAXSUBS];
+ char pNull[MAXSUBS];
+ long ival;
+ double dval;
+ int i, valInit;
+ long row, elem, nelem;
+ double rndVal;
+
+ i = this->nSubNodes;
+ allConst = 1;
+ while( i-- ) {
+ theParams[i] = gParse.Nodes + this->SubNodes[i];
+ vector[i] = ( theParams[i]->operation!=CONST_OP );
+ if( vector[i] ) {
+ allConst = 0;
+ vector[i] = theParams[i]->value.nelem;
+ } else {
+ if( theParams[i]->type==DOUBLE ) {
+ pVals[i].data.dbl = theParams[i]->value.data.dbl;
+ } else if( theParams[i]->type==LONG ) {
+ pVals[i].data.lng = theParams[i]->value.data.lng;
+ } else if( theParams[i]->type==BOOLEAN ) {
+ pVals[i].data.log = theParams[i]->value.data.log;
+ } else
+ strcpy(pVals[i].data.str, theParams[i]->value.data.str);
+ pNull[i] = 0;
+ }
+ }
+
+ if( this->nSubNodes==0 ) allConst = 0; /* These do produce scalars */
+
+ if( allConst ) {
+
+ switch( this->operation ) {
+
+ /* Non-Trig single-argument functions */
+
+ case sum_fct:
+ if( theParams[0]->type==BOOLEAN )
+ this->value.data.lng = ( pVals[0].data.log ? 1 : 0 );
+ else if( theParams[0]->type==LONG )
+ this->value.data.lng = pVals[0].data.lng;
+ else if( theParams[0]->type==DOUBLE )
+ this->value.data.dbl = pVals[0].data.dbl;
+ else if( theParams[0]->type==BITSTR )
+ strcpy(this->value.data.str, pVals[0].data.str);
+ break;
+ case average_fct:
+ if( theParams[0]->type==LONG )
+ this->value.data.dbl = pVals[0].data.lng;
+ else if( theParams[0]->type==DOUBLE )
+ this->value.data.dbl = pVals[0].data.dbl;
+ break;
+ case stddev_fct:
+ this->value.data.dbl = 0; /* Standard deviation of a constant = 0 */
+ break;
+ case median_fct:
+ if( theParams[0]->type==BOOLEAN )
+ this->value.data.lng = ( pVals[0].data.log ? 1 : 0 );
+ else if( theParams[0]->type==LONG )
+ this->value.data.lng = pVals[0].data.lng;
+ else
+ this->value.data.dbl = pVals[0].data.dbl;
+ break;
+ case abs_fct:
+ if( theParams[0]->type==DOUBLE ) {
+ dval = pVals[0].data.dbl;
+ this->value.data.dbl = (dval>0.0 ? dval : -dval);
+ } else {
+ ival = pVals[0].data.lng;
+ this->value.data.lng = (ival> 0 ? ival : -ival);
+ }
+ break;
+
+ /* Special Null-Handling Functions */
+
+ case nonnull_fct:
+ this->value.data.lng = 1; /* Constants are always 1-element and defined */
+ break;
+ case isnull_fct: /* Constants are always defined */
+ this->value.data.log = 0;
+ break;
+ case defnull_fct:
+ if( this->type==BOOLEAN )
+ this->value.data.log = pVals[0].data.log;
+ else if( this->type==LONG )
+ this->value.data.lng = pVals[0].data.lng;
+ else if( this->type==DOUBLE )
+ this->value.data.dbl = pVals[0].data.dbl;
+ else if( this->type==STRING )
+ strcpy(this->value.data.str,pVals[0].data.str);
+ break;
+
+ /* Math functions with 1 double argument */
+
+ case sin_fct:
+ this->value.data.dbl = sin( pVals[0].data.dbl );
+ break;
+ case cos_fct:
+ this->value.data.dbl = cos( pVals[0].data.dbl );
+ break;
+ case tan_fct:
+ this->value.data.dbl = tan( pVals[0].data.dbl );
+ break;
+ case asin_fct:
+ dval = pVals[0].data.dbl;
+ if( dval<-1.0 || dval>1.0 )
+ yyerror("Out of range argument to arcsin");
+ else
+ this->value.data.dbl = asin( dval );
+ break;
+ case acos_fct:
+ dval = pVals[0].data.dbl;
+ if( dval<-1.0 || dval>1.0 )
+ yyerror("Out of range argument to arccos");
+ else
+ this->value.data.dbl = acos( dval );
+ break;
+ case atan_fct:
+ this->value.data.dbl = atan( pVals[0].data.dbl );
+ break;
+ case sinh_fct:
+ this->value.data.dbl = sinh( pVals[0].data.dbl );
+ break;
+ case cosh_fct:
+ this->value.data.dbl = cosh( pVals[0].data.dbl );
+ break;
+ case tanh_fct:
+ this->value.data.dbl = tanh( pVals[0].data.dbl );
+ break;
+ case exp_fct:
+ this->value.data.dbl = exp( pVals[0].data.dbl );
+ break;
+ case log_fct:
+ dval = pVals[0].data.dbl;
+ if( dval<=0.0 )
+ yyerror("Out of range argument to log");
+ else
+ this->value.data.dbl = log( dval );
+ break;
+ case log10_fct:
+ dval = pVals[0].data.dbl;
+ if( dval<=0.0 )
+ yyerror("Out of range argument to log10");
+ else
+ this->value.data.dbl = log10( dval );
+ break;
+ case sqrt_fct:
+ dval = pVals[0].data.dbl;
+ if( dval<0.0 )
+ yyerror("Out of range argument to sqrt");
+ else
+ this->value.data.dbl = sqrt( dval );
+ break;
+ case ceil_fct:
+ this->value.data.dbl = ceil( pVals[0].data.dbl );
+ break;
+ case floor_fct:
+ this->value.data.dbl = floor( pVals[0].data.dbl );
+ break;
+ case round_fct:
+ this->value.data.dbl = floor( pVals[0].data.dbl + 0.5 );
+ break;
+
+ /* Two-argument Trig Functions */
+
+ case atan2_fct:
+ this->value.data.dbl =
+ atan2( pVals[0].data.dbl, pVals[1].data.dbl );
+ break;
+
+ /* Min/Max functions taking 1 or 2 arguments */
+
+ case min1_fct:
+ /* No constant vectors! */
+ if( this->type == DOUBLE )
+ this->value.data.dbl = pVals[0].data.dbl;
+ else if( this->type == LONG )
+ this->value.data.lng = pVals[0].data.lng;
+ else if( this->type == BITSTR )
+ strcpy(this->value.data.str, pVals[0].data.str);
+ break;
+ case min2_fct:
+ if( this->type == DOUBLE )
+ this->value.data.dbl =
+ minvalue( pVals[0].data.dbl, pVals[1].data.dbl );
+ else if( this->type == LONG )
+ this->value.data.lng =
+ minvalue( pVals[0].data.lng, pVals[1].data.lng );
+ break;
+ case max1_fct:
+ /* No constant vectors! */
+ if( this->type == DOUBLE )
+ this->value.data.dbl = pVals[0].data.dbl;
+ else if( this->type == LONG )
+ this->value.data.lng = pVals[0].data.lng;
+ else if( this->type == BITSTR )
+ strcpy(this->value.data.str, pVals[0].data.str);
+ break;
+ case max2_fct:
+ if( this->type == DOUBLE )
+ this->value.data.dbl =
+ maxvalue( pVals[0].data.dbl, pVals[1].data.dbl );
+ else if( this->type == LONG )
+ this->value.data.lng =
+ maxvalue( pVals[0].data.lng, pVals[1].data.lng );
+ break;
+
+ /* Boolean SAO region Functions... all arguments scalar dbls */
+
+ case near_fct:
+ this->value.data.log = bnear( pVals[0].data.dbl, pVals[1].data.dbl,
+ pVals[2].data.dbl );
+ break;
+ case circle_fct:
+ this->value.data.log = circle( pVals[0].data.dbl, pVals[1].data.dbl,
+ pVals[2].data.dbl, pVals[3].data.dbl,
+ pVals[4].data.dbl );
+ break;
+ case box_fct:
+ this->value.data.log = saobox( pVals[0].data.dbl, pVals[1].data.dbl,
+ pVals[2].data.dbl, pVals[3].data.dbl,
+ pVals[4].data.dbl, pVals[5].data.dbl,
+ pVals[6].data.dbl );
+ break;
+ case elps_fct:
+ this->value.data.log =
+ ellipse( pVals[0].data.dbl, pVals[1].data.dbl,
+ pVals[2].data.dbl, pVals[3].data.dbl,
+ pVals[4].data.dbl, pVals[5].data.dbl,
+ pVals[6].data.dbl );
+ break;
+
+ /* C Conditional expression: bool ? expr : expr */
+
+ case ifthenelse_fct:
+ switch( this->type ) {
+ case BOOLEAN:
+ this->value.data.log = ( pVals[2].data.log ?
+ pVals[0].data.log : pVals[1].data.log );
+ break;
+ case LONG:
+ this->value.data.lng = ( pVals[2].data.log ?
+ pVals[0].data.lng : pVals[1].data.lng );
+ break;
+ case DOUBLE:
+ this->value.data.dbl = ( pVals[2].data.log ?
+ pVals[0].data.dbl : pVals[1].data.dbl );
+ break;
+ case STRING:
+ strcpy(this->value.data.str, ( pVals[2].data.log ?
+ pVals[0].data.str :
+ pVals[1].data.str ) );
+ break;
+ }
+ break;
+
+ }
+ this->operation = CONST_OP;
+
+ } else {
+
+ Allocate_Ptrs( this );
+
+ row = gParse.nRows;
+ elem = row * this->value.nelem;
+
+ if( !gParse.status ) {
+ switch( this->operation ) {
+
+ /* Special functions with no arguments */
+
+ case row_fct:
+ while( row-- ) {
+ this->value.data.lngptr[row] = gParse.firstRow + row;
+ this->value.undef[row] = 0;
+ }
+ break;
+ case null_fct:
+ if( this->type==LONG ) {
+ while( row-- ) {
+ this->value.data.lngptr[row] = 0;
+ this->value.undef[row] = 1;
+ }
+ } else if( this->type==STRING ) {
+ while( row-- ) {
+ this->value.data.strptr[row][0] = '\0';
+ this->value.undef[row] = 1;
+ }
+ }
+ break;
+ case rnd_fct:
+ if( rand()<32768 && rand()<32768 )
+ dval = 32768.0;
+ else
+ dval = 2147483648.0;
+ while( row-- ) {
+ rndVal = (double)rand();
+ while( rndVal > dval ) dval *= 2.0;
+ this->value.data.dblptr[row] = rndVal/dval;
+ this->value.undef[row] = 0;
+ }
+ break;
+
+ /* Non-Trig single-argument functions */
+
+ case sum_fct:
+ elem = row * theParams[0]->value.nelem;
+ if( theParams[0]->type==BOOLEAN ) {
+ while( row-- ) {
+ this->value.data.lngptr[row] = 0;
+ /* Default is UNDEF until a defined value is found */
+ this->value.undef[row] = 1;
+ nelem = theParams[0]->value.nelem;
+ while( nelem-- ) {
+ elem--;
+ if ( ! theParams[0]->value.undef[elem] ) {
+ this->value.data.lngptr[row] +=
+ ( theParams[0]->value.data.logptr[elem] ? 1 : 0 );
+ this->value.undef[row] = 0;
+ }
+ }
+ }
+ } else if( theParams[0]->type==LONG ) {
+ while( row-- ) {
+ this->value.data.lngptr[row] = 0;
+ /* Default is UNDEF until a defined value is found */
+ this->value.undef[row] = 1;
+ nelem = theParams[0]->value.nelem;
+ while( nelem-- ) {
+ elem--;
+ if ( ! theParams[0]->value.undef[elem] ) {
+ this->value.data.lngptr[row] +=
+ theParams[0]->value.data.lngptr[elem];
+ this->value.undef[row] = 0;
+ }
+ }
+ }
+ } else if( theParams[0]->type==DOUBLE ){
+ while( row-- ) {
+ this->value.data.dblptr[row] = 0.0;
+ /* Default is UNDEF until a defined value is found */
+ this->value.undef[row] = 1;
+ nelem = theParams[0]->value.nelem;
+ while( nelem-- ) {
+ elem--;
+ if ( ! theParams[0]->value.undef[elem] ) {
+ this->value.data.dblptr[row] +=
+ theParams[0]->value.data.dblptr[elem];
+ this->value.undef[row] = 0;
+ }
+ }
+ }
+ } else { /* BITSTR */
+ nelem = theParams[0]->value.nelem;
+ while( row-- ) {
+ char *sptr1 = theParams[0]->value.data.strptr[row];
+ this->value.data.lngptr[row] = 0;
+ this->value.undef[row] = 0;
+ while (*sptr1) {
+ if (*sptr1 == '1') this->value.data.lngptr[row] ++;
+ sptr1++;
+ }
+ }
+ }
+ break;
+
+ case average_fct:
+ elem = row * theParams[0]->value.nelem;
+ if( theParams[0]->type==LONG ) {
+ while( row-- ) {
+ int count = 0;
+ this->value.data.dblptr[row] = 0;
+ nelem = theParams[0]->value.nelem;
+ while( nelem-- ) {
+ elem--;
+ if (theParams[0]->value.undef[elem] == 0) {
+ this->value.data.dblptr[row] +=
+ theParams[0]->value.data.lngptr[elem];
+ count ++;
+ }
+ }
+ if (count == 0) {
+ this->value.undef[row] = 1;
+ } else {
+ this->value.undef[row] = 0;
+ this->value.data.dblptr[row] /= count;
+ }
+ }
+ } else if( theParams[0]->type==DOUBLE ){
+ while( row-- ) {
+ int count = 0;
+ this->value.data.dblptr[row] = 0;
+ nelem = theParams[0]->value.nelem;
+ while( nelem-- ) {
+ elem--;
+ if (theParams[0]->value.undef[elem] == 0) {
+ this->value.data.dblptr[row] +=
+ theParams[0]->value.data.dblptr[elem];
+ count ++;
+ }
+ }
+ if (count == 0) {
+ this->value.undef[row] = 1;
+ } else {
+ this->value.undef[row] = 0;
+ this->value.data.dblptr[row] /= count;
+ }
+ }
+ }
+ break;
+ case stddev_fct:
+ elem = row * theParams[0]->value.nelem;
+ if( theParams[0]->type==LONG ) {
+
+ /* Compute the mean value */
+ while( row-- ) {
+ int count = 0;
+ double sum = 0, sum2 = 0;
+
+ nelem = theParams[0]->value.nelem;
+ while( nelem-- ) {
+ elem--;
+ if (theParams[0]->value.undef[elem] == 0) {
+ sum += theParams[0]->value.data.lngptr[elem];
+ count ++;
+ }
+ }
+ if (count > 1) {
+ sum /= count;
+
+ /* Compute the sum of squared deviations */
+ nelem = theParams[0]->value.nelem;
+ elem += nelem; /* Reset elem for second pass */
+ while( nelem-- ) {
+ elem--;
+ if (theParams[0]->value.undef[elem] == 0) {
+ double dx = (theParams[0]->value.data.lngptr[elem] - sum);
+ sum2 += (dx*dx);
+ }
+ }
+
+ sum2 /= (double)count-1;
+
+ this->value.undef[row] = 0;
+ this->value.data.dblptr[row] = sqrt(sum2);
+ } else {
+ this->value.undef[row] = 0; /* STDDEV => 0 */
+ this->value.data.dblptr[row] = 0;
+ }
+ }
+ } else if( theParams[0]->type==DOUBLE ){
+
+ /* Compute the mean value */
+ while( row-- ) {
+ int count = 0;
+ double sum = 0, sum2 = 0;
+
+ nelem = theParams[0]->value.nelem;
+ while( nelem-- ) {
+ elem--;
+ if (theParams[0]->value.undef[elem] == 0) {
+ sum += theParams[0]->value.data.dblptr[elem];
+ count ++;
+ }
+ }
+ if (count > 1) {
+ sum /= count;
+
+ /* Compute the sum of squared deviations */
+ nelem = theParams[0]->value.nelem;
+ elem += nelem; /* Reset elem for second pass */
+ while( nelem-- ) {
+ elem--;
+ if (theParams[0]->value.undef[elem] == 0) {
+ double dx = (theParams[0]->value.data.dblptr[elem] - sum);
+ sum2 += (dx*dx);
+ }
+ }
+
+ sum2 /= (double)count-1;
+
+ this->value.undef[row] = 0;
+ this->value.data.dblptr[row] = sqrt(sum2);
+ } else {
+ this->value.undef[row] = 0; /* STDDEV => 0 */
+ this->value.data.dblptr[row] = 0;
+ }
+ }
+ }
+ break;
+
+ case median_fct:
+ elem = row * theParams[0]->value.nelem;
+ nelem = theParams[0]->value.nelem;
+ if( theParams[0]->type==LONG ) {
+ long *dptr = theParams[0]->value.data.lngptr;
+ char *uptr = theParams[0]->value.undef;
+ long *mptr = (long *) malloc(sizeof(long)*nelem);
+ int irow;
+
+ /* Allocate temporary storage for this row, since the
+ quickselect function will scramble the contents */
+ if (mptr == 0) {
+ yyerror("Could not allocate temporary memory in median function");
+ free( this->value.data.ptr );
+ break;
+ }
+
+ for (irow=0; irow<row; irow++) {
+ long *p = mptr;
+ int nelem1 = nelem;
+ int count = 0;
+
+ while ( nelem1-- ) {
+ if (*uptr == 0) {
+ *p++ = *dptr; /* Only advance the dest pointer if we copied */
+ }
+ dptr ++; /* Advance the source pointer ... */
+ uptr ++; /* ... and source "undef" pointer */
+ }
+
+ nelem1 = (p - mptr); /* Number of accepted data points */
+ if (nelem1 > 0) {
+ this->value.undef[irow] = 0;
+ this->value.data.lngptr[irow] = qselect_median_lng(mptr, nelem1);
+ } else {
+ this->value.undef[irow] = 1;
+ this->value.data.lngptr[irow] = 0;
+ }
+
+ }
+
+ free(mptr);
+ } else {
+ double *dptr = theParams[0]->value.data.dblptr;
+ char *uptr = theParams[0]->value.undef;
+ double *mptr = (double *) malloc(sizeof(double)*nelem);
+ int irow;
+
+ /* Allocate temporary storage for this row, since the
+ quickselect function will scramble the contents */
+ if (mptr == 0) {
+ yyerror("Could not allocate temporary memory in median function");
+ free( this->value.data.ptr );
+ break;
+ }
+
+ for (irow=0; irow<row; irow++) {
+ double *p = mptr;
+ int nelem1 = nelem;
+
+ while ( nelem1-- ) {
+ if (*uptr == 0) {
+ *p++ = *dptr; /* Only advance the dest pointer if we copied */
+ }
+ dptr ++; /* Advance the source pointer ... */
+ uptr ++; /* ... and source "undef" pointer */
+ }
+
+ nelem1 = (p - mptr); /* Number of accepted data points */
+ if (nelem1 > 0) {
+ this->value.undef[irow] = 0;
+ this->value.data.dblptr[irow] = qselect_median_dbl(mptr, nelem1);
+ } else {
+ this->value.undef[irow] = 1;
+ this->value.data.dblptr[irow] = 0;
+ }
+
+ }
+ free(mptr);
+ }
+ break;
+ case abs_fct:
+ if( theParams[0]->type==DOUBLE )
+ while( elem-- ) {
+ dval = theParams[0]->value.data.dblptr[elem];
+ this->value.data.dblptr[elem] = (dval>0.0 ? dval : -dval);
+ this->value.undef[elem] = theParams[0]->value.undef[elem];
+ }
+ else
+ while( elem-- ) {
+ ival = theParams[0]->value.data.lngptr[elem];
+ this->value.data.lngptr[elem] = (ival> 0 ? ival : -ival);
+ this->value.undef[elem] = theParams[0]->value.undef[elem];
+ }
+ break;
+
+ /* Special Null-Handling Functions */
+
+ case nonnull_fct:
+ nelem = theParams[0]->value.nelem;
+ if ( theParams[0]->type==STRING ) nelem = 1;
+ elem = row * nelem;
+ while( row-- ) {
+ int nelem1 = nelem;
+
+ this->value.undef[row] = 0; /* Initialize to 0 (defined) */
+ this->value.data.lngptr[row] = 0;
+ while( nelem1-- ) {
+ elem --;
+ if ( theParams[0]->value.undef[elem] == 0 ) this->value.data.lngptr[row] ++;
+ }
+ }
+ break;
+ case isnull_fct:
+ if( theParams[0]->type==STRING ) elem = row;
+ while( elem-- ) {
+ this->value.data.logptr[elem] = theParams[0]->value.undef[elem];
+ this->value.undef[elem] = 0;
+ }
+ break;
+ case defnull_fct:
+ switch( this->type ) {
+ case BOOLEAN:
+ while( row-- ) {
+ nelem = this->value.nelem;
+ while( nelem-- ) {
+ elem--;
+ i=2; while( i-- )
+ if( vector[i]>1 ) {
+ pNull[i] = theParams[i]->value.undef[elem];
+ pVals[i].data.log =
+ theParams[i]->value.data.logptr[elem];
+ } else if( vector[i] ) {
+ pNull[i] = theParams[i]->value.undef[row];
+ pVals[i].data.log =
+ theParams[i]->value.data.logptr[row];
+ }
+ if( pNull[0] ) {
+ this->value.undef[elem] = pNull[1];
+ this->value.data.logptr[elem] = pVals[1].data.log;
+ } else {
+ this->value.undef[elem] = 0;
+ this->value.data.logptr[elem] = pVals[0].data.log;
+ }
+ }
+ }
+ break;
+ case LONG:
+ while( row-- ) {
+ nelem = this->value.nelem;
+ while( nelem-- ) {
+ elem--;
+ i=2; while( i-- )
+ if( vector[i]>1 ) {
+ pNull[i] = theParams[i]->value.undef[elem];
+ pVals[i].data.lng =
+ theParams[i]->value.data.lngptr[elem];
+ } else if( vector[i] ) {
+ pNull[i] = theParams[i]->value.undef[row];
+ pVals[i].data.lng =
+ theParams[i]->value.data.lngptr[row];
+ }
+ if( pNull[0] ) {
+ this->value.undef[elem] = pNull[1];
+ this->value.data.lngptr[elem] = pVals[1].data.lng;
+ } else {
+ this->value.undef[elem] = 0;
+ this->value.data.lngptr[elem] = pVals[0].data.lng;
+ }
+ }
+ }
+ break;
+ case DOUBLE:
+ while( row-- ) {
+ nelem = this->value.nelem;
+ while( nelem-- ) {
+ elem--;
+ i=2; while( i-- )
+ if( vector[i]>1 ) {
+ pNull[i] = theParams[i]->value.undef[elem];
+ pVals[i].data.dbl =
+ theParams[i]->value.data.dblptr[elem];
+ } else if( vector[i] ) {
+ pNull[i] = theParams[i]->value.undef[row];
+ pVals[i].data.dbl =
+ theParams[i]->value.data.dblptr[row];
+ }
+ if( pNull[0] ) {
+ this->value.undef[elem] = pNull[1];
+ this->value.data.dblptr[elem] = pVals[1].data.dbl;
+ } else {
+ this->value.undef[elem] = 0;
+ this->value.data.dblptr[elem] = pVals[0].data.dbl;
+ }
+ }
+ }
+ break;
+ case STRING:
+ while( row-- ) {
+ i=2; while( i-- )
+ if( vector[i] ) {
+ pNull[i] = theParams[i]->value.undef[row];
+ strcpy(pVals[i].data.str,
+ theParams[i]->value.data.strptr[row]);
+ }
+ if( pNull[0] ) {
+ this->value.undef[row] = pNull[1];
+ strcpy(this->value.data.strptr[row],pVals[1].data.str);
+ } else {
+ this->value.undef[elem] = 0;
+ strcpy(this->value.data.strptr[row],pVals[0].data.str);
+ }
+ }
+ }
+ break;
+
+ /* Math functions with 1 double argument */
+
+ case sin_fct:
+ while( elem-- )
+ if( !(this->value.undef[elem] = theParams[0]->value.undef[elem]) ) {
+ this->value.data.dblptr[elem] =
+ sin( theParams[0]->value.data.dblptr[elem] );
+ }
+ break;
+ case cos_fct:
+ while( elem-- )
+ if( !(this->value.undef[elem] = theParams[0]->value.undef[elem]) ) {
+ this->value.data.dblptr[elem] =
+ cos( theParams[0]->value.data.dblptr[elem] );
+ }
+ break;
+ case tan_fct:
+ while( elem-- )
+ if( !(this->value.undef[elem] = theParams[0]->value.undef[elem]) ) {
+ this->value.data.dblptr[elem] =
+ tan( theParams[0]->value.data.dblptr[elem] );
+ }
+ break;
+ case asin_fct:
+ while( elem-- )
+ if( !(this->value.undef[elem] = theParams[0]->value.undef[elem]) ) {
+ dval = theParams[0]->value.data.dblptr[elem];
+ if( dval<-1.0 || dval>1.0 ) {
+ this->value.data.dblptr[elem] = 0.0;
+ this->value.undef[elem] = 1;
+ } else
+ this->value.data.dblptr[elem] = asin( dval );
+ }
+ break;
+ case acos_fct:
+ while( elem-- )
+ if( !(this->value.undef[elem] = theParams[0]->value.undef[elem]) ) {
+ dval = theParams[0]->value.data.dblptr[elem];
+ if( dval<-1.0 || dval>1.0 ) {
+ this->value.data.dblptr[elem] = 0.0;
+ this->value.undef[elem] = 1;
+ } else
+ this->value.data.dblptr[elem] = acos( dval );
+ }
+ break;
+ case atan_fct:
+ while( elem-- )
+ if( !(this->value.undef[elem] = theParams[0]->value.undef[elem]) ) {
+ dval = theParams[0]->value.data.dblptr[elem];
+ this->value.data.dblptr[elem] = atan( dval );
+ }
+ break;
+ case sinh_fct:
+ while( elem-- )
+ if( !(this->value.undef[elem] = theParams[0]->value.undef[elem]) ) {
+ this->value.data.dblptr[elem] =
+ sinh( theParams[0]->value.data.dblptr[elem] );
+ }
+ break;
+ case cosh_fct:
+ while( elem-- )
+ if( !(this->value.undef[elem] = theParams[0]->value.undef[elem]) ) {
+ this->value.data.dblptr[elem] =
+ cosh( theParams[0]->value.data.dblptr[elem] );
+ }
+ break;
+ case tanh_fct:
+ while( elem-- )
+ if( !(this->value.undef[elem] = theParams[0]->value.undef[elem]) ) {
+ this->value.data.dblptr[elem] =
+ tanh( theParams[0]->value.data.dblptr[elem] );
+ }
+ break;
+ case exp_fct:
+ while( elem-- )
+ if( !(this->value.undef[elem] = theParams[0]->value.undef[elem]) ) {
+ dval = theParams[0]->value.data.dblptr[elem];
+ this->value.data.dblptr[elem] = exp( dval );
+ }
+ break;
+ case log_fct:
+ while( elem-- )
+ if( !(this->value.undef[elem] = theParams[0]->value.undef[elem]) ) {
+ dval = theParams[0]->value.data.dblptr[elem];
+ if( dval<=0.0 ) {
+ this->value.data.dblptr[elem] = 0.0;
+ this->value.undef[elem] = 1;
+ } else
+ this->value.data.dblptr[elem] = log( dval );
+ }
+ break;
+ case log10_fct:
+ while( elem-- )
+ if( !(this->value.undef[elem] = theParams[0]->value.undef[elem]) ) {
+ dval = theParams[0]->value.data.dblptr[elem];
+ if( dval<=0.0 ) {
+ this->value.data.dblptr[elem] = 0.0;
+ this->value.undef[elem] = 1;
+ } else
+ this->value.data.dblptr[elem] = log10( dval );
+ }
+ break;
+ case sqrt_fct:
+ while( elem-- )
+ if( !(this->value.undef[elem] = theParams[0]->value.undef[elem]) ) {
+ dval = theParams[0]->value.data.dblptr[elem];
+ if( dval<0.0 ) {
+ this->value.data.dblptr[elem] = 0.0;
+ this->value.undef[elem] = 1;
+ } else
+ this->value.data.dblptr[elem] = sqrt( dval );
+ }
+ break;
+ case ceil_fct:
+ while( elem-- )
+ if( !(this->value.undef[elem] = theParams[0]->value.undef[elem]) ) {
+ this->value.data.dblptr[elem] =
+ ceil( theParams[0]->value.data.dblptr[elem] );
+ }
+ break;
+ case floor_fct:
+ while( elem-- )
+ if( !(this->value.undef[elem] = theParams[0]->value.undef[elem]) ) {
+ this->value.data.dblptr[elem] =
+ floor( theParams[0]->value.data.dblptr[elem] );
+ }
+ break;
+ case round_fct:
+ while( elem-- )
+ if( !(this->value.undef[elem] = theParams[0]->value.undef[elem]) ) {
+ this->value.data.dblptr[elem] =
+ floor( theParams[0]->value.data.dblptr[elem] + 0.5);
+ }
+ break;
+
+ /* Two-argument Trig Functions */
+
+ case atan2_fct:
+ while( row-- ) {
+ nelem = this->value.nelem;
+ while( nelem-- ) {
+ elem--;
+ i=2; while( i-- )
+ if( vector[i]>1 ) {
+ pVals[i].data.dbl =
+ theParams[i]->value.data.dblptr[elem];
+ pNull[i] = theParams[i]->value.undef[elem];
+ } else if( vector[i] ) {
+ pVals[i].data.dbl =
+ theParams[i]->value.data.dblptr[row];
+ pNull[i] = theParams[i]->value.undef[row];
+ }
+ if( !(this->value.undef[elem] = (pNull[0] || pNull[1]) ) )
+ this->value.data.dblptr[elem] =
+ atan2( pVals[0].data.dbl, pVals[1].data.dbl );
+ }
+ }
+ break;
+
+ /* Min/Max functions taking 1 or 2 arguments */
+
+ case min1_fct:
+ elem = row * theParams[0]->value.nelem;
+ if( this->type==LONG ) {
+ long minVal=0;
+ while( row-- ) {
+ valInit = 1;
+ this->value.undef[row] = 1;
+ nelem = theParams[0]->value.nelem;
+ while( nelem-- ) {
+ elem--;
+ if ( !theParams[0]->value.undef[elem] ) {
+ if ( valInit ) {
+ valInit = 0;
+ minVal = theParams[0]->value.data.lngptr[elem];
+ } else {
+ minVal = minvalue( minVal,
+ theParams[0]->value.data.lngptr[elem] );
+ }
+ this->value.undef[row] = 0;
+ }
+ }
+ this->value.data.lngptr[row] = minVal;
+ }
+ } else if( this->type==DOUBLE ) {
+ double minVal=0.0;
+ while( row-- ) {
+ valInit = 1;
+ this->value.undef[row] = 1;
+ nelem = theParams[0]->value.nelem;
+ while( nelem-- ) {
+ elem--;
+ if ( !theParams[0]->value.undef[elem] ) {
+ if ( valInit ) {
+ valInit = 0;
+ minVal = theParams[0]->value.data.dblptr[elem];
+ } else {
+ minVal = minvalue( minVal,
+ theParams[0]->value.data.dblptr[elem] );
+ }
+ this->value.undef[row] = 0;
+ }
+ }
+ this->value.data.dblptr[row] = minVal;
+ }
+ } else if( this->type==BITSTR ) {
+ char minVal;
+ while( row-- ) {
+ char *sptr1 = theParams[0]->value.data.strptr[row];
+ minVal = '1';
+ while (*sptr1) {
+ if (*sptr1 == '0') minVal = '0';
+ sptr1++;
+ }
+ this->value.data.strptr[row][0] = minVal;
+ this->value.data.strptr[row][1] = 0; /* Null terminate */
+ }
+ }
+ break;
+ case min2_fct:
+ if( this->type==LONG ) {
+ while( row-- ) {
+ nelem = this->value.nelem;
+ while( nelem-- ) {
+ elem--;
+ i=2; while( i-- )
+ if( vector[i]>1 ) {
+ pVals[i].data.lng =
+ theParams[i]->value.data.lngptr[elem];
+ pNull[i] = theParams[i]->value.undef[elem];
+ } else if( vector[i] ) {
+ pVals[i].data.lng =
+ theParams[i]->value.data.lngptr[row];
+ pNull[i] = theParams[i]->value.undef[row];
+ }
+ if( pNull[0] && pNull[1] ) {
+ this->value.undef[elem] = 1;
+ this->value.data.lngptr[elem] = 0;
+ } else if (pNull[0]) {
+ this->value.undef[elem] = 0;
+ this->value.data.lngptr[elem] = pVals[1].data.lng;
+ } else if (pNull[1]) {
+ this->value.undef[elem] = 0;
+ this->value.data.lngptr[elem] = pVals[0].data.lng;
+ } else {
+ this->value.undef[elem] = 0;
+ this->value.data.lngptr[elem] =
+ minvalue( pVals[0].data.lng, pVals[1].data.lng );
+ }
+ }
+ }
+ } else if( this->type==DOUBLE ) {
+ while( row-- ) {
+ nelem = this->value.nelem;
+ while( nelem-- ) {
+ elem--;
+ i=2; while( i-- )
+ if( vector[i]>1 ) {
+ pVals[i].data.dbl =
+ theParams[i]->value.data.dblptr[elem];
+ pNull[i] = theParams[i]->value.undef[elem];
+ } else if( vector[i] ) {
+ pVals[i].data.dbl =
+ theParams[i]->value.data.dblptr[row];
+ pNull[i] = theParams[i]->value.undef[row];
+ }
+ if( pNull[0] && pNull[1] ) {
+ this->value.undef[elem] = 1;
+ this->value.data.dblptr[elem] = 0;
+ } else if (pNull[0]) {
+ this->value.undef[elem] = 0;
+ this->value.data.dblptr[elem] = pVals[1].data.dbl;
+ } else if (pNull[1]) {
+ this->value.undef[elem] = 0;
+ this->value.data.dblptr[elem] = pVals[0].data.dbl;
+ } else {
+ this->value.undef[elem] = 0;
+ this->value.data.dblptr[elem] =
+ minvalue( pVals[0].data.dbl, pVals[1].data.dbl );
+ }
+ }
+ }
+ }
+ break;
+
+ case max1_fct:
+ elem = row * theParams[0]->value.nelem;
+ if( this->type==LONG ) {
+ long maxVal=0;
+ while( row-- ) {
+ valInit = 1;
+ this->value.undef[row] = 1;
+ nelem = theParams[0]->value.nelem;
+ while( nelem-- ) {
+ elem--;
+ if ( !theParams[0]->value.undef[elem] ) {
+ if ( valInit ) {
+ valInit = 0;
+ maxVal = theParams[0]->value.data.lngptr[elem];
+ } else {
+ maxVal = maxvalue( maxVal,
+ theParams[0]->value.data.lngptr[elem] );
+ }
+ this->value.undef[row] = 0;
+ }
+ }
+ this->value.data.lngptr[row] = maxVal;
+ }
+ } else if( this->type==DOUBLE ) {
+ double maxVal=0.0;
+ while( row-- ) {
+ valInit = 1;
+ this->value.undef[row] = 1;
+ nelem = theParams[0]->value.nelem;
+ while( nelem-- ) {
+ elem--;
+ if ( !theParams[0]->value.undef[elem] ) {
+ if ( valInit ) {
+ valInit = 0;
+ maxVal = theParams[0]->value.data.dblptr[elem];
+ } else {
+ maxVal = maxvalue( maxVal,
+ theParams[0]->value.data.dblptr[elem] );
+ }
+ this->value.undef[row] = 0;
+ }
+ }
+ this->value.data.dblptr[row] = maxVal;
+ }
+ } else if( this->type==BITSTR ) {
+ char maxVal;
+ while( row-- ) {
+ char *sptr1 = theParams[0]->value.data.strptr[row];
+ maxVal = '0';
+ while (*sptr1) {
+ if (*sptr1 == '1') maxVal = '1';
+ sptr1++;
+ }
+ this->value.data.strptr[row][0] = maxVal;
+ this->value.data.strptr[row][1] = 0; /* Null terminate */
+ }
+ }
+ break;
+ case max2_fct:
+ if( this->type==LONG ) {
+ while( row-- ) {
+ nelem = this->value.nelem;
+ while( nelem-- ) {
+ elem--;
+ i=2; while( i-- )
+ if( vector[i]>1 ) {
+ pVals[i].data.lng =
+ theParams[i]->value.data.lngptr[elem];
+ pNull[i] = theParams[i]->value.undef[elem];
+ } else if( vector[i] ) {
+ pVals[i].data.lng =
+ theParams[i]->value.data.lngptr[row];
+ pNull[i] = theParams[i]->value.undef[row];
+ }
+ if( pNull[0] && pNull[1] ) {
+ this->value.undef[elem] = 1;
+ this->value.data.lngptr[elem] = 0;
+ } else if (pNull[0]) {
+ this->value.undef[elem] = 0;
+ this->value.data.lngptr[elem] = pVals[1].data.lng;
+ } else if (pNull[1]) {
+ this->value.undef[elem] = 0;
+ this->value.data.lngptr[elem] = pVals[0].data.lng;
+ } else {
+ this->value.undef[elem] = 0;
+ this->value.data.lngptr[elem] =
+ maxvalue( pVals[0].data.lng, pVals[1].data.lng );
+ }
+ }
+ }
+ } else if( this->type==DOUBLE ) {
+ while( row-- ) {
+ nelem = this->value.nelem;
+ while( nelem-- ) {
+ elem--;
+ i=2; while( i-- )
+ if( vector[i]>1 ) {
+ pVals[i].data.dbl =
+ theParams[i]->value.data.dblptr[elem];
+ pNull[i] = theParams[i]->value.undef[elem];
+ } else if( vector[i] ) {
+ pVals[i].data.dbl =
+ theParams[i]->value.data.dblptr[row];
+ pNull[i] = theParams[i]->value.undef[row];
+ }
+ if( pNull[0] && pNull[1] ) {
+ this->value.undef[elem] = 1;
+ this->value.data.dblptr[elem] = 0;
+ } else if (pNull[0]) {
+ this->value.undef[elem] = 0;
+ this->value.data.dblptr[elem] = pVals[1].data.dbl;
+ } else if (pNull[1]) {
+ this->value.undef[elem] = 0;
+ this->value.data.dblptr[elem] = pVals[0].data.dbl;
+ } else {
+ this->value.undef[elem] = 0;
+ this->value.data.dblptr[elem] =
+ maxvalue( pVals[0].data.dbl, pVals[1].data.dbl );
+ }
+ }
+ }
+ }
+ break;
+
+ /* Boolean SAO region Functions... all arguments scalar dbls */
+
+ case near_fct:
+ while( row-- ) {
+ this->value.undef[row] = 0;
+ i=3; while( i-- )
+ if( vector[i] ) {
+ pVals[i].data.dbl = theParams[i]->value.data.dblptr[row];
+ this->value.undef[row] |= theParams[i]->value.undef[row];
+ }
+ if( !(this->value.undef[row]) )
+ this->value.data.logptr[row] =
+ bnear( pVals[0].data.dbl, pVals[1].data.dbl,
+ pVals[2].data.dbl );
+ }
+ break;
+ case circle_fct:
+ while( row-- ) {
+ this->value.undef[row] = 0;
+ i=5; while( i-- )
+ if( vector[i] ) {
+ pVals[i].data.dbl = theParams[i]->value.data.dblptr[row];
+ this->value.undef[row] |= theParams[i]->value.undef[row];
+ }
+ if( !(this->value.undef[row]) )
+ this->value.data.logptr[row] =
+ circle( pVals[0].data.dbl, pVals[1].data.dbl,
+ pVals[2].data.dbl, pVals[3].data.dbl,
+ pVals[4].data.dbl );
+ }
+ break;
+ case box_fct:
+ while( row-- ) {
+ this->value.undef[row] = 0;
+ i=7; while( i-- )
+ if( vector[i] ) {
+ pVals[i].data.dbl = theParams[i]->value.data.dblptr[row];
+ this->value.undef[row] |= theParams[i]->value.undef[row];
+ }
+ if( !(this->value.undef[row]) )
+ this->value.data.logptr[row] =
+ saobox( pVals[0].data.dbl, pVals[1].data.dbl,
+ pVals[2].data.dbl, pVals[3].data.dbl,
+ pVals[4].data.dbl, pVals[5].data.dbl,
+ pVals[6].data.dbl );
+ }
+ break;
+ case elps_fct:
+ while( row-- ) {
+ this->value.undef[row] = 0;
+ i=7; while( i-- )
+ if( vector[i] ) {
+ pVals[i].data.dbl = theParams[i]->value.data.dblptr[row];
+ this->value.undef[row] |= theParams[i]->value.undef[row];
+ }
+ if( !(this->value.undef[row]) )
+ this->value.data.logptr[row] =
+ ellipse( pVals[0].data.dbl, pVals[1].data.dbl,
+ pVals[2].data.dbl, pVals[3].data.dbl,
+ pVals[4].data.dbl, pVals[5].data.dbl,
+ pVals[6].data.dbl );
+ }
+ break;
+
+ /* C Conditional expression: bool ? expr : expr */
+
+ case ifthenelse_fct:
+ switch( this->type ) {
+ case BOOLEAN:
+ while( row-- ) {
+ nelem = this->value.nelem;
+ while( nelem-- ) {
+ elem--;
+ if( vector[2]>1 ) {
+ pVals[2].data.log =
+ theParams[2]->value.data.logptr[elem];
+ pNull[2] = theParams[2]->value.undef[elem];
+ } else if( vector[2] ) {
+ pVals[2].data.log =
+ theParams[2]->value.data.logptr[row];
+ pNull[2] = theParams[2]->value.undef[row];
+ }
+ i=2; while( i-- )
+ if( vector[i]>1 ) {
+ pVals[i].data.log =
+ theParams[i]->value.data.logptr[elem];
+ pNull[i] = theParams[i]->value.undef[elem];
+ } else if( vector[i] ) {
+ pVals[i].data.log =
+ theParams[i]->value.data.logptr[row];
+ pNull[i] = theParams[i]->value.undef[row];
+ }
+ if( !(this->value.undef[elem] = pNull[2]) ) {
+ if( pVals[2].data.log ) {
+ this->value.data.logptr[elem] = pVals[0].data.log;
+ this->value.undef[elem] = pNull[0];
+ } else {
+ this->value.data.logptr[elem] = pVals[1].data.log;
+ this->value.undef[elem] = pNull[1];
+ }
+ }
+ }
+ }
+ break;
+ case LONG:
+ while( row-- ) {
+ nelem = this->value.nelem;
+ while( nelem-- ) {
+ elem--;
+ if( vector[2]>1 ) {
+ pVals[2].data.log =
+ theParams[2]->value.data.logptr[elem];
+ pNull[2] = theParams[2]->value.undef[elem];
+ } else if( vector[2] ) {
+ pVals[2].data.log =
+ theParams[2]->value.data.logptr[row];
+ pNull[2] = theParams[2]->value.undef[row];
+ }
+ i=2; while( i-- )
+ if( vector[i]>1 ) {
+ pVals[i].data.lng =
+ theParams[i]->value.data.lngptr[elem];
+ pNull[i] = theParams[i]->value.undef[elem];
+ } else if( vector[i] ) {
+ pVals[i].data.lng =
+ theParams[i]->value.data.lngptr[row];
+ pNull[i] = theParams[i]->value.undef[row];
+ }
+ if( !(this->value.undef[elem] = pNull[2]) ) {
+ if( pVals[2].data.log ) {
+ this->value.data.lngptr[elem] = pVals[0].data.lng;
+ this->value.undef[elem] = pNull[0];
+ } else {
+ this->value.data.lngptr[elem] = pVals[1].data.lng;
+ this->value.undef[elem] = pNull[1];
+ }
+ }
+ }
+ }
+ break;
+ case DOUBLE:
+ while( row-- ) {
+ nelem = this->value.nelem;
+ while( nelem-- ) {
+ elem--;
+ if( vector[2]>1 ) {
+ pVals[2].data.log =
+ theParams[2]->value.data.logptr[elem];
+ pNull[2] = theParams[2]->value.undef[elem];
+ } else if( vector[2] ) {
+ pVals[2].data.log =
+ theParams[2]->value.data.logptr[row];
+ pNull[2] = theParams[2]->value.undef[row];
+ }
+ i=2; while( i-- )
+ if( vector[i]>1 ) {
+ pVals[i].data.dbl =
+ theParams[i]->value.data.dblptr[elem];
+ pNull[i] = theParams[i]->value.undef[elem];
+ } else if( vector[i] ) {
+ pVals[i].data.dbl =
+ theParams[i]->value.data.dblptr[row];
+ pNull[i] = theParams[i]->value.undef[row];
+ }
+ if( !(this->value.undef[elem] = pNull[2]) ) {
+ if( pVals[2].data.log ) {
+ this->value.data.dblptr[elem] = pVals[0].data.dbl;
+ this->value.undef[elem] = pNull[0];
+ } else {
+ this->value.data.dblptr[elem] = pVals[1].data.dbl;
+ this->value.undef[elem] = pNull[1];
+ }
+ }
+ }
+ }
+ break;
+ case STRING:
+ while( row-- ) {
+ if( vector[2] ) {
+ pVals[2].data.log = theParams[2]->value.data.logptr[row];
+ pNull[2] = theParams[2]->value.undef[row];
+ }
+ i=2; while( i-- )
+ if( vector[i] ) {
+ strcpy( pVals[i].data.str,
+ theParams[i]->value.data.strptr[row] );
+ pNull[i] = theParams[i]->value.undef[row];
+ }
+ if( !(this->value.undef[row] = pNull[2]) ) {
+ if( pVals[2].data.log ) {
+ strcpy( this->value.data.strptr[row],
+ pVals[0].data.str );
+ this->value.undef[row] = pNull[0];
+ } else {
+ strcpy( this->value.data.strptr[row],
+ pVals[1].data.str );
+ this->value.undef[row] = pNull[1];
+ }
+ } else {
+ this->value.data.strptr[row][0] = '\0';
+ }
+ }
+ break;
+
+ }
+ break;
+
+ }
+ }
+ }
+
+ i = this->nSubNodes;
+ while( i-- ) {
+ if( theParams[i]->operation>0 ) {
+ /* Currently only numeric params allowed */
+ free( theParams[i]->value.data.ptr );
+ }
+ }
+}
+
+static void Do_Deref( Node *this )
+{
+ Node *theVar, *theDims[MAXDIMS];
+ int isConst[MAXDIMS], allConst;
+ long dimVals[MAXDIMS];
+ int i, nDims;
+ long row, elem, dsize;
+
+ theVar = gParse.Nodes + this->SubNodes[0];
+
+ i = nDims = this->nSubNodes-1;
+ allConst = 1;
+ while( i-- ) {
+ theDims[i] = gParse.Nodes + this->SubNodes[i+1];
+ isConst[i] = ( theDims[i]->operation==CONST_OP );
+ if( isConst[i] )
+ dimVals[i] = theDims[i]->value.data.lng;
+ else
+ allConst = 0;
+ }
+
+ if( this->type==DOUBLE ) {
+ dsize = sizeof( double );
+ } else if( this->type==LONG ) {
+ dsize = sizeof( long );
+ } else if( this->type==BOOLEAN ) {
+ dsize = sizeof( char );
+ } else
+ dsize = 0;
+
+ Allocate_Ptrs( this );
+
+ if( !gParse.status ) {
+
+ if( allConst && theVar->value.naxis==nDims ) {
+
+ /* Dereference completely using constant indices */
+
+ elem = 0;
+ i = nDims;
+ while( i-- ) {
+ if( dimVals[i]<1 || dimVals[i]>theVar->value.naxes[i] ) break;
+ elem = theVar->value.naxes[i]*elem + dimVals[i]-1;
+ }
+ if( i<0 ) {
+ for( row=0; row<gParse.nRows; row++ ) {
+ if( this->type==STRING )
+ this->value.undef[row] = theVar->value.undef[row];
+ else if( this->type==BITSTR )
+ this->value.undef; /* Dummy - BITSTRs do not have undefs */
+ else
+ this->value.undef[row] = theVar->value.undef[elem];
+
+ if( this->type==DOUBLE )
+ this->value.data.dblptr[row] =
+ theVar->value.data.dblptr[elem];
+ else if( this->type==LONG )
+ this->value.data.lngptr[row] =
+ theVar->value.data.lngptr[elem];
+ else if( this->type==BOOLEAN )
+ this->value.data.logptr[row] =
+ theVar->value.data.logptr[elem];
+ else {
+ /* XXX Note, the below expression uses knowledge of
+ the layout of the string format, namely (nelem+1)
+ characters per string, followed by (nelem+1)
+ "undef" values. */
+ this->value.data.strptr[row][0] =
+ theVar->value.data.strptr[0][elem+row];
+ this->value.data.strptr[row][1] = 0; /* Null terminate */
+ }
+ elem += theVar->value.nelem;
+ }
+ } else {
+ yyerror("Index out of range");
+ free( this->value.data.ptr );
+ }
+
+ } else if( allConst && nDims==1 ) {
+
+ /* Reduce dimensions by 1, using a constant index */
+
+ if( dimVals[0] < 1 ||
+ dimVals[0] > theVar->value.naxes[ theVar->value.naxis-1 ] ) {
+ yyerror("Index out of range");
+ free( this->value.data.ptr );
+ } else if ( this->type == BITSTR || this->type == STRING ) {
+ elem = this->value.nelem * (dimVals[0]-1);
+ for( row=0; row<gParse.nRows; row++ ) {
+ if (this->value.undef)
+ this->value.undef[row] = theVar->value.undef[row];
+ memcpy( (char*)this->value.data.strptr[0]
+ + row*sizeof(char)*(this->value.nelem+1),
+ (char*)theVar->value.data.strptr[0] + elem*sizeof(char),
+ this->value.nelem * sizeof(char) );
+ /* Null terminate */
+ this->value.data.strptr[row][this->value.nelem] = 0;
+ elem += theVar->value.nelem+1;
+ }
+ } else {
+ elem = this->value.nelem * (dimVals[0]-1);
+ for( row=0; row<gParse.nRows; row++ ) {
+ memcpy( this->value.undef + row*this->value.nelem,
+ theVar->value.undef + elem,
+ this->value.nelem * sizeof(char) );
+ memcpy( (char*)this->value.data.ptr
+ + row*dsize*this->value.nelem,
+ (char*)theVar->value.data.ptr + elem*dsize,
+ this->value.nelem * dsize );
+ elem += theVar->value.nelem;
+ }
+ }
+
+ } else if( theVar->value.naxis==nDims ) {
+
+ /* Dereference completely using an expression for the indices */
+
+ for( row=0; row<gParse.nRows; row++ ) {
+
+ for( i=0; i<nDims; i++ ) {
+ if( !isConst[i] ) {
+ if( theDims[i]->value.undef[row] ) {
+ yyerror("Null encountered as vector index");
+ free( this->value.data.ptr );
+ break;
+ } else
+ dimVals[i] = theDims[i]->value.data.lngptr[row];
+ }
+ }
+ if( gParse.status ) break;
+
+ elem = 0;
+ i = nDims;
+ while( i-- ) {
+ if( dimVals[i]<1 || dimVals[i]>theVar->value.naxes[i] ) break;
+ elem = theVar->value.naxes[i]*elem + dimVals[i]-1;
+ }
+ if( i<0 ) {
+ elem += row*theVar->value.nelem;
+
+ if( this->type==STRING )
+ this->value.undef[row] = theVar->value.undef[row];
+ else if( this->type==BITSTR )
+ this->value.undef; /* Dummy - BITSTRs do not have undefs */
+ else
+ this->value.undef[row] = theVar->value.undef[elem];
+
+ if( this->type==DOUBLE )
+ this->value.data.dblptr[row] =
+ theVar->value.data.dblptr[elem];
+ else if( this->type==LONG )
+ this->value.data.lngptr[row] =
+ theVar->value.data.lngptr[elem];
+ else if( this->type==BOOLEAN )
+ this->value.data.logptr[row] =
+ theVar->value.data.logptr[elem];
+ else {
+ /* XXX Note, the below expression uses knowledge of
+ the layout of the string format, namely (nelem+1)
+ characters per string, followed by (nelem+1)
+ "undef" values. */
+ this->value.data.strptr[row][0] =
+ theVar->value.data.strptr[0][elem+row];
+ this->value.data.strptr[row][1] = 0; /* Null terminate */
+ }
+ } else {
+ yyerror("Index out of range");
+ free( this->value.data.ptr );
+ }
+ }
+
+ } else {
+
+ /* Reduce dimensions by 1, using a nonconstant expression */
+
+ for( row=0; row<gParse.nRows; row++ ) {
+
+ /* Index cannot be a constant */
+
+ if( theDims[0]->value.undef[row] ) {
+ yyerror("Null encountered as vector index");
+ free( this->value.data.ptr );
+ break;
+ } else
+ dimVals[0] = theDims[0]->value.data.lngptr[row];
+
+ if( dimVals[0] < 1 ||
+ dimVals[0] > theVar->value.naxes[ theVar->value.naxis-1 ] ) {
+ yyerror("Index out of range");
+ free( this->value.data.ptr );
+ } else if ( this->type == BITSTR || this->type == STRING ) {
+ elem = this->value.nelem * (dimVals[0]-1);
+ elem += row*(theVar->value.nelem+1);
+ if (this->value.undef)
+ this->value.undef[row] = theVar->value.undef[row];
+ memcpy( (char*)this->value.data.strptr[0]
+ + row*sizeof(char)*(this->value.nelem+1),
+ (char*)theVar->value.data.strptr[0] + elem*sizeof(char),
+ this->value.nelem * sizeof(char) );
+ /* Null terminate */
+ this->value.data.strptr[row][this->value.nelem] = 0;
+ } else {
+ elem = this->value.nelem * (dimVals[0]-1);
+ elem += row*theVar->value.nelem;
+ memcpy( this->value.undef + row*this->value.nelem,
+ theVar->value.undef + elem,
+ this->value.nelem * sizeof(char) );
+ memcpy( (char*)this->value.data.ptr
+ + row*dsize*this->value.nelem,
+ (char*)theVar->value.data.ptr + elem*dsize,
+ this->value.nelem * dsize );
+ }
+ }
+ }
+ }
+
+ if( theVar->operation>0 ) {
+ if (theVar->type == STRING || theVar->type == BITSTR)
+ free(theVar->value.data.strptr[0] );
+ else
+ free( theVar->value.data.ptr );
+ }
+ for( i=0; i<nDims; i++ )
+ if( theDims[i]->operation>0 ) {
+ free( theDims[i]->value.data.ptr );
+ }
+}
+
+static void Do_GTI( Node *this )
+{
+ Node *theExpr, *theTimes;
+ double *start, *stop, *times;
+ long elem, nGTI, gti;
+ int ordered;
+
+ theTimes = gParse.Nodes + this->SubNodes[0];
+ theExpr = gParse.Nodes + this->SubNodes[1];
+
+ nGTI = theTimes->value.nelem;
+ start = theTimes->value.data.dblptr;
+ stop = theTimes->value.data.dblptr + nGTI;
+ ordered = theTimes->type;
+
+ if( theExpr->operation==CONST_OP ) {
+
+ this->value.data.log =
+ (Search_GTI( theExpr->value.data.dbl, nGTI, start, stop, ordered )>=0);
+ this->operation = CONST_OP;
+
+ } else {
+
+ Allocate_Ptrs( this );
+
+ times = theExpr->value.data.dblptr;
+ if( !gParse.status ) {
+
+ elem = gParse.nRows * this->value.nelem;
+ if( nGTI ) {
+ gti = -1;
+ while( elem-- ) {
+ if( (this->value.undef[elem] = theExpr->value.undef[elem]) )
+ continue;
+
+ /* Before searching entire GTI, check the GTI found last time */
+ if( gti<0 || times[elem]<start[gti] || times[elem]>stop[gti] ) {
+ gti = Search_GTI( times[elem], nGTI, start, stop, ordered );
+ }
+ this->value.data.logptr[elem] = ( gti>=0 );
+ }
+ } else
+ while( elem-- ) {
+ this->value.data.logptr[elem] = 0;
+ this->value.undef[elem] = 0;
+ }
+ }
+ }
+
+ if( theExpr->operation>0 )
+ free( theExpr->value.data.ptr );
+}
+
+static long Search_GTI( double evtTime, long nGTI, double *start,
+ double *stop, int ordered )
+{
+ long gti, step;
+
+ if( ordered && nGTI>15 ) { /* If time-ordered and lots of GTIs, */
+ /* use "FAST" Binary search algorithm */
+ if( evtTime>=start[0] && evtTime<=stop[nGTI-1] ) {
+ gti = step = (nGTI >> 1);
+ while(1) {
+ if( step>1L ) step >>= 1;
+
+ if( evtTime>stop[gti] ) {
+ if( evtTime>=start[gti+1] )
+ gti += step;
+ else {
+ gti = -1L;
+ break;
+ }
+ } else if( evtTime<start[gti] ) {
+ if( evtTime<=stop[gti-1] )
+ gti -= step;
+ else {
+ gti = -1L;
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+ } else
+ gti = -1L;
+
+ } else { /* Use "SLOW" linear search */
+ gti = nGTI;
+ while( gti-- )
+ if( evtTime>=start[gti] && evtTime<=stop[gti] )
+ break;
+ }
+ return( gti );
+}
+
+static void Do_REG( Node *this )
+{
+ Node *theRegion, *theX, *theY;
+ double Xval=0.0, Yval=0.0;
+ char Xnull=0, Ynull=0;
+ int Xvector, Yvector;
+ long nelem, elem, rows;
+
+ theRegion = gParse.Nodes + this->SubNodes[0];
+ theX = gParse.Nodes + this->SubNodes[1];
+ theY = gParse.Nodes + this->SubNodes[2];
+
+ Xvector = ( theX->operation!=CONST_OP );
+ if( Xvector )
+ Xvector = theX->value.nelem;
+ else {
+ Xval = theX->value.data.dbl;
+ }
+
+ Yvector = ( theY->operation!=CONST_OP );
+ if( Yvector )
+ Yvector = theY->value.nelem;
+ else {
+ Yval = theY->value.data.dbl;
+ }
+
+ if( !Xvector && !Yvector ) {
+
+ this->value.data.log =
+ ( fits_in_region( Xval, Yval, (SAORegion *)theRegion->value.data.ptr )
+ != 0 );
+ this->operation = CONST_OP;
+
+ } else {
+
+ Allocate_Ptrs( this );
+
+ if( !gParse.status ) {
+
+ rows = gParse.nRows;
+ nelem = this->value.nelem;
+ elem = rows*nelem;
+
+ while( rows-- ) {
+ while( nelem-- ) {
+ elem--;
+
+ if( Xvector>1 ) {
+ Xval = theX->value.data.dblptr[elem];
+ Xnull = theX->value.undef[elem];
+ } else if( Xvector ) {
+ Xval = theX->value.data.dblptr[rows];
+ Xnull = theX->value.undef[rows];
+ }
+
+ if( Yvector>1 ) {
+ Yval = theY->value.data.dblptr[elem];
+ Ynull = theY->value.undef[elem];
+ } else if( Yvector ) {
+ Yval = theY->value.data.dblptr[rows];
+ Ynull = theY->value.undef[rows];
+ }
+
+ this->value.undef[elem] = ( Xnull || Ynull );
+ if( this->value.undef[elem] )
+ continue;
+
+ this->value.data.logptr[elem] =
+ ( fits_in_region( Xval, Yval,
+ (SAORegion *)theRegion->value.data.ptr )
+ != 0 );
+ }
+ nelem = this->value.nelem;
+ }
+ }
+ }
+
+ if( theX->operation>0 )
+ free( theX->value.data.ptr );
+ if( theY->operation>0 )
+ free( theY->value.data.ptr );
+}
+
+static void Do_Vector( Node *this )
+{
+ Node *that;
+ long row, elem, idx, jdx, offset=0;
+ int node;
+
+ Allocate_Ptrs( this );
+
+ if( !gParse.status ) {
+
+ for( node=0; node<this->nSubNodes; node++ ) {
+
+ that = gParse.Nodes + this->SubNodes[node];
+
+ if( that->operation == CONST_OP ) {
+
+ idx = gParse.nRows*this->value.nelem + offset;
+ while( (idx-=this->value.nelem)>=0 ) {
+
+ this->value.undef[idx] = 0;
+
+ switch( this->type ) {
+ case BOOLEAN:
+ this->value.data.logptr[idx] = that->value.data.log;
+ break;
+ case LONG:
+ this->value.data.lngptr[idx] = that->value.data.lng;
+ break;
+ case DOUBLE:
+ this->value.data.dblptr[idx] = that->value.data.dbl;
+ break;
+ }
+ }
+
+ } else {
+
+ row = gParse.nRows;
+ idx = row * that->value.nelem;
+ while( row-- ) {
+ elem = that->value.nelem;
+ jdx = row*this->value.nelem + offset;
+ while( elem-- ) {
+ this->value.undef[jdx+elem] =
+ that->value.undef[--idx];
+
+ switch( this->type ) {
+ case BOOLEAN:
+ this->value.data.logptr[jdx+elem] =
+ that->value.data.logptr[idx];
+ break;
+ case LONG:
+ this->value.data.lngptr[jdx+elem] =
+ that->value.data.lngptr[idx];
+ break;
+ case DOUBLE:
+ this->value.data.dblptr[jdx+elem] =
+ that->value.data.dblptr[idx];
+ break;
+ }
+ }
+ }
+ }
+ offset += that->value.nelem;
+ }
+
+ }
+
+ for( node=0; node < this->nSubNodes; node++ )
+ if( gParse.Nodes[this->SubNodes[node]].operation>0 )
+ free( gParse.Nodes[this->SubNodes[node]].value.data.ptr );
+}
+
+/*****************************************************************************/
+/* Utility routines which perform the calculations on bits and SAO regions */
+/*****************************************************************************/
+
+static char bitlgte(char *bits1, int oper, char *bits2)
+{
+ int val1, val2, nextbit;
+ char result;
+ int i, l1, l2, length, ldiff;
+ char stream[256];
+ char chr1, chr2;
+
+ l1 = strlen(bits1);
+ l2 = strlen(bits2);
+ if (l1 < l2)
+ {
+ length = l2;
+ ldiff = l2 - l1;
+ i=0;
+ while( ldiff-- ) stream[i++] = '0';
+ while( l1-- ) stream[i++] = *(bits1++);
+ stream[i] = '\0';
+ bits1 = stream;
+ }
+ else if (l2 < l1)
+ {
+ length = l1;
+ ldiff = l1 - l2;
+ i=0;
+ while( ldiff-- ) stream[i++] = '0';
+ while( l2-- ) stream[i++] = *(bits2++);
+ stream[i] = '\0';
+ bits2 = stream;
+ }
+ else
+ length = l1;
+
+ val1 = val2 = 0;
+ nextbit = 1;
+
+ while( length-- )
+ {
+ chr1 = bits1[length];
+ chr2 = bits2[length];
+ if ((chr1 != 'x')&&(chr1 != 'X')&&(chr2 != 'x')&&(chr2 != 'X'))
+ {
+ if (chr1 == '1') val1 += nextbit;
+ if (chr2 == '1') val2 += nextbit;
+ nextbit *= 2;
+ }
+ }
+ result = 0;
+ switch (oper)
+ {
+ case LT:
+ if (val1 < val2) result = 1;
+ break;
+ case LTE:
+ if (val1 <= val2) result = 1;
+ break;
+ case GT:
+ if (val1 > val2) result = 1;
+ break;
+ case GTE:
+ if (val1 >= val2) result = 1;
+ break;
+ }
+ return (result);
+}
+
+static void bitand(char *result,char *bitstrm1,char *bitstrm2)
+{
+ int i, l1, l2, ldiff;
+ char stream[256];
+ char chr1, chr2;
+
+ l1 = strlen(bitstrm1);
+ l2 = strlen(bitstrm2);
+ if (l1 < l2)
+ {
+ ldiff = l2 - l1;
+ i=0;
+ while( ldiff-- ) stream[i++] = '0';
+ while( l1-- ) stream[i++] = *(bitstrm1++);
+ stream[i] = '\0';
+ bitstrm1 = stream;
+ }
+ else if (l2 < l1)
+ {
+ ldiff = l1 - l2;
+ i=0;
+ while( ldiff-- ) stream[i++] = '0';
+ while( l2-- ) stream[i++] = *(bitstrm2++);
+ stream[i] = '\0';
+ bitstrm2 = stream;
+ }
+ while ( (chr1 = *(bitstrm1++)) )
+ {
+ chr2 = *(bitstrm2++);
+ if ((chr1 == 'x') || (chr2 == 'x'))
+ *result = 'x';
+ else if ((chr1 == '1') && (chr2 == '1'))
+ *result = '1';
+ else
+ *result = '0';
+ result++;
+ }
+ *result = '\0';
+}
+
+static void bitor(char *result,char *bitstrm1,char *bitstrm2)
+{
+ int i, l1, l2, ldiff;
+ char stream[256];
+ char chr1, chr2;
+
+ l1 = strlen(bitstrm1);
+ l2 = strlen(bitstrm2);
+ if (l1 < l2)
+ {
+ ldiff = l2 - l1;
+ i=0;
+ while( ldiff-- ) stream[i++] = '0';
+ while( l1-- ) stream[i++] = *(bitstrm1++);
+ stream[i] = '\0';
+ bitstrm1 = stream;
+ }
+ else if (l2 < l1)
+ {
+ ldiff = l1 - l2;
+ i=0;
+ while( ldiff-- ) stream[i++] = '0';
+ while( l2-- ) stream[i++] = *(bitstrm2++);
+ stream[i] = '\0';
+ bitstrm2 = stream;
+ }
+ while ( (chr1 = *(bitstrm1++)) )
+ {
+ chr2 = *(bitstrm2++);
+ if ((chr1 == '1') || (chr2 == '1'))
+ *result = '1';
+ else if ((chr1 == '0') || (chr2 == '0'))
+ *result = '0';
+ else
+ *result = 'x';
+ result++;
+ }
+ *result = '\0';
+}
+
+static void bitnot(char *result,char *bits)
+{
+ int length;
+ char chr;
+
+ length = strlen(bits);
+ while( length-- ) {
+ chr = *(bits++);
+ *(result++) = ( chr=='1' ? '0' : ( chr=='0' ? '1' : chr ) );
+ }
+ *result = '\0';
+}
+
+static char bitcmp(char *bitstrm1, char *bitstrm2)
+{
+ int i, l1, l2, ldiff;
+ char stream[256];
+ char chr1, chr2;
+
+ l1 = strlen(bitstrm1);
+ l2 = strlen(bitstrm2);
+ if (l1 < l2)
+ {
+ ldiff = l2 - l1;
+ i=0;
+ while( ldiff-- ) stream[i++] = '0';
+ while( l1-- ) stream[i++] = *(bitstrm1++);
+ stream[i] = '\0';
+ bitstrm1 = stream;
+ }
+ else if (l2 < l1)
+ {
+ ldiff = l1 - l2;
+ i=0;
+ while( ldiff-- ) stream[i++] = '0';
+ while( l2-- ) stream[i++] = *(bitstrm2++);
+ stream[i] = '\0';
+ bitstrm2 = stream;
+ }
+ while( (chr1 = *(bitstrm1++)) )
+ {
+ chr2 = *(bitstrm2++);
+ if ( ((chr1 == '0') && (chr2 == '1'))
+ || ((chr1 == '1') && (chr2 == '0')) )
+ return( 0 );
+ }
+ return( 1 );
+}
+
+static char bnear(double x, double y, double tolerance)
+{
+ if (fabs(x - y) < tolerance)
+ return ( 1 );
+ else
+ return ( 0 );
+}
+
+static char saobox(double xcen, double ycen, double xwid, double ywid,
+ double rot, double xcol, double ycol)
+{
+ double x,y,xprime,yprime,xmin,xmax,ymin,ymax,theta;
+
+ theta = (rot / 180.0) * myPI;
+ xprime = xcol - xcen;
+ yprime = ycol - ycen;
+ x = xprime * cos(theta) + yprime * sin(theta);
+ y = -xprime * sin(theta) + yprime * cos(theta);
+ xmin = - 0.5 * xwid; xmax = 0.5 * xwid;
+ ymin = - 0.5 * ywid; ymax = 0.5 * ywid;
+ if ((x >= xmin) && (x <= xmax) && (y >= ymin) && (y <= ymax))
+ return ( 1 );
+ else
+ return ( 0 );
+}
+
+static char circle(double xcen, double ycen, double rad,
+ double xcol, double ycol)
+{
+ double r2,dx,dy,dlen;
+
+ dx = xcol - xcen;
+ dy = ycol - ycen;
+ dx *= dx; dy *= dy;
+ dlen = dx + dy;
+ r2 = rad * rad;
+ if (dlen <= r2)
+ return ( 1 );
+ else
+ return ( 0 );
+}
+
+static char ellipse(double xcen, double ycen, double xrad, double yrad,
+ double rot, double xcol, double ycol)
+{
+ double x,y,xprime,yprime,dx,dy,dlen,theta;
+
+ theta = (rot / 180.0) * myPI;
+ xprime = xcol - xcen;
+ yprime = ycol - ycen;
+ x = xprime * cos(theta) + yprime * sin(theta);
+ y = -xprime * sin(theta) + yprime * cos(theta);
+ dx = x / xrad; dy = y / yrad;
+ dx *= dx; dy *= dy;
+ dlen = dx + dy;
+ if (dlen <= 1.0)
+ return ( 1 );
+ else
+ return ( 0 );
+}
+
+static void yyerror(char *s)
+{
+ char msg[80];
+
+ if( !gParse.status ) gParse.status = PARSE_SYNTAX_ERR;
+
+ strncpy(msg, s, 80);
+ msg[79] = '\0';
+ ffpmsg(msg);
+}
diff --git a/pkg/tbtables/cfitsio/eval_defs.h b/pkg/tbtables/cfitsio/eval_defs.h
new file mode 100644
index 00000000..d991fc16
--- /dev/null
+++ b/pkg/tbtables/cfitsio/eval_defs.h
@@ -0,0 +1,153 @@
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+#if defined(__sgi) || defined(__hpux)
+#include <alloca.h>
+#endif
+#ifdef sparc
+#include <malloc.h>
+#endif
+#include "fitsio2.h"
+
+#ifndef FFBISON
+#include "eval_tab.h"
+#endif
+
+#define MAXDIMS 5
+#define MAXSUBS 10
+#define MAXVARNAME 80
+#define CONST_OP -1000
+#define pERROR -1
+
+typedef struct {
+ char name[MAXVARNAME+1];
+ int type;
+ long nelem;
+ int naxis;
+ long naxes[MAXDIMS];
+ char *undef;
+ void *data;
+ } DataInfo;
+
+typedef struct {
+ long nelem;
+ int naxis;
+ long naxes[MAXDIMS];
+ char *undef;
+ union {
+ double dbl;
+ long lng;
+ char log;
+ char str[256];
+ double *dblptr;
+ long *lngptr;
+ char *logptr;
+ char **strptr;
+ void *ptr;
+ } data;
+ } lval;
+
+typedef struct Node {
+ int operation;
+ void (*DoOp)(struct Node *this);
+ int nSubNodes;
+ int SubNodes[MAXSUBS];
+ int type;
+ lval value;
+ } Node;
+
+typedef struct {
+ fitsfile *def_fptr;
+ int (*getData)( char *dataName, void *dataValue );
+ int (*loadData)( int varNum, long fRow, long nRows,
+ void *data, char *undef );
+
+ int compressed;
+ int timeCol;
+ int parCol;
+ int valCol;
+
+ char *expr;
+ int index;
+ int is_eobuf;
+
+ Node *Nodes;
+ int nNodes;
+ int nNodesAlloc;
+ int resultNode;
+
+ long firstRow;
+ long nRows;
+
+ int nCols;
+ iteratorCol *colData;
+ DataInfo *varData;
+
+ long firstDataRow;
+ long nDataRows;
+ long totalRows;
+
+ int datatype;
+
+ int status;
+ } ParseData;
+
+typedef enum {
+ rnd_fct = 1001,
+ sum_fct,
+ nelem_fct,
+ sin_fct,
+ cos_fct,
+ tan_fct,
+ asin_fct,
+ acos_fct,
+ atan_fct,
+ sinh_fct,
+ cosh_fct,
+ tanh_fct,
+ exp_fct,
+ log_fct,
+ log10_fct,
+ sqrt_fct,
+ abs_fct,
+ atan2_fct,
+ ceil_fct,
+ floor_fct,
+ round_fct,
+ min1_fct,
+ min2_fct,
+ max1_fct,
+ max2_fct,
+ near_fct,
+ circle_fct,
+ box_fct,
+ elps_fct,
+ isnull_fct,
+ defnull_fct,
+ gtifilt_fct,
+ regfilt_fct,
+ ifthenelse_fct,
+ row_fct,
+ null_fct,
+ median_fct,
+ average_fct,
+ stddev_fct,
+ nonnull_fct
+ } funcOp;
+
+extern ParseData gParse;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ int ffparse(void);
+ int fflex(void);
+ void ffrestart(FILE*);
+
+ void Evaluate_Parser( long firstRow, long nRows );
+
+#ifdef __cplusplus
+ }
+#endif
diff --git a/pkg/tbtables/cfitsio/eval_f.c b/pkg/tbtables/cfitsio/eval_f.c
new file mode 100644
index 00000000..20441818
--- /dev/null
+++ b/pkg/tbtables/cfitsio/eval_f.c
@@ -0,0 +1,2293 @@
+/************************************************************************/
+/* */
+/* CFITSIO Lexical Parser */
+/* */
+/* This file is one of 3 files containing code which parses an */
+/* arithmetic expression and evaluates it in the context of an input */
+/* FITS file table extension. The CFITSIO lexical parser is divided */
+/* into the following 3 parts/files: the CFITSIO "front-end", */
+/* eval_f.c, contains the interface between the user/CFITSIO and the */
+/* real core of the parser; the FLEX interpreter, eval_l.c, takes the */
+/* input string and parses it into tokens and identifies the FITS */
+/* information required to evaluate the expression (ie, keywords and */
+/* columns); and, the BISON grammar and evaluation routines, eval_y.c, */
+/* receives the FLEX output and determines and performs the actual */
+/* operations. The files eval_l.c and eval_y.c are produced from */
+/* running flex and bison on the files eval.l and eval.y, respectively. */
+/* (flex and bison are available from any GNU archive: see www.gnu.org) */
+/* */
+/* The grammar rules, rather than evaluating the expression in situ, */
+/* builds a tree, or Nodal, structure mapping out the order of */
+/* operations and expression dependencies. This "compilation" process */
+/* allows for much faster processing of multiple rows. This technique */
+/* was developed by Uwe Lammers of the XMM Science Analysis System, */
+/* although the CFITSIO implementation is entirely code original. */
+/* */
+/* */
+/* Modification History: */
+/* */
+/* Kent Blackburn c1992 Original parser code developed for the */
+/* FTOOLS software package, in particular, */
+/* the fselect task. */
+/* Kent Blackburn c1995 BIT column support added */
+/* Peter D Wilson Feb 1998 Vector column support added */
+/* Peter D Wilson May 1998 Ported to CFITSIO library. User */
+/* interface routines written, in essence */
+/* making fselect, fcalc, and maketime */
+/* capabilities available to all tools */
+/* via single function calls. */
+/* Peter D Wilson Jun 1998 Major rewrite of parser core, so as to */
+/* create a run-time evaluation tree, */
+/* inspired by the work of Uwe Lammers, */
+/* resulting in a speed increase of */
+/* 10-100 times. */
+/* Peter D Wilson Jul 1998 gtifilter(a,b,c,d) function added */
+/* Peter D Wilson Aug 1998 regfilter(a,b,c,d) function added */
+/* Peter D Wilson Jul 1999 Make parser fitsfile-independent, */
+/* allowing a purely vector-based usage */
+/* Peter D Wilson Aug 1999 Add row-offset capability */
+/* Peter D Wilson Sep 1999 Add row-range capability to ffcalc_rng */
+/* */
+/************************************************************************/
+
+#include <limits.h>
+#include <ctype.h>
+#include "eval_defs.h"
+#include "region.h"
+
+typedef struct {
+ int datatype; /* Data type to cast parse results into for user */
+ void *dataPtr; /* Pointer to array of results, NULL if to use iterCol */
+ void *nullPtr; /* Pointer to nulval, use zero if NULL */
+ long maxRows; /* Max No. of rows to process, -1=all, 0=1 iteration */
+ int anyNull; /* Flag indicating at least 1 undef value encountered */
+} parseInfo;
+
+/* Internal routines needed to allow the evaluator to operate on FITS data */
+
+static void Setup_DataArrays( int nCols, iteratorCol *cols,
+ long fRow, long nRows );
+static int find_column( char *colName, void *itslval );
+static int find_keywd ( char *key, void *itslval );
+static int allocateCol( int nCol, int *status );
+static int load_column( int varNum, long fRow, long nRows,
+ void *data, char *undef );
+
+/*---------------------------------------------------------------------------*/
+int fffrow( fitsfile *fptr, /* I - Input FITS file */
+ char *expr, /* I - Boolean expression */
+ long firstrow, /* I - First row of table to eval */
+ long nrows, /* I - Number of rows to evaluate */
+ long *n_good_rows, /* O - Number of rows eval to True */
+ char *row_status, /* O - Array of boolean results */
+ int *status ) /* O - Error status */
+/* */
+/* Evaluate a boolean expression using the indicated rows, returning an */
+/* array of flags indicating which rows evaluated to TRUE/FALSE */
+/*---------------------------------------------------------------------------*/
+{
+ parseInfo Info;
+ int naxis, constant;
+ long nelem, naxes[MAXDIMS], elem;
+ char result;
+
+ if( *status ) return( *status );
+
+ if( ffiprs( fptr, 0, expr, MAXDIMS, &Info.datatype, &nelem, &naxis,
+ naxes, status ) ) {
+ ffcprs();
+ return( *status );
+ }
+ if( nelem<0 ) {
+ constant = 1;
+ nelem = -nelem;
+ } else
+ constant = 0;
+
+ if( Info.datatype!=TLOGICAL || nelem!=1 ) {
+ ffcprs();
+ ffpmsg("Expression does not evaluate to a logical scalar.");
+ return( *status = PARSE_BAD_TYPE );
+ }
+
+ if( constant ) { /* No need to call parser... have result from ffiprs */
+ result = gParse.Nodes[gParse.resultNode].value.data.log;
+ *n_good_rows = nrows;
+ for( elem=0; elem<nrows; elem++ )
+ row_status[elem] = result;
+ } else {
+ firstrow = (firstrow>1 ? firstrow : 1);
+ Info.dataPtr = row_status;
+ Info.nullPtr = NULL;
+ Info.maxRows = nrows;
+
+ if( ffiter( gParse.nCols, gParse.colData, firstrow-1, 0,
+ parse_data, (void*)&Info, status ) == -1 )
+ *status = 0; /* -1 indicates exitted without error before end... OK */
+
+ if( *status ) {
+
+ /***********************/
+ /* Error... Do nothing */
+ /***********************/
+
+ } else {
+
+ /***********************************/
+ /* Count number of good rows found */
+ /***********************************/
+
+ *n_good_rows = 0L;
+ for( elem=0; elem<Info.maxRows; elem++ ) {
+ if( row_status[elem]==1 ) ++*n_good_rows;
+ }
+ }
+ }
+
+ ffcprs();
+ return(*status);
+}
+
+/*--------------------------------------------------------------------------*/
+int ffsrow( fitsfile *infptr, /* I - Input FITS file */
+ fitsfile *outfptr, /* I - Output FITS file */
+ char *expr, /* I - Boolean expression */
+ int *status ) /* O - Error status */
+/* */
+/* Evaluate an expression on all rows of a table. If the input and output */
+/* files are not the same, copy the TRUE rows to the output file. If the */
+/* files are the same, delete the FALSE rows (preserve the TRUE rows). */
+/* Can copy rows between extensions of the same file, *BUT* if output */
+/* extension is before the input extension, the second extension *MUST* be */
+/* opened using ffreopen, so that CFITSIO can handle changing file lengths. */
+/*--------------------------------------------------------------------------*/
+{
+ parseInfo Info;
+ int naxis, constant;
+ long nelem, rdlen, naxes[MAXDIMS], maxrows, nbuff, nGood, inloc, outloc;
+ OFF_T inbyteloc, outbyteloc, hsize;
+ long ntodo, freespace;
+ unsigned char *buffer, result;
+ struct {
+ long rowLength, numRows, heapSize;
+ OFF_T dataStart, heapStart;
+ } inExt, outExt;
+
+ if( *status ) return( *status );
+
+ if( ffiprs( infptr, 0, expr, MAXDIMS, &Info.datatype, &nelem, &naxis,
+ naxes, status ) ) {
+ ffcprs();
+ return( *status );
+ }
+ if( nelem<0 ) {
+ constant = 1;
+ nelem = -nelem;
+ } else
+ constant = 0;
+
+ /**********************************************************************/
+ /* Make sure expression evaluates to the right type... logical scalar */
+ /**********************************************************************/
+
+ if( Info.datatype!=TLOGICAL || nelem!=1 ) {
+ ffcprs();
+ ffpmsg("Expression does not evaluate to a logical scalar.");
+ return( *status = PARSE_BAD_TYPE );
+ }
+
+ /***********************************************************/
+ /* Extract various table information from each extension */
+ /***********************************************************/
+
+ if( infptr->HDUposition != (infptr->Fptr)->curhdu )
+ ffmahd( infptr, (infptr->HDUposition) + 1, NULL, status );
+ if( *status ) {
+ ffcprs();
+ return( *status );
+ }
+ inExt.rowLength = (long) (infptr->Fptr)->rowlength;
+ inExt.numRows = (infptr->Fptr)->numrows;
+ inExt.heapSize = (infptr->Fptr)->heapsize;
+ if( inExt.numRows == 0 ) { /* Nothing to copy */
+ ffcprs();
+ return( *status );
+ }
+
+ if( outfptr->HDUposition != (outfptr->Fptr)->curhdu )
+ ffmahd( outfptr, (outfptr->HDUposition) + 1, NULL, status );
+ if( (outfptr->Fptr)->datastart < 0 )
+ ffrdef( outfptr, status );
+ if( *status ) {
+ ffcprs();
+ return( *status );
+ }
+ outExt.rowLength = (long) (outfptr->Fptr)->rowlength;
+ outExt.numRows = (outfptr->Fptr)->numrows;
+ if( !outExt.numRows )
+ (outfptr->Fptr)->heapsize = 0L;
+ outExt.heapSize = (outfptr->Fptr)->heapsize;
+
+ if( inExt.rowLength != outExt.rowLength ) {
+ ffpmsg("Output table has different row length from input");
+ ffcprs();
+ return( *status = PARSE_BAD_OUTPUT );
+ }
+
+ /***********************************/
+ /* Fill out Info data for parser */
+ /***********************************/
+
+ Info.dataPtr = (char *)malloc( (inExt.numRows + 1) * sizeof(char) );
+ Info.nullPtr = NULL;
+ Info.maxRows = inExt.numRows;
+ if( !Info.dataPtr ) {
+ ffpmsg("Unable to allocate memory for row selection");
+ ffcprs();
+ return( *status = MEMORY_ALLOCATION );
+ }
+
+ /* make sure array is zero terminated */
+ ((char*)Info.dataPtr)[inExt.numRows] = 0;
+
+ if( constant ) { /* Set all rows to the same value from constant result */
+
+ result = gParse.Nodes[gParse.resultNode].value.data.log;
+ for( ntodo = 0; ntodo<inExt.numRows; ntodo++ )
+ ((char*)Info.dataPtr)[ntodo] = result;
+ nGood = (result ? inExt.numRows : 0);
+
+ } else {
+
+ ffiter( gParse.nCols, gParse.colData, 0L, 0L,
+ parse_data, (void*)&Info, status );
+
+ nGood = 0;
+ for( ntodo = 0; ntodo<inExt.numRows; ntodo++ )
+ if( ((char*)Info.dataPtr)[ntodo] ) nGood++;
+ }
+
+ if( *status ) {
+ /* Error... Do nothing */
+ } else {
+ rdlen = inExt.rowLength;
+ buffer = (unsigned char *)malloc(maxvalue(500000,rdlen) * sizeof(char) );
+ if( buffer==NULL ) {
+ ffcprs();
+ return( *status=MEMORY_ALLOCATION );
+ }
+ maxrows = maxvalue( (500000L/rdlen), 1);
+ nbuff = 0;
+ inloc = 1;
+ if( infptr==outfptr ) { /* Skip initial good rows if input==output file */
+ while( ((char*)Info.dataPtr)[inloc-1] ) inloc++;
+ outloc = inloc;
+ } else {
+ outloc = outExt.numRows + 1;
+ if (outloc > 1)
+ ffirow( outfptr, outExt.numRows, nGood, status );
+ }
+
+ do {
+ if( ((char*)Info.dataPtr)[inloc-1] ) {
+ ffgtbb( infptr, inloc, 1L, rdlen, buffer+rdlen*nbuff, status );
+ nbuff++;
+ if( nbuff==maxrows ) {
+ ffptbb( outfptr, outloc, 1L, rdlen*nbuff, buffer, status );
+ outloc += nbuff;
+ nbuff = 0;
+ }
+ }
+ inloc++;
+ } while( !*status && inloc<=inExt.numRows );
+
+ if( nbuff ) {
+ ffptbb( outfptr, outloc, 1L, rdlen*nbuff, buffer, status );
+ outloc += nbuff;
+ }
+
+ if( infptr==outfptr ) {
+
+ if( outloc<=inExt.numRows )
+ ffdrow( infptr, outloc, inExt.numRows-outloc+1, status );
+
+ } else if( inExt.heapSize && nGood ) {
+
+ /* Copy heap, if it exists and at least one row copied */
+
+ /********************************************************/
+ /* Get location information from the output extension */
+ /********************************************************/
+
+ if( outfptr->HDUposition != (outfptr->Fptr)->curhdu )
+ ffmahd( outfptr, (outfptr->HDUposition) + 1, NULL, status );
+ outExt.dataStart = (outfptr->Fptr)->datastart;
+ outExt.heapStart = (outfptr->Fptr)->heapstart;
+
+ /*************************************************/
+ /* Insert more space into outfptr if necessary */
+ /*************************************************/
+
+ hsize = outExt.heapStart + outExt.heapSize;
+ freespace = ( ( (hsize + 2879) / 2880) * 2880) - hsize;
+ ntodo = inExt.heapSize;
+
+ if ( (freespace - ntodo) < 0) { /* not enough existing space? */
+ ntodo = (ntodo - freespace + 2879) / 2880; /* number of blocks */
+ ffiblk(outfptr, ntodo, 1, status); /* insert the blocks */
+ }
+ ffukyj( outfptr, "PCOUNT", inExt.heapSize+outExt.heapSize,
+ NULL, status );
+
+ /*******************************************************/
+ /* Get location information from the input extension */
+ /*******************************************************/
+
+ if( infptr->HDUposition != (infptr->Fptr)->curhdu )
+ ffmahd( infptr, (infptr->HDUposition) + 1, NULL, status );
+ inExt.dataStart = (infptr->Fptr)->datastart;
+ inExt.heapStart = (infptr->Fptr)->heapstart;
+
+ /**********************************/
+ /* Finally copy heap to outfptr */
+ /**********************************/
+
+ ntodo = inExt.heapSize;
+ inbyteloc = inExt.heapStart + inExt.dataStart;
+ outbyteloc = outExt.heapStart + outExt.dataStart + outExt.heapSize;
+
+ while ( ntodo && !*status ) {
+ rdlen = minvalue(ntodo,500000);
+ ffmbyt( infptr, inbyteloc, REPORT_EOF, status );
+ ffgbyt( infptr, rdlen, buffer, status );
+ ffmbyt( outfptr, outbyteloc, IGNORE_EOF, status );
+ ffpbyt( outfptr, rdlen, buffer, status );
+ inbyteloc += rdlen;
+ outbyteloc += rdlen;
+ ntodo -= rdlen;
+ }
+
+ /***********************************************************/
+ /* But must update DES if data is being appended to a */
+ /* pre-existing heap space. Edit each new entry in file */
+ /***********************************************************/
+
+ if( outExt.heapSize ) {
+ long repeat, offset, j;
+ int i;
+ for( i=1; i<=(outfptr->Fptr)->tfield; i++ ) {
+ if( (outfptr->Fptr)->tableptr[i-1].tdatatype<0 ) {
+ for( j=outExt.numRows+1; j<=outExt.numRows+nGood; j++ ) {
+ ffgdes( outfptr, i, j, &repeat, &offset, status );
+ offset += outExt.heapSize;
+ ffpdes( outfptr, i, j, repeat, offset, status );
+ }
+ }
+ }
+ }
+
+ } /* End of HEAP copy */
+
+ free(buffer);
+ }
+
+ free(Info.dataPtr);
+ ffcprs();
+
+ ffcmph(outfptr, status); /* compress heap, deleting any orphaned data */
+ return(*status);
+}
+
+/*---------------------------------------------------------------------------*/
+int ffcrow( fitsfile *fptr, /* I - Input FITS file */
+ int datatype, /* I - Datatype to return results as */
+ char *expr, /* I - Arithmetic expression */
+ long firstrow, /* I - First row to evaluate */
+ long nelements, /* I - Number of elements to return */
+ void *nulval, /* I - Ptr to value to use as UNDEF */
+ void *array, /* O - Array of results */
+ int *anynul, /* O - Were any UNDEFs encountered? */
+ int *status ) /* O - Error status */
+/* */
+/* Calculate an expression for the indicated rows of a table, returning */
+/* the results, cast as datatype (TSHORT, TDOUBLE, etc), in array. If */
+/* nulval==NULL, UNDEFs will be zeroed out. For vector results, the number */
+/* of elements returned may be less than nelements if nelements is not an */
+/* even multiple of the result dimension. Call fftexp to obtain the */
+/* dimensions of the results. */
+/*---------------------------------------------------------------------------*/
+{
+ parseInfo Info;
+ int naxis;
+ long nelem1, naxes[MAXDIMS];
+
+ if( *status ) return( *status );
+
+ if( ffiprs( fptr, 0, expr, MAXDIMS, &Info.datatype, &nelem1, &naxis,
+ naxes, status ) ) {
+ ffcprs();
+ return( *status );
+ }
+ if( nelem1<0 ) nelem1 = - nelem1;
+
+ if( nelements<nelem1 ) {
+ ffcprs();
+ ffpmsg("Array not large enough to hold at least one row of data.");
+ return( *status = PARSE_LRG_VECTOR );
+ }
+
+ firstrow = (firstrow>1 ? firstrow : 1);
+
+ if( datatype ) Info.datatype = datatype;
+
+ Info.dataPtr = array;
+ Info.nullPtr = nulval;
+ Info.maxRows = nelements / nelem1;
+
+ if( ffiter( gParse.nCols, gParse.colData, firstrow-1, 0,
+ parse_data, (void*)&Info, status ) == -1 )
+ *status=0; /* -1 indicates exitted without error before end... OK */
+
+ *anynul = Info.anyNull;
+ ffcprs();
+ return( *status );
+}
+
+/*--------------------------------------------------------------------------*/
+int ffcalc( fitsfile *infptr, /* I - Input FITS file */
+ char *expr, /* I - Arithmetic expression */
+ fitsfile *outfptr, /* I - Output fits file */
+ char *parName, /* I - Name of output parameter */
+ char *parInfo, /* I - Extra information on parameter */
+ int *status ) /* O - Error status */
+/* */
+/* Evaluate an expression for all rows of a table. Call ffcalc_rng with */
+/* a row range of 1-MAX. */
+{
+ long start=1, end=LONG_MAX;
+
+ return ffcalc_rng( infptr, expr, outfptr, parName, parInfo,
+ 1, &start, &end, status );
+}
+
+/*--------------------------------------------------------------------------*/
+int ffcalc_rng( fitsfile *infptr, /* I - Input FITS file */
+ char *expr, /* I - Arithmetic expression */
+ fitsfile *outfptr, /* I - Output fits file */
+ char *parName, /* I - Name of output parameter */
+ char *parInfo, /* I - Extra information on parameter */
+ int nRngs, /* I - Row range info */
+ long *start, /* I - Row range info */
+ long *end, /* I - Row range info */
+ int *status ) /* O - Error status */
+/* */
+/* Evaluate an expression using the data in the input FITS file and place */
+/* the results into either a column or keyword in the output fits file, */
+/* depending on the value of parName (keywords normally prefixed with '#') */
+/* and whether the expression evaluates to a constant or a table column. */
+/* The logic is as follows: */
+/* (1) If a column exists with name, parName, put results there. */
+/* (2) If parName starts with '#', as in #NAXIS, put result there, */
+/* with parInfo used as the comment. If expression does not evaluate */
+/* to a constant, flag an error. */
+/* (3) If a keyword exists with name, parName, and expression is a */
+/* constant, put result there, using parInfo as the new comment. */
+/* (4) Else, create a new column with name parName and TFORM parInfo. */
+/* If parInfo is NULL, use a default data type for the column. */
+/*--------------------------------------------------------------------------*/
+{
+ parseInfo Info;
+ int naxis, constant, typecode, newNullKwd=0;
+ long nelem, naxes[MAXDIMS], repeat, width;
+ int col_cnt, colNo;
+ Node *result;
+ char card[81], tform[16], nullKwd[9], tdimKwd[9];
+ int hdutype;
+
+ if( *status ) return( *status );
+
+ if( ffiprs( infptr, 0, expr, MAXDIMS, &Info.datatype, &nelem, &naxis,
+ naxes, status ) ) {
+ ffcprs();
+ return( *status );
+ }
+ if( nelem<0 ) {
+ constant = 1;
+ nelem = -nelem;
+ } else
+ constant = 0;
+
+ /* Case (1): If column exists put it there */
+
+ colNo = 0;
+ if( ffgcno( outfptr, CASEINSEN, parName, &colNo, status )==COL_NOT_FOUND ) {
+
+ /* Output column doesn't exist. Test for keyword. */
+
+ /* Case (2): Does parName indicate result should be put into keyword */
+
+ *status = 0;
+ if( parName[0]=='#' ) {
+ if( ! constant ) {
+ ffcprs();
+ ffpmsg( "Cannot put tabular result into keyword (ffcalc)" );
+ return( *status = PARSE_BAD_TYPE );
+ }
+ parName++;
+
+ } else if( constant ) {
+
+ /* Case (3): Does a keyword named parName already exist */
+
+ if( ffgcrd( outfptr, parName, card, status )==KEY_NO_EXIST ) {
+ colNo = -1;
+ } else if( *status ) {
+ ffcprs();
+ return( *status );
+ }
+
+ } else
+ colNo = -1;
+
+ if( colNo<0 ) {
+
+ /* Case (4): Create new column */
+
+ *status = 0;
+ ffgncl( outfptr, &colNo, status );
+ colNo++;
+ ffghdt( outfptr, &hdutype, status );
+ if( parInfo==NULL || *parInfo=='\0' ) {
+ /* Figure out best default column type */
+ if( hdutype==BINARY_TBL ) {
+ sprintf(tform,"%ld",nelem);
+ switch( Info.datatype ) {
+ case TLOGICAL: strcat(tform,"L"); break;
+ case TLONG: strcat(tform,"J"); break;
+ case TDOUBLE: strcat(tform,"D"); break;
+ case TSTRING: strcat(tform,"A"); break;
+ case TBIT: strcat(tform,"X"); break;
+ }
+ } else {
+ switch( Info.datatype ) {
+ case TLOGICAL:
+ ffcprs();
+ ffpmsg("Cannot create LOGICAL column in ASCII table");
+ return( *status = NOT_BTABLE );
+ break;
+ case TLONG: strcpy(tform,"I11"); break;
+ case TDOUBLE: strcpy(tform,"D23.15"); break;
+ case TSTRING:
+ case TBIT: sprintf(tform,"A%ld",nelem); break;
+ }
+ }
+ parInfo = tform;
+ } else if( !(isdigit((int) *parInfo)) && hdutype==BINARY_TBL ) {
+ if( Info.datatype==TBIT && *parInfo=='B' )
+ nelem = (nelem+7)/8;
+ sprintf(tform,"%ld%s",nelem,parInfo);
+ parInfo = tform;
+ }
+ fficol( outfptr, colNo, parName, parInfo, status );
+ if( naxis>1 )
+ ffptdm( outfptr, colNo, naxis, naxes, status );
+
+ /* Setup TNULLn keyword in case NULLs are encountered */
+
+ ffkeyn("TNULL", colNo, nullKwd, status);
+ if( ffgcrd( outfptr, nullKwd, card, status )==KEY_NO_EXIST ) {
+ *status = 0;
+ if( hdutype==BINARY_TBL ) {
+ long nullVal=0;
+ fits_binary_tform( parInfo, &typecode, &repeat, &width, status );
+ if( typecode==TBYTE )
+ nullVal = UCHAR_MAX;
+ else if( typecode==TSHORT )
+ nullVal = SHRT_MIN;
+ else if( typecode==TINT )
+ nullVal = INT_MIN;
+ else if( typecode==TLONG )
+ nullVal = LONG_MIN;
+ if( nullVal ) {
+ ffpkyj( outfptr, nullKwd, nullVal, "Null value", status );
+ fits_set_btblnull( outfptr, colNo, nullVal, status );
+ newNullKwd = 1;
+ }
+ } else if( hdutype==ASCII_TBL ) {
+ ffpkys( outfptr, nullKwd, "NULL", "Null value string", status );
+ fits_set_atblnull( outfptr, colNo, "NULL", status );
+ newNullKwd = 1;
+ }
+ }
+
+ }
+
+ } else if( *status ) {
+ ffcprs();
+ return( *status );
+ } else {
+
+ /********************************************************/
+ /* Check if a TDIM keyword should be written/updated. */
+ /********************************************************/
+
+ ffkeyn("TDIM", colNo, tdimKwd, status);
+ ffgcrd( outfptr, tdimKwd, card, status );
+ if( *status==0 ) {
+ /* TDIM exists, so update it with result's dimension */
+ ffptdm( outfptr, colNo, naxis, naxes, status );
+ } else if( *status==KEY_NO_EXIST ) {
+ /* TDIM does not exist, so clear error stack and */
+ /* write a TDIM only if result is multi-dimensional */
+ *status = 0;
+ ffcmsg();
+ if( naxis>1 )
+ ffptdm( outfptr, colNo, naxis, naxes, status );
+ }
+ if( *status ) {
+ /* Either some other error happened in ffgcrd */
+ /* or one happened in ffptdm */
+ ffcprs();
+ return( *status );
+ }
+
+ }
+
+ if( colNo>0 ) {
+
+ /* Output column exists (now)... put results into it */
+
+ int anyNull = 0;
+ int nPerLp, i;
+ long totaln;
+
+ ffgkyj(infptr, "NAXIS2", &totaln, 0, status);
+
+ /*************************************/
+ /* Create new iterator Output Column */
+ /*************************************/
+
+ col_cnt = gParse.nCols;
+ if( allocateCol( col_cnt, status ) ) {
+ ffcprs();
+ return( *status );
+ }
+
+ fits_iter_set_by_num( gParse.colData+col_cnt, outfptr,
+ colNo, 0, OutputCol );
+ gParse.nCols++;
+
+ for( i=0; i<nRngs; i++ ) {
+ Info.dataPtr = NULL;
+ Info.maxRows = end[i]-start[i]+1;
+
+ /*
+ If there is only 1 range, and it includes all the rows,
+ and there are 10 or more rows, then set nPerLp = 0 so
+ that the iterator function will dynamically choose the
+ most efficient number of rows to process in each loop.
+ Otherwise, set nPerLp to the number of rows in this range.
+ */
+
+ if( (Info.maxRows >= 10) && (nRngs == 1) &&
+ (start[0] == 1) && (end[0] == totaln))
+ nPerLp = 0;
+ else
+ nPerLp = Info.maxRows;
+
+ if( ffiter( gParse.nCols, gParse.colData, start[i]-1,
+ nPerLp, parse_data, (void*)&Info, status ) == -1 )
+ *status = 0;
+ else if( *status ) {
+ ffcprs();
+ return( *status );
+ }
+ if( Info.anyNull ) anyNull = 1;
+ }
+
+ if( newNullKwd && !anyNull ) {
+ ffdkey( outfptr, nullKwd, status );
+ }
+
+ } else {
+
+ /* Put constant result into keyword */
+
+ result = gParse.Nodes + gParse.resultNode;
+ switch( Info.datatype ) {
+ case TDOUBLE:
+ ffukyd( outfptr, parName, result->value.data.dbl, 15,
+ parInfo, status );
+ break;
+ case TLONG:
+ ffukyj( outfptr, parName, result->value.data.lng, parInfo, status );
+ break;
+ case TLOGICAL:
+ ffukyl( outfptr, parName, result->value.data.log, parInfo, status );
+ break;
+ case TBIT:
+ case TSTRING:
+ ffukys( outfptr, parName, result->value.data.str, parInfo, status );
+ break;
+ }
+ }
+
+ ffcprs();
+ return( *status );
+}
+
+/*--------------------------------------------------------------------------*/
+int fftexp( fitsfile *fptr, /* I - Input FITS file */
+ char *expr, /* I - Arithmetic expression */
+ int maxdim, /* I - Max Dimension of naxes */
+ int *datatype, /* O - Data type of result */
+ long *nelem, /* O - Vector length of result */
+ int *naxis, /* O - # of dimensions of result */
+ long *naxes, /* O - Size of each dimension */
+ int *status ) /* O - Error status */
+/* */
+/* Evaluate the given expression and return information on the result. */
+/*--------------------------------------------------------------------------*/
+{
+ ffiprs( fptr, 0, expr, maxdim, datatype, nelem, naxis, naxes, status );
+ ffcprs();
+ return( *status );
+}
+
+/*--------------------------------------------------------------------------*/
+int ffiprs( fitsfile *fptr, /* I - Input FITS file */
+ int compressed, /* I - Is FITS file hkunexpanded? */
+ char *expr, /* I - Arithmetic expression */
+ int maxdim, /* I - Max Dimension of naxes */
+ int *datatype, /* O - Data type of result */
+ long *nelem, /* O - Vector length of result */
+ int *naxis, /* O - # of dimensions of result */
+ long *naxes, /* O - Size of each dimension */
+ int *status ) /* O - Error status */
+/* */
+/* Initialize the parser and determine what type of result the expression */
+/* produces. */
+/*--------------------------------------------------------------------------*/
+{
+ Node *result;
+ int i,lexpr, tstatus = 0;
+ static iteratorCol dmyCol;
+
+ if( *status ) return( *status );
+
+ /* Initialize the Parser structure */
+
+ gParse.def_fptr = fptr;
+ gParse.compressed = compressed;
+ gParse.nCols = 0;
+ gParse.colData = NULL;
+ gParse.varData = NULL;
+ gParse.getData = find_column;
+ gParse.loadData = load_column;
+ gParse.Nodes = NULL;
+ gParse.nNodesAlloc= 0;
+ gParse.nNodes = 0;
+ gParse.status = 0;
+
+ if( ffgkyj(fptr, "NAXIS2", &gParse.totalRows, 0, &tstatus) )
+ {
+ /* this might be a 1D or null image with no NAXIS2 keyword */
+ gParse.totalRows = 0;
+ }
+ /* Copy expression into parser... read from file if necessary */
+
+ if( expr[0]=='@' ) {
+ if( ffimport_file( expr+1, &gParse.expr, status ) ) return( *status );
+ lexpr = strlen(gParse.expr);
+ } else {
+ lexpr = strlen(expr);
+ gParse.expr = (char*)malloc( (2+lexpr)*sizeof(char));
+ strcpy(gParse.expr,expr);
+ }
+ strcat(gParse.expr + lexpr,"\n");
+ gParse.index = 0;
+ gParse.is_eobuf = 0;
+
+ /* Parse the expression, building the Nodes and determing */
+ /* which columns are neded and what data type is returned */
+
+ ffrestart(NULL);
+ if( ffparse() ) {
+ return( *status = PARSE_SYNTAX_ERR );
+ }
+ /* Check results */
+
+ *status = gParse.status;
+ if( *status ) return(*status);
+
+ if( !gParse.nNodes ) {
+ ffpmsg("Blank expression");
+ return( *status = PARSE_SYNTAX_ERR );
+ }
+ if( !gParse.nCols ) {
+ dmyCol.fptr = fptr; /* This allows iterator to know value of */
+ gParse.colData = &dmyCol; /* fptr when no columns are referenced */
+ }
+
+ result = gParse.Nodes + gParse.resultNode;
+
+ *naxis = result->value.naxis;
+ *nelem = result->value.nelem;
+ for( i=0; i<*naxis && i<maxdim; i++ )
+ naxes[i] = result->value.naxes[i];
+
+ switch( result->type ) {
+ case BOOLEAN:
+ *datatype = TLOGICAL;
+ break;
+ case LONG:
+ *datatype = TLONG;
+ break;
+ case DOUBLE:
+ *datatype = TDOUBLE;
+ break;
+ case BITSTR:
+ *datatype = TBIT;
+ break;
+ case STRING:
+ *datatype = TSTRING;
+ break;
+ default:
+ *datatype = 0;
+ ffpmsg("Bad return data type");
+ *status = gParse.status = PARSE_BAD_TYPE;
+ break;
+ }
+ gParse.datatype = *datatype;
+ free(gParse.expr);
+
+ if( result->operation==CONST_OP ) *nelem = - *nelem;
+ return(*status);
+}
+
+/*--------------------------------------------------------------------------*/
+void ffcprs( void ) /* No parameters */
+/* */
+/* Clear the parser, making it ready to accept a new expression. */
+/*--------------------------------------------------------------------------*/
+{
+ int col, node, i;
+
+ if( gParse.nCols > 0 ) {
+ free( gParse.colData );
+ for( col=0; col<gParse.nCols; col++ ) {
+ if( gParse.varData[col].undef == NULL ) continue;
+ if( gParse.varData[col].type == BITSTR )
+ free( ((char**)gParse.varData[col].data)[0] );
+ free( gParse.varData[col].undef );
+ }
+ free( gParse.varData );
+ gParse.nCols = 0;
+ }
+
+ if( gParse.nNodes > 0 ) {
+ node = gParse.nNodes;
+ while( node-- ) {
+ i = gParse.Nodes[node].SubNodes[0];
+ if( gParse.Nodes[node].operation==gtifilt_fct ) {
+ free( gParse.Nodes[ i ].value.data.ptr );
+ }
+ else if( gParse.Nodes[node].operation==regfilt_fct ) {
+ fits_free_region( (SAORegion *)gParse.Nodes[ i ].value.data.ptr );
+ }
+ }
+ gParse.nNodes = 0;
+ }
+ if( gParse.Nodes ) free( gParse.Nodes );
+ gParse.Nodes = NULL;
+}
+
+/*---------------------------------------------------------------------------*/
+int parse_data( long totalrows, /* I - Total rows to be processed */
+ long offset, /* I - Number of rows skipped at start*/
+ long firstrow, /* I - First row of this iteration */
+ long nrows, /* I - Number of rows in this iter */
+ int nCols, /* I - Number of columns in use */
+ iteratorCol *colData, /* IO- Column information/data */
+ void *userPtr ) /* I - Data handling instructions */
+/* */
+/* Iterator work function which calls the parser and copies the results */
+/* into either an OutputCol or a data pointer supplied in the userPtr */
+/* structure. */
+/*---------------------------------------------------------------------------*/
+{
+ int status, constant=0, anyNullThisTime=0;
+ long jj, kk, idx, remain, ntodo;
+ Node *result;
+
+ /* declare variables static to preserve their values between calls */
+ static void *Data, *Null;
+ static int datasize;
+ static long lastRow, jnull, repeat, resDataSize;
+ static parseInfo *userInfo;
+ static long zeros[4] = {0,0,0,0};
+
+ /*--------------------------------------------------------*/
+ /* Initialization procedures: execute on the first call */
+ /*--------------------------------------------------------*/
+ if (firstrow == offset+1)
+ {
+ userInfo = (parseInfo*)userPtr;
+ userInfo->anyNull = 0;
+
+ if( userInfo->maxRows>0 )
+ userInfo->maxRows = minvalue(totalrows,userInfo->maxRows);
+ else if( userInfo->maxRows<0 )
+ userInfo->maxRows = totalrows;
+ else
+ userInfo->maxRows = nrows;
+
+ lastRow = firstrow + userInfo->maxRows - 1;
+
+ if( userInfo->dataPtr==NULL ) {
+
+ if( colData[nCols-1].iotype == InputCol ) {
+ ffpmsg("Output column for parser results not found!");
+ return( PARSE_NO_OUTPUT );
+ }
+ /* Data gets set later */
+ Null = colData[nCols-1].array;
+ userInfo->datatype = colData[nCols-1].datatype;
+
+ /* Check for a TNULL keyword for output column */
+
+ status = 0;
+ jnull = 0L;
+ ffgknj( colData[nCols-1].fptr, "TNULL", colData[nCols-1].colnum,
+ 1, &jnull, (int*)&jj, &status );
+ if( status==BAD_INTKEY ) {
+ /* Probably ASCII table with text TNULL keyword */
+ switch( userInfo->datatype ) {
+ case TSHORT: jnull = SHRT_MIN; break;
+ case TINT: jnull = INT_MIN; break;
+ case TLONG: jnull = LONG_MIN; break;
+ }
+ }
+ repeat = colData[nCols-1].repeat;
+
+ } else {
+
+ Data = userInfo->dataPtr;
+ Null = (userInfo->nullPtr ? userInfo->nullPtr : zeros);
+ repeat = gParse.Nodes[gParse.resultNode].value.nelem;
+
+ }
+
+ /* Determine the size of each element of the returned result */
+
+ switch( userInfo->datatype ) {
+ case TBIT: /* Fall through to TBYTE */
+ case TLOGICAL: /* Fall through to TBYTE */
+ case TBYTE: datasize = sizeof(char); break;
+ case TSHORT: datasize = sizeof(short); break;
+ case TINT: datasize = sizeof(int); break;
+ case TLONG: datasize = sizeof(long); break;
+ case TFLOAT: datasize = sizeof(float); break;
+ case TDOUBLE: datasize = sizeof(double); break;
+ case TSTRING: datasize = sizeof(char*); break;
+ }
+
+ /* Determine the size of each element of the calculated result */
+ /* (only matters for numeric/logical data) */
+
+ switch( gParse.Nodes[gParse.resultNode].type ) {
+ case BOOLEAN: resDataSize = sizeof(char); break;
+ case LONG: resDataSize = sizeof(long); break;
+ case DOUBLE: resDataSize = sizeof(double); break;
+ }
+ }
+
+ /*-------------------------------------------*/
+ /* Main loop: process all the rows of data */
+ /*-------------------------------------------*/
+
+ /* If writing to output column, set first element to appropriate */
+ /* null value. If no NULLs encounter, zero out before returning. */
+
+ if( userInfo->dataPtr == NULL ) {
+ /* First, reset Data pointer to start of output array */
+ Data = (char*)colData[nCols-1].array + datasize;
+
+ switch( userInfo->datatype ) {
+ case TLOGICAL: *(char *)Null = 'U'; break;
+ case TBYTE: *(char *)Null = (char )jnull; break;
+ case TSHORT: *(short *)Null = (short)jnull; break;
+ case TINT: *(int *)Null = (int )jnull; break;
+ case TLONG: *(long *)Null = (long )jnull; break;
+ case TFLOAT: *(float *)Null = FLOATNULLVALUE; break;
+ case TDOUBLE: *(double*)Null = DOUBLENULLVALUE; break;
+ case TSTRING: (*(char **)Null)[0] = '\1';
+ (*(char **)Null)[1] = '\0'; break;
+ }
+ }
+
+ /* Alter nrows in case calling routine didn't want to do all rows */
+
+ nrows = minvalue(nrows,lastRow-firstrow+1);
+
+ Setup_DataArrays( nCols, colData, firstrow, nrows );
+
+ /* Parser allocates arrays for each column and calculation it performs. */
+ /* Limit number of rows processed during each pass to reduce memory */
+ /* requirements... In most cases, iterator will limit rows to less */
+ /* than 2500 rows per iteration, so this is really only relevant for */
+ /* hk-compressed files which must be decompressed in memory and sent */
+ /* whole to parse_data in a single iteration. */
+
+ remain = nrows;
+ while( remain ) {
+
+ ntodo = minvalue(remain,2500);
+ Evaluate_Parser ( firstrow, ntodo );
+ if( gParse.status ) break;
+
+ firstrow += ntodo;
+ remain -= ntodo;
+
+ /* Copy results into data array */
+
+ result = gParse.Nodes + gParse.resultNode;
+ if( result->operation==CONST_OP ) constant = 1;
+
+ switch( result->type ) {
+
+ case BOOLEAN:
+ case LONG:
+ case DOUBLE:
+ if( constant ) {
+ char undef=0;
+ for( kk=0; kk<ntodo; kk++ )
+ for( jj=0; jj<repeat; jj++ )
+ ffcvtn( gParse.datatype,
+ &(result->value.data),
+ &undef, result->value.nelem /* 1 */,
+ userInfo->datatype, Null,
+ (char*)Data + (kk*repeat+jj)*datasize,
+ &anyNullThisTime, &gParse.status );
+ } else {
+ if ( repeat == result->value.nelem ) {
+ ffcvtn( gParse.datatype,
+ result->value.data.ptr,
+ result->value.undef,
+ result->value.nelem*ntodo,
+ userInfo->datatype, Null, Data,
+ &anyNullThisTime, &gParse.status );
+ } else if( result->value.nelem == 1 ) {
+ for( kk=0; kk<ntodo; kk++ )
+ for( jj=0; jj<repeat; jj++ ) {
+ ffcvtn( gParse.datatype,
+ (char*)result->value.data.ptr + kk*resDataSize,
+ (char*)result->value.undef + kk,
+ 1, userInfo->datatype, Null,
+ (char*)Data + (kk*repeat+jj)*datasize,
+ &anyNullThisTime, &gParse.status );
+ }
+ } else {
+ int nCopy;
+ nCopy = minvalue( repeat, result->value.nelem );
+ for( kk=0; kk<ntodo; kk++ ) {
+ ffcvtn( gParse.datatype,
+ (char*)result->value.data.ptr
+ + kk*result->value.nelem*resDataSize,
+ (char*)result->value.undef
+ + kk*result->value.nelem,
+ nCopy, userInfo->datatype, Null,
+ (char*)Data + (kk*repeat)*datasize,
+ &anyNullThisTime, &gParse.status );
+ if( nCopy < repeat ) {
+ memset( (char*)Data + (kk*repeat+nCopy)*datasize,
+ 0, (repeat-nCopy)*datasize);
+ }
+ }
+
+ }
+ if( result->operation>0 ) {
+ free( result->value.data.ptr );
+ }
+ }
+ if( gParse.status==OVERFLOW_ERR ) {
+ gParse.status = NUM_OVERFLOW;
+ ffpmsg("Numerical overflow while converting expression to necessary datatype");
+ }
+ break;
+
+ case BITSTR:
+ switch( userInfo->datatype ) {
+ case TBYTE:
+ idx = -1;
+ for( kk=0; kk<ntodo; kk++ ) {
+ for( jj=0; jj<result->value.nelem; jj++ ) {
+ if( jj%8 == 0 )
+ ((char*)Data)[++idx] = 0;
+ if( constant ) {
+ if( result->value.data.str[jj]=='1' )
+ ((char*)Data)[idx] |= 128>>(jj%8);
+ } else {
+ if( result->value.data.strptr[kk][jj]=='1' )
+ ((char*)Data)[idx] |= 128>>(jj%8);
+ }
+ }
+ }
+ break;
+ case TBIT:
+ case TLOGICAL:
+ if( constant ) {
+ for( kk=0; kk<ntodo; kk++ )
+ for( jj=0; jj<result->value.nelem; jj++ ) {
+ ((char*)Data)[ jj+kk*result->value.nelem ] =
+ ( result->value.data.str[jj]=='1' );
+ }
+ } else {
+ for( kk=0; kk<ntodo; kk++ )
+ for( jj=0; jj<result->value.nelem; jj++ ) {
+ ((char*)Data)[ jj+kk*result->value.nelem ] =
+ ( result->value.data.strptr[kk][jj]=='1' );
+ }
+ }
+ break;
+ case TSTRING:
+ if( constant ) {
+ for( jj=0; jj<ntodo; jj++ ) {
+ strcpy( ((char**)Data)[jj], result->value.data.str );
+ }
+ } else {
+ for( jj=0; jj<ntodo; jj++ ) {
+ strcpy( ((char**)Data)[jj], result->value.data.strptr[jj] );
+ }
+ }
+ break;
+ default:
+ ffpmsg("Cannot convert bit expression to desired type.");
+ gParse.status = PARSE_BAD_TYPE;
+ break;
+ }
+ if( result->operation>0 ) {
+ free( result->value.data.strptr[0] );
+ free( result->value.data.strptr );
+ }
+ break;
+
+ case STRING:
+ if( userInfo->datatype==TSTRING ) {
+ if( constant ) {
+ for( jj=0; jj<ntodo; jj++ )
+ strcpy( ((char**)Data)[jj], result->value.data.str );
+ } else {
+ for( jj=0; jj<ntodo; jj++ )
+ if( result->value.undef[jj] ) {
+ anyNullThisTime = 1;
+ strcpy( ((char**)Data)[jj],
+ *(char **)Null );
+ } else {
+ strcpy( ((char**)Data)[jj],
+ result->value.data.strptr[jj] );
+ }
+ }
+ } else {
+ ffpmsg("Cannot convert string expression to desired type.");
+ gParse.status = PARSE_BAD_TYPE;
+ }
+ if( result->operation>0 ) {
+ free( result->value.data.strptr[0] );
+ free( result->value.data.strptr );
+ }
+ break;
+ }
+
+ if( gParse.status ) break;
+
+ /* Increment Data to point to where the next block should go */
+
+ if( result->type==BITSTR && userInfo->datatype==TBYTE )
+ Data = (char*)Data
+ + datasize * ( (result->value.nelem+7)/8 ) * ntodo;
+ else if( result->type==STRING )
+ Data = (char*)Data + datasize * ntodo;
+ else
+ Data = (char*)Data + datasize * ntodo * repeat;
+ }
+
+ /* If no NULLs encountered during this pass, set Null value to */
+ /* zero to make the writing of the output column data faster */
+
+ if( anyNullThisTime )
+ userInfo->anyNull = 1;
+ else if( userInfo->dataPtr == NULL ) {
+ if( userInfo->datatype == TSTRING )
+ memcpy( *(char **)Null, zeros, 2 );
+ else
+ memcpy( Null, zeros, datasize );
+ }
+
+ /*-------------------------------------------------------*/
+ /* Clean up procedures: after processing all the rows */
+ /*-------------------------------------------------------*/
+
+ if( firstrow - 1 == lastRow ) {
+ if( !gParse.status && userInfo->maxRows<totalrows ) return (-1);
+ }
+
+ return(gParse.status); /* return successful status */
+}
+
+static void Setup_DataArrays( int nCols, iteratorCol *cols,
+ long fRow, long nRows )
+ /***********************************************************************/
+ /* Setup the varData array in gParse to contain the fits column data. */
+ /* Then, allocate and initialize the necessary UNDEF arrays for each */
+ /* column used by the parser. */
+ /***********************************************************************/
+{
+ int i;
+ long nelem, len, row, idx;
+ char **bitStrs;
+ char **sptr;
+ char *barray;
+ long *iarray;
+ double *rarray;
+
+ gParse.firstDataRow = fRow;
+ gParse.nDataRows = nRows;
+
+ /* Resize and fill in UNDEF arrays for each column */
+
+ for( i=0; i<nCols; i++ ) {
+ if( cols[i].iotype == OutputCol ) continue;
+
+ nelem = gParse.varData[i].nelem;
+ len = nelem * nRows;
+
+ switch ( gParse.varData[i].type ) {
+
+ case BITSTR:
+ /* No need for UNDEF array, but must make string DATA array */
+ len = (nelem+1)*nRows; /* Count '\0' */
+ bitStrs = (char**)gParse.varData[i].data;
+ if( bitStrs ) free( bitStrs[0] );
+ free( bitStrs );
+ bitStrs = (char**)malloc( nRows*sizeof(char*) );
+ if( bitStrs==NULL ) {
+ gParse.varData[i].data = gParse.varData[i].undef = NULL;
+ gParse.status = MEMORY_ALLOCATION;
+ break;
+ }
+ bitStrs[0] = (char*)malloc( len*sizeof(char) );
+ if( bitStrs[0]==NULL ) {
+ free( bitStrs );
+ gParse.varData[i].data = gParse.varData[i].undef = NULL;
+ gParse.status = MEMORY_ALLOCATION;
+ break;
+ }
+
+ for( row=0; row<nRows; row++ ) {
+ bitStrs[row] = bitStrs[0] + row*(nelem+1);
+ idx = (row)*( (nelem+7)/8 ) + 1;
+ for(len=0; len<nelem; len++) {
+ if( ((char*)cols[i].array)[idx] & (1<<(7-len%8)) )
+ bitStrs[row][len] = '1';
+ else
+ bitStrs[row][len] = '0';
+ if( len%8==7 ) idx++;
+ }
+ bitStrs[row][len] = '\0';
+ }
+ gParse.varData[i].undef = (char*)bitStrs;
+ gParse.varData[i].data = (char*)bitStrs;
+ break;
+
+ case STRING:
+ sptr = (char**)cols[i].array;
+ free( gParse.varData[i].undef );
+ gParse.varData[i].undef = (char*)malloc( nRows*sizeof(char) );
+ if( gParse.varData[i].undef==NULL ) {
+ gParse.status = MEMORY_ALLOCATION;
+ break;
+ }
+ row = nRows;
+ while( row-- )
+ gParse.varData[i].undef[row] =
+ ( **sptr != '\0' && FSTRCMP( sptr[0], sptr[row+1] )==0 );
+ gParse.varData[i].data = sptr + 1;
+ break;
+
+ case BOOLEAN:
+ barray = (char*)cols[i].array;
+ free( gParse.varData[i].undef );
+ gParse.varData[i].undef = (char*)malloc( len*sizeof(char) );
+ if( gParse.varData[i].undef==NULL ) {
+ gParse.status = MEMORY_ALLOCATION;
+ break;
+ }
+ while( len-- ) {
+ gParse.varData[i].undef[len] =
+ ( barray[0]!=0 && barray[0]==barray[len+1] );
+ }
+ gParse.varData[i].data = barray + 1;
+ break;
+
+ case LONG:
+ iarray = (long*)cols[i].array;
+ free( gParse.varData[i].undef );
+ gParse.varData[i].undef = (char*)malloc( len*sizeof(char) );
+ if( gParse.varData[i].undef==NULL ) {
+ gParse.status = MEMORY_ALLOCATION;
+ break;
+ }
+ while( len-- ) {
+ gParse.varData[i].undef[len] =
+ ( iarray[0]!=0L && iarray[0]==iarray[len+1] );
+ }
+ gParse.varData[i].data = iarray + 1;
+ break;
+
+ case DOUBLE:
+ rarray = (double*)cols[i].array;
+ free( gParse.varData[i].undef );
+ gParse.varData[i].undef = (char*)malloc( len*sizeof(char) );
+ if( gParse.varData[i].undef==NULL ) {
+ gParse.status = MEMORY_ALLOCATION;
+ break;
+ }
+ while( len-- ) {
+ gParse.varData[i].undef[len] =
+ ( rarray[0]!=0.0 && rarray[0]==rarray[len+1]);
+ }
+ gParse.varData[i].data = rarray + 1;
+ break;
+ }
+
+ if( gParse.status ) { /* Deallocate NULL arrays of previous columns */
+ while( i-- ) {
+ if( gParse.varData[i].type==BITSTR )
+ free( ((char**)gParse.varData[i].data)[0] );
+ free( gParse.varData[i].undef );
+ gParse.varData[i].undef = NULL;
+ }
+ return;
+ }
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+int ffcvtn( int inputType, /* I - Data type of input array */
+ void *input, /* I - Input array of type inputType */
+ char *undef, /* I - Array of flags indicating UNDEF elems */
+ long ntodo, /* I - Number of elements to process */
+ int outputType, /* I - Data type of output array */
+ void *nulval, /* I - Ptr to value to use for UNDEF elements */
+ void *output, /* O - Output array of type outputType */
+ int *anynull, /* O - Any nulls flagged? */
+ int *status ) /* O - Error status */
+/* */
+/* Convert an array of any input data type to an array of any output */
+/* data type, using an array of UNDEF flags to assign nulvals to */
+/*--------------------------------------------------------------------------*/
+{
+ long i;
+
+ switch( outputType ) {
+
+ case TLOGICAL:
+ switch( inputType ) {
+ case TLOGICAL:
+ case TBYTE:
+ for( i=0; i<ntodo; i++ )
+ if( ((unsigned char*)input)[i] )
+ ((unsigned char*)output)[i] = 1;
+ else
+ ((unsigned char*)output)[i] = 0;
+ break;
+ case TSHORT:
+ for( i=0; i<ntodo; i++ )
+ if( ((short*)input)[i] )
+ ((unsigned char*)output)[i] = 1;
+ else
+ ((unsigned char*)output)[i] = 0;
+ break;
+ case TLONG:
+ for( i=0; i<ntodo; i++ )
+ if( ((long*)input)[i] )
+ ((unsigned char*)output)[i] = 1;
+ else
+ ((unsigned char*)output)[i] = 0;
+ break;
+ case TFLOAT:
+ for( i=0; i<ntodo; i++ )
+ if( ((float*)input)[i] )
+ ((unsigned char*)output)[i] = 1;
+ else
+ ((unsigned char*)output)[i] = 0;
+ break;
+ case TDOUBLE:
+ for( i=0; i<ntodo; i++ )
+ if( ((double*)input)[i] )
+ ((unsigned char*)output)[i] = 1;
+ else
+ ((unsigned char*)output)[i] = 0;
+ break;
+ default:
+ *status = BAD_DATATYPE;
+ break;
+ }
+ for(i=0;i<ntodo;i++) {
+ if( undef[i] ) {
+ ((unsigned char*)output)[i] = *(unsigned char*)nulval;
+ *anynull = 1;
+ }
+ }
+ break;
+
+ case TBYTE:
+ switch( inputType ) {
+ case TLOGICAL:
+ case TBYTE:
+ for( i=0; i<ntodo; i++ )
+ ((unsigned char*)output)[i] = ((unsigned char*)input)[i];
+ break;
+ case TSHORT:
+ fffi2i1((short*)input,ntodo,1.,0.,0,0,0,NULL,NULL,(unsigned char*)output,status);
+ break;
+ case TLONG:
+ for (i = 0; i < ntodo; i++) {
+ if( undef[i] ) {
+ ((unsigned char*)output)[i] = *(unsigned char*)nulval;
+ *anynull = 1;
+ } else {
+ if( ((long*)input)[i] < 0 ) {
+ *status = OVERFLOW_ERR;
+ ((unsigned char*)output)[i] = 0;
+ } else if( ((long*)input)[i] > UCHAR_MAX ) {
+ *status = OVERFLOW_ERR;
+ ((unsigned char*)output)[i] = UCHAR_MAX;
+ } else
+ ((unsigned char*)output)[i] =
+ (unsigned char) ((long*)input)[i];
+ }
+ }
+ return( *status );
+ break;
+ case TFLOAT:
+ fffr4i1((float*)input,ntodo,1.,0.,0,0,NULL,NULL,
+ (unsigned char*)output,status);
+ break;
+ case TDOUBLE:
+ fffr8i1((double*)input,ntodo,1.,0.,0,0,NULL,NULL,
+ (unsigned char*)output,status);
+ break;
+ default:
+ *status = BAD_DATATYPE;
+ break;
+ }
+ for(i=0;i<ntodo;i++) {
+ if( undef[i] ) {
+ ((unsigned char*)output)[i] = *(unsigned char*)nulval;
+ *anynull = 1;
+ }
+ }
+ break;
+
+ case TSHORT:
+ switch( inputType ) {
+ case TLOGICAL:
+ case TBYTE:
+ for( i=0; i<ntodo; i++ )
+ ((short*)output)[i] = ((unsigned char*)input)[i];
+ break;
+ case TSHORT:
+ for( i=0; i<ntodo; i++ )
+ ((short*)output)[i] = ((short*)input)[i];
+ break;
+ case TLONG:
+ for (i = 0; i < ntodo; i++) {
+ if( undef[i] ) {
+ ((short*)output)[i] = *(short*)nulval;
+ *anynull = 1;
+ } else {
+ if( ((long*)input)[i] < SHRT_MIN ) {
+ *status = OVERFLOW_ERR;
+ ((short*)output)[i] = SHRT_MIN;
+ } else if ( ((long*)input)[i] > SHRT_MAX ) {
+ *status = OVERFLOW_ERR;
+ ((short*)output)[i] = SHRT_MAX;
+ } else
+ ((short*)output)[i] = (short) ((long*)input)[i];
+ }
+ }
+ return( *status );
+ break;
+ case TFLOAT:
+ fffr4i2((float*)input,ntodo,1.,0.,0,0,NULL,NULL,
+ (short*)output,status);
+ break;
+ case TDOUBLE:
+ fffr8i2((double*)input,ntodo,1.,0.,0,0,NULL,NULL,
+ (short*)output,status);
+ break;
+ default:
+ *status = BAD_DATATYPE;
+ break;
+ }
+ for(i=0;i<ntodo;i++) {
+ if( undef[i] ) {
+ ((short*)output)[i] = *(short*)nulval;
+ *anynull = 1;
+ }
+ }
+ break;
+
+ case TINT:
+ switch( inputType ) {
+ case TLOGICAL:
+ case TBYTE:
+ for( i=0; i<ntodo; i++ )
+ ((int*)output)[i] = ((unsigned char*)input)[i];
+ break;
+ case TSHORT:
+ for( i=0; i<ntodo; i++ )
+ ((int*)output)[i] = ((short*)input)[i];
+ break;
+ case TLONG:
+ for( i=0; i<ntodo; i++ )
+ ((int*)output)[i] = ((long*)input)[i];
+ break;
+ case TFLOAT:
+ fffr4int((float*)input,ntodo,1.,0.,0,0,NULL,NULL,
+ (int*)output,status);
+ break;
+ case TDOUBLE:
+ fffr8int((double*)input,ntodo,1.,0.,0,0,NULL,NULL,
+ (int*)output,status);
+ break;
+ default:
+ *status = BAD_DATATYPE;
+ break;
+ }
+ for(i=0;i<ntodo;i++) {
+ if( undef[i] ) {
+ ((int*)output)[i] = *(int*)nulval;
+ *anynull = 1;
+ }
+ }
+ break;
+
+ case TLONG:
+ switch( inputType ) {
+ case TLOGICAL:
+ case TBYTE:
+ for( i=0; i<ntodo; i++ )
+ ((long*)output)[i] = ((unsigned char*)input)[i];
+ break;
+ case TSHORT:
+ for( i=0; i<ntodo; i++ )
+ ((long*)output)[i] = ((short*)input)[i];
+ break;
+ case TLONG:
+ for( i=0; i<ntodo; i++ )
+ ((long*)output)[i] = ((long*)input)[i];
+ break;
+ case TFLOAT:
+ fffr4i4((float*)input,ntodo,1.,0.,0,0,NULL,NULL,
+ (long*)output,status);
+ break;
+ case TDOUBLE:
+ fffr8i4((double*)input,ntodo,1.,0.,0,0,NULL,NULL,
+ (long*)output,status);
+ break;
+ default:
+ *status = BAD_DATATYPE;
+ break;
+ }
+ for(i=0;i<ntodo;i++) {
+ if( undef[i] ) {
+ ((long*)output)[i] = *(long*)nulval;
+ *anynull = 1;
+ }
+ }
+ break;
+
+ case TFLOAT:
+ switch( inputType ) {
+ case TLOGICAL:
+ case TBYTE:
+ for( i=0; i<ntodo; i++ )
+ ((float*)output)[i] = ((unsigned char*)input)[i];
+ break;
+ case TSHORT:
+ for( i=0; i<ntodo; i++ )
+ ((float*)output)[i] = ((short*)input)[i];
+ break;
+ case TLONG:
+ for( i=0; i<ntodo; i++ )
+ ((float*)output)[i] = ((long*)input)[i];
+ break;
+ case TFLOAT:
+ for( i=0; i<ntodo; i++ )
+ ((float*)output)[i] = ((float*)input)[i];
+ break;
+ case TDOUBLE:
+ fffr8r4((double*)input,ntodo,1.,0.,0,0,NULL,NULL,
+ (float*)output,status);
+ break;
+ default:
+ *status = BAD_DATATYPE;
+ break;
+ }
+ for(i=0;i<ntodo;i++) {
+ if( undef[i] ) {
+ ((float*)output)[i] = *(float*)nulval;
+ *anynull = 1;
+ }
+ }
+ break;
+
+ case TDOUBLE:
+ switch( inputType ) {
+ case TLOGICAL:
+ case TBYTE:
+ for( i=0; i<ntodo; i++ )
+ ((double*)output)[i] = ((unsigned char*)input)[i];
+ break;
+ case TSHORT:
+ for( i=0; i<ntodo; i++ )
+ ((double*)output)[i] = ((short*)input)[i];
+ break;
+ case TLONG:
+ for( i=0; i<ntodo; i++ )
+ ((double*)output)[i] = ((long*)input)[i];
+ break;
+ case TFLOAT:
+ for( i=0; i<ntodo; i++ )
+ ((double*)output)[i] = ((float*)input)[i];
+ break;
+ case TDOUBLE:
+ for( i=0; i<ntodo; i++ )
+ ((double*)output)[i] = ((double*)input)[i];
+ break;
+ default:
+ *status = BAD_DATATYPE;
+ break;
+ }
+ for(i=0;i<ntodo;i++) {
+ if( undef[i] ) {
+ ((double*)output)[i] = *(double*)nulval;
+ *anynull = 1;
+ }
+ }
+ break;
+
+ default:
+ *status = BAD_DATATYPE;
+ break;
+ }
+ return ( *status );
+}
+
+/*---------------------------------------------------------------------------*/
+int fffrwc( fitsfile *fptr, /* I - Input FITS file */
+ char *expr, /* I - Boolean expression */
+ char *timeCol, /* I - Name of time column */
+ char *parCol, /* I - Name of parameter column */
+ char *valCol, /* I - Name of value column */
+ long ntimes, /* I - Number of distinct times in file */
+ double *times, /* O - Array of times in file */
+ char *time_status, /* O - Array of boolean results */
+ int *status ) /* O - Error status */
+/* */
+/* Evaluate a boolean expression for each time in a compressed file, */
+/* returning an array of flags indicating which times evaluated to TRUE/FALSE*/
+/*---------------------------------------------------------------------------*/
+{
+ parseInfo Info;
+ long alen, width;
+ int parNo, typecode;
+ int naxis, constant, nCol=0;
+ long nelem, naxes[MAXDIMS], elem;
+ char result;
+
+ if( *status ) return( *status );
+
+ fits_get_colnum( fptr, CASEINSEN, timeCol, &gParse.timeCol, status );
+ fits_get_colnum( fptr, CASEINSEN, parCol, &gParse.parCol , status );
+ fits_get_colnum( fptr, CASEINSEN, valCol, &gParse.valCol, status );
+ if( *status ) return( *status );
+
+ if( ffiprs( fptr, 1, expr, MAXDIMS, &Info.datatype, &nelem,
+ &naxis, naxes, status ) ) {
+ ffcprs();
+ return( *status );
+ }
+ if( nelem<0 ) {
+ constant = 1;
+ nelem = -nelem;
+ nCol = gParse.nCols;
+ gParse.nCols = 0; /* Ignore all column references */
+ } else
+ constant = 0;
+
+ if( Info.datatype!=TLOGICAL || nelem!=1 ) {
+ ffcprs();
+ ffpmsg("Expression does not evaluate to a logical scalar.");
+ return( *status = PARSE_BAD_TYPE );
+ }
+
+ /*******************************************/
+ /* Allocate data arrays for each parameter */
+ /*******************************************/
+
+ parNo = gParse.nCols;
+ while( parNo-- ) {
+ switch( gParse.colData[parNo].datatype ) {
+ case TLONG:
+ if( (gParse.colData[parNo].array =
+ (long *)malloc( (ntimes+1)*sizeof(long) )) )
+ ((long*)gParse.colData[parNo].array)[0] = 1234554321;
+ else
+ *status = MEMORY_ALLOCATION;
+ break;
+ case TDOUBLE:
+ if( (gParse.colData[parNo].array =
+ (double *)malloc( (ntimes+1)*sizeof(double) )) )
+ ((double*)gParse.colData[parNo].array)[0] = DOUBLENULLVALUE;
+ else
+ *status = MEMORY_ALLOCATION;
+ break;
+ case TSTRING:
+ if( !fits_get_coltype( fptr, gParse.valCol, &typecode,
+ &alen, &width, status ) ) {
+ alen++;
+ if( (gParse.colData[parNo].array =
+ (char **)malloc( (ntimes+1)*sizeof(char*) )) ) {
+ if( (((char **)gParse.colData[parNo].array)[0] =
+ (char *)malloc( (ntimes+1)*sizeof(char)*alen )) ) {
+ for( elem=1; elem<=ntimes; elem++ )
+ ((char **)gParse.colData[parNo].array)[elem] =
+ ((char **)gParse.colData[parNo].array)[elem-1]+alen;
+ ((char **)gParse.colData[parNo].array)[0][0] = '\0';
+ } else {
+ free( gParse.colData[parNo].array );
+ *status = MEMORY_ALLOCATION;
+ }
+ } else {
+ *status = MEMORY_ALLOCATION;
+ }
+ }
+ break;
+ }
+ if( *status ) {
+ while( parNo-- ) {
+ if( gParse.colData[parNo].datatype==TSTRING )
+ free( ((char **)gParse.colData[parNo].array)[0] );
+ free( gParse.colData[parNo].array );
+ }
+ return( *status );
+ }
+ }
+
+ /**********************************************************************/
+ /* Read data from columns needed for the expression and then parse it */
+ /**********************************************************************/
+
+ if( !uncompress_hkdata( fptr, ntimes, times, status ) ) {
+ if( constant ) {
+ result = gParse.Nodes[gParse.resultNode].value.data.log;
+ elem = ntimes;
+ while( elem-- ) time_status[elem] = result;
+ } else {
+ Info.dataPtr = time_status;
+ Info.nullPtr = NULL;
+ Info.maxRows = ntimes;
+ *status = parse_data( ntimes, 0, 1, ntimes, gParse.nCols,
+ gParse.colData, (void*)&Info );
+ }
+ }
+
+ /************/
+ /* Clean up */
+ /************/
+
+ parNo = gParse.nCols;
+ while ( parNo-- ) {
+ if( gParse.colData[parNo].datatype==TSTRING )
+ free( ((char **)gParse.colData[parNo].array)[0] );
+ free( gParse.colData[parNo].array );
+ }
+
+ if( constant ) gParse.nCols = nCol;
+
+ ffcprs();
+ return(*status);
+}
+
+/*---------------------------------------------------------------------------*/
+int uncompress_hkdata( fitsfile *fptr,
+ long ntimes,
+ double *times,
+ int *status )
+/* */
+/* description */
+/*---------------------------------------------------------------------------*/
+{
+ char parName[256], *sPtr[1], found[1000];
+ int parNo, anynul;
+ long naxis2, row, currelem;
+ double currtime, newtime;
+
+ sPtr[0] = parName;
+ currelem = 0;
+ currtime = -1e38;
+
+ parNo=gParse.nCols;
+ while( parNo-- ) found[parNo] = 0;
+
+ if( ffgkyj( fptr, "NAXIS2", &naxis2, NULL, status ) ) return( *status );
+
+ for( row=1; row<=naxis2; row++ ) {
+ if( ffgcvd( fptr, gParse.timeCol, row, 1L, 1L, 0.0,
+ &newtime, &anynul, status ) ) return( *status );
+ if( newtime != currtime ) {
+ /* New time encountered... propogate parameters to next row */
+ if( currelem==ntimes ) {
+ ffpmsg("Found more unique time stamps than caller indicated");
+ return( *status = PARSE_BAD_COL );
+ }
+ times[currelem++] = currtime = newtime;
+ parNo = gParse.nCols;
+ while( parNo-- ) {
+ switch( gParse.colData[parNo].datatype ) {
+ case TLONG:
+ ((long*)gParse.colData[parNo].array)[currelem] =
+ ((long*)gParse.colData[parNo].array)[currelem-1];
+ break;
+ case TDOUBLE:
+ ((double*)gParse.colData[parNo].array)[currelem] =
+ ((double*)gParse.colData[parNo].array)[currelem-1];
+ break;
+ case TSTRING:
+ strcpy( ((char **)gParse.colData[parNo].array)[currelem],
+ ((char **)gParse.colData[parNo].array)[currelem-1] );
+ break;
+ }
+ }
+ }
+
+ if( ffgcvs( fptr, gParse.parCol, row, 1L, 1L, "",
+ sPtr, &anynul, status ) ) return( *status );
+ parNo = gParse.nCols;
+ while( parNo-- )
+ if( !strcasecmp( parName, gParse.varData[parNo].name ) ) break;
+
+ if( parNo>=0 ) {
+ found[parNo] = 1; /* Flag this parameter as found */
+ switch( gParse.colData[parNo].datatype ) {
+ case TLONG:
+ ffgcvj( fptr, gParse.valCol, row, 1L, 1L,
+ ((long*)gParse.colData[parNo].array)[0],
+ ((long*)gParse.colData[parNo].array)+currelem,
+ &anynul, status );
+ break;
+ case TDOUBLE:
+ ffgcvd( fptr, gParse.valCol, row, 1L, 1L,
+ ((double*)gParse.colData[parNo].array)[0],
+ ((double*)gParse.colData[parNo].array)+currelem,
+ &anynul, status );
+ break;
+ case TSTRING:
+ ffgcvs( fptr, gParse.valCol, row, 1L, 1L,
+ ((char**)gParse.colData[parNo].array)[0],
+ ((char**)gParse.colData[parNo].array)+currelem,
+ &anynul, status );
+ break;
+ }
+ if( *status ) return( *status );
+ }
+ }
+
+ if( currelem<ntimes ) {
+ ffpmsg("Found fewer unique time stamps than caller indicated");
+ return( *status = PARSE_BAD_COL );
+ }
+
+ /* Check for any parameters which were not located in the table */
+ parNo = gParse.nCols;
+ while( parNo-- )
+ if( !found[parNo] ) {
+ sprintf( parName, "Parameter not found: %-30s",
+ gParse.varData[parNo].name );
+ ffpmsg( parName );
+ *status = PARSE_SYNTAX_ERR;
+ }
+ return( *status );
+}
+
+/*---------------------------------------------------------------------------*/
+int ffffrw( fitsfile *fptr, /* I - Input FITS file */
+ char *expr, /* I - Boolean expression */
+ long *rownum, /* O - First row of table to eval to T */
+ int *status ) /* O - Error status */
+/* */
+/* Evaluate a boolean expression, returning the row number of the first */
+/* row which evaluates to TRUE */
+/*---------------------------------------------------------------------------*/
+{
+ int naxis, constant, dtype;
+ long nelem, naxes[MAXDIMS];
+ char result;
+
+ if( *status ) return( *status );
+
+ if( ffiprs( fptr, 0, expr, MAXDIMS, &dtype, &nelem, &naxis,
+ naxes, status ) ) {
+ ffcprs();
+ return( *status );
+ }
+ if( nelem<0 ) {
+ constant = 1;
+ nelem = -nelem;
+ } else
+ constant = 0;
+
+ if( dtype!=TLOGICAL || nelem!=1 ) {
+ ffcprs();
+ ffpmsg("Expression does not evaluate to a logical scalar.");
+ return( *status = PARSE_BAD_TYPE );
+ }
+
+ *rownum = 0;
+ if( constant ) { /* No need to call parser... have result from ffiprs */
+ result = gParse.Nodes[gParse.resultNode].value.data.log;
+ if( result ) {
+ /* Make sure there is at least 1 row in table */
+ ffgnrw( fptr, &nelem, status );
+ if( nelem )
+ *rownum = 1;
+ }
+ } else {
+ if( ffiter( gParse.nCols, gParse.colData, 0, 0,
+ ffffrw_work, (void*)rownum, status ) == -1 )
+ *status = 0; /* -1 indicates exitted without error before end... OK */
+ }
+
+ ffcprs();
+ return(*status);
+}
+
+/*---------------------------------------------------------------------------*/
+int ffffrw_work(long totalrows, /* I - Total rows to be processed */
+ long offset, /* I - Number of rows skipped at start*/
+ long firstrow, /* I - First row of this iteration */
+ long nrows, /* I - Number of rows in this iter */
+ int nCols, /* I - Number of columns in use */
+ iteratorCol *colData, /* IO- Column information/data */
+ void *userPtr ) /* I - Data handling instructions */
+/* */
+/* Iterator work function which calls the parser and searches for the */
+/* first row which evaluates to TRUE. */
+/*---------------------------------------------------------------------------*/
+{
+ long idx;
+ Node *result;
+
+ Evaluate_Parser( firstrow, nrows );
+
+ if( !gParse.status ) {
+
+ result = gParse.Nodes + gParse.resultNode;
+ if( result->operation==CONST_OP ) {
+
+ if( result->value.data.log ) {
+ *(long*)userPtr = firstrow;
+ return( -1 );
+ }
+
+ } else {
+
+ for( idx=0; idx<nrows; idx++ )
+ if( result->value.data.logptr[idx] && !result->value.undef[idx] ) {
+ *(long*)userPtr = firstrow + idx;
+ return( -1 );
+ }
+ }
+ }
+
+ return( gParse.status );
+}
+
+
+/*************************************************************************
+
+ Functions used by the evaluator to access FITS data
+ (find_column, find_keywd, allocateCol, load_column)
+
+ *************************************************************************/
+
+
+static int find_column( char *colName, void *itslval )
+{
+ FFSTYPE *thelval = (FFSTYPE*)itslval;
+ int col_cnt, status;
+ int colnum, typecode, type, hdutype;
+ long repeat, width;
+ fitsfile *fptr;
+ char temp[80];
+ double tzero,tscale;
+ int istatus;
+
+ if( *colName == '#' )
+ return( find_keywd( colName + 1, itslval ) );
+
+ fptr = gParse.def_fptr;
+ status = 0;
+ if( gParse.compressed )
+ colnum = gParse.valCol;
+ else
+ if( fits_get_colnum( fptr, CASEINSEN, colName, &colnum, &status ) ) {
+ if( status == COL_NOT_FOUND ) {
+ type = find_keywd( colName, itslval );
+ if( type != pERROR ) ffcmsg();
+ return( type );
+ }
+ gParse.status = status;
+ return pERROR;
+ }
+
+ if( fits_get_coltype( fptr, colnum, &typecode,
+ &repeat, &width, &status ) ) {
+ gParse.status = status;
+ return pERROR;
+ }
+
+ col_cnt = gParse.nCols;
+ if( allocateCol( col_cnt, &gParse.status ) ) return pERROR;
+ fits_iter_set_by_num( gParse.colData+col_cnt, fptr, colnum, 0, InputCol );
+
+ /* Make sure we don't overflow variable name array */
+ strncpy(gParse.varData[col_cnt].name,colName,MAXVARNAME);
+ gParse.varData[col_cnt].name[MAXVARNAME] = '\0';
+
+ switch( typecode ) {
+ case TBIT:
+ gParse.varData[col_cnt].type = BITSTR;
+ gParse.colData[col_cnt].datatype = TBYTE;
+ type = BITCOL;
+ break;
+ case TBYTE:
+ case TSHORT:
+ case TLONG:
+ /* The datatype of column with TZERO and TSCALE keywords might be
+ float or double.
+ */
+ sprintf(temp,"TZERO%d",colnum);
+ istatus = 0;
+ if(fits_read_key(fptr,TDOUBLE,temp,&tzero,NULL,&istatus)) {
+ tzero = 0.0;
+ }
+ sprintf(temp,"TSCAL%d",colnum);
+ istatus = 0;
+ if(fits_read_key(fptr,TDOUBLE,temp,&tscale,NULL,&istatus)) {
+ tscale = 1.0;
+ }
+ if (tscale == 1.0 && (tzero == 0.0 || tzero == 32768.0 )) {
+ gParse.varData[col_cnt].type = LONG;
+ gParse.colData[col_cnt].datatype = TLONG;
+ } else if (tscale == 1.0 && tzero == 2147483648.0 ) {
+ gParse.varData[col_cnt].type = LONG;
+ gParse.colData[col_cnt].datatype = TULONG;
+ } else {
+ gParse.varData[col_cnt].type = DOUBLE;
+ gParse.colData[col_cnt].datatype = TDOUBLE;
+ }
+ type = COLUMN;
+ break;
+ case TFLOAT:
+ case TDOUBLE:
+ gParse.varData[col_cnt].type = DOUBLE;
+ gParse.colData[col_cnt].datatype = TDOUBLE;
+ type = COLUMN;
+ break;
+ case TLOGICAL:
+ gParse.varData[col_cnt].type = BOOLEAN;
+ gParse.colData[col_cnt].datatype = TLOGICAL;
+ type = BCOLUMN;
+ break;
+ case TSTRING:
+ gParse.varData[col_cnt].type = STRING;
+ gParse.colData[col_cnt].datatype = TSTRING;
+ type = SCOLUMN;
+ fits_get_hdu_type( fptr, &hdutype, &status );
+ if( hdutype == ASCII_TBL ) repeat = width;
+ break;
+ default:
+ gParse.status = PARSE_BAD_TYPE;
+ return pERROR;
+ }
+ gParse.varData[col_cnt].nelem = repeat;
+ if( repeat>1 && typecode!=TSTRING ) {
+ if( fits_read_tdim( fptr, colnum, MAXDIMS,
+ &gParse.varData[col_cnt].naxis,
+ &gParse.varData[col_cnt].naxes[0], &status )
+ ) {
+ gParse.status = status;
+ return pERROR;
+ }
+ } else {
+ gParse.varData[col_cnt].naxis = 1;
+ gParse.varData[col_cnt].naxes[0] = 1;
+ }
+ gParse.nCols++;
+ thelval->lng = col_cnt;
+
+ return( type );
+}
+
+static int find_keywd(char *keyname, void *itslval )
+{
+ FFSTYPE *thelval = (FFSTYPE*)itslval;
+ int status, type;
+ char keyvalue[FLEN_VALUE], dtype;
+ fitsfile *fptr;
+ double rval;
+ int bval;
+ long ival;
+
+ status = 0;
+ fptr = gParse.def_fptr;
+ if( fits_read_keyword( fptr, keyname, keyvalue, NULL, &status ) ) {
+ if( status == KEY_NO_EXIST ) {
+ /* Do this since ffgkey doesn't put an error message on stack */
+ sprintf(keyvalue, "ffgkey could not find keyword: %s",keyname);
+ ffpmsg(keyvalue);
+ }
+ gParse.status = status;
+ return( pERROR );
+ }
+
+ if( fits_get_keytype( keyvalue, &dtype, &status ) ) {
+ gParse.status = status;
+ return( pERROR );
+ }
+
+ switch( dtype ) {
+ case 'C':
+ fits_read_key_str( fptr, keyname, keyvalue, NULL, &status );
+ type = STRING;
+ strcpy( thelval->str , keyvalue );
+ break;
+ case 'L':
+ fits_read_key_log( fptr, keyname, &bval, NULL, &status );
+ type = BOOLEAN;
+ thelval->log = bval;
+ break;
+ case 'I':
+ fits_read_key_lng( fptr, keyname, &ival, NULL, &status );
+ type = LONG;
+ thelval->lng = ival;
+ break;
+ case 'F':
+ fits_read_key_dbl( fptr, keyname, &rval, NULL, &status );
+ type = DOUBLE;
+ thelval->dbl = rval;
+ break;
+ default:
+ type = pERROR;
+ break;
+ }
+
+ if( status ) {
+ gParse.status=status;
+ return pERROR;
+ }
+
+ return( type );
+}
+
+static int allocateCol( int nCol, int *status )
+{
+ if( (nCol%25)==0 ) {
+ if( nCol ) {
+ gParse.colData = (iteratorCol*) realloc( gParse.colData,
+ (nCol+25)*sizeof(iteratorCol) );
+ gParse.varData = (DataInfo *) realloc( gParse.varData,
+ (nCol+25)*sizeof(DataInfo) );
+ } else {
+ gParse.colData = (iteratorCol*) malloc( 25*sizeof(iteratorCol) );
+ gParse.varData = (DataInfo *) malloc( 25*sizeof(DataInfo) );
+ }
+ if( gParse.colData == NULL
+ || gParse.varData == NULL ) {
+ if( gParse.colData ) free(gParse.colData);
+ if( gParse.varData ) free(gParse.varData);
+ gParse.colData = NULL;
+ gParse.varData = NULL;
+ return( *status = MEMORY_ALLOCATION );
+ }
+ }
+ gParse.varData[nCol].data = NULL;
+ gParse.varData[nCol].undef = NULL;
+ return 0;
+}
+
+static int load_column( int varNum, long fRow, long nRows,
+ void *data, char *undef )
+{
+ iteratorCol *var = gParse.colData+varNum;
+ long nelem,nbytes,row,len,idx;
+ char **bitStrs;
+ unsigned char *bytes;
+ int status = 0, anynul;
+
+ nelem = nRows * var->repeat;
+
+ switch( var->datatype ) {
+ case TBYTE:
+ nbytes = ((var->repeat+7)/8) * nRows;
+ bytes = (unsigned char *)malloc( nbytes * sizeof(char) );
+
+ ffgcvb(var->fptr, var->colnum, fRow, 1L, nbytes,
+ 0, bytes, &anynul, &status);
+
+ nelem = var->repeat;
+ bitStrs = (char **)data;
+ for( row=0; row<nRows; row++ ) {
+ idx = (row)*( (nelem+7)/8 ) + 1;
+ for(len=0; len<nelem; len++) {
+ if( bytes[idx] & (1<<(7-len%8)) )
+ bitStrs[row][len] = '1';
+ else
+ bitStrs[row][len] = '0';
+ if( len%8==7 ) idx++;
+ }
+ bitStrs[row][len] = '\0';
+ }
+
+ free( (char *)bytes );
+ break;
+ case TSTRING:
+ ffgcfs(var->fptr, var->colnum, fRow, 1L, nRows,
+ (char **)data, undef, &anynul, &status);
+ break;
+ case TLOGICAL:
+ ffgcfl(var->fptr, var->colnum, fRow, 1L, nelem,
+ (char *)data, undef, &anynul, &status);
+ break;
+ case TLONG:
+ ffgcfj(var->fptr, var->colnum, fRow, 1L, nelem,
+ (long *)data, undef, &anynul, &status);
+ break;
+ case TDOUBLE:
+ ffgcfd(var->fptr, var->colnum, fRow, 1L, nelem,
+ (double *)data, undef, &anynul, &status);
+ break;
+ }
+
+ if( status ) {
+ gParse.status = status;
+ return pERROR;
+ }
+
+ return 0;
+}
diff --git a/pkg/tbtables/cfitsio/eval_l.c b/pkg/tbtables/cfitsio/eval_l.c
new file mode 100644
index 00000000..4eb58555
--- /dev/null
+++ b/pkg/tbtables/cfitsio/eval_l.c
@@ -0,0 +1,2219 @@
+/* A lexical scanner generated by flex */
+
+/* Scanner skeleton version:
+ * $Header: /thor/data2/sienkiew/cvs/st/tables/lib/tbtables/cfitsio/eval_l.c,v 1.11 2005/09/27 14:58:21 hodge Exp $
+ */
+
+#define FLEX_SCANNER
+#define FF_FLEX_MAJOR_VERSION 2
+#define FF_FLEX_MINOR_VERSION 5
+
+#include <stdio.h>
+
+
+/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */
+#ifdef c_plusplus
+#ifndef __cplusplus
+#define __cplusplus
+#endif
+#endif
+
+
+#ifdef __cplusplus
+
+#include <stdlib.h>
+#include <unistd.h>
+
+/* Use prototypes in function declarations. */
+#define FF_USE_PROTOS
+
+/* The "const" storage-class-modifier is valid. */
+#define FF_USE_CONST
+
+#else /* ! __cplusplus */
+
+#if __STDC__
+
+#define FF_USE_PROTOS
+#define FF_USE_CONST
+
+#endif /* __STDC__ */
+#endif /* ! __cplusplus */
+
+#ifdef __TURBOC__
+ #pragma warn -rch
+ #pragma warn -use
+#include <io.h>
+#include <stdlib.h>
+#define FF_USE_CONST
+#define FF_USE_PROTOS
+#endif
+
+#ifdef FF_USE_CONST
+#define ffconst const
+#else
+#define ffconst
+#endif
+
+
+#ifdef FF_USE_PROTOS
+#define FF_PROTO(proto) proto
+#else
+#define FF_PROTO(proto) ()
+#endif
+
+/* Returned upon end-of-file. */
+#define FF_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index. If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define FF_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* Enter a start condition. This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN ff_start = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state. The FFSTATE alias is for lex
+ * compatibility.
+ */
+#define FF_START ((ff_start - 1) / 2)
+#define FFSTATE FF_START
+
+/* Action number for EOF rule of a given start state. */
+#define FF_STATE_EOF(state) (FF_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define FF_NEW_FILE ffrestart( ffin )
+
+#define FF_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#define FF_BUF_SIZE 16384
+
+typedef struct ff_buffer_state *FF_BUFFER_STATE;
+
+extern int ffleng;
+extern FILE *ffin, *ffout;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+/* The funky do-while in the following #define is used to turn the definition
+ * int a single C statement (which needs a semi-colon terminator). This
+ * avoids problems with code like:
+ *
+ * if ( condition_holds )
+ * ffless( 5 );
+ * else
+ * do_something_else();
+ *
+ * Prior to using the do-while the compiler would get upset at the
+ * "else" because it interpreted the "if" statement as being all
+ * done when it reached the ';' after the ffless() call.
+ */
+
+/* Return all but the first 'n' matched characters back to the input stream. */
+
+#define ffless(n) \
+ do \
+ { \
+ /* Undo effects of setting up fftext. */ \
+ *ff_cp = ff_hold_char; \
+ FF_RESTORE_FF_MORE_OFFSET \
+ ff_c_buf_p = ff_cp = ff_bp + n - FF_MORE_ADJ; \
+ FF_DO_BEFORE_ACTION; /* set up fftext again */ \
+ } \
+ while ( 0 )
+
+#define unput(c) ffunput( c, fftext_ptr )
+
+/* The following is because we cannot portably get our hands on size_t
+ * (without autoconf's help, which isn't available because we want
+ * flex-generated scanners to compile on their own).
+ */
+typedef unsigned int ff_size_t;
+
+
+struct ff_buffer_state
+ {
+ FILE *ff_input_file;
+
+ char *ff_ch_buf; /* input buffer */
+ char *ff_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ ff_size_t ff_buf_size;
+
+ /* Number of characters read into ff_ch_buf, not including EOB
+ * characters.
+ */
+ int ff_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int ff_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int ff_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int ff_at_bol;
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int ff_fill_buffer;
+
+ int ff_buffer_status;
+#define FF_BUFFER_NEW 0
+#define FF_BUFFER_NORMAL 1
+ /* When an EOF's been seen but there's still some text to process
+ * then we mark the buffer as FF_EOF_PENDING, to indicate that we
+ * shouldn't try reading from the input source any more. We might
+ * still have a bunch of tokens to match, though, because of
+ * possible backing-up.
+ *
+ * When we actually see the EOF, we change the status to "new"
+ * (via ffrestart()), so that the user can continue scanning by
+ * just pointing ffin at a new input file.
+ */
+#define FF_BUFFER_EOF_PENDING 2
+ };
+
+static FF_BUFFER_STATE ff_current_buffer = 0;
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ */
+#define FF_CURRENT_BUFFER ff_current_buffer
+
+
+/* ff_hold_char holds the character lost when fftext is formed. */
+static char ff_hold_char;
+
+static int ff_n_chars; /* number of characters read into ff_ch_buf */
+
+
+int ffleng;
+
+/* Points to current character in buffer. */
+static char *ff_c_buf_p = (char *) 0;
+static int ff_init = 1; /* whether we need to initialize */
+static int ff_start = 0; /* start state number */
+
+/* Flag which is used to allow ffwrap()'s to do buffer switches
+ * instead of setting up a fresh ffin. A bit of a hack ...
+ */
+static int ff_did_buffer_switch_on_eof;
+
+void ffrestart FF_PROTO(( FILE *input_file ));
+
+void ff_switch_to_buffer FF_PROTO(( FF_BUFFER_STATE new_buffer ));
+void ff_load_buffer_state FF_PROTO(( void ));
+FF_BUFFER_STATE ff_create_buffer FF_PROTO(( FILE *file, int size ));
+void ff_delete_buffer FF_PROTO(( FF_BUFFER_STATE b ));
+void ff_init_buffer FF_PROTO(( FF_BUFFER_STATE b, FILE *file ));
+void ff_flush_buffer FF_PROTO(( FF_BUFFER_STATE b ));
+#define FF_FLUSH_BUFFER ff_flush_buffer( ff_current_buffer )
+
+FF_BUFFER_STATE ff_scan_buffer FF_PROTO(( char *base, ff_size_t size ));
+FF_BUFFER_STATE ff_scan_string FF_PROTO(( ffconst char *ff_str ));
+FF_BUFFER_STATE ff_scan_bytes FF_PROTO(( ffconst char *bytes, int len ));
+
+static void *ff_flex_alloc FF_PROTO(( ff_size_t ));
+static void *ff_flex_realloc FF_PROTO(( void *, ff_size_t ));
+static void ff_flex_free FF_PROTO(( void * ));
+
+#define ff_new_buffer ff_create_buffer
+
+#define ff_set_interactive(is_interactive) \
+ { \
+ if ( ! ff_current_buffer ) \
+ ff_current_buffer = ff_create_buffer( ffin, FF_BUF_SIZE ); \
+ ff_current_buffer->ff_is_interactive = is_interactive; \
+ }
+
+#define ff_set_bol(at_bol) \
+ { \
+ if ( ! ff_current_buffer ) \
+ ff_current_buffer = ff_create_buffer( ffin, FF_BUF_SIZE ); \
+ ff_current_buffer->ff_at_bol = at_bol; \
+ }
+
+#define FF_AT_BOL() (ff_current_buffer->ff_at_bol)
+
+typedef unsigned char FF_CHAR;
+FILE *ffin = (FILE *) 0, *ffout = (FILE *) 0;
+typedef int ff_state_type;
+extern char *fftext;
+#define fftext_ptr fftext
+
+static ff_state_type ff_get_previous_state FF_PROTO(( void ));
+static ff_state_type ff_try_NUL_trans FF_PROTO(( ff_state_type current_state ));
+static int ff_get_next_buffer FF_PROTO(( void ));
+static void ff_fatal_error FF_PROTO(( ffconst char msg[] ));
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up fftext.
+ */
+#define FF_DO_BEFORE_ACTION \
+ fftext_ptr = ff_bp; \
+ ffleng = (int) (ff_cp - ff_bp); \
+ ff_hold_char = *ff_cp; \
+ *ff_cp = '\0'; \
+ ff_c_buf_p = ff_cp;
+
+#define FF_NUM_RULES 26
+#define FF_END_OF_BUFFER 27
+static ffconst short int ff_accept[160] =
+ { 0,
+ 0, 0, 27, 25, 1, 24, 15, 25, 25, 25,
+ 25, 25, 25, 25, 7, 5, 21, 25, 20, 10,
+ 10, 10, 10, 6, 10, 10, 10, 10, 10, 14,
+ 10, 10, 10, 10, 10, 10, 10, 25, 1, 19,
+ 0, 9, 0, 8, 0, 10, 17, 0, 0, 0,
+ 0, 0, 0, 0, 14, 0, 7, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 7,
+ 5, 0, 23, 18, 22, 10, 10, 10, 2, 10,
+ 10, 10, 4, 10, 10, 10, 10, 3, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 16, 0,
+
+ 8, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 7, 11, 10,
+ 20, 21, 10, 10, 10, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 15, 0, 0, 12, 0,
+ 0, 0, 0, 0, 0, 0, 13, 0, 0
+ } ;
+
+static ffconst int ff_ec[256] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 4, 5, 6, 7, 1, 8, 9, 10,
+ 11, 12, 13, 1, 13, 14, 1, 15, 15, 16,
+ 16, 16, 16, 16, 16, 17, 17, 1, 1, 18,
+ 19, 20, 1, 1, 21, 22, 23, 24, 25, 26,
+ 27, 28, 29, 30, 30, 31, 30, 32, 33, 30,
+ 34, 35, 30, 36, 37, 30, 30, 38, 30, 30,
+ 1, 1, 1, 39, 40, 1, 41, 42, 23, 43,
+
+ 44, 45, 46, 28, 47, 30, 30, 48, 30, 49,
+ 50, 30, 51, 52, 30, 53, 54, 30, 30, 38,
+ 30, 30, 1, 55, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1
+ } ;
+
+static ffconst int ff_meta[56] =
+ { 0,
+ 1, 1, 2, 1, 1, 1, 3, 1, 1, 1,
+ 1, 1, 1, 1, 4, 4, 4, 1, 1, 1,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 1, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 1
+ } ;
+
+static ffconst short int ff_base[167] =
+ { 0,
+ 0, 0, 367, 368, 364, 368, 346, 359, 356, 355,
+ 353, 351, 32, 347, 66, 103, 339, 44, 338, 25,
+ 52, 316, 26, 315, 34, 133, 48, 61, 125, 368,
+ 0, 29, 45, 60, 81, 82, 93, 299, 351, 368,
+ 347, 368, 344, 343, 342, 368, 368, 339, 314, 315,
+ 313, 294, 295, 293, 368, 121, 164, 307, 301, 70,
+ 117, 43, 296, 276, 271, 58, 86, 79, 269, 152,
+ 168, 181, 368, 368, 368, 151, 162, 0, 180, 189,
+ 190, 191, 309, 196, 199, 205, 204, 211, 214, 207,
+ 223, 224, 232, 238, 243, 245, 222, 246, 368, 311,
+
+ 310, 279, 282, 278, 259, 262, 258, 252, 286, 295,
+ 294, 293, 292, 291, 290, 267, 288, 258, 285, 284,
+ 278, 270, 268, 259, 218, 252, 264, 272, 368, 251,
+ 368, 368, 260, 280, 283, 236, 222, 230, 193, 184,
+ 212, 208, 202, 173, 156, 368, 133, 126, 368, 104,
+ 98, 119, 132, 80, 94, 92, 368, 78, 368, 323,
+ 325, 329, 333, 68, 67, 337
+ } ;
+
+static ffconst short int ff_def[167] =
+ { 0,
+ 159, 1, 159, 159, 159, 159, 159, 160, 161, 162,
+ 159, 163, 159, 159, 159, 159, 159, 159, 159, 164,
+ 164, 164, 164, 164, 164, 164, 164, 164, 164, 159,
+ 165, 164, 164, 164, 164, 164, 164, 159, 159, 159,
+ 160, 159, 166, 161, 162, 159, 159, 163, 159, 159,
+ 159, 159, 159, 159, 159, 159, 159, 159, 159, 159,
+ 159, 159, 159, 159, 159, 159, 159, 159, 159, 159,
+ 159, 159, 159, 159, 159, 164, 164, 165, 164, 164,
+ 164, 164, 26, 164, 164, 164, 164, 164, 164, 164,
+ 164, 164, 164, 164, 164, 164, 164, 164, 159, 166,
+
+ 166, 159, 159, 159, 159, 159, 159, 159, 159, 159,
+ 159, 159, 159, 159, 159, 159, 159, 159, 159, 159,
+ 159, 159, 159, 159, 159, 159, 159, 159, 159, 164,
+ 159, 159, 164, 164, 164, 159, 159, 159, 159, 159,
+ 159, 159, 159, 159, 159, 159, 159, 159, 159, 159,
+ 159, 159, 159, 159, 159, 159, 159, 159, 0, 159,
+ 159, 159, 159, 159, 159, 159
+ } ;
+
+static ffconst short int ff_nxt[424] =
+ { 0,
+ 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
+ 4, 14, 4, 15, 16, 16, 16, 17, 18, 19,
+ 20, 21, 22, 22, 23, 24, 25, 26, 22, 22,
+ 27, 28, 29, 22, 22, 24, 22, 22, 30, 31,
+ 32, 21, 22, 33, 24, 34, 22, 35, 36, 37,
+ 22, 22, 24, 22, 38, 49, 77, 50, 81, 80,
+ 51, 73, 74, 75, 78, 78, 79, 115, 78, 82,
+ 78, 76, 84, 78, 52, 116, 53, 90, 54, 56,
+ 57, 57, 57, 85, 78, 86, 58, 78, 157, 79,
+ 59, 78, 60, 87, 111, 91, 61, 62, 63, 78,
+
+ 78, 120, 157, 92, 157, 112, 64, 88, 88, 65,
+ 121, 66, 93, 67, 68, 69, 70, 71, 71, 71,
+ 78, 78, 124, 158, 94, 96, 72, 72, 125, 122,
+ 88, 97, 78, 95, 56, 108, 108, 108, 123, 88,
+ 88, 113, 157, 156, 98, 72, 72, 83, 83, 83,
+ 155, 154, 114, 83, 83, 83, 83, 83, 83, 89,
+ 129, 153, 88, 152, 78, 56, 57, 57, 57, 146,
+ 83, 129, 78, 83, 83, 83, 83, 83, 57, 57,
+ 57, 70, 71, 71, 71, 130, 47, 72, 72, 129,
+ 78, 72, 72, 127, 79, 128, 128, 128, 129, 129,
+
+ 129, 78, 74, 75, 131, 129, 72, 72, 129, 73,
+ 72, 72, 132, 129, 129, 146, 129, 79, 40, 78,
+ 129, 47, 149, 129, 151, 88, 88, 99, 78, 78,
+ 78, 129, 129, 129, 150, 78, 74, 75, 78, 133,
+ 149, 129, 148, 78, 78, 131, 78, 129, 88, 134,
+ 78, 73, 129, 78, 129, 129, 132, 147, 40, 99,
+ 129, 78, 78, 78, 47, 99, 108, 108, 108, 129,
+ 145, 78, 40, 146, 135, 72, 72, 78, 128, 128,
+ 128, 132, 78, 73, 78, 78, 128, 128, 128, 129,
+ 78, 131, 129, 47, 72, 72, 146, 75, 74, 78,
+
+ 144, 99, 143, 40, 132, 73, 131, 75, 74, 142,
+ 141, 140, 139, 138, 137, 136, 101, 101, 129, 78,
+ 126, 119, 78, 41, 118, 41, 41, 44, 44, 45,
+ 117, 45, 45, 48, 110, 48, 48, 100, 109, 100,
+ 100, 107, 106, 105, 104, 103, 102, 42, 46, 159,
+ 101, 42, 39, 99, 78, 78, 75, 73, 55, 42,
+ 47, 46, 43, 42, 40, 39, 159, 3, 159, 159,
+ 159, 159, 159, 159, 159, 159, 159, 159, 159, 159,
+ 159, 159, 159, 159, 159, 159, 159, 159, 159, 159,
+ 159, 159, 159, 159, 159, 159, 159, 159, 159, 159,
+
+ 159, 159, 159, 159, 159, 159, 159, 159, 159, 159,
+ 159, 159, 159, 159, 159, 159, 159, 159, 159, 159,
+ 159, 159, 159
+ } ;
+
+static ffconst short int ff_chk[424] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 13, 20, 13, 25, 23,
+ 13, 18, 18, 18, 20, 23, 21, 62, 32, 25,
+ 165, 164, 27, 25, 13, 62, 13, 32, 13, 15,
+ 15, 15, 15, 27, 33, 28, 15, 27, 158, 21,
+ 15, 21, 15, 28, 60, 33, 15, 15, 15, 34,
+
+ 28, 66, 156, 34, 155, 60, 15, 37, 37, 15,
+ 66, 15, 34, 15, 15, 15, 16, 16, 16, 16,
+ 35, 36, 68, 154, 35, 36, 16, 16, 68, 67,
+ 37, 36, 37, 35, 56, 56, 56, 56, 67, 29,
+ 29, 61, 153, 152, 37, 16, 16, 26, 26, 26,
+ 151, 150, 61, 26, 26, 26, 26, 26, 26, 29,
+ 76, 148, 29, 147, 29, 70, 70, 70, 70, 145,
+ 26, 77, 26, 26, 26, 26, 26, 26, 57, 57,
+ 57, 71, 71, 71, 71, 77, 144, 57, 57, 79,
+ 76, 71, 71, 72, 79, 72, 72, 72, 80, 81,
+
+ 82, 77, 80, 81, 82, 84, 57, 57, 85, 84,
+ 71, 71, 85, 87, 86, 143, 90, 79, 86, 79,
+ 88, 142, 141, 89, 140, 88, 88, 89, 80, 81,
+ 82, 97, 91, 92, 139, 84, 91, 92, 85, 87,
+ 138, 93, 137, 87, 86, 93, 90, 94, 88, 90,
+ 88, 94, 95, 89, 96, 98, 95, 136, 96, 98,
+ 130, 97, 91, 92, 130, 126, 108, 108, 108, 133,
+ 125, 93, 124, 133, 97, 108, 108, 94, 127, 127,
+ 127, 123, 95, 122, 96, 98, 128, 128, 128, 134,
+ 130, 121, 135, 134, 108, 108, 135, 120, 119, 133,
+
+ 118, 117, 116, 115, 114, 113, 112, 111, 110, 109,
+ 107, 106, 105, 104, 103, 102, 101, 100, 83, 134,
+ 69, 65, 135, 160, 64, 160, 160, 161, 161, 162,
+ 63, 162, 162, 163, 59, 163, 163, 166, 58, 166,
+ 166, 54, 53, 52, 51, 50, 49, 48, 45, 44,
+ 43, 41, 39, 38, 24, 22, 19, 17, 14, 12,
+ 11, 10, 9, 8, 7, 5, 3, 159, 159, 159,
+ 159, 159, 159, 159, 159, 159, 159, 159, 159, 159,
+ 159, 159, 159, 159, 159, 159, 159, 159, 159, 159,
+ 159, 159, 159, 159, 159, 159, 159, 159, 159, 159,
+
+ 159, 159, 159, 159, 159, 159, 159, 159, 159, 159,
+ 159, 159, 159, 159, 159, 159, 159, 159, 159, 159,
+ 159, 159, 159
+ } ;
+
+static ff_state_type ff_last_accepting_state;
+static char *ff_last_accepting_cpos;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define ffmore() ffmore_used_but_not_detected
+#define FF_MORE_ADJ 0
+#define FF_RESTORE_FF_MORE_OFFSET
+char *fftext;
+#line 1 "eval.l"
+#define INITIAL 0
+#line 2 "eval.l"
+/************************************************************************/
+/* */
+/* CFITSIO Lexical Parser */
+/* */
+/* This file is one of 3 files containing code which parses an */
+/* arithmetic expression and evaluates it in the context of an input */
+/* FITS file table extension. The CFITSIO lexical parser is divided */
+/* into the following 3 parts/files: the CFITSIO "front-end", */
+/* eval_f.c, contains the interface between the user/CFITSIO and the */
+/* real core of the parser; the FLEX interpreter, eval_l.c, takes the */
+/* input string and parses it into tokens and identifies the FITS */
+/* information required to evaluate the expression (ie, keywords and */
+/* columns); and, the BISON grammar and evaluation routines, eval_y.c, */
+/* receives the FLEX output and determines and performs the actual */
+/* operations. The files eval_l.c and eval_y.c are produced from */
+/* running flex and bison on the files eval.l and eval.y, respectively. */
+/* (flex and bison are available from any GNU archive: see www.gnu.org) */
+/* */
+/* The grammar rules, rather than evaluating the expression in situ, */
+/* builds a tree, or Nodal, structure mapping out the order of */
+/* operations and expression dependencies. This "compilation" process */
+/* allows for much faster processing of multiple rows. This technique */
+/* was developed by Uwe Lammers of the XMM Science Analysis System, */
+/* although the CFITSIO implementation is entirely code original. */
+/* */
+/* */
+/* Modification History: */
+/* */
+/* Kent Blackburn c1992 Original parser code developed for the */
+/* FTOOLS software package, in particular, */
+/* the fselect task. */
+/* Kent Blackburn c1995 BIT column support added */
+/* Peter D Wilson Feb 1998 Vector column support added */
+/* Peter D Wilson May 1998 Ported to CFITSIO library. User */
+/* interface routines written, in essence */
+/* making fselect, fcalc, and maketime */
+/* capabilities available to all tools */
+/* via single function calls. */
+/* Peter D Wilson Jun 1998 Major rewrite of parser core, so as to */
+/* create a run-time evaluation tree, */
+/* inspired by the work of Uwe Lammers, */
+/* resulting in a speed increase of */
+/* 10-100 times. */
+/* Peter D Wilson Jul 1998 gtifilter(a,b,c,d) function added */
+/* Peter D Wilson Aug 1998 regfilter(a,b,c,d) function added */
+/* Peter D Wilson Jul 1999 Make parser fitsfile-independent, */
+/* allowing a purely vector-based usage */
+/* */
+/************************************************************************/
+
+#include <math.h>
+#include <string.h>
+#include <ctype.h>
+#ifdef sparc
+#include <malloc.h>
+#else
+#include <stdlib.h>
+#endif
+#include "eval_defs.h"
+
+ParseData gParse; /* Global structure holding all parser information */
+
+/***** Internal functions *****/
+
+ int ffGetVariable( char *varName, FFSTYPE *varVal );
+
+static int find_variable( char *varName );
+static int expr_read( char *buf, int nbytes );
+
+/***** Definitions *****/
+
+#define FF_NO_UNPUT /* Don't include FFUNPUT function */
+#define FF_NEVER_INTERACTIVE 1
+
+#define MAXCHR 256
+#define MAXBIT 128
+
+#define OCT_0 "000"
+#define OCT_1 "001"
+#define OCT_2 "010"
+#define OCT_3 "011"
+#define OCT_4 "100"
+#define OCT_5 "101"
+#define OCT_6 "110"
+#define OCT_7 "111"
+#define OCT_X "xxx"
+
+#define HEX_0 "0000"
+#define HEX_1 "0001"
+#define HEX_2 "0010"
+#define HEX_3 "0011"
+#define HEX_4 "0100"
+#define HEX_5 "0101"
+#define HEX_6 "0110"
+#define HEX_7 "0111"
+#define HEX_8 "1000"
+#define HEX_9 "1001"
+#define HEX_A "1010"
+#define HEX_B "1011"
+#define HEX_C "1100"
+#define HEX_D "1101"
+#define HEX_E "1110"
+#define HEX_F "1111"
+#define HEX_X "xxxx"
+
+/*
+ MJT - 13 June 1996
+ read from buffer instead of stdin
+ (as per old ftools.skel)
+*/
+#undef FF_INPUT
+#define FF_INPUT(buf,result,max_size) \
+ if ( (result = expr_read( (char *) buf, max_size )) < 0 ) \
+ FF_FATAL_ERROR( "read() in flex scanner failed" );
+
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef FF_SKIP_FFWRAP
+#ifdef __cplusplus
+extern "C" int ffwrap FF_PROTO(( void ));
+#else
+extern int ffwrap FF_PROTO(( void ));
+#endif
+#endif
+
+#ifndef FF_NO_UNPUT
+static void ffunput FF_PROTO(( int c, char *buf_ptr ));
+#endif
+
+#ifndef fftext_ptr
+static void ff_flex_strncpy FF_PROTO(( char *, ffconst char *, int ));
+#endif
+
+#ifdef FF_NEED_STRLEN
+static int ff_flex_strlen FF_PROTO(( ffconst char * ));
+#endif
+
+#ifndef FF_NO_INPUT
+#ifdef __cplusplus
+static int ffinput FF_PROTO(( void ));
+#else
+static int input FF_PROTO(( void ));
+#endif
+#endif
+
+#if FF_STACK_USED
+static int ff_start_stack_ptr = 0;
+static int ff_start_stack_depth = 0;
+static int *ff_start_stack = 0;
+#ifndef FF_NO_PUSH_STATE
+static void ff_push_state FF_PROTO(( int new_state ));
+#endif
+#ifndef FF_NO_POP_STATE
+static void ff_pop_state FF_PROTO(( void ));
+#endif
+#ifndef FF_NO_TOP_STATE
+static int ff_top_state FF_PROTO(( void ));
+#endif
+
+#else
+#define FF_NO_PUSH_STATE 1
+#define FF_NO_POP_STATE 1
+#define FF_NO_TOP_STATE 1
+#endif
+
+#ifdef FF_MALLOC_DECL
+FF_MALLOC_DECL
+#else
+#if __STDC__
+#ifndef __cplusplus
+#include <stdlib.h>
+#endif
+#else
+/* Just try to get by without declaring the routines. This will fail
+ * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int)
+ * or sizeof(void*) != sizeof(int).
+ */
+#endif
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef FF_READ_BUF_SIZE
+#define FF_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO (void) fwrite( fftext, ffleng, 1, ffout )
+#endif
+
+/* Gets input and stuffs it into "buf". number of characters read, or FF_NULL,
+ * is returned in "result".
+ */
+#ifndef FF_INPUT
+#define FF_INPUT(buf,result,max_size) \
+ if ( ff_current_buffer->ff_is_interactive ) \
+ { \
+ int c = '*', n; \
+ for ( n = 0; n < max_size && \
+ (c = getc( ffin )) != EOF && c != '\n'; ++n ) \
+ buf[n] = (char) c; \
+ if ( c == '\n' ) \
+ buf[n++] = (char) c; \
+ if ( c == EOF && ferror( ffin ) ) \
+ FF_FATAL_ERROR( "input in flex scanner failed" ); \
+ result = n; \
+ } \
+ else if ( ((result = fread( buf, 1, max_size, ffin )) == 0) \
+ && ferror( ffin ) ) \
+ FF_FATAL_ERROR( "input in flex scanner failed" );
+#endif
+
+/* No semi-colon after return; correct usage is to write "ffterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef ffterminate
+#define ffterminate() return FF_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef FF_START_STACK_INCR
+#define FF_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef FF_FATAL_ERROR
+#define FF_FATAL_ERROR(msg) ff_fatal_error( msg )
+#endif
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef FF_DECL
+#define FF_DECL int fflex FF_PROTO(( void ))
+#endif
+
+/* Code executed at the beginning of each rule, after fftext and ffleng
+ * have been set up.
+ */
+#ifndef FF_USER_ACTION
+#define FF_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef FF_BREAK
+#define FF_BREAK break;
+#endif
+
+#define FF_RULE_SETUP \
+ FF_USER_ACTION
+
+FF_DECL
+ {
+ register ff_state_type ff_current_state;
+ register char *ff_cp, *ff_bp;
+ register int ff_act;
+
+#line 142 "eval.l"
+
+
+
+ if ( ff_init )
+ {
+ ff_init = 0;
+
+#ifdef FF_USER_INIT
+ FF_USER_INIT;
+#endif
+
+ if ( ! ff_start )
+ ff_start = 1; /* first start state */
+
+ if ( ! ffin )
+ ffin = stdin;
+
+ if ( ! ffout )
+ ffout = stdout;
+
+ if ( ! ff_current_buffer )
+ ff_current_buffer =
+ ff_create_buffer( ffin, FF_BUF_SIZE );
+
+ ff_load_buffer_state();
+ }
+
+ while ( 1 ) /* loops until end-of-file is reached */
+ {
+ ff_cp = ff_c_buf_p;
+
+ /* Support of fftext. */
+ *ff_cp = ff_hold_char;
+
+ /* ff_bp points to the position in ff_ch_buf of the start of
+ * the current run.
+ */
+ ff_bp = ff_cp;
+
+ ff_current_state = ff_start;
+ff_match:
+ do
+ {
+ register FF_CHAR ff_c = ff_ec[FF_SC_TO_UI(*ff_cp)];
+ if ( ff_accept[ff_current_state] )
+ {
+ ff_last_accepting_state = ff_current_state;
+ ff_last_accepting_cpos = ff_cp;
+ }
+ while ( ff_chk[ff_base[ff_current_state] + ff_c] != ff_current_state )
+ {
+ ff_current_state = (int) ff_def[ff_current_state];
+ if ( ff_current_state >= 160 )
+ ff_c = ff_meta[(unsigned int) ff_c];
+ }
+ ff_current_state = ff_nxt[ff_base[ff_current_state] + (unsigned int) ff_c];
+ ++ff_cp;
+ }
+ while ( ff_base[ff_current_state] != 368 );
+
+ff_find_action:
+ ff_act = ff_accept[ff_current_state];
+ if ( ff_act == 0 )
+ { /* have to back up */
+ ff_cp = ff_last_accepting_cpos;
+ ff_current_state = ff_last_accepting_state;
+ ff_act = ff_accept[ff_current_state];
+ }
+
+ FF_DO_BEFORE_ACTION;
+
+
+do_action: /* This label is used only to access EOF actions. */
+
+
+ switch ( ff_act )
+ { /* beginning of action switch */
+ case 0: /* must back up */
+ /* undo the effects of FF_DO_BEFORE_ACTION */
+ *ff_cp = ff_hold_char;
+ ff_cp = ff_last_accepting_cpos;
+ ff_current_state = ff_last_accepting_state;
+ goto ff_find_action;
+
+case 1:
+FF_RULE_SETUP
+#line 144 "eval.l"
+;
+ FF_BREAK
+case 2:
+FF_RULE_SETUP
+#line 145 "eval.l"
+{
+ int len;
+ len = strlen(fftext);
+ while (fftext[len] == ' ')
+ len--;
+ len = len - 1;
+ strncpy(fflval.str,&fftext[1],len);
+ fflval.str[len] = '\0';
+ return( BITSTR );
+ }
+ FF_BREAK
+case 3:
+FF_RULE_SETUP
+#line 155 "eval.l"
+{
+ int len;
+ char tmpstring[256];
+ char bitstring[256];
+ len = strlen(fftext);
+ while (fftext[len] == ' ')
+ len--;
+ len = len - 1;
+ strncpy(tmpstring,&fftext[1],len);
+ tmpstring[len] = '\0';
+ bitstring[0] = '\0';
+ len = 0;
+ while ( tmpstring[len] != '\0')
+ {
+ switch ( tmpstring[len] )
+ {
+ case '0':
+ strcat(bitstring,OCT_0);
+ break;
+ case '1':
+ strcat(bitstring,OCT_1);
+ break;
+ case '2':
+ strcat(bitstring,OCT_2);
+ break;
+ case '3':
+ strcat(bitstring,OCT_3);
+ break;
+ case '4':
+ strcat(bitstring,OCT_4);
+ break;
+ case '5':
+ strcat(bitstring,OCT_5);
+ break;
+ case '6':
+ strcat(bitstring,OCT_6);
+ break;
+ case '7':
+ strcat(bitstring,OCT_7);
+ break;
+ case 'x':
+ case 'X':
+ strcat(bitstring,OCT_X);
+ break;
+ }
+ len++;
+ }
+ strcpy( fflval.str, bitstring );
+ return( BITSTR );
+ }
+ FF_BREAK
+case 4:
+FF_RULE_SETUP
+#line 205 "eval.l"
+{
+ int len;
+ char tmpstring[256];
+ char bitstring[256];
+ len = strlen(fftext);
+ while (fftext[len] == ' ')
+ len--;
+ len = len - 1;
+ strncpy(tmpstring,&fftext[1],len);
+ tmpstring[len] = '\0';
+ bitstring[0] = '\0';
+ len = 0;
+ while ( tmpstring[len] != '\0')
+ {
+ switch ( tmpstring[len] )
+ {
+ case '0':
+ strcat(bitstring,HEX_0);
+ break;
+ case '1':
+ strcat(bitstring,HEX_1);
+ break;
+ case '2':
+ strcat(bitstring,HEX_2);
+ break;
+ case '3':
+ strcat(bitstring,HEX_3);
+ break;
+ case '4':
+ strcat(bitstring,HEX_4);
+ break;
+ case '5':
+ strcat(bitstring,HEX_5);
+ break;
+ case '6':
+ strcat(bitstring,HEX_6);
+ break;
+ case '7':
+ strcat(bitstring,HEX_7);
+ break;
+ case '8':
+ strcat(bitstring,HEX_8);
+ break;
+ case '9':
+ strcat(bitstring,HEX_9);
+ break;
+ case 'a':
+ case 'A':
+ strcat(bitstring,HEX_A);
+ break;
+ case 'b':
+ case 'B':
+ strcat(bitstring,HEX_B);
+ break;
+ case 'c':
+ case 'C':
+ strcat(bitstring,HEX_C);
+ break;
+ case 'd':
+ case 'D':
+ strcat(bitstring,HEX_D);
+ break;
+ case 'e':
+ case 'E':
+ strcat(bitstring,HEX_E);
+ break;
+ case 'f':
+ case 'F':
+ strcat(bitstring,HEX_F);
+ break;
+ case 'x':
+ case 'X':
+ strcat(bitstring,HEX_X);
+ break;
+ }
+ len++;
+ }
+
+ strcpy( fflval.str, bitstring );
+ return( BITSTR );
+ }
+ FF_BREAK
+case 5:
+FF_RULE_SETUP
+#line 286 "eval.l"
+{
+ fflval.lng = atol(fftext);
+ return( LONG );
+ }
+ FF_BREAK
+case 6:
+FF_RULE_SETUP
+#line 290 "eval.l"
+{
+ if ((fftext[0] == 't') || (fftext[0] == 'T'))
+ fflval.log = 1;
+ else
+ fflval.log = 0;
+ return( BOOLEAN );
+ }
+ FF_BREAK
+case 7:
+FF_RULE_SETUP
+#line 297 "eval.l"
+{
+ fflval.dbl = atof(fftext);
+ return( DOUBLE );
+ }
+ FF_BREAK
+case 8:
+FF_RULE_SETUP
+#line 301 "eval.l"
+{
+ if( !strcasecmp(fftext,"#PI") ) {
+ fflval.dbl = (double)(4) * atan((double)(1));
+ return( DOUBLE );
+ } else if( !strcasecmp(fftext,"#E") ) {
+ fflval.dbl = exp((double)(1));
+ return( DOUBLE );
+ } else if( !strcasecmp(fftext,"#DEG") ) {
+ fflval.dbl = ((double)4)*atan((double)1)/((double)180);
+ return( DOUBLE );
+ } else if( !strcasecmp(fftext,"#ROW") ) {
+ return( ROWREF );
+ } else if( !strcasecmp(fftext,"#NULL") ) {
+ return( NULLREF );
+ } else if( !strcasecmp(fftext,"#SNULL") ) {
+ return( SNULLREF );
+ } else {
+ int len;
+ if (fftext[1] == '$') {
+ len = strlen(fftext) - 3;
+ fflval.str[0] = '#';
+ strncpy(fflval.str+1,&fftext[2],len);
+ fflval.str[len+1] = '\0';
+ fftext = fflval.str;
+ }
+ return( (*gParse.getData)(fftext, &fflval) );
+ }
+ }
+ FF_BREAK
+case 9:
+FF_RULE_SETUP
+#line 329 "eval.l"
+{
+ int len;
+ len = strlen(fftext) - 2;
+ strncpy(fflval.str,&fftext[1],len);
+ fflval.str[len] = '\0';
+ return( STRING );
+ }
+ FF_BREAK
+case 10:
+FF_RULE_SETUP
+#line 336 "eval.l"
+{
+ int len,type;
+
+ if (fftext[0] == '$') {
+ len = strlen(fftext) - 2;
+ strncpy(fflval.str,&fftext[1],len);
+ fflval.str[len] = '\0';
+ fftext = fflval.str;
+ }
+ type = ffGetVariable(fftext, &fflval);
+ return( type );
+ }
+ FF_BREAK
+case 11:
+FF_RULE_SETUP
+#line 348 "eval.l"
+{
+ char *fname;
+ int len=0;
+ fname = &fflval.str[0];
+ while( (fname[len]=toupper(fftext[len])) ) len++;
+
+ if( FSTRCMP(fname,"BOX(")==0
+ || FSTRCMP(fname,"CIRCLE(")==0
+ || FSTRCMP(fname,"ELLIPSE(")==0
+ || FSTRCMP(fname,"NEAR(")==0
+ || FSTRCMP(fname,"ISNULL(")==0
+ )
+ /* Return type is always boolean */
+ return( BFUNCTION );
+
+ else if( FSTRCMP(fname,"GTIFILTER(")==0 )
+ return( GTIFILTER );
+
+ else if( FSTRCMP(fname,"REGFILTER(")==0 )
+ return( REGFILTER );
+
+ else
+ return( FUNCTION );
+ }
+ FF_BREAK
+case 12:
+FF_RULE_SETUP
+#line 372 "eval.l"
+{ return( INTCAST ); }
+ FF_BREAK
+case 13:
+FF_RULE_SETUP
+#line 373 "eval.l"
+{ return( FLTCAST ); }
+ FF_BREAK
+case 14:
+FF_RULE_SETUP
+#line 374 "eval.l"
+{ return( POWER ); }
+ FF_BREAK
+case 15:
+FF_RULE_SETUP
+#line 375 "eval.l"
+{ return( NOT ); }
+ FF_BREAK
+case 16:
+FF_RULE_SETUP
+#line 376 "eval.l"
+{ return( OR ); }
+ FF_BREAK
+case 17:
+FF_RULE_SETUP
+#line 377 "eval.l"
+{ return( AND ); }
+ FF_BREAK
+case 18:
+FF_RULE_SETUP
+#line 378 "eval.l"
+{ return( EQ ); }
+ FF_BREAK
+case 19:
+FF_RULE_SETUP
+#line 379 "eval.l"
+{ return( NE ); }
+ FF_BREAK
+case 20:
+FF_RULE_SETUP
+#line 380 "eval.l"
+{ return( GT ); }
+ FF_BREAK
+case 21:
+FF_RULE_SETUP
+#line 381 "eval.l"
+{ return( LT ); }
+ FF_BREAK
+case 22:
+FF_RULE_SETUP
+#line 382 "eval.l"
+{ return( GTE ); }
+ FF_BREAK
+case 23:
+FF_RULE_SETUP
+#line 383 "eval.l"
+{ return( LTE ); }
+ FF_BREAK
+case 24:
+FF_RULE_SETUP
+#line 384 "eval.l"
+{ return( '\n' ); }
+ FF_BREAK
+case 25:
+FF_RULE_SETUP
+#line 385 "eval.l"
+{ return( fftext[0] ); }
+ FF_BREAK
+case 26:
+FF_RULE_SETUP
+#line 386 "eval.l"
+ECHO;
+ FF_BREAK
+case FF_STATE_EOF(INITIAL):
+ ffterminate();
+
+ case FF_END_OF_BUFFER:
+ {
+ /* Amount of text matched not including the EOB char. */
+ int ff_amount_of_matched_text = (int) (ff_cp - fftext_ptr) - 1;
+
+ /* Undo the effects of FF_DO_BEFORE_ACTION. */
+ *ff_cp = ff_hold_char;
+ FF_RESTORE_FF_MORE_OFFSET
+
+ if ( ff_current_buffer->ff_buffer_status == FF_BUFFER_NEW )
+ {
+ /* We're scanning a new file or input source. It's
+ * possible that this happened because the user
+ * just pointed ffin at a new source and called
+ * fflex(). If so, then we have to assure
+ * consistency between ff_current_buffer and our
+ * globals. Here is the right place to do so, because
+ * this is the first action (other than possibly a
+ * back-up) that will match for the new input source.
+ */
+ ff_n_chars = ff_current_buffer->ff_n_chars;
+ ff_current_buffer->ff_input_file = ffin;
+ ff_current_buffer->ff_buffer_status = FF_BUFFER_NORMAL;
+ }
+
+ /* Note that here we test for ff_c_buf_p "<=" to the position
+ * of the first EOB in the buffer, since ff_c_buf_p will
+ * already have been incremented past the NUL character
+ * (since all states make transitions on EOB to the
+ * end-of-buffer state). Contrast this with the test
+ * in input().
+ */
+ if ( ff_c_buf_p <= &ff_current_buffer->ff_ch_buf[ff_n_chars] )
+ { /* This was really a NUL. */
+ ff_state_type ff_next_state;
+
+ ff_c_buf_p = fftext_ptr + ff_amount_of_matched_text;
+
+ ff_current_state = ff_get_previous_state();
+
+ /* Okay, we're now positioned to make the NUL
+ * transition. We couldn't have
+ * ff_get_previous_state() go ahead and do it
+ * for us because it doesn't know how to deal
+ * with the possibility of jamming (and we don't
+ * want to build jamming into it because then it
+ * will run more slowly).
+ */
+
+ ff_next_state = ff_try_NUL_trans( ff_current_state );
+
+ ff_bp = fftext_ptr + FF_MORE_ADJ;
+
+ if ( ff_next_state )
+ {
+ /* Consume the NUL. */
+ ff_cp = ++ff_c_buf_p;
+ ff_current_state = ff_next_state;
+ goto ff_match;
+ }
+
+ else
+ {
+ ff_cp = ff_c_buf_p;
+ goto ff_find_action;
+ }
+ }
+
+ else switch ( ff_get_next_buffer() )
+ {
+ case EOB_ACT_END_OF_FILE:
+ {
+ ff_did_buffer_switch_on_eof = 0;
+
+ if ( ffwrap() )
+ {
+ /* Note: because we've taken care in
+ * ff_get_next_buffer() to have set up
+ * fftext, we can now set up
+ * ff_c_buf_p so that if some total
+ * hoser (like flex itself) wants to
+ * call the scanner after we return the
+ * FF_NULL, it'll still work - another
+ * FF_NULL will get returned.
+ */
+ ff_c_buf_p = fftext_ptr + FF_MORE_ADJ;
+
+ ff_act = FF_STATE_EOF(FF_START);
+ goto do_action;
+ }
+
+ else
+ {
+ if ( ! ff_did_buffer_switch_on_eof )
+ FF_NEW_FILE;
+ }
+ break;
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ ff_c_buf_p =
+ fftext_ptr + ff_amount_of_matched_text;
+
+ ff_current_state = ff_get_previous_state();
+
+ ff_cp = ff_c_buf_p;
+ ff_bp = fftext_ptr + FF_MORE_ADJ;
+ goto ff_match;
+
+ case EOB_ACT_LAST_MATCH:
+ ff_c_buf_p =
+ &ff_current_buffer->ff_ch_buf[ff_n_chars];
+
+ ff_current_state = ff_get_previous_state();
+
+ ff_cp = ff_c_buf_p;
+ ff_bp = fftext_ptr + FF_MORE_ADJ;
+ goto ff_find_action;
+ }
+ break;
+ }
+
+ default:
+ FF_FATAL_ERROR(
+ "fatal flex scanner internal error--no action found" );
+ } /* end of action switch */
+ } /* end of scanning one token */
+ } /* end of fflex */
+
+
+/* ff_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ * EOB_ACT_LAST_MATCH -
+ * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ * EOB_ACT_END_OF_FILE - end of file
+ */
+
+static int ff_get_next_buffer()
+ {
+ register char *dest = ff_current_buffer->ff_ch_buf;
+ register char *source = fftext_ptr;
+ register int number_to_move, i;
+ int ret_val;
+
+ if ( ff_c_buf_p > &ff_current_buffer->ff_ch_buf[ff_n_chars + 1] )
+ FF_FATAL_ERROR(
+ "fatal flex scanner internal error--end of buffer missed" );
+
+ if ( ff_current_buffer->ff_fill_buffer == 0 )
+ { /* Don't try to fill the buffer, so this is an EOF. */
+ if ( ff_c_buf_p - fftext_ptr - FF_MORE_ADJ == 1 )
+ {
+ /* We matched a single character, the EOB, so
+ * treat this as a final EOF.
+ */
+ return EOB_ACT_END_OF_FILE;
+ }
+
+ else
+ {
+ /* We matched some text prior to the EOB, first
+ * process it.
+ */
+ return EOB_ACT_LAST_MATCH;
+ }
+ }
+
+ /* Try to read more data. */
+
+ /* First move last chars to start of buffer. */
+ number_to_move = (int) (ff_c_buf_p - fftext_ptr) - 1;
+
+ for ( i = 0; i < number_to_move; ++i )
+ *(dest++) = *(source++);
+
+ if ( ff_current_buffer->ff_buffer_status == FF_BUFFER_EOF_PENDING )
+ /* don't do the read, it's not guaranteed to return an EOF,
+ * just force an EOF
+ */
+ ff_current_buffer->ff_n_chars = ff_n_chars = 0;
+
+ else
+ {
+ int num_to_read =
+ ff_current_buffer->ff_buf_size - number_to_move - 1;
+
+ while ( num_to_read <= 0 )
+ { /* Not enough room in the buffer - grow it. */
+#ifdef FF_USES_REJECT
+ FF_FATAL_ERROR(
+"input buffer overflow, can't enlarge buffer because scanner uses REJECT" );
+#else
+
+ /* just a shorter name for the current buffer */
+ FF_BUFFER_STATE b = ff_current_buffer;
+
+ int ff_c_buf_p_offset =
+ (int) (ff_c_buf_p - b->ff_ch_buf);
+
+ if ( b->ff_is_our_buffer )
+ {
+ int new_size = b->ff_buf_size * 2;
+
+ if ( new_size <= 0 )
+ b->ff_buf_size += b->ff_buf_size / 8;
+ else
+ b->ff_buf_size *= 2;
+
+ b->ff_ch_buf = (char *)
+ /* Include room in for 2 EOB chars. */
+ ff_flex_realloc( (void *) b->ff_ch_buf,
+ b->ff_buf_size + 2 );
+ }
+ else
+ /* Can't grow it, we don't own it. */
+ b->ff_ch_buf = 0;
+
+ if ( ! b->ff_ch_buf )
+ FF_FATAL_ERROR(
+ "fatal error - scanner input buffer overflow" );
+
+ ff_c_buf_p = &b->ff_ch_buf[ff_c_buf_p_offset];
+
+ num_to_read = ff_current_buffer->ff_buf_size -
+ number_to_move - 1;
+#endif
+ }
+
+ if ( num_to_read > FF_READ_BUF_SIZE )
+ num_to_read = FF_READ_BUF_SIZE;
+
+ /* Read in more data. */
+ FF_INPUT( (&ff_current_buffer->ff_ch_buf[number_to_move]),
+ ff_n_chars, num_to_read );
+
+ ff_current_buffer->ff_n_chars = ff_n_chars;
+ }
+
+ if ( ff_n_chars == 0 )
+ {
+ if ( number_to_move == FF_MORE_ADJ )
+ {
+ ret_val = EOB_ACT_END_OF_FILE;
+ ffrestart( ffin );
+ }
+
+ else
+ {
+ ret_val = EOB_ACT_LAST_MATCH;
+ ff_current_buffer->ff_buffer_status =
+ FF_BUFFER_EOF_PENDING;
+ }
+ }
+
+ else
+ ret_val = EOB_ACT_CONTINUE_SCAN;
+
+ ff_n_chars += number_to_move;
+ ff_current_buffer->ff_ch_buf[ff_n_chars] = FF_END_OF_BUFFER_CHAR;
+ ff_current_buffer->ff_ch_buf[ff_n_chars + 1] = FF_END_OF_BUFFER_CHAR;
+
+ fftext_ptr = &ff_current_buffer->ff_ch_buf[0];
+
+ return ret_val;
+ }
+
+
+/* ff_get_previous_state - get the state just before the EOB char was reached */
+
+static ff_state_type ff_get_previous_state()
+ {
+ register ff_state_type ff_current_state;
+ register char *ff_cp;
+
+ ff_current_state = ff_start;
+
+ for ( ff_cp = fftext_ptr + FF_MORE_ADJ; ff_cp < ff_c_buf_p; ++ff_cp )
+ {
+ register FF_CHAR ff_c = (*ff_cp ? ff_ec[FF_SC_TO_UI(*ff_cp)] : 1);
+ if ( ff_accept[ff_current_state] )
+ {
+ ff_last_accepting_state = ff_current_state;
+ ff_last_accepting_cpos = ff_cp;
+ }
+ while ( ff_chk[ff_base[ff_current_state] + ff_c] != ff_current_state )
+ {
+ ff_current_state = (int) ff_def[ff_current_state];
+ if ( ff_current_state >= 160 )
+ ff_c = ff_meta[(unsigned int) ff_c];
+ }
+ ff_current_state = ff_nxt[ff_base[ff_current_state] + (unsigned int) ff_c];
+ }
+
+ return ff_current_state;
+ }
+
+
+/* ff_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ * next_state = ff_try_NUL_trans( current_state );
+ */
+
+#ifdef FF_USE_PROTOS
+static ff_state_type ff_try_NUL_trans( ff_state_type ff_current_state )
+#else
+static ff_state_type ff_try_NUL_trans( ff_current_state )
+ff_state_type ff_current_state;
+#endif
+ {
+ register int ff_is_jam;
+ register char *ff_cp = ff_c_buf_p;
+
+ register FF_CHAR ff_c = 1;
+ if ( ff_accept[ff_current_state] )
+ {
+ ff_last_accepting_state = ff_current_state;
+ ff_last_accepting_cpos = ff_cp;
+ }
+ while ( ff_chk[ff_base[ff_current_state] + ff_c] != ff_current_state )
+ {
+ ff_current_state = (int) ff_def[ff_current_state];
+ if ( ff_current_state >= 160 )
+ ff_c = ff_meta[(unsigned int) ff_c];
+ }
+ ff_current_state = ff_nxt[ff_base[ff_current_state] + (unsigned int) ff_c];
+ ff_is_jam = (ff_current_state == 159);
+
+ return ff_is_jam ? 0 : ff_current_state;
+ }
+
+
+#ifndef FF_NO_UNPUT
+#ifdef FF_USE_PROTOS
+static void ffunput( int c, register char *ff_bp )
+#else
+static void ffunput( c, ff_bp )
+int c;
+register char *ff_bp;
+#endif
+ {
+ register char *ff_cp = ff_c_buf_p;
+
+ /* undo effects of setting up fftext */
+ *ff_cp = ff_hold_char;
+
+ if ( ff_cp < ff_current_buffer->ff_ch_buf + 2 )
+ { /* need to shift things up to make room */
+ /* +2 for EOB chars. */
+ register int number_to_move = ff_n_chars + 2;
+ register char *dest = &ff_current_buffer->ff_ch_buf[
+ ff_current_buffer->ff_buf_size + 2];
+ register char *source =
+ &ff_current_buffer->ff_ch_buf[number_to_move];
+
+ while ( source > ff_current_buffer->ff_ch_buf )
+ *--dest = *--source;
+
+ ff_cp += (int) (dest - source);
+ ff_bp += (int) (dest - source);
+ ff_current_buffer->ff_n_chars =
+ ff_n_chars = ff_current_buffer->ff_buf_size;
+
+ if ( ff_cp < ff_current_buffer->ff_ch_buf + 2 )
+ FF_FATAL_ERROR( "flex scanner push-back overflow" );
+ }
+
+ *--ff_cp = (char) c;
+
+
+ fftext_ptr = ff_bp;
+ ff_hold_char = *ff_cp;
+ ff_c_buf_p = ff_cp;
+ }
+#endif /* ifndef FF_NO_UNPUT */
+
+
+#ifdef __cplusplus
+static int ffinput()
+#else
+static int input()
+#endif
+ {
+ int c;
+
+ *ff_c_buf_p = ff_hold_char;
+
+ if ( *ff_c_buf_p == FF_END_OF_BUFFER_CHAR )
+ {
+ /* ff_c_buf_p now points to the character we want to return.
+ * If this occurs *before* the EOB characters, then it's a
+ * valid NUL; if not, then we've hit the end of the buffer.
+ */
+ if ( ff_c_buf_p < &ff_current_buffer->ff_ch_buf[ff_n_chars] )
+ /* This was really a NUL. */
+ *ff_c_buf_p = '\0';
+
+ else
+ { /* need more input */
+ int offset = ff_c_buf_p - fftext_ptr;
+ ++ff_c_buf_p;
+
+ switch ( ff_get_next_buffer() )
+ {
+ case EOB_ACT_LAST_MATCH:
+ /* This happens because ff_g_n_b()
+ * sees that we've accumulated a
+ * token and flags that we need to
+ * try matching the token before
+ * proceeding. But for input(),
+ * there's no matching to consider.
+ * So convert the EOB_ACT_LAST_MATCH
+ * to EOB_ACT_END_OF_FILE.
+ */
+
+ /* Reset buffer status. */
+ ffrestart( ffin );
+
+ /* fall through */
+
+ case EOB_ACT_END_OF_FILE:
+ {
+ if ( ffwrap() )
+ return EOF;
+
+ if ( ! ff_did_buffer_switch_on_eof )
+ FF_NEW_FILE;
+#ifdef __cplusplus
+ return ffinput();
+#else
+ return input();
+#endif
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ ff_c_buf_p = fftext_ptr + offset;
+ break;
+ }
+ }
+ }
+
+ c = *(unsigned char *) ff_c_buf_p; /* cast for 8-bit char's */
+ *ff_c_buf_p = '\0'; /* preserve fftext */
+ ff_hold_char = *++ff_c_buf_p;
+
+
+ return c;
+ }
+
+
+#ifdef FF_USE_PROTOS
+void ffrestart( FILE *input_file )
+#else
+void ffrestart( input_file )
+FILE *input_file;
+#endif
+ {
+ if ( ! ff_current_buffer )
+ ff_current_buffer = ff_create_buffer( ffin, FF_BUF_SIZE );
+
+ ff_init_buffer( ff_current_buffer, input_file );
+ ff_load_buffer_state();
+ }
+
+
+#ifdef FF_USE_PROTOS
+void ff_switch_to_buffer( FF_BUFFER_STATE new_buffer )
+#else
+void ff_switch_to_buffer( new_buffer )
+FF_BUFFER_STATE new_buffer;
+#endif
+ {
+ if ( ff_current_buffer == new_buffer )
+ return;
+
+ if ( ff_current_buffer )
+ {
+ /* Flush out information for old buffer. */
+ *ff_c_buf_p = ff_hold_char;
+ ff_current_buffer->ff_buf_pos = ff_c_buf_p;
+ ff_current_buffer->ff_n_chars = ff_n_chars;
+ }
+
+ ff_current_buffer = new_buffer;
+ ff_load_buffer_state();
+
+ /* We don't actually know whether we did this switch during
+ * EOF (ffwrap()) processing, but the only time this flag
+ * is looked at is after ffwrap() is called, so it's safe
+ * to go ahead and always set it.
+ */
+ ff_did_buffer_switch_on_eof = 1;
+ }
+
+
+#ifdef FF_USE_PROTOS
+void ff_load_buffer_state( void )
+#else
+void ff_load_buffer_state()
+#endif
+ {
+ ff_n_chars = ff_current_buffer->ff_n_chars;
+ fftext_ptr = ff_c_buf_p = ff_current_buffer->ff_buf_pos;
+ ffin = ff_current_buffer->ff_input_file;
+ ff_hold_char = *ff_c_buf_p;
+ }
+
+
+#ifdef FF_USE_PROTOS
+FF_BUFFER_STATE ff_create_buffer( FILE *file, int size )
+#else
+FF_BUFFER_STATE ff_create_buffer( file, size )
+FILE *file;
+int size;
+#endif
+ {
+ FF_BUFFER_STATE b;
+
+ b = (FF_BUFFER_STATE) ff_flex_alloc( sizeof( struct ff_buffer_state ) );
+ if ( ! b )
+ FF_FATAL_ERROR( "out of dynamic memory in ff_create_buffer()" );
+
+ b->ff_buf_size = size;
+
+ /* ff_ch_buf has to be 2 characters longer than the size given because
+ * we need to put in 2 end-of-buffer characters.
+ */
+ b->ff_ch_buf = (char *) ff_flex_alloc( b->ff_buf_size + 2 );
+ if ( ! b->ff_ch_buf )
+ FF_FATAL_ERROR( "out of dynamic memory in ff_create_buffer()" );
+
+ b->ff_is_our_buffer = 1;
+
+ ff_init_buffer( b, file );
+
+ return b;
+ }
+
+
+#ifdef FF_USE_PROTOS
+void ff_delete_buffer( FF_BUFFER_STATE b )
+#else
+void ff_delete_buffer( b )
+FF_BUFFER_STATE b;
+#endif
+ {
+ if ( ! b )
+ return;
+
+ if ( b == ff_current_buffer )
+ ff_current_buffer = (FF_BUFFER_STATE) 0;
+
+ if ( b->ff_is_our_buffer )
+ ff_flex_free( (void *) b->ff_ch_buf );
+
+ ff_flex_free( (void *) b );
+ }
+
+
+#ifndef FF_ALWAYS_INTERACTIVE
+#ifndef FF_NEVER_INTERACTIVE
+extern int isatty FF_PROTO(( int ));
+#endif
+#endif
+
+#ifdef FF_USE_PROTOS
+void ff_init_buffer( FF_BUFFER_STATE b, FILE *file )
+#else
+void ff_init_buffer( b, file )
+FF_BUFFER_STATE b;
+FILE *file;
+#endif
+
+
+ {
+ ff_flush_buffer( b );
+
+ b->ff_input_file = file;
+ b->ff_fill_buffer = 1;
+
+#if FF_ALWAYS_INTERACTIVE
+ b->ff_is_interactive = 1;
+#else
+#if FF_NEVER_INTERACTIVE
+ b->ff_is_interactive = 0;
+#else
+ b->ff_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+#endif
+#endif
+ }
+
+
+#ifdef FF_USE_PROTOS
+void ff_flush_buffer( FF_BUFFER_STATE b )
+#else
+void ff_flush_buffer( b )
+FF_BUFFER_STATE b;
+#endif
+
+ {
+ if ( ! b )
+ return;
+
+ b->ff_n_chars = 0;
+
+ /* We always need two end-of-buffer characters. The first causes
+ * a transition to the end-of-buffer state. The second causes
+ * a jam in that state.
+ */
+ b->ff_ch_buf[0] = FF_END_OF_BUFFER_CHAR;
+ b->ff_ch_buf[1] = FF_END_OF_BUFFER_CHAR;
+
+ b->ff_buf_pos = &b->ff_ch_buf[0];
+
+ b->ff_at_bol = 1;
+ b->ff_buffer_status = FF_BUFFER_NEW;
+
+ if ( b == ff_current_buffer )
+ ff_load_buffer_state();
+ }
+
+
+#ifndef FF_NO_SCAN_BUFFER
+#ifdef FF_USE_PROTOS
+FF_BUFFER_STATE ff_scan_buffer( char *base, ff_size_t size )
+#else
+FF_BUFFER_STATE ff_scan_buffer( base, size )
+char *base;
+ff_size_t size;
+#endif
+ {
+ FF_BUFFER_STATE b;
+
+ if ( size < 2 ||
+ base[size-2] != FF_END_OF_BUFFER_CHAR ||
+ base[size-1] != FF_END_OF_BUFFER_CHAR )
+ /* They forgot to leave room for the EOB's. */
+ return 0;
+
+ b = (FF_BUFFER_STATE) ff_flex_alloc( sizeof( struct ff_buffer_state ) );
+ if ( ! b )
+ FF_FATAL_ERROR( "out of dynamic memory in ff_scan_buffer()" );
+
+ b->ff_buf_size = size - 2; /* "- 2" to take care of EOB's */
+ b->ff_buf_pos = b->ff_ch_buf = base;
+ b->ff_is_our_buffer = 0;
+ b->ff_input_file = 0;
+ b->ff_n_chars = b->ff_buf_size;
+ b->ff_is_interactive = 0;
+ b->ff_at_bol = 1;
+ b->ff_fill_buffer = 0;
+ b->ff_buffer_status = FF_BUFFER_NEW;
+
+ ff_switch_to_buffer( b );
+
+ return b;
+ }
+#endif
+
+
+#ifndef FF_NO_SCAN_STRING
+#ifdef FF_USE_PROTOS
+FF_BUFFER_STATE ff_scan_string( ffconst char *ff_str )
+#else
+FF_BUFFER_STATE ff_scan_string( ff_str )
+ffconst char *ff_str;
+#endif
+ {
+ int len;
+ for ( len = 0; ff_str[len]; ++len )
+ ;
+
+ return ff_scan_bytes( ff_str, len );
+ }
+#endif
+
+
+#ifndef FF_NO_SCAN_BYTES
+#ifdef FF_USE_PROTOS
+FF_BUFFER_STATE ff_scan_bytes( ffconst char *bytes, int len )
+#else
+FF_BUFFER_STATE ff_scan_bytes( bytes, len )
+ffconst char *bytes;
+int len;
+#endif
+ {
+ FF_BUFFER_STATE b;
+ char *buf;
+ ff_size_t n;
+ int i;
+
+ /* Get memory for full buffer, including space for trailing EOB's. */
+ n = len + 2;
+ buf = (char *) ff_flex_alloc( n );
+ if ( ! buf )
+ FF_FATAL_ERROR( "out of dynamic memory in ff_scan_bytes()" );
+
+ for ( i = 0; i < len; ++i )
+ buf[i] = bytes[i];
+
+ buf[len] = buf[len+1] = FF_END_OF_BUFFER_CHAR;
+
+ b = ff_scan_buffer( buf, n );
+ if ( ! b )
+ FF_FATAL_ERROR( "bad buffer in ff_scan_bytes()" );
+
+ /* It's okay to grow etc. this buffer, and we should throw it
+ * away when we're done.
+ */
+ b->ff_is_our_buffer = 1;
+
+ return b;
+ }
+#endif
+
+
+#ifndef FF_NO_PUSH_STATE
+#ifdef FF_USE_PROTOS
+static void ff_push_state( int new_state )
+#else
+static void ff_push_state( new_state )
+int new_state;
+#endif
+ {
+ if ( ff_start_stack_ptr >= ff_start_stack_depth )
+ {
+ ff_size_t new_size;
+
+ ff_start_stack_depth += FF_START_STACK_INCR;
+ new_size = ff_start_stack_depth * sizeof( int );
+
+ if ( ! ff_start_stack )
+ ff_start_stack = (int *) ff_flex_alloc( new_size );
+
+ else
+ ff_start_stack = (int *) ff_flex_realloc(
+ (void *) ff_start_stack, new_size );
+
+ if ( ! ff_start_stack )
+ FF_FATAL_ERROR(
+ "out of memory expanding start-condition stack" );
+ }
+
+ ff_start_stack[ff_start_stack_ptr++] = FF_START;
+
+ BEGIN(new_state);
+ }
+#endif
+
+
+#ifndef FF_NO_POP_STATE
+static void ff_pop_state()
+ {
+ if ( --ff_start_stack_ptr < 0 )
+ FF_FATAL_ERROR( "start-condition stack underflow" );
+
+ BEGIN(ff_start_stack[ff_start_stack_ptr]);
+ }
+#endif
+
+
+#ifndef FF_NO_TOP_STATE
+static int ff_top_state()
+ {
+ return ff_start_stack[ff_start_stack_ptr - 1];
+ }
+#endif
+
+#ifndef FF_EXIT_FAILURE
+#define FF_EXIT_FAILURE 2
+#endif
+
+#ifdef FF_USE_PROTOS
+static void ff_fatal_error( ffconst char msg[] )
+#else
+static void ff_fatal_error( msg )
+char msg[];
+#endif
+ {
+ (void) fprintf( stderr, "%s\n", msg );
+ exit( FF_EXIT_FAILURE );
+ }
+
+
+
+/* Redefine ffless() so it works in section 3 code. */
+
+#undef ffless
+#define ffless(n) \
+ do \
+ { \
+ /* Undo effects of setting up fftext. */ \
+ fftext[ffleng] = ff_hold_char; \
+ ff_c_buf_p = fftext + n; \
+ ff_hold_char = *ff_c_buf_p; \
+ *ff_c_buf_p = '\0'; \
+ ffleng = n; \
+ } \
+ while ( 0 )
+
+
+/* Internal utility routines. */
+
+#ifndef fftext_ptr
+#ifdef FF_USE_PROTOS
+static void ff_flex_strncpy( char *s1, ffconst char *s2, int n )
+#else
+static void ff_flex_strncpy( s1, s2, n )
+char *s1;
+ffconst char *s2;
+int n;
+#endif
+ {
+ register int i;
+ for ( i = 0; i < n; ++i )
+ s1[i] = s2[i];
+ }
+#endif
+
+#ifdef FF_NEED_STRLEN
+#ifdef FF_USE_PROTOS
+static int ff_flex_strlen( ffconst char *s )
+#else
+static int ff_flex_strlen( s )
+ffconst char *s;
+#endif
+ {
+ register int n;
+ for ( n = 0; s[n]; ++n )
+ ;
+
+ return n;
+ }
+#endif
+
+
+#ifdef FF_USE_PROTOS
+static void *ff_flex_alloc( ff_size_t size )
+#else
+static void *ff_flex_alloc( size )
+ff_size_t size;
+#endif
+ {
+ return (void *) malloc( size );
+ }
+
+#ifdef FF_USE_PROTOS
+static void *ff_flex_realloc( void *ptr, ff_size_t size )
+#else
+static void *ff_flex_realloc( ptr, size )
+void *ptr;
+ff_size_t size;
+#endif
+ {
+ /* The cast to (char *) in the following accommodates both
+ * implementations that use char* generic pointers, and those
+ * that use void* generic pointers. It works with the latter
+ * because both ANSI C and C++ allow castless assignment from
+ * any pointer type to void*, and deal with argument conversions
+ * as though doing an assignment.
+ */
+ return (void *) realloc( (char *) ptr, size );
+ }
+
+#ifdef FF_USE_PROTOS
+static void ff_flex_free( void *ptr )
+#else
+static void ff_flex_free( ptr )
+void *ptr;
+#endif
+ {
+ free( ptr );
+ }
+
+#if FF_MAIN
+int main()
+ {
+ fflex();
+ return 0;
+ }
+#endif
+#line 386 "eval.l"
+
+
+int ffwrap()
+{
+ /* MJT -- 13 June 1996
+ Supplied for compatibility with
+ pre-2.5.1 versions of flex which
+ do not recognize %option noffwrap
+ */
+ return(1);
+}
+
+/*
+ expr_read is lifted from old ftools.skel.
+ Now we can use any version of flex with
+ no .skel file necessary! MJT - 13 June 1996
+
+ keep a memory of how many bytes have been
+ read previously, so that an unlimited-sized
+ buffer can be supported. PDW - 28 Feb 1998
+*/
+
+static int expr_read(char *buf, int nbytes)
+{
+ int n;
+
+ n = 0;
+ if( !gParse.is_eobuf ) {
+ do {
+ buf[n++] = gParse.expr[gParse.index++];
+ } while ((n<nbytes)&&(gParse.expr[gParse.index] != '\0'));
+ if( gParse.expr[gParse.index] == '\0' ) gParse.is_eobuf = 1;
+ }
+ buf[n] = '\0';
+ return(n);
+}
+
+int ffGetVariable( char *varName, FFSTYPE *thelval )
+{
+ int varNum, type;
+ char errMsg[MAXVARNAME+25];
+
+ varNum = find_variable( varName );
+ if( varNum<0 ) {
+ if( gParse.getData ) {
+ type = (*gParse.getData)( varName, thelval );
+ } else {
+ type = pERROR;
+ gParse.status = PARSE_SYNTAX_ERR;
+ strcpy (errMsg,"Unable to find data: ");
+ strncat(errMsg, varName, MAXVARNAME);
+ ffpmsg (errMsg);
+ }
+ } else {
+ /* Convert variable type into expression type */
+ switch( gParse.varData[ varNum ].type ) {
+ case LONG:
+ case DOUBLE: type = COLUMN; break;
+ case BOOLEAN: type = BCOLUMN; break;
+ case STRING: type = SCOLUMN; break;
+ case BITSTR: type = BITCOL; break;
+ default:
+ type = pERROR;
+ gParse.status = PARSE_SYNTAX_ERR;
+ strcpy (errMsg,"Bad datatype for data: ");
+ strncat(errMsg, varName, MAXVARNAME);
+ ffpmsg (errMsg);
+ break;
+ }
+ thelval->lng = varNum;
+ }
+ return( type );
+}
+
+static int find_variable(char *varName)
+{
+ int i;
+
+ if( gParse.nCols )
+ for( i=0; i<gParse.nCols; i++ ) {
+ if( ! strncasecmp(gParse.varData[i].name,varName,MAXVARNAME) ) {
+ return( i );
+ }
+ }
+ return( -1 );
+}
+
+#if defined(vms) || defined(__vms) || defined(WIN32) || defined(__WIN32__) || defined(macintosh)
+
+/* ================================================================== */
+/* A hack for nonunix machines, which lack strcasecmp and strncasecmp */
+/* ================================================================== */
+
+int strcasecmp(const char *s1, const char *s2)
+{
+ char c1, c2;
+
+ for (;;) {
+ c1 = toupper( *s1 );
+ c2 = toupper( *s2 );
+
+ if (c1 < c2) return(-1);
+ if (c1 > c2) return(1);
+ if (c1 == 0) return(0);
+ s1++;
+ s2++;
+ }
+}
+
+int strncasecmp(const char *s1, const char *s2, size_t n)
+{
+ char c1, c2;
+
+ for (; n-- ;) {
+ c1 = toupper( *s1 );
+ c2 = toupper( *s2 );
+
+ if (c1 < c2) return(-1);
+ if (c1 > c2) return(1);
+ if (c1 == 0) return(0);
+ s1++;
+ s2++;
+ }
+ return(0);
+}
+
+#endif
diff --git a/pkg/tbtables/cfitsio/eval_tab.h b/pkg/tbtables/cfitsio/eval_tab.h
new file mode 100644
index 00000000..2715f0fd
--- /dev/null
+++ b/pkg/tbtables/cfitsio/eval_tab.h
@@ -0,0 +1,41 @@
+typedef union {
+ int Node; /* Index of Node */
+ double dbl; /* real value */
+ long lng; /* integer value */
+ char log; /* logical value */
+ char str[256]; /* string value */
+} FFSTYPE;
+#define BOOLEAN 258
+#define LONG 259
+#define DOUBLE 260
+#define STRING 261
+#define BITSTR 262
+#define FUNCTION 263
+#define BFUNCTION 264
+#define GTIFILTER 265
+#define REGFILTER 266
+#define COLUMN 267
+#define BCOLUMN 268
+#define SCOLUMN 269
+#define BITCOL 270
+#define ROWREF 271
+#define NULLREF 272
+#define SNULLREF 273
+#define OR 274
+#define AND 275
+#define EQ 276
+#define NE 277
+#define GT 278
+#define LT 279
+#define LTE 280
+#define GTE 281
+#define POWER 282
+#define NOT 283
+#define INTCAST 284
+#define FLTCAST 285
+#define UMINUS 286
+#define ACCUM 287
+#define DIFF 288
+
+
+extern FFSTYPE fflval;
diff --git a/pkg/tbtables/cfitsio/eval_y.c b/pkg/tbtables/cfitsio/eval_y.c
new file mode 100644
index 00000000..56e7690a
--- /dev/null
+++ b/pkg/tbtables/cfitsio/eval_y.c
@@ -0,0 +1,6686 @@
+
+/* A Bison parser, made from eval.y
+ by GNU Bison version 1.25
+ */
+
+#define FFBISON 1 /* Identify Bison output. */
+
+#define BOOLEAN 258
+#define LONG 259
+#define DOUBLE 260
+#define STRING 261
+#define BITSTR 262
+#define FUNCTION 263
+#define BFUNCTION 264
+#define GTIFILTER 265
+#define REGFILTER 266
+#define COLUMN 267
+#define BCOLUMN 268
+#define SCOLUMN 269
+#define BITCOL 270
+#define ROWREF 271
+#define NULLREF 272
+#define SNULLREF 273
+#define OR 274
+#define AND 275
+#define EQ 276
+#define NE 277
+#define GT 278
+#define LT 279
+#define LTE 280
+#define GTE 281
+#define POWER 282
+#define NOT 283
+#define INTCAST 284
+#define FLTCAST 285
+#define UMINUS 286
+#define ACCUM 287
+#define DIFF 288
+
+#line 1 "eval.y"
+
+/************************************************************************/
+/* */
+/* CFITSIO Lexical Parser */
+/* */
+/* This file is one of 3 files containing code which parses an */
+/* arithmetic expression and evaluates it in the context of an input */
+/* FITS file table extension. The CFITSIO lexical parser is divided */
+/* into the following 3 parts/files: the CFITSIO "front-end", */
+/* eval_f.c, contains the interface between the user/CFITSIO and the */
+/* real core of the parser; the FLEX interpreter, eval_l.c, takes the */
+/* input string and parses it into tokens and identifies the FITS */
+/* information required to evaluate the expression (ie, keywords and */
+/* columns); and, the BISON grammar and evaluation routines, eval_y.c, */
+/* receives the FLEX output and determines and performs the actual */
+/* operations. The files eval_l.c and eval_y.c are produced from */
+/* running flex and bison on the files eval.l and eval.y, respectively. */
+/* (flex and bison are available from any GNU archive: see www.gnu.org) */
+/* */
+/* The grammar rules, rather than evaluating the expression in situ, */
+/* builds a tree, or Nodal, structure mapping out the order of */
+/* operations and expression dependencies. This "compilation" process */
+/* allows for much faster processing of multiple rows. This technique */
+/* was developed by Uwe Lammers of the XMM Science Analysis System, */
+/* although the CFITSIO implementation is entirely code original. */
+/* */
+/* */
+/* Modification History: */
+/* */
+/* Kent Blackburn c1992 Original parser code developed for the */
+/* FTOOLS software package, in particular, */
+/* the fselect task. */
+/* Kent Blackburn c1995 BIT column support added */
+/* Peter D Wilson Feb 1998 Vector column support added */
+/* Peter D Wilson May 1998 Ported to CFITSIO library. User */
+/* interface routines written, in essence */
+/* making fselect, fcalc, and maketime */
+/* capabilities available to all tools */
+/* via single function calls. */
+/* Peter D Wilson Jun 1998 Major rewrite of parser core, so as to */
+/* create a run-time evaluation tree, */
+/* inspired by the work of Uwe Lammers, */
+/* resulting in a speed increase of */
+/* 10-100 times. */
+/* Peter D Wilson Jul 1998 gtifilter(a,b,c,d) function added */
+/* Peter D Wilson Aug 1998 regfilter(a,b,c,d) function added */
+/* Peter D Wilson Jul 1999 Make parser fitsfile-independent, */
+/* allowing a purely vector-based usage */
+/* Craig B Markwardt Jun 2004 Add MEDIAN() function */
+/* Craig B Markwardt Jun 2004 Add SUM(), and MIN/MAX() for bit arrays */
+/* Craig B Markwardt Jun 2004 Allow subscripting of nX bit arrays */
+/* Craig B Markwardt Jun 2004 Implement statistical functions */
+/* NVALID(), AVERAGE(), and STDDEV() */
+/* for integer and floating point vectors */
+/* Craig B Markwardt Jun 2004 Use NULL values for range errors instead*/
+/* of throwing a parse error */
+/* Craig B Markwardt Oct 2004 Add ACCUM() and SEQDIFF() functions */
+/* */
+/************************************************************************/
+
+#define APPROX 1.0e-7
+#include "eval_defs.h"
+#include "region.h"
+#include <time.h>
+
+#include <stdlib.h>
+
+#ifndef alloca
+#define alloca malloc
+#endif
+
+ /* Shrink the initial stack depth to keep local data <32K (mac limit) */
+ /* yacc will allocate more space if needed, though. */
+#define FFINITDEPTH 100
+
+/***************************************************************/
+/* Replace Bison's BACKUP macro with one that fixes a bug -- */
+/* must update state after popping the stack -- and allows */
+/* popping multiple terms at one time. */
+/***************************************************************/
+
+#define FFNEWBACKUP(token, value) \
+ do \
+ if (ffchar == FFEMPTY ) \
+ { ffchar = (token); \
+ memcpy( &fflval, &(value), sizeof(value) ); \
+ ffchar1 = FFTRANSLATE (ffchar); \
+ while (fflen--) FFPOPSTACK; \
+ ffstate = *ffssp; \
+ goto ffbackup; \
+ } \
+ else \
+ { fferror ("syntax error: cannot back up"); FFERROR; } \
+ while (0)
+
+/***************************************************************/
+/* Useful macros for accessing/testing Nodes */
+/***************************************************************/
+
+#define TEST(a) if( (a)<0 ) FFERROR
+#define SIZE(a) gParse.Nodes[ a ].value.nelem
+#define TYPE(a) gParse.Nodes[ a ].type
+#define PROMOTE(a,b) if( TYPE(a) > TYPE(b) ) \
+ b = New_Unary( TYPE(a), 0, b ); \
+ else if( TYPE(a) < TYPE(b) ) \
+ a = New_Unary( TYPE(b), 0, a );
+
+/***** Internal functions *****/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static int Alloc_Node ( void );
+static void Free_Last_Node( void );
+static void Evaluate_Node ( int thisNode );
+
+static int New_Const ( int returnType, void *value, long len );
+static int New_Column( int ColNum );
+static int New_Offset( int ColNum, int offset );
+static int New_Unary ( int returnType, int Op, int Node1 );
+static int New_BinOp ( int returnType, int Node1, int Op, int Node2 );
+static int New_Func ( int returnType, funcOp Op, int nNodes,
+ int Node1, int Node2, int Node3, int Node4,
+ int Node5, int Node6, int Node7 );
+static int New_Deref ( int Var, int nDim,
+ int Dim1, int Dim2, int Dim3, int Dim4, int Dim5 );
+static int New_GTI ( char *fname, int Node1, char *start, char *stop );
+static int New_REG ( char *fname, int NodeX, int NodeY, char *colNames );
+static int New_Vector( int subNode );
+static int Close_Vec ( int vecNode );
+static int Locate_Col( Node *this );
+static int Test_Dims ( int Node1, int Node2 );
+static void Copy_Dims ( int Node1, int Node2 );
+
+static void Allocate_Ptrs( Node *this );
+static void Do_Unary ( Node *this );
+static void Do_Offset ( Node *this );
+static void Do_BinOp_bit ( Node *this );
+static void Do_BinOp_str ( Node *this );
+static void Do_BinOp_log ( Node *this );
+static void Do_BinOp_lng ( Node *this );
+static void Do_BinOp_dbl ( Node *this );
+static void Do_Func ( Node *this );
+static void Do_Deref ( Node *this );
+static void Do_GTI ( Node *this );
+static void Do_REG ( Node *this );
+static void Do_Vector ( Node *this );
+
+static long Search_GTI ( double evtTime, long nGTI, double *start,
+ double *stop, int ordered );
+
+static char saobox (double xcen, double ycen, double xwid, double ywid,
+ double rot, double xcol, double ycol);
+static char ellipse(double xcen, double ycen, double xrad, double yrad,
+ double rot, double xcol, double ycol);
+static char circle (double xcen, double ycen, double rad,
+ double xcol, double ycol);
+static char bnear (double x, double y, double tolerance);
+static char bitcmp (char *bitstrm1, char *bitstrm2);
+static char bitlgte(char *bits1, int oper, char *bits2);
+
+static void bitand(char *result, char *bitstrm1, char *bitstrm2);
+static void bitor (char *result, char *bitstrm1, char *bitstrm2);
+static void bitnot(char *result, char *bits);
+
+static void fferror(char *msg);
+
+#ifdef __cplusplus
+ }
+#endif
+
+
+#line 175 "eval.y"
+typedef union {
+ int Node; /* Index of Node */
+ double dbl; /* real value */
+ long lng; /* integer value */
+ char log; /* logical value */
+ char str[256]; /* string value */
+} FFSTYPE;
+#include <stdio.h>
+
+#ifndef __cplusplus
+#ifndef __STDC__
+#define const
+#endif
+#endif
+
+
+
+#define FFFINAL 276
+#define FFFLAG -32768
+#define FFNTBASE 53
+
+#define FFTRANSLATE(x) ((unsigned)(x) <= 288 ? fftranslate[x] : 61)
+
+static const char fftranslate[] = { 0,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 49,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 36, 40, 2, 51,
+ 52, 37, 34, 19, 35, 2, 38, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 21, 2, 2,
+ 20, 2, 24, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 46, 2, 50, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 22, 39, 23, 29, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 1, 2, 3, 4, 5,
+ 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 25, 26, 27, 28, 30, 31, 32,
+ 33, 41, 42, 43, 44, 45, 47, 48
+};
+
+#if FFDEBUG != 0
+static const short ffprhs[] = { 0,
+ 0, 1, 4, 6, 9, 12, 15, 18, 21, 24,
+ 28, 31, 35, 39, 43, 46, 49, 51, 53, 58,
+ 62, 66, 70, 75, 82, 91, 102, 115, 118, 122,
+ 124, 126, 128, 133, 135, 137, 141, 145, 149, 153,
+ 157, 161, 164, 167, 171, 175, 179, 185, 191, 197,
+ 200, 204, 208, 212, 216, 222, 227, 234, 243, 254,
+ 267, 270, 273, 276, 279, 281, 283, 288, 292, 296,
+ 300, 304, 308, 312, 316, 320, 324, 328, 332, 336,
+ 340, 344, 348, 352, 356, 360, 364, 368, 372, 376,
+ 380, 386, 392, 396, 400, 404, 410, 418, 430, 446,
+ 449, 453, 459, 469, 473, 481, 491, 496, 503, 512,
+ 523, 536, 539, 543, 545, 547, 552, 554, 558, 562,
+ 568
+};
+
+static const short ffrhs[] = { -1,
+ 53, 54, 0, 49, 0, 57, 49, 0, 58, 49,
+ 0, 60, 49, 0, 59, 49, 0, 1, 49, 0,
+ 22, 58, 0, 55, 19, 58, 0, 22, 57, 0,
+ 56, 19, 57, 0, 56, 19, 58, 0, 55, 19,
+ 57, 0, 56, 23, 0, 55, 23, 0, 7, 0,
+ 15, 0, 15, 22, 57, 23, 0, 59, 40, 59,
+ 0, 59, 39, 59, 0, 59, 34, 59, 0, 59,
+ 46, 57, 50, 0, 59, 46, 57, 19, 57, 50,
+ 0, 59, 46, 57, 19, 57, 19, 57, 50, 0,
+ 59, 46, 57, 19, 57, 19, 57, 19, 57, 50,
+ 0, 59, 46, 57, 19, 57, 19, 57, 19, 57,
+ 19, 57, 50, 0, 42, 59, 0, 51, 59, 52,
+ 0, 4, 0, 5, 0, 12, 0, 12, 22, 57,
+ 23, 0, 16, 0, 17, 0, 57, 36, 57, 0,
+ 57, 34, 57, 0, 57, 35, 57, 0, 57, 37,
+ 57, 0, 57, 38, 57, 0, 57, 41, 57, 0,
+ 34, 57, 0, 35, 57, 0, 51, 57, 52, 0,
+ 57, 37, 58, 0, 58, 37, 57, 0, 58, 24,
+ 57, 21, 57, 0, 58, 24, 58, 21, 57, 0,
+ 58, 24, 57, 21, 58, 0, 8, 52, 0, 8,
+ 58, 52, 0, 8, 60, 52, 0, 8, 59, 52,
+ 0, 8, 57, 52, 0, 8, 57, 19, 57, 52,
+ 0, 57, 46, 57, 50, 0, 57, 46, 57, 19,
+ 57, 50, 0, 57, 46, 57, 19, 57, 19, 57,
+ 50, 0, 57, 46, 57, 19, 57, 19, 57, 19,
+ 57, 50, 0, 57, 46, 57, 19, 57, 19, 57,
+ 19, 57, 19, 57, 50, 0, 43, 57, 0, 43,
+ 58, 0, 44, 57, 0, 44, 58, 0, 3, 0,
+ 13, 0, 13, 22, 57, 23, 0, 59, 27, 59,
+ 0, 59, 28, 59, 0, 59, 31, 59, 0, 59,
+ 32, 59, 0, 59, 30, 59, 0, 59, 33, 59,
+ 0, 57, 30, 57, 0, 57, 31, 57, 0, 57,
+ 33, 57, 0, 57, 32, 57, 0, 57, 29, 57,
+ 0, 57, 27, 57, 0, 57, 28, 57, 0, 60,
+ 27, 60, 0, 60, 28, 60, 0, 60, 30, 60,
+ 0, 60, 33, 60, 0, 60, 31, 60, 0, 60,
+ 32, 60, 0, 58, 26, 58, 0, 58, 25, 58,
+ 0, 58, 27, 58, 0, 58, 28, 58, 0, 57,
+ 20, 57, 21, 57, 0, 58, 24, 58, 21, 58,
+ 0, 9, 57, 52, 0, 9, 58, 52, 0, 9,
+ 60, 52, 0, 8, 58, 19, 58, 52, 0, 9,
+ 57, 19, 57, 19, 57, 52, 0, 9, 57, 19,
+ 57, 19, 57, 19, 57, 19, 57, 52, 0, 9,
+ 57, 19, 57, 19, 57, 19, 57, 19, 57, 19,
+ 57, 19, 57, 52, 0, 10, 52, 0, 10, 6,
+ 52, 0, 10, 6, 19, 57, 52, 0, 10, 6,
+ 19, 57, 19, 6, 19, 6, 52, 0, 11, 6,
+ 52, 0, 11, 6, 19, 57, 19, 57, 52, 0,
+ 11, 6, 19, 57, 19, 57, 19, 6, 52, 0,
+ 58, 46, 57, 50, 0, 58, 46, 57, 19, 57,
+ 50, 0, 58, 46, 57, 19, 57, 19, 57, 50,
+ 0, 58, 46, 57, 19, 57, 19, 57, 19, 57,
+ 50, 0, 58, 46, 57, 19, 57, 19, 57, 19,
+ 57, 19, 57, 50, 0, 42, 58, 0, 51, 58,
+ 52, 0, 6, 0, 14, 0, 14, 22, 57, 23,
+ 0, 18, 0, 51, 60, 52, 0, 60, 34, 60,
+ 0, 58, 24, 60, 21, 60, 0, 8, 60, 19,
+ 60, 52, 0
+};
+
+#endif
+
+#if FFDEBUG != 0
+static const short ffrline[] = { 0,
+ 226, 227, 230, 231, 237, 243, 249, 255, 258, 260,
+ 273, 275, 288, 299, 313, 317, 321, 326, 328, 337,
+ 340, 343, 346, 348, 350, 352, 354, 356, 359, 363,
+ 365, 367, 369, 378, 380, 382, 385, 388, 391, 394,
+ 397, 400, 402, 404, 406, 410, 414, 433, 452, 471,
+ 481, 495, 507, 532, 612, 664, 666, 668, 670, 672,
+ 674, 676, 678, 680, 684, 686, 688, 697, 700, 703,
+ 706, 709, 712, 715, 718, 721, 724, 727, 730, 733,
+ 736, 739, 742, 745, 748, 751, 754, 756, 758, 760,
+ 763, 770, 787, 800, 813, 824, 840, 858, 879, 906,
+ 910, 914, 917, 921, 925, 928, 932, 934, 936, 938,
+ 940, 942, 944, 948, 951, 953, 962, 964, 966, 969,
+ 981
+};
+#endif
+
+
+#if FFDEBUG != 0 || defined (FFERROR_VERBOSE)
+
+static const char * const fftname[] = { "$","error","$undefined.","BOOLEAN",
+"LONG","DOUBLE","STRING","BITSTR","FUNCTION","BFUNCTION","GTIFILTER","REGFILTER",
+"COLUMN","BCOLUMN","SCOLUMN","BITCOL","ROWREF","NULLREF","SNULLREF","','","'='",
+"':'","'{'","'}'","'?'","OR","AND","EQ","NE","'~'","GT","LT","LTE","GTE","'+'",
+"'-'","'%'","'*'","'/'","'|'","'&'","POWER","NOT","INTCAST","FLTCAST","UMINUS",
+"'['","ACCUM","DIFF","'\\n'","']'","'('","')'","lines","line","bvector","vector",
+"expr","bexpr","bits","sexpr", NULL
+};
+#endif
+
+static const short ffr1[] = { 0,
+ 53, 53, 54, 54, 54, 54, 54, 54, 55, 55,
+ 56, 56, 56, 56, 57, 58, 59, 59, 59, 59,
+ 59, 59, 59, 59, 59, 59, 59, 59, 59, 57,
+ 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
+ 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
+ 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
+ 57, 57, 57, 57, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 60, 60, 60, 60, 60, 60, 60,
+ 60
+};
+
+static const short ffr2[] = { 0,
+ 0, 2, 1, 2, 2, 2, 2, 2, 2, 3,
+ 2, 3, 3, 3, 2, 2, 1, 1, 4, 3,
+ 3, 3, 4, 6, 8, 10, 12, 2, 3, 1,
+ 1, 1, 4, 1, 1, 3, 3, 3, 3, 3,
+ 3, 2, 2, 3, 3, 3, 5, 5, 5, 2,
+ 3, 3, 3, 3, 5, 4, 6, 8, 10, 12,
+ 2, 2, 2, 2, 1, 1, 4, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 5, 5, 3, 3, 3, 5, 7, 11, 15, 2,
+ 3, 5, 9, 3, 7, 9, 4, 6, 8, 10,
+ 12, 2, 3, 1, 1, 4, 1, 3, 3, 5,
+ 5
+};
+
+static const short ffdefact[] = { 1,
+ 0, 0, 65, 30, 31, 114, 17, 0, 0, 0,
+ 0, 32, 66, 115, 18, 34, 35, 117, 0, 0,
+ 0, 0, 0, 0, 3, 0, 2, 0, 0, 0,
+ 0, 0, 0, 8, 50, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 100, 0, 0, 0, 0, 0,
+ 11, 9, 0, 42, 0, 43, 0, 112, 28, 61,
+ 62, 63, 64, 0, 0, 0, 0, 0, 16, 0,
+ 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 4, 0, 0, 0,
+ 0, 0, 0, 0, 5, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 7, 0, 0, 0, 0,
+ 0, 0, 0, 6, 0, 54, 0, 51, 53, 0,
+ 52, 0, 93, 94, 95, 0, 101, 0, 104, 0,
+ 0, 0, 0, 44, 113, 29, 118, 14, 10, 12,
+ 13, 0, 79, 80, 78, 74, 75, 77, 76, 37,
+ 38, 36, 39, 45, 40, 41, 0, 0, 0, 0,
+ 88, 87, 89, 90, 46, 0, 0, 0, 68, 69,
+ 72, 70, 71, 73, 22, 21, 20, 0, 81, 82,
+ 83, 85, 86, 84, 119, 0, 0, 0, 0, 0,
+ 0, 33, 67, 116, 19, 0, 0, 56, 0, 0,
+ 0, 0, 107, 28, 0, 0, 23, 55, 96, 121,
+ 0, 0, 102, 0, 91, 0, 47, 49, 48, 92,
+ 120, 0, 0, 0, 0, 0, 0, 57, 0, 108,
+ 0, 24, 0, 97, 0, 0, 105, 0, 0, 0,
+ 0, 0, 0, 0, 58, 0, 109, 0, 25, 0,
+ 103, 106, 0, 0, 0, 0, 0, 59, 0, 110,
+ 0, 26, 0, 98, 0, 0, 0, 0, 60, 111,
+ 27, 0, 0, 99, 0, 0
+};
+
+static const short ffdefgoto[] = { 1,
+ 27, 28, 29, 57, 55, 42, 53
+};
+
+static const short ffpact[] = {-32768,
+ 290, -46,-32768,-32768,-32768,-32768,-32768, 339, 389, -2,
+ 10, 5, 6, 21, 23,-32768,-32768,-32768, 389, 389,
+ 389, 389, 389, 389,-32768, 389,-32768, 40, 42, 1024,
+ 165, 1299, 1319,-32768,-32768, 415, -13, 283, 131, 443,
+ 160, 1345, 385, -18,-32768, -17, 389, 389, 389, 389,
+ 1251, 1297, 1392, 20, 1297, 20, 1251, 22, 45, 20,
+ 22, 20, 22, 582, 209, 332, 1268, 389,-32768, 389,
+-32768, 389, 389, 389, 389, 389, 389, 389, 389, 389,
+ 389, 389, 389, 389, 389, 389,-32768, 389, 389, 389,
+ 389, 389, 389, 389,-32768, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 389,-32768, 389, 389, 389, 389,
+ 389, 389, 389,-32768, 389,-32768, 389,-32768,-32768, 389,
+-32768, 389,-32768,-32768,-32768, 389,-32768, 389,-32768, 1127,
+ 1147, 1167, 1187,-32768,-32768,-32768,-32768, 1251, 1297, 1251,
+ 1297, 1209, 1362, 1362, 1362, 1375, 1375, 1375, 1375, 82,
+ 82, 82, -36, 22, -36, -36, 664, 1231, 1282, 249,
+ 14, 62, -16, -16, -36, 688, 2, 2, -8, -8,
+ -8, -8, -8, -8, 16, 45, 45, 712, 100, 100,
+ 52, 52, 52, 52,-32768, 609, 226, 1284, 1047, 471,
+ 1067,-32768,-32768,-32768,-32768, 389, 389,-32768, 389, 389,
+ 389, 389,-32768, 45, 18, 389,-32768,-32768,-32768,-32768,
+ 389, 88,-32768, 389, 1328, 736, 1328, 1297, 1328, 1297,
+ 1392, 760, 784, 499, 78, 527, 389,-32768, 389,-32768,
+ 389,-32768, 389,-32768, 92, 94,-32768, 808, 832, 856,
+ 1087, 49, 50, 389,-32768, 389,-32768, 389,-32768, 389,
+-32768,-32768, 880, 904, 928, 555, 389,-32768, 389,-32768,
+ 389,-32768, 389,-32768, 952, 976, 1000, 1107,-32768,-32768,
+-32768, 389, 636,-32768, 103,-32768
+};
+
+static const short ffpgoto[] = {-32768,
+-32768,-32768,-32768, -1, 87, 121, 28
+};
+
+
+#define FFLAST 1426
+
+
+static const short fftable[] = { 30,
+ 126, 128, 34, 44, 85, 117, 36, 40, 7, 86,
+ 88, 89, 90, 91, 92, 46, 15, 51, 54, 56,
+ 93, 60, 62, 93, 64, 102, 47, 48, 33, 94,
+ 103, 104, 94, 127, 129, 39, 43, 105, 118, 90,
+ 91, 92, 49, 167, 50, 130, 131, 132, 133, 45,
+ 93, 102, 168, 67, 103, 104, 103, 104, 68, 94,
+ 70, 105, 69, 105, 71, 86, 138, 94, 140, 136,
+ 142, 143, 144, 145, 146, 147, 148, 149, 150, 151,
+ 152, 153, 155, 156, 157, 113, 158, 31, 91, 92,
+ 105, 165, 166, 225, 37, 41, 235, 242, 93, 243,
+ 251, 252, 276, 178, 0, 52, 0, 94, 58, 61,
+ 63, 0, 65, 186, 0, 160, 0, 0, 83, 84,
+ 189, 32, 85, 0, 190, 0, 191, 86, 38, 109,
+ 110, 111, 112, 113, 179, 180, 181, 182, 183, 184,
+ 185, 0, 59, 0, 0, 0, 66, 188, 0, 120,
+ 0, 0, 0, 0, 139, 0, 141, 107, 108, 0,
+ 109, 110, 111, 112, 113, 0, 0, 0, 0, 154,
+ 0, 0, 0, 0, 159, 161, 162, 163, 164, 0,
+ 0, 0, 121, 88, 89, 90, 91, 92, 88, 89,
+ 90, 91, 92, 0, 215, 216, 93, 217, 219, 0,
+ 222, 93, 0, 187, 223, 94, 0, 0, 0, 224,
+ 94, 124, 226, 95, 0, 0, 169, 170, 171, 172,
+ 173, 174, 175, 176, 177, 238, 0, 239, 221, 240,
+ 0, 241, 88, 89, 90, 91, 92, 0, 0, 0,
+ 0, 0, 253, 0, 254, 93, 255, 0, 256, 88,
+ 89, 90, 91, 92, 94, 265, 0, 266, 0, 267,
+ 135, 268, 93, 0, 0, 0, 0, 0, 0, 201,
+ 273, 94, 0, 0, 0, 107, 108, 209, 109, 110,
+ 111, 112, 113, 0, 0, 218, 220, 204, 205, 275,
+ 2, 0, 3, 4, 5, 6, 7, 8, 9, 10,
+ 11, 12, 13, 14, 15, 16, 17, 18, 0, 96,
+ 97, 19, 98, 99, 100, 101, 102, 0, 0, 0,
+ 0, 103, 104, 20, 21, 0, 0, 0, 105, 0,
+ 0, 22, 23, 24, 119, 0, 0, 0, 25, 0,
+ 26, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+ 12, 13, 14, 15, 16, 17, 18, 0, 96, 97,
+ 19, 98, 99, 100, 101, 102, 0, 0, 0, 0,
+ 103, 104, 20, 21, 0, 0, 0, 105, 0, 0,
+ 22, 23, 24, 136, 0, 0, 0, 0, 0, 26,
+ 35, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+ 12, 13, 14, 15, 16, 17, 18, 0, 0, 0,
+ 19, 107, 108, 0, 109, 110, 111, 112, 113, 0,
+ 0, 0, 20, 21, 0, 0, 0, 0, 0, 0,
+ 22, 23, 24, 115, 72, 0, 125, 0, 0, 26,
+ 0, 73, 74, 75, 76, 77, 78, 79, 80, 81,
+ 82, 83, 84, 0, 0, 85, 0, 0, 0, 0,
+ 86, 122, 72, 0, 0, 0, 116, 0, 0, 73,
+ 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,
+ 84, 0, 0, 85, 0, 0, 0, 0, 86, 212,
+ 72, 0, 0, 0, 123, 0, 0, 73, 74, 75,
+ 76, 77, 78, 79, 80, 81, 82, 83, 84, 0,
+ 0, 85, 0, 0, 0, 0, 86, 233, 72, 0,
+ 0, 0, 213, 0, 0, 73, 74, 75, 76, 77,
+ 78, 79, 80, 81, 82, 83, 84, 0, 0, 85,
+ 0, 0, 0, 0, 86, 236, 72, 0, 0, 0,
+ 234, 0, 0, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 0, 0, 85, 0, 0,
+ 0, 0, 86, 263, 72, 0, 0, 0, 237, 0,
+ 0, 73, 74, 75, 76, 77, 78, 79, 80, 81,
+ 82, 83, 84, 0, 0, 85, 0, 0, 0, 0,
+ 86, 72, 0, 0, 0, 0, 264, 0, 73, 74,
+ 75, 76, 77, 78, 79, 80, 81, 82, 83, 84,
+ 0, 0, 85, 0, 0, 0, 0, 86, 72, 0,
+ 0, 0, 0, 134, 0, 73, 74, 75, 76, 77,
+ 78, 79, 80, 81, 82, 83, 84, 0, 0, 85,
+ 0, 0, 0, 0, 86, 72, 0, 0, 0, 0,
+ 208, 0, 73, 74, 75, 76, 77, 78, 79, 80,
+ 81, 82, 83, 84, 0, 0, 85, 0, 0, 0,
+ 0, 86, 197, 72, 0, 0, 0, 274, 0, 0,
+ 73, 74, 75, 76, 77, 78, 79, 80, 81, 82,
+ 83, 84, 0, 0, 85, 0, 202, 72, 0, 86,
+ 0, 0, 0, 198, 73, 74, 75, 76, 77, 78,
+ 79, 80, 81, 82, 83, 84, 0, 0, 85, 0,
+ 206, 72, 0, 86, 0, 0, 0, 203, 73, 74,
+ 75, 76, 77, 78, 79, 80, 81, 82, 83, 84,
+ 0, 0, 85, 0, 227, 72, 0, 86, 0, 0,
+ 0, 207, 73, 74, 75, 76, 77, 78, 79, 80,
+ 81, 82, 83, 84, 0, 0, 85, 0, 229, 72,
+ 0, 86, 0, 0, 0, 228, 73, 74, 75, 76,
+ 77, 78, 79, 80, 81, 82, 83, 84, 0, 0,
+ 85, 0, 231, 72, 0, 86, 0, 0, 0, 230,
+ 73, 74, 75, 76, 77, 78, 79, 80, 81, 82,
+ 83, 84, 0, 0, 85, 0, 244, 72, 0, 86,
+ 0, 0, 0, 232, 73, 74, 75, 76, 77, 78,
+ 79, 80, 81, 82, 83, 84, 0, 0, 85, 0,
+ 246, 72, 0, 86, 0, 0, 0, 245, 73, 74,
+ 75, 76, 77, 78, 79, 80, 81, 82, 83, 84,
+ 0, 0, 85, 0, 248, 72, 0, 86, 0, 0,
+ 0, 247, 73, 74, 75, 76, 77, 78, 79, 80,
+ 81, 82, 83, 84, 0, 0, 85, 0, 257, 72,
+ 0, 86, 0, 0, 0, 249, 73, 74, 75, 76,
+ 77, 78, 79, 80, 81, 82, 83, 84, 0, 0,
+ 85, 0, 259, 72, 0, 86, 0, 0, 0, 258,
+ 73, 74, 75, 76, 77, 78, 79, 80, 81, 82,
+ 83, 84, 0, 0, 85, 0, 261, 72, 0, 86,
+ 0, 0, 0, 260, 73, 74, 75, 76, 77, 78,
+ 79, 80, 81, 82, 83, 84, 0, 0, 85, 0,
+ 0, 72, 0, 86, 0, 0, 0, 262, 73, 74,
+ 75, 76, 77, 78, 79, 80, 81, 82, 83, 84,
+ 0, 0, 85, 0, 0, 72, 0, 86, 0, 0,
+ 0, 269, 73, 74, 75, 76, 77, 78, 79, 80,
+ 81, 82, 83, 84, 0, 0, 85, 0, 0, 72,
+ 0, 86, 0, 0, 0, 270, 73, 74, 75, 76,
+ 77, 78, 79, 80, 81, 82, 83, 84, 0, 0,
+ 85, 0, 0, 72, 0, 86, 0, 0, 0, 271,
+ 73, 74, 75, 76, 77, 78, 79, 80, 81, 82,
+ 83, 84, 0, 0, 85, 211, 72, 0, 0, 86,
+ 0, 0, 87, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 214, 72, 85, 0, 0,
+ 0, 0, 86, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 250, 72, 85, 0, 0,
+ 0, 0, 86, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 272, 72, 85, 0, 0,
+ 0, 0, 86, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 0, 72, 85, 0, 192,
+ 0, 0, 86, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 0, 72, 85, 0, 193,
+ 0, 0, 86, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 0, 72, 85, 0, 194,
+ 0, 0, 86, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 0, 72, 85, 0, 195,
+ 0, 0, 86, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 0, 0, 85, 72, 196,
+ 0, 0, 86, 0, 0, 73, 74, 75, 76, 77,
+ 78, 79, 80, 81, 82, 83, 84, 0, 0, 85,
+ 72, 199, 0, 0, 86, 0, 0, 73, 74, 75,
+ 76, 77, 78, 79, 80, 81, 82, 83, 84, 0,
+ 72, 85, 0, 0, 0, 0, 86, 73, 74, 75,
+ 76, 77, 78, 79, 80, 81, 82, 83, 84, 0,
+ 0, 85, 0, 0, 107, 108, 86, 109, 110, 111,
+ 112, 113, 200, 0, 0, 88, 89, 90, 91, 92,
+ 107, 108, 0, 109, 110, 111, 112, 113, 93, 137,
+ 88, 89, 90, 91, 92, 96, 97, 94, 98, 99,
+ 100, 101, 102, 93, 0, 210, 0, 103, 104, 0,
+ 0, 0, 94, 0, 105, 107, 108, 106, 109, 110,
+ 111, 112, 113, 0, 73, 74, 75, 76, 77, 78,
+ 79, 80, 81, 82, 83, 84, 0, 114, 85, 0,
+ 0, 96, 97, 86, 98, 99, 100, 101, 102, 0,
+ 0, 0, 0, 103, 104, 0, 0, 0, 0, 0,
+ 105, 76, 77, 78, 79, 80, 81, 82, 83, 84,
+ 0, 0, 85, 0, 0, 0, 0, 86, 80, 81,
+ 82, 83, 84, 0, 0, 85, 0, 0, 107, 108,
+ 86, 109, 110, 111, 112, 113
+};
+
+static const short ffcheck[] = { 1,
+ 19, 19, 49, 6, 41, 19, 8, 9, 7, 46,
+ 24, 25, 26, 27, 28, 6, 15, 19, 20, 21,
+ 37, 23, 24, 37, 26, 34, 22, 22, 1, 46,
+ 39, 40, 46, 52, 52, 8, 9, 46, 52, 26,
+ 27, 28, 22, 42, 22, 47, 48, 49, 50, 52,
+ 37, 34, 51, 26, 39, 40, 39, 40, 19, 46,
+ 19, 46, 23, 46, 23, 46, 68, 46, 70, 52,
+ 72, 73, 74, 75, 76, 77, 78, 79, 80, 81,
+ 82, 83, 84, 85, 86, 34, 88, 1, 27, 28,
+ 46, 93, 94, 6, 8, 9, 19, 6, 37, 6,
+ 52, 52, 0, 105, -1, 19, -1, 46, 22, 23,
+ 24, -1, 26, 115, -1, 88, -1, -1, 37, 38,
+ 122, 1, 41, -1, 126, -1, 128, 46, 8, 30,
+ 31, 32, 33, 34, 107, 108, 109, 110, 111, 112,
+ 113, -1, 22, -1, -1, -1, 26, 120, -1, 19,
+ -1, -1, -1, -1, 68, -1, 70, 27, 28, -1,
+ 30, 31, 32, 33, 34, -1, -1, -1, -1, 83,
+ -1, -1, -1, -1, 88, 89, 90, 91, 92, -1,
+ -1, -1, 52, 24, 25, 26, 27, 28, 24, 25,
+ 26, 27, 28, -1, 196, 197, 37, 199, 200, -1,
+ 202, 37, -1, 117, 206, 46, -1, -1, -1, 211,
+ 46, 52, 214, 49, -1, -1, 96, 97, 98, 99,
+ 100, 101, 102, 103, 104, 227, -1, 229, 201, 231,
+ -1, 233, 24, 25, 26, 27, 28, -1, -1, -1,
+ -1, -1, 244, -1, 246, 37, 248, -1, 250, 24,
+ 25, 26, 27, 28, 46, 257, -1, 259, -1, 261,
+ 52, 263, 37, -1, -1, -1, -1, -1, -1, 21,
+ 272, 46, -1, -1, -1, 27, 28, 52, 30, 31,
+ 32, 33, 34, -1, -1, 199, 200, 167, 168, 0,
+ 1, -1, 3, 4, 5, 6, 7, 8, 9, 10,
+ 11, 12, 13, 14, 15, 16, 17, 18, -1, 27,
+ 28, 22, 30, 31, 32, 33, 34, -1, -1, -1,
+ -1, 39, 40, 34, 35, -1, -1, -1, 46, -1,
+ -1, 42, 43, 44, 52, -1, -1, -1, 49, -1,
+ 51, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+ 12, 13, 14, 15, 16, 17, 18, -1, 27, 28,
+ 22, 30, 31, 32, 33, 34, -1, -1, -1, -1,
+ 39, 40, 34, 35, -1, -1, -1, 46, -1, -1,
+ 42, 43, 44, 52, -1, -1, -1, -1, -1, 51,
+ 52, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+ 12, 13, 14, 15, 16, 17, 18, -1, -1, -1,
+ 22, 27, 28, -1, 30, 31, 32, 33, 34, -1,
+ -1, -1, 34, 35, -1, -1, -1, -1, -1, -1,
+ 42, 43, 44, 19, 20, -1, 52, -1, -1, 51,
+ -1, 27, 28, 29, 30, 31, 32, 33, 34, 35,
+ 36, 37, 38, -1, -1, 41, -1, -1, -1, -1,
+ 46, 19, 20, -1, -1, -1, 52, -1, -1, 27,
+ 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
+ 38, -1, -1, 41, -1, -1, -1, -1, 46, 19,
+ 20, -1, -1, -1, 52, -1, -1, 27, 28, 29,
+ 30, 31, 32, 33, 34, 35, 36, 37, 38, -1,
+ -1, 41, -1, -1, -1, -1, 46, 19, 20, -1,
+ -1, -1, 52, -1, -1, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, -1, -1, 41,
+ -1, -1, -1, -1, 46, 19, 20, -1, -1, -1,
+ 52, -1, -1, 27, 28, 29, 30, 31, 32, 33,
+ 34, 35, 36, 37, 38, -1, -1, 41, -1, -1,
+ -1, -1, 46, 19, 20, -1, -1, -1, 52, -1,
+ -1, 27, 28, 29, 30, 31, 32, 33, 34, 35,
+ 36, 37, 38, -1, -1, 41, -1, -1, -1, -1,
+ 46, 20, -1, -1, -1, -1, 52, -1, 27, 28,
+ 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
+ -1, -1, 41, -1, -1, -1, -1, 46, 20, -1,
+ -1, -1, -1, 52, -1, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, -1, -1, 41,
+ -1, -1, -1, -1, 46, 20, -1, -1, -1, -1,
+ 52, -1, 27, 28, 29, 30, 31, 32, 33, 34,
+ 35, 36, 37, 38, -1, -1, 41, -1, -1, -1,
+ -1, 46, 19, 20, -1, -1, -1, 52, -1, -1,
+ 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
+ 37, 38, -1, -1, 41, -1, 19, 20, -1, 46,
+ -1, -1, -1, 50, 27, 28, 29, 30, 31, 32,
+ 33, 34, 35, 36, 37, 38, -1, -1, 41, -1,
+ 19, 20, -1, 46, -1, -1, -1, 50, 27, 28,
+ 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
+ -1, -1, 41, -1, 19, 20, -1, 46, -1, -1,
+ -1, 50, 27, 28, 29, 30, 31, 32, 33, 34,
+ 35, 36, 37, 38, -1, -1, 41, -1, 19, 20,
+ -1, 46, -1, -1, -1, 50, 27, 28, 29, 30,
+ 31, 32, 33, 34, 35, 36, 37, 38, -1, -1,
+ 41, -1, 19, 20, -1, 46, -1, -1, -1, 50,
+ 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
+ 37, 38, -1, -1, 41, -1, 19, 20, -1, 46,
+ -1, -1, -1, 50, 27, 28, 29, 30, 31, 32,
+ 33, 34, 35, 36, 37, 38, -1, -1, 41, -1,
+ 19, 20, -1, 46, -1, -1, -1, 50, 27, 28,
+ 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
+ -1, -1, 41, -1, 19, 20, -1, 46, -1, -1,
+ -1, 50, 27, 28, 29, 30, 31, 32, 33, 34,
+ 35, 36, 37, 38, -1, -1, 41, -1, 19, 20,
+ -1, 46, -1, -1, -1, 50, 27, 28, 29, 30,
+ 31, 32, 33, 34, 35, 36, 37, 38, -1, -1,
+ 41, -1, 19, 20, -1, 46, -1, -1, -1, 50,
+ 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
+ 37, 38, -1, -1, 41, -1, 19, 20, -1, 46,
+ -1, -1, -1, 50, 27, 28, 29, 30, 31, 32,
+ 33, 34, 35, 36, 37, 38, -1, -1, 41, -1,
+ -1, 20, -1, 46, -1, -1, -1, 50, 27, 28,
+ 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
+ -1, -1, 41, -1, -1, 20, -1, 46, -1, -1,
+ -1, 50, 27, 28, 29, 30, 31, 32, 33, 34,
+ 35, 36, 37, 38, -1, -1, 41, -1, -1, 20,
+ -1, 46, -1, -1, -1, 50, 27, 28, 29, 30,
+ 31, 32, 33, 34, 35, 36, 37, 38, -1, -1,
+ 41, -1, -1, 20, -1, 46, -1, -1, -1, 50,
+ 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
+ 37, 38, -1, -1, 41, 19, 20, -1, -1, 46,
+ -1, -1, 49, 27, 28, 29, 30, 31, 32, 33,
+ 34, 35, 36, 37, 38, 19, 20, 41, -1, -1,
+ -1, -1, 46, 27, 28, 29, 30, 31, 32, 33,
+ 34, 35, 36, 37, 38, 19, 20, 41, -1, -1,
+ -1, -1, 46, 27, 28, 29, 30, 31, 32, 33,
+ 34, 35, 36, 37, 38, 19, 20, 41, -1, -1,
+ -1, -1, 46, 27, 28, 29, 30, 31, 32, 33,
+ 34, 35, 36, 37, 38, -1, 20, 41, -1, 23,
+ -1, -1, 46, 27, 28, 29, 30, 31, 32, 33,
+ 34, 35, 36, 37, 38, -1, 20, 41, -1, 23,
+ -1, -1, 46, 27, 28, 29, 30, 31, 32, 33,
+ 34, 35, 36, 37, 38, -1, 20, 41, -1, 23,
+ -1, -1, 46, 27, 28, 29, 30, 31, 32, 33,
+ 34, 35, 36, 37, 38, -1, 20, 41, -1, 23,
+ -1, -1, 46, 27, 28, 29, 30, 31, 32, 33,
+ 34, 35, 36, 37, 38, -1, -1, 41, 20, 21,
+ -1, -1, 46, -1, -1, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, -1, -1, 41,
+ 20, 21, -1, -1, 46, -1, -1, 27, 28, 29,
+ 30, 31, 32, 33, 34, 35, 36, 37, 38, -1,
+ 20, 41, -1, -1, -1, -1, 46, 27, 28, 29,
+ 30, 31, 32, 33, 34, 35, 36, 37, 38, -1,
+ -1, 41, -1, -1, 27, 28, 46, 30, 31, 32,
+ 33, 34, 21, -1, -1, 24, 25, 26, 27, 28,
+ 27, 28, -1, 30, 31, 32, 33, 34, 37, 52,
+ 24, 25, 26, 27, 28, 27, 28, 46, 30, 31,
+ 32, 33, 34, 37, -1, 52, -1, 39, 40, -1,
+ -1, -1, 46, -1, 46, 27, 28, 49, 30, 31,
+ 32, 33, 34, -1, 27, 28, 29, 30, 31, 32,
+ 33, 34, 35, 36, 37, 38, -1, 49, 41, -1,
+ -1, 27, 28, 46, 30, 31, 32, 33, 34, -1,
+ -1, -1, -1, 39, 40, -1, -1, -1, -1, -1,
+ 46, 30, 31, 32, 33, 34, 35, 36, 37, 38,
+ -1, -1, 41, -1, -1, -1, -1, 46, 34, 35,
+ 36, 37, 38, -1, -1, 41, -1, -1, 27, 28,
+ 46, 30, 31, 32, 33, 34
+};
+/* -*-C-*- Note some compilers choke on comments on `#line' lines. */
+#line 3 "/usr1/local/share/bison.simple"
+
+/* Skeleton output parser for bison,
+ Copyright (C) 1984, 1989, 1990 Free Software Foundation, Inc.
+
+ This program 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 2, 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* As a special exception, when this file is copied by Bison into a
+ Bison output file, you may use that output file without restriction.
+ This special exception was added by the Free Software Foundation
+ in version 1.24 of Bison. */
+
+#ifndef alloca
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#else /* not GNU C. */
+#if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) || defined (__sparc) || defined (__sgi)
+#include <alloca.h>
+#else /* not sparc */
+#if defined (MSDOS) && !defined (__TURBOC__)
+#include <malloc.h>
+#else /* not MSDOS, or __TURBOC__ */
+#if defined(_AIX)
+#include <malloc.h>
+ #pragma alloca
+#else /* not MSDOS, __TURBOC__, or _AIX */
+#ifdef __hpux
+#ifdef __cplusplus
+extern "C" {
+void *alloca (unsigned int);
+};
+#else /* not __cplusplus */
+void *alloca ();
+#endif /* not __cplusplus */
+#endif /* __hpux */
+#endif /* not _AIX */
+#endif /* not MSDOS, or __TURBOC__ */
+#endif /* not sparc. */
+#endif /* not GNU C. */
+#endif /* alloca not defined. */
+
+/* This is the parser code that is written into each bison parser
+ when the %semantic_parser declaration is not specified in the grammar.
+ It was written by Richard Stallman by simplifying the hairy parser
+ used when %semantic_parser is specified. */
+
+/* Note: there must be only one dollar sign in this file.
+ It is replaced by the list of actions, each action
+ as one case of the switch. */
+
+#define fferrok (fferrstatus = 0)
+#define ffclearin (ffchar = FFEMPTY)
+#define FFEMPTY -2
+#define FFEOF 0
+#define FFACCEPT return(0)
+#define FFABORT return(1)
+#define FFERROR goto fferrlab1
+/* Like FFERROR except do call fferror.
+ This remains here temporarily to ease the
+ transition to the new meaning of FFERROR, for GCC.
+ Once GCC version 2 has supplanted version 1, this can go. */
+#define FFFAIL goto fferrlab
+#define FFRECOVERING() (!!fferrstatus)
+#define FFBACKUP(token, value) \
+do \
+ if (ffchar == FFEMPTY && fflen == 1) \
+ { ffchar = (token), fflval = (value); \
+ ffchar1 = FFTRANSLATE (ffchar); \
+ FFPOPSTACK; \
+ goto ffbackup; \
+ } \
+ else \
+ { fferror ("syntax error: cannot back up"); FFERROR; } \
+while (0)
+
+#define FFTERROR 1
+#define FFERRCODE 256
+
+#ifndef FFPURE
+#define FFLEX fflex()
+#endif
+
+#ifdef FFPURE
+#ifdef FFLSP_NEEDED
+#ifdef FFLEX_PARAM
+#define FFLEX fflex(&fflval, &fflloc, FFLEX_PARAM)
+#else
+#define FFLEX fflex(&fflval, &fflloc)
+#endif
+#else /* not FFLSP_NEEDED */
+#ifdef FFLEX_PARAM
+#define FFLEX fflex(&fflval, FFLEX_PARAM)
+#else
+#define FFLEX fflex(&fflval)
+#endif
+#endif /* not FFLSP_NEEDED */
+#endif
+
+/* If nonreentrant, generate the variables here */
+
+#ifndef FFPURE
+
+int ffchar; /* the lookahead symbol */
+FFSTYPE fflval; /* the semantic value of the */
+ /* lookahead symbol */
+
+#ifdef FFLSP_NEEDED
+FFLTYPE fflloc; /* location data for the lookahead */
+ /* symbol */
+#endif
+
+int ffnerrs; /* number of parse errors so far */
+#endif /* not FFPURE */
+
+#if FFDEBUG != 0
+int ffdebug; /* nonzero means print parse trace */
+/* Since this is uninitialized, it does not stop multiple parsers
+ from coexisting. */
+#endif
+
+/* FFINITDEPTH indicates the initial size of the parser's stacks */
+
+#ifndef FFINITDEPTH
+#define FFINITDEPTH 200
+#endif
+
+/* FFMAXDEPTH is the maximum size the stacks can grow to
+ (effective only if the built-in stack extension method is used). */
+
+#if FFMAXDEPTH == 0
+#undef FFMAXDEPTH
+#endif
+
+#ifndef FFMAXDEPTH
+#define FFMAXDEPTH 10000
+#endif
+
+/* Prevent warning if -Wstrict-prototypes. */
+#ifdef __GNUC__
+int ffparse (void);
+#endif
+
+#if __GNUC__ > 1 /* GNU C and GNU C++ define this. */
+#define __ff_memcpy(TO,FROM,COUNT) __builtin_memcpy(TO,FROM,COUNT)
+#else /* not GNU C or C++ */
+#ifndef __cplusplus
+
+/* This is the most reliable way to avoid incompatibilities
+ in available built-in functions on various systems. */
+static void
+__ff_memcpy (to, from, count)
+ char *to;
+ char *from;
+ int count;
+{
+ register char *f = from;
+ register char *t = to;
+ register int i = count;
+
+ while (i-- > 0)
+ *t++ = *f++;
+}
+
+#else /* __cplusplus */
+
+/* This is the most reliable way to avoid incompatibilities
+ in available built-in functions on various systems. */
+static void
+__ff_memcpy (char *to, char *from, int count)
+{
+ register char *f = from;
+ register char *t = to;
+ register int i = count;
+
+ while (i-- > 0)
+ *t++ = *f++;
+}
+
+#endif
+#endif
+
+#line 196 "/usr1/local/share/bison.simple"
+
+/* The user can define FFPARSE_PARAM as the name of an argument to be passed
+ into ffparse. The argument should have type void *.
+ It should actually point to an object.
+ Grammar actions can access the variable by casting it
+ to the proper pointer type. */
+
+#ifdef FFPARSE_PARAM
+#ifdef __cplusplus
+#define FFPARSE_PARAM_ARG void *FFPARSE_PARAM
+#define FFPARSE_PARAM_DECL
+#else /* not __cplusplus */
+#define FFPARSE_PARAM_ARG FFPARSE_PARAM
+#define FFPARSE_PARAM_DECL void *FFPARSE_PARAM;
+#endif /* not __cplusplus */
+#else /* not FFPARSE_PARAM */
+#define FFPARSE_PARAM_ARG
+#define FFPARSE_PARAM_DECL
+#endif /* not FFPARSE_PARAM */
+
+int
+ffparse(FFPARSE_PARAM_ARG)
+ FFPARSE_PARAM_DECL
+{
+ register int ffstate;
+ register int ffn;
+ register short *ffssp;
+ register FFSTYPE *ffvsp;
+ int fferrstatus; /* number of tokens to shift before error messages enabled */
+ int ffchar1 = 0; /* lookahead token as an internal (translated) token number */
+
+ short ffssa[FFINITDEPTH]; /* the state stack */
+ FFSTYPE ffvsa[FFINITDEPTH]; /* the semantic value stack */
+
+ short *ffss = ffssa; /* refer to the stacks thru separate pointers */
+ FFSTYPE *ffvs = ffvsa; /* to allow ffoverflow to reallocate them elsewhere */
+
+#ifdef FFLSP_NEEDED
+ FFLTYPE fflsa[FFINITDEPTH]; /* the location stack */
+ FFLTYPE *ffls = fflsa;
+ FFLTYPE *fflsp;
+
+#define FFPOPSTACK (ffvsp--, ffssp--, fflsp--)
+#else
+#define FFPOPSTACK (ffvsp--, ffssp--)
+#endif
+
+ int ffstacksize = FFINITDEPTH;
+
+#ifdef FFPURE
+ int ffchar;
+ FFSTYPE fflval;
+ int ffnerrs;
+#ifdef FFLSP_NEEDED
+ FFLTYPE fflloc;
+#endif
+#endif
+
+ FFSTYPE ffval; /* the variable used to return */
+ /* semantic values from the action */
+ /* routines */
+
+ int fflen;
+
+#if FFDEBUG != 0
+ if (ffdebug)
+ fprintf(stderr, "Starting parse\n");
+#endif
+
+ ffstate = 0;
+ fferrstatus = 0;
+ ffnerrs = 0;
+ ffchar = FFEMPTY; /* Cause a token to be read. */
+
+ /* Initialize stack pointers.
+ Waste one element of value and location stack
+ so that they stay on the same level as the state stack.
+ The wasted elements are never initialized. */
+
+ ffssp = ffss - 1;
+ ffvsp = ffvs;
+#ifdef FFLSP_NEEDED
+ fflsp = ffls;
+#endif
+
+/* Push a new state, which is found in ffstate . */
+/* In all cases, when you get here, the value and location stacks
+ have just been pushed. so pushing a state here evens the stacks. */
+ffnewstate:
+
+ *++ffssp = ffstate;
+
+ if (ffssp >= ffss + ffstacksize - 1)
+ {
+ /* Give user a chance to reallocate the stack */
+ /* Use copies of these so that the &'s don't force the real ones into memory. */
+ FFSTYPE *ffvs1 = ffvs;
+ short *ffss1 = ffss;
+#ifdef FFLSP_NEEDED
+ FFLTYPE *ffls1 = ffls;
+#endif
+
+ /* Get the current used size of the three stacks, in elements. */
+ int size = ffssp - ffss + 1;
+
+#ifdef ffoverflow
+ /* Each stack pointer address is followed by the size of
+ the data in use in that stack, in bytes. */
+#ifdef FFLSP_NEEDED
+ /* This used to be a conditional around just the two extra args,
+ but that might be undefined if ffoverflow is a macro. */
+ ffoverflow("parser stack overflow",
+ &ffss1, size * sizeof (*ffssp),
+ &ffvs1, size * sizeof (*ffvsp),
+ &ffls1, size * sizeof (*fflsp),
+ &ffstacksize);
+#else
+ ffoverflow("parser stack overflow",
+ &ffss1, size * sizeof (*ffssp),
+ &ffvs1, size * sizeof (*ffvsp),
+ &ffstacksize);
+#endif
+
+ ffss = ffss1; ffvs = ffvs1;
+#ifdef FFLSP_NEEDED
+ ffls = ffls1;
+#endif
+#else /* no ffoverflow */
+ /* Extend the stack our own way. */
+ if (ffstacksize >= FFMAXDEPTH)
+ {
+ fferror("parser stack overflow");
+ return 2;
+ }
+ ffstacksize *= 2;
+ if (ffstacksize > FFMAXDEPTH)
+ ffstacksize = FFMAXDEPTH;
+ ffss = (short *) alloca (ffstacksize * sizeof (*ffssp));
+ __ff_memcpy ((char *)ffss, (char *)ffss1, size * sizeof (*ffssp));
+ ffvs = (FFSTYPE *) alloca (ffstacksize * sizeof (*ffvsp));
+ __ff_memcpy ((char *)ffvs, (char *)ffvs1, size * sizeof (*ffvsp));
+#ifdef FFLSP_NEEDED
+ ffls = (FFLTYPE *) alloca (ffstacksize * sizeof (*fflsp));
+ __ff_memcpy ((char *)ffls, (char *)ffls1, size * sizeof (*fflsp));
+#endif
+#endif /* no ffoverflow */
+
+ ffssp = ffss + size - 1;
+ ffvsp = ffvs + size - 1;
+#ifdef FFLSP_NEEDED
+ fflsp = ffls + size - 1;
+#endif
+
+#if FFDEBUG != 0
+ if (ffdebug)
+ fprintf(stderr, "Stack size increased to %d\n", ffstacksize);
+#endif
+
+ if (ffssp >= ffss + ffstacksize - 1)
+ FFABORT;
+ }
+
+#if FFDEBUG != 0
+ if (ffdebug)
+ fprintf(stderr, "Entering state %d\n", ffstate);
+#endif
+
+ goto ffbackup;
+ ffbackup:
+
+/* Do appropriate processing given the current state. */
+/* Read a lookahead token if we need one and don't already have one. */
+/* ffresume: */
+
+ /* First try to decide what to do without reference to lookahead token. */
+
+ ffn = ffpact[ffstate];
+ if (ffn == FFFLAG)
+ goto ffdefault;
+
+ /* Not known => get a lookahead token if don't already have one. */
+
+ /* ffchar is either FFEMPTY or FFEOF
+ or a valid token in external form. */
+
+ if (ffchar == FFEMPTY)
+ {
+#if FFDEBUG != 0
+ if (ffdebug)
+ fprintf(stderr, "Reading a token: ");
+#endif
+ ffchar = FFLEX;
+ }
+
+ /* Convert token to internal form (in ffchar1) for indexing tables with */
+
+ if (ffchar <= 0) /* This means end of input. */
+ {
+ ffchar1 = 0;
+ ffchar = FFEOF; /* Don't call FFLEX any more */
+
+#if FFDEBUG != 0
+ if (ffdebug)
+ fprintf(stderr, "Now at end of input.\n");
+#endif
+ }
+ else
+ {
+ ffchar1 = FFTRANSLATE(ffchar);
+
+#if FFDEBUG != 0
+ if (ffdebug)
+ {
+ fprintf (stderr, "Next token is %d (%s", ffchar, fftname[ffchar1]);
+ /* Give the individual parser a way to print the precise meaning
+ of a token, for further debugging info. */
+#ifdef FFPRINT
+ FFPRINT (stderr, ffchar, fflval);
+#endif
+ fprintf (stderr, ")\n");
+ }
+#endif
+ }
+
+ ffn += ffchar1;
+ if (ffn < 0 || ffn > FFLAST || ffcheck[ffn] != ffchar1)
+ goto ffdefault;
+
+ ffn = fftable[ffn];
+
+ /* ffn is what to do for this token type in this state.
+ Negative => reduce, -ffn is rule number.
+ Positive => shift, ffn is new state.
+ New state is final state => don't bother to shift,
+ just return success.
+ 0, or most negative number => error. */
+
+ if (ffn < 0)
+ {
+ if (ffn == FFFLAG)
+ goto fferrlab;
+ ffn = -ffn;
+ goto ffreduce;
+ }
+ else if (ffn == 0)
+ goto fferrlab;
+
+ if (ffn == FFFINAL)
+ FFACCEPT;
+
+ /* Shift the lookahead token. */
+
+#if FFDEBUG != 0
+ if (ffdebug)
+ fprintf(stderr, "Shifting token %d (%s), ", ffchar, fftname[ffchar1]);
+#endif
+
+ /* Discard the token being shifted unless it is eof. */
+ if (ffchar != FFEOF)
+ ffchar = FFEMPTY;
+
+ *++ffvsp = fflval;
+#ifdef FFLSP_NEEDED
+ *++fflsp = fflloc;
+#endif
+
+ /* count tokens shifted since error; after three, turn off error status. */
+ if (fferrstatus) fferrstatus--;
+
+ ffstate = ffn;
+ goto ffnewstate;
+
+/* Do the default action for the current state. */
+ffdefault:
+
+ ffn = ffdefact[ffstate];
+ if (ffn == 0)
+ goto fferrlab;
+
+/* Do a reduction. ffn is the number of a rule to reduce with. */
+ffreduce:
+ fflen = ffr2[ffn];
+ if (fflen > 0)
+ ffval = ffvsp[1-fflen]; /* implement default value of the action */
+
+#if FFDEBUG != 0
+ if (ffdebug)
+ {
+ int i;
+
+ fprintf (stderr, "Reducing via rule %d (line %d), ",
+ ffn, ffrline[ffn]);
+
+ /* Print the symbols being reduced, and their result. */
+ for (i = ffprhs[ffn]; ffrhs[i] > 0; i++)
+ fprintf (stderr, "%s ", fftname[ffrhs[i]]);
+ fprintf (stderr, " -> %s\n", fftname[ffr1[ffn]]);
+ }
+#endif
+
+
+ switch (ffn) {
+
+case 3:
+#line 230 "eval.y"
+{;
+ break;}
+case 4:
+#line 232 "eval.y"
+{ if( ffvsp[-1].Node<0 ) {
+ fferror("Couldn't build node structure: out of memory?");
+ FFERROR; }
+ gParse.resultNode = ffvsp[-1].Node;
+ ;
+ break;}
+case 5:
+#line 238 "eval.y"
+{ if( ffvsp[-1].Node<0 ) {
+ fferror("Couldn't build node structure: out of memory?");
+ FFERROR; }
+ gParse.resultNode = ffvsp[-1].Node;
+ ;
+ break;}
+case 6:
+#line 244 "eval.y"
+{ if( ffvsp[-1].Node<0 ) {
+ fferror("Couldn't build node structure: out of memory?");
+ FFERROR; }
+ gParse.resultNode = ffvsp[-1].Node;
+ ;
+ break;}
+case 7:
+#line 250 "eval.y"
+{ if( ffvsp[-1].Node<0 ) {
+ fferror("Couldn't build node structure: out of memory?");
+ FFERROR; }
+ gParse.resultNode = ffvsp[-1].Node;
+ ;
+ break;}
+case 8:
+#line 255 "eval.y"
+{ fferrok; ;
+ break;}
+case 9:
+#line 259 "eval.y"
+{ ffval.Node = New_Vector( ffvsp[0].Node ); TEST(ffval.Node); ;
+ break;}
+case 10:
+#line 261 "eval.y"
+{
+ if( gParse.Nodes[ffvsp[-2].Node].nSubNodes >= MAXSUBS ) {
+ ffvsp[-2].Node = Close_Vec( ffvsp[-2].Node ); TEST(ffvsp[-2].Node);
+ ffval.Node = New_Vector( ffvsp[-2].Node ); TEST(ffval.Node);
+ } else {
+ ffval.Node = ffvsp[-2].Node;
+ }
+ gParse.Nodes[ffval.Node].SubNodes[ gParse.Nodes[ffval.Node].nSubNodes++ ]
+ = ffvsp[0].Node;
+ ;
+ break;}
+case 11:
+#line 274 "eval.y"
+{ ffval.Node = New_Vector( ffvsp[0].Node ); TEST(ffval.Node); ;
+ break;}
+case 12:
+#line 276 "eval.y"
+{
+ if( TYPE(ffvsp[-2].Node) < TYPE(ffvsp[0].Node) )
+ TYPE(ffvsp[-2].Node) = TYPE(ffvsp[0].Node);
+ if( gParse.Nodes[ffvsp[-2].Node].nSubNodes >= MAXSUBS ) {
+ ffvsp[-2].Node = Close_Vec( ffvsp[-2].Node ); TEST(ffvsp[-2].Node);
+ ffval.Node = New_Vector( ffvsp[-2].Node ); TEST(ffval.Node);
+ } else {
+ ffval.Node = ffvsp[-2].Node;
+ }
+ gParse.Nodes[ffval.Node].SubNodes[ gParse.Nodes[ffval.Node].nSubNodes++ ]
+ = ffvsp[0].Node;
+ ;
+ break;}
+case 13:
+#line 289 "eval.y"
+{
+ if( gParse.Nodes[ffvsp[-2].Node].nSubNodes >= MAXSUBS ) {
+ ffvsp[-2].Node = Close_Vec( ffvsp[-2].Node ); TEST(ffvsp[-2].Node);
+ ffval.Node = New_Vector( ffvsp[-2].Node ); TEST(ffval.Node);
+ } else {
+ ffval.Node = ffvsp[-2].Node;
+ }
+ gParse.Nodes[ffval.Node].SubNodes[ gParse.Nodes[ffval.Node].nSubNodes++ ]
+ = ffvsp[0].Node;
+ ;
+ break;}
+case 14:
+#line 300 "eval.y"
+{
+ TYPE(ffvsp[-2].Node) = TYPE(ffvsp[0].Node);
+ if( gParse.Nodes[ffvsp[-2].Node].nSubNodes >= MAXSUBS ) {
+ ffvsp[-2].Node = Close_Vec( ffvsp[-2].Node ); TEST(ffvsp[-2].Node);
+ ffval.Node = New_Vector( ffvsp[-2].Node ); TEST(ffval.Node);
+ } else {
+ ffval.Node = ffvsp[-2].Node;
+ }
+ gParse.Nodes[ffval.Node].SubNodes[ gParse.Nodes[ffval.Node].nSubNodes++ ]
+ = ffvsp[0].Node;
+ ;
+ break;}
+case 15:
+#line 314 "eval.y"
+{ ffval.Node = Close_Vec( ffvsp[-1].Node ); TEST(ffval.Node); ;
+ break;}
+case 16:
+#line 318 "eval.y"
+{ ffval.Node = Close_Vec( ffvsp[-1].Node ); TEST(ffval.Node); ;
+ break;}
+case 17:
+#line 322 "eval.y"
+{
+ ffval.Node = New_Const( BITSTR, ffvsp[0].str, strlen(ffvsp[0].str)+1 ); TEST(ffval.Node);
+ SIZE(ffval.Node) = strlen(ffvsp[0].str);
+ ;
+ break;}
+case 18:
+#line 327 "eval.y"
+{ ffval.Node = New_Column( ffvsp[0].lng ); TEST(ffval.Node); ;
+ break;}
+case 19:
+#line 329 "eval.y"
+{
+ if( TYPE(ffvsp[-1].Node) != LONG
+ || gParse.Nodes[ffvsp[-1].Node].operation != CONST_OP ) {
+ fferror("Offset argument must be a constant integer");
+ FFERROR;
+ }
+ ffval.Node = New_Offset( ffvsp[-3].lng, ffvsp[-1].Node ); TEST(ffval.Node);
+ ;
+ break;}
+case 20:
+#line 338 "eval.y"
+{ ffval.Node = New_BinOp( BITSTR, ffvsp[-2].Node, '&', ffvsp[0].Node ); TEST(ffval.Node);
+ SIZE(ffval.Node) = ( SIZE(ffvsp[-2].Node)>SIZE(ffvsp[0].Node) ? SIZE(ffvsp[-2].Node) : SIZE(ffvsp[0].Node) ); ;
+ break;}
+case 21:
+#line 341 "eval.y"
+{ ffval.Node = New_BinOp( BITSTR, ffvsp[-2].Node, '|', ffvsp[0].Node ); TEST(ffval.Node);
+ SIZE(ffval.Node) = ( SIZE(ffvsp[-2].Node)>SIZE(ffvsp[0].Node) ? SIZE(ffvsp[-2].Node) : SIZE(ffvsp[0].Node) ); ;
+ break;}
+case 22:
+#line 344 "eval.y"
+{ ffval.Node = New_BinOp( BITSTR, ffvsp[-2].Node, '+', ffvsp[0].Node ); TEST(ffval.Node);
+ SIZE(ffval.Node) = SIZE(ffvsp[-2].Node) + SIZE(ffvsp[0].Node); ;
+ break;}
+case 23:
+#line 347 "eval.y"
+{ ffval.Node = New_Deref( ffvsp[-3].Node, 1, ffvsp[-1].Node, 0, 0, 0, 0 ); TEST(ffval.Node); ;
+ break;}
+case 24:
+#line 349 "eval.y"
+{ ffval.Node = New_Deref( ffvsp[-5].Node, 2, ffvsp[-3].Node, ffvsp[-1].Node, 0, 0, 0 ); TEST(ffval.Node); ;
+ break;}
+case 25:
+#line 351 "eval.y"
+{ ffval.Node = New_Deref( ffvsp[-7].Node, 3, ffvsp[-5].Node, ffvsp[-3].Node, ffvsp[-1].Node, 0, 0 ); TEST(ffval.Node); ;
+ break;}
+case 26:
+#line 353 "eval.y"
+{ ffval.Node = New_Deref( ffvsp[-9].Node, 4, ffvsp[-7].Node, ffvsp[-5].Node, ffvsp[-3].Node, ffvsp[-1].Node, 0 ); TEST(ffval.Node); ;
+ break;}
+case 27:
+#line 355 "eval.y"
+{ ffval.Node = New_Deref( ffvsp[-11].Node, 5, ffvsp[-9].Node, ffvsp[-7].Node, ffvsp[-5].Node, ffvsp[-3].Node, ffvsp[-1].Node ); TEST(ffval.Node); ;
+ break;}
+case 28:
+#line 357 "eval.y"
+{ ffval.Node = New_Unary( BITSTR, NOT, ffvsp[0].Node ); TEST(ffval.Node); ;
+ break;}
+case 29:
+#line 360 "eval.y"
+{ ffval.Node = ffvsp[-1].Node; ;
+ break;}
+case 30:
+#line 364 "eval.y"
+{ ffval.Node = New_Const( LONG, &(ffvsp[0].lng), sizeof(long) ); TEST(ffval.Node); ;
+ break;}
+case 31:
+#line 366 "eval.y"
+{ ffval.Node = New_Const( DOUBLE, &(ffvsp[0].dbl), sizeof(double) ); TEST(ffval.Node); ;
+ break;}
+case 32:
+#line 368 "eval.y"
+{ ffval.Node = New_Column( ffvsp[0].lng ); TEST(ffval.Node); ;
+ break;}
+case 33:
+#line 370 "eval.y"
+{
+ if( TYPE(ffvsp[-1].Node) != LONG
+ || gParse.Nodes[ffvsp[-1].Node].operation != CONST_OP ) {
+ fferror("Offset argument must be a constant integer");
+ FFERROR;
+ }
+ ffval.Node = New_Offset( ffvsp[-3].lng, ffvsp[-1].Node ); TEST(ffval.Node);
+ ;
+ break;}
+case 34:
+#line 379 "eval.y"
+{ ffval.Node = New_Func( LONG, row_fct, 0, 0, 0, 0, 0, 0, 0, 0 ); ;
+ break;}
+case 35:
+#line 381 "eval.y"
+{ ffval.Node = New_Func( LONG, null_fct, 0, 0, 0, 0, 0, 0, 0, 0 ); ;
+ break;}
+case 36:
+#line 383 "eval.y"
+{ PROMOTE(ffvsp[-2].Node,ffvsp[0].Node); ffval.Node = New_BinOp( TYPE(ffvsp[-2].Node), ffvsp[-2].Node, '%', ffvsp[0].Node );
+ TEST(ffval.Node); ;
+ break;}
+case 37:
+#line 386 "eval.y"
+{ PROMOTE(ffvsp[-2].Node,ffvsp[0].Node); ffval.Node = New_BinOp( TYPE(ffvsp[-2].Node), ffvsp[-2].Node, '+', ffvsp[0].Node );
+ TEST(ffval.Node); ;
+ break;}
+case 38:
+#line 389 "eval.y"
+{ PROMOTE(ffvsp[-2].Node,ffvsp[0].Node); ffval.Node = New_BinOp( TYPE(ffvsp[-2].Node), ffvsp[-2].Node, '-', ffvsp[0].Node );
+ TEST(ffval.Node); ;
+ break;}
+case 39:
+#line 392 "eval.y"
+{ PROMOTE(ffvsp[-2].Node,ffvsp[0].Node); ffval.Node = New_BinOp( TYPE(ffvsp[-2].Node), ffvsp[-2].Node, '*', ffvsp[0].Node );
+ TEST(ffval.Node); ;
+ break;}
+case 40:
+#line 395 "eval.y"
+{ PROMOTE(ffvsp[-2].Node,ffvsp[0].Node); ffval.Node = New_BinOp( TYPE(ffvsp[-2].Node), ffvsp[-2].Node, '/', ffvsp[0].Node );
+ TEST(ffval.Node); ;
+ break;}
+case 41:
+#line 398 "eval.y"
+{ PROMOTE(ffvsp[-2].Node,ffvsp[0].Node); ffval.Node = New_BinOp( TYPE(ffvsp[-2].Node), ffvsp[-2].Node, POWER, ffvsp[0].Node );
+ TEST(ffval.Node); ;
+ break;}
+case 42:
+#line 401 "eval.y"
+{ ffval.Node = ffvsp[0].Node; ;
+ break;}
+case 43:
+#line 403 "eval.y"
+{ ffval.Node = New_Unary( TYPE(ffvsp[0].Node), UMINUS, ffvsp[0].Node ); TEST(ffval.Node); ;
+ break;}
+case 44:
+#line 405 "eval.y"
+{ ffval.Node = ffvsp[-1].Node; ;
+ break;}
+case 45:
+#line 407 "eval.y"
+{ ffvsp[0].Node = New_Unary( TYPE(ffvsp[-2].Node), 0, ffvsp[0].Node );
+ ffval.Node = New_BinOp( TYPE(ffvsp[-2].Node), ffvsp[-2].Node, '*', ffvsp[0].Node );
+ TEST(ffval.Node); ;
+ break;}
+case 46:
+#line 411 "eval.y"
+{ ffvsp[-2].Node = New_Unary( TYPE(ffvsp[0].Node), 0, ffvsp[-2].Node );
+ ffval.Node = New_BinOp( TYPE(ffvsp[0].Node), ffvsp[-2].Node, '*', ffvsp[0].Node );
+ TEST(ffval.Node); ;
+ break;}
+case 47:
+#line 415 "eval.y"
+{
+ PROMOTE(ffvsp[-2].Node,ffvsp[0].Node);
+ if( ! Test_Dims(ffvsp[-2].Node,ffvsp[0].Node) ) {
+ fferror("Incompatible dimensions in '?:' arguments");
+ FFERROR;
+ }
+ ffval.Node = New_Func( 0, ifthenelse_fct, 3, ffvsp[-2].Node, ffvsp[0].Node, ffvsp[-4].Node,
+ 0, 0, 0, 0 );
+ TEST(ffval.Node);
+ if( SIZE(ffvsp[-2].Node)<SIZE(ffvsp[0].Node) ) Copy_Dims(ffval.Node, ffvsp[0].Node);
+ TYPE(ffvsp[-4].Node) = TYPE(ffvsp[-2].Node);
+ if( ! Test_Dims(ffvsp[-4].Node,ffval.Node) ) {
+ fferror("Incompatible dimensions in '?:' condition");
+ FFERROR;
+ }
+ TYPE(ffvsp[-4].Node) = BOOLEAN;
+ if( SIZE(ffval.Node)<SIZE(ffvsp[-4].Node) ) Copy_Dims(ffval.Node, ffvsp[-4].Node);
+ ;
+ break;}
+case 48:
+#line 434 "eval.y"
+{
+ PROMOTE(ffvsp[-2].Node,ffvsp[0].Node);
+ if( ! Test_Dims(ffvsp[-2].Node,ffvsp[0].Node) ) {
+ fferror("Incompatible dimensions in '?:' arguments");
+ FFERROR;
+ }
+ ffval.Node = New_Func( 0, ifthenelse_fct, 3, ffvsp[-2].Node, ffvsp[0].Node, ffvsp[-4].Node,
+ 0, 0, 0, 0 );
+ TEST(ffval.Node);
+ if( SIZE(ffvsp[-2].Node)<SIZE(ffvsp[0].Node) ) Copy_Dims(ffval.Node, ffvsp[0].Node);
+ TYPE(ffvsp[-4].Node) = TYPE(ffvsp[-2].Node);
+ if( ! Test_Dims(ffvsp[-4].Node,ffval.Node) ) {
+ fferror("Incompatible dimensions in '?:' condition");
+ FFERROR;
+ }
+ TYPE(ffvsp[-4].Node) = BOOLEAN;
+ if( SIZE(ffval.Node)<SIZE(ffvsp[-4].Node) ) Copy_Dims(ffval.Node, ffvsp[-4].Node);
+ ;
+ break;}
+case 49:
+#line 453 "eval.y"
+{
+ PROMOTE(ffvsp[-2].Node,ffvsp[0].Node);
+ if( ! Test_Dims(ffvsp[-2].Node,ffvsp[0].Node) ) {
+ fferror("Incompatible dimensions in '?:' arguments");
+ FFERROR;
+ }
+ ffval.Node = New_Func( 0, ifthenelse_fct, 3, ffvsp[-2].Node, ffvsp[0].Node, ffvsp[-4].Node,
+ 0, 0, 0, 0 );
+ TEST(ffval.Node);
+ if( SIZE(ffvsp[-2].Node)<SIZE(ffvsp[0].Node) ) Copy_Dims(ffval.Node, ffvsp[0].Node);
+ TYPE(ffvsp[-4].Node) = TYPE(ffvsp[-2].Node);
+ if( ! Test_Dims(ffvsp[-4].Node,ffval.Node) ) {
+ fferror("Incompatible dimensions in '?:' condition");
+ FFERROR;
+ }
+ TYPE(ffvsp[-4].Node) = BOOLEAN;
+ if( SIZE(ffval.Node)<SIZE(ffvsp[-4].Node) ) Copy_Dims(ffval.Node, ffvsp[-4].Node);
+ ;
+ break;}
+case 50:
+#line 472 "eval.y"
+{ if (FSTRCMP(ffvsp[-1].str,"RANDOM(") == 0) {
+ srand( (unsigned int) time(NULL) );
+ ffval.Node = New_Func( DOUBLE, rnd_fct, 0, 0, 0, 0, 0, 0, 0, 0 );
+ } else {
+ fferror("Function() not supported");
+ FFERROR;
+ }
+ TEST(ffval.Node);
+ ;
+ break;}
+case 51:
+#line 482 "eval.y"
+{ if (FSTRCMP(ffvsp[-2].str,"SUM(") == 0) {
+ ffval.Node = New_Func( LONG, sum_fct, 1, ffvsp[-1].Node, 0, 0, 0, 0, 0, 0 );
+ } else if (FSTRCMP(ffvsp[-2].str,"NELEM(") == 0) {
+ ffval.Node = New_Const( LONG, &( SIZE(ffvsp[-1].Node) ), sizeof(long) );
+ } else if (FSTRCMP(ffvsp[-2].str,"ACCUM(") == 0) {
+ long zero = 0;
+ ffval.Node = New_BinOp( LONG , ffvsp[-1].Node, ACCUM, New_Const( LONG, &zero, sizeof(zero) ));
+ } else {
+ fferror("Function(bool) not supported");
+ FFERROR;
+ }
+ TEST(ffval.Node);
+ ;
+ break;}
+case 52:
+#line 496 "eval.y"
+{ if (FSTRCMP(ffvsp[-2].str,"NELEM(") == 0) {
+ ffval.Node = New_Const( LONG, &( SIZE(ffvsp[-1].Node) ), sizeof(long) );
+ } else if (FSTRCMP(ffvsp[-2].str,"NVALID(") == 0) {
+ ffval.Node = New_Func( LONG, nonnull_fct, 1, ffvsp[-1].Node,
+ 0, 0, 0, 0, 0, 0 );
+ } else {
+ fferror("Function(str) not supported");
+ FFERROR;
+ }
+ TEST(ffval.Node);
+ ;
+ break;}
+case 53:
+#line 508 "eval.y"
+{ if (FSTRCMP(ffvsp[-2].str,"NELEM(") == 0) {
+ ffval.Node = New_Const( LONG, &( SIZE(ffvsp[-1].Node) ), sizeof(long) );
+ } else if (FSTRCMP(ffvsp[-2].str,"NVALID(") == 0) { /* Bit arrays do not have NULL */
+ ffval.Node = New_Const( LONG, &( SIZE(ffvsp[-1].Node) ), sizeof(long) );
+ } else if (FSTRCMP(ffvsp[-2].str,"SUM(") == 0) {
+ ffval.Node = New_Func( LONG, sum_fct, 1, ffvsp[-1].Node,
+ 0, 0, 0, 0, 0, 0 );
+ } else if (FSTRCMP(ffvsp[-2].str,"MIN(") == 0) {
+ ffval.Node = New_Func( TYPE(ffvsp[-1].Node), /* Force 1D result */
+ min1_fct, 1, ffvsp[-1].Node, 0, 0, 0, 0, 0, 0 );
+ SIZE(ffval.Node) = 1;
+ } else if (FSTRCMP(ffvsp[-2].str,"ACCUM(") == 0) {
+ long zero = 0;
+ ffval.Node = New_BinOp( LONG , ffvsp[-1].Node, ACCUM, New_Const( LONG, &zero, sizeof(zero) ));
+ } else if (FSTRCMP(ffvsp[-2].str,"MAX(") == 0) {
+ ffval.Node = New_Func( TYPE(ffvsp[-1].Node), /* Force 1D result */
+ max1_fct, 1, ffvsp[-1].Node, 0, 0, 0, 0, 0, 0 );
+ SIZE(ffval.Node) = 1;
+ } else {
+ fferror("Function(bits) not supported");
+ FFERROR;
+ }
+ TEST(ffval.Node);
+ ;
+ break;}
+case 54:
+#line 533 "eval.y"
+{ if (FSTRCMP(ffvsp[-2].str,"SUM(") == 0)
+ ffval.Node = New_Func( TYPE(ffvsp[-1].Node), sum_fct, 1, ffvsp[-1].Node,
+ 0, 0, 0, 0, 0, 0 );
+ else if (FSTRCMP(ffvsp[-2].str,"AVERAGE(") == 0)
+ ffval.Node = New_Func( DOUBLE, average_fct, 1, ffvsp[-1].Node,
+ 0, 0, 0, 0, 0, 0 );
+ else if (FSTRCMP(ffvsp[-2].str,"STDDEV(") == 0)
+ ffval.Node = New_Func( DOUBLE, stddev_fct, 1, ffvsp[-1].Node,
+ 0, 0, 0, 0, 0, 0 );
+ else if (FSTRCMP(ffvsp[-2].str,"MEDIAN(") == 0)
+ ffval.Node = New_Func( TYPE(ffvsp[-1].Node), median_fct, 1, ffvsp[-1].Node,
+ 0, 0, 0, 0, 0, 0 );
+ else if (FSTRCMP(ffvsp[-2].str,"NELEM(") == 0)
+ ffval.Node = New_Const( LONG, &( SIZE(ffvsp[-1].Node) ), sizeof(long) );
+ else if (FSTRCMP(ffvsp[-2].str,"NVALID(") == 0)
+ ffval.Node = New_Func( LONG, nonnull_fct, 1, ffvsp[-1].Node,
+ 0, 0, 0, 0, 0, 0 );
+ else if ((FSTRCMP(ffvsp[-2].str,"ACCUM(") == 0) && (TYPE(ffvsp[-1].Node) == LONG)) {
+ long zero = 0;
+ ffval.Node = New_BinOp( LONG , ffvsp[-1].Node, ACCUM, New_Const( LONG, &zero, sizeof(zero) ));
+ } else if ((FSTRCMP(ffvsp[-2].str,"ACCUM(") == 0) && (TYPE(ffvsp[-1].Node) == DOUBLE)) {
+ double zero = 0;
+ ffval.Node = New_BinOp( DOUBLE , ffvsp[-1].Node, ACCUM, New_Const( DOUBLE, &zero, sizeof(zero) ));
+ } else if ((FSTRCMP(ffvsp[-2].str,"SEQDIFF(") == 0) && (TYPE(ffvsp[-1].Node) == LONG)) {
+ long zero = 0;
+ ffval.Node = New_BinOp( LONG , ffvsp[-1].Node, DIFF, New_Const( LONG, &zero, sizeof(zero) ));
+ } else if ((FSTRCMP(ffvsp[-2].str,"SEQDIFF(") == 0) && (TYPE(ffvsp[-1].Node) == DOUBLE)) {
+ double zero = 0;
+ ffval.Node = New_BinOp( DOUBLE , ffvsp[-1].Node, DIFF, New_Const( DOUBLE, &zero, sizeof(zero) ));
+ } else if (FSTRCMP(ffvsp[-2].str,"ABS(") == 0)
+ ffval.Node = New_Func( 0, abs_fct, 1, ffvsp[-1].Node, 0, 0, 0, 0, 0, 0 );
+ else if (FSTRCMP(ffvsp[-2].str,"MIN(") == 0)
+ ffval.Node = New_Func( TYPE(ffvsp[-1].Node), /* Force 1D result */
+ min1_fct, 1, ffvsp[-1].Node, 0, 0, 0, 0, 0, 0 );
+ else if (FSTRCMP(ffvsp[-2].str,"MAX(") == 0)
+ ffval.Node = New_Func( TYPE(ffvsp[-1].Node), /* Force 1D result */
+ max1_fct, 1, ffvsp[-1].Node, 0, 0, 0, 0, 0, 0 );
+ else { /* These all take DOUBLE arguments */
+ if( TYPE(ffvsp[-1].Node) != DOUBLE ) ffvsp[-1].Node = New_Unary( DOUBLE, 0, ffvsp[-1].Node );
+ if (FSTRCMP(ffvsp[-2].str,"SIN(") == 0)
+ ffval.Node = New_Func( 0, sin_fct, 1, ffvsp[-1].Node, 0, 0, 0, 0, 0, 0 );
+ else if (FSTRCMP(ffvsp[-2].str,"COS(") == 0)
+ ffval.Node = New_Func( 0, cos_fct, 1, ffvsp[-1].Node, 0, 0, 0, 0, 0, 0 );
+ else if (FSTRCMP(ffvsp[-2].str,"TAN(") == 0)
+ ffval.Node = New_Func( 0, tan_fct, 1, ffvsp[-1].Node, 0, 0, 0, 0, 0, 0 );
+ else if (FSTRCMP(ffvsp[-2].str,"ARCSIN(") == 0
+ || FSTRCMP(ffvsp[-2].str,"ASIN(") == 0)
+ ffval.Node = New_Func( 0, asin_fct, 1, ffvsp[-1].Node, 0, 0, 0, 0, 0, 0 );
+ else if (FSTRCMP(ffvsp[-2].str,"ARCCOS(") == 0
+ || FSTRCMP(ffvsp[-2].str,"ACOS(") == 0)
+ ffval.Node = New_Func( 0, acos_fct, 1, ffvsp[-1].Node, 0, 0, 0, 0, 0, 0 );
+ else if (FSTRCMP(ffvsp[-2].str,"ARCTAN(") == 0
+ || FSTRCMP(ffvsp[-2].str,"ATAN(") == 0)
+ ffval.Node = New_Func( 0, atan_fct, 1, ffvsp[-1].Node, 0, 0, 0, 0, 0, 0 );
+ else if (FSTRCMP(ffvsp[-2].str,"SINH(") == 0)
+ ffval.Node = New_Func( 0, sinh_fct, 1, ffvsp[-1].Node, 0, 0, 0, 0, 0, 0 );
+ else if (FSTRCMP(ffvsp[-2].str,"COSH(") == 0)
+ ffval.Node = New_Func( 0, cosh_fct, 1, ffvsp[-1].Node, 0, 0, 0, 0, 0, 0 );
+ else if (FSTRCMP(ffvsp[-2].str,"TANH(") == 0)
+ ffval.Node = New_Func( 0, tanh_fct, 1, ffvsp[-1].Node, 0, 0, 0, 0, 0, 0 );
+ else if (FSTRCMP(ffvsp[-2].str,"EXP(") == 0)
+ ffval.Node = New_Func( 0, exp_fct, 1, ffvsp[-1].Node, 0, 0, 0, 0, 0, 0 );
+ else if (FSTRCMP(ffvsp[-2].str,"LOG(") == 0)
+ ffval.Node = New_Func( 0, log_fct, 1, ffvsp[-1].Node, 0, 0, 0, 0, 0, 0 );
+ else if (FSTRCMP(ffvsp[-2].str,"LOG10(") == 0)
+ ffval.Node = New_Func( 0, log10_fct, 1, ffvsp[-1].Node, 0, 0, 0, 0, 0, 0 );
+ else if (FSTRCMP(ffvsp[-2].str,"SQRT(") == 0)
+ ffval.Node = New_Func( 0, sqrt_fct, 1, ffvsp[-1].Node, 0, 0, 0, 0, 0, 0 );
+ else if (FSTRCMP(ffvsp[-2].str,"FLOOR(") == 0)
+ ffval.Node = New_Func( 0, floor_fct, 1, ffvsp[-1].Node, 0, 0, 0, 0, 0, 0 );
+ else if (FSTRCMP(ffvsp[-2].str,"CEIL(") == 0)
+ ffval.Node = New_Func( 0, ceil_fct, 1, ffvsp[-1].Node, 0, 0, 0, 0, 0, 0 );
+ else {
+ fferror("Function(expr) not supported");
+ FFERROR;
+ }
+ }
+ TEST(ffval.Node);
+ ;
+ break;}
+case 55:
+#line 613 "eval.y"
+{
+ if (FSTRCMP(ffvsp[-4].str,"DEFNULL(") == 0) {
+ if( SIZE(ffvsp[-3].Node)>=SIZE(ffvsp[-1].Node) && Test_Dims( ffvsp[-3].Node, ffvsp[-1].Node ) ) {
+ PROMOTE(ffvsp[-3].Node,ffvsp[-1].Node);
+ ffval.Node = New_Func( 0, defnull_fct, 2, ffvsp[-3].Node, ffvsp[-1].Node, 0,
+ 0, 0, 0, 0 );
+ TEST(ffval.Node);
+ } else {
+ fferror("Dimensions of DEFNULL arguments "
+ "are not compatible");
+ FFERROR;
+ }
+ } else if (FSTRCMP(ffvsp[-4].str,"ARCTAN2(") == 0) {
+ if( TYPE(ffvsp[-3].Node) != DOUBLE ) ffvsp[-3].Node = New_Unary( DOUBLE, 0, ffvsp[-3].Node );
+ if( TYPE(ffvsp[-1].Node) != DOUBLE ) ffvsp[-1].Node = New_Unary( DOUBLE, 0, ffvsp[-1].Node );
+ if( Test_Dims( ffvsp[-3].Node, ffvsp[-1].Node ) ) {
+ ffval.Node = New_Func( 0, atan2_fct, 2, ffvsp[-3].Node, ffvsp[-1].Node, 0, 0, 0, 0, 0 );
+ TEST(ffval.Node);
+ if( SIZE(ffvsp[-3].Node)<SIZE(ffvsp[-1].Node) ) Copy_Dims(ffval.Node, ffvsp[-1].Node);
+ } else {
+ fferror("Dimensions of arctan2 arguments "
+ "are not compatible");
+ FFERROR;
+ }
+ } else if (FSTRCMP(ffvsp[-4].str,"MIN(") == 0) {
+ PROMOTE( ffvsp[-3].Node, ffvsp[-1].Node );
+ if( Test_Dims( ffvsp[-3].Node, ffvsp[-1].Node ) ) {
+ ffval.Node = New_Func( 0, min2_fct, 2, ffvsp[-3].Node, ffvsp[-1].Node, 0, 0, 0, 0, 0 );
+ TEST(ffval.Node);
+ if( SIZE(ffvsp[-3].Node)<SIZE(ffvsp[-1].Node) ) Copy_Dims(ffval.Node, ffvsp[-1].Node);
+ } else {
+ fferror("Dimensions of min(a,b) arguments "
+ "are not compatible");
+ FFERROR;
+ }
+ } else if (FSTRCMP(ffvsp[-4].str,"MAX(") == 0) {
+ PROMOTE( ffvsp[-3].Node, ffvsp[-1].Node );
+ if( Test_Dims( ffvsp[-3].Node, ffvsp[-1].Node ) ) {
+ ffval.Node = New_Func( 0, max2_fct, 2, ffvsp[-3].Node, ffvsp[-1].Node, 0, 0, 0, 0, 0 );
+ TEST(ffval.Node);
+ if( SIZE(ffvsp[-3].Node)<SIZE(ffvsp[-1].Node) ) Copy_Dims(ffval.Node, ffvsp[-1].Node);
+ } else {
+ fferror("Dimensions of max(a,b) arguments "
+ "are not compatible");
+ FFERROR;
+ }
+ } else {
+ fferror("Function(expr,expr) not supported");
+ FFERROR;
+ }
+ ;
+ break;}
+case 56:
+#line 665 "eval.y"
+{ ffval.Node = New_Deref( ffvsp[-3].Node, 1, ffvsp[-1].Node, 0, 0, 0, 0 ); TEST(ffval.Node); ;
+ break;}
+case 57:
+#line 667 "eval.y"
+{ ffval.Node = New_Deref( ffvsp[-5].Node, 2, ffvsp[-3].Node, ffvsp[-1].Node, 0, 0, 0 ); TEST(ffval.Node); ;
+ break;}
+case 58:
+#line 669 "eval.y"
+{ ffval.Node = New_Deref( ffvsp[-7].Node, 3, ffvsp[-5].Node, ffvsp[-3].Node, ffvsp[-1].Node, 0, 0 ); TEST(ffval.Node); ;
+ break;}
+case 59:
+#line 671 "eval.y"
+{ ffval.Node = New_Deref( ffvsp[-9].Node, 4, ffvsp[-7].Node, ffvsp[-5].Node, ffvsp[-3].Node, ffvsp[-1].Node, 0 ); TEST(ffval.Node); ;
+ break;}
+case 60:
+#line 673 "eval.y"
+{ ffval.Node = New_Deref( ffvsp[-11].Node, 5, ffvsp[-9].Node, ffvsp[-7].Node, ffvsp[-5].Node, ffvsp[-3].Node, ffvsp[-1].Node ); TEST(ffval.Node); ;
+ break;}
+case 61:
+#line 675 "eval.y"
+{ ffval.Node = New_Unary( LONG, INTCAST, ffvsp[0].Node ); TEST(ffval.Node); ;
+ break;}
+case 62:
+#line 677 "eval.y"
+{ ffval.Node = New_Unary( LONG, INTCAST, ffvsp[0].Node ); TEST(ffval.Node); ;
+ break;}
+case 63:
+#line 679 "eval.y"
+{ ffval.Node = New_Unary( DOUBLE, FLTCAST, ffvsp[0].Node ); TEST(ffval.Node); ;
+ break;}
+case 64:
+#line 681 "eval.y"
+{ ffval.Node = New_Unary( DOUBLE, FLTCAST, ffvsp[0].Node ); TEST(ffval.Node); ;
+ break;}
+case 65:
+#line 685 "eval.y"
+{ ffval.Node = New_Const( BOOLEAN, &(ffvsp[0].log), sizeof(char) ); TEST(ffval.Node); ;
+ break;}
+case 66:
+#line 687 "eval.y"
+{ ffval.Node = New_Column( ffvsp[0].lng ); TEST(ffval.Node); ;
+ break;}
+case 67:
+#line 689 "eval.y"
+{
+ if( TYPE(ffvsp[-1].Node) != LONG
+ || gParse.Nodes[ffvsp[-1].Node].operation != CONST_OP ) {
+ fferror("Offset argument must be a constant integer");
+ FFERROR;
+ }
+ ffval.Node = New_Offset( ffvsp[-3].lng, ffvsp[-1].Node ); TEST(ffval.Node);
+ ;
+ break;}
+case 68:
+#line 698 "eval.y"
+{ ffval.Node = New_BinOp( BOOLEAN, ffvsp[-2].Node, EQ, ffvsp[0].Node ); TEST(ffval.Node);
+ SIZE(ffval.Node) = 1; ;
+ break;}
+case 69:
+#line 701 "eval.y"
+{ ffval.Node = New_BinOp( BOOLEAN, ffvsp[-2].Node, NE, ffvsp[0].Node ); TEST(ffval.Node);
+ SIZE(ffval.Node) = 1; ;
+ break;}
+case 70:
+#line 704 "eval.y"
+{ ffval.Node = New_BinOp( BOOLEAN, ffvsp[-2].Node, LT, ffvsp[0].Node ); TEST(ffval.Node);
+ SIZE(ffval.Node) = 1; ;
+ break;}
+case 71:
+#line 707 "eval.y"
+{ ffval.Node = New_BinOp( BOOLEAN, ffvsp[-2].Node, LTE, ffvsp[0].Node ); TEST(ffval.Node);
+ SIZE(ffval.Node) = 1; ;
+ break;}
+case 72:
+#line 710 "eval.y"
+{ ffval.Node = New_BinOp( BOOLEAN, ffvsp[-2].Node, GT, ffvsp[0].Node ); TEST(ffval.Node);
+ SIZE(ffval.Node) = 1; ;
+ break;}
+case 73:
+#line 713 "eval.y"
+{ ffval.Node = New_BinOp( BOOLEAN, ffvsp[-2].Node, GTE, ffvsp[0].Node ); TEST(ffval.Node);
+ SIZE(ffval.Node) = 1; ;
+ break;}
+case 74:
+#line 716 "eval.y"
+{ PROMOTE(ffvsp[-2].Node,ffvsp[0].Node); ffval.Node = New_BinOp( BOOLEAN, ffvsp[-2].Node, GT, ffvsp[0].Node );
+ TEST(ffval.Node); ;
+ break;}
+case 75:
+#line 719 "eval.y"
+{ PROMOTE(ffvsp[-2].Node,ffvsp[0].Node); ffval.Node = New_BinOp( BOOLEAN, ffvsp[-2].Node, LT, ffvsp[0].Node );
+ TEST(ffval.Node); ;
+ break;}
+case 76:
+#line 722 "eval.y"
+{ PROMOTE(ffvsp[-2].Node,ffvsp[0].Node); ffval.Node = New_BinOp( BOOLEAN, ffvsp[-2].Node, GTE, ffvsp[0].Node );
+ TEST(ffval.Node); ;
+ break;}
+case 77:
+#line 725 "eval.y"
+{ PROMOTE(ffvsp[-2].Node,ffvsp[0].Node); ffval.Node = New_BinOp( BOOLEAN, ffvsp[-2].Node, LTE, ffvsp[0].Node );
+ TEST(ffval.Node); ;
+ break;}
+case 78:
+#line 728 "eval.y"
+{ PROMOTE(ffvsp[-2].Node,ffvsp[0].Node); ffval.Node = New_BinOp( BOOLEAN, ffvsp[-2].Node, '~', ffvsp[0].Node );
+ TEST(ffval.Node); ;
+ break;}
+case 79:
+#line 731 "eval.y"
+{ PROMOTE(ffvsp[-2].Node,ffvsp[0].Node); ffval.Node = New_BinOp( BOOLEAN, ffvsp[-2].Node, EQ, ffvsp[0].Node );
+ TEST(ffval.Node); ;
+ break;}
+case 80:
+#line 734 "eval.y"
+{ PROMOTE(ffvsp[-2].Node,ffvsp[0].Node); ffval.Node = New_BinOp( BOOLEAN, ffvsp[-2].Node, NE, ffvsp[0].Node );
+ TEST(ffval.Node); ;
+ break;}
+case 81:
+#line 737 "eval.y"
+{ ffval.Node = New_BinOp( BOOLEAN, ffvsp[-2].Node, EQ, ffvsp[0].Node ); TEST(ffval.Node);
+ SIZE(ffval.Node) = 1; ;
+ break;}
+case 82:
+#line 740 "eval.y"
+{ ffval.Node = New_BinOp( BOOLEAN, ffvsp[-2].Node, NE, ffvsp[0].Node ); TEST(ffval.Node);
+ SIZE(ffval.Node) = 1; ;
+ break;}
+case 83:
+#line 743 "eval.y"
+{ ffval.Node = New_BinOp( BOOLEAN, ffvsp[-2].Node, GT, ffvsp[0].Node ); TEST(ffval.Node);
+ SIZE(ffval.Node) = 1; ;
+ break;}
+case 84:
+#line 746 "eval.y"
+{ ffval.Node = New_BinOp( BOOLEAN, ffvsp[-2].Node, GTE, ffvsp[0].Node ); TEST(ffval.Node);
+ SIZE(ffval.Node) = 1; ;
+ break;}
+case 85:
+#line 749 "eval.y"
+{ ffval.Node = New_BinOp( BOOLEAN, ffvsp[-2].Node, LT, ffvsp[0].Node ); TEST(ffval.Node);
+ SIZE(ffval.Node) = 1; ;
+ break;}
+case 86:
+#line 752 "eval.y"
+{ ffval.Node = New_BinOp( BOOLEAN, ffvsp[-2].Node, LTE, ffvsp[0].Node ); TEST(ffval.Node);
+ SIZE(ffval.Node) = 1; ;
+ break;}
+case 87:
+#line 755 "eval.y"
+{ ffval.Node = New_BinOp( BOOLEAN, ffvsp[-2].Node, AND, ffvsp[0].Node ); TEST(ffval.Node); ;
+ break;}
+case 88:
+#line 757 "eval.y"
+{ ffval.Node = New_BinOp( BOOLEAN, ffvsp[-2].Node, OR, ffvsp[0].Node ); TEST(ffval.Node); ;
+ break;}
+case 89:
+#line 759 "eval.y"
+{ ffval.Node = New_BinOp( BOOLEAN, ffvsp[-2].Node, EQ, ffvsp[0].Node ); TEST(ffval.Node); ;
+ break;}
+case 90:
+#line 761 "eval.y"
+{ ffval.Node = New_BinOp( BOOLEAN, ffvsp[-2].Node, NE, ffvsp[0].Node ); TEST(ffval.Node); ;
+ break;}
+case 91:
+#line 764 "eval.y"
+{ PROMOTE(ffvsp[-4].Node,ffvsp[-2].Node); PROMOTE(ffvsp[-4].Node,ffvsp[0].Node); PROMOTE(ffvsp[-2].Node,ffvsp[0].Node);
+ ffvsp[-2].Node = New_BinOp( BOOLEAN, ffvsp[-2].Node, LTE, ffvsp[-4].Node );
+ ffvsp[0].Node = New_BinOp( BOOLEAN, ffvsp[-4].Node, LTE, ffvsp[0].Node );
+ ffval.Node = New_BinOp( BOOLEAN, ffvsp[-2].Node, AND, ffvsp[0].Node );
+ TEST(ffval.Node); ;
+ break;}
+case 92:
+#line 771 "eval.y"
+{
+ if( ! Test_Dims(ffvsp[-2].Node,ffvsp[0].Node) ) {
+ fferror("Incompatible dimensions in '?:' arguments");
+ FFERROR;
+ }
+ ffval.Node = New_Func( 0, ifthenelse_fct, 3, ffvsp[-2].Node, ffvsp[0].Node, ffvsp[-4].Node,
+ 0, 0, 0, 0 );
+ TEST(ffval.Node);
+ if( SIZE(ffvsp[-2].Node)<SIZE(ffvsp[0].Node) ) Copy_Dims(ffval.Node, ffvsp[0].Node);
+ if( ! Test_Dims(ffvsp[-4].Node,ffval.Node) ) {
+ fferror("Incompatible dimensions in '?:' condition");
+ FFERROR;
+ }
+ if( SIZE(ffval.Node)<SIZE(ffvsp[-4].Node) ) Copy_Dims(ffval.Node, ffvsp[-4].Node);
+ ;
+ break;}
+case 93:
+#line 788 "eval.y"
+{
+ if (FSTRCMP(ffvsp[-2].str,"ISNULL(") == 0) {
+ ffval.Node = New_Func( 0, isnull_fct, 1, ffvsp[-1].Node, 0, 0,
+ 0, 0, 0, 0 );
+ TEST(ffval.Node);
+ /* Use expression's size, but return BOOLEAN */
+ TYPE(ffval.Node) = BOOLEAN;
+ } else {
+ fferror("Boolean Function(expr) not supported");
+ FFERROR;
+ }
+ ;
+ break;}
+case 94:
+#line 801 "eval.y"
+{
+ if (FSTRCMP(ffvsp[-2].str,"ISNULL(") == 0) {
+ ffval.Node = New_Func( 0, isnull_fct, 1, ffvsp[-1].Node, 0, 0,
+ 0, 0, 0, 0 );
+ TEST(ffval.Node);
+ /* Use expression's size, but return BOOLEAN */
+ TYPE(ffval.Node) = BOOLEAN;
+ } else {
+ fferror("Boolean Function(expr) not supported");
+ FFERROR;
+ }
+ ;
+ break;}
+case 95:
+#line 814 "eval.y"
+{
+ if (FSTRCMP(ffvsp[-2].str,"ISNULL(") == 0) {
+ ffval.Node = New_Func( BOOLEAN, isnull_fct, 1, ffvsp[-1].Node, 0, 0,
+ 0, 0, 0, 0 );
+ TEST(ffval.Node);
+ } else {
+ fferror("Boolean Function(expr) not supported");
+ FFERROR;
+ }
+ ;
+ break;}
+case 96:
+#line 825 "eval.y"
+{
+ if (FSTRCMP(ffvsp[-4].str,"DEFNULL(") == 0) {
+ if( SIZE(ffvsp[-3].Node)>=SIZE(ffvsp[-1].Node) && Test_Dims( ffvsp[-3].Node, ffvsp[-1].Node ) ) {
+ ffval.Node = New_Func( 0, defnull_fct, 2, ffvsp[-3].Node, ffvsp[-1].Node, 0,
+ 0, 0, 0, 0 );
+ TEST(ffval.Node);
+ } else {
+ fferror("Dimensions of DEFNULL arguments are not compatible");
+ FFERROR;
+ }
+ } else {
+ fferror("Boolean Function(expr,expr) not supported");
+ FFERROR;
+ }
+ ;
+ break;}
+case 97:
+#line 841 "eval.y"
+{
+ if( SIZE(ffvsp[-5].Node)>1 || SIZE(ffvsp[-3].Node)>1 || SIZE(ffvsp[-1].Node)>1 ) {
+ fferror("Cannot use array as function argument");
+ FFERROR;
+ }
+ if( TYPE(ffvsp[-5].Node) != DOUBLE ) ffvsp[-5].Node = New_Unary( DOUBLE, 0, ffvsp[-5].Node );
+ if( TYPE(ffvsp[-3].Node) != DOUBLE ) ffvsp[-3].Node = New_Unary( DOUBLE, 0, ffvsp[-3].Node );
+ if( TYPE(ffvsp[-1].Node) != DOUBLE ) ffvsp[-1].Node = New_Unary( DOUBLE, 0, ffvsp[-1].Node );
+ if (FSTRCMP(ffvsp[-6].str,"NEAR(") == 0)
+ ffval.Node = New_Func( BOOLEAN, near_fct, 3, ffvsp[-5].Node, ffvsp[-3].Node, ffvsp[-1].Node,
+ 0, 0, 0, 0 );
+ else {
+ fferror("Boolean Function not supported");
+ FFERROR;
+ }
+ TEST(ffval.Node);
+ ;
+ break;}
+case 98:
+#line 859 "eval.y"
+{
+ if( SIZE(ffvsp[-9].Node)>1 || SIZE(ffvsp[-7].Node)>1 || SIZE(ffvsp[-5].Node)>1 || SIZE(ffvsp[-3].Node)>1
+ || SIZE(ffvsp[-1].Node)>1 ) {
+ fferror("Cannot use array as function argument");
+ FFERROR;
+ }
+ if( TYPE(ffvsp[-9].Node) != DOUBLE ) ffvsp[-9].Node = New_Unary( DOUBLE, 0, ffvsp[-9].Node );
+ if( TYPE(ffvsp[-7].Node) != DOUBLE ) ffvsp[-7].Node = New_Unary( DOUBLE, 0, ffvsp[-7].Node );
+ if( TYPE(ffvsp[-5].Node) != DOUBLE ) ffvsp[-5].Node = New_Unary( DOUBLE, 0, ffvsp[-5].Node );
+ if( TYPE(ffvsp[-3].Node) != DOUBLE ) ffvsp[-3].Node = New_Unary( DOUBLE, 0, ffvsp[-3].Node );
+ if( TYPE(ffvsp[-1].Node)!= DOUBLE ) ffvsp[-1].Node= New_Unary( DOUBLE, 0, ffvsp[-1].Node);
+ if (FSTRCMP(ffvsp[-10].str,"CIRCLE(") == 0)
+ ffval.Node = New_Func( BOOLEAN, circle_fct, 5, ffvsp[-9].Node, ffvsp[-7].Node, ffvsp[-5].Node, ffvsp[-3].Node,
+ ffvsp[-1].Node, 0, 0 );
+ else {
+ fferror("Boolean Function not supported");
+ FFERROR;
+ }
+ TEST(ffval.Node);
+ ;
+ break;}
+case 99:
+#line 880 "eval.y"
+{
+ if( SIZE(ffvsp[-13].Node)>1 || SIZE(ffvsp[-11].Node)>1 || SIZE(ffvsp[-9].Node)>1 || SIZE(ffvsp[-7].Node)>1
+ || SIZE(ffvsp[-5].Node)>1 || SIZE(ffvsp[-3].Node)>1 || SIZE(ffvsp[-1].Node)>1 ) {
+ fferror("Cannot use array as function argument");
+ FFERROR;
+ }
+ if( TYPE(ffvsp[-13].Node) != DOUBLE ) ffvsp[-13].Node = New_Unary( DOUBLE, 0, ffvsp[-13].Node );
+ if( TYPE(ffvsp[-11].Node) != DOUBLE ) ffvsp[-11].Node = New_Unary( DOUBLE, 0, ffvsp[-11].Node );
+ if( TYPE(ffvsp[-9].Node) != DOUBLE ) ffvsp[-9].Node = New_Unary( DOUBLE, 0, ffvsp[-9].Node );
+ if( TYPE(ffvsp[-7].Node) != DOUBLE ) ffvsp[-7].Node = New_Unary( DOUBLE, 0, ffvsp[-7].Node );
+ if( TYPE(ffvsp[-5].Node)!= DOUBLE ) ffvsp[-5].Node= New_Unary( DOUBLE, 0, ffvsp[-5].Node);
+ if( TYPE(ffvsp[-3].Node)!= DOUBLE ) ffvsp[-3].Node= New_Unary( DOUBLE, 0, ffvsp[-3].Node);
+ if( TYPE(ffvsp[-1].Node)!= DOUBLE ) ffvsp[-1].Node= New_Unary( DOUBLE, 0, ffvsp[-1].Node);
+ if (FSTRCMP(ffvsp[-14].str,"BOX(") == 0)
+ ffval.Node = New_Func( BOOLEAN, box_fct, 7, ffvsp[-13].Node, ffvsp[-11].Node, ffvsp[-9].Node, ffvsp[-7].Node,
+ ffvsp[-5].Node, ffvsp[-3].Node, ffvsp[-1].Node );
+ else if (FSTRCMP(ffvsp[-14].str,"ELLIPSE(") == 0)
+ ffval.Node = New_Func( BOOLEAN, elps_fct, 7, ffvsp[-13].Node, ffvsp[-11].Node, ffvsp[-9].Node, ffvsp[-7].Node,
+ ffvsp[-5].Node, ffvsp[-3].Node, ffvsp[-1].Node );
+ else {
+ fferror("SAO Image Function not supported");
+ FFERROR;
+ }
+ TEST(ffval.Node);
+ ;
+ break;}
+case 100:
+#line 907 "eval.y"
+{ /* Use defaults for all elements */
+ ffval.Node = New_GTI( "", -99, "*START*", "*STOP*" );
+ TEST(ffval.Node); ;
+ break;}
+case 101:
+#line 911 "eval.y"
+{ /* Use defaults for all except filename */
+ ffval.Node = New_GTI( ffvsp[-1].str, -99, "*START*", "*STOP*" );
+ TEST(ffval.Node); ;
+ break;}
+case 102:
+#line 915 "eval.y"
+{ ffval.Node = New_GTI( ffvsp[-3].str, ffvsp[-1].Node, "*START*", "*STOP*" );
+ TEST(ffval.Node); ;
+ break;}
+case 103:
+#line 918 "eval.y"
+{ ffval.Node = New_GTI( ffvsp[-7].str, ffvsp[-5].Node, ffvsp[-3].str, ffvsp[-1].str );
+ TEST(ffval.Node); ;
+ break;}
+case 104:
+#line 922 "eval.y"
+{ /* Use defaults for all except filename */
+ ffval.Node = New_REG( ffvsp[-1].str, -99, -99, "" );
+ TEST(ffval.Node); ;
+ break;}
+case 105:
+#line 926 "eval.y"
+{ ffval.Node = New_REG( ffvsp[-5].str, ffvsp[-3].Node, ffvsp[-1].Node, "" );
+ TEST(ffval.Node); ;
+ break;}
+case 106:
+#line 929 "eval.y"
+{ ffval.Node = New_REG( ffvsp[-7].str, ffvsp[-5].Node, ffvsp[-3].Node, ffvsp[-1].str );
+ TEST(ffval.Node); ;
+ break;}
+case 107:
+#line 933 "eval.y"
+{ ffval.Node = New_Deref( ffvsp[-3].Node, 1, ffvsp[-1].Node, 0, 0, 0, 0 ); TEST(ffval.Node); ;
+ break;}
+case 108:
+#line 935 "eval.y"
+{ ffval.Node = New_Deref( ffvsp[-5].Node, 2, ffvsp[-3].Node, ffvsp[-1].Node, 0, 0, 0 ); TEST(ffval.Node); ;
+ break;}
+case 109:
+#line 937 "eval.y"
+{ ffval.Node = New_Deref( ffvsp[-7].Node, 3, ffvsp[-5].Node, ffvsp[-3].Node, ffvsp[-1].Node, 0, 0 ); TEST(ffval.Node); ;
+ break;}
+case 110:
+#line 939 "eval.y"
+{ ffval.Node = New_Deref( ffvsp[-9].Node, 4, ffvsp[-7].Node, ffvsp[-5].Node, ffvsp[-3].Node, ffvsp[-1].Node, 0 ); TEST(ffval.Node); ;
+ break;}
+case 111:
+#line 941 "eval.y"
+{ ffval.Node = New_Deref( ffvsp[-11].Node, 5, ffvsp[-9].Node, ffvsp[-7].Node, ffvsp[-5].Node, ffvsp[-3].Node, ffvsp[-1].Node ); TEST(ffval.Node); ;
+ break;}
+case 112:
+#line 943 "eval.y"
+{ ffval.Node = New_Unary( BOOLEAN, NOT, ffvsp[0].Node ); TEST(ffval.Node); ;
+ break;}
+case 113:
+#line 945 "eval.y"
+{ ffval.Node = ffvsp[-1].Node; ;
+ break;}
+case 114:
+#line 949 "eval.y"
+{ ffval.Node = New_Const( STRING, ffvsp[0].str, strlen(ffvsp[0].str)+1 ); TEST(ffval.Node);
+ SIZE(ffval.Node) = strlen(ffvsp[0].str); ;
+ break;}
+case 115:
+#line 952 "eval.y"
+{ ffval.Node = New_Column( ffvsp[0].lng ); TEST(ffval.Node); ;
+ break;}
+case 116:
+#line 954 "eval.y"
+{
+ if( TYPE(ffvsp[-1].Node) != LONG
+ || gParse.Nodes[ffvsp[-1].Node].operation != CONST_OP ) {
+ fferror("Offset argument must be a constant integer");
+ FFERROR;
+ }
+ ffval.Node = New_Offset( ffvsp[-3].lng, ffvsp[-1].Node ); TEST(ffval.Node);
+ ;
+ break;}
+case 117:
+#line 963 "eval.y"
+{ ffval.Node = New_Func( STRING, null_fct, 0, 0, 0, 0, 0, 0, 0, 0 ); ;
+ break;}
+case 118:
+#line 965 "eval.y"
+{ ffval.Node = ffvsp[-1].Node; ;
+ break;}
+case 119:
+#line 967 "eval.y"
+{ ffval.Node = New_BinOp( STRING, ffvsp[-2].Node, '+', ffvsp[0].Node ); TEST(ffval.Node);
+ SIZE(ffval.Node) = SIZE(ffvsp[-2].Node) + SIZE(ffvsp[0].Node); ;
+ break;}
+case 120:
+#line 970 "eval.y"
+{
+ if( SIZE(ffvsp[-4].Node)!=1 ) {
+ fferror("Cannot have a vector string column");
+ FFERROR;
+ }
+ ffval.Node = New_Func( 0, ifthenelse_fct, 3, ffvsp[-2].Node, ffvsp[0].Node, ffvsp[-4].Node,
+ 0, 0, 0, 0 );
+ TEST(ffval.Node);
+ if( SIZE(ffvsp[-2].Node)<SIZE(ffvsp[0].Node) ) Copy_Dims(ffval.Node, ffvsp[0].Node);
+ ;
+ break;}
+case 121:
+#line 982 "eval.y"
+{
+ if (FSTRCMP(ffvsp[-4].str,"DEFNULL(") == 0) {
+ ffval.Node = New_Func( 0, defnull_fct, 2, ffvsp[-3].Node, ffvsp[-1].Node, 0,
+ 0, 0, 0, 0 );
+ TEST(ffval.Node);
+ if( SIZE(ffvsp[-1].Node)>SIZE(ffvsp[-3].Node) ) SIZE(ffval.Node) = SIZE(ffvsp[-1].Node);
+ }
+ ;
+ break;}
+}
+ /* the action file gets copied in in place of this dollarsign */
+#line 498 "/usr1/local/share/bison.simple"
+
+ ffvsp -= fflen;
+ ffssp -= fflen;
+#ifdef FFLSP_NEEDED
+ fflsp -= fflen;
+#endif
+
+#if FFDEBUG != 0
+ if (ffdebug)
+ {
+ short *ssp1 = ffss - 1;
+ fprintf (stderr, "state stack now");
+ while (ssp1 != ffssp)
+ fprintf (stderr, " %d", *++ssp1);
+ fprintf (stderr, "\n");
+ }
+#endif
+
+ *++ffvsp = ffval;
+
+#ifdef FFLSP_NEEDED
+ fflsp++;
+ if (fflen == 0)
+ {
+ fflsp->first_line = fflloc.first_line;
+ fflsp->first_column = fflloc.first_column;
+ fflsp->last_line = (fflsp-1)->last_line;
+ fflsp->last_column = (fflsp-1)->last_column;
+ fflsp->text = 0;
+ }
+ else
+ {
+ fflsp->last_line = (fflsp+fflen-1)->last_line;
+ fflsp->last_column = (fflsp+fflen-1)->last_column;
+ }
+#endif
+
+ /* Now "shift" the result of the reduction.
+ Determine what state that goes to,
+ based on the state we popped back to
+ and the rule number reduced by. */
+
+ ffn = ffr1[ffn];
+
+ ffstate = ffpgoto[ffn - FFNTBASE] + *ffssp;
+ if (ffstate >= 0 && ffstate <= FFLAST && ffcheck[ffstate] == *ffssp)
+ ffstate = fftable[ffstate];
+ else
+ ffstate = ffdefgoto[ffn - FFNTBASE];
+
+ goto ffnewstate;
+
+fferrlab: /* here on detecting error */
+
+ if (! fferrstatus)
+ /* If not already recovering from an error, report this error. */
+ {
+ ++ffnerrs;
+
+#ifdef FFERROR_VERBOSE
+ ffn = ffpact[ffstate];
+
+ if (ffn > FFFLAG && ffn < FFLAST)
+ {
+ int size = 0;
+ char *msg;
+ int x, count;
+
+ count = 0;
+ /* Start X at -ffn if nec to avoid negative indexes in ffcheck. */
+ for (x = (ffn < 0 ? -ffn : 0);
+ x < (sizeof(fftname) / sizeof(char *)); x++)
+ if (ffcheck[x + ffn] == x)
+ size += strlen(fftname[x]) + 15, count++;
+ msg = (char *) malloc(size + 15);
+ if (msg != 0)
+ {
+ strcpy(msg, "parse error");
+
+ if (count < 5)
+ {
+ count = 0;
+ for (x = (ffn < 0 ? -ffn : 0);
+ x < (sizeof(fftname) / sizeof(char *)); x++)
+ if (ffcheck[x + ffn] == x)
+ {
+ strcat(msg, count == 0 ? ", expecting `" : " or `");
+ strcat(msg, fftname[x]);
+ strcat(msg, "'");
+ count++;
+ }
+ }
+ fferror(msg);
+ free(msg);
+ }
+ else
+ fferror ("parse error; also virtual memory exceeded");
+ }
+ else
+#endif /* FFERROR_VERBOSE */
+ fferror("parse error");
+ }
+
+ goto fferrlab1;
+fferrlab1: /* here on error raised explicitly by an action */
+
+ if (fferrstatus == 3)
+ {
+ /* if just tried and failed to reuse lookahead token after an error, discard it. */
+
+ /* return failure if at end of input */
+ if (ffchar == FFEOF)
+ FFABORT;
+
+#if FFDEBUG != 0
+ if (ffdebug)
+ fprintf(stderr, "Discarding token %d (%s).\n", ffchar, fftname[ffchar1]);
+#endif
+
+ ffchar = FFEMPTY;
+ }
+
+ /* Else will try to reuse lookahead token
+ after shifting the error token. */
+
+ fferrstatus = 3; /* Each real token shifted decrements this */
+
+ goto fferrhandle;
+
+fferrdefault: /* current state does not do anything special for the error token. */
+
+#if 0
+ /* This is wrong; only states that explicitly want error tokens
+ should shift them. */
+ ffn = ffdefact[ffstate]; /* If its default is to accept any token, ok. Otherwise pop it.*/
+ if (ffn) goto ffdefault;
+#endif
+
+fferrpop: /* pop the current state because it cannot handle the error token */
+
+ if (ffssp == ffss) FFABORT;
+ ffvsp--;
+ ffstate = *--ffssp;
+#ifdef FFLSP_NEEDED
+ fflsp--;
+#endif
+
+#if FFDEBUG != 0
+ if (ffdebug)
+ {
+ short *ssp1 = ffss - 1;
+ fprintf (stderr, "Error: state stack now");
+ while (ssp1 != ffssp)
+ fprintf (stderr, " %d", *++ssp1);
+ fprintf (stderr, "\n");
+ }
+#endif
+
+fferrhandle:
+
+ ffn = ffpact[ffstate];
+ if (ffn == FFFLAG)
+ goto fferrdefault;
+
+ ffn += FFTERROR;
+ if (ffn < 0 || ffn > FFLAST || ffcheck[ffn] != FFTERROR)
+ goto fferrdefault;
+
+ ffn = fftable[ffn];
+ if (ffn < 0)
+ {
+ if (ffn == FFFLAG)
+ goto fferrpop;
+ ffn = -ffn;
+ goto ffreduce;
+ }
+ else if (ffn == 0)
+ goto fferrpop;
+
+ if (ffn == FFFINAL)
+ FFACCEPT;
+
+#if FFDEBUG != 0
+ if (ffdebug)
+ fprintf(stderr, "Shifting error token, ");
+#endif
+
+ *++ffvsp = fflval;
+#ifdef FFLSP_NEEDED
+ *++fflsp = fflloc;
+#endif
+
+ ffstate = ffn;
+ goto ffnewstate;
+}
+#line 992 "eval.y"
+
+
+/*************************************************************************/
+/* Start of "New" routines which build the expression Nodal structure */
+/*************************************************************************/
+
+static int Alloc_Node( void )
+{
+ /* Use this for allocation to guarantee *Nodes */
+ Node *newNodePtr; /* survives on failure, making it still valid */
+ /* while working our way out of this error */
+
+ if( gParse.nNodes == gParse.nNodesAlloc ) {
+ if( gParse.Nodes ) {
+ gParse.nNodesAlloc += gParse.nNodesAlloc;
+ newNodePtr = (Node *)realloc( gParse.Nodes,
+ sizeof(Node)*gParse.nNodesAlloc );
+ } else {
+ gParse.nNodesAlloc = 100;
+ newNodePtr = (Node *)malloc ( sizeof(Node)*gParse.nNodesAlloc );
+ }
+
+ if( newNodePtr ) {
+ gParse.Nodes = newNodePtr;
+ } else {
+ gParse.status = MEMORY_ALLOCATION;
+ return( -1 );
+ }
+ }
+
+ return ( gParse.nNodes++ );
+}
+
+static void Free_Last_Node( void )
+{
+ if( gParse.nNodes ) gParse.nNodes--;
+}
+
+static int New_Const( int returnType, void *value, long len )
+{
+ Node *this;
+ int n;
+
+ n = Alloc_Node();
+ if( n>=0 ) {
+ this = gParse.Nodes + n;
+ this->operation = CONST_OP; /* Flag a constant */
+ this->DoOp = NULL;
+ this->nSubNodes = 0;
+ this->type = returnType;
+ memcpy( &(this->value.data), value, len );
+ this->value.undef = NULL;
+ this->value.nelem = 1;
+ this->value.naxis = 1;
+ this->value.naxes[0] = 1;
+ }
+ return(n);
+}
+
+static int New_Column( int ColNum )
+{
+ Node *this;
+ int n, i;
+
+ n = Alloc_Node();
+ if( n>=0 ) {
+ this = gParse.Nodes + n;
+ this->operation = -ColNum;
+ this->DoOp = NULL;
+ this->nSubNodes = 0;
+ this->type = gParse.varData[ColNum].type;
+ this->value.nelem = gParse.varData[ColNum].nelem;
+ this->value.naxis = gParse.varData[ColNum].naxis;
+ for( i=0; i<gParse.varData[ColNum].naxis; i++ )
+ this->value.naxes[i] = gParse.varData[ColNum].naxes[i];
+ }
+ return(n);
+}
+
+static int New_Offset( int ColNum, int offsetNode )
+{
+ Node *this;
+ int n, i, colNode;
+
+ colNode = New_Column( ColNum );
+ if( colNode<0 ) return(-1);
+
+ n = Alloc_Node();
+ if( n>=0 ) {
+ this = gParse.Nodes + n;
+ this->operation = '{';
+ this->DoOp = Do_Offset;
+ this->nSubNodes = 2;
+ this->SubNodes[0] = colNode;
+ this->SubNodes[1] = offsetNode;
+ this->type = gParse.varData[ColNum].type;
+ this->value.nelem = gParse.varData[ColNum].nelem;
+ this->value.naxis = gParse.varData[ColNum].naxis;
+ for( i=0; i<gParse.varData[ColNum].naxis; i++ )
+ this->value.naxes[i] = gParse.varData[ColNum].naxes[i];
+ }
+ return(n);
+}
+
+static int New_Unary( int returnType, int Op, int Node1 )
+{
+ Node *this, *that;
+ int i,n;
+
+ if( Node1<0 ) return(-1);
+ that = gParse.Nodes + Node1;
+
+ if( !Op ) Op = returnType;
+
+ if( (Op==DOUBLE || Op==FLTCAST) && that->type==DOUBLE ) return( Node1 );
+ if( (Op==LONG || Op==INTCAST) && that->type==LONG ) return( Node1 );
+ if( (Op==BOOLEAN ) && that->type==BOOLEAN ) return( Node1 );
+
+ n = Alloc_Node();
+ if( n>=0 ) {
+ this = gParse.Nodes + n;
+ this->operation = Op;
+ this->DoOp = Do_Unary;
+ this->nSubNodes = 1;
+ this->SubNodes[0] = Node1;
+ this->type = returnType;
+
+ that = gParse.Nodes + Node1; /* Reset in case .Nodes mv'd */
+ this->value.nelem = that->value.nelem;
+ this->value.naxis = that->value.naxis;
+ for( i=0; i<that->value.naxis; i++ )
+ this->value.naxes[i] = that->value.naxes[i];
+
+ if( that->operation==CONST_OP ) this->DoOp( this );
+ }
+ return( n );
+}
+
+static int New_BinOp( int returnType, int Node1, int Op, int Node2 )
+{
+ Node *this,*that1,*that2;
+ int n,i,constant;
+
+ if( Node1<0 || Node2<0 ) return(-1);
+
+ n = Alloc_Node();
+ if( n>=0 ) {
+ this = gParse.Nodes + n;
+ this->operation = Op;
+ this->nSubNodes = 2;
+ this->SubNodes[0]= Node1;
+ this->SubNodes[1]= Node2;
+ this->type = returnType;
+
+ that1 = gParse.Nodes + Node1;
+ that2 = gParse.Nodes + Node2;
+ constant = (that1->operation==CONST_OP
+ && that2->operation==CONST_OP);
+ if( that1->type!=STRING && that1->type!=BITSTR )
+ if( !Test_Dims( Node1, Node2 ) ) {
+ Free_Last_Node();
+ fferror("Array sizes/dims do not match for binary operator");
+ return(-1);
+ }
+ if( that1->value.nelem == 1 ) that1 = that2;
+
+ this->value.nelem = that1->value.nelem;
+ this->value.naxis = that1->value.naxis;
+ for( i=0; i<that1->value.naxis; i++ )
+ this->value.naxes[i] = that1->value.naxes[i];
+
+ if ( Op == ACCUM && that1->type == BITSTR ) {
+ /* ACCUM is rank-reducing on bit strings */
+ this->value.nelem = 1;
+ this->value.naxis = 1;
+ this->value.naxes[0] = 1;
+ }
+
+ /* Both subnodes should be of same time */
+ switch( that1->type ) {
+ case BITSTR: this->DoOp = Do_BinOp_bit; break;
+ case STRING: this->DoOp = Do_BinOp_str; break;
+ case BOOLEAN: this->DoOp = Do_BinOp_log; break;
+ case LONG: this->DoOp = Do_BinOp_lng; break;
+ case DOUBLE: this->DoOp = Do_BinOp_dbl; break;
+ }
+ if( constant ) this->DoOp( this );
+ }
+ return( n );
+}
+
+static int New_Func( int returnType, funcOp Op, int nNodes,
+ int Node1, int Node2, int Node3, int Node4,
+ int Node5, int Node6, int Node7 )
+/* If returnType==0 , use Node1's type and vector sizes as returnType, */
+/* else return a single value of type returnType */
+{
+ Node *this, *that;
+ int i,n,constant;
+
+ if( Node1<0 || Node2<0 || Node3<0 || Node4<0 ||
+ Node5<0 || Node6<0 || Node7<0 ) return(-1);
+
+ n = Alloc_Node();
+ if( n>=0 ) {
+ this = gParse.Nodes + n;
+ this->operation = (int)Op;
+ this->DoOp = Do_Func;
+ this->nSubNodes = nNodes;
+ this->SubNodes[0] = Node1;
+ this->SubNodes[1] = Node2;
+ this->SubNodes[2] = Node3;
+ this->SubNodes[3] = Node4;
+ this->SubNodes[4] = Node5;
+ this->SubNodes[5] = Node6;
+ this->SubNodes[6] = Node7;
+ i = constant = nNodes; /* Functions with zero params are not const */
+ while( i-- )
+ constant = ( constant &&
+ gParse.Nodes[ this->SubNodes[i] ].operation==CONST_OP );
+
+ if( returnType ) {
+ this->type = returnType;
+ this->value.nelem = 1;
+ this->value.naxis = 1;
+ this->value.naxes[0] = 1;
+ } else {
+ that = gParse.Nodes + Node1;
+ this->type = that->type;
+ this->value.nelem = that->value.nelem;
+ this->value.naxis = that->value.naxis;
+ for( i=0; i<that->value.naxis; i++ )
+ this->value.naxes[i] = that->value.naxes[i];
+ }
+ if( constant ) this->DoOp( this );
+ }
+ return( n );
+}
+
+static int New_Deref( int Var, int nDim,
+ int Dim1, int Dim2, int Dim3, int Dim4, int Dim5 )
+{
+ int n, idx, constant;
+ long elem=0;
+ Node *this, *theVar, *theDim[MAXDIMS];
+
+ if( Var<0 || Dim1<0 || Dim2<0 || Dim3<0 || Dim4<0 || Dim5<0 ) return(-1);
+
+ theVar = gParse.Nodes + Var;
+ if( theVar->operation==CONST_OP || theVar->value.nelem==1 ) {
+ fferror("Cannot index a scalar value");
+ return(-1);
+ }
+
+ n = Alloc_Node();
+ if( n>=0 ) {
+ this = gParse.Nodes + n;
+ this->nSubNodes = nDim+1;
+ theVar = gParse.Nodes + (this->SubNodes[0]=Var);
+ theDim[0] = gParse.Nodes + (this->SubNodes[1]=Dim1);
+ theDim[1] = gParse.Nodes + (this->SubNodes[2]=Dim2);
+ theDim[2] = gParse.Nodes + (this->SubNodes[3]=Dim3);
+ theDim[3] = gParse.Nodes + (this->SubNodes[4]=Dim4);
+ theDim[4] = gParse.Nodes + (this->SubNodes[5]=Dim5);
+ constant = theVar->operation==CONST_OP;
+ for( idx=0; idx<nDim; idx++ )
+ constant = (constant && theDim[idx]->operation==CONST_OP);
+
+ for( idx=0; idx<nDim; idx++ )
+ if( theDim[idx]->value.nelem>1 ) {
+ Free_Last_Node();
+ fferror("Cannot use an array as an index value");
+ return(-1);
+ } else if( theDim[idx]->type!=LONG ) {
+ Free_Last_Node();
+ fferror("Index value must be an integer type");
+ return(-1);
+ }
+
+ this->operation = '[';
+ this->DoOp = Do_Deref;
+ this->type = theVar->type;
+
+ if( theVar->value.naxis == nDim ) { /* All dimensions specified */
+ this->value.nelem = 1;
+ this->value.naxis = 1;
+ this->value.naxes[0] = 1;
+ } else if( nDim==1 ) { /* Dereference only one dimension */
+ elem=1;
+ this->value.naxis = theVar->value.naxis-1;
+ for( idx=0; idx<this->value.naxis; idx++ ) {
+ elem *= ( this->value.naxes[idx] = theVar->value.naxes[idx] );
+ }
+ this->value.nelem = elem;
+ } else {
+ Free_Last_Node();
+ fferror("Must specify just one or all indices for vector");
+ return(-1);
+ }
+ if( constant ) this->DoOp( this );
+ }
+ return(n);
+}
+
+extern int ffGetVariable( char *varName, FFSTYPE *varVal );
+
+static int New_GTI( char *fname, int Node1, char *start, char *stop )
+{
+ fitsfile *fptr;
+ Node *this, *that0, *that1;
+ int type,i,n, startCol, stopCol, Node0;
+ int hdutype, hdunum, evthdu, samefile, extvers, movetotype, tstat;
+ char extname[100];
+ long nrows;
+ double timeZeroI[2], timeZeroF[2], dt, timeSpan;
+ char xcol[20], xexpr[20];
+ FFSTYPE colVal;
+
+ if( Node1==-99 ) {
+ type = ffGetVariable( "TIME", &colVal );
+ if( type==COLUMN ) {
+ Node1 = New_Column( (int)colVal.lng );
+ } else {
+ fferror("Could not build TIME column for GTIFILTER");
+ return(-1);
+ }
+ }
+ Node1 = New_Unary( DOUBLE, 0, Node1 );
+ Node0 = Alloc_Node(); /* This will hold the START/STOP times */
+ if( Node1<0 || Node0<0 ) return(-1);
+
+ /* Record current HDU number in case we need to move within this file */
+
+ fptr = gParse.def_fptr;
+ ffghdn( fptr, &evthdu );
+
+ /* Look for TIMEZERO keywords in current extension */
+
+ tstat = 0;
+ if( ffgkyd( fptr, "TIMEZERO", timeZeroI, NULL, &tstat ) ) {
+ tstat = 0;
+ if( ffgkyd( fptr, "TIMEZERI", timeZeroI, NULL, &tstat ) ) {
+ timeZeroI[0] = timeZeroF[0] = 0.0;
+ } else if( ffgkyd( fptr, "TIMEZERF", timeZeroF, NULL, &tstat ) ) {
+ timeZeroF[0] = 0.0;
+ }
+ } else {
+ timeZeroF[0] = 0.0;
+ }
+
+ /* Resolve filename parameter */
+
+ switch( fname[0] ) {
+ case '\0':
+ samefile = 1;
+ hdunum = 1;
+ break;
+ case '[':
+ samefile = 1;
+ i = 1;
+ while( fname[i] != '\0' && fname[i] != ']' ) i++;
+ if( fname[i] ) {
+ fname[i] = '\0';
+ fname++;
+ ffexts( fname, &hdunum, extname, &extvers, &movetotype,
+ xcol, xexpr, &gParse.status );
+ if( *extname ) {
+ ffmnhd( fptr, movetotype, extname, extvers, &gParse.status );
+ ffghdn( fptr, &hdunum );
+ } else if( hdunum ) {
+ ffmahd( fptr, ++hdunum, &hdutype, &gParse.status );
+ } else if( !gParse.status ) {
+ fferror("Cannot use primary array for GTI filter");
+ return( -1 );
+ }
+ } else {
+ fferror("File extension specifier lacks closing ']'");
+ return( -1 );
+ }
+ break;
+ case '+':
+ samefile = 1;
+ hdunum = atoi( fname ) + 1;
+ if( hdunum>1 )
+ ffmahd( fptr, hdunum, &hdutype, &gParse.status );
+ else {
+ fferror("Cannot use primary array for GTI filter");
+ return( -1 );
+ }
+ break;
+ default:
+ samefile = 0;
+ if( ! ffopen( &fptr, fname, READONLY, &gParse.status ) )
+ ffghdn( fptr, &hdunum );
+ break;
+ }
+ if( gParse.status ) return(-1);
+
+ /* If at primary, search for GTI extension */
+
+ if( hdunum==1 ) {
+ while( 1 ) {
+ hdunum++;
+ if( ffmahd( fptr, hdunum, &hdutype, &gParse.status ) ) break;
+ if( hdutype==IMAGE_HDU ) continue;
+ tstat = 0;
+ if( ffgkys( fptr, "EXTNAME", extname, NULL, &tstat ) ) continue;
+ ffupch( extname );
+ if( strstr( extname, "GTI" ) ) break;
+ }
+ if( gParse.status ) {
+ if( gParse.status==END_OF_FILE )
+ fferror("GTI extension not found in this file");
+ return(-1);
+ }
+ }
+
+ /* Locate START/STOP Columns */
+
+ ffgcno( fptr, CASEINSEN, start, &startCol, &gParse.status );
+ ffgcno( fptr, CASEINSEN, stop, &stopCol, &gParse.status );
+ if( gParse.status ) return(-1);
+
+ /* Look for TIMEZERO keywords in GTI extension */
+
+ tstat = 0;
+ if( ffgkyd( fptr, "TIMEZERO", timeZeroI+1, NULL, &tstat ) ) {
+ tstat = 0;
+ if( ffgkyd( fptr, "TIMEZERI", timeZeroI+1, NULL, &tstat ) ) {
+ timeZeroI[1] = timeZeroF[1] = 0.0;
+ } else if( ffgkyd( fptr, "TIMEZERF", timeZeroF+1, NULL, &tstat ) ) {
+ timeZeroF[1] = 0.0;
+ }
+ } else {
+ timeZeroF[1] = 0.0;
+ }
+
+ n = Alloc_Node();
+ if( n >= 0 ) {
+ this = gParse.Nodes + n;
+ this->nSubNodes = 2;
+ this->SubNodes[1] = Node1;
+ this->operation = (int)gtifilt_fct;
+ this->DoOp = Do_GTI;
+ this->type = BOOLEAN;
+ that1 = gParse.Nodes + Node1;
+ this->value.nelem = that1->value.nelem;
+ this->value.naxis = that1->value.naxis;
+ for( i=0; i < that1->value.naxis; i++ )
+ this->value.naxes[i] = that1->value.naxes[i];
+
+ /* Init START/STOP node to be treated as a "constant" */
+
+ this->SubNodes[0] = Node0;
+ that0 = gParse.Nodes + Node0;
+ that0->operation = CONST_OP;
+ that0->DoOp = NULL;
+ that0->value.data.ptr= NULL;
+
+ /* Read in START/STOP times */
+
+ if( ffgkyj( fptr, "NAXIS2", &nrows, NULL, &gParse.status ) )
+ return(-1);
+ that0->value.nelem = nrows;
+ if( nrows ) {
+
+ that0->value.data.dblptr = (double*)malloc( 2*nrows*sizeof(double) );
+ if( !that0->value.data.dblptr ) {
+ gParse.status = MEMORY_ALLOCATION;
+ return(-1);
+ }
+
+ ffgcvd( fptr, startCol, 1L, 1L, nrows, 0.0,
+ that0->value.data.dblptr, &i, &gParse.status );
+ ffgcvd( fptr, stopCol, 1L, 1L, nrows, 0.0,
+ that0->value.data.dblptr+nrows, &i, &gParse.status );
+ if( gParse.status ) {
+ free( that0->value.data.dblptr );
+ return(-1);
+ }
+
+ /* Test for fully time-ordered GTI... both START && STOP */
+
+ that0->type = 1; /* Assume yes */
+ i = nrows;
+ while( --i )
+ if( that0->value.data.dblptr[i-1]
+ >= that0->value.data.dblptr[i]
+ || that0->value.data.dblptr[i-1+nrows]
+ >= that0->value.data.dblptr[i+nrows] ) {
+ that0->type = 0;
+ break;
+ }
+
+ /* Handle TIMEZERO offset, if any */
+
+ dt = (timeZeroI[1] - timeZeroI[0]) + (timeZeroF[1] - timeZeroF[0]);
+ timeSpan = that0->value.data.dblptr[nrows+nrows-1]
+ - that0->value.data.dblptr[0];
+
+ if( fabs( dt / timeSpan ) > 1e-12 ) {
+ for( i=0; i<(nrows+nrows); i++ )
+ that0->value.data.dblptr[i] += dt;
+ }
+ }
+ if( gParse.Nodes[Node1].operation==CONST_OP )
+ this->DoOp( this );
+ }
+
+ if( samefile )
+ ffmahd( fptr, evthdu, &hdutype, &gParse.status );
+ else
+ ffclos( fptr, &gParse.status );
+
+ return( n );
+}
+
+static int New_REG( char *fname, int NodeX, int NodeY, char *colNames )
+{
+ Node *this, *that0;
+ int type, n, Node0;
+ int Xcol, Ycol, tstat;
+ WCSdata wcs;
+ SAORegion *Rgn;
+ char *cX, *cY;
+ FFSTYPE colVal;
+
+ if( NodeX==-99 ) {
+ type = ffGetVariable( "X", &colVal );
+ if( type==COLUMN ) {
+ NodeX = New_Column( (int)colVal.lng );
+ } else {
+ fferror("Could not build X column for REGFILTER");
+ return(-1);
+ }
+ }
+ if( NodeY==-99 ) {
+ type = ffGetVariable( "Y", &colVal );
+ if( type==COLUMN ) {
+ NodeY = New_Column( (int)colVal.lng );
+ } else {
+ fferror("Could not build Y column for REGFILTER");
+ return(-1);
+ }
+ }
+ NodeX = New_Unary( DOUBLE, 0, NodeX );
+ NodeY = New_Unary( DOUBLE, 0, NodeY );
+ Node0 = Alloc_Node(); /* This will hold the Region Data */
+ if( NodeX<0 || NodeY<0 || Node0<0 ) return(-1);
+
+ n = Alloc_Node();
+ if( n >= 0 ) {
+ this = gParse.Nodes + n;
+ this->nSubNodes = 3;
+ this->SubNodes[0] = Node0;
+ this->SubNodes[1] = NodeX;
+ this->SubNodes[2] = NodeY;
+ this->operation = (int)regfilt_fct;
+ this->DoOp = Do_REG;
+ this->type = BOOLEAN;
+ this->value.nelem = 1;
+ this->value.naxis = 1;
+ this->value.naxes[0] = 1;
+
+ /* Init Region node to be treated as a "constant" */
+
+ that0 = gParse.Nodes + Node0;
+ that0->operation = CONST_OP;
+ that0->DoOp = NULL;
+
+ /* Identify what columns to use for WCS information */
+
+ Xcol = Ycol = 0;
+ if( *colNames ) {
+ /* Use the column names in this string for WCS info */
+ while( *colNames==' ' ) colNames++;
+ cX = cY = colNames;
+ while( *cY && *cY!=' ' && *cY!=',' ) cY++;
+ if( *cY )
+ *(cY++) = '\0';
+ while( *cY==' ' ) cY++;
+ if( !*cY ) {
+ fferror("Could not extract valid pair of column names from REGFILTER");
+ Free_Last_Node();
+ return( -1 );
+ }
+ fits_get_colnum( gParse.def_fptr, CASEINSEN, cX, &Xcol,
+ &gParse.status );
+ fits_get_colnum( gParse.def_fptr, CASEINSEN, cY, &Ycol,
+ &gParse.status );
+ if( gParse.status ) {
+ fferror("Could not locate columns indicated for WCS info");
+ Free_Last_Node();
+ return( -1 );
+ }
+
+ } else {
+ /* Try to find columns used in X/Y expressions */
+ Xcol = Locate_Col( gParse.Nodes + NodeX );
+ Ycol = Locate_Col( gParse.Nodes + NodeY );
+ if( Xcol<0 || Ycol<0 ) {
+ fferror("Found multiple X/Y column references in REGFILTER");
+ Free_Last_Node();
+ return( -1 );
+ }
+ }
+
+ /* Now, get the WCS info, if it exists, from the indicated columns */
+ wcs.exists = 0;
+ if( Xcol>0 && Ycol>0 ) {
+ tstat = 0;
+ ffgtcs( gParse.def_fptr, Xcol, Ycol,
+ &wcs.xrefval, &wcs.yrefval,
+ &wcs.xrefpix, &wcs.yrefpix,
+ &wcs.xinc, &wcs.yinc,
+ &wcs.rot, wcs.type,
+ &tstat );
+ if( tstat==NO_WCS_KEY ) {
+ wcs.exists = 0;
+ } else if( tstat ) {
+ gParse.status = tstat;
+ Free_Last_Node();
+ return( -1 );
+ } else {
+ wcs.exists = 1;
+ }
+ }
+
+ /* Read in Region file */
+
+ fits_read_rgnfile( fname, &wcs, &Rgn, &gParse.status );
+ if( gParse.status ) {
+ Free_Last_Node();
+ return( -1 );
+ }
+
+ that0->value.data.ptr = Rgn;
+
+ if( gParse.Nodes[NodeX].operation==CONST_OP
+ && gParse.Nodes[NodeY].operation==CONST_OP )
+ this->DoOp( this );
+ }
+
+ return( n );
+}
+
+static int New_Vector( int subNode )
+{
+ Node *this, *that;
+ int n;
+
+ n = Alloc_Node();
+ if( n >= 0 ) {
+ this = gParse.Nodes + n;
+ that = gParse.Nodes + subNode;
+ this->type = that->type;
+ this->nSubNodes = 1;
+ this->SubNodes[0] = subNode;
+ this->operation = '{';
+ this->DoOp = Do_Vector;
+ }
+
+ return( n );
+}
+
+static int Close_Vec( int vecNode )
+{
+ Node *this;
+ int n, nelem=0;
+
+ this = gParse.Nodes + vecNode;
+ for( n=0; n < this->nSubNodes; n++ ) {
+ if( TYPE( this->SubNodes[n] ) != this->type ) {
+ this->SubNodes[n] = New_Unary( this->type, 0, this->SubNodes[n] );
+ if( this->SubNodes[n]<0 ) return(-1);
+ }
+ nelem += SIZE(this->SubNodes[n]);
+ }
+ this->value.naxis = 1;
+ this->value.nelem = nelem;
+ this->value.naxes[0] = nelem;
+
+ return( vecNode );
+}
+
+static int Locate_Col( Node *this )
+/* Locate the TABLE column number of any columns in "this" calculation. */
+/* Return ZERO if none found, or negative if more than 1 found. */
+{
+ Node *that;
+ int i, col=0, newCol, nfound=0;
+
+ if( this->nSubNodes==0
+ && this->operation<=0 && this->operation!=CONST_OP )
+ return gParse.colData[ - this->operation].colnum;
+
+ for( i=0; i<this->nSubNodes; i++ ) {
+ that = gParse.Nodes + this->SubNodes[i];
+ if( that->operation>0 ) {
+ newCol = Locate_Col( that );
+ if( newCol<=0 ) {
+ nfound += -newCol;
+ } else {
+ if( !nfound ) {
+ col = newCol;
+ nfound++;
+ } else if( col != newCol ) {
+ nfound++;
+ }
+ }
+ } else if( that->operation!=CONST_OP ) {
+ /* Found a Column */
+ newCol = gParse.colData[- that->operation].colnum;
+ if( !nfound ) {
+ col = newCol;
+ nfound++;
+ } else if( col != newCol ) {
+ nfound++;
+ }
+ }
+ }
+ if( nfound!=1 )
+ return( - nfound );
+ else
+ return( col );
+}
+
+static int Test_Dims( int Node1, int Node2 )
+{
+ Node *that1, *that2;
+ int valid, i;
+
+ if( Node1<0 || Node2<0 ) return(0);
+
+ that1 = gParse.Nodes + Node1;
+ that2 = gParse.Nodes + Node2;
+
+ if( that1->value.nelem==1 || that2->value.nelem==1 )
+ valid = 1;
+ else if( that1->type==that2->type
+ && that1->value.nelem==that2->value.nelem
+ && that1->value.naxis==that2->value.naxis ) {
+ valid = 1;
+ for( i=0; i<that1->value.naxis; i++ ) {
+ if( that1->value.naxes[i]!=that2->value.naxes[i] )
+ valid = 0;
+ }
+ } else
+ valid = 0;
+ return( valid );
+}
+
+static void Copy_Dims( int Node1, int Node2 )
+{
+ Node *that1, *that2;
+ int i;
+
+ if( Node1<0 || Node2<0 ) return;
+
+ that1 = gParse.Nodes + Node1;
+ that2 = gParse.Nodes + Node2;
+
+ that1->value.nelem = that2->value.nelem;
+ that1->value.naxis = that2->value.naxis;
+ for( i=0; i<that2->value.naxis; i++ )
+ that1->value.naxes[i] = that2->value.naxes[i];
+}
+
+/********************************************************************/
+/* Routines for actually evaluating the expression start here */
+/********************************************************************/
+
+void Evaluate_Parser( long firstRow, long nRows )
+ /***********************************************************************/
+ /* Reset the parser for processing another batch of data... */
+ /* firstRow: Row number of the first element to evaluate */
+ /* nRows: Number of rows to be processed */
+ /* Initialize each COLUMN node so that its UNDEF and DATA pointers */
+ /* point to the appropriate column arrays. */
+ /* Finally, call Evaluate_Node for final node. */
+ /***********************************************************************/
+{
+ int i, column;
+ long offset, rowOffset;
+
+ gParse.firstRow = firstRow;
+ gParse.nRows = nRows;
+
+ /* Reset Column Nodes' pointers to point to right data and UNDEF arrays */
+
+ rowOffset = firstRow - gParse.firstDataRow;
+ for( i=0; i<gParse.nNodes; i++ ) {
+ if( gParse.Nodes[i].operation > 0
+ || gParse.Nodes[i].operation == CONST_OP ) continue;
+
+ column = -gParse.Nodes[i].operation;
+ offset = gParse.varData[column].nelem * rowOffset;
+
+ gParse.Nodes[i].value.undef = gParse.varData[column].undef + offset;
+
+ switch( gParse.Nodes[i].type ) {
+ case BITSTR:
+ gParse.Nodes[i].value.data.strptr =
+ (char**)gParse.varData[column].data + rowOffset;
+ gParse.Nodes[i].value.undef = NULL;
+ break;
+ case STRING:
+ gParse.Nodes[i].value.data.strptr =
+ (char**)gParse.varData[column].data + rowOffset;
+ gParse.Nodes[i].value.undef = gParse.varData[column].undef + rowOffset;
+ break;
+ case BOOLEAN:
+ gParse.Nodes[i].value.data.logptr =
+ (char*)gParse.varData[column].data + offset;
+ break;
+ case LONG:
+ gParse.Nodes[i].value.data.lngptr =
+ (long*)gParse.varData[column].data + offset;
+ break;
+ case DOUBLE:
+ gParse.Nodes[i].value.data.dblptr =
+ (double*)gParse.varData[column].data + offset;
+ break;
+ }
+ }
+
+ Evaluate_Node( gParse.resultNode );
+}
+
+static void Evaluate_Node( int thisNode )
+ /**********************************************************************/
+ /* Recursively evaluate thisNode's subNodes, then call one of the */
+ /* Do_<Action> functions pointed to by thisNode's DoOp element. */
+ /**********************************************************************/
+{
+ Node *this;
+ int i;
+
+ if( gParse.status ) return;
+
+ this = gParse.Nodes + thisNode;
+ if( this->operation>0 ) { /* <=0 indicate constants and columns */
+ i = this->nSubNodes;
+ while( i-- ) {
+ Evaluate_Node( this->SubNodes[i] );
+ if( gParse.status ) return;
+ }
+ this->DoOp( this );
+ }
+}
+
+static void Allocate_Ptrs( Node *this )
+{
+ long elem, row, size;
+
+ if( this->type==BITSTR || this->type==STRING ) {
+
+ this->value.data.strptr = (char**)malloc( gParse.nRows
+ * sizeof(char*) );
+ if( this->value.data.strptr ) {
+ this->value.data.strptr[0] = (char*)malloc( gParse.nRows
+ * (this->value.nelem+2)
+ * sizeof(char) );
+ if( this->value.data.strptr[0] ) {
+ row = 0;
+ while( (++row)<gParse.nRows ) {
+ this->value.data.strptr[row] =
+ this->value.data.strptr[row-1] + this->value.nelem+1;
+ }
+ if( this->type==STRING ) {
+ this->value.undef = this->value.data.strptr[row-1]
+ + this->value.nelem+1;
+ } else {
+ this->value.undef = NULL; /* BITSTRs don't use undef array */
+ }
+ } else {
+ gParse.status = MEMORY_ALLOCATION;
+ free( this->value.data.strptr );
+ }
+ } else {
+ gParse.status = MEMORY_ALLOCATION;
+ }
+
+ } else {
+
+ elem = this->value.nelem * gParse.nRows;
+ switch( this->type ) {
+ case DOUBLE: size = sizeof( double ); break;
+ case LONG: size = sizeof( long ); break;
+ case BOOLEAN: size = sizeof( char ); break;
+ default: size = 1; break;
+ }
+
+ this->value.data.ptr = malloc( elem*(size+1) );
+
+ if( this->value.data.ptr==NULL ) {
+ gParse.status = MEMORY_ALLOCATION;
+ } else {
+ this->value.undef = (char *)this->value.data.ptr + elem*size;
+ }
+ }
+}
+
+static void Do_Unary( Node *this )
+{
+ Node *that;
+ long elem;
+
+ that = gParse.Nodes + this->SubNodes[0];
+
+ if( that->operation==CONST_OP ) { /* Operating on a constant! */
+ switch( this->operation ) {
+ case DOUBLE:
+ case FLTCAST:
+ if( that->type==LONG )
+ this->value.data.dbl = (double)that->value.data.lng;
+ else if( that->type==BOOLEAN )
+ this->value.data.dbl = ( that->value.data.log ? 1.0 : 0.0 );
+ break;
+ case LONG:
+ case INTCAST:
+ if( that->type==DOUBLE )
+ this->value.data.lng = (long)that->value.data.dbl;
+ else if( that->type==BOOLEAN )
+ this->value.data.lng = ( that->value.data.log ? 1L : 0L );
+ break;
+ case BOOLEAN:
+ if( that->type==DOUBLE )
+ this->value.data.log = ( that->value.data.dbl != 0.0 );
+ else if( that->type==LONG )
+ this->value.data.log = ( that->value.data.lng != 0L );
+ break;
+ case UMINUS:
+ if( that->type==DOUBLE )
+ this->value.data.dbl = - that->value.data.dbl;
+ else if( that->type==LONG )
+ this->value.data.lng = - that->value.data.lng;
+ break;
+ case NOT:
+ if( that->type==BOOLEAN )
+ this->value.data.log = ( ! that->value.data.log );
+ else if( that->type==BITSTR )
+ bitnot( this->value.data.str, that->value.data.str );
+ break;
+ }
+ this->operation = CONST_OP;
+
+ } else {
+
+ Allocate_Ptrs( this );
+
+ if( !gParse.status ) {
+
+ if( this->type!=BITSTR ) {
+ elem = gParse.nRows;
+ if( this->type!=STRING )
+ elem *= this->value.nelem;
+ while( elem-- )
+ this->value.undef[elem] = that->value.undef[elem];
+ }
+
+ elem = gParse.nRows * this->value.nelem;
+
+ switch( this->operation ) {
+
+ case BOOLEAN:
+ if( that->type==DOUBLE )
+ while( elem-- )
+ this->value.data.logptr[elem] =
+ ( that->value.data.dblptr[elem] != 0.0 );
+ else if( that->type==LONG )
+ while( elem-- )
+ this->value.data.logptr[elem] =
+ ( that->value.data.lngptr[elem] != 0L );
+ break;
+
+ case DOUBLE:
+ case FLTCAST:
+ if( that->type==LONG )
+ while( elem-- )
+ this->value.data.dblptr[elem] =
+ (double)that->value.data.lngptr[elem];
+ else if( that->type==BOOLEAN )
+ while( elem-- )
+ this->value.data.dblptr[elem] =
+ ( that->value.data.logptr[elem] ? 1.0 : 0.0 );
+ break;
+
+ case LONG:
+ case INTCAST:
+ if( that->type==DOUBLE )
+ while( elem-- )
+ this->value.data.lngptr[elem] =
+ (long)that->value.data.dblptr[elem];
+ else if( that->type==BOOLEAN )
+ while( elem-- )
+ this->value.data.lngptr[elem] =
+ ( that->value.data.logptr[elem] ? 1L : 0L );
+ break;
+
+ case UMINUS:
+ if( that->type==DOUBLE ) {
+ while( elem-- )
+ this->value.data.dblptr[elem] =
+ - that->value.data.dblptr[elem];
+ } else if( that->type==LONG ) {
+ while( elem-- )
+ this->value.data.lngptr[elem] =
+ - that->value.data.lngptr[elem];
+ }
+ break;
+
+ case NOT:
+ if( that->type==BOOLEAN ) {
+ while( elem-- )
+ this->value.data.logptr[elem] =
+ ( ! that->value.data.logptr[elem] );
+ } else if( that->type==BITSTR ) {
+ elem = gParse.nRows;
+ while( elem-- )
+ bitnot( this->value.data.strptr[elem],
+ that->value.data.strptr[elem] );
+ }
+ break;
+ }
+ }
+ }
+
+ if( that->operation>0 ) {
+ free( that->value.data.ptr );
+ }
+}
+
+static void Do_Offset( Node *this )
+{
+ Node *col;
+ long fRow, nRowOverlap, nRowReload, rowOffset;
+ long nelem, elem, offset, nRealElem;
+ int status;
+
+ col = gParse.Nodes + this->SubNodes[0];
+ rowOffset = gParse.Nodes[ this->SubNodes[1] ].value.data.lng;
+
+ Allocate_Ptrs( this );
+
+ fRow = gParse.firstRow + rowOffset;
+ if( this->type==STRING || this->type==BITSTR )
+ nRealElem = 1;
+ else
+ nRealElem = this->value.nelem;
+
+ nelem = nRealElem;
+
+ if( fRow < gParse.firstDataRow ) {
+
+ /* Must fill in data at start of array */
+
+ nRowReload = gParse.firstDataRow - fRow;
+ if( nRowReload > gParse.nRows ) nRowReload = gParse.nRows;
+ nRowOverlap = gParse.nRows - nRowReload;
+
+ offset = 0;
+
+ /* NULLify any values falling out of bounds */
+
+ while( fRow<1 && nRowReload>0 ) {
+ if( this->type == BITSTR ) {
+ nelem = this->value.nelem;
+ this->value.data.strptr[offset][ nelem ] = '\0';
+ while( nelem-- ) this->value.data.strptr[offset][nelem] = '0';
+ offset++;
+ } else {
+ while( nelem-- )
+ this->value.undef[offset++] = 1;
+ }
+ nelem = nRealElem;
+ fRow++;
+ nRowReload--;
+ }
+
+ } else if( fRow + gParse.nRows > gParse.firstDataRow + gParse.nDataRows ) {
+
+ /* Must fill in data at end of array */
+
+ nRowReload = (fRow+gParse.nRows) - (gParse.firstDataRow+gParse.nDataRows);
+ if( nRowReload>gParse.nRows ) {
+ nRowReload = gParse.nRows;
+ } else {
+ fRow = gParse.firstDataRow + gParse.nDataRows;
+ }
+ nRowOverlap = gParse.nRows - nRowReload;
+
+ offset = nRowOverlap * nelem;
+
+ /* NULLify any values falling out of bounds */
+
+ elem = gParse.nRows * nelem;
+ while( fRow+nRowReload>gParse.totalRows && nRowReload>0 ) {
+ if( this->type == BITSTR ) {
+ nelem = this->value.nelem;
+ elem--;
+ this->value.data.strptr[elem][ nelem ] = '\0';
+ while( nelem-- ) this->value.data.strptr[elem][nelem] = '0';
+ } else {
+ while( nelem-- )
+ this->value.undef[--elem] = 1;
+ }
+ nelem = nRealElem;
+ nRowReload--;
+ }
+
+ } else {
+
+ nRowReload = 0;
+ nRowOverlap = gParse.nRows;
+ offset = 0;
+
+ }
+
+ if( nRowReload>0 ) {
+ switch( this->type ) {
+ case BITSTR:
+ case STRING:
+ status = (*gParse.loadData)( -col->operation, fRow, nRowReload,
+ this->value.data.strptr+offset,
+ this->value.undef+offset );
+ break;
+ case BOOLEAN:
+ status = (*gParse.loadData)( -col->operation, fRow, nRowReload,
+ this->value.data.logptr+offset,
+ this->value.undef+offset );
+ break;
+ case LONG:
+ status = (*gParse.loadData)( -col->operation, fRow, nRowReload,
+ this->value.data.lngptr+offset,
+ this->value.undef+offset );
+ break;
+ case DOUBLE:
+ status = (*gParse.loadData)( -col->operation, fRow, nRowReload,
+ this->value.data.dblptr+offset,
+ this->value.undef+offset );
+ break;
+ }
+ }
+
+ /* Now copy over the overlapping region, if any */
+
+ if( nRowOverlap <= 0 ) return;
+
+ if( rowOffset>0 )
+ elem = nRowOverlap * nelem;
+ else
+ elem = gParse.nRows * nelem;
+
+ offset = nelem * rowOffset;
+ while( nRowOverlap-- && !gParse.status ) {
+ while( nelem-- && !gParse.status ) {
+ elem--;
+ if( this->type != BITSTR )
+ this->value.undef[elem] = col->value.undef[elem+offset];
+ switch( this->type ) {
+ case BITSTR:
+ strcpy( this->value.data.strptr[elem ],
+ col->value.data.strptr[elem+offset] );
+ break;
+ case STRING:
+ strcpy( this->value.data.strptr[elem ],
+ col->value.data.strptr[elem+offset] );
+ break;
+ case BOOLEAN:
+ this->value.data.logptr[elem] = col->value.data.logptr[elem+offset];
+ break;
+ case LONG:
+ this->value.data.lngptr[elem] = col->value.data.lngptr[elem+offset];
+ break;
+ case DOUBLE:
+ this->value.data.dblptr[elem] = col->value.data.dblptr[elem+offset];
+ break;
+ }
+ }
+ nelem = nRealElem;
+ }
+}
+
+static void Do_BinOp_bit( Node *this )
+{
+ Node *that1, *that2;
+ char *sptr1=NULL, *sptr2=NULL;
+ int const1, const2;
+ long rows;
+
+ that1 = gParse.Nodes + this->SubNodes[0];
+ that2 = gParse.Nodes + this->SubNodes[1];
+
+ const1 = ( that1->operation==CONST_OP );
+ const2 = ( that2->operation==CONST_OP );
+ sptr1 = ( const1 ? that1->value.data.str : NULL );
+ sptr2 = ( const2 ? that2->value.data.str : NULL );
+
+ if( const1 && const2 ) {
+ switch( this->operation ) {
+ case NE:
+ this->value.data.log = !bitcmp( sptr1, sptr2 );
+ break;
+ case EQ:
+ this->value.data.log = bitcmp( sptr1, sptr2 );
+ break;
+ case GT:
+ case LT:
+ case LTE:
+ case GTE:
+ this->value.data.log = bitlgte( sptr1, this->operation, sptr2 );
+ break;
+ case '|':
+ bitor( this->value.data.str, sptr1, sptr2 );
+ break;
+ case '&':
+ bitand( this->value.data.str, sptr1, sptr2 );
+ break;
+ case '+':
+ strcpy( this->value.data.str, sptr1 );
+ strcat( this->value.data.str, sptr2 );
+ break;
+ case ACCUM:
+ this->value.data.lng = 0;
+ while( *sptr1 ) {
+ if ( *sptr1 == '1' ) this->value.data.lng ++;
+ sptr1 ++;
+ }
+ break;
+
+ }
+ this->operation = CONST_OP;
+
+ } else {
+
+ Allocate_Ptrs( this );
+
+ if( !gParse.status ) {
+ rows = gParse.nRows;
+ switch( this->operation ) {
+
+ /* BITSTR comparisons */
+
+ case NE:
+ case EQ:
+ case GT:
+ case LT:
+ case LTE:
+ case GTE:
+ while( rows-- ) {
+ if( !const1 )
+ sptr1 = that1->value.data.strptr[rows];
+ if( !const2 )
+ sptr2 = that2->value.data.strptr[rows];
+ switch( this->operation ) {
+ case NE: this->value.data.logptr[rows] =
+ !bitcmp( sptr1, sptr2 );
+ break;
+ case EQ: this->value.data.logptr[rows] =
+ bitcmp( sptr1, sptr2 );
+ break;
+ case GT:
+ case LT:
+ case LTE:
+ case GTE: this->value.data.logptr[rows] =
+ bitlgte( sptr1, this->operation, sptr2 );
+ break;
+ }
+ this->value.undef[rows] = 0;
+ }
+ break;
+
+ /* BITSTR AND/ORs ... no UNDEFS in or out */
+
+ case '|':
+ case '&':
+ case '+':
+ while( rows-- ) {
+ if( !const1 )
+ sptr1 = that1->value.data.strptr[rows];
+ if( !const2 )
+ sptr2 = that2->value.data.strptr[rows];
+ if( this->operation=='|' )
+ bitor( this->value.data.strptr[rows], sptr1, sptr2 );
+ else if( this->operation=='&' )
+ bitand( this->value.data.strptr[rows], sptr1, sptr2 );
+ else {
+ strcpy( this->value.data.strptr[rows], sptr1 );
+ strcat( this->value.data.strptr[rows], sptr2 );
+ }
+ }
+ break;
+
+ /* Accumulate 1 bits */
+ case ACCUM:
+ {
+ long i, previous, curr;
+
+ previous = that2->value.data.lng;
+
+ /* Cumulative sum of this chunk */
+ for (i=0; i<rows; i++) {
+ sptr1 = that1->value.data.strptr[i];
+ for (curr = 0; *sptr1; sptr1 ++) {
+ if ( *sptr1 == '1' ) curr ++;
+ }
+ previous += curr;
+ this->value.data.lngptr[i] = previous;
+ this->value.undef[i] = 0;
+ }
+
+ /* Store final cumulant for next pass */
+ that2->value.data.lng = previous;
+ }
+ }
+ }
+ }
+
+ if( that1->operation>0 ) {
+ free( that1->value.data.strptr[0] );
+ free( that1->value.data.strptr );
+ }
+ if( that2->operation>0 ) {
+ free( that2->value.data.strptr[0] );
+ free( that2->value.data.strptr );
+ }
+}
+
+static void Do_BinOp_str( Node *this )
+{
+ Node *that1, *that2;
+ char *sptr1, *sptr2, null1=0, null2=0;
+ int const1, const2, val;
+ long rows;
+
+ that1 = gParse.Nodes + this->SubNodes[0];
+ that2 = gParse.Nodes + this->SubNodes[1];
+
+ const1 = ( that1->operation==CONST_OP );
+ const2 = ( that2->operation==CONST_OP );
+ sptr1 = ( const1 ? that1->value.data.str : NULL );
+ sptr2 = ( const2 ? that2->value.data.str : NULL );
+
+ if( const1 && const2 ) { /* Result is a constant */
+ switch( this->operation ) {
+
+ /* Compare Strings */
+
+ case NE:
+ case EQ:
+ val = ( FSTRCMP( sptr1, sptr2 ) == 0 );
+ this->value.data.log = ( this->operation==EQ ? val : !val );
+ break;
+ case GT:
+ this->value.data.log = ( FSTRCMP( sptr1, sptr2 ) > 0 );
+ break;
+ case LT:
+ this->value.data.log = ( FSTRCMP( sptr1, sptr2 ) < 0 );
+ break;
+ case GTE:
+ this->value.data.log = ( FSTRCMP( sptr1, sptr2 ) >= 0 );
+ break;
+ case LTE:
+ this->value.data.log = ( FSTRCMP( sptr1, sptr2 ) <= 0 );
+ break;
+
+ /* Concat Strings */
+
+ case '+':
+ strcpy( this->value.data.str, sptr1 );
+ strcat( this->value.data.str, sptr2 );
+ break;
+ }
+ this->operation = CONST_OP;
+
+ } else { /* Not a constant */
+
+ Allocate_Ptrs( this );
+
+ if( !gParse.status ) {
+
+ rows = gParse.nRows;
+ switch( this->operation ) {
+
+ /* Compare Strings */
+
+ case NE:
+ case EQ:
+ while( rows-- ) {
+ if( !const1 ) null1 = that1->value.undef[rows];
+ if( !const2 ) null2 = that2->value.undef[rows];
+ this->value.undef[rows] = (null1 || null2);
+ if( ! this->value.undef[rows] ) {
+ if( !const1 ) sptr1 = that1->value.data.strptr[rows];
+ if( !const2 ) sptr2 = that2->value.data.strptr[rows];
+ val = ( FSTRCMP( sptr1, sptr2 ) == 0 );
+ this->value.data.logptr[rows] =
+ ( this->operation==EQ ? val : !val );
+ }
+ }
+ break;
+
+ case GT:
+ case LT:
+ while( rows-- ) {
+ if( !const1 ) null1 = that1->value.undef[rows];
+ if( !const2 ) null2 = that2->value.undef[rows];
+ this->value.undef[rows] = (null1 || null2);
+ if( ! this->value.undef[rows] ) {
+ if( !const1 ) sptr1 = that1->value.data.strptr[rows];
+ if( !const2 ) sptr2 = that2->value.data.strptr[rows];
+ val = ( FSTRCMP( sptr1, sptr2 ) );
+ this->value.data.logptr[rows] =
+ ( this->operation==GT ? val>0 : val<0 );
+ }
+ }
+ break;
+
+ case GTE:
+ case LTE:
+ while( rows-- ) {
+ if( !const1 ) null1 = that1->value.undef[rows];
+ if( !const2 ) null2 = that2->value.undef[rows];
+ this->value.undef[rows] = (null1 || null2);
+ if( ! this->value.undef[rows] ) {
+ if( !const1 ) sptr1 = that1->value.data.strptr[rows];
+ if( !const2 ) sptr2 = that2->value.data.strptr[rows];
+ val = ( FSTRCMP( sptr1, sptr2 ) );
+ this->value.data.logptr[rows] =
+ ( this->operation==GTE ? val>=0 : val<=0 );
+ }
+ }
+ break;
+
+ /* Concat Strings */
+
+ case '+':
+ while( rows-- ) {
+ if( !const1 ) null1 = that1->value.undef[rows];
+ if( !const2 ) null2 = that2->value.undef[rows];
+ this->value.undef[rows] = (null1 || null2);
+ if( ! this->value.undef[rows] ) {
+ if( !const1 ) sptr1 = that1->value.data.strptr[rows];
+ if( !const2 ) sptr2 = that2->value.data.strptr[rows];
+ strcpy( this->value.data.strptr[rows], sptr1 );
+ strcat( this->value.data.strptr[rows], sptr2 );
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ if( that1->operation>0 ) {
+ free( that1->value.data.strptr[0] );
+ free( that1->value.data.strptr );
+ }
+ if( that2->operation>0 ) {
+ free( that2->value.data.strptr[0] );
+ free( that2->value.data.strptr );
+ }
+}
+
+static void Do_BinOp_log( Node *this )
+{
+ Node *that1, *that2;
+ int vector1, vector2;
+ char val1=0, val2=0, null1=0, null2=0;
+ long rows, nelem, elem;
+
+ that1 = gParse.Nodes + this->SubNodes[0];
+ that2 = gParse.Nodes + this->SubNodes[1];
+
+ vector1 = ( that1->operation!=CONST_OP );
+ if( vector1 )
+ vector1 = that1->value.nelem;
+ else {
+ val1 = that1->value.data.log;
+ }
+
+ vector2 = ( that2->operation!=CONST_OP );
+ if( vector2 )
+ vector2 = that2->value.nelem;
+ else {
+ val2 = that2->value.data.log;
+ }
+
+ if( !vector1 && !vector2 ) { /* Result is a constant */
+ switch( this->operation ) {
+ case OR:
+ this->value.data.log = (val1 || val2);
+ break;
+ case AND:
+ this->value.data.log = (val1 && val2);
+ break;
+ case EQ:
+ this->value.data.log = ( (val1 && val2) || (!val1 && !val2) );
+ break;
+ case NE:
+ this->value.data.log = ( (val1 && !val2) || (!val1 && val2) );
+ break;
+ case ACCUM:
+ this->value.data.lng = val1;
+ break;
+ }
+ this->operation=CONST_OP;
+ } else if (this->operation == ACCUM) {
+ long i, previous, curr;
+ rows = gParse.nRows;
+ nelem = this->value.nelem;
+ elem = this->value.nelem * rows;
+
+ Allocate_Ptrs( this );
+
+ if( !gParse.status ) {
+ previous = that2->value.data.lng;
+
+ /* Cumulative sum of this chunk */
+ for (i=0; i<elem; i++) {
+ if (!that1->value.undef[i]) {
+ curr = that1->value.data.logptr[i];
+ previous += curr;
+ }
+ this->value.data.lngptr[i] = previous;
+ this->value.undef[i] = 0;
+ }
+
+ /* Store final cumulant for next pass */
+ that2->value.data.lng = previous;
+ }
+
+ } else {
+ rows = gParse.nRows;
+ nelem = this->value.nelem;
+ elem = this->value.nelem * rows;
+
+ Allocate_Ptrs( this );
+
+ if( !gParse.status ) {
+
+ if (this->operation == ACCUM) {
+ long i, previous, curr;
+
+ previous = that2->value.data.lng;
+
+ /* Cumulative sum of this chunk */
+ for (i=0; i<elem; i++) {
+ if (!that1->value.undef[i]) {
+ curr = that1->value.data.logptr[i];
+ previous += curr;
+ }
+ this->value.data.lngptr[i] = previous;
+ this->value.undef[i] = 0;
+ }
+
+ /* Store final cumulant for next pass */
+ that2->value.data.lng = previous;
+ }
+
+ while( rows-- ) {
+ while( nelem-- ) {
+ elem--;
+
+ if( vector1>1 ) {
+ val1 = that1->value.data.logptr[elem];
+ null1 = that1->value.undef[elem];
+ } else if( vector1 ) {
+ val1 = that1->value.data.logptr[rows];
+ null1 = that1->value.undef[rows];
+ }
+
+ if( vector2>1 ) {
+ val2 = that2->value.data.logptr[elem];
+ null2 = that2->value.undef[elem];
+ } else if( vector2 ) {
+ val2 = that2->value.data.logptr[rows];
+ null2 = that2->value.undef[rows];
+ }
+
+ this->value.undef[elem] = (null1 || null2);
+ switch( this->operation ) {
+
+ case OR:
+ /* This is more complicated than others to suppress UNDEFs */
+ /* in those cases where the other argument is DEF && TRUE */
+
+ if( !null1 && !null2 ) {
+ this->value.data.logptr[elem] = (val1 || val2);
+ } else if( (null1 && !null2 && val2)
+ || ( !null1 && null2 && val1 ) ) {
+ this->value.data.logptr[elem] = 1;
+ this->value.undef[elem] = 0;
+ }
+ break;
+
+ case AND:
+ /* This is more complicated than others to suppress UNDEFs */
+ /* in those cases where the other argument is DEF && FALSE */
+
+ if( !null1 && !null2 ) {
+ this->value.data.logptr[elem] = (val1 && val2);
+ } else if( (null1 && !null2 && !val2)
+ || ( !null1 && null2 && !val1 ) ) {
+ this->value.data.logptr[elem] = 0;
+ this->value.undef[elem] = 0;
+ }
+ break;
+
+ case EQ:
+ this->value.data.logptr[elem] =
+ ( (val1 && val2) || (!val1 && !val2) );
+ break;
+
+ case NE:
+ this->value.data.logptr[elem] =
+ ( (val1 && !val2) || (!val1 && val2) );
+ break;
+ }
+ }
+ nelem = this->value.nelem;
+ }
+ }
+ }
+
+ if( that1->operation>0 ) {
+ free( that1->value.data.ptr );
+ }
+ if( that2->operation>0 ) {
+ free( that2->value.data.ptr );
+ }
+}
+
+static void Do_BinOp_lng( Node *this )
+{
+ Node *that1, *that2;
+ int vector1, vector2;
+ long val1=0, val2=0;
+ char null1=0, null2=0;
+ long rows, nelem, elem;
+
+ that1 = gParse.Nodes + this->SubNodes[0];
+ that2 = gParse.Nodes + this->SubNodes[1];
+
+ vector1 = ( that1->operation!=CONST_OP );
+ if( vector1 )
+ vector1 = that1->value.nelem;
+ else {
+ val1 = that1->value.data.lng;
+ }
+
+ vector2 = ( that2->operation!=CONST_OP );
+ if( vector2 )
+ vector2 = that2->value.nelem;
+ else {
+ val2 = that2->value.data.lng;
+ }
+
+ if( !vector1 && !vector2 ) { /* Result is a constant */
+
+ switch( this->operation ) {
+ case '~': /* Treat as == for LONGS */
+ case EQ: this->value.data.log = (val1 == val2); break;
+ case NE: this->value.data.log = (val1 != val2); break;
+ case GT: this->value.data.log = (val1 > val2); break;
+ case LT: this->value.data.log = (val1 < val2); break;
+ case LTE: this->value.data.log = (val1 <= val2); break;
+ case GTE: this->value.data.log = (val1 >= val2); break;
+
+ case '+': this->value.data.lng = (val1 + val2); break;
+ case '-': this->value.data.lng = (val1 - val2); break;
+ case '*': this->value.data.lng = (val1 * val2); break;
+
+ case '%':
+ if( val2 ) this->value.data.lng = (val1 % val2);
+ else fferror("Divide by Zero");
+ break;
+ case '/':
+ if( val2 ) this->value.data.lng = (val1 / val2);
+ else fferror("Divide by Zero");
+ break;
+ case POWER:
+ this->value.data.lng = (long)pow((double)val1,(double)val2);
+ break;
+ case ACCUM:
+ this->value.data.lng = val1;
+ break;
+ case DIFF:
+ this->value.data.lng = 0;
+ break;
+ }
+ this->operation=CONST_OP;
+
+ } else if ((this->operation == ACCUM) || (this->operation == DIFF)) {
+ long i, previous, curr;
+ int undef;
+ rows = gParse.nRows;
+ nelem = this->value.nelem;
+ elem = this->value.nelem * rows;
+
+ Allocate_Ptrs( this );
+
+ if( !gParse.status ) {
+ previous = that2->value.data.lng;
+ undef = (int) that2->value.undef;
+
+ if (this->operation == ACCUM) {
+ /* Cumulative sum of this chunk */
+ for (i=0; i<elem; i++) {
+ if (!that1->value.undef[i]) {
+ curr = that1->value.data.lngptr[i];
+ previous += curr;
+ }
+ this->value.data.lngptr[i] = previous;
+ this->value.undef[i] = 0;
+ }
+ } else {
+ /* Sequential difference for this chunk */
+ for (i=0; i<elem; i++) {
+ curr = that1->value.data.lngptr[i];
+ if (that1->value.undef[i] || undef) {
+ /* Either this, or previous, value was undefined */
+ this->value.data.lngptr[i] = 0;
+ this->value.undef[i] = 1;
+ } else {
+ /* Both defined, we are okay! */
+ this->value.data.lngptr[i] = curr - previous;
+ this->value.undef[i] = 0;
+ }
+
+ previous = curr;
+ undef = that1->value.undef[i];
+ }
+ }
+
+ /* Store final cumulant for next pass */
+ that2->value.data.lng = previous;
+ that2->value.undef = (char *) undef; /* XXX evil, but no harm here */
+ }
+
+ } else {
+
+ rows = gParse.nRows;
+ nelem = this->value.nelem;
+ elem = this->value.nelem * rows;
+
+ Allocate_Ptrs( this );
+
+ while( rows-- && !gParse.status ) {
+ while( nelem-- && !gParse.status ) {
+ elem--;
+
+ if( vector1>1 ) {
+ val1 = that1->value.data.lngptr[elem];
+ null1 = that1->value.undef[elem];
+ } else if( vector1 ) {
+ val1 = that1->value.data.lngptr[rows];
+ null1 = that1->value.undef[rows];
+ }
+
+ if( vector2>1 ) {
+ val2 = that2->value.data.lngptr[elem];
+ null2 = that2->value.undef[elem];
+ } else if( vector2 ) {
+ val2 = that2->value.data.lngptr[rows];
+ null2 = that2->value.undef[rows];
+ }
+
+ this->value.undef[elem] = (null1 || null2);
+ switch( this->operation ) {
+ case '~': /* Treat as == for LONGS */
+ case EQ: this->value.data.logptr[elem] = (val1 == val2); break;
+ case NE: this->value.data.logptr[elem] = (val1 != val2); break;
+ case GT: this->value.data.logptr[elem] = (val1 > val2); break;
+ case LT: this->value.data.logptr[elem] = (val1 < val2); break;
+ case LTE: this->value.data.logptr[elem] = (val1 <= val2); break;
+ case GTE: this->value.data.logptr[elem] = (val1 >= val2); break;
+
+ case '+': this->value.data.lngptr[elem] = (val1 + val2); break;
+ case '-': this->value.data.lngptr[elem] = (val1 - val2); break;
+ case '*': this->value.data.lngptr[elem] = (val1 * val2); break;
+
+ case '%':
+ if( val2 ) this->value.data.lngptr[elem] = (val1 % val2);
+ else {
+ this->value.data.lngptr[elem] = 0;
+ this->value.undef[elem] = 1;
+ }
+ break;
+ case '/':
+ if( val2 ) this->value.data.lngptr[elem] = (val1 / val2);
+ else {
+ this->value.data.lngptr[elem] = 0;
+ this->value.undef[elem] = 1;
+ }
+ break;
+ case POWER:
+ this->value.data.lngptr[elem] = (long)pow((double)val1,(double)val2);
+ break;
+ }
+ }
+ nelem = this->value.nelem;
+ }
+ }
+
+ if( that1->operation>0 ) {
+ free( that1->value.data.ptr );
+ }
+ if( that2->operation>0 ) {
+ free( that2->value.data.ptr );
+ }
+}
+
+static void Do_BinOp_dbl( Node *this )
+{
+ Node *that1, *that2;
+ int vector1, vector2;
+ double val1=0.0, val2=0.0;
+ char null1=0, null2=0;
+ long rows, nelem, elem;
+
+ that1 = gParse.Nodes + this->SubNodes[0];
+ that2 = gParse.Nodes + this->SubNodes[1];
+
+ vector1 = ( that1->operation!=CONST_OP );
+ if( vector1 )
+ vector1 = that1->value.nelem;
+ else {
+ val1 = that1->value.data.dbl;
+ }
+
+ vector2 = ( that2->operation!=CONST_OP );
+ if( vector2 )
+ vector2 = that2->value.nelem;
+ else {
+ val2 = that2->value.data.dbl;
+ }
+
+ if( !vector1 && !vector2 ) { /* Result is a constant */
+
+ switch( this->operation ) {
+ case '~': this->value.data.log = ( fabs(val1-val2) < APPROX ); break;
+ case EQ: this->value.data.log = (val1 == val2); break;
+ case NE: this->value.data.log = (val1 != val2); break;
+ case GT: this->value.data.log = (val1 > val2); break;
+ case LT: this->value.data.log = (val1 < val2); break;
+ case LTE: this->value.data.log = (val1 <= val2); break;
+ case GTE: this->value.data.log = (val1 >= val2); break;
+
+ case '+': this->value.data.dbl = (val1 + val2); break;
+ case '-': this->value.data.dbl = (val1 - val2); break;
+ case '*': this->value.data.dbl = (val1 * val2); break;
+
+ case '%':
+ if( val2 ) this->value.data.dbl = val1 - val2*((int)(val1/val2));
+ else fferror("Divide by Zero");
+ break;
+ case '/':
+ if( val2 ) this->value.data.dbl = (val1 / val2);
+ else fferror("Divide by Zero");
+ break;
+ case POWER:
+ this->value.data.dbl = (double)pow(val1,val2);
+ break;
+ case ACCUM:
+ this->value.data.dbl = val1;
+ break;
+ case DIFF:
+ this->value.data.dbl = 0;
+ break;
+ }
+ this->operation=CONST_OP;
+
+ } else if ((this->operation == ACCUM) || (this->operation == DIFF)) {
+ long i;
+ int undef;
+ double previous, curr;
+ rows = gParse.nRows;
+ nelem = this->value.nelem;
+ elem = this->value.nelem * rows;
+
+ Allocate_Ptrs( this );
+
+ if( !gParse.status ) {
+ previous = that2->value.data.dbl;
+ undef = (int) that2->value.undef;
+
+ if (this->operation == ACCUM) {
+ /* Cumulative sum of this chunk */
+ for (i=0; i<elem; i++) {
+ if (!that1->value.undef[i]) {
+ curr = that1->value.data.dblptr[i];
+ previous += curr;
+ }
+ this->value.data.dblptr[i] = previous;
+ this->value.undef[i] = 0;
+ }
+ } else {
+ /* Sequential difference for this chunk */
+ for (i=0; i<elem; i++) {
+ curr = that1->value.data.dblptr[i];
+ if (that1->value.undef[i] || undef) {
+ /* Either this, or previous, value was undefined */
+ this->value.data.dblptr[i] = 0;
+ this->value.undef[i] = 1;
+ } else {
+ /* Both defined, we are okay! */
+ this->value.data.dblptr[i] = curr - previous;
+ this->value.undef[i] = 0;
+ }
+
+ previous = curr;
+ undef = that1->value.undef[i];
+ }
+ }
+
+ /* Store final cumulant for next pass */
+ that2->value.data.dbl = previous;
+ that2->value.undef = (char *) undef; /* XXX evil, but no harm here */
+ }
+
+ } else {
+
+ rows = gParse.nRows;
+ nelem = this->value.nelem;
+ elem = this->value.nelem * rows;
+
+ Allocate_Ptrs( this );
+
+ while( rows-- && !gParse.status ) {
+ while( nelem-- && !gParse.status ) {
+ elem--;
+
+ if( vector1>1 ) {
+ val1 = that1->value.data.dblptr[elem];
+ null1 = that1->value.undef[elem];
+ } else if( vector1 ) {
+ val1 = that1->value.data.dblptr[rows];
+ null1 = that1->value.undef[rows];
+ }
+
+ if( vector2>1 ) {
+ val2 = that2->value.data.dblptr[elem];
+ null2 = that2->value.undef[elem];
+ } else if( vector2 ) {
+ val2 = that2->value.data.dblptr[rows];
+ null2 = that2->value.undef[rows];
+ }
+
+ this->value.undef[elem] = (null1 || null2);
+ switch( this->operation ) {
+ case '~': this->value.data.logptr[elem] =
+ ( fabs(val1-val2) < APPROX ); break;
+ case EQ: this->value.data.logptr[elem] = (val1 == val2); break;
+ case NE: this->value.data.logptr[elem] = (val1 != val2); break;
+ case GT: this->value.data.logptr[elem] = (val1 > val2); break;
+ case LT: this->value.data.logptr[elem] = (val1 < val2); break;
+ case LTE: this->value.data.logptr[elem] = (val1 <= val2); break;
+ case GTE: this->value.data.logptr[elem] = (val1 >= val2); break;
+
+ case '+': this->value.data.dblptr[elem] = (val1 + val2); break;
+ case '-': this->value.data.dblptr[elem] = (val1 - val2); break;
+ case '*': this->value.data.dblptr[elem] = (val1 * val2); break;
+
+ case '%':
+ if( val2 ) this->value.data.dblptr[elem] =
+ val1 - val2*((int)(val1/val2));
+ else {
+ this->value.data.dblptr[elem] = 0.0;
+ this->value.undef[elem] = 1;
+ }
+ break;
+ case '/':
+ if( val2 ) this->value.data.dblptr[elem] = (val1 / val2);
+ else {
+ this->value.data.dblptr[elem] = 0.0;
+ this->value.undef[elem] = 1;
+ }
+ break;
+ case POWER:
+ this->value.data.dblptr[elem] = (double)pow(val1,val2);
+ break;
+ }
+ }
+ nelem = this->value.nelem;
+ }
+ }
+
+ if( that1->operation>0 ) {
+ free( that1->value.data.ptr );
+ }
+ if( that2->operation>0 ) {
+ free( that2->value.data.ptr );
+ }
+}
+
+/*
+ * This Quickselect routine is based on the algorithm described in
+ * "Numerical recipes in C", Second Edition,
+ * Cambridge University Press, 1992, Section 8.5, ISBN 0-521-43108-5
+ * This code by Nicolas Devillard - 1998. Public domain.
+ * http://ndevilla.free.fr/median/median/src/quickselect.c
+ */
+
+#define ELEM_SWAP(a,b) { register long t=(a);(a)=(b);(b)=t; }
+
+/*
+ * qselect_median_lng - select the median value of a long array
+ *
+ * This routine selects the median value of the long integer array
+ * arr[]. If there are an even number of elements, the "lower median"
+ * is selected.
+ *
+ * The array arr[] is scrambled, so users must operate on a scratch
+ * array if they wish the values to be preserved.
+ *
+ * long arr[] - array of values
+ * int n - number of elements in arr
+ *
+ * RETURNS: the lower median value of arr[]
+ *
+ */
+long qselect_median_lng(long arr[], int n)
+{
+ int low, high ;
+ int median;
+ int middle, ll, hh;
+
+ low = 0 ; high = n-1 ; median = (low + high) / 2;
+ for (;;) {
+
+ if (high <= low) { /* One element only */
+ return arr[median];
+ }
+
+ if (high == low + 1) { /* Two elements only */
+ if (arr[low] > arr[high])
+ ELEM_SWAP(arr[low], arr[high]) ;
+ return arr[median];
+ }
+
+ /* Find median of low, middle and high items; swap into position low */
+ middle = (low + high) / 2;
+ if (arr[middle] > arr[high]) ELEM_SWAP(arr[middle], arr[high]) ;
+ if (arr[low] > arr[high]) ELEM_SWAP(arr[low], arr[high]) ;
+ if (arr[middle] > arr[low]) ELEM_SWAP(arr[middle], arr[low]) ;
+
+ /* Swap low item (now in position middle) into position (low+1) */
+ ELEM_SWAP(arr[middle], arr[low+1]) ;
+
+ /* Nibble from each end towards middle, swapping items when stuck */
+ ll = low + 1;
+ hh = high;
+ for (;;) {
+ do ll++; while (arr[low] > arr[ll]) ;
+ do hh--; while (arr[hh] > arr[low]) ;
+
+ if (hh < ll)
+ break;
+
+ ELEM_SWAP(arr[ll], arr[hh]) ;
+ }
+
+ /* Swap middle item (in position low) back into correct position */
+ ELEM_SWAP(arr[low], arr[hh]) ;
+
+ /* Re-set active partition */
+ if (hh <= median)
+ low = ll;
+ if (hh >= median)
+ high = hh - 1;
+ }
+}
+
+#undef ELEM_SWAP
+
+#define ELEM_SWAP(a,b) { register double t=(a);(a)=(b);(b)=t; }
+
+/*
+ * qselect_median_dbl - select the median value of a double array
+ *
+ * This routine selects the median value of the double array
+ * arr[]. If there are an even number of elements, the "lower median"
+ * is selected.
+ *
+ * The array arr[] is scrambled, so users must operate on a scratch
+ * array if they wish the values to be preserved.
+ *
+ * double arr[] - array of values
+ * int n - number of elements in arr
+ *
+ * RETURNS: the lower median value of arr[]
+ *
+ */
+double qselect_median_dbl(double arr[], int n)
+{
+ int low, high ;
+ int median;
+ int middle, ll, hh;
+
+ low = 0 ; high = n-1 ; median = (low + high) / 2;
+ for (;;) {
+ if (high <= low) { /* One element only */
+ return arr[median] ;
+ }
+
+ if (high == low + 1) { /* Two elements only */
+ if (arr[low] > arr[high])
+ ELEM_SWAP(arr[low], arr[high]) ;
+ return arr[median] ;
+ }
+
+ /* Find median of low, middle and high items; swap into position low */
+ middle = (low + high) / 2;
+ if (arr[middle] > arr[high]) ELEM_SWAP(arr[middle], arr[high]) ;
+ if (arr[low] > arr[high]) ELEM_SWAP(arr[low], arr[high]) ;
+ if (arr[middle] > arr[low]) ELEM_SWAP(arr[middle], arr[low]) ;
+
+ /* Swap low item (now in position middle) into position (low+1) */
+ ELEM_SWAP(arr[middle], arr[low+1]) ;
+
+ /* Nibble from each end towards middle, swapping items when stuck */
+ ll = low + 1;
+ hh = high;
+ for (;;) {
+ do ll++; while (arr[low] > arr[ll]) ;
+ do hh--; while (arr[hh] > arr[low]) ;
+
+ if (hh < ll)
+ break;
+
+ ELEM_SWAP(arr[ll], arr[hh]) ;
+ }
+
+ /* Swap middle item (in position low) back into correct position */
+ ELEM_SWAP(arr[low], arr[hh]) ;
+
+ /* Re-set active partition */
+ if (hh <= median)
+ low = ll;
+ if (hh >= median)
+ high = hh - 1;
+ }
+}
+
+#undef ELEM_SWAP
+
+static void Do_Func( Node *this )
+{
+ Node *theParams[MAXSUBS];
+ int vector[MAXSUBS], allConst;
+ lval pVals[MAXSUBS];
+ char pNull[MAXSUBS];
+ long ival;
+ double dval;
+ int i, valInit;
+ long row, elem, nelem;
+ double rndVal;
+
+ i = this->nSubNodes;
+ allConst = 1;
+ while( i-- ) {
+ theParams[i] = gParse.Nodes + this->SubNodes[i];
+ vector[i] = ( theParams[i]->operation!=CONST_OP );
+ if( vector[i] ) {
+ allConst = 0;
+ vector[i] = theParams[i]->value.nelem;
+ } else {
+ if( theParams[i]->type==DOUBLE ) {
+ pVals[i].data.dbl = theParams[i]->value.data.dbl;
+ } else if( theParams[i]->type==LONG ) {
+ pVals[i].data.lng = theParams[i]->value.data.lng;
+ } else if( theParams[i]->type==BOOLEAN ) {
+ pVals[i].data.log = theParams[i]->value.data.log;
+ } else
+ strcpy(pVals[i].data.str, theParams[i]->value.data.str);
+ pNull[i] = 0;
+ }
+ }
+
+ if( this->nSubNodes==0 ) allConst = 0; /* These do produce scalars */
+
+ if( allConst ) {
+
+ switch( this->operation ) {
+
+ /* Non-Trig single-argument functions */
+
+ case sum_fct:
+ if( theParams[0]->type==BOOLEAN )
+ this->value.data.lng = ( pVals[0].data.log ? 1 : 0 );
+ else if( theParams[0]->type==LONG )
+ this->value.data.lng = pVals[0].data.lng;
+ else if( theParams[0]->type==DOUBLE )
+ this->value.data.dbl = pVals[0].data.dbl;
+ else if( theParams[0]->type==BITSTR )
+ strcpy(this->value.data.str, pVals[0].data.str);
+ break;
+ case average_fct:
+ if( theParams[0]->type==LONG )
+ this->value.data.dbl = pVals[0].data.lng;
+ else if( theParams[0]->type==DOUBLE )
+ this->value.data.dbl = pVals[0].data.dbl;
+ break;
+ case stddev_fct:
+ this->value.data.dbl = 0; /* Standard deviation of a constant = 0 */
+ break;
+ case median_fct:
+ if( theParams[0]->type==BOOLEAN )
+ this->value.data.lng = ( pVals[0].data.log ? 1 : 0 );
+ else if( theParams[0]->type==LONG )
+ this->value.data.lng = pVals[0].data.lng;
+ else
+ this->value.data.dbl = pVals[0].data.dbl;
+ break;
+ case abs_fct:
+ if( theParams[0]->type==DOUBLE ) {
+ dval = pVals[0].data.dbl;
+ this->value.data.dbl = (dval>0.0 ? dval : -dval);
+ } else {
+ ival = pVals[0].data.lng;
+ this->value.data.lng = (ival> 0 ? ival : -ival);
+ }
+ break;
+
+ /* Special Null-Handling Functions */
+
+ case nonnull_fct:
+ this->value.data.lng = 1; /* Constants are always 1-element and defined */
+ break;
+ case isnull_fct: /* Constants are always defined */
+ this->value.data.log = 0;
+ break;
+ case defnull_fct:
+ if( this->type==BOOLEAN )
+ this->value.data.log = pVals[0].data.log;
+ else if( this->type==LONG )
+ this->value.data.lng = pVals[0].data.lng;
+ else if( this->type==DOUBLE )
+ this->value.data.dbl = pVals[0].data.dbl;
+ else if( this->type==STRING )
+ strcpy(this->value.data.str,pVals[0].data.str);
+ break;
+
+ /* Math functions with 1 double argument */
+
+ case sin_fct:
+ this->value.data.dbl = sin( pVals[0].data.dbl );
+ break;
+ case cos_fct:
+ this->value.data.dbl = cos( pVals[0].data.dbl );
+ break;
+ case tan_fct:
+ this->value.data.dbl = tan( pVals[0].data.dbl );
+ break;
+ case asin_fct:
+ dval = pVals[0].data.dbl;
+ if( dval<-1.0 || dval>1.0 )
+ fferror("Out of range argument to arcsin");
+ else
+ this->value.data.dbl = asin( dval );
+ break;
+ case acos_fct:
+ dval = pVals[0].data.dbl;
+ if( dval<-1.0 || dval>1.0 )
+ fferror("Out of range argument to arccos");
+ else
+ this->value.data.dbl = acos( dval );
+ break;
+ case atan_fct:
+ this->value.data.dbl = atan( pVals[0].data.dbl );
+ break;
+ case sinh_fct:
+ this->value.data.dbl = sinh( pVals[0].data.dbl );
+ break;
+ case cosh_fct:
+ this->value.data.dbl = cosh( pVals[0].data.dbl );
+ break;
+ case tanh_fct:
+ this->value.data.dbl = tanh( pVals[0].data.dbl );
+ break;
+ case exp_fct:
+ this->value.data.dbl = exp( pVals[0].data.dbl );
+ break;
+ case log_fct:
+ dval = pVals[0].data.dbl;
+ if( dval<=0.0 )
+ fferror("Out of range argument to log");
+ else
+ this->value.data.dbl = log( dval );
+ break;
+ case log10_fct:
+ dval = pVals[0].data.dbl;
+ if( dval<=0.0 )
+ fferror("Out of range argument to log10");
+ else
+ this->value.data.dbl = log10( dval );
+ break;
+ case sqrt_fct:
+ dval = pVals[0].data.dbl;
+ if( dval<0.0 )
+ fferror("Out of range argument to sqrt");
+ else
+ this->value.data.dbl = sqrt( dval );
+ break;
+ case ceil_fct:
+ this->value.data.dbl = ceil( pVals[0].data.dbl );
+ break;
+ case floor_fct:
+ this->value.data.dbl = floor( pVals[0].data.dbl );
+ break;
+ case round_fct:
+ this->value.data.dbl = floor( pVals[0].data.dbl + 0.5 );
+ break;
+
+ /* Two-argument Trig Functions */
+
+ case atan2_fct:
+ this->value.data.dbl =
+ atan2( pVals[0].data.dbl, pVals[1].data.dbl );
+ break;
+
+ /* Min/Max functions taking 1 or 2 arguments */
+
+ case min1_fct:
+ /* No constant vectors! */
+ if( this->type == DOUBLE )
+ this->value.data.dbl = pVals[0].data.dbl;
+ else if( this->type == LONG )
+ this->value.data.lng = pVals[0].data.lng;
+ else if( this->type == BITSTR )
+ strcpy(this->value.data.str, pVals[0].data.str);
+ break;
+ case min2_fct:
+ if( this->type == DOUBLE )
+ this->value.data.dbl =
+ minvalue( pVals[0].data.dbl, pVals[1].data.dbl );
+ else if( this->type == LONG )
+ this->value.data.lng =
+ minvalue( pVals[0].data.lng, pVals[1].data.lng );
+ break;
+ case max1_fct:
+ /* No constant vectors! */
+ if( this->type == DOUBLE )
+ this->value.data.dbl = pVals[0].data.dbl;
+ else if( this->type == LONG )
+ this->value.data.lng = pVals[0].data.lng;
+ else if( this->type == BITSTR )
+ strcpy(this->value.data.str, pVals[0].data.str);
+ break;
+ case max2_fct:
+ if( this->type == DOUBLE )
+ this->value.data.dbl =
+ maxvalue( pVals[0].data.dbl, pVals[1].data.dbl );
+ else if( this->type == LONG )
+ this->value.data.lng =
+ maxvalue( pVals[0].data.lng, pVals[1].data.lng );
+ break;
+
+ /* Boolean SAO region Functions... all arguments scalar dbls */
+
+ case near_fct:
+ this->value.data.log = bnear( pVals[0].data.dbl, pVals[1].data.dbl,
+ pVals[2].data.dbl );
+ break;
+ case circle_fct:
+ this->value.data.log = circle( pVals[0].data.dbl, pVals[1].data.dbl,
+ pVals[2].data.dbl, pVals[3].data.dbl,
+ pVals[4].data.dbl );
+ break;
+ case box_fct:
+ this->value.data.log = saobox( pVals[0].data.dbl, pVals[1].data.dbl,
+ pVals[2].data.dbl, pVals[3].data.dbl,
+ pVals[4].data.dbl, pVals[5].data.dbl,
+ pVals[6].data.dbl );
+ break;
+ case elps_fct:
+ this->value.data.log =
+ ellipse( pVals[0].data.dbl, pVals[1].data.dbl,
+ pVals[2].data.dbl, pVals[3].data.dbl,
+ pVals[4].data.dbl, pVals[5].data.dbl,
+ pVals[6].data.dbl );
+ break;
+
+ /* C Conditional expression: bool ? expr : expr */
+
+ case ifthenelse_fct:
+ switch( this->type ) {
+ case BOOLEAN:
+ this->value.data.log = ( pVals[2].data.log ?
+ pVals[0].data.log : pVals[1].data.log );
+ break;
+ case LONG:
+ this->value.data.lng = ( pVals[2].data.log ?
+ pVals[0].data.lng : pVals[1].data.lng );
+ break;
+ case DOUBLE:
+ this->value.data.dbl = ( pVals[2].data.log ?
+ pVals[0].data.dbl : pVals[1].data.dbl );
+ break;
+ case STRING:
+ strcpy(this->value.data.str, ( pVals[2].data.log ?
+ pVals[0].data.str :
+ pVals[1].data.str ) );
+ break;
+ }
+ break;
+
+ }
+ this->operation = CONST_OP;
+
+ } else {
+
+ Allocate_Ptrs( this );
+
+ row = gParse.nRows;
+ elem = row * this->value.nelem;
+
+ if( !gParse.status ) {
+ switch( this->operation ) {
+
+ /* Special functions with no arguments */
+
+ case row_fct:
+ while( row-- ) {
+ this->value.data.lngptr[row] = gParse.firstRow + row;
+ this->value.undef[row] = 0;
+ }
+ break;
+ case null_fct:
+ if( this->type==LONG ) {
+ while( row-- ) {
+ this->value.data.lngptr[row] = 0;
+ this->value.undef[row] = 1;
+ }
+ } else if( this->type==STRING ) {
+ while( row-- ) {
+ this->value.data.strptr[row][0] = '\0';
+ this->value.undef[row] = 1;
+ }
+ }
+ break;
+ case rnd_fct:
+ if( rand()<32768 && rand()<32768 )
+ dval = 32768.0;
+ else
+ dval = 2147483648.0;
+ while( row-- ) {
+ rndVal = (double)rand();
+ while( rndVal > dval ) dval *= 2.0;
+ this->value.data.dblptr[row] = rndVal/dval;
+ this->value.undef[row] = 0;
+ }
+ break;
+
+ /* Non-Trig single-argument functions */
+
+ case sum_fct:
+ elem = row * theParams[0]->value.nelem;
+ if( theParams[0]->type==BOOLEAN ) {
+ while( row-- ) {
+ this->value.data.lngptr[row] = 0;
+ /* Default is UNDEF until a defined value is found */
+ this->value.undef[row] = 1;
+ nelem = theParams[0]->value.nelem;
+ while( nelem-- ) {
+ elem--;
+ if ( ! theParams[0]->value.undef[elem] ) {
+ this->value.data.lngptr[row] +=
+ ( theParams[0]->value.data.logptr[elem] ? 1 : 0 );
+ this->value.undef[row] = 0;
+ }
+ }
+ }
+ } else if( theParams[0]->type==LONG ) {
+ while( row-- ) {
+ this->value.data.lngptr[row] = 0;
+ /* Default is UNDEF until a defined value is found */
+ this->value.undef[row] = 1;
+ nelem = theParams[0]->value.nelem;
+ while( nelem-- ) {
+ elem--;
+ if ( ! theParams[0]->value.undef[elem] ) {
+ this->value.data.lngptr[row] +=
+ theParams[0]->value.data.lngptr[elem];
+ this->value.undef[row] = 0;
+ }
+ }
+ }
+ } else if( theParams[0]->type==DOUBLE ){
+ while( row-- ) {
+ this->value.data.dblptr[row] = 0.0;
+ /* Default is UNDEF until a defined value is found */
+ this->value.undef[row] = 1;
+ nelem = theParams[0]->value.nelem;
+ while( nelem-- ) {
+ elem--;
+ if ( ! theParams[0]->value.undef[elem] ) {
+ this->value.data.dblptr[row] +=
+ theParams[0]->value.data.dblptr[elem];
+ this->value.undef[row] = 0;
+ }
+ }
+ }
+ } else { /* BITSTR */
+ nelem = theParams[0]->value.nelem;
+ while( row-- ) {
+ char *sptr1 = theParams[0]->value.data.strptr[row];
+ this->value.data.lngptr[row] = 0;
+ this->value.undef[row] = 0;
+ while (*sptr1) {
+ if (*sptr1 == '1') this->value.data.lngptr[row] ++;
+ sptr1++;
+ }
+ }
+ }
+ break;
+
+ case average_fct:
+ elem = row * theParams[0]->value.nelem;
+ if( theParams[0]->type==LONG ) {
+ while( row-- ) {
+ int count = 0;
+ this->value.data.dblptr[row] = 0;
+ nelem = theParams[0]->value.nelem;
+ while( nelem-- ) {
+ elem--;
+ if (theParams[0]->value.undef[elem] == 0) {
+ this->value.data.dblptr[row] +=
+ theParams[0]->value.data.lngptr[elem];
+ count ++;
+ }
+ }
+ if (count == 0) {
+ this->value.undef[row] = 1;
+ } else {
+ this->value.undef[row] = 0;
+ this->value.data.dblptr[row] /= count;
+ }
+ }
+ } else if( theParams[0]->type==DOUBLE ){
+ while( row-- ) {
+ int count = 0;
+ this->value.data.dblptr[row] = 0;
+ nelem = theParams[0]->value.nelem;
+ while( nelem-- ) {
+ elem--;
+ if (theParams[0]->value.undef[elem] == 0) {
+ this->value.data.dblptr[row] +=
+ theParams[0]->value.data.dblptr[elem];
+ count ++;
+ }
+ }
+ if (count == 0) {
+ this->value.undef[row] = 1;
+ } else {
+ this->value.undef[row] = 0;
+ this->value.data.dblptr[row] /= count;
+ }
+ }
+ }
+ break;
+ case stddev_fct:
+ elem = row * theParams[0]->value.nelem;
+ if( theParams[0]->type==LONG ) {
+
+ /* Compute the mean value */
+ while( row-- ) {
+ int count = 0;
+ double sum = 0, sum2 = 0;
+
+ nelem = theParams[0]->value.nelem;
+ while( nelem-- ) {
+ elem--;
+ if (theParams[0]->value.undef[elem] == 0) {
+ sum += theParams[0]->value.data.lngptr[elem];
+ count ++;
+ }
+ }
+ if (count > 1) {
+ sum /= count;
+
+ /* Compute the sum of squared deviations */
+ nelem = theParams[0]->value.nelem;
+ elem += nelem; /* Reset elem for second pass */
+ while( nelem-- ) {
+ elem--;
+ if (theParams[0]->value.undef[elem] == 0) {
+ double dx = (theParams[0]->value.data.lngptr[elem] - sum);
+ sum2 += (dx*dx);
+ }
+ }
+
+ sum2 /= (double)count-1;
+
+ this->value.undef[row] = 0;
+ this->value.data.dblptr[row] = sqrt(sum2);
+ } else {
+ this->value.undef[row] = 0; /* STDDEV => 0 */
+ this->value.data.dblptr[row] = 0;
+ }
+ }
+ } else if( theParams[0]->type==DOUBLE ){
+
+ /* Compute the mean value */
+ while( row-- ) {
+ int count = 0;
+ double sum = 0, sum2 = 0;
+
+ nelem = theParams[0]->value.nelem;
+ while( nelem-- ) {
+ elem--;
+ if (theParams[0]->value.undef[elem] == 0) {
+ sum += theParams[0]->value.data.dblptr[elem];
+ count ++;
+ }
+ }
+ if (count > 1) {
+ sum /= count;
+
+ /* Compute the sum of squared deviations */
+ nelem = theParams[0]->value.nelem;
+ elem += nelem; /* Reset elem for second pass */
+ while( nelem-- ) {
+ elem--;
+ if (theParams[0]->value.undef[elem] == 0) {
+ double dx = (theParams[0]->value.data.dblptr[elem] - sum);
+ sum2 += (dx*dx);
+ }
+ }
+
+ sum2 /= (double)count-1;
+
+ this->value.undef[row] = 0;
+ this->value.data.dblptr[row] = sqrt(sum2);
+ } else {
+ this->value.undef[row] = 0; /* STDDEV => 0 */
+ this->value.data.dblptr[row] = 0;
+ }
+ }
+ }
+ break;
+
+ case median_fct:
+ elem = row * theParams[0]->value.nelem;
+ nelem = theParams[0]->value.nelem;
+ if( theParams[0]->type==LONG ) {
+ long *dptr = theParams[0]->value.data.lngptr;
+ char *uptr = theParams[0]->value.undef;
+ long *mptr = (long *) malloc(sizeof(long)*nelem);
+ int irow;
+
+ /* Allocate temporary storage for this row, since the
+ quickselect function will scramble the contents */
+ if (mptr == 0) {
+ fferror("Could not allocate temporary memory in median function");
+ free( this->value.data.ptr );
+ break;
+ }
+
+ for (irow=0; irow<row; irow++) {
+ long *p = mptr;
+ int nelem1 = nelem;
+ int count = 0;
+
+ while ( nelem1-- ) {
+ if (*uptr == 0) {
+ *p++ = *dptr; /* Only advance the dest pointer if we copied */
+ }
+ dptr ++; /* Advance the source pointer ... */
+ uptr ++; /* ... and source "undef" pointer */
+ }
+
+ nelem1 = (p - mptr); /* Number of accepted data points */
+ if (nelem1 > 0) {
+ this->value.undef[irow] = 0;
+ this->value.data.lngptr[irow] = qselect_median_lng(mptr, nelem1);
+ } else {
+ this->value.undef[irow] = 1;
+ this->value.data.lngptr[irow] = 0;
+ }
+
+ }
+
+ free(mptr);
+ } else {
+ double *dptr = theParams[0]->value.data.dblptr;
+ char *uptr = theParams[0]->value.undef;
+ double *mptr = (double *) malloc(sizeof(double)*nelem);
+ int irow;
+
+ /* Allocate temporary storage for this row, since the
+ quickselect function will scramble the contents */
+ if (mptr == 0) {
+ fferror("Could not allocate temporary memory in median function");
+ free( this->value.data.ptr );
+ break;
+ }
+
+ for (irow=0; irow<row; irow++) {
+ double *p = mptr;
+ int nelem1 = nelem;
+
+ while ( nelem1-- ) {
+ if (*uptr == 0) {
+ *p++ = *dptr; /* Only advance the dest pointer if we copied */
+ }
+ dptr ++; /* Advance the source pointer ... */
+ uptr ++; /* ... and source "undef" pointer */
+ }
+
+ nelem1 = (p - mptr); /* Number of accepted data points */
+ if (nelem1 > 0) {
+ this->value.undef[irow] = 0;
+ this->value.data.dblptr[irow] = qselect_median_dbl(mptr, nelem1);
+ } else {
+ this->value.undef[irow] = 1;
+ this->value.data.dblptr[irow] = 0;
+ }
+
+ }
+ free(mptr);
+ }
+ break;
+ case abs_fct:
+ if( theParams[0]->type==DOUBLE )
+ while( elem-- ) {
+ dval = theParams[0]->value.data.dblptr[elem];
+ this->value.data.dblptr[elem] = (dval>0.0 ? dval : -dval);
+ this->value.undef[elem] = theParams[0]->value.undef[elem];
+ }
+ else
+ while( elem-- ) {
+ ival = theParams[0]->value.data.lngptr[elem];
+ this->value.data.lngptr[elem] = (ival> 0 ? ival : -ival);
+ this->value.undef[elem] = theParams[0]->value.undef[elem];
+ }
+ break;
+
+ /* Special Null-Handling Functions */
+
+ case nonnull_fct:
+ nelem = theParams[0]->value.nelem;
+ if ( theParams[0]->type==STRING ) nelem = 1;
+ elem = row * nelem;
+ while( row-- ) {
+ int nelem1 = nelem;
+
+ this->value.undef[row] = 0; /* Initialize to 0 (defined) */
+ this->value.data.lngptr[row] = 0;
+ while( nelem1-- ) {
+ elem --;
+ if ( theParams[0]->value.undef[elem] == 0 ) this->value.data.lngptr[row] ++;
+ }
+ }
+ break;
+ case isnull_fct:
+ if( theParams[0]->type==STRING ) elem = row;
+ while( elem-- ) {
+ this->value.data.logptr[elem] = theParams[0]->value.undef[elem];
+ this->value.undef[elem] = 0;
+ }
+ break;
+ case defnull_fct:
+ switch( this->type ) {
+ case BOOLEAN:
+ while( row-- ) {
+ nelem = this->value.nelem;
+ while( nelem-- ) {
+ elem--;
+ i=2; while( i-- )
+ if( vector[i]>1 ) {
+ pNull[i] = theParams[i]->value.undef[elem];
+ pVals[i].data.log =
+ theParams[i]->value.data.logptr[elem];
+ } else if( vector[i] ) {
+ pNull[i] = theParams[i]->value.undef[row];
+ pVals[i].data.log =
+ theParams[i]->value.data.logptr[row];
+ }
+ if( pNull[0] ) {
+ this->value.undef[elem] = pNull[1];
+ this->value.data.logptr[elem] = pVals[1].data.log;
+ } else {
+ this->value.undef[elem] = 0;
+ this->value.data.logptr[elem] = pVals[0].data.log;
+ }
+ }
+ }
+ break;
+ case LONG:
+ while( row-- ) {
+ nelem = this->value.nelem;
+ while( nelem-- ) {
+ elem--;
+ i=2; while( i-- )
+ if( vector[i]>1 ) {
+ pNull[i] = theParams[i]->value.undef[elem];
+ pVals[i].data.lng =
+ theParams[i]->value.data.lngptr[elem];
+ } else if( vector[i] ) {
+ pNull[i] = theParams[i]->value.undef[row];
+ pVals[i].data.lng =
+ theParams[i]->value.data.lngptr[row];
+ }
+ if( pNull[0] ) {
+ this->value.undef[elem] = pNull[1];
+ this->value.data.lngptr[elem] = pVals[1].data.lng;
+ } else {
+ this->value.undef[elem] = 0;
+ this->value.data.lngptr[elem] = pVals[0].data.lng;
+ }
+ }
+ }
+ break;
+ case DOUBLE:
+ while( row-- ) {
+ nelem = this->value.nelem;
+ while( nelem-- ) {
+ elem--;
+ i=2; while( i-- )
+ if( vector[i]>1 ) {
+ pNull[i] = theParams[i]->value.undef[elem];
+ pVals[i].data.dbl =
+ theParams[i]->value.data.dblptr[elem];
+ } else if( vector[i] ) {
+ pNull[i] = theParams[i]->value.undef[row];
+ pVals[i].data.dbl =
+ theParams[i]->value.data.dblptr[row];
+ }
+ if( pNull[0] ) {
+ this->value.undef[elem] = pNull[1];
+ this->value.data.dblptr[elem] = pVals[1].data.dbl;
+ } else {
+ this->value.undef[elem] = 0;
+ this->value.data.dblptr[elem] = pVals[0].data.dbl;
+ }
+ }
+ }
+ break;
+ case STRING:
+ while( row-- ) {
+ i=2; while( i-- )
+ if( vector[i] ) {
+ pNull[i] = theParams[i]->value.undef[row];
+ strcpy(pVals[i].data.str,
+ theParams[i]->value.data.strptr[row]);
+ }
+ if( pNull[0] ) {
+ this->value.undef[row] = pNull[1];
+ strcpy(this->value.data.strptr[row],pVals[1].data.str);
+ } else {
+ this->value.undef[elem] = 0;
+ strcpy(this->value.data.strptr[row],pVals[0].data.str);
+ }
+ }
+ }
+ break;
+
+ /* Math functions with 1 double argument */
+
+ case sin_fct:
+ while( elem-- )
+ if( !(this->value.undef[elem] = theParams[0]->value.undef[elem]) ) {
+ this->value.data.dblptr[elem] =
+ sin( theParams[0]->value.data.dblptr[elem] );
+ }
+ break;
+ case cos_fct:
+ while( elem-- )
+ if( !(this->value.undef[elem] = theParams[0]->value.undef[elem]) ) {
+ this->value.data.dblptr[elem] =
+ cos( theParams[0]->value.data.dblptr[elem] );
+ }
+ break;
+ case tan_fct:
+ while( elem-- )
+ if( !(this->value.undef[elem] = theParams[0]->value.undef[elem]) ) {
+ this->value.data.dblptr[elem] =
+ tan( theParams[0]->value.data.dblptr[elem] );
+ }
+ break;
+ case asin_fct:
+ while( elem-- )
+ if( !(this->value.undef[elem] = theParams[0]->value.undef[elem]) ) {
+ dval = theParams[0]->value.data.dblptr[elem];
+ if( dval<-1.0 || dval>1.0 ) {
+ this->value.data.dblptr[elem] = 0.0;
+ this->value.undef[elem] = 1;
+ } else
+ this->value.data.dblptr[elem] = asin( dval );
+ }
+ break;
+ case acos_fct:
+ while( elem-- )
+ if( !(this->value.undef[elem] = theParams[0]->value.undef[elem]) ) {
+ dval = theParams[0]->value.data.dblptr[elem];
+ if( dval<-1.0 || dval>1.0 ) {
+ this->value.data.dblptr[elem] = 0.0;
+ this->value.undef[elem] = 1;
+ } else
+ this->value.data.dblptr[elem] = acos( dval );
+ }
+ break;
+ case atan_fct:
+ while( elem-- )
+ if( !(this->value.undef[elem] = theParams[0]->value.undef[elem]) ) {
+ dval = theParams[0]->value.data.dblptr[elem];
+ this->value.data.dblptr[elem] = atan( dval );
+ }
+ break;
+ case sinh_fct:
+ while( elem-- )
+ if( !(this->value.undef[elem] = theParams[0]->value.undef[elem]) ) {
+ this->value.data.dblptr[elem] =
+ sinh( theParams[0]->value.data.dblptr[elem] );
+ }
+ break;
+ case cosh_fct:
+ while( elem-- )
+ if( !(this->value.undef[elem] = theParams[0]->value.undef[elem]) ) {
+ this->value.data.dblptr[elem] =
+ cosh( theParams[0]->value.data.dblptr[elem] );
+ }
+ break;
+ case tanh_fct:
+ while( elem-- )
+ if( !(this->value.undef[elem] = theParams[0]->value.undef[elem]) ) {
+ this->value.data.dblptr[elem] =
+ tanh( theParams[0]->value.data.dblptr[elem] );
+ }
+ break;
+ case exp_fct:
+ while( elem-- )
+ if( !(this->value.undef[elem] = theParams[0]->value.undef[elem]) ) {
+ dval = theParams[0]->value.data.dblptr[elem];
+ this->value.data.dblptr[elem] = exp( dval );
+ }
+ break;
+ case log_fct:
+ while( elem-- )
+ if( !(this->value.undef[elem] = theParams[0]->value.undef[elem]) ) {
+ dval = theParams[0]->value.data.dblptr[elem];
+ if( dval<=0.0 ) {
+ this->value.data.dblptr[elem] = 0.0;
+ this->value.undef[elem] = 1;
+ } else
+ this->value.data.dblptr[elem] = log( dval );
+ }
+ break;
+ case log10_fct:
+ while( elem-- )
+ if( !(this->value.undef[elem] = theParams[0]->value.undef[elem]) ) {
+ dval = theParams[0]->value.data.dblptr[elem];
+ if( dval<=0.0 ) {
+ this->value.data.dblptr[elem] = 0.0;
+ this->value.undef[elem] = 1;
+ } else
+ this->value.data.dblptr[elem] = log10( dval );
+ }
+ break;
+ case sqrt_fct:
+ while( elem-- )
+ if( !(this->value.undef[elem] = theParams[0]->value.undef[elem]) ) {
+ dval = theParams[0]->value.data.dblptr[elem];
+ if( dval<0.0 ) {
+ this->value.data.dblptr[elem] = 0.0;
+ this->value.undef[elem] = 1;
+ } else
+ this->value.data.dblptr[elem] = sqrt( dval );
+ }
+ break;
+ case ceil_fct:
+ while( elem-- )
+ if( !(this->value.undef[elem] = theParams[0]->value.undef[elem]) ) {
+ this->value.data.dblptr[elem] =
+ ceil( theParams[0]->value.data.dblptr[elem] );
+ }
+ break;
+ case floor_fct:
+ while( elem-- )
+ if( !(this->value.undef[elem] = theParams[0]->value.undef[elem]) ) {
+ this->value.data.dblptr[elem] =
+ floor( theParams[0]->value.data.dblptr[elem] );
+ }
+ break;
+ case round_fct:
+ while( elem-- )
+ if( !(this->value.undef[elem] = theParams[0]->value.undef[elem]) ) {
+ this->value.data.dblptr[elem] =
+ floor( theParams[0]->value.data.dblptr[elem] + 0.5);
+ }
+ break;
+
+ /* Two-argument Trig Functions */
+
+ case atan2_fct:
+ while( row-- ) {
+ nelem = this->value.nelem;
+ while( nelem-- ) {
+ elem--;
+ i=2; while( i-- )
+ if( vector[i]>1 ) {
+ pVals[i].data.dbl =
+ theParams[i]->value.data.dblptr[elem];
+ pNull[i] = theParams[i]->value.undef[elem];
+ } else if( vector[i] ) {
+ pVals[i].data.dbl =
+ theParams[i]->value.data.dblptr[row];
+ pNull[i] = theParams[i]->value.undef[row];
+ }
+ if( !(this->value.undef[elem] = (pNull[0] || pNull[1]) ) )
+ this->value.data.dblptr[elem] =
+ atan2( pVals[0].data.dbl, pVals[1].data.dbl );
+ }
+ }
+ break;
+
+ /* Min/Max functions taking 1 or 2 arguments */
+
+ case min1_fct:
+ elem = row * theParams[0]->value.nelem;
+ if( this->type==LONG ) {
+ long minVal=0;
+ while( row-- ) {
+ valInit = 1;
+ this->value.undef[row] = 1;
+ nelem = theParams[0]->value.nelem;
+ while( nelem-- ) {
+ elem--;
+ if ( !theParams[0]->value.undef[elem] ) {
+ if ( valInit ) {
+ valInit = 0;
+ minVal = theParams[0]->value.data.lngptr[elem];
+ } else {
+ minVal = minvalue( minVal,
+ theParams[0]->value.data.lngptr[elem] );
+ }
+ this->value.undef[row] = 0;
+ }
+ }
+ this->value.data.lngptr[row] = minVal;
+ }
+ } else if( this->type==DOUBLE ) {
+ double minVal=0.0;
+ while( row-- ) {
+ valInit = 1;
+ this->value.undef[row] = 1;
+ nelem = theParams[0]->value.nelem;
+ while( nelem-- ) {
+ elem--;
+ if ( !theParams[0]->value.undef[elem] ) {
+ if ( valInit ) {
+ valInit = 0;
+ minVal = theParams[0]->value.data.dblptr[elem];
+ } else {
+ minVal = minvalue( minVal,
+ theParams[0]->value.data.dblptr[elem] );
+ }
+ this->value.undef[row] = 0;
+ }
+ }
+ this->value.data.dblptr[row] = minVal;
+ }
+ } else if( this->type==BITSTR ) {
+ char minVal;
+ while( row-- ) {
+ char *sptr1 = theParams[0]->value.data.strptr[row];
+ minVal = '1';
+ while (*sptr1) {
+ if (*sptr1 == '0') minVal = '0';
+ sptr1++;
+ }
+ this->value.data.strptr[row][0] = minVal;
+ this->value.data.strptr[row][1] = 0; /* Null terminate */
+ }
+ }
+ break;
+ case min2_fct:
+ if( this->type==LONG ) {
+ while( row-- ) {
+ nelem = this->value.nelem;
+ while( nelem-- ) {
+ elem--;
+ i=2; while( i-- )
+ if( vector[i]>1 ) {
+ pVals[i].data.lng =
+ theParams[i]->value.data.lngptr[elem];
+ pNull[i] = theParams[i]->value.undef[elem];
+ } else if( vector[i] ) {
+ pVals[i].data.lng =
+ theParams[i]->value.data.lngptr[row];
+ pNull[i] = theParams[i]->value.undef[row];
+ }
+ if( pNull[0] && pNull[1] ) {
+ this->value.undef[elem] = 1;
+ this->value.data.lngptr[elem] = 0;
+ } else if (pNull[0]) {
+ this->value.undef[elem] = 0;
+ this->value.data.lngptr[elem] = pVals[1].data.lng;
+ } else if (pNull[1]) {
+ this->value.undef[elem] = 0;
+ this->value.data.lngptr[elem] = pVals[0].data.lng;
+ } else {
+ this->value.undef[elem] = 0;
+ this->value.data.lngptr[elem] =
+ minvalue( pVals[0].data.lng, pVals[1].data.lng );
+ }
+ }
+ }
+ } else if( this->type==DOUBLE ) {
+ while( row-- ) {
+ nelem = this->value.nelem;
+ while( nelem-- ) {
+ elem--;
+ i=2; while( i-- )
+ if( vector[i]>1 ) {
+ pVals[i].data.dbl =
+ theParams[i]->value.data.dblptr[elem];
+ pNull[i] = theParams[i]->value.undef[elem];
+ } else if( vector[i] ) {
+ pVals[i].data.dbl =
+ theParams[i]->value.data.dblptr[row];
+ pNull[i] = theParams[i]->value.undef[row];
+ }
+ if( pNull[0] && pNull[1] ) {
+ this->value.undef[elem] = 1;
+ this->value.data.dblptr[elem] = 0;
+ } else if (pNull[0]) {
+ this->value.undef[elem] = 0;
+ this->value.data.dblptr[elem] = pVals[1].data.dbl;
+ } else if (pNull[1]) {
+ this->value.undef[elem] = 0;
+ this->value.data.dblptr[elem] = pVals[0].data.dbl;
+ } else {
+ this->value.undef[elem] = 0;
+ this->value.data.dblptr[elem] =
+ minvalue( pVals[0].data.dbl, pVals[1].data.dbl );
+ }
+ }
+ }
+ }
+ break;
+
+ case max1_fct:
+ elem = row * theParams[0]->value.nelem;
+ if( this->type==LONG ) {
+ long maxVal=0;
+ while( row-- ) {
+ valInit = 1;
+ this->value.undef[row] = 1;
+ nelem = theParams[0]->value.nelem;
+ while( nelem-- ) {
+ elem--;
+ if ( !theParams[0]->value.undef[elem] ) {
+ if ( valInit ) {
+ valInit = 0;
+ maxVal = theParams[0]->value.data.lngptr[elem];
+ } else {
+ maxVal = maxvalue( maxVal,
+ theParams[0]->value.data.lngptr[elem] );
+ }
+ this->value.undef[row] = 0;
+ }
+ }
+ this->value.data.lngptr[row] = maxVal;
+ }
+ } else if( this->type==DOUBLE ) {
+ double maxVal=0.0;
+ while( row-- ) {
+ valInit = 1;
+ this->value.undef[row] = 1;
+ nelem = theParams[0]->value.nelem;
+ while( nelem-- ) {
+ elem--;
+ if ( !theParams[0]->value.undef[elem] ) {
+ if ( valInit ) {
+ valInit = 0;
+ maxVal = theParams[0]->value.data.dblptr[elem];
+ } else {
+ maxVal = maxvalue( maxVal,
+ theParams[0]->value.data.dblptr[elem] );
+ }
+ this->value.undef[row] = 0;
+ }
+ }
+ this->value.data.dblptr[row] = maxVal;
+ }
+ } else if( this->type==BITSTR ) {
+ char maxVal;
+ while( row-- ) {
+ char *sptr1 = theParams[0]->value.data.strptr[row];
+ maxVal = '0';
+ while (*sptr1) {
+ if (*sptr1 == '1') maxVal = '1';
+ sptr1++;
+ }
+ this->value.data.strptr[row][0] = maxVal;
+ this->value.data.strptr[row][1] = 0; /* Null terminate */
+ }
+ }
+ break;
+ case max2_fct:
+ if( this->type==LONG ) {
+ while( row-- ) {
+ nelem = this->value.nelem;
+ while( nelem-- ) {
+ elem--;
+ i=2; while( i-- )
+ if( vector[i]>1 ) {
+ pVals[i].data.lng =
+ theParams[i]->value.data.lngptr[elem];
+ pNull[i] = theParams[i]->value.undef[elem];
+ } else if( vector[i] ) {
+ pVals[i].data.lng =
+ theParams[i]->value.data.lngptr[row];
+ pNull[i] = theParams[i]->value.undef[row];
+ }
+ if( pNull[0] && pNull[1] ) {
+ this->value.undef[elem] = 1;
+ this->value.data.lngptr[elem] = 0;
+ } else if (pNull[0]) {
+ this->value.undef[elem] = 0;
+ this->value.data.lngptr[elem] = pVals[1].data.lng;
+ } else if (pNull[1]) {
+ this->value.undef[elem] = 0;
+ this->value.data.lngptr[elem] = pVals[0].data.lng;
+ } else {
+ this->value.undef[elem] = 0;
+ this->value.data.lngptr[elem] =
+ maxvalue( pVals[0].data.lng, pVals[1].data.lng );
+ }
+ }
+ }
+ } else if( this->type==DOUBLE ) {
+ while( row-- ) {
+ nelem = this->value.nelem;
+ while( nelem-- ) {
+ elem--;
+ i=2; while( i-- )
+ if( vector[i]>1 ) {
+ pVals[i].data.dbl =
+ theParams[i]->value.data.dblptr[elem];
+ pNull[i] = theParams[i]->value.undef[elem];
+ } else if( vector[i] ) {
+ pVals[i].data.dbl =
+ theParams[i]->value.data.dblptr[row];
+ pNull[i] = theParams[i]->value.undef[row];
+ }
+ if( pNull[0] && pNull[1] ) {
+ this->value.undef[elem] = 1;
+ this->value.data.dblptr[elem] = 0;
+ } else if (pNull[0]) {
+ this->value.undef[elem] = 0;
+ this->value.data.dblptr[elem] = pVals[1].data.dbl;
+ } else if (pNull[1]) {
+ this->value.undef[elem] = 0;
+ this->value.data.dblptr[elem] = pVals[0].data.dbl;
+ } else {
+ this->value.undef[elem] = 0;
+ this->value.data.dblptr[elem] =
+ maxvalue( pVals[0].data.dbl, pVals[1].data.dbl );
+ }
+ }
+ }
+ }
+ break;
+
+ /* Boolean SAO region Functions... all arguments scalar dbls */
+
+ case near_fct:
+ while( row-- ) {
+ this->value.undef[row] = 0;
+ i=3; while( i-- )
+ if( vector[i] ) {
+ pVals[i].data.dbl = theParams[i]->value.data.dblptr[row];
+ this->value.undef[row] |= theParams[i]->value.undef[row];
+ }
+ if( !(this->value.undef[row]) )
+ this->value.data.logptr[row] =
+ bnear( pVals[0].data.dbl, pVals[1].data.dbl,
+ pVals[2].data.dbl );
+ }
+ break;
+ case circle_fct:
+ while( row-- ) {
+ this->value.undef[row] = 0;
+ i=5; while( i-- )
+ if( vector[i] ) {
+ pVals[i].data.dbl = theParams[i]->value.data.dblptr[row];
+ this->value.undef[row] |= theParams[i]->value.undef[row];
+ }
+ if( !(this->value.undef[row]) )
+ this->value.data.logptr[row] =
+ circle( pVals[0].data.dbl, pVals[1].data.dbl,
+ pVals[2].data.dbl, pVals[3].data.dbl,
+ pVals[4].data.dbl );
+ }
+ break;
+ case box_fct:
+ while( row-- ) {
+ this->value.undef[row] = 0;
+ i=7; while( i-- )
+ if( vector[i] ) {
+ pVals[i].data.dbl = theParams[i]->value.data.dblptr[row];
+ this->value.undef[row] |= theParams[i]->value.undef[row];
+ }
+ if( !(this->value.undef[row]) )
+ this->value.data.logptr[row] =
+ saobox( pVals[0].data.dbl, pVals[1].data.dbl,
+ pVals[2].data.dbl, pVals[3].data.dbl,
+ pVals[4].data.dbl, pVals[5].data.dbl,
+ pVals[6].data.dbl );
+ }
+ break;
+ case elps_fct:
+ while( row-- ) {
+ this->value.undef[row] = 0;
+ i=7; while( i-- )
+ if( vector[i] ) {
+ pVals[i].data.dbl = theParams[i]->value.data.dblptr[row];
+ this->value.undef[row] |= theParams[i]->value.undef[row];
+ }
+ if( !(this->value.undef[row]) )
+ this->value.data.logptr[row] =
+ ellipse( pVals[0].data.dbl, pVals[1].data.dbl,
+ pVals[2].data.dbl, pVals[3].data.dbl,
+ pVals[4].data.dbl, pVals[5].data.dbl,
+ pVals[6].data.dbl );
+ }
+ break;
+
+ /* C Conditional expression: bool ? expr : expr */
+
+ case ifthenelse_fct:
+ switch( this->type ) {
+ case BOOLEAN:
+ while( row-- ) {
+ nelem = this->value.nelem;
+ while( nelem-- ) {
+ elem--;
+ if( vector[2]>1 ) {
+ pVals[2].data.log =
+ theParams[2]->value.data.logptr[elem];
+ pNull[2] = theParams[2]->value.undef[elem];
+ } else if( vector[2] ) {
+ pVals[2].data.log =
+ theParams[2]->value.data.logptr[row];
+ pNull[2] = theParams[2]->value.undef[row];
+ }
+ i=2; while( i-- )
+ if( vector[i]>1 ) {
+ pVals[i].data.log =
+ theParams[i]->value.data.logptr[elem];
+ pNull[i] = theParams[i]->value.undef[elem];
+ } else if( vector[i] ) {
+ pVals[i].data.log =
+ theParams[i]->value.data.logptr[row];
+ pNull[i] = theParams[i]->value.undef[row];
+ }
+ if( !(this->value.undef[elem] = pNull[2]) ) {
+ if( pVals[2].data.log ) {
+ this->value.data.logptr[elem] = pVals[0].data.log;
+ this->value.undef[elem] = pNull[0];
+ } else {
+ this->value.data.logptr[elem] = pVals[1].data.log;
+ this->value.undef[elem] = pNull[1];
+ }
+ }
+ }
+ }
+ break;
+ case LONG:
+ while( row-- ) {
+ nelem = this->value.nelem;
+ while( nelem-- ) {
+ elem--;
+ if( vector[2]>1 ) {
+ pVals[2].data.log =
+ theParams[2]->value.data.logptr[elem];
+ pNull[2] = theParams[2]->value.undef[elem];
+ } else if( vector[2] ) {
+ pVals[2].data.log =
+ theParams[2]->value.data.logptr[row];
+ pNull[2] = theParams[2]->value.undef[row];
+ }
+ i=2; while( i-- )
+ if( vector[i]>1 ) {
+ pVals[i].data.lng =
+ theParams[i]->value.data.lngptr[elem];
+ pNull[i] = theParams[i]->value.undef[elem];
+ } else if( vector[i] ) {
+ pVals[i].data.lng =
+ theParams[i]->value.data.lngptr[row];
+ pNull[i] = theParams[i]->value.undef[row];
+ }
+ if( !(this->value.undef[elem] = pNull[2]) ) {
+ if( pVals[2].data.log ) {
+ this->value.data.lngptr[elem] = pVals[0].data.lng;
+ this->value.undef[elem] = pNull[0];
+ } else {
+ this->value.data.lngptr[elem] = pVals[1].data.lng;
+ this->value.undef[elem] = pNull[1];
+ }
+ }
+ }
+ }
+ break;
+ case DOUBLE:
+ while( row-- ) {
+ nelem = this->value.nelem;
+ while( nelem-- ) {
+ elem--;
+ if( vector[2]>1 ) {
+ pVals[2].data.log =
+ theParams[2]->value.data.logptr[elem];
+ pNull[2] = theParams[2]->value.undef[elem];
+ } else if( vector[2] ) {
+ pVals[2].data.log =
+ theParams[2]->value.data.logptr[row];
+ pNull[2] = theParams[2]->value.undef[row];
+ }
+ i=2; while( i-- )
+ if( vector[i]>1 ) {
+ pVals[i].data.dbl =
+ theParams[i]->value.data.dblptr[elem];
+ pNull[i] = theParams[i]->value.undef[elem];
+ } else if( vector[i] ) {
+ pVals[i].data.dbl =
+ theParams[i]->value.data.dblptr[row];
+ pNull[i] = theParams[i]->value.undef[row];
+ }
+ if( !(this->value.undef[elem] = pNull[2]) ) {
+ if( pVals[2].data.log ) {
+ this->value.data.dblptr[elem] = pVals[0].data.dbl;
+ this->value.undef[elem] = pNull[0];
+ } else {
+ this->value.data.dblptr[elem] = pVals[1].data.dbl;
+ this->value.undef[elem] = pNull[1];
+ }
+ }
+ }
+ }
+ break;
+ case STRING:
+ while( row-- ) {
+ if( vector[2] ) {
+ pVals[2].data.log = theParams[2]->value.data.logptr[row];
+ pNull[2] = theParams[2]->value.undef[row];
+ }
+ i=2; while( i-- )
+ if( vector[i] ) {
+ strcpy( pVals[i].data.str,
+ theParams[i]->value.data.strptr[row] );
+ pNull[i] = theParams[i]->value.undef[row];
+ }
+ if( !(this->value.undef[row] = pNull[2]) ) {
+ if( pVals[2].data.log ) {
+ strcpy( this->value.data.strptr[row],
+ pVals[0].data.str );
+ this->value.undef[row] = pNull[0];
+ } else {
+ strcpy( this->value.data.strptr[row],
+ pVals[1].data.str );
+ this->value.undef[row] = pNull[1];
+ }
+ } else {
+ this->value.data.strptr[row][0] = '\0';
+ }
+ }
+ break;
+
+ }
+ break;
+
+ }
+ }
+ }
+
+ i = this->nSubNodes;
+ while( i-- ) {
+ if( theParams[i]->operation>0 ) {
+ /* Currently only numeric params allowed */
+ free( theParams[i]->value.data.ptr );
+ }
+ }
+}
+
+static void Do_Deref( Node *this )
+{
+ Node *theVar, *theDims[MAXDIMS];
+ int isConst[MAXDIMS], allConst;
+ long dimVals[MAXDIMS];
+ int i, nDims;
+ long row, elem, dsize;
+
+ theVar = gParse.Nodes + this->SubNodes[0];
+
+ i = nDims = this->nSubNodes-1;
+ allConst = 1;
+ while( i-- ) {
+ theDims[i] = gParse.Nodes + this->SubNodes[i+1];
+ isConst[i] = ( theDims[i]->operation==CONST_OP );
+ if( isConst[i] )
+ dimVals[i] = theDims[i]->value.data.lng;
+ else
+ allConst = 0;
+ }
+
+ if( this->type==DOUBLE ) {
+ dsize = sizeof( double );
+ } else if( this->type==LONG ) {
+ dsize = sizeof( long );
+ } else if( this->type==BOOLEAN ) {
+ dsize = sizeof( char );
+ } else
+ dsize = 0;
+
+ Allocate_Ptrs( this );
+
+ if( !gParse.status ) {
+
+ if( allConst && theVar->value.naxis==nDims ) {
+
+ /* Dereference completely using constant indices */
+
+ elem = 0;
+ i = nDims;
+ while( i-- ) {
+ if( dimVals[i]<1 || dimVals[i]>theVar->value.naxes[i] ) break;
+ elem = theVar->value.naxes[i]*elem + dimVals[i]-1;
+ }
+ if( i<0 ) {
+ for( row=0; row<gParse.nRows; row++ ) {
+ if( this->type==STRING )
+ this->value.undef[row] = theVar->value.undef[row];
+ else if( this->type==BITSTR )
+ this->value.undef; /* Dummy - BITSTRs do not have undefs */
+ else
+ this->value.undef[row] = theVar->value.undef[elem];
+
+ if( this->type==DOUBLE )
+ this->value.data.dblptr[row] =
+ theVar->value.data.dblptr[elem];
+ else if( this->type==LONG )
+ this->value.data.lngptr[row] =
+ theVar->value.data.lngptr[elem];
+ else if( this->type==BOOLEAN )
+ this->value.data.logptr[row] =
+ theVar->value.data.logptr[elem];
+ else {
+ /* XXX Note, the below expression uses knowledge of
+ the layout of the string format, namely (nelem+1)
+ characters per string, followed by (nelem+1)
+ "undef" values. */
+ this->value.data.strptr[row][0] =
+ theVar->value.data.strptr[0][elem+row];
+ this->value.data.strptr[row][1] = 0; /* Null terminate */
+ }
+ elem += theVar->value.nelem;
+ }
+ } else {
+ fferror("Index out of range");
+ free( this->value.data.ptr );
+ }
+
+ } else if( allConst && nDims==1 ) {
+
+ /* Reduce dimensions by 1, using a constant index */
+
+ if( dimVals[0] < 1 ||
+ dimVals[0] > theVar->value.naxes[ theVar->value.naxis-1 ] ) {
+ fferror("Index out of range");
+ free( this->value.data.ptr );
+ } else if ( this->type == BITSTR || this->type == STRING ) {
+ elem = this->value.nelem * (dimVals[0]-1);
+ for( row=0; row<gParse.nRows; row++ ) {
+ if (this->value.undef)
+ this->value.undef[row] = theVar->value.undef[row];
+ memcpy( (char*)this->value.data.strptr[0]
+ + row*sizeof(char)*(this->value.nelem+1),
+ (char*)theVar->value.data.strptr[0] + elem*sizeof(char),
+ this->value.nelem * sizeof(char) );
+ /* Null terminate */
+ this->value.data.strptr[row][this->value.nelem] = 0;
+ elem += theVar->value.nelem+1;
+ }
+ } else {
+ elem = this->value.nelem * (dimVals[0]-1);
+ for( row=0; row<gParse.nRows; row++ ) {
+ memcpy( this->value.undef + row*this->value.nelem,
+ theVar->value.undef + elem,
+ this->value.nelem * sizeof(char) );
+ memcpy( (char*)this->value.data.ptr
+ + row*dsize*this->value.nelem,
+ (char*)theVar->value.data.ptr + elem*dsize,
+ this->value.nelem * dsize );
+ elem += theVar->value.nelem;
+ }
+ }
+
+ } else if( theVar->value.naxis==nDims ) {
+
+ /* Dereference completely using an expression for the indices */
+
+ for( row=0; row<gParse.nRows; row++ ) {
+
+ for( i=0; i<nDims; i++ ) {
+ if( !isConst[i] ) {
+ if( theDims[i]->value.undef[row] ) {
+ fferror("Null encountered as vector index");
+ free( this->value.data.ptr );
+ break;
+ } else
+ dimVals[i] = theDims[i]->value.data.lngptr[row];
+ }
+ }
+ if( gParse.status ) break;
+
+ elem = 0;
+ i = nDims;
+ while( i-- ) {
+ if( dimVals[i]<1 || dimVals[i]>theVar->value.naxes[i] ) break;
+ elem = theVar->value.naxes[i]*elem + dimVals[i]-1;
+ }
+ if( i<0 ) {
+ elem += row*theVar->value.nelem;
+
+ if( this->type==STRING )
+ this->value.undef[row] = theVar->value.undef[row];
+ else if( this->type==BITSTR )
+ this->value.undef; /* Dummy - BITSTRs do not have undefs */
+ else
+ this->value.undef[row] = theVar->value.undef[elem];
+
+ if( this->type==DOUBLE )
+ this->value.data.dblptr[row] =
+ theVar->value.data.dblptr[elem];
+ else if( this->type==LONG )
+ this->value.data.lngptr[row] =
+ theVar->value.data.lngptr[elem];
+ else if( this->type==BOOLEAN )
+ this->value.data.logptr[row] =
+ theVar->value.data.logptr[elem];
+ else {
+ /* XXX Note, the below expression uses knowledge of
+ the layout of the string format, namely (nelem+1)
+ characters per string, followed by (nelem+1)
+ "undef" values. */
+ this->value.data.strptr[row][0] =
+ theVar->value.data.strptr[0][elem+row];
+ this->value.data.strptr[row][1] = 0; /* Null terminate */
+ }
+ } else {
+ fferror("Index out of range");
+ free( this->value.data.ptr );
+ }
+ }
+
+ } else {
+
+ /* Reduce dimensions by 1, using a nonconstant expression */
+
+ for( row=0; row<gParse.nRows; row++ ) {
+
+ /* Index cannot be a constant */
+
+ if( theDims[0]->value.undef[row] ) {
+ fferror("Null encountered as vector index");
+ free( this->value.data.ptr );
+ break;
+ } else
+ dimVals[0] = theDims[0]->value.data.lngptr[row];
+
+ if( dimVals[0] < 1 ||
+ dimVals[0] > theVar->value.naxes[ theVar->value.naxis-1 ] ) {
+ fferror("Index out of range");
+ free( this->value.data.ptr );
+ } else if ( this->type == BITSTR || this->type == STRING ) {
+ elem = this->value.nelem * (dimVals[0]-1);
+ elem += row*(theVar->value.nelem+1);
+ if (this->value.undef)
+ this->value.undef[row] = theVar->value.undef[row];
+ memcpy( (char*)this->value.data.strptr[0]
+ + row*sizeof(char)*(this->value.nelem+1),
+ (char*)theVar->value.data.strptr[0] + elem*sizeof(char),
+ this->value.nelem * sizeof(char) );
+ /* Null terminate */
+ this->value.data.strptr[row][this->value.nelem] = 0;
+ } else {
+ elem = this->value.nelem * (dimVals[0]-1);
+ elem += row*theVar->value.nelem;
+ memcpy( this->value.undef + row*this->value.nelem,
+ theVar->value.undef + elem,
+ this->value.nelem * sizeof(char) );
+ memcpy( (char*)this->value.data.ptr
+ + row*dsize*this->value.nelem,
+ (char*)theVar->value.data.ptr + elem*dsize,
+ this->value.nelem * dsize );
+ }
+ }
+ }
+ }
+
+ if( theVar->operation>0 ) {
+ if (theVar->type == STRING || theVar->type == BITSTR)
+ free(theVar->value.data.strptr[0] );
+ else
+ free( theVar->value.data.ptr );
+ }
+ for( i=0; i<nDims; i++ )
+ if( theDims[i]->operation>0 ) {
+ free( theDims[i]->value.data.ptr );
+ }
+}
+
+static void Do_GTI( Node *this )
+{
+ Node *theExpr, *theTimes;
+ double *start, *stop, *times;
+ long elem, nGTI, gti;
+ int ordered;
+
+ theTimes = gParse.Nodes + this->SubNodes[0];
+ theExpr = gParse.Nodes + this->SubNodes[1];
+
+ nGTI = theTimes->value.nelem;
+ start = theTimes->value.data.dblptr;
+ stop = theTimes->value.data.dblptr + nGTI;
+ ordered = theTimes->type;
+
+ if( theExpr->operation==CONST_OP ) {
+
+ this->value.data.log =
+ (Search_GTI( theExpr->value.data.dbl, nGTI, start, stop, ordered )>=0);
+ this->operation = CONST_OP;
+
+ } else {
+
+ Allocate_Ptrs( this );
+
+ times = theExpr->value.data.dblptr;
+ if( !gParse.status ) {
+
+ elem = gParse.nRows * this->value.nelem;
+ if( nGTI ) {
+ gti = -1;
+ while( elem-- ) {
+ if( (this->value.undef[elem] = theExpr->value.undef[elem]) )
+ continue;
+
+ /* Before searching entire GTI, check the GTI found last time */
+ if( gti<0 || times[elem]<start[gti] || times[elem]>stop[gti] ) {
+ gti = Search_GTI( times[elem], nGTI, start, stop, ordered );
+ }
+ this->value.data.logptr[elem] = ( gti>=0 );
+ }
+ } else
+ while( elem-- ) {
+ this->value.data.logptr[elem] = 0;
+ this->value.undef[elem] = 0;
+ }
+ }
+ }
+
+ if( theExpr->operation>0 )
+ free( theExpr->value.data.ptr );
+}
+
+static long Search_GTI( double evtTime, long nGTI, double *start,
+ double *stop, int ordered )
+{
+ long gti, step;
+
+ if( ordered && nGTI>15 ) { /* If time-ordered and lots of GTIs, */
+ /* use "FAST" Binary search algorithm */
+ if( evtTime>=start[0] && evtTime<=stop[nGTI-1] ) {
+ gti = step = (nGTI >> 1);
+ while(1) {
+ if( step>1L ) step >>= 1;
+
+ if( evtTime>stop[gti] ) {
+ if( evtTime>=start[gti+1] )
+ gti += step;
+ else {
+ gti = -1L;
+ break;
+ }
+ } else if( evtTime<start[gti] ) {
+ if( evtTime<=stop[gti-1] )
+ gti -= step;
+ else {
+ gti = -1L;
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+ } else
+ gti = -1L;
+
+ } else { /* Use "SLOW" linear search */
+ gti = nGTI;
+ while( gti-- )
+ if( evtTime>=start[gti] && evtTime<=stop[gti] )
+ break;
+ }
+ return( gti );
+}
+
+static void Do_REG( Node *this )
+{
+ Node *theRegion, *theX, *theY;
+ double Xval=0.0, Yval=0.0;
+ char Xnull=0, Ynull=0;
+ int Xvector, Yvector;
+ long nelem, elem, rows;
+
+ theRegion = gParse.Nodes + this->SubNodes[0];
+ theX = gParse.Nodes + this->SubNodes[1];
+ theY = gParse.Nodes + this->SubNodes[2];
+
+ Xvector = ( theX->operation!=CONST_OP );
+ if( Xvector )
+ Xvector = theX->value.nelem;
+ else {
+ Xval = theX->value.data.dbl;
+ }
+
+ Yvector = ( theY->operation!=CONST_OP );
+ if( Yvector )
+ Yvector = theY->value.nelem;
+ else {
+ Yval = theY->value.data.dbl;
+ }
+
+ if( !Xvector && !Yvector ) {
+
+ this->value.data.log =
+ ( fits_in_region( Xval, Yval, (SAORegion *)theRegion->value.data.ptr )
+ != 0 );
+ this->operation = CONST_OP;
+
+ } else {
+
+ Allocate_Ptrs( this );
+
+ if( !gParse.status ) {
+
+ rows = gParse.nRows;
+ nelem = this->value.nelem;
+ elem = rows*nelem;
+
+ while( rows-- ) {
+ while( nelem-- ) {
+ elem--;
+
+ if( Xvector>1 ) {
+ Xval = theX->value.data.dblptr[elem];
+ Xnull = theX->value.undef[elem];
+ } else if( Xvector ) {
+ Xval = theX->value.data.dblptr[rows];
+ Xnull = theX->value.undef[rows];
+ }
+
+ if( Yvector>1 ) {
+ Yval = theY->value.data.dblptr[elem];
+ Ynull = theY->value.undef[elem];
+ } else if( Yvector ) {
+ Yval = theY->value.data.dblptr[rows];
+ Ynull = theY->value.undef[rows];
+ }
+
+ this->value.undef[elem] = ( Xnull || Ynull );
+ if( this->value.undef[elem] )
+ continue;
+
+ this->value.data.logptr[elem] =
+ ( fits_in_region( Xval, Yval,
+ (SAORegion *)theRegion->value.data.ptr )
+ != 0 );
+ }
+ nelem = this->value.nelem;
+ }
+ }
+ }
+
+ if( theX->operation>0 )
+ free( theX->value.data.ptr );
+ if( theY->operation>0 )
+ free( theY->value.data.ptr );
+}
+
+static void Do_Vector( Node *this )
+{
+ Node *that;
+ long row, elem, idx, jdx, offset=0;
+ int node;
+
+ Allocate_Ptrs( this );
+
+ if( !gParse.status ) {
+
+ for( node=0; node<this->nSubNodes; node++ ) {
+
+ that = gParse.Nodes + this->SubNodes[node];
+
+ if( that->operation == CONST_OP ) {
+
+ idx = gParse.nRows*this->value.nelem + offset;
+ while( (idx-=this->value.nelem)>=0 ) {
+
+ this->value.undef[idx] = 0;
+
+ switch( this->type ) {
+ case BOOLEAN:
+ this->value.data.logptr[idx] = that->value.data.log;
+ break;
+ case LONG:
+ this->value.data.lngptr[idx] = that->value.data.lng;
+ break;
+ case DOUBLE:
+ this->value.data.dblptr[idx] = that->value.data.dbl;
+ break;
+ }
+ }
+
+ } else {
+
+ row = gParse.nRows;
+ idx = row * that->value.nelem;
+ while( row-- ) {
+ elem = that->value.nelem;
+ jdx = row*this->value.nelem + offset;
+ while( elem-- ) {
+ this->value.undef[jdx+elem] =
+ that->value.undef[--idx];
+
+ switch( this->type ) {
+ case BOOLEAN:
+ this->value.data.logptr[jdx+elem] =
+ that->value.data.logptr[idx];
+ break;
+ case LONG:
+ this->value.data.lngptr[jdx+elem] =
+ that->value.data.lngptr[idx];
+ break;
+ case DOUBLE:
+ this->value.data.dblptr[jdx+elem] =
+ that->value.data.dblptr[idx];
+ break;
+ }
+ }
+ }
+ }
+ offset += that->value.nelem;
+ }
+
+ }
+
+ for( node=0; node < this->nSubNodes; node++ )
+ if( gParse.Nodes[this->SubNodes[node]].operation>0 )
+ free( gParse.Nodes[this->SubNodes[node]].value.data.ptr );
+}
+
+/*****************************************************************************/
+/* Utility routines which perform the calculations on bits and SAO regions */
+/*****************************************************************************/
+
+static char bitlgte(char *bits1, int oper, char *bits2)
+{
+ int val1, val2, nextbit;
+ char result;
+ int i, l1, l2, length, ldiff;
+ char stream[256];
+ char chr1, chr2;
+
+ l1 = strlen(bits1);
+ l2 = strlen(bits2);
+ if (l1 < l2)
+ {
+ length = l2;
+ ldiff = l2 - l1;
+ i=0;
+ while( ldiff-- ) stream[i++] = '0';
+ while( l1-- ) stream[i++] = *(bits1++);
+ stream[i] = '\0';
+ bits1 = stream;
+ }
+ else if (l2 < l1)
+ {
+ length = l1;
+ ldiff = l1 - l2;
+ i=0;
+ while( ldiff-- ) stream[i++] = '0';
+ while( l2-- ) stream[i++] = *(bits2++);
+ stream[i] = '\0';
+ bits2 = stream;
+ }
+ else
+ length = l1;
+
+ val1 = val2 = 0;
+ nextbit = 1;
+
+ while( length-- )
+ {
+ chr1 = bits1[length];
+ chr2 = bits2[length];
+ if ((chr1 != 'x')&&(chr1 != 'X')&&(chr2 != 'x')&&(chr2 != 'X'))
+ {
+ if (chr1 == '1') val1 += nextbit;
+ if (chr2 == '1') val2 += nextbit;
+ nextbit *= 2;
+ }
+ }
+ result = 0;
+ switch (oper)
+ {
+ case LT:
+ if (val1 < val2) result = 1;
+ break;
+ case LTE:
+ if (val1 <= val2) result = 1;
+ break;
+ case GT:
+ if (val1 > val2) result = 1;
+ break;
+ case GTE:
+ if (val1 >= val2) result = 1;
+ break;
+ }
+ return (result);
+}
+
+static void bitand(char *result,char *bitstrm1,char *bitstrm2)
+{
+ int i, l1, l2, ldiff;
+ char stream[256];
+ char chr1, chr2;
+
+ l1 = strlen(bitstrm1);
+ l2 = strlen(bitstrm2);
+ if (l1 < l2)
+ {
+ ldiff = l2 - l1;
+ i=0;
+ while( ldiff-- ) stream[i++] = '0';
+ while( l1-- ) stream[i++] = *(bitstrm1++);
+ stream[i] = '\0';
+ bitstrm1 = stream;
+ }
+ else if (l2 < l1)
+ {
+ ldiff = l1 - l2;
+ i=0;
+ while( ldiff-- ) stream[i++] = '0';
+ while( l2-- ) stream[i++] = *(bitstrm2++);
+ stream[i] = '\0';
+ bitstrm2 = stream;
+ }
+ while ( (chr1 = *(bitstrm1++)) )
+ {
+ chr2 = *(bitstrm2++);
+ if ((chr1 == 'x') || (chr2 == 'x'))
+ *result = 'x';
+ else if ((chr1 == '1') && (chr2 == '1'))
+ *result = '1';
+ else
+ *result = '0';
+ result++;
+ }
+ *result = '\0';
+}
+
+static void bitor(char *result,char *bitstrm1,char *bitstrm2)
+{
+ int i, l1, l2, ldiff;
+ char stream[256];
+ char chr1, chr2;
+
+ l1 = strlen(bitstrm1);
+ l2 = strlen(bitstrm2);
+ if (l1 < l2)
+ {
+ ldiff = l2 - l1;
+ i=0;
+ while( ldiff-- ) stream[i++] = '0';
+ while( l1-- ) stream[i++] = *(bitstrm1++);
+ stream[i] = '\0';
+ bitstrm1 = stream;
+ }
+ else if (l2 < l1)
+ {
+ ldiff = l1 - l2;
+ i=0;
+ while( ldiff-- ) stream[i++] = '0';
+ while( l2-- ) stream[i++] = *(bitstrm2++);
+ stream[i] = '\0';
+ bitstrm2 = stream;
+ }
+ while ( (chr1 = *(bitstrm1++)) )
+ {
+ chr2 = *(bitstrm2++);
+ if ((chr1 == '1') || (chr2 == '1'))
+ *result = '1';
+ else if ((chr1 == '0') || (chr2 == '0'))
+ *result = '0';
+ else
+ *result = 'x';
+ result++;
+ }
+ *result = '\0';
+}
+
+static void bitnot(char *result,char *bits)
+{
+ int length;
+ char chr;
+
+ length = strlen(bits);
+ while( length-- ) {
+ chr = *(bits++);
+ *(result++) = ( chr=='1' ? '0' : ( chr=='0' ? '1' : chr ) );
+ }
+ *result = '\0';
+}
+
+static char bitcmp(char *bitstrm1, char *bitstrm2)
+{
+ int i, l1, l2, ldiff;
+ char stream[256];
+ char chr1, chr2;
+
+ l1 = strlen(bitstrm1);
+ l2 = strlen(bitstrm2);
+ if (l1 < l2)
+ {
+ ldiff = l2 - l1;
+ i=0;
+ while( ldiff-- ) stream[i++] = '0';
+ while( l1-- ) stream[i++] = *(bitstrm1++);
+ stream[i] = '\0';
+ bitstrm1 = stream;
+ }
+ else if (l2 < l1)
+ {
+ ldiff = l1 - l2;
+ i=0;
+ while( ldiff-- ) stream[i++] = '0';
+ while( l2-- ) stream[i++] = *(bitstrm2++);
+ stream[i] = '\0';
+ bitstrm2 = stream;
+ }
+ while( (chr1 = *(bitstrm1++)) )
+ {
+ chr2 = *(bitstrm2++);
+ if ( ((chr1 == '0') && (chr2 == '1'))
+ || ((chr1 == '1') && (chr2 == '0')) )
+ return( 0 );
+ }
+ return( 1 );
+}
+
+static char bnear(double x, double y, double tolerance)
+{
+ if (fabs(x - y) < tolerance)
+ return ( 1 );
+ else
+ return ( 0 );
+}
+
+static char saobox(double xcen, double ycen, double xwid, double ywid,
+ double rot, double xcol, double ycol)
+{
+ double x,y,xprime,yprime,xmin,xmax,ymin,ymax,theta;
+
+ theta = (rot / 180.0) * myPI;
+ xprime = xcol - xcen;
+ yprime = ycol - ycen;
+ x = xprime * cos(theta) + yprime * sin(theta);
+ y = -xprime * sin(theta) + yprime * cos(theta);
+ xmin = - 0.5 * xwid; xmax = 0.5 * xwid;
+ ymin = - 0.5 * ywid; ymax = 0.5 * ywid;
+ if ((x >= xmin) && (x <= xmax) && (y >= ymin) && (y <= ymax))
+ return ( 1 );
+ else
+ return ( 0 );
+}
+
+static char circle(double xcen, double ycen, double rad,
+ double xcol, double ycol)
+{
+ double r2,dx,dy,dlen;
+
+ dx = xcol - xcen;
+ dy = ycol - ycen;
+ dx *= dx; dy *= dy;
+ dlen = dx + dy;
+ r2 = rad * rad;
+ if (dlen <= r2)
+ return ( 1 );
+ else
+ return ( 0 );
+}
+
+static char ellipse(double xcen, double ycen, double xrad, double yrad,
+ double rot, double xcol, double ycol)
+{
+ double x,y,xprime,yprime,dx,dy,dlen,theta;
+
+ theta = (rot / 180.0) * myPI;
+ xprime = xcol - xcen;
+ yprime = ycol - ycen;
+ x = xprime * cos(theta) + yprime * sin(theta);
+ y = -xprime * sin(theta) + yprime * cos(theta);
+ dx = x / xrad; dy = y / yrad;
+ dx *= dx; dy *= dy;
+ dlen = dx + dy;
+ if (dlen <= 1.0)
+ return ( 1 );
+ else
+ return ( 0 );
+}
+
+static void fferror(char *s)
+{
+ char msg[80];
+
+ if( !gParse.status ) gParse.status = PARSE_SYNTAX_ERR;
+
+ strncpy(msg, s, 80);
+ msg[79] = '\0';
+ ffpmsg(msg);
+}
diff --git a/pkg/tbtables/cfitsio/f77.inc b/pkg/tbtables/cfitsio/f77.inc
new file mode 100644
index 00000000..51e05e49
--- /dev/null
+++ b/pkg/tbtables/cfitsio/f77.inc
@@ -0,0 +1,31 @@
+C Codes for FITS extension types
+ integer IMAGE_HDU, ASCII_TBL, BINARY_TBL
+ parameter (
+ & IMAGE_HDU = 0,
+ & ASCII_TBL = 1,
+ & BINARY_TBL = 2 )
+
+C Codes for FITS table data types
+
+ integer TBIT,TBYTE,TLOGICAL,TSTRING,TSHORT,TINT
+ integer TFLOAT,TDOUBLE,TCOMPLEX,TDBLCOMPLEX
+ parameter (
+ & TBIT = 1,
+ & TBYTE = 11,
+ & TLOGICAL = 14,
+ & TSTRING = 16,
+ & TSHORT = 21,
+ & TINT = 31,
+ & TFLOAT = 42,
+ & TDOUBLE = 82,
+ & TCOMPLEX = 83,
+ & TDBLCOMPLEX = 163 )
+
+C Codes for iterator column types
+
+ integer InputCol, InputOutputCol, OutputCol
+ parameter (
+ & InputCol = 0,
+ & InputOutputCol = 1,
+ & OutputCol = 2 )
+
diff --git a/pkg/tbtables/cfitsio/f77_wrap.h b/pkg/tbtables/cfitsio/f77_wrap.h
new file mode 100644
index 00000000..c197167d
--- /dev/null
+++ b/pkg/tbtables/cfitsio/f77_wrap.h
@@ -0,0 +1,278 @@
+#define UNSIGNED_BYTE
+#include "cfortran.h"
+
+/************************************************************************
+ DEC C creates longs as 8-byte integers. On most other machines, ints
+ and longs are both 4-bytes, so both are compatible with Fortrans
+ default integer which is 4-bytes. To support DECs, we must redefine
+ LONGs and convert them to 8-bytes when going to C, and restore them
+ to 4-bytes when returning to Fortran. Ugh!!!
+*************************************************************************/
+
+#if defined(DECFortran) || (defined(__alpha) && defined(g77Fortran)) \
+ || (defined(mipsFortran) && _MIPS_SZLONG==64) \
+ || (defined(IBMR2Fortran) && defined(__64BIT__))
+#undef LONGV_cfSTR
+#undef PLONG_cfSTR
+#undef LONGVVVVVVV_cfTYPE
+#undef PLONG_cfTYPE
+#undef LONGV_cfT
+#undef PLONG_cfT
+
+#define LONGV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,LONGV,A,B,C,D,E)
+#define PLONG_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,PLONG,A,B,C,D,E)
+#define LONGVVVVVVV_cfTYPE int
+#define PLONG_cfTYPE int
+#define LONGV_cfQ(B) long *B, _(B,N);
+#define PLONG_cfQ(B) long B;
+#define LONGV_cfT(M,I,A,B,D) ( (_(B,N) = * _3(M,_LONGV_A,I)), \
+ B = F2Clongv(_(B,N),A) )
+#define PLONG_cfT(M,I,A,B,D) ((B=*A),&B)
+#define LONGV_cfR(A,B,D) C2Flongv(_(B,N),A,B);
+#define PLONG_cfR(A,B,D) *A=B;
+#define LONGV_cfH(S,U,B)
+#define PLONG_cfH(S,U,B)
+
+static long *F2Clongv(long size, int *A)
+{
+ long i;
+ long *B;
+
+ B=(long *)malloc( size*sizeof(long) );
+ for(i=0;i<size;i++) B[i]=A[i];
+ return(B);
+}
+
+static void C2Flongv(long size, int *A, long *B)
+{
+ long i;
+
+ for(i=0;i<size;i++) A[i]=B[i];
+ free(B);
+}
+
+#endif
+
+/************************************************************************
+ Modify cfortran.h's handling of strings. C interprets a "char **"
+ parameter as an array of pointers to the strings (or as a handle),
+ not as a pointer to a block of contiguous strings. Also set a
+ a minimum length for string allocations, to minimize risk of
+ overflow.
+*************************************************************************/
+
+extern unsigned long gMinStrLen;
+
+#undef STRINGV_cfQ
+#undef STRINGV_cfR
+#undef TTSTR
+#undef TTTTSTRV
+#undef RRRRPSTRV
+
+#undef PPSTRING_cfT
+
+#ifdef vmsFortran
+#define PPSTRING_cfT(M,I,A,B,D) (unsigned char*)A->dsc$a_pointer
+
+/* We want single strings to be equivalent to string vectors with */
+/* a single element, so ignore the number of elements info in the */
+/* vector structure, and rely on the NUM_ELEM definitions. */
+
+#undef STRINGV_cfT
+#define STRINGV_cfT(M,I,A,B,D) TTTTSTRV(A->dsc$a_pointer, B, \
+ A->dsc$w_length, \
+ num_elem(A->dsc$a_pointer, \
+ A->dsc$w_length, \
+ _3(M,_STRV_A,I) ) )
+#else
+#ifdef CRAYFortran
+#define PPSTRING_cfT(M,I,A,B,D) (unsigned char*)_fcdtocp(A)
+#else
+#define PPSTRING_cfT(M,I,A,B,D) (unsigned char*)A
+#endif
+#endif
+
+#define _cfMAX(A,B) ( (A>B) ? A : B )
+#define STRINGV_cfQ(B) char **B; unsigned int _(B,N), _(B,M);
+#define STRINGV_cfR(A,B,D) free(B[0]); free(B);
+#define TTSTR( A,B,D) \
+ ((B=(char*)malloc(_cfMAX(D,gMinStrLen)+1))[D]='\0',memcpy(B,A,D), \
+ kill_trailing(B,' '))
+#define TTTTSTRV( A,B,D,E) ( \
+ _(B,N)=_cfMAX(E,1), \
+ _(B,M)=_cfMAX(D,gMinStrLen)+1, \
+ B=(char**)malloc(_(B,N)*sizeof(char*)), \
+ B[0]=(char*)malloc(_(B,N)*_(B,M)), \
+ vindex(B,_(B,M),_(B,N),f2cstrv2(A,B[0],D,_(B,M),_(B,N))) \
+ )
+#define RRRRPSTRV(A,B,D) \
+ c2fstrv2(B[0],A,_(B,M),D,_(B,N)), \
+ free(B[0]), \
+ free(B);
+
+static char **vindex(char **B, int elem_len, int nelem, char *B0)
+{
+ int i;
+ if( nelem )
+ for( i=0;i<nelem;i++ ) B[i] = B0+i*elem_len;
+ return B;
+}
+
+static char *c2fstrv2(char* cstr, char *fstr, int celem_len, int felem_len,
+ int nelem)
+{
+ int i,j;
+
+ if( nelem )
+ for (i=0; i<nelem; i++) {
+ for (j=0; j<felem_len && *cstr; j++) *fstr++ = *cstr++;
+ cstr += celem_len-j;
+ for (; j<felem_len; j++) *fstr++ = ' ';
+ }
+ return( fstr-felem_len*nelem );
+}
+
+static char *f2cstrv2(char *fstr, char* cstr, int felem_len, int celem_len,
+ int nelem)
+{
+ int i,j;
+
+ if( nelem )
+ for (i=0; i<nelem; i++, cstr+=(celem_len-felem_len)) {
+ for (j=0; j<felem_len; j++) *cstr++ = *fstr++;
+ *cstr='\0';
+ kill_trailingn( cstr-felem_len, ' ', cstr );
+ }
+ return( cstr-celem_len*nelem );
+}
+
+/************************************************************************
+ The following definitions redefine the BYTE data type to be
+ interpretted as a character*1 string instead of an integer*1 which
+ is not supported by all compilers.
+*************************************************************************/
+
+#undef BYTE_cfT
+#undef BYTEV_cfT
+#undef BYTE_cfINT
+#undef BYTEV_cfINT
+#undef BYTE_cfSTR
+#undef BYTEV_cfSTR
+
+#define BYTE_cfINT(N,A,B,X,Y,Z) _(CFARGS,N)(A,BYTE,B,X,Y,Z,0)
+#define BYTEV_cfINT(N,A,B,X,Y,Z) _(CFARGS,N)(A,BYTEV,B,X,Y,Z,0)
+#define BYTE_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,BYTE,A,B,C,D,E)
+#define BYTEV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,BYTEV,A,B,C,D,E)
+#define BYTE_cfSEP(T,B) INT_cfSEP(T,B)
+#define BYTEV_cfSEP(T,B) INT_cfSEP(T,B)
+#define BYTE_cfH(S,U,B) STRING_cfH(S,U,B)
+#define BYTEV_cfH(S,U,B) STRING_cfH(S,U,B)
+#define BYTE_cfQ(B)
+#define BYTEV_cfQ(B)
+#define BYTE_cfR(A,B,D)
+#define BYTEV_cfR(A,B,D)
+
+#ifdef vmsFortran
+#define BYTE_cfN(T,A) fstring * A
+#define BYTEV_cfN(T,A) fstringvector * A
+#define BYTE_cfT(M,I,A,B,D) (INTEGER_BYTE)((A->dsc$a_pointer)[0])
+#define BYTEV_cfT(M,I,A,B,D) (INTEGER_BYTE*)A->dsc$a_pointer
+#else
+#ifdef CRAYFortran
+#define BYTE_cfN(T,A) _fcd A
+#define BYTEV_cfN(T,A) _fcd A
+#define BYTE_cfT(M,I,A,B,D) (INTEGER_BYTE)((_fcdtocp(A))[0])
+#define BYTEV_cfT(M,I,A,B,D) (INTEGER_BYTE*)_fcdtocp(A)
+#else
+#define BYTE_cfN(T,A) INTEGER_BYTE * A
+#define BYTEV_cfN(T,A) INTEGER_BYTE * A
+#define BYTE_cfT(M,I,A,B,D) A[0]
+#define BYTEV_cfT(M,I,A,B,D) A
+#endif
+#endif
+
+/************************************************************************
+ The following definitions and functions handle conversions between
+ C and Fortran arrays of LOGICALS. Individually, LOGICALS are
+ treated as int's but as char's when in an array. cfortran defines
+ (F2C/C2F)LOGICALV but never uses them, so these routines also
+ handle TRUE/FALSE conversions.
+*************************************************************************/
+
+#undef LOGICALV_cfSTR
+#undef LOGICALV_cfT
+#define LOGICALV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,LOGICALV,A,B,C,D,E)
+#define LOGICALV_cfQ(B) char *B; unsigned int _(B,N);
+#define LOGICALV_cfT(M,I,A,B,D) (_(B,N)= * _3(M,_LOGV_A,I), \
+ B=F2CcopyLogVect(_(B,N),A))
+#define LOGICALV_cfR(A,B,D) C2FcopyLogVect(_(B,N),A,B);
+#define LOGICALV_cfH(S,U,B)
+
+static char *F2CcopyLogVect(long size, int *A)
+{
+ long i;
+ char *B;
+
+ B=(char *)malloc(size*sizeof(char));
+ for( i=0; i<size; i++ ) B[i]=F2CLOGICAL(A[i]);
+ return(B);
+}
+
+static void C2FcopyLogVect(long size, int *A, char *B)
+{
+ long i;
+
+ for( i=0; i<size; i++ ) A[i]=C2FLOGICAL(B[i]);
+ free(B);
+}
+
+/*------------------ Fortran File Handling ----------------------*/
+/* Fortran uses unit numbers, whereas C uses file pointers, so */
+/* a global array of file pointers is setup in which Fortran's */
+/* unit number serves as the index. Two FITSIO routines are */
+/* the integer unit number and the fitsfile file pointer. */
+/*-----------------------------------------------------------------*/
+
+#define MAXFITSFILES 200 /* Array of file pointers indexed */
+extern fitsfile *gFitsFiles[]; /* by Fortran unit numbers */
+
+#define FITSUNIT_cfINT(N,A,B,X,Y,Z) INT_cfINT(N,A,B,X,Y,Z)
+#define FITSUNIT_cfSTR(N,T,A,B,C,D,E) INT_cfSTR(N,T,A,B,C,D,E)
+#define FITSUNIT_cfT(M,I,A,B,D) gFitsFiles[*A]
+#define FITSUNITVVVVVVV_cfTYPE int
+#define PFITSUNIT_cfINT(N,A,B,X,Y,Z) PINT_cfINT(N,A,B,X,Y,Z)
+#define PFITSUNIT_cfSTR(N,T,A,B,C,D,E) PINT_cfSTR(N,T,A,B,C,D,E)
+#define PFITSUNIT_cfT(M,I,A,B,D) (gFitsFiles + *A)
+#define PFITSUNIT_cfTYPE int
+
+
+/*---------------------- Make C++ Happy -----------------------------*/
+/* Redefine FCALLSCFUNn so that they create prototypes of themselves */
+/* and change TTTTSTR to use (char *)0 instead of NULL */
+/*-------------------------------------------------------------------*/
+
+#undef FCALLSCFUN0
+#undef FCALLSCFUN14
+#undef TTTTSTR
+
+#define TTTTSTR(A,B,D) ( !(D<4||A[0]||A[1]||A[2]||A[3]) ) ? ((char*)0) : \
+ memchr(A,'\0',D) ? A : TTSTR(A,B,D)
+
+#define FCALLSCFUN0(T0,CN,UN,LN) \
+ CFextern _(T0,_cfFZ)(UN,LN) void ABSOFT_cf2(T0)); \
+ CFextern _(T0,_cfFZ)(UN,LN) void ABSOFT_cf2(T0)) \
+ {_Icf(2,UU,T0,A0,0); _Icf(0,L,T0,0,0) CN(); _Icf(0,K,T0,0,0) _(T0,_cfI)}
+
+#define FCALLSCFUN14(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE) \
+ CFextern _(T0,_cfF)(UN,LN) \
+ CFARGT14(NCF,DCF,ABSOFT_cf2(T0),T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)); \
+ CFextern _(T0,_cfF)(UN,LN) \
+ CFARGT14(NCF,DCF,ABSOFT_cf2(T0),T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)) \
+ { CFARGT14S(QCF,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE) \
+ _Icf(2,UU,T0,A0,0); _Icf(0,L,T0,0,0) CN( TCF(LN,T1,1,0) TCF(LN,T2,2,1) \
+ TCF(LN,T3,3,1) TCF(LN,T4,4,1) TCF(LN,T5,5,1) TCF(LN,T6,6,1) TCF(LN,T7,7,1) \
+ TCF(LN,T8,8,1) TCF(LN,T9,9,1) TCF(LN,TA,A,1) TCF(LN,TB,B,1) TCF(LN,TC,C,1) \
+ TCF(LN,TD,D,1) TCF(LN,TE,E,1) ); _Icf(0,K,T0,0,0) \
+ CFARGT14S(RCF,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE) _(T0,_cfI) \
+ }
+
diff --git a/pkg/tbtables/cfitsio/f77_wrap1.c b/pkg/tbtables/cfitsio/f77_wrap1.c
new file mode 100644
index 00000000..4e466cb7
--- /dev/null
+++ b/pkg/tbtables/cfitsio/f77_wrap1.c
@@ -0,0 +1,960 @@
+/************************************************************************
+ Together, f77_wrap1.c and f77_wrap2.c contain C wrappers for all
+ the CFITSIO routines prototyped in fitsio.h, except for the
+ generic datatype routines and features not supported in fortran
+ (eg, unsigned integers), a few routines prototyped in fitsio2.h,
+ which only a handful of FTOOLS use, plus a few obsolete FITSIO
+ routines not present in CFITSIO. This file allows Fortran code
+ to use the CFITSIO library instead of the FITSIO library without
+ modification. It also gives access to new routines not present
+ in FITSIO. Fortran FTOOLS must continue using the old routine
+ names from FITSIO (ie, ftxxxx), but most of the C-wrappers simply
+ redirect those calls to the corresponding CFITSIO routines (ie,
+ ffxxxx), with appropriate parameter massaging where necessary.
+ The main exception are read/write routines ending in j (ie, long
+ data) which get redirected to C routines ending in k (ie, int
+ data). This is more consistent with the default integer type in
+ Fortran. f77_wrap1.c primarily holds routines operating on whole
+ files and extension headers. f77_wrap2.c handle routines which
+ read and write the data portion, plus miscellaneous extra routines.
+
+ File created by Peter Wilson (HSTX), Oct-Dec. 1997
+************************************************************************/
+
+#include "fitsio2.h"
+#include "f77_wrap.h"
+
+unsigned long gMinStrLen=80L;
+fitsfile *gFitsFiles[MAXFITSFILES]={0};
+
+/*---------------- Fortran Unit Number Allocation -------------*/
+
+void Cffgiou( int *unit, int *status );
+void Cffgiou( int *unit, int *status )
+{
+ int i;
+
+ if( *status>0 ) return;
+ for( i=50;i<MAXFITSFILES;i++ ) /* Using a unit=0 sounds bad, so start at 1 */
+ if( gFitsFiles[i]==NULL ) break;
+ if( i==MAXFITSFILES ) {
+ *unit = 0;
+ *status = TOO_MANY_FILES;
+ ffpmsg("Cffgiou has no more available unit numbers.");
+ } else {
+ *unit=i;
+ gFitsFiles[i] = (fitsfile *)1; /* Flag it as taken until ftopen/init */
+ /* can be called and set a real value */
+ }
+}
+FCALLSCSUB2(Cffgiou,FTGIOU,ftgiou,PINT,PINT)
+
+void Cfffiou( int unit, int *status );
+void Cfffiou( int unit, int *status )
+{
+ if( *status>0 ) return;
+ if( unit == -1 ) {
+ int i; for( i=50; i<MAXFITSFILES; ) gFitsFiles[i++]=NULL;
+ } else if( unit<1 || unit>=MAXFITSFILES ) {
+ *status = BAD_FILEPTR;
+ ffpmsg("Cfffiou was sent an unacceptable unit number.");
+ } else gFitsFiles[unit]=NULL;
+}
+FCALLSCSUB2(Cfffiou,FTFIOU,ftfiou,INT,PINT)
+
+
+int CFits2Unit( fitsfile *fptr );
+int CFits2Unit( fitsfile *fptr )
+ /* Utility routine to convert a fitspointer to a Fortran unit number */
+ /* for use when a C program is calling a Fortran routine which could */
+ /* in turn call CFITSIO... Modelled after code by Ning Gan. */
+{
+ static fitsfile *last_fptr = (fitsfile *)NULL; /* Remember last fptr */
+ static int last_unit = 0; /* Remember last unit */
+ int status = 0;
+
+ /* Test whether we are repeating the last lookup */
+
+ if( last_unit && fptr==gFitsFiles[last_unit] )
+ return( last_unit );
+
+ /* Check if gFitsFiles has an entry for this fptr. */
+ /* Allows Fortran to call C to call Fortran to */
+ /* call CFITSIO... OUCH!!! */
+
+ last_fptr = fptr;
+ for( last_unit=1; last_unit<MAXFITSFILES; last_unit++ ) {
+ if( fptr == gFitsFiles[last_unit] )
+ return( last_unit );
+ }
+
+ /* Allocate a new unit number for this fptr */
+ Cffgiou( &last_unit, &status );
+ if( status )
+ last_unit = 0;
+ else
+ gFitsFiles[last_unit] = fptr;
+ return( last_unit );
+}
+
+ /**************************************************/
+ /* Start of wrappers for routines in fitsio.h */
+ /**************************************************/
+
+/*---------------- FITS file URL parsing routines -------------*/
+
+FCALLSCSUB9(ffiurl,FTIURL,ftiurl,STRING,PSTRING,PSTRING,PSTRING,PSTRING,PSTRING,PSTRING,PSTRING,PINT)
+FCALLSCSUB3(ffrtnm,FTRTNM,ftrtnm,STRING,PSTRING,PINT)
+FCALLSCSUB3(ffextn,FTEXTN,ftextn,STRING,PINT,PINT)
+
+/*---------------- FITS file I/O routines ---------------*/
+
+void Cffopen( fitsfile **fptr, const char *filename, int iomode, int *blocksize, int *status );
+void Cffopen( fitsfile **fptr, const char *filename, int iomode, int *blocksize, int *status )
+{
+ int hdutype;
+
+ if( *fptr==NULL || *fptr==(fitsfile*)1 ) {
+ ffopen( fptr, filename, iomode, status );
+ ffmahd( *fptr, 1, &hdutype, status );
+ *blocksize = 1;
+ } else {
+ *status = FILE_NOT_OPENED;
+ ffpmsg("Cffopen tried to use an already opened unit.");
+ }
+}
+FCALLSCSUB5(Cffopen,FTOPEN,ftopen,PFITSUNIT,STRING,INT,PINT,PINT)
+
+void Cffnopn( fitsfile **fptr, const char *filename, int iomode, int *status );
+void Cffnopn( fitsfile **fptr, const char *filename, int iomode, int *status )
+{
+ if( *fptr==NULL || *fptr==(fitsfile*)1 ) {
+ ffopen( fptr, filename, iomode, status );
+ } else {
+ *status = FILE_NOT_OPENED;
+ ffpmsg("Cffnopn tried to use an already opened unit.");
+ }
+}
+FCALLSCSUB4(Cffnopn,FTNOPN,ftnopn,PFITSUNIT,STRING,INT,PINT)
+
+void Cffreopen( fitsfile *openfptr, fitsfile **newfptr, int *status );
+void Cffreopen( fitsfile *openfptr, fitsfile **newfptr, int *status )
+{
+ if( *newfptr==NULL || *newfptr==(fitsfile*)1 ) {
+ ffreopen( openfptr, newfptr, status );
+ } else {
+ *status = FILE_NOT_OPENED;
+ ffpmsg("Cffreopen tried to use an already opened unit.");
+ }
+}
+FCALLSCSUB3(Cffreopen,FTREOPEN,ftreopen,FITSUNIT,PFITSUNIT,PINT)
+
+void Cffinit( fitsfile **fptr, const char *filename, int blocksize, int *status );
+void Cffinit( fitsfile **fptr, const char *filename, int blocksize, int *status )
+{
+ if( *fptr==NULL || *fptr==(fitsfile*)1 ) {
+ ffinit( fptr, filename, status );
+ } else {
+ *status = FILE_NOT_CREATED;
+ ffpmsg("Cffinit tried to use an already opened unit.");
+ }
+}
+FCALLSCSUB4(Cffinit,FTINIT,ftinit,PFITSUNIT,STRING,INT,PINT)
+
+void Cfftplt( fitsfile **fptr, const char *filename, const char *tempname,
+ int *status );
+void Cfftplt( fitsfile **fptr, const char *filename, const char *tempname,
+ int *status )
+{
+ if( *fptr==NULL || *fptr==(fitsfile*)1 ) {
+ fftplt( fptr, filename, tempname, status );
+ } else {
+ *status = FILE_NOT_CREATED;
+ ffpmsg("Cfftplt tried to use an already opened unit.");
+ }
+}
+FCALLSCSUB4(Cfftplt,FTTPLT,fttplt,PFITSUNIT,STRING,STRING,PINT)
+
+FCALLSCSUB2(ffflus,FTFLUS,ftflus,FITSUNIT,PINT)
+
+void Cffclos( int unit, int *status );
+void Cffclos( int unit, int *status )
+{
+ if( gFitsFiles[unit]!=NULL && gFitsFiles[unit]!=(void*)1 ) {
+ ffclos( gFitsFiles[unit], status ); /* Flag unit number as unavailable */
+ gFitsFiles[unit]=(fitsfile*)1; /* in case want to reuse it */
+ }
+}
+FCALLSCSUB2(Cffclos,FTCLOS,ftclos,INT,PINT)
+
+void Cffdelt( int unit, int *status );
+void Cffdelt( int unit, int *status )
+{
+ if( gFitsFiles[unit]!=NULL && gFitsFiles[unit]!=(void*)1 ) {
+ ffdelt( gFitsFiles[unit], status ); /* Flag unit number as unavailable */
+ gFitsFiles[unit]=(fitsfile*)1; /* in case want to reuse it */
+ }
+}
+FCALLSCSUB2(Cffdelt,FTDELT,ftdelt,INT,PINT)
+
+FCALLSCSUB3(ffflnm,FTFLNM,ftflnm,FITSUNIT,PSTRING,PINT)
+FCALLSCSUB3(ffflmd,FTFLMD,ftflmd,FITSUNIT,PINT,PINT)
+
+/*--------------- utility routines ---------------*/
+FCALLSCSUB1(ffvers,FTVERS,ftvers,PFLOAT)
+FCALLSCSUB1(ffupch,FTUPCH,ftupch,PSTRING)
+FCALLSCSUB2(ffgerr,FTGERR,ftgerr,INT,PSTRING)
+FCALLSCSUB1(ffpmsg,FTPMSG,ftpmsg,STRING)
+FCALLSCSUB1(ffgmsg,FTGMSG,ftgmsg,PSTRING)
+FCALLSCSUB0(ffcmsg,FTCMSG,ftcmsg)
+
+void Cffrprt( char *fname, int status );
+void Cffrprt( char *fname, int status )
+{
+ if( !strcmp(fname,"STDOUT") || !strcmp(fname,"stdout") )
+ ffrprt( stdout, status );
+ else if( !strcmp(fname,"STDERR") || !strcmp(fname,"stderr") )
+ ffrprt( stderr, status );
+ else {
+ FILE *fptr;
+
+ fptr = fopen(fname, "a");
+ if (fptr==NULL)
+ printf("file pointer is null.\n");
+ else {
+ ffrprt(fptr,status);
+ fclose(fptr);
+ }
+ }
+}
+FCALLSCSUB2(Cffrprt,FTRPRT,ftrprt,STRING,INT)
+
+FCALLSCSUB5(ffcmps,FTCMPS,ftcmps,STRING,STRING,LOGICAL,PLOGICAL,PLOGICAL)
+FCALLSCSUB2(fftkey,FTTKEY,fttkey,STRING,PINT)
+FCALLSCSUB2(fftrec,FTTREC,fttrec,STRING,PINT)
+FCALLSCSUB2(ffnchk,FTNCHK,ftnchk,FITSUNIT,PINT)
+FCALLSCSUB4(ffkeyn,FTKEYN,ftkeyn,STRING,INT,PSTRING,PINT)
+FCALLSCSUB4(ffgknm,FTGKNM,ftgknm,STRING,PSTRING, PINT, PINT)
+FCALLSCSUB4(ffnkey,FTNKEY,ftnkey,INT,STRING,PSTRING,PINT)
+FCALLSCSUB3(ffdtyp,FTDTYP,ftdtyp,STRING,PSTRING,PINT)
+FCALLSCFUN1(INT,ffgkcl,FTGKCL,ftgkcl,STRING)
+FCALLSCSUB4(ffpsvc,FTPSVC,ftpsvc,STRING,PSTRING,PSTRING,PINT)
+FCALLSCSUB4(ffgthd,FTGTHD,ftgthd,STRING,PSTRING,PINT,PINT)
+FCALLSCSUB5(ffasfm,FTASFM,ftasfm,STRING,PINT,PLONG,PINT,PINT)
+FCALLSCSUB5(ffbnfm,FTBNFM,ftbnfm,STRING,PINT,PLONG,PLONG,PINT)
+
+#define ftgabc_STRV_A2 NUM_ELEM_ARG(1)
+#define ftgabc_LONGV_A5 A1
+FCALLSCSUB6(ffgabc,FTGABC,ftgabc,INT,STRINGV,INT,PLONG,LONGV,PINT)
+
+/*----------------- write single keywords --------------*/
+FCALLSCSUB3(ffprec,FTPREC,ftprec,FITSUNIT,STRING,PINT)
+FCALLSCSUB3(ffpcom,FTPCOM,ftpcom,FITSUNIT,STRING,PINT)
+FCALLSCSUB4(ffpunt,FTPUNT,ftpunt,FITSUNIT,STRING,STRING,PINT)
+FCALLSCSUB3(ffphis,FTPHIS,ftphis,FITSUNIT,STRING,PINT)
+FCALLSCSUB2(ffpdat,FTPDAT,ftpdat,FITSUNIT,PINT)
+FCALLSCSUB3(ffgstm,FTGSTM,ftgstm,PSTRING,PINT,PINT)
+FCALLSCSUB4(ffgsdt,FTGSDT,ftgsdt,PINT,PINT,PINT,PINT)
+FCALLSCSUB5(ffdt2s,FTDT2S,ftdt2s,INT,INT,INT,PSTRING,PINT)
+FCALLSCSUB9(fftm2s,FTTM2S,fttm2s,INT,INT,INT,INT,INT,DOUBLE,INT,PSTRING,PINT)
+FCALLSCSUB5(ffs2dt,FTS2DT,fts2dt,STRING,PINT,PINT,PINT,PINT)
+FCALLSCSUB8(ffs2tm,FTS2TM,fts2tm,STRING,PINT,PINT,PINT,PINT,PINT,PDOUBLE,PINT)
+FCALLSCSUB4(ffpkyu,FTPKYU,ftpkyu,FITSUNIT,STRING,STRING,PINT)
+FCALLSCSUB5(ffpkys,FTPKYS,ftpkys,FITSUNIT,STRING,STRING,STRING,PINT)
+FCALLSCSUB5(ffpkls,FTPKLS,ftpkls,FITSUNIT,STRING,STRING,STRING,PINT)
+FCALLSCSUB2(ffplsw,FTPLSW,ftplsw,FITSUNIT,PINT)
+FCALLSCSUB5(ffpkyl,FTPKYL,ftpkyl,FITSUNIT,STRING,INT,STRING,PINT)
+FCALLSCSUB5(ffpkyj,FTPKYJ,ftpkyj,FITSUNIT,STRING,LONG,STRING,PINT)
+FCALLSCSUB6(ffpkyf,FTPKYF,ftpkyf,FITSUNIT,STRING,FLOAT,INT,STRING,PINT)
+FCALLSCSUB6(ffpkye,FTPKYE,ftpkye,FITSUNIT,STRING,FLOAT,INT,STRING,PINT)
+FCALLSCSUB6(ffpkyg,FTPKYG,ftpkyg,FITSUNIT,STRING,DOUBLE,INT,STRING,PINT)
+FCALLSCSUB6(ffpkyd,FTPKYD,ftpkyd,FITSUNIT,STRING,DOUBLE,INT,STRING,PINT)
+FCALLSCSUB6(ffpkyc,FTPKYC,ftpkyc,FITSUNIT,STRING,FLOATV,INT,STRING,PINT)
+FCALLSCSUB6(ffpkym,FTPKYM,ftpkym,FITSUNIT,STRING,DOUBLEV,INT,STRING,PINT)
+FCALLSCSUB6(ffpkfc,FTPKFC,ftpkfc,FITSUNIT,STRING,FLOATV,INT,STRING,PINT)
+FCALLSCSUB6(ffpkfm,FTPKFM,ftpkfm,FITSUNIT,STRING,DOUBLEV,INT,STRING,PINT)
+FCALLSCSUB6(ffpkyt,FTPKYT,ftpkyt,FITSUNIT,STRING,LONG,DOUBLE,STRING,PINT)
+
+#define ftptdm_LONGV_A4 A3
+FCALLSCSUB5(ffptdm,FTPTDM,ftptdm,FITSUNIT,INT,INT,LONGV,PINT)
+
+/*----------------- write array of keywords --------------*/
+#define ftpkns_STRV_A5 NUM_ELEM_ARG(4)
+#define ftpkns_STRV_A6 NUM_ELEM_ARG(4)
+FCALLSCSUB7(ffpkns,FTPKNS,ftpkns,FITSUNIT,STRING,INT,INT,STRINGV,STRINGV,PINT)
+
+/* Must handle LOGICALV conversion manually... ffpknl uses ints */
+void Cffpknl( fitsfile *fptr, char *keyroot, int nstart, int nkeys,
+ int *numval, char **comment, int *status );
+void Cffpknl( fitsfile *fptr, char *keyroot, int nstart, int nkeys,
+ int *numval, char **comment, int *status )
+{
+ int i;
+
+ for( i=0; i<nkeys; i++ )
+ numval[i] = F2CLOGICAL(numval[i]);
+ ffpknl( fptr, keyroot, nstart, nkeys, numval, comment, status );
+ for( i=0; i<nkeys; i++ )
+ numval[i] = C2FLOGICAL(numval[i]);
+}
+#define ftpknl_STRV_A6 NUM_ELEM_ARG(4)
+FCALLSCSUB7(Cffpknl,FTPKNL,ftpknl,FITSUNIT,STRING,INT,INT,INTV,STRINGV,PINT)
+
+#define ftpknj_STRV_A6 NUM_ELEM_ARG(4)
+#define ftpknj_LONGV_A5 A4
+FCALLSCSUB7(ffpknj,FTPKNJ,ftpknj,FITSUNIT,STRING,INT,INT,LONGV,STRINGV,PINT)
+
+#define ftpknf_STRV_A7 NUM_ELEM_ARG(4)
+FCALLSCSUB8(ffpknf,FTPKNF,ftpknf,FITSUNIT,STRING,INT,INT,FLOATV,INT,STRINGV,PINT)
+
+#define ftpkne_STRV_A7 NUM_ELEM_ARG(4)
+FCALLSCSUB8(ffpkne,FTPKNE,ftpkne,FITSUNIT,STRING,INT,INT,FLOATV,INT,STRINGV,PINT)
+
+#define ftpkng_STRV_A7 NUM_ELEM_ARG(4)
+FCALLSCSUB8(ffpkng,FTPKNG,ftpkng,FITSUNIT,STRING,INT,INT,DOUBLEV,INT,STRINGV,PINT)
+
+#define ftpknd_STRV_A7 NUM_ELEM_ARG(4)
+FCALLSCSUB8(ffpknd,FTPKND,ftpknd,FITSUNIT,STRING,INT,INT,DOUBLEV,INT,STRINGV,PINT)
+
+FCALLSCSUB6(ffcpky,FTCPKY,ftcpky,FITSUNIT,FITSUNIT,INT,INT,STRING,PINT)
+
+/*----------------- write required header keywords --------------*/
+#define ftphps_LONGV_A4 A3
+FCALLSCSUB5(ffphps,FTPHPS,ftphps,FITSUNIT,INT,INT,LONGV,PINT)
+
+void Cffphpr( fitsfile *fptr, int simple, int bitpix, int naxis, long naxes[], long pcount, long gcount, int extend, int *status );
+void Cffphpr( fitsfile *fptr, int simple, int bitpix, int naxis, long naxes[], long pcount, long gcount, int extend, int *status )
+{
+ if( gcount==0 ) gcount=1;
+ ffphpr( fptr, simple, bitpix, naxis, naxes, pcount,
+ gcount, extend, status );
+}
+#define ftphpr_LONGV_A5 A4
+FCALLSCSUB9(Cffphpr,FTPHPR,ftphpr,FITSUNIT,LOGICAL,INT,INT,LONGV,LONG,LONG,LOGICAL,PINT)
+
+
+#define ftphtb_STRV_A5 NUM_ELEM_ARG(4)
+#define ftphtb_STRV_A7 NUM_ELEM_ARG(4)
+#define ftphtb_STRV_A8 NUM_ELEM_ARG(4)
+#define ftphtb_LONGV_A6 A4
+FCALLSCSUB10(ffphtb,FTPHTB,ftphtb,FITSUNIT,LONG,LONG,INT,STRINGV,LONGV,STRINGV,STRINGV,STRING,PINT)
+
+#define ftphbn_STRV_A4 NUM_ELEM_ARG(3)
+#define ftphbn_STRV_A5 NUM_ELEM_ARG(3)
+#define ftphbn_STRV_A6 NUM_ELEM_ARG(3)
+FCALLSCSUB9(ffphbn,FTPHBN,ftphbn,FITSUNIT,LONG,INT,STRINGV,STRINGV,STRINGV,STRING,LONG,PINT)
+
+/* Archaic names exist for preceding 3 functions...
+ continue supporting them. */
+
+#define ftpprh_LONGV_A5 A4
+FCALLSCSUB9(Cffphpr,FTPPRH,ftpprh,FITSUNIT,LOGICAL,INT,INT,LONGV,LONG,LONG,LOGICAL,PINT)
+
+#define ftpbnh_STRV_A4 NUM_ELEM_ARG(3)
+#define ftpbnh_STRV_A5 NUM_ELEM_ARG(3)
+#define ftpbnh_STRV_A6 NUM_ELEM_ARG(3)
+FCALLSCSUB9(ffphbn,FTPBNH,ftpbnh,FITSUNIT,LONG,INT,STRINGV,STRINGV,STRINGV,STRING,LONG,PINT)
+
+#define ftptbh_STRV_A5 NUM_ELEM_ARG(4)
+#define ftptbh_STRV_A7 NUM_ELEM_ARG(4)
+#define ftptbh_STRV_A8 NUM_ELEM_ARG(4)
+#define ftptbh_LONGV_A6 A4
+FCALLSCSUB10(ffphtb,FTPTBH,ftptbh,FITSUNIT,LONG,LONG,INT,STRINGV,LONGV,STRINGV,STRINGV,STRING,PINT)
+
+/*----------------- write template keywords --------------*/
+FCALLSCSUB3(ffpktp,FTPKTP,ftpktp,FITSUNIT,STRING,PINT)
+
+/*------------------ get header information --------------*/
+FCALLSCSUB4(ffghsp,FTGHSP,ftghsp,FITSUNIT,PINT,PINT,PINT)
+FCALLSCSUB4(ffghps,FTGHPS,ftghps,FITSUNIT,PINT,PINT,PINT)
+
+/*------------------ move position in header -------------*/
+FCALLSCSUB3(ffmaky,FTMAKY,ftmaky,FITSUNIT,INT,PINT)
+FCALLSCSUB3(ffmrky,FTMRKY,ftmrky,FITSUNIT,INT,PINT)
+
+/*------------------ read single keywords ----------------*/
+#define ftgnxk_STRV_A2 NUM_ELEM_ARG(3)
+#define ftgnxk_STRV_A4 NUM_ELEM_ARG(5)
+FCALLSCSUB7(ffgnxk,FTGNXK,ftgnxk,FITSUNIT,STRINGV,INT,STRINGV,INT,PSTRING,PINT)
+FCALLSCSUB4(ffgrec,FTGREC,ftgrec,FITSUNIT,INT,PSTRING,PINT)
+FCALLSCSUB4(ffgcrd,FTGCRD,ftgcrd,FITSUNIT,STRING,PSTRING,PINT)
+FCALLSCSUB4(ffgunt,FTGUNT,ftgunt,FITSUNIT,STRING,PSTRING,PINT)
+FCALLSCSUB6(ffgkyn,FTGKYN,ftgkyn,FITSUNIT,INT,PSTRING,PSTRING,PSTRING,PINT)
+FCALLSCSUB5(ffgkey,FTGKEY,ftgkey,FITSUNIT,STRING,PSTRING,PSTRING,PINT)
+
+/* FTGKYS supported the long string convention but FFGKYS does not,
+ so redirect to FFGKLS. To handle the pointer to a pointer,
+ manually expand the FCALLSC macro and modify function call. */
+
+CFextern VOID_cfF(FTGKYS,ftgkys)
+CFARGT14(NCF,DCF,ABSOFT_cf2(VOID),FITSUNIT,STRING,PSTRING,PSTRING,PINT,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0));
+CFextern VOID_cfF(FTGKYS,ftgkys)
+CFARGT14(NCF,DCF,ABSOFT_cf2(VOID),FITSUNIT,STRING,PSTRING,PSTRING,PINT,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0))
+{
+ QCF(FITSUNIT,1)
+ QCF(STRING,2)
+ QCF(PSTRING,3) /* Defines a character pointer */
+ QCF(PSTRING,4)
+ QCF(PINT,5)
+
+ ffgkls( TCF(ftgkys,FITSUNIT,1,0)
+ TCF(ftgkys,STRING,2,1)
+ , &B3 /* Pass address of pointer */
+ TCF(ftgkys,PSTRING,4,1)
+ TCF(ftgkys,PINT,5,1) );
+
+ RCF(FITSUNIT,1)
+ RCF(STRING,2)
+ RCF(PSTRING,3) /* Copies as much of pointer as will fit */
+ RCF(PSTRING,4) /* into fortran string and frees space */
+ RCF(PINT,5)
+}
+
+/* This is the *real* wrapper to FFGKLS, although it is exactly the
+ same as the one for FFGKYS. To handle the pointer to a pointer,
+ manually expand the FCALLSC macro and modify function call. */
+
+CFextern VOID_cfF(FTGKLS,ftgkls)
+CFARGT14(NCF,DCF,ABSOFT_cf2(VOID),FITSUNIT,STRING,PSTRING,PSTRING,PINT,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0));
+CFextern VOID_cfF(FTGKLS,ftgkls)
+CFARGT14(NCF,DCF,ABSOFT_cf2(VOID),FITSUNIT,STRING,PSTRING,PSTRING,PINT,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0))
+{
+ QCF(FITSUNIT,1)
+ QCF(STRING,2)
+ QCF(PSTRING,3) /* Defines a character pointer */
+ QCF(PSTRING,4)
+ QCF(PINT,5)
+
+ ffgkls( TCF(ftgkls,FITSUNIT,1,0)
+ TCF(ftgkls,STRING,2,1)
+ , &B3 /* Pass address of pointer */
+ TCF(ftgkls,PSTRING,4,1)
+ TCF(ftgkls,PINT,5,1) );
+
+ RCF(FITSUNIT,1)
+ RCF(STRING,2)
+ RCF(PSTRING,3) /* Copies as much of pointer as will fit */
+ RCF(PSTRING,4) /* into fortran string and frees space */
+ RCF(PINT,5)
+}
+
+FCALLSCSUB5(ffgkyl,FTGKYL,ftgkyl,FITSUNIT,STRING,PINT,PSTRING,PINT)
+FCALLSCSUB5(ffgkyj,FTGKYJ,ftgkyj,FITSUNIT,STRING,PLONG,PSTRING,PINT)
+FCALLSCSUB5(ffgkye,FTGKYE,ftgkye,FITSUNIT,STRING,PFLOAT,PSTRING,PINT)
+FCALLSCSUB5(ffgkyd,FTGKYD,ftgkyd,FITSUNIT,STRING,PDOUBLE,PSTRING,PINT)
+FCALLSCSUB5(ffgkyc,FTGKYC,ftgkyc,FITSUNIT,STRING,PFLOAT,PSTRING,PINT)
+FCALLSCSUB5(ffgkym,FTGKYM,ftgkym,FITSUNIT,STRING,PDOUBLE,PSTRING,PINT)
+FCALLSCSUB6(ffgkyt,FTGKYT,ftgkyt,FITSUNIT,STRING,PLONG,PDOUBLE,PSTRING,PINT)
+
+#define ftgtdm_LONGV_A5 A3
+FCALLSCSUB6(ffgtdm,FTGTDM,ftgtdm,FITSUNIT,INT,INT,PINT,LONGV,PINT)
+
+/*------------------ read array of keywords -----------------*/
+
+ /* Handle array of strings such that only the number of */
+ /* keywords actually found get copied back to the Fortran */
+ /* array. Faster as well as won't cause array overflows */
+ /* if the the array is smaller than nkeys, but larger than */
+ /* nfound. */
+
+#define ftgkns_STRV_A5 NUM_ELEM_ARG(4)
+CFextern VOID_cfF(FTGKNS,ftgkns)
+CFARGT14(NCF,DCF,ABSOFT_cf2(VOID),FITSUNIT,STRING,INT,INT,PSTRINGV,PINT,PINT,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0));
+CFextern VOID_cfF(FTGKNS,ftgkns)
+CFARGT14(NCF,DCF,ABSOFT_cf2(VOID),FITSUNIT,STRING,INT,INT,PSTRINGV,PINT,PINT,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0))
+{
+ QCF(FITSUNIT,1)
+ QCF(STRING,2)
+ QCF(INT,3)
+ QCF(INT,4)
+ QCF(PSTRINGV,5)
+ QCF(PINT,6)
+ QCF(PINT,7)
+
+ ffgkns( TCF(ftgkns,FITSUNIT,1,0)
+ TCF(ftgkns,STRING,2,1)
+ TCF(ftgkns,INT,3,1)
+ TCF(ftgkns,INT,4,1)
+ TCF(ftgkns,PSTRINGV,5,1) /* Defines the number of strings */
+ /* in array, B5N */
+ TCF(ftgkns,PINT,6,1)
+ TCF(ftgkns,PINT,7,1) );
+
+ if ( *A7 ) /* Redefine number of array elements to */
+ B5N = 0; /* number found, or none if error. */
+ else
+ B5N = *A6;
+
+ RCF(FITSUNIT,1)
+ RCF(STRING,2)
+ RCF(INT,3)
+ RCF(INT,4)
+ RCF(PSTRINGV,5) /* Copies only found keywords back to Fortran */
+ RCF(PINT,6)
+ RCF(PINT,7)
+}
+
+/* Must handle LOGICALV conversion manually... ffgknl uses ints */
+void Cffgknl( fitsfile *fptr, char *keyroot, int nstart, int nkeys,
+ int *numval, int *nfound, int *status );
+void Cffgknl( fitsfile *fptr, char *keyroot, int nstart, int nkeys,
+ int *numval, int *nfound, int *status )
+{
+ int i;
+
+ for( i=0; i<nkeys; i++ ) /* This preserves array elements across call */
+ numval[i] = F2CLOGICAL(numval[i]);
+ ffgknl( fptr, keyroot, nstart, nkeys, numval, nfound, status );
+ for( i=0; i<nkeys; i++ )
+ numval[i] = C2FLOGICAL(numval[i]);
+}
+FCALLSCSUB7(Cffgknl,FTGKNL,ftgknl,FITSUNIT,STRING,INT,INT,INTV,PINT,PINT)
+
+#define ftgknj_LONGV_A5 A4
+FCALLSCSUB7(ffgknj,FTGKNJ,ftgknj,FITSUNIT,STRING,INT,INT,LONGV,PINT,PINT)
+FCALLSCSUB7(ffgkne,FTGKNE,ftgkne,FITSUNIT,STRING,INT,INT,FLOATV,PINT,PINT)
+FCALLSCSUB7(ffgknd,FTGKND,ftgknd,FITSUNIT,STRING,INT,INT,DOUBLEV,PINT,PINT)
+
+/*----------------- read required header keywords --------------*/
+#define ftghpr_LONGV_A6 A2
+FCALLSCSUB10(ffghpr,FTGHPR,ftghpr,FITSUNIT,INT,PLOGICAL,PINT,PINT,LONGV,PLONG,PLONG,PLOGICAL,PINT)
+
+
+ /* The following 2 routines contain 3 string vector parameters, */
+ /* intended to hold column information. Normally the vectors */
+ /* are defined with 500-999 elements, but very rarely do tables */
+ /* have that many columns. So, to prevent the allocation of */
+ /* 240K of memory to hold all these empty strings and the waste */
+ /* of CPU time converting Fortran strings to C, *and* back */
+ /* again, get the number of columns in the table and only */
+ /* process that many strings (or maxdim, if it is smaller). */
+
+#define ftghtb_STRV_A6 NUM_ELEMS(maxdim)
+#define ftghtb_STRV_A8 NUM_ELEMS(maxdim)
+#define ftghtb_STRV_A9 NUM_ELEMS(maxdim)
+#define ftghtb_LONGV_A7 A2
+CFextern VOID_cfF(FTGHTB,ftghtb)
+CFARGT14(NCF,DCF,ABSOFT_cf2(VOID),FITSUNIT,INT,PLONG,PLONG,PINT,PSTRINGV,LONGV,PSTRINGV,PSTRINGV,PSTRING,PINT,CF_0,CF_0,CF_0));
+CFextern VOID_cfF(FTGHTB,ftghtb)
+CFARGT14(NCF,DCF,ABSOFT_cf2(VOID),FITSUNIT,INT,PLONG,PLONG,PINT,PSTRINGV,LONGV,PSTRINGV,PSTRINGV,PSTRING,PINT,CF_0,CF_0,CF_0))
+{
+ QCF(FITSUNIT,1)
+ QCF(INT,2)
+ QCF(PLONG,3)
+ QCF(PLONG,4)
+ QCF(PINT,5)
+ QCF(PSTRINGV,6)
+ QCF(LONGV,7)
+ QCF(PSTRINGV,8)
+ QCF(PSTRINGV,9)
+ QCF(PSTRING,A)
+ QCF(PINT,B)
+
+ fitsfile *fptr;
+ long tfields;
+ int maxdim,*status;
+
+ fptr = TCF(ftghtb,FITSUNIT,1,0);
+ status = TCF(ftghtb,PINT,B,0);
+ maxdim = TCF(ftghtb,INT,2,0);
+ ffgkyj( fptr, "TFIELDS", &tfields, 0, status );
+ maxdim = (maxdim<0) ? tfields : _cfMIN(tfields,maxdim);
+
+ ffghtb( fptr, maxdim
+ TCF(ftghtb,PLONG,3,1)
+ TCF(ftghtb,PLONG,4,1)
+ TCF(ftghtb,PINT,5,1)
+ TCF(ftghtb,PSTRINGV,6,1)
+ TCF(ftghtb,LONGV,7,1)
+ TCF(ftghtb,PSTRINGV,8,1)
+ TCF(ftghtb,PSTRINGV,9,1)
+ TCF(ftghtb,PSTRING,A,1)
+ , status );
+
+ RCF(FITSUNIT,1)
+ RCF(INT,2)
+ RCF(PLONG,3)
+ RCF(PLONG,4)
+ RCF(PINT,5)
+ RCF(PSTRINGV,6)
+ RCF(LONGV,7)
+ RCF(PSTRINGV,8)
+ RCF(PSTRINGV,9)
+ RCF(PSTRING,A)
+ RCF(PINT,B)
+}
+
+#define ftghbn_STRV_A5 NUM_ELEMS(maxdim)
+#define ftghbn_STRV_A6 NUM_ELEMS(maxdim)
+#define ftghbn_STRV_A7 NUM_ELEMS(maxdim)
+CFextern VOID_cfF(FTGHBN,ftghbn)
+CFARGT14(NCF,DCF,ABSOFT_cf2(VOID),FITSUNIT,INT,PLONG,PINT,PSTRINGV,PSTRINGV,PSTRINGV,PSTRING,PLONG,PINT,CF_0,CF_0,CF_0,CF_0));
+CFextern VOID_cfF(FTGHBN,ftghbn)
+CFARGT14(NCF,DCF,ABSOFT_cf2(VOID),FITSUNIT,INT,PLONG,PINT,PSTRINGV,PSTRINGV,PSTRINGV,PSTRING,PLONG,PINT,CF_0,CF_0,CF_0,CF_0))
+{
+ QCF(FITSUNIT,1)
+ QCF(INT,2)
+ QCF(PLONG,3)
+ QCF(PINT,4)
+ QCF(PSTRINGV,5)
+ QCF(PSTRINGV,6)
+ QCF(PSTRINGV,7)
+ QCF(PSTRING,8)
+ QCF(PLONG,9)
+ QCF(PINT,A)
+
+ fitsfile *fptr;
+ long tfields;
+ int maxdim,*status;
+
+ fptr = TCF(ftghbn,FITSUNIT,1,0);
+ status = TCF(ftghbn,PINT,A,0);
+ maxdim = TCF(ftghbn,INT,2,0);
+ ffgkyj( fptr, "TFIELDS", &tfields, 0, status );
+ maxdim = (maxdim<0) ? tfields : _cfMIN(tfields,maxdim);
+
+ ffghbn( fptr, maxdim
+ TCF(ftghbn,PLONG,3,1)
+ TCF(ftghbn,PINT,4,1)
+ TCF(ftghbn,PSTRINGV,5,1)
+ TCF(ftghbn,PSTRINGV,6,1)
+ TCF(ftghbn,PSTRINGV,7,1)
+ TCF(ftghbn,PSTRING,8,1)
+ TCF(ftghbn,PLONG,9,1)
+ , status );
+
+ RCF(FITSUNIT,1)
+ RCF(INT,2)
+ RCF(PLONG,3)
+ RCF(PINT,4)
+ RCF(PSTRINGV,5)
+ RCF(PSTRINGV,6)
+ RCF(PSTRINGV,7)
+ RCF(PSTRING,8)
+ RCF(PLONG,9)
+ RCF(PINT,A)
+}
+
+ /* The following 3 routines are obsolete and dangerous to use as */
+ /* there is no bounds checking with the arrays. Call ftghxx instead. */
+ /* To get cfortran to work, ftgtbh and ftgbnh require information */
+ /* on the array size of the string vectors. The "TFIELDS" key word */
+ /* is read and used as the vector size. This *will* cause a */
+ /* problem if ttype, tform, and tunit are declared with fewer */
+ /* elements than the actual number of columns. */
+
+#if defined(DECFortran) || (defined(__alpha) && defined(g77Fortran)) \
+ || (defined(mipsFortran) && _MIPS_SZLONG==64) \
+ || (defined(IBMR2Fortran) && defined(__64BIT__))
+ /* If running under DECFortran, we also need to worry about the length */
+ /* of the long naxes array. So read NAXIS manually. :( */
+
+void Cffgprh( fitsfile *fptr, int *simple, int *bitpix, int *naxis, int naxes[],
+ long *pcount, long *gcount, int *extend, int *status );
+void Cffgprh( fitsfile *fptr, int *simple, int *bitpix, int *naxis, int naxes[],
+ long *pcount, long *gcount, int *extend, int *status )
+{
+ long *LONGnaxes, size;
+
+ ffgkyj( fptr, "NAXIS", &size, 0, status );
+ LONGnaxes = F2Clongv(size,naxes);
+ ffghpr( fptr, (int)size, simple, bitpix, naxis, LONGnaxes,
+ pcount, gcount, extend, status );
+ C2Flongv(size,naxes,LONGnaxes);
+}
+FCALLSCSUB9(Cffgprh,FTGPRH,ftgprh,FITSUNIT,PLOGICAL,PINT,PINT,INTV,PLONG,PLONG,PLOGICAL,PINT)
+
+#else
+
+void Cffgprh( fitsfile *fptr, int *simple, int *bitpix, int *naxis, long naxes[],
+ long *pcount, long *gcount, int *extend, int *status );
+void Cffgprh( fitsfile *fptr, int *simple, int *bitpix, int *naxis, long naxes[],
+ long *pcount, long *gcount, int *extend, int *status )
+{
+ ffghpr( fptr, -1, simple, bitpix, naxis, naxes,
+ pcount, gcount, extend, status );
+}
+#define ftghpr_LONGV_A5 NONE
+FCALLSCSUB9(Cffgprh,FTGPRH,ftgprh,FITSUNIT,PLOGICAL,PINT,PINT,LONGV,PLONG,PLONG,PLOGICAL,PINT)
+
+#endif
+
+#define ftgtbh_STRV_A5 NUM_ELEMS(tfields)
+#define ftgtbh_STRV_A7 NUM_ELEMS(tfields)
+#define ftgtbh_STRV_A8 NUM_ELEMS(tfields)
+CFextern VOID_cfF(FTGTBH,ftgtbh)
+CFARGT14(NCF,DCF,ABSOFT_cf2(VOID),FITSUNIT,PLONG,PLONG,PINT,PSTRINGV,PLONG,PSTRINGV,PSTRINGV,PSTRING,PINT,CF_0,CF_0,CF_0,CF_0));
+CFextern VOID_cfF(FTGTBH,ftgtbh)
+CFARGT14(NCF,DCF,ABSOFT_cf2(VOID),FITSUNIT,PLONG,PLONG,PINT,PSTRINGV,PLONG,PSTRINGV,PSTRINGV,PSTRING,PINT,CF_0,CF_0,CF_0,CF_0))
+{
+ QCF(FITSUNIT,1)
+ QCF(PLONG,2)
+ QCF(PLONG,3)
+ QCF(PINT,4)
+ QCF(PSTRINGV,5)
+ QCF(PLONG,6)
+ QCF(PSTRINGV,7)
+ QCF(PSTRINGV,8)
+ QCF(PSTRING,9)
+ QCF(PINT,A)
+
+ fitsfile *fptr;
+ long tfields;
+ int *status;
+
+ fptr = TCF(ftgtbh,FITSUNIT,1,0);
+ status = TCF(ftgtbh,PINT,A,0);
+ ffgkyj( fptr, "TFIELDS", &tfields, 0, status );
+
+ ffghtb( fptr, (int)tfields
+ TCF(ftgtbh,PLONG,2,1)
+ TCF(ftgtbh,PLONG,3,1)
+ TCF(ftgtbh,PINT,4,1)
+ TCF(ftgtbh,PSTRINGV,5,1)
+ TCF(ftgtbh,PLONG,6,1)
+ TCF(ftgtbh,PSTRINGV,7,1)
+ TCF(ftgtbh,PSTRINGV,8,1)
+ TCF(ftgtbh,PSTRING,9,1)
+ , status );
+
+ RCF(FITSUNIT,1)
+ RCF(PLONG,2)
+ RCF(PLONG,3)
+ RCF(PINT,4)
+ RCF(PSTRINGV,5)
+ RCF(PLONG,6)
+ RCF(PSTRINGV,7)
+ RCF(PSTRINGV,8)
+ RCF(PSTRING,9)
+ RCF(PINT,A)
+}
+
+#define ftgbnh_STRV_A4 NUM_ELEMS(tfields)
+#define ftgbnh_STRV_A5 NUM_ELEMS(tfields)
+#define ftgbnh_STRV_A6 NUM_ELEMS(tfields)
+CFextern VOID_cfF(FTGBNH,ftgbnh)
+CFARGT14(NCF,DCF,ABSOFT_cf2(VOID),FITSUNIT,PLONG,PINT,PSTRINGV,PSTRINGV,PSTRINGV,PSTRING,PLONG,PINT,CF_0,CF_0,CF_0,CF_0,CF_0));
+CFextern VOID_cfF(FTGBNH,ftgbnh)
+CFARGT14(NCF,DCF,ABSOFT_cf2(VOID),FITSUNIT,PLONG,PINT,PSTRINGV,PSTRINGV,PSTRINGV,PSTRING,PLONG,PINT,CF_0,CF_0,CF_0,CF_0,CF_0))
+{
+ QCF(FITSUNIT,1)
+ QCF(PLONG,2)
+ QCF(PINT,3)
+ QCF(PSTRINGV,4)
+ QCF(PSTRINGV,5)
+ QCF(PSTRINGV,6)
+ QCF(PSTRING,7)
+ QCF(PLONG,8)
+ QCF(PINT,9)
+
+ fitsfile *fptr;
+ long tfields;
+ int *status;
+
+ fptr = TCF(ftgbnh,FITSUNIT,1,0);
+ status = TCF(ftgbnh,PINT,9,0);
+ ffgkyj( fptr, "TFIELDS", &tfields, 0, status );
+
+ ffghbn( fptr, (int)tfields
+ TCF(ftgbnh,PLONG,2,1)
+ TCF(ftgbnh,PINT,3,1)
+ TCF(ftgbnh,PSTRINGV,4,1)
+ TCF(ftgbnh,PSTRINGV,5,1)
+ TCF(ftgbnh,PSTRINGV,6,1)
+ TCF(ftgbnh,PSTRING,7,1)
+ TCF(ftgbnh,PLONG,8,1)
+ , status );
+
+ RCF(FITSUNIT,1)
+ RCF(PLONG,2)
+ RCF(PINT,3)
+ RCF(PSTRINGV,4)
+ RCF(PSTRINGV,5)
+ RCF(PSTRINGV,6)
+ RCF(PSTRING,7)
+ RCF(PLONG,8)
+ RCF(PINT,9)
+}
+
+
+/*--------------------- update keywords ---------------*/
+FCALLSCSUB4(ffucrd,FTUCRD,ftucrd,FITSUNIT,STRING,STRING,PINT)
+FCALLSCSUB4(ffukyu,FTUKYU,ftukyu,FITSUNIT,STRING,STRING,PINT)
+FCALLSCSUB5(ffukys,FTUKYS,ftukys,FITSUNIT,STRING,STRING,STRING,PINT)
+FCALLSCSUB5(ffukls,FTUKLS,ftukls,FITSUNIT,STRING,STRING,STRING,PINT)
+FCALLSCSUB5(ffukyl,FTUKYL,ftukyl,FITSUNIT,STRING,INT,STRING,PINT)
+FCALLSCSUB5(ffukyj,FTUKYJ,ftukyj,FITSUNIT,STRING,LONG,STRING,PINT)
+FCALLSCSUB6(ffukyf,FTUKYF,ftukyf,FITSUNIT,STRING,FLOAT,INT,STRING,PINT)
+FCALLSCSUB6(ffukye,FTUKYE,ftukye,FITSUNIT,STRING,FLOAT,INT,STRING,PINT)
+FCALLSCSUB6(ffukyg,FTUKYG,ftukyg,FITSUNIT,STRING,DOUBLE,INT,STRING,PINT)
+FCALLSCSUB6(ffukyd,FTUKYD,ftukyd,FITSUNIT,STRING,DOUBLE,INT,STRING,PINT)
+FCALLSCSUB6(ffukyc,FTUKYC,ftukyc,FITSUNIT,STRING,FLOATV,INT,STRING,PINT)
+FCALLSCSUB6(ffukym,FTUKYM,ftukym,FITSUNIT,STRING,DOUBLEV,INT,STRING,PINT)
+FCALLSCSUB6(ffukfc,FTUKFC,ftukfc,FITSUNIT,STRING,FLOATV,INT,STRING,PINT)
+FCALLSCSUB6(ffukfm,FTUKFM,ftukfm,FITSUNIT,STRING,DOUBLEV,INT,STRING,PINT)
+
+/*--------------------- modify keywords ---------------*/
+FCALLSCSUB4(ffmrec,FTMREC,ftmrec,FITSUNIT,INT,STRING,PINT)
+FCALLSCSUB4(ffmcrd,FTMCRD,ftmcrd,FITSUNIT,STRING,STRING,PINT)
+FCALLSCSUB4(ffmnam,FTMNAM,ftmnam,FITSUNIT,STRING,STRING,PINT)
+FCALLSCSUB4(ffmcom,FTMCOM,ftmcom,FITSUNIT,STRING,STRING,PINT)
+FCALLSCSUB4(ffmkyu,FTMKYU,ftmkyu,FITSUNIT,STRING,STRING,PINT)
+FCALLSCSUB5(ffmkys,FTMKYS,ftmkys,FITSUNIT,STRING,STRING,STRING,PINT)
+FCALLSCSUB5(ffmkls,FTMKLS,ftmkls,FITSUNIT,STRING,STRING,STRING,PINT)
+FCALLSCSUB5(ffmkyl,FTMKYL,ftmkyl,FITSUNIT,STRING,INT,STRING,PINT)
+FCALLSCSUB5(ffmkyj,FTMKYJ,ftmkyj,FITSUNIT,STRING,LONG,STRING,PINT)
+FCALLSCSUB6(ffmkyf,FTMKYF,ftmkyf,FITSUNIT,STRING,FLOAT,INT,STRING,PINT)
+FCALLSCSUB6(ffmkye,FTMKYE,ftmkye,FITSUNIT,STRING,FLOAT,INT,STRING,PINT)
+FCALLSCSUB6(ffmkyg,FTMKYG,ftmkyg,FITSUNIT,STRING,DOUBLE,INT,STRING,PINT)
+FCALLSCSUB6(ffmkyd,FTMKYD,ftmkyd,FITSUNIT,STRING,DOUBLE,INT,STRING,PINT)
+FCALLSCSUB6(ffmkyc,FTMKYC,ftmkyc,FITSUNIT,STRING,FLOATV,INT,STRING,PINT)
+FCALLSCSUB6(ffmkym,FTMKYM,ftmkym,FITSUNIT,STRING,DOUBLEV,INT,STRING,PINT)
+FCALLSCSUB6(ffmkfc,FTMKFC,ftmkfc,FITSUNIT,STRING,FLOATV,INT,STRING,PINT)
+FCALLSCSUB6(ffmkfm,FTMKFM,ftmkfm,FITSUNIT,STRING,DOUBLEV,INT,STRING,PINT)
+
+/*--------------------- insert keywords ---------------*/
+FCALLSCSUB4(ffirec,FTIREC,ftirec,FITSUNIT,INT,STRING,PINT)
+FCALLSCSUB4(ffikyu,FTIKYU,ftikyu,FITSUNIT,STRING,STRING,PINT)
+FCALLSCSUB5(ffikys,FTIKYS,ftikys,FITSUNIT,STRING,STRING,STRING,PINT)
+FCALLSCSUB5(ffikls,FTIKLS,ftikls,FITSUNIT,STRING,STRING,STRING,PINT)
+FCALLSCSUB5(ffikyl,FTIKYL,ftikyl,FITSUNIT,STRING,INT,STRING,PINT)
+FCALLSCSUB5(ffikyj,FTIKYJ,ftikyj,FITSUNIT,STRING,LONG,STRING,PINT)
+FCALLSCSUB6(ffikyf,FTIKYF,ftikyf,FITSUNIT,STRING,FLOAT,INT,STRING,PINT)
+FCALLSCSUB6(ffikye,FTIKYE,ftikye,FITSUNIT,STRING,FLOAT,INT,STRING,PINT)
+FCALLSCSUB6(ffikyg,FTIKYG,ftikyg,FITSUNIT,STRING,DOUBLE,INT,STRING,PINT)
+FCALLSCSUB6(ffikyd,FTIKYD,ftikyd,FITSUNIT,STRING,DOUBLE,INT,STRING,PINT)
+FCALLSCSUB6(ffikyc,FTIKYC,ftikyc,FITSUNIT,STRING,FLOATV,INT,STRING,PINT)
+FCALLSCSUB6(ffikym,FTIKYM,ftikym,FITSUNIT,STRING,DOUBLEV,INT,STRING,PINT)
+FCALLSCSUB6(ffikfc,FTIKFC,ftikfc,FITSUNIT,STRING,FLOATV,INT,STRING,PINT)
+FCALLSCSUB6(ffikfm,FTIKFM,ftikfm,FITSUNIT,STRING,DOUBLEV,INT,STRING,PINT)
+
+/*--------------------- delete keywords ---------------*/
+FCALLSCSUB3(ffdkey,FTDKEY,ftdkey,FITSUNIT,STRING,PINT)
+FCALLSCSUB3(ffdrec,FTDREC,ftdrec,FITSUNIT,INT,PINT)
+
+/*--------------------- get HDU information -------------*/
+FCALLSCSUB2(ffghdn,FTGHDN,ftghdn,FITSUNIT,PINT)
+FCALLSCSUB3(ffghdt,FTGHDT,ftghdt,FITSUNIT,PINT,PINT)
+
+FCALLSCSUB5(ffghad,FTGHAD,ftghad,FITSUNIT,PLONG,PLONG,PLONG,PINT)
+
+FCALLSCSUB3(ffgidt,FTGIDT,ftgidt,FITSUNIT,PINT,PINT)
+FCALLSCSUB3(ffgidm,FTGIDM,ftgidm,FITSUNIT,PINT,PINT)
+
+#define ftgisz_LONGV_A3 A2
+FCALLSCSUB4(ffgisz,FTGISZ,ftgisz,FITSUNIT,INT,LONGV,PINT)
+
+#define ftgipr_LONGV_A5 A2
+FCALLSCSUB6(ffgipr,FTGIPR,ftgipr,FITSUNIT,INT,PINT,PINT,LONGV,PINT)
+
+/*--------------------- HDU operations -------------*/
+FCALLSCSUB4(ffmahd,FTMAHD,ftmahd,FITSUNIT,INT,PINT,PINT)
+FCALLSCSUB4(ffmrhd,FTMRHD,ftmrhd,FITSUNIT,INT,PINT,PINT)
+FCALLSCSUB5(ffmnhd,FTMNHD,ftmnhd,FITSUNIT,INT,STRING,INT,PINT)
+FCALLSCSUB3(ffthdu,FTTHDU,ftthdu,FITSUNIT,PINT,PINT)
+FCALLSCSUB2(ffcrhd,FTCRHD,ftcrhd,FITSUNIT,PINT)
+
+#define ftcrim_LONGV_A4 A3
+FCALLSCSUB5(ffcrim,FTCRIM,ftcrim,FITSUNIT,INT,INT,LONGV,PINT)
+
+#define ftcrtb_STRV_A5 NUM_ELEM_ARG(4)
+#define ftcrtb_STRV_A6 NUM_ELEM_ARG(4)
+#define ftcrtb_STRV_A7 NUM_ELEM_ARG(4)
+FCALLSCSUB9(ffcrtb,FTCRTB,ftcrtb,FITSUNIT,INT,LONG,INT,STRINGV,STRINGV,STRINGV,STRING,PINT)
+
+#define ftiimg_LONGV_A4 A3
+FCALLSCSUB5(ffiimg,FTIIMG,ftiimg,FITSUNIT,INT,INT,LONGV,PINT)
+
+#define ftitab_STRV_A5 NUM_ELEM_ARG(4)
+#define ftitab_LONGV_A6 A4
+#define ftitab_STRV_A7 NUM_ELEM_ARG(4)
+#define ftitab_STRV_A8 NUM_ELEM_ARG(4)
+FCALLSCSUB10(ffitab,FTITAB,ftitab,FITSUNIT,LONG,LONG,INT,STRINGV,LONGV,STRINGV,STRINGV,STRING,PINT)
+
+#define ftibin_STRV_A4 NUM_ELEM_ARG(3)
+#define ftibin_STRV_A5 NUM_ELEM_ARG(3)
+#define ftibin_STRV_A6 NUM_ELEM_ARG(3)
+FCALLSCSUB9(ffibin,FTIBIN,ftibin,FITSUNIT,LONG,INT,STRINGV,STRINGV,STRINGV,STRING,LONG,PINT)
+
+#define ftrsim_LONGV_A4 A3
+FCALLSCSUB5(ffrsim,FTRSIM,ftrsim,FITSUNIT,INT,INT,LONGV,PINT)
+FCALLSCSUB3(ffdhdu,FTDHDU,ftdhdu,FITSUNIT,PINT,PINT)
+FCALLSCSUB4(ffcopy,FTCOPY,ftcopy,FITSUNIT,FITSUNIT,INT,PINT)
+FCALLSCSUB3(ffcphd,FTCPHD,ftcphd,FITSUNIT,FITSUNIT,PINT)
+FCALLSCSUB3(ffcpdt,FTCPDT,ftcpdt,FITSUNIT,FITSUNIT,PINT)
+FCALLSCSUB2(ffchfl,FTCHFL,ftchfl,FITSUNIT,PINT)
+FCALLSCSUB2(ffcdfl,FTCDFL,ftcdfl,FITSUNIT,PINT)
+
+FCALLSCSUB2(ffrdef,FTRDEF,ftrdef,FITSUNIT,PINT)
+FCALLSCSUB3(ffhdef,FTHDEF,fthdef,FITSUNIT,INT,PINT)
+FCALLSCSUB3(ffpthp,FTPTHP,ftpthp,FITSUNIT,LONG,PINT)
+
+FCALLSCSUB2(ffpcks,FTPCKS,ftpcks,FITSUNIT,PINT)
+FCALLSCSUB4(ffvcks,FTVCKS,ftvcks,FITSUNIT,PINT,PINT,PINT)
+
+ /* Checksum changed from double to long */
+
+void Cffgcks( fitsfile *fptr, double *datasum, double *hdusum, int *status );
+void Cffgcks( fitsfile *fptr, double *datasum, double *hdusum, int *status )
+{
+ unsigned long data, hdu;
+
+ ffgcks( fptr, &data, &hdu, status );
+ *datasum = data;
+ *hdusum = hdu;
+}
+FCALLSCSUB4(Cffgcks,FTGCKS,ftgcks,FITSUNIT,PDOUBLE,PDOUBLE,PINT)
+
+void Cffcsum( fitsfile *fptr, long nrec, double *dsum, int *status );
+void Cffcsum( fitsfile *fptr, long nrec, double *dsum, int *status )
+{
+ unsigned long sum;
+
+ ffcsum( fptr, nrec, &sum, status );
+ *dsum = sum;
+}
+FCALLSCSUB4(Cffcsum,FTCSUM,ftcsum,FITSUNIT,LONG,PDOUBLE,PINT)
+
+void Cffesum( double dsum, int complm, char *ascii );
+void Cffesum( double dsum, int complm, char *ascii )
+{
+ unsigned long sum=(unsigned long)dsum;
+
+ ffesum( sum, complm, ascii );
+}
+FCALLSCSUB3(Cffesum,FTESUM,ftesum,DOUBLE,LOGICAL,PSTRING)
+
+void Cffdsum( char *ascii, int complm, double *dsum );
+void Cffdsum( char *ascii, int complm, double *dsum )
+{
+ unsigned long sum;
+
+ ffdsum( ascii, complm, &sum );
+ *dsum = sum;
+}
+FCALLSCSUB3(Cffdsum,FTDSUM,ftdsum,PSTRING,LOGICAL,PDOUBLE)
+
+ /* Name changed, so support both versions */
+FCALLSCSUB2(ffupck,FTUPCK,ftupck,FITSUNIT,PINT)
+FCALLSCSUB2(ffupck,FTUCKS,ftucks,FITSUNIT,PINT)
+
+/*--------------- define scaling or null values -------------*/
+FCALLSCSUB4(ffpscl,FTPSCL,ftpscl,FITSUNIT,DOUBLE,DOUBLE,PINT)
+FCALLSCSUB3(ffpnul,FTPNUL,ftpnul,FITSUNIT,LONG,PINT)
+FCALLSCSUB5(fftscl,FTTSCL,fttscl,FITSUNIT,INT,DOUBLE,DOUBLE,PINT)
+FCALLSCSUB4(fftnul,FTTNUL,fttnul,FITSUNIT,INT,LONG,PINT)
+FCALLSCSUB4(ffsnul,FTSNUL,ftsnul,FITSUNIT,INT,STRING,PINT)
+
+/*--------------------- get column information -------------*/
+FCALLSCSUB5(ffgcno,FTGCNO,ftgcno,FITSUNIT,LOGICAL,STRING,PINT,PINT)
+FCALLSCSUB6(ffgcnn,FTGCNN,ftgcnn,FITSUNIT,LOGICAL,STRING,PSTRING,PINT,PINT)
+FCALLSCSUB3(ffgnrw,FTGNRW,ftgnrw,FITSUNIT,PLONG,PINT)
+FCALLSCSUB3(ffgncl,FTGNCL,ftgncl,FITSUNIT,PINT,PINT)
+FCALLSCSUB4(ffgcdw,FTGCDW,ftgcdw,FITSUNIT,INT,PINT,PINT)
+
+FCALLSCSUB6(ffgtcl,FTGTCL,ftgtcl,FITSUNIT,INT,PINT,PLONG,PLONG,PINT)
+FCALLSCSUB11(ffgacl,FTGACL,ftgacl,FITSUNIT,INT,PSTRING,PLONG,PSTRING,PSTRING,PDOUBLE,PDOUBLE,PSTRING,PSTRING,PINT)
+FCALLSCSUB11(ffgbcl,FTGBCL,ftgbcl,FITSUNIT,INT,PSTRING,PSTRING,PSTRING,PLONG,PDOUBLE,PDOUBLE,PLONG,PSTRING,PINT)
+FCALLSCSUB3(ffgrsz,FTGRSZ,ftgrsz,FITSUNIT,PLONG,PINT)
+
+
diff --git a/pkg/tbtables/cfitsio/f77_wrap2.c b/pkg/tbtables/cfitsio/f77_wrap2.c
new file mode 100644
index 00000000..3c148cc1
--- /dev/null
+++ b/pkg/tbtables/cfitsio/f77_wrap2.c
@@ -0,0 +1,1081 @@
+/************************************************************************
+ Together, f77_wrap1.c and f77_wrap2.c contain C wrappers for all
+ the CFITSIO routines prototyped in fitsio.h, except for the
+ generic datatype routines and features not supported in fortran
+ (eg, unsigned integers), a few routines prototyped in fitsio2.h,
+ which only a handful of FTOOLS use, plus a few obsolete FITSIO
+ routines not present in CFITSIO. This file allows Fortran code
+ to use the CFITSIO library instead of the FITSIO library without
+ modification. It also gives access to new routines not present
+ in FITSIO. Fortran FTOOLS must continue using the old routine
+ names from FITSIO (ie, ftxxxx), but most of the C-wrappers simply
+ redirect those calls to the corresponding CFITSIO routines (ie,
+ ffxxxx), with appropriate parameter massaging where necessary.
+ The main exception are read/write routines ending in j (ie, long
+ data) which get redirected to C routines ending in k (ie, int
+ data). This is more consistent with the default integer type in
+ Fortran. f77_wrap1.c primarily holds routines operating on whole
+ files and extension headers. f77_wrap2.c handle routines which
+ read and write the data portion, plus miscellaneous extra routines.
+
+ File created by Peter Wilson (HSTX), Oct-Dec. 1997
+************************************************************************/
+
+#include "fitsio2.h"
+#include "f77_wrap.h"
+
+/*------------ read primary array or image elements -------------*/
+FCALLSCSUB8(ffgpvb,FTGPVB,ftgpvb,FITSUNIT,LONG,LONG,LONG,BYTE,BYTEV,PLOGICAL,PINT)
+FCALLSCSUB8(ffgpvi,FTGPVI,ftgpvi,FITSUNIT,LONG,LONG,LONG,SHORT,SHORTV,PLOGICAL,PINT)
+FCALLSCSUB8(ffgpvk,FTGPVJ,ftgpvj,FITSUNIT,LONG,LONG,LONG,INT,INTV,PLOGICAL,PINT)
+FCALLSCSUB8(ffgpvk,FTGPVK,ftgpvk,FITSUNIT,LONG,LONG,LONG,INT,INTV,PLOGICAL,PINT)
+FCALLSCSUB8(ffgpve,FTGPVE,ftgpve,FITSUNIT,LONG,LONG,LONG,FLOAT,FLOATV,PLOGICAL,PINT)
+FCALLSCSUB8(ffgpvd,FTGPVD,ftgpvd,FITSUNIT,LONG,LONG,LONG,DOUBLE,DOUBLEV,PLOGICAL,PINT)
+
+
+#define ftgpfb_LOGV_A6 A4
+FCALLSCSUB8(ffgpfb,FTGPFB,ftgpfb,FITSUNIT,LONG,LONG,LONG,BYTEV,LOGICALV,PLOGICAL,PINT)
+
+#define ftgpfi_LOGV_A6 A4
+FCALLSCSUB8(ffgpfi,FTGPFI,ftgpfi,FITSUNIT,LONG,LONG,LONG,SHORTV,LOGICALV,PLOGICAL,PINT)
+
+#define ftgpfj_LOGV_A6 A4
+FCALLSCSUB8(ffgpfk,FTGPFJ,ftgpfj,FITSUNIT,LONG,LONG,LONG,INTV,LOGICALV,PLOGICAL,PINT)
+
+#define ftgpfk_LOGV_A6 A4
+FCALLSCSUB8(ffgpfk,FTGPFK,ftgpfk,FITSUNIT,LONG,LONG,LONG,INTV,LOGICALV,PLOGICAL,PINT)
+
+#define ftgpfe_LOGV_A6 A4
+FCALLSCSUB8(ffgpfe,FTGPFE,ftgpfe,FITSUNIT,LONG,LONG,LONG,FLOATV,LOGICALV,PLOGICAL,PINT)
+
+#define ftgpfd_LOGV_A6 A4
+FCALLSCSUB8(ffgpfd,FTGPFD,ftgpfd,FITSUNIT,LONG,LONG,LONG,DOUBLEV,LOGICALV,PLOGICAL,PINT)
+
+FCALLSCSUB9(ffg2db,FTG2DB,ftg2db,FITSUNIT,LONG,BYTE,LONG,LONG,LONG,BYTEV,PLOGICAL,PINT)
+FCALLSCSUB9(ffg2di,FTG2DI,ftg2di,FITSUNIT,LONG,SHORT,LONG,LONG,LONG,SHORTV,PLOGICAL,PINT)
+FCALLSCSUB9(ffg2dk,FTG2DJ,ftg2dj,FITSUNIT,LONG,INT,LONG,LONG,LONG,INTV,PLOGICAL,PINT)
+FCALLSCSUB9(ffg2dk,FTG2DK,ftg2dk,FITSUNIT,LONG,INT,LONG,LONG,LONG,INTV,PLOGICAL,PINT)
+FCALLSCSUB9(ffg2de,FTG2DE,ftg2de,FITSUNIT,LONG,FLOAT,LONG,LONG,LONG,FLOATV,PLOGICAL,PINT)
+FCALLSCSUB9(ffg2dd,FTG2DD,ftg2dd,FITSUNIT,LONG,DOUBLE,LONG,LONG,LONG,DOUBLEV,PLOGICAL,PINT)
+
+FCALLSCSUB11(ffg3db,FTG3DB,ftg3db,FITSUNIT,LONG,BYTE,LONG,LONG,LONG,LONG,LONG,BYTEV,PLOGICAL,PINT)
+FCALLSCSUB11(ffg3di,FTG3DI,ftg3di,FITSUNIT,LONG,SHORT,LONG,LONG,LONG,LONG,LONG,SHORTV,PLOGICAL,PINT)
+FCALLSCSUB11(ffg3dk,FTG3DJ,ftg3dj,FITSUNIT,LONG,INT,LONG,LONG,LONG,LONG,LONG,INTV,PLOGICAL,PINT)
+FCALLSCSUB11(ffg3dk,FTG3DK,ftg3dk,FITSUNIT,LONG,INT,LONG,LONG,LONG,LONG,LONG,INTV,PLOGICAL,PINT)
+FCALLSCSUB11(ffg3de,FTG3DE,ftg3de,FITSUNIT,LONG,FLOAT,LONG,LONG,LONG,LONG,LONG,FLOATV,PLOGICAL,PINT)
+FCALLSCSUB11(ffg3dd,FTG3DD,ftg3dd,FITSUNIT,LONG,DOUBLE,LONG,LONG,LONG,LONG,LONG,DOUBLEV,PLOGICAL,PINT)
+
+ /* The follow LONGV definitions have +1 appended because the */
+ /* routines use of NAXIS+1 elements of the long vectors. */
+
+#define ftgsvb_LONGV_A4 A3+1
+#define ftgsvb_LONGV_A5 A3+1
+#define ftgsvb_LONGV_A6 A3+1
+#define ftgsvb_LONGV_A7 A3+1
+FCALLSCSUB11(ffgsvb,FTGSVB,ftgsvb,FITSUNIT,INT,INT,LONGV,LONGV,LONGV,LONGV,BYTE,BYTEV,PLOGICAL,PINT)
+
+#define ftgsvi_LONGV_A4 A3+1
+#define ftgsvi_LONGV_A5 A3+1
+#define ftgsvi_LONGV_A6 A3+1
+#define ftgsvi_LONGV_A7 A3+1
+FCALLSCSUB11(ffgsvi,FTGSVI,ftgsvi,FITSUNIT,INT,INT,LONGV,LONGV,LONGV,LONGV,SHORT,SHORTV,PLOGICAL,PINT)
+
+#define ftgsvj_LONGV_A4 A3+1
+#define ftgsvj_LONGV_A5 A3+1
+#define ftgsvj_LONGV_A6 A3+1
+#define ftgsvj_LONGV_A7 A3+1
+FCALLSCSUB11(ffgsvk,FTGSVJ,ftgsvj,FITSUNIT,INT,INT,LONGV,LONGV,LONGV,LONGV,INT,INTV,PLOGICAL,PINT)
+
+#define ftgsvk_LONGV_A4 A3+1
+#define ftgsvk_LONGV_A5 A3+1
+#define ftgsvk_LONGV_A6 A3+1
+#define ftgsvk_LONGV_A7 A3+1
+FCALLSCSUB11(ffgsvk,FTGSVK,ftgsvk,FITSUNIT,INT,INT,LONGV,LONGV,LONGV,LONGV,INT,INTV,PLOGICAL,PINT)
+
+#define ftgsve_LONGV_A4 A3+1
+#define ftgsve_LONGV_A5 A3+1
+#define ftgsve_LONGV_A6 A3+1
+#define ftgsve_LONGV_A7 A3+1
+FCALLSCSUB11(ffgsve,FTGSVE,ftgsve,FITSUNIT,INT,INT,LONGV,LONGV,LONGV,LONGV,FLOAT,FLOATV,PLOGICAL,PINT)
+
+#define ftgsvd_LONGV_A4 A3+1
+#define ftgsvd_LONGV_A5 A3+1
+#define ftgsvd_LONGV_A6 A3+1
+#define ftgsvd_LONGV_A7 A3+1
+FCALLSCSUB11(ffgsvd,FTGSVD,ftgsvd,FITSUNIT,INT,INT,LONGV,LONGV,LONGV,LONGV,DOUBLE,DOUBLEV,PLOGICAL,PINT)
+
+
+/* Must handle LOGICALV conversion manually */
+void Cffgsfb( fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc, long *trc, long *inc, unsigned char *array, int *flagval, int *anynul, int *status );
+void Cffgsfb( fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc, long *trc, long *inc, unsigned char *array, int *flagval, int *anynul, int *status )
+{
+ char *Cflagval;
+ long nflagval;
+ int i;
+
+ for( nflagval=1, i=0; i<naxis; i++ )
+ nflagval *= (trc[i]-blc[i])/inc[i]+1;
+ Cflagval = F2CcopyLogVect(nflagval, flagval );
+ ffgsfb( fptr, colnum, naxis, naxes, blc, trc, inc, array, Cflagval, anynul, status );
+ C2FcopyLogVect(nflagval, flagval, Cflagval);
+}
+#define ftgsfb_LONGV_A4 A3+1
+#define ftgsfb_LONGV_A5 A3+1
+#define ftgsfb_LONGV_A6 A3+1
+#define ftgsfb_LONGV_A7 A3+1
+FCALLSCSUB11(Cffgsfb,FTGSFB,ftgsfb,FITSUNIT,INT,INT,LONGV,LONGV,LONGV,LONGV,BYTEV,INTV,PLOGICAL,PINT)
+
+/* Must handle LOGICALV conversion manually */
+void Cffgsfi( fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc, long *trc, long *inc, short *array, int *flagval, int *anynul, int *status );
+void Cffgsfi( fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc, long *trc, long *inc, short *array, int *flagval, int *anynul, int *status )
+{
+ char *Cflagval;
+ long nflagval;
+ int i;
+
+ for( nflagval=1, i=0; i<naxis; i++ )
+ nflagval *= (trc[i]-blc[i])/inc[i]+1;
+ Cflagval = F2CcopyLogVect(nflagval, flagval );
+ ffgsfi( fptr, colnum, naxis, naxes, blc, trc, inc, array, Cflagval, anynul, status );
+ C2FcopyLogVect(nflagval, flagval, Cflagval);
+}
+#define ftgsfi_LONGV_A4 A3+1
+#define ftgsfi_LONGV_A5 A3+1
+#define ftgsfi_LONGV_A6 A3+1
+#define ftgsfi_LONGV_A7 A3+1
+FCALLSCSUB11(Cffgsfi,FTGSFI,ftgsfi,FITSUNIT,INT,INT,LONGV,LONGV,LONGV,LONGV,SHORTV,INTV,PLOGICAL,PINT)
+
+/* Must handle LOGICALV conversion manually */
+void Cffgsfk( fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc, long *trc, long *inc, int *array, int *flagval, int *anynul, int *status );
+void Cffgsfk( fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc, long *trc, long *inc, int *array, int *flagval, int *anynul, int *status )
+{
+ char *Cflagval;
+ long nflagval;
+ int i;
+
+ for( nflagval=1, i=0; i<naxis; i++ )
+ nflagval *= (trc[i]-blc[i])/inc[i]+1;
+ Cflagval = F2CcopyLogVect(nflagval, flagval );
+ ffgsfk( fptr, colnum, naxis, naxes, blc, trc, inc, array, Cflagval, anynul, status );
+ C2FcopyLogVect(nflagval, flagval, Cflagval);
+}
+#define ftgsfk_LONGV_A4 A3+1
+#define ftgsfk_LONGV_A5 A3+1
+#define ftgsfk_LONGV_A6 A3+1
+#define ftgsfk_LONGV_A7 A3+1
+FCALLSCSUB11(Cffgsfk,FTGSFK,ftgsfk,FITSUNIT,INT,INT,LONGV,LONGV,LONGV,LONGV,INTV,INTV,PLOGICAL,PINT)
+
+#define ftgsfj_LONGV_A4 A3+1
+#define ftgsfj_LONGV_A5 A3+1
+#define ftgsfj_LONGV_A6 A3+1
+#define ftgsfj_LONGV_A7 A3+1
+FCALLSCSUB11(Cffgsfk,FTGSFJ,ftgsfj,FITSUNIT,INT,INT,LONGV,LONGV,LONGV,LONGV,INTV,INTV,PLOGICAL,PINT)
+
+/* Must handle LOGICALV conversion manually */
+void Cffgsfe( fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc, long *trc, long *inc, float *array, int *flagval, int *anynul, int *status );
+void Cffgsfe( fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc, long *trc, long *inc, float *array, int *flagval, int *anynul, int *status )
+{
+ char *Cflagval;
+ long nflagval;
+ int i;
+
+ for( nflagval=1, i=0; i<naxis; i++ )
+ nflagval *= (trc[i]-blc[i])/inc[i]+1;
+ Cflagval = F2CcopyLogVect(nflagval, flagval );
+ ffgsfe( fptr, colnum, naxis, naxes, blc, trc, inc, array, Cflagval, anynul, status );
+ C2FcopyLogVect(nflagval, flagval, Cflagval);
+}
+#define ftgsfe_LONGV_A4 A3+1
+#define ftgsfe_LONGV_A5 A3+1
+#define ftgsfe_LONGV_A6 A3+1
+#define ftgsfe_LONGV_A7 A3+1
+FCALLSCSUB11(Cffgsfe,FTGSFE,ftgsfe,FITSUNIT,INT,INT,LONGV,LONGV,LONGV,LONGV,FLOATV,INTV,PLOGICAL,PINT)
+
+/* Must handle LOGICALV conversion manually */
+void Cffgsfd( fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc, long *trc, long *inc, double *array, int *flagval, int *anynul, int *status );
+void Cffgsfd( fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc, long *trc, long *inc, double *array, int *flagval, int *anynul, int *status )
+{
+ char *Cflagval;
+ long nflagval;
+ int i;
+
+ for( nflagval=1, i=0; i<naxis; i++ )
+ nflagval *= (trc[i]-blc[i])/inc[i]+1;
+ Cflagval = F2CcopyLogVect(nflagval, flagval );
+ ffgsfd( fptr, colnum, naxis, naxes, blc, trc, inc, array, Cflagval, anynul, status );
+ C2FcopyLogVect(nflagval, flagval, Cflagval);
+}
+#define ftgsfd_LONGV_A4 A3+1
+#define ftgsfd_LONGV_A5 A3+1
+#define ftgsfd_LONGV_A6 A3+1
+#define ftgsfd_LONGV_A7 A3+1
+FCALLSCSUB11(Cffgsfd,FTGSFD,ftgsfd,FITSUNIT,INT,INT,LONGV,LONGV,LONGV,LONGV,DOUBLEV,INTV,PLOGICAL,PINT)
+
+FCALLSCSUB6(ffggpb,FTGGPB,ftggpb,FITSUNIT,LONG,LONG,LONG,BYTEV,PINT)
+FCALLSCSUB6(ffggpi,FTGGPI,ftggpi,FITSUNIT,LONG,LONG,LONG,SHORTV,PINT)
+FCALLSCSUB6(ffggpk,FTGGPJ,ftggpj,FITSUNIT,LONG,LONG,LONG,INTV,PINT)
+FCALLSCSUB6(ffggpk,FTGGPK,ftggpk,FITSUNIT,LONG,LONG,LONG,INTV,PINT)
+FCALLSCSUB6(ffggpe,FTGGPE,ftggpe,FITSUNIT,LONG,LONG,LONG,FLOATV,PINT)
+FCALLSCSUB6(ffggpd,FTGGPD,ftggpd,FITSUNIT,LONG,LONG,LONG,DOUBLEV,PINT)
+
+/*--------------------- read column elements -------------*/
+/* To guarantee that we allocate enough memory to hold strings within
+ a table, call FFGTCL first to obtain width of the unique string
+ and use it as the minimum string width. Also test whether column
+ has a variable width in which case a single string is read
+ containing all its characters, so only declare a string vector
+ with 1 element. */
+
+#define ftgcvs_STRV_A7 NUM_ELEMS(velem)
+CFextern VOID_cfF(FTGCVS,ftgcvs)
+CFARGT14(NCF,DCF,ABSOFT_cf2(VOID),FITSUNIT,INT,LONG,LONG,LONG,STRING,PSTRINGV,PLOGICAL,PINT,CF_0,CF_0,CF_0,CF_0,CF_0));
+CFextern VOID_cfF(FTGCVS,ftgcvs)
+CFARGT14(NCF,DCF,ABSOFT_cf2(VOID),FITSUNIT,INT,LONG,LONG,LONG,STRING,PSTRINGV,PLOGICAL,PINT,CF_0,CF_0,CF_0,CF_0,CF_0))
+{
+ QCF(FITSUNIT,1)
+ QCF(INT,2)
+ QCF(LONG,3)
+ QCF(LONG,4)
+ QCF(LONG,5)
+ QCF(STRING,6)
+ QCF(PSTRINGV,7)
+ QCF(PLOGICAL,8)
+ QCF(PINT,9)
+
+ fitsfile *fptr;
+ int colnum, *anynul, *status, velem, type;
+ long firstrow, firstelem, nelem;
+ long repeat;
+ unsigned long gMinStrLen=80L; /* gMin = width */
+ char *nulval, **array;
+
+ fptr = TCF(ftgcvs,FITSUNIT,1,0);
+ colnum = TCF(ftgcvs,INT,2,0);
+ firstrow = TCF(ftgcvs,LONG,3,0);
+ firstelem = TCF(ftgcvs,LONG,4,0);
+ nelem = TCF(ftgcvs,LONG,5,0);
+ nulval = TCF(ftgcvs,STRING,6,0);
+ /* put off variable 7 (array) until column type is learned */
+ anynul = TCF(ftgcvs,PLOGICAL,8,0);
+ status = TCF(ftgcvs,PINT,9,0);
+
+ ffgtcl( fptr, colnum, &type, &repeat, (long *)&gMinStrLen, status );
+ if( type<0 ) velem = 1; /* Variable length column */
+ else velem = nelem;
+
+ array = TCF(ftgcvs,PSTRINGV,7,0);
+
+ ffgcvs( fptr, colnum, firstrow, firstelem, nelem, nulval, array,
+ anynul, status );
+
+ RCF(FITSUNIT,1)
+ RCF(INT,2)
+ RCF(LONG,3)
+ RCF(LONG,4)
+ RCF(LONG,5)
+ RCF(STRING,6)
+ RCF(PSTRINGV,7)
+ RCF(PLOGICAL,8)
+ RCF(PINT,9)
+}
+
+
+
+#define ftgcl_LOGV_A6 A5
+FCALLSCSUB7(ffgcl,FTGCL,ftgcl,FITSUNIT,INT,LONG,LONG,LONG,LOGICALV,PINT)
+
+#define ftgcvl_LOGV_A7 A5
+FCALLSCSUB9(ffgcvl,FTGCVL,ftgcvl,FITSUNIT,INT,LONG,LONG,LONG,LOGICAL,LOGICALV,PLOGICAL,PINT)
+FCALLSCSUB9(ffgcvb,FTGCVB,ftgcvb,FITSUNIT,INT,LONG,LONG,LONG,BYTE,BYTEV,PLOGICAL,PINT)
+FCALLSCSUB9(ffgcvi,FTGCVI,ftgcvi,FITSUNIT,INT,LONG,LONG,LONG,SHORT,SHORTV,PLOGICAL,PINT)
+FCALLSCSUB9(ffgcvk,FTGCVJ,ftgcvj,FITSUNIT,INT,LONG,LONG,LONG,INT,INTV,PLOGICAL,PINT)
+FCALLSCSUB9(ffgcvk,FTGCVK,ftgcvk,FITSUNIT,INT,LONG,LONG,LONG,INT,INTV,PLOGICAL,PINT)
+FCALLSCSUB9(ffgcve,FTGCVE,ftgcve,FITSUNIT,INT,LONG,LONG,LONG,FLOAT,FLOATV,PLOGICAL,PINT)
+FCALLSCSUB9(ffgcvd,FTGCVD,ftgcvd,FITSUNIT,INT,LONG,LONG,LONG,DOUBLE,DOUBLEV,PLOGICAL,PINT)
+FCALLSCSUB9(ffgcvc,FTGCVC,ftgcvc,FITSUNIT,INT,LONG,LONG,LONG,FLOAT,FLOATV,PLOGICAL,PINT)
+FCALLSCSUB9(ffgcvm,FTGCVM,ftgcvm,FITSUNIT,INT,LONG,LONG,LONG,DOUBLE,DOUBLEV,PLOGICAL,PINT)
+
+#define ftgcx_LOGV_A6 A5
+FCALLSCSUB7(ffgcx,FTGCX,ftgcx,FITSUNIT,INT,LONG,LONG,LONG,LOGICALV,PINT)
+
+/* We need to worry about unsigned vs signed pointers in the following */
+/* two routines, so use a pair of C wrappers which cast the pointers */
+/* before passing them to CFITSIO. */
+
+void Cffgcxui(fitsfile *fptr, int colnum, long firstrow, long nrows,
+ long firstbit, int nbits, short *array, int *status);
+void Cffgcxui(fitsfile *fptr, int colnum, long firstrow, long nrows,
+ long firstbit, int nbits, short *array, int *status)
+{
+ ffgcxui( fptr, colnum, firstrow, nrows, firstbit, nbits,
+ (unsigned short *)array, status );
+}
+FCALLSCSUB8(Cffgcxui,FTGCXI,ftgcxi,FITSUNIT,INT,LONG,LONG,LONG,INT,SHORTV,PINT)
+
+void Cffgcxuk(fitsfile *fptr, int colnum, long firstrow, long nrows,
+ long firstbit, int nbits, int *array, int *status);
+void Cffgcxuk(fitsfile *fptr, int colnum, long firstrow, long nrows,
+ long firstbit, int nbits, int *array, int *status)
+{
+ ffgcxuk( fptr, colnum, firstrow, nrows, firstbit, nbits,
+ (unsigned int *)array, status );
+}
+FCALLSCSUB8(Cffgcxuk,FTGCXJ,ftgcxj,FITSUNIT,INT,LONG,LONG,LONG,INT,INTV,PINT)
+
+/* To guarantee that we allocate enough memory to hold strings within
+ a table, call FFGTCL first to obtain width of the unique string
+ and use it as the minimum string width. Also test whether column
+ has a variable width in which case a single string is read
+ containing all its characters, so only declare a string vector
+ with 1 element. */
+
+#define ftgcfs_STRV_A6 NUM_ELEMS(velem)
+#define ftgcfs_LOGV_A7 A5
+CFextern VOID_cfF(FTGCFS,ftgcfs)
+CFARGT14(NCF,DCF,ABSOFT_cf2(VOID),FITSUNIT,INT,LONG,LONG,LONG,PSTRINGV,LOGICALV,PLOGICAL,PINT,CF_0,CF_0,CF_0,CF_0,CF_0));
+CFextern VOID_cfF(FTGCFS,ftgcfs)
+CFARGT14(NCF,DCF,ABSOFT_cf2(VOID),FITSUNIT,INT,LONG,LONG,LONG,PSTRINGV,LOGICALV,PLOGICAL,PINT,CF_0,CF_0,CF_0,CF_0,CF_0))
+{
+ QCF(FITSUNIT,1)
+ QCF(INT,2)
+ QCF(LONG,3)
+ QCF(LONG,4)
+ QCF(LONG,5)
+ QCF(PSTRINGV,6)
+ QCF(LOGICALV,7)
+ QCF(PLOGICAL,8)
+ QCF(PINT,9)
+
+ fitsfile *fptr;
+ int colnum, *anynul, *status, velem, type;
+ long firstrow, firstelem, nelem;
+ long repeat;
+ unsigned long gMinStrLen=80L; /* gMin = width */
+ char **array, *nularray;
+
+ fptr = TCF(ftgcfs,FITSUNIT,1,0);
+ colnum = TCF(ftgcfs,INT,2,0);
+ firstrow = TCF(ftgcfs,LONG,3,0);
+ firstelem = TCF(ftgcfs,LONG,4,0);
+ nelem = TCF(ftgcfs,LONG,5,0);
+ /* put off variable 6 (array) until column type is learned */
+ nularray = TCF(ftgcfs,LOGICALV,7,0);
+ anynul = TCF(ftgcfs,PLOGICAL,8,0);
+ status = TCF(ftgcfs,PINT,9,0);
+
+ ffgtcl( fptr, colnum, &type, &repeat, (long*)&gMinStrLen, status );
+ if( type<0 ) velem = 1; /* Variable length column */
+ else velem = nelem;
+
+ array = TCF(ftgcfs,PSTRINGV,6,0);
+
+ ffgcfs( fptr, colnum, firstrow, firstelem, nelem, array, nularray,
+ anynul, status);
+
+ RCF(FITSUNIT,1)
+ RCF(INT,2)
+ RCF(LONG,3)
+ RCF(LONG,4)
+ RCF(LONG,5)
+ RCF(PSTRINGV,6)
+ RCF(LOGICALV,7)
+ RCF(PLOGICAL,8)
+ RCF(PINT,9)
+}
+
+
+
+#define ftgcfl_LOGV_A6 A5
+#define ftgcfl_LOGV_A7 A5
+FCALLSCSUB9(ffgcfl,FTGCFL,ftgcfl,FITSUNIT,INT,LONG,LONG,LONG,LOGICALV,LOGICALV,PLOGICAL,PINT)
+
+#define ftgcfb_LOGV_A7 A5
+FCALLSCSUB9(ffgcfb,FTGCFB,ftgcfb,FITSUNIT,INT,LONG,LONG,LONG,BYTEV,LOGICALV,PLOGICAL,PINT)
+
+#define ftgcfi_LOGV_A7 A5
+FCALLSCSUB9(ffgcfi,FTGCFI,ftgcfi,FITSUNIT,INT,LONG,LONG,LONG,SHORTV,LOGICALV,PLOGICAL,PINT)
+
+#define ftgcfj_LOGV_A7 A5
+FCALLSCSUB9(ffgcfk,FTGCFJ,ftgcfj,FITSUNIT,INT,LONG,LONG,LONG,INTV,LOGICALV,PLOGICAL,PINT)
+
+#define ftgcfk_LOGV_A7 A5
+FCALLSCSUB9(ffgcfk,FTGCFK,ftgcfk,FITSUNIT,INT,LONG,LONG,LONG,INTV,LOGICALV,PLOGICAL,PINT)
+
+#define ftgcfe_LOGV_A7 A5
+FCALLSCSUB9(ffgcfe,FTGCFE,ftgcfe,FITSUNIT,INT,LONG,LONG,LONG,FLOATV,LOGICALV,PLOGICAL,PINT)
+
+#define ftgcfd_LOGV_A7 A5
+FCALLSCSUB9(ffgcfd,FTGCFD,ftgcfd,FITSUNIT,INT,LONG,LONG,LONG,DOUBLEV,LOGICALV,PLOGICAL,PINT)
+
+/* Must handle LOGICALV conversion manually */
+void Cffgcfc( fitsfile *fptr, int colnum, long firstrow, long firstelem, long nelem, float *array, int *nularray, int *anynul, int *status );
+void Cffgcfc( fitsfile *fptr, int colnum, long firstrow, long firstelem, long nelem, float *array, int *nularray, int *anynul, int *status )
+{
+ char *Cnularray;
+
+ Cnularray = F2CcopyLogVect(nelem*2, nularray );
+ ffgcfc( fptr, colnum, firstrow, firstelem, nelem, array, Cnularray, anynul, status );
+ C2FcopyLogVect(nelem*2, nularray, Cnularray );
+}
+FCALLSCSUB9(Cffgcfc,FTGCFC,ftgcfc,FITSUNIT,INT,LONG,LONG,LONG,FLOATV,INTV,PLOGICAL,PINT)
+
+/* Must handle LOGICALV conversion manually */
+void Cffgcfm( fitsfile *fptr, int colnum, long firstrow, long firstelem, long nelem, double *array, int *nularray, int *anynul, int *status );
+void Cffgcfm( fitsfile *fptr, int colnum, long firstrow, long firstelem, long nelem, double *array, int *nularray, int *anynul, int *status )
+{
+ char *Cnularray;
+
+ Cnularray = F2CcopyLogVect(nelem*2, nularray );
+ ffgcfm( fptr, colnum, firstrow, firstelem, nelem, array, Cnularray, anynul, status );
+ C2FcopyLogVect(nelem*2, nularray, Cnularray );
+}
+FCALLSCSUB9(Cffgcfm,FTGCFM,ftgcfm,FITSUNIT,INT,LONG,LONG,LONG,DOUBLEV,INTV,PLOGICAL,PINT)
+
+FCALLSCSUB6(ffgdes,FTGDES,ftgdes,FITSUNIT,INT,LONG,PLONG,PLONG,PINT)
+
+FCALLSCSUB6(ffgtbb,FTGTBB,ftgtbb,FITSUNIT,LONG,LONG,LONG,BYTEV,PINT)
+FCALLSCSUB6(ffgtbb,FTGTBS,ftgtbs,FITSUNIT,LONG,LONG,LONG,BYTEV,PINT)
+
+/*------------ write primary array or image elements -------------*/
+FCALLSCSUB6(ffpprb,FTPPRB,ftpprb,FITSUNIT,LONG,LONG,LONG,BYTEV,PINT)
+FCALLSCSUB6(ffppri,FTPPRI,ftppri,FITSUNIT,LONG,LONG,LONG,SHORTV,PINT)
+FCALLSCSUB6(ffpprk,FTPPRJ,ftpprj,FITSUNIT,LONG,LONG,LONG,INTV,PINT)
+FCALLSCSUB6(ffpprk,FTPPRK,ftpprk,FITSUNIT,LONG,LONG,LONG,INTV,PINT)
+FCALLSCSUB6(ffppre,FTPPRE,ftppre,FITSUNIT,LONG,LONG,LONG,FLOATV,PINT)
+FCALLSCSUB6(ffpprd,FTPPRD,ftpprd,FITSUNIT,LONG,LONG,LONG,DOUBLEV,PINT)
+
+FCALLSCSUB7(ffppnb,FTPPNB,ftppnb,FITSUNIT,LONG,LONG,LONG,BYTEV,BYTE,PINT)
+FCALLSCSUB7(ffppni,FTPPNI,ftppni,FITSUNIT,LONG,LONG,LONG,SHORTV,SHORT,PINT)
+FCALLSCSUB7(ffppnk,FTPPNJ,ftppnj,FITSUNIT,LONG,LONG,LONG,INTV,INT,PINT)
+FCALLSCSUB7(ffppnk,FTPPNK,ftppnk,FITSUNIT,LONG,LONG,LONG,INTV,INT,PINT)
+FCALLSCSUB7(ffppne,FTPPNE,ftppne,FITSUNIT,LONG,LONG,LONG,FLOATV,FLOAT,PINT)
+FCALLSCSUB7(ffppnd,FTPPND,ftppnd,FITSUNIT,LONG,LONG,LONG,DOUBLEV,DOUBLE,PINT)
+
+FCALLSCSUB7(ffp2db,FTP2DB,ftp2db,FITSUNIT,LONG,LONG,LONG,LONG,BYTEV,PINT)
+FCALLSCSUB7(ffp2di,FTP2DI,ftp2di,FITSUNIT,LONG,LONG,LONG,LONG,SHORTV,PINT)
+FCALLSCSUB7(ffp2dk,FTP2DJ,ftp2dj,FITSUNIT,LONG,LONG,LONG,LONG,INTV,PINT)
+FCALLSCSUB7(ffp2dk,FTP2DK,ftp2dk,FITSUNIT,LONG,LONG,LONG,LONG,INTV,PINT)
+FCALLSCSUB7(ffp2de,FTP2DE,ftp2de,FITSUNIT,LONG,LONG,LONG,LONG,FLOATV,PINT)
+FCALLSCSUB7(ffp2dd,FTP2DD,ftp2dd,FITSUNIT,LONG,LONG,LONG,LONG,DOUBLEV,PINT)
+
+FCALLSCSUB9(ffp3db,FTP3DB,ftp3db,FITSUNIT,LONG,LONG,LONG,LONG,LONG,LONG,BYTEV,PINT)
+FCALLSCSUB9(ffp3di,FTP3DI,ftp3di,FITSUNIT,LONG,LONG,LONG,LONG,LONG,LONG,SHORTV,PINT)
+FCALLSCSUB9(ffp3dk,FTP3DJ,ftp3dj,FITSUNIT,LONG,LONG,LONG,LONG,LONG,LONG,INTV,PINT)
+FCALLSCSUB9(ffp3dk,FTP3DK,ftp3dk,FITSUNIT,LONG,LONG,LONG,LONG,LONG,LONG,INTV,PINT)
+FCALLSCSUB9(ffp3de,FTP3DE,ftp3de,FITSUNIT,LONG,LONG,LONG,LONG,LONG,LONG,FLOATV,PINT)
+FCALLSCSUB9(ffp3dd,FTP3DD,ftp3dd,FITSUNIT,LONG,LONG,LONG,LONG,LONG,LONG,DOUBLEV,PINT)
+
+#define ftpssb_LONGV_A4 A3
+#define ftpssb_LONGV_A5 A3
+#define ftpssb_LONGV_A6 A3
+FCALLSCSUB8(ffpssb,FTPSSB,ftpssb,FITSUNIT,LONG,LONG,LONGV,LONGV,LONGV,BYTEV,PINT)
+
+#define ftpssi_LONGV_A4 A3
+#define ftpssi_LONGV_A5 A3
+#define ftpssi_LONGV_A6 A3
+FCALLSCSUB8(ffpssi,FTPSSI,ftpssi,FITSUNIT,LONG,LONG,LONGV,LONGV,LONGV,SHORTV,PINT)
+
+#define ftpssj_LONGV_A4 A3
+#define ftpssj_LONGV_A5 A3
+#define ftpssj_LONGV_A6 A3
+FCALLSCSUB8(ffpssk,FTPSSJ,ftpssj,FITSUNIT,LONG,LONG,LONGV,LONGV,LONGV,INTV,PINT)
+
+#define ftpssk_LONGV_A4 A3
+#define ftpssk_LONGV_A5 A3
+#define ftpssk_LONGV_A6 A3
+FCALLSCSUB8(ffpssk,FTPSSK,ftpssk,FITSUNIT,LONG,LONG,LONGV,LONGV,LONGV,INTV,PINT)
+
+#define ftpsse_LONGV_A4 A3
+#define ftpsse_LONGV_A5 A3
+#define ftpsse_LONGV_A6 A3
+FCALLSCSUB8(ffpsse,FTPSSE,ftpsse,FITSUNIT,LONG,LONG,LONGV,LONGV,LONGV,FLOATV,PINT)
+
+#define ftpssd_LONGV_A4 A3
+#define ftpssd_LONGV_A5 A3
+#define ftpssd_LONGV_A6 A3
+FCALLSCSUB8(ffpssd,FTPSSD,ftpssd,FITSUNIT,LONG,LONG,LONGV,LONGV,LONGV,DOUBLEV,PINT)
+
+FCALLSCSUB6(ffpgpb,FTPGPB,ftpgpb,FITSUNIT,LONG,LONG,LONG,BYTEV,PINT)
+FCALLSCSUB6(ffpgpi,FTPGPI,ftpgpi,FITSUNIT,LONG,LONG,LONG,SHORTV,PINT)
+FCALLSCSUB6(ffpgpk,FTPGPJ,ftpgpj,FITSUNIT,LONG,LONG,LONG,INTV,PINT)
+FCALLSCSUB6(ffpgpk,FTPGPK,ftpgpk,FITSUNIT,LONG,LONG,LONG,INTV,PINT)
+FCALLSCSUB6(ffpgpe,FTPGPE,ftpgpe,FITSUNIT,LONG,LONG,LONG,FLOATV,PINT)
+FCALLSCSUB6(ffpgpd,FTPGPD,ftpgpd,FITSUNIT,LONG,LONG,LONG,DOUBLEV,PINT)
+
+FCALLSCSUB5(ffppru,FTPPRU,ftppru,FITSUNIT,LONG,LONG,LONG,PINT)
+FCALLSCSUB4(ffpprn,FTPPRN,ftpprn,FITSUNIT,LONG,LONG,PINT)
+
+/*--------------------- write column elements -------------*/
+#define ftpcls_STRV_A6 NUM_ELEM_ARG(5)
+FCALLSCSUB7(ffpcls,FTPCLS,ftpcls,FITSUNIT,INT,LONG,LONG,LONG,STRINGV,PINT)
+
+#define ftpcll_LOGV_A6 A5
+FCALLSCSUB7(ffpcll,FTPCLL,ftpcll,FITSUNIT,INT,LONG,LONG,LONG,LOGICALV,PINT)
+FCALLSCSUB7(ffpclb,FTPCLB,ftpclb,FITSUNIT,INT,LONG,LONG,LONG,BYTEV,PINT)
+FCALLSCSUB7(ffpcli,FTPCLI,ftpcli,FITSUNIT,INT,LONG,LONG,LONG,SHORTV,PINT)
+FCALLSCSUB7(ffpclk,FTPCLJ,ftpclj,FITSUNIT,INT,LONG,LONG,LONG,INTV,PINT)
+FCALLSCSUB7(ffpclk,FTPCLK,ftpclk,FITSUNIT,INT,LONG,LONG,LONG,INTV,PINT)
+FCALLSCSUB7(ffpcle,FTPCLE,ftpcle,FITSUNIT,INT,LONG,LONG,LONG,FLOATV,PINT)
+FCALLSCSUB7(ffpcld,FTPCLD,ftpcld,FITSUNIT,INT,LONG,LONG,LONG,DOUBLEV,PINT)
+FCALLSCSUB7(ffpclc,FTPCLC,ftpclc,FITSUNIT,INT,LONG,LONG,LONG,FLOATV,PINT)
+FCALLSCSUB7(ffpclm,FTPCLM,ftpclm,FITSUNIT,INT,LONG,LONG,LONG,DOUBLEV,PINT)
+FCALLSCSUB6(ffpclu,FTPCLU,ftpclu,FITSUNIT,INT,LONG,LONG,LONG,PINT)
+
+#define ftpclx_LOGV_A6 A5
+FCALLSCSUB7(ffpclx,FTPCLX,ftpclx,FITSUNIT,INT,LONG,LONG,LONG,LOGICALV,PINT)
+
+#define ftpcns_STRV_A6 NUM_ELEM_ARG(5)
+FCALLSCSUB8(ffpcns,FTPCNS,ftpcns,FITSUNIT,INT,LONG,LONG,LONG,STRINGV,STRING,PINT)
+
+FCALLSCSUB8(ffpcnb,FTPCNB,ftpcnb,FITSUNIT,INT,LONG,LONG,LONG,BYTEV,BYTE,PINT)
+FCALLSCSUB8(ffpcni,FTPCNI,ftpcni,FITSUNIT,INT,LONG,LONG,LONG,SHORTV,SHORT,PINT)
+FCALLSCSUB8(ffpcnk,FTPCNJ,ftpcnj,FITSUNIT,INT,LONG,LONG,LONG,INTV,INT,PINT)
+FCALLSCSUB8(ffpcnk,FTPCNK,ftpcnk,FITSUNIT,INT,LONG,LONG,LONG,INTV,INT,PINT)
+FCALLSCSUB8(ffpcne,FTPCNE,ftpcne,FITSUNIT,INT,LONG,LONG,LONG,FLOATV,FLOAT,PINT)
+FCALLSCSUB8(ffpcnd,FTPCND,ftpcnd,FITSUNIT,INT,LONG,LONG,LONG,DOUBLEV,DOUBLE,PINT)
+
+FCALLSCSUB6(ffpdes,FTPDES,ftpdes,FITSUNIT,INT,LONG,LONG,LONG,PINT)
+
+FCALLSCSUB6(ffptbb,FTPTBB,ftptbb,FITSUNIT,LONG,LONG,LONG,BYTEV,PINT)
+ /* Add extra entry point to ffptbb... ftptbs obsolete */
+FCALLSCSUB6(ffptbb,FTPTBS,ftptbs,FITSUNIT,LONG,LONG,LONG,BYTEV,PINT)
+
+FCALLSCSUB4(ffirow,FTIROW,ftirow,FITSUNIT,LONG,LONG,PINT)
+FCALLSCSUB4(ffdrow,FTDROW,ftdrow,FITSUNIT,LONG,LONG,PINT)
+#define ftdrws_LONGV_A2 A3
+FCALLSCSUB4(ffdrws,FTDRWS,ftdrws,FITSUNIT,LONGV,LONG,PINT)
+FCALLSCSUB5(fficol,FTICOL,fticol,FITSUNIT,INT,STRING,STRING,PINT)
+
+#define fticls_STRV_A4 NUM_ELEM_ARG(3)
+#define fticls_STRV_A5 NUM_ELEM_ARG(3)
+FCALLSCSUB6(fficls,FTICLS,fticls,FITSUNIT,INT,INT,STRINGV,STRINGV,PINT)
+FCALLSCSUB4(ffmvec,FTMVEC,ftmvec,FITSUNIT,INT,LONG,PINT)
+FCALLSCSUB3(ffdcol,FTDCOL,ftdcol,FITSUNIT,INT,PINT)
+FCALLSCSUB6(ffcpcl,FTCPCL,ftcpcl,FITSUNIT,FITSUNIT,INT,INT,INT,PINT)
+
+/*********************************************************************/
+/* Iterator Functions */
+/*********************************************************************/
+
+/* Use a simple ellipse prototype for Fwork_fn to satisfy finicky compilers */
+typedef struct {
+ void *userData;
+ void (*Fwork_fn)(PLONG_cfTYPE *total_n, ...);
+} FtnUserData;
+
+/* Declare protoypes to make C++ happy */
+int Cwork_fn(long, long, long, long, int, iteratorCol *, void *);
+void Cffiter( int n_cols, int *units, int *colnum, char *colname[],
+ int *datatype, int *iotype,
+ long offset, long n_per_loop, void *Fwork_fn,
+ void *userData, int *status);
+
+/******************************************************************/
+/* Cffiter is the wrapper for CFITSIO's ffiter which takes most */
+/* of its arguments via a structure, iteratorCol. This routine */
+/* takes a list of arrays and converts them into a single array */
+/* of type iteratorCol and passes it to CFITSIO. Because ffiter */
+/* will be passing control to a Fortran work function, the C */
+/* wrapper, Cwork_fn, must be passed in its place which then */
+/* calls the Fortran routine after the necessary data */
+/* manipulation. The Fortran routine is passed via the user- */
+/* supplied parameter pointer. */
+/******************************************************************/
+
+void Cffiter( int n_cols, int *units, int *colnum, char *colname[],
+ int *datatype, int *iotype,
+ long offset, long n_per_loop, void *Fwork_fn,
+ void *userData, int *status)
+{
+ iteratorCol *cols;
+ int i;
+ FtnUserData FuserData;
+
+ FuserData.Fwork_fn = (void(*)(PLONG_cfTYPE *,...))Fwork_fn;
+ FuserData.userData = userData;
+
+ cols = (iteratorCol *)malloc( n_cols*sizeof(iteratorCol) );
+ if( cols==NULL ) {
+ *status = MEMORY_ALLOCATION;
+ return;
+ }
+ for(i=0;i<n_cols;i++) {
+ cols[i].fptr = gFitsFiles[ units[i] ];
+ cols[i].colnum = colnum[i];
+ strncpy(cols[i].colname,colname[i],70);
+ cols[i].datatype = datatype[i];
+ cols[i].iotype = iotype[i];
+ }
+
+ ffiter( n_cols, cols, offset, n_per_loop, Cwork_fn,
+ (void*)&FuserData, status );
+ free(cols);
+}
+#define ftiter_STRV_A4 NUM_ELEM_ARG(1)
+FCALLSCSUB11(Cffiter,FTITER,ftiter,INT,INTV,INTV,STRINGV,INTV,INTV,LONG,LONG,PVOID,PVOID,PINT)
+
+/*-----------------------------------------------------------------*/
+/* This function is called by CFITSIO's ffiter and serves as the */
+/* wrapper for the Fortran work function which is passed in the */
+/* extra user-supplied pointer. It breaks up C's iteratorCol */
+/* into several separate arrays. Because we cannot send an */
+/* array of pointers for the column data, we instead send *many* */
+/* arrays as final parameters. */
+/*-----------------------------------------------------------------*/
+
+int Cwork_fn( long total_n, long offset, long first_n, long n_values,
+ int n_cols, iteratorCol *cols, void *FuserData )
+{
+ int *units, *colnum, *datatype, *iotype, *repeat;
+ char **sptr;
+ void **ptrs;
+ int i,j,k,nstr,status=0;
+ long *slen;
+
+#ifdef vmsFortran
+ /* Passing strings under VMS require a special structure */
+ fstringvector *vmsStrs;
+#endif
+
+ /* Allocate memory for all the arrays. Grab all the int's */
+ /* at once and divide up among parameters */
+
+ ptrs = (void**)malloc(2*n_cols*sizeof(void*));
+ if( ptrs==NULL )
+ return( MEMORY_ALLOCATION );
+ units = (int*)malloc(5*n_cols*sizeof(int));
+ if( units==NULL ) {
+ free(ptrs);
+ return( MEMORY_ALLOCATION );
+ }
+ colnum = units + 1 * n_cols;
+ datatype = units + 2 * n_cols;
+ iotype = units + 3 * n_cols;
+ repeat = units + 4 * n_cols;
+
+ nstr = 0;
+ slen = (long*)(ptrs+n_cols);
+#ifdef vmsFortran
+ vmsStrs = (fstringvector *)calloc(sizeof(fstringvector),n_cols);
+ if( vmsStrs==NULL ) {
+ free(ptrs);
+ free(units);
+ return( MEMORY_ALLOCATION );
+ }
+#endif
+
+ for(i=0;i<n_cols;i++) {
+ for(j=0;j<MAXFITSFILES;j++)
+ if( cols[i].fptr==gFitsFiles[j] )
+ units[i] = j;
+ colnum[i] = cols[i].colnum;
+ datatype[i] = cols[i].datatype;
+ iotype[i] = cols[i].iotype;
+ repeat[i] = cols[i].repeat;
+
+ if( datatype[i]==TLOGICAL ) {
+ /* Don't forget first element is null value */
+ ptrs[i] = (void *)malloc( (n_values*repeat[i]+1)*4 );
+ if( ptrs[i]==NULL ) {
+ free(ptrs);
+ free(units);
+ return( MEMORY_ALLOCATION );
+ }
+ for( j=0;j<=n_values*repeat[i]; j++ )
+ ((int*)ptrs[i])[j] = C2FLOGICAL( ((char*)cols[i].array)[j]);
+ } else if ( datatype[i]==TSTRING ) {
+ sptr = (char**)cols[i].array;
+ slen[nstr] = sptr[1] - sptr[0];
+ for(j=0;j<=n_values;j++)
+ for(k=strlen( sptr[j] );k<slen[nstr];k++)
+ sptr[j][k] = ' ';
+#ifdef vmsFortran
+ vmsStrs[nstr].dsc$a_pointer = sptr[0];
+ vmsStrs[nstr].dsc$w_length = slen[nstr];
+ vmsStrs[nstr].dsc$l_m[0] = n_values+1;
+ vmsStrs[nstr].dsc$l_arsize = slen[nstr] * (n_values+1);
+ vmsStrs[nstr].dsc$bounds[0].dsc$l_u = n_values+1;
+ vmsStrs[nstr].dsc$a_a0 = sptr[0] - slen[nstr];
+ ptrs[i] = (void *)(vmsStrs+nstr);
+#else
+ ptrs[i] = (void *)sptr[0];
+#endif
+ nstr++;
+ } else
+ ptrs[i] = (void *)cols[i].array;
+ }
+
+ if(!status) {
+ /* Handle Fortran function call manually... */
+ /* cfortran.h cannot handle all the desired */
+ /* 'ptrs' nor the indirect function call. */
+
+ PLONG_cfTYPE a1,a2,a3,a4; /* Do this in case longs are */
+ FtnUserData *f; /* not the same size as ints */
+
+ a1 = total_n;
+ a2 = offset;
+ a3 = first_n;
+ a4 = n_values;
+ f = (FtnUserData *)FuserData;
+
+ f->Fwork_fn(&a1,&a2,&a3,&a4,&n_cols,units,colnum,datatype,
+ iotype,repeat,&status,f->userData,
+ ptrs[ 0], ptrs[ 1], ptrs[ 2], ptrs[ 3], ptrs[ 4],
+ ptrs[ 5], ptrs[ 6], ptrs[ 7], ptrs[ 8], ptrs[ 9],
+ ptrs[10], ptrs[11], ptrs[12], ptrs[13], ptrs[14],
+ ptrs[15], ptrs[16], ptrs[17], ptrs[18], ptrs[19],
+ ptrs[20], ptrs[21], ptrs[22], ptrs[23], ptrs[24] );
+ }
+
+ /* Check whether there are any LOGICAL or STRING columns being outputted */
+ nstr=0;
+ for( i=0;i<n_cols;i++ ) {
+ if( iotype[i]!=InputCol ) {
+ if( datatype[i]==TLOGICAL ) {
+ for( j=0;j<=n_values*repeat[i];j++ )
+ ((char*)cols[i].array)[j] = F2CLOGICAL( ((int*)ptrs[i])[j] );
+ free(ptrs[i]);
+ } else if( datatype[i]==TSTRING ) {
+ for( j=0;j<=n_values;j++ )
+ ((char**)cols[i].array)[j][slen[nstr]-1] = '\0';
+ }
+ }
+ if( datatype[i]==TSTRING ) nstr++;
+ }
+
+ free(ptrs);
+ free(units);
+#ifdef vmsFortran
+ free(vmsStrs);
+#endif
+ return(status);
+}
+
+
+/*--------------------- WCS Utilities ----------------------------*/
+FCALLSCSUB10(ffgics,FTGICS,ftgics,FITSUNIT,PDOUBLE,PDOUBLE,PDOUBLE,PDOUBLE,PDOUBLE,PDOUBLE,PDOUBLE,PSTRING,PINT)
+FCALLSCSUB12(ffgtcs,FTGTCS,ftgtcs,FITSUNIT,INT,INT,PDOUBLE,PDOUBLE,PDOUBLE,PDOUBLE,PDOUBLE,PDOUBLE,PDOUBLE,PSTRING,PINT)
+FCALLSCSUB13(ffwldp,FTWLDP,ftwldp,DOUBLE,DOUBLE,DOUBLE,DOUBLE,DOUBLE,DOUBLE,DOUBLE,DOUBLE,DOUBLE,STRING,PDOUBLE,PDOUBLE,PINT)
+FCALLSCSUB13(ffxypx,FTXYPX,ftxypx,DOUBLE,DOUBLE,DOUBLE,DOUBLE,DOUBLE,DOUBLE,DOUBLE,DOUBLE,DOUBLE,STRING,PDOUBLE,PDOUBLE,PINT)
+
+/*------------------- Conversion Utilities -----------------*/
+/* (prototyped in fitsio2.h) */
+/*----------------------------------------------------------*/
+
+CFextern VOID_cfF(FTI2C,fti2c)
+CFARGT14(NCF,DCF,ABSOFT_cf2(VOID),LONG,PSTRING,PINT,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0));
+CFextern VOID_cfF(FTI2C,fti2c)
+CFARGT14(NCF,DCF,ABSOFT_cf2(VOID),LONG,PSTRING,PINT,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0))
+{
+ QCF(LONG,1)
+ QCF(PSTRING,2)
+ QCF(PINT,3)
+ char str[21];
+
+ ffi2c( TCF(fti2c,LONG,1,0)
+ TCF(fti2c,PSTRING,2,1)
+ TCF(fti2c,PINT,3,1) );
+
+ sprintf(str,"%20s",B2);
+ strcpy(B2,str);
+
+ RCF(LONG,1)
+ RCF(PSTRING,2)
+ RCF(PINT,3)
+}
+
+CFextern VOID_cfF(FTL2C,ftl2c)
+CFARGT14(NCF,DCF,ABSOFT_cf2(VOID),LOGICAL,PSTRING,PINT,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0));
+CFextern VOID_cfF(FTL2C,ftl2c)
+CFARGT14(NCF,DCF,ABSOFT_cf2(VOID),LOGICAL,PSTRING,PINT,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0))
+{
+ QCF(LOGICAL,1)
+ QCF(PSTRING,2)
+ QCF(PINT,3)
+ char str[21];
+
+ ffl2c( TCF(ftl2c,LOGICAL,1,0)
+ TCF(ftl2c,PSTRING,2,1)
+ TCF(ftl2c,PINT,3,1) );
+
+ sprintf(str,"%20s",B2);
+ strcpy(B2,str);
+
+ RCF(LOGICAL,1)
+ RCF(PSTRING,2)
+ RCF(PINT,3)
+}
+
+FCALLSCSUB3(ffs2c,FTS2C,fts2c,STRING,PSTRING,PINT)
+
+CFextern VOID_cfF(FTR2F,ftr2f)
+CFARGT14(NCF,DCF,ABSOFT_cf2(VOID),FLOAT,INT,PSTRING,PINT,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0));
+CFextern VOID_cfF(FTR2F,ftr2f)
+CFARGT14(NCF,DCF,ABSOFT_cf2(VOID),FLOAT,INT,PSTRING,PINT,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0))
+{
+ QCF(FLOAT,1)
+ QCF(INT,2)
+ QCF(PSTRING,3)
+ QCF(PINT,4)
+ char str[21];
+
+ ffr2f( TCF(ftr2f,FLOAT,1,0)
+ TCF(ftr2f,INT,2,1)
+ TCF(ftr2f,PSTRING,3,1)
+ TCF(ftr2f,PINT,4,1) );
+
+ sprintf(str,"%20s",B3);
+ strcpy(B3,str);
+
+ RCF(FLOAT,1)
+ RCF(INT,2)
+ RCF(PSTRING,3)
+ RCF(PINT,4)
+}
+
+CFextern VOID_cfF(FTR2E,ftr2e)
+CFARGT14(NCF,DCF,ABSOFT_cf2(VOID),FLOAT,INT,PSTRING,PINT,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0));
+CFextern VOID_cfF(FTR2E,ftr2e)
+CFARGT14(NCF,DCF,ABSOFT_cf2(VOID),FLOAT,INT,PSTRING,PINT,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0))
+{
+ QCF(FLOAT,1)
+ QCF(INT,2)
+ QCF(PSTRING,3)
+ QCF(PINT,4)
+ char str[21];
+
+ ffr2e( TCF(ftr2e,FLOAT,1,0)
+ TCF(ftr2e,INT,2,1)
+ TCF(ftr2e,PSTRING,3,1)
+ TCF(ftr2e,PINT,4,1) );
+
+ sprintf(str,"%20s",B3);
+ strcpy(B3,str);
+
+ RCF(FLOAT,1)
+ RCF(INT,2)
+ RCF(PSTRING,3)
+ RCF(PINT,4)
+}
+
+CFextern VOID_cfF(FTD2F,ftd2f)
+CFARGT14(NCF,DCF,ABSOFT_cf2(VOID),DOUBLE,INT,PSTRING,PINT,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0));
+CFextern VOID_cfF(FTD2F,ftd2f)
+CFARGT14(NCF,DCF,ABSOFT_cf2(VOID),DOUBLE,INT,PSTRING,PINT,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0))
+{
+ QCF(DOUBLE,1)
+ QCF(INT,2)
+ QCF(PSTRING,3)
+ QCF(PINT,4)
+ char str[21];
+
+ ffd2f( TCF(ftd2f,DOUBLE,1,0)
+ TCF(ftd2f,INT,2,1)
+ TCF(ftd2f,PSTRING,3,1)
+ TCF(ftd2f,PINT,4,1) );
+
+ sprintf(str,"%20s",B3);
+ strcpy(B3,str);
+
+ RCF(DOUBLE,1)
+ RCF(INT,2)
+ RCF(PSTRING,3)
+ RCF(PINT,4)
+}
+
+CFextern VOID_cfF(FTD2E,ftd2e)
+CFARGT14(NCF,DCF,ABSOFT_cf2(VOID),DOUBLE,INT,PSTRING,PINT,PINT,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0));
+CFextern VOID_cfF(FTD2E,ftd2e)
+CFARGT14(NCF,DCF,ABSOFT_cf2(VOID),DOUBLE,INT,PSTRING,PINT,PINT,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0))
+{
+ QCF(DOUBLE,1)
+ QCF(INT,2)
+ QCF(PSTRING,3)
+ QCF(PINT,4)
+ QCF(PINT,5)
+ char str[21];
+ int *vlen;
+
+ vlen = TCF(ftd2e,PINT,4,0);
+
+ /* C version of routine doesn't use the 4th parameter, vlen */
+ ffd2e( TCF(ftd2e,DOUBLE,1,0)
+ TCF(ftd2e,INT,2,1)
+ TCF(ftd2e,PSTRING,3,1)
+ TCF(ftd2e,PINT,5,1) );
+
+ *vlen = strlen(B3);
+ if ( *vlen<20 ) {
+ sprintf(str,"%20s",B3); /* right justify if vlen<20 characters */
+ strcpy(B3,str);
+ *vlen = 20;
+ }
+
+ RCF(DOUBLE,1)
+ RCF(INT,2)
+ RCF(PSTRING,3)
+ RCF(PINT,4)
+ RCF(PINT,5)
+}
+
+FCALLSCSUB3(ffc2ii,FTC2II,ftc2ii,STRING,PLONG,PINT)
+FCALLSCSUB3(ffc2ll,FTC2LL,ftc2ll,STRING,PINT,PINT)
+FCALLSCSUB3(ffc2rr,FTC2RR,ftc2rr,STRING,PFLOAT,PINT)
+FCALLSCSUB3(ffc2dd,FTC2DD,ftc2dd,STRING,PDOUBLE,PINT)
+FCALLSCSUB7(ffc2x,FTC2X,ftc2x,STRING,PSTRING,PLONG,PINT,PSTRING,PDOUBLE,PINT)
+FCALLSCSUB3(ffc2s,FTC2S,ftc2s,STRING,PSTRING,PINT)
+FCALLSCSUB3(ffc2i,FTC2I,ftc2i,STRING,PLONG,PINT)
+FCALLSCSUB3(ffc2r,FTC2R,ftc2r,STRING,PFLOAT,PINT)
+FCALLSCSUB3(ffc2d,FTC2D,ftc2d,STRING,PDOUBLE,PINT)
+FCALLSCSUB3(ffc2l,FTC2L,ftc2l,STRING,PINT,PINT)
+
+/*------------------ Byte-level read/seek/write -----------------*/
+/* (prototyped in fitsio2.h) */
+/*---------------------------------------------------------------*/
+
+/*
+ ffmbyt should not be called by any application programs, so
+ the wrapper should not need to be defined. If it is needed then
+ the second parameter (LONG) will need to be changed to the
+ equivalent of the C 'off_t' type, which may be 32 or 64 bits long
+ depending on the compiler.
+ -W.Pence (7/21/00)
+
+FCALLSCSUB4(ffmbyt,FTMBYT,ftmbyt,FITSUNIT,LONG,LOGICAL,PINT)
+*/
+
+FCALLSCSUB4(ffgbyt,FTGCBF,ftgcbf,FITSUNIT,LONG,PVOID,PINT)
+FCALLSCSUB4(ffgbyt,FTGBYT,ftgbyt,FITSUNIT,LONG,PVOID,PINT)
+
+FCALLSCSUB4(ffpbyt,FTPCBF,ftpcbf,FITSUNIT,LONG,PVOID,PINT)
+FCALLSCSUB4(ffpbyt,FTPBYT,ftpbyt,FITSUNIT,LONG,PVOID,PINT)
+
+
+/*-------------- Additional missing FITSIO routines -------------*/
+/* (abandoned in CFITSIO) */
+/*---------------------------------------------------------------*/
+
+void Cffcrep( char *comm, char *comm1, int *repeat );
+void Cffcrep( char *comm, char *comm1, int *repeat )
+{
+/*
+ check if the first comment string is to be repeated for all keywords
+ (if the last non-blank character is '&', then it is to be repeated)
+
+ comm input comment string
+ OUTPUT PARAMETERS:
+ comm1 output comment string, = COMM minus the last '&' character
+ repeat TRUE if the last character of COMM was the '&' character
+
+ written by Wm Pence, HEASARC/GSFC, June 1991
+ translated to C by Peter Wilson, HSTX/GSFC, Oct 1997
+*/
+
+ int len;
+
+ *repeat=FALSE;
+ len=strlen(comm);
+ /* cfortran strips trailing spaces so only check last character */
+ if( len && comm[ len-1 ]=='&' ) {
+ strncpy(comm1,comm,len-1); /* Don't copy '&' */
+ comm1[len-1]='\0';
+ *repeat=TRUE;
+ }
+ return;
+}
+FCALLSCSUB3(Cffcrep,FTCREP,ftcrep,STRING,PSTRING,PLOGICAL)
+
+
+/*------------------ Test floats for NAN values -----------------*/
+/* (defined in fitsio2.h) */
+/*---------------------------------------------------------------*/
+
+int Cfnan( float *val );
+int Cfnan( float *val )
+{
+ int code;
+
+#if BYTESWAPPED
+ short *sptr = (short*)val + 1;
+#else
+ short *sptr = (short*)val;
+#endif
+
+ code = fnan(*sptr);
+ if( code==2 ) *val = 0.0; /* Underflow */
+
+ return( code!=0 );
+}
+FCALLSCFUN1(LOGICAL,Cfnan,FTTRNN,fttrnn,PFLOAT)
+
+
+int Cdnan( double *val );
+int Cdnan( double *val )
+{
+ int code;
+
+#if BYTESWAPPED
+ short *sptr = (short*)val + 3;
+#else
+ short *sptr = (short*)val;
+#endif
+
+ code = dnan(*sptr);
+ if( code==2 ) *val = 0.0; /* Underflow */
+
+ return( code!=0 );
+}
+FCALLSCFUN1(LOGICAL,Cdnan,FTTDNN,fttdnn,PDOUBLE)
+
+/*-------- Functions no longer supported... normally redundant -----------*/
+/* Included only to support older code */
+/*------------------------------------------------------------------------*/
+
+void Cffempty(void);
+void Cffempty(void)
+{ return; }
+FCALLSCSUB0(Cffempty,FTPDEF,ftpdef)
+FCALLSCSUB0(Cffempty,FTBDEF,ftbdef)
+FCALLSCSUB0(Cffempty,FTADEF,ftadef)
+FCALLSCSUB0(Cffempty,FTDDEF,ftddef)
+
+
+/*-------- Functions which use the lex and yacc/bison parser code -----------*/
+/*---------------------------------------------------------------------------*/
+
+#define fttexp_LONGV_A7 A3
+FCALLSCSUB8(fftexp,FTTEXP,fttexp,FITSUNIT,STRING,INT,PINT,PLONG,PINT,LONGV,PINT)
+
+#define ftfrow_LOGV_A6 A4
+FCALLSCSUB7(fffrow,FTFROW,ftfrow,FITSUNIT,STRING,LONG,LONG,PLONG,LOGICALV,PINT)
+
+#define ftfrwc_LOGV_A8 A6
+FCALLSCSUB9(fffrwc,FTFRWC,ftfrwc,FITSUNIT,STRING,STRING,STRING,STRING,LONG,DOUBLEV,LOGICALV,PINT)
+
+FCALLSCSUB4(ffsrow,FTSROW,ftsrow,FITSUNIT,FITSUNIT,STRING,PINT)
+FCALLSCSUB9(ffcrow,FTCROW,ftcrow,FITSUNIT,INT,STRING,LONG,LONG,PVOID,PVOID,PLOGICAL,PINT)
+FCALLSCSUB6(ffcalc,FTCALC,ftcalc,FITSUNIT,STRING,FITSUNIT,STRING,STRING,PINT)
+
+#define ftcalc_rng_LONGV_A7 A6
+#define ftcalc_rng_LONGV_A8 A6
+FCALLSCSUB9(ffcalc_rng,FTCALC_RNG,ftcalc_rng,FITSUNIT,STRING,FITSUNIT,STRING,STRING,INT,LONGV,LONGV,PINT)
+
+/*--------------------- grouping routines ------------------*/
+
+FCALLSCSUB4(ffgtcr,FTGTCR,ftgtcr,FITSUNIT,STRING,INT,PINT)
+FCALLSCSUB4(ffgtis,FTGTIS,ftgtis,FITSUNIT,STRING,INT,PINT)
+FCALLSCSUB3(ffgtch,FTGTCH,ftgtch,FITSUNIT,INT,PINT)
+FCALLSCSUB3(ffgtrm,FTGTRM,ftgtrm,FITSUNIT,INT,PINT)
+FCALLSCSUB4(ffgtcp,FTGTCP,ftgtcp,FITSUNIT,FITSUNIT,INT,PINT)
+FCALLSCSUB4(ffgtmg,FTGTMG,ftgtmg,FITSUNIT,FITSUNIT,INT,PINT)
+FCALLSCSUB3(ffgtcm,FTGTCM,ftgtcm,FITSUNIT,INT,PINT)
+FCALLSCSUB3(ffgtvf,FTGTVF,ftgtvf,FITSUNIT,PLONG,PINT)
+FCALLSCSUB4(ffgtop,FTGTOP,ftgtop,FITSUNIT,INT,PFITSUNIT,PINT)
+FCALLSCSUB4(ffgtam,FTGTAM,ftgtam,FITSUNIT,FITSUNIT,INT,PINT)
+FCALLSCSUB3(ffgtnm,FTGTNM,ftgtnm,FITSUNIT,PLONG,PINT)
+FCALLSCSUB3(ffgmng,FTGMNG,ftgmng,FITSUNIT,PLONG,PINT)
+FCALLSCSUB4(ffgmop,FTGMOP,ftgmop,FITSUNIT,LONG,PFITSUNIT,PINT)
+FCALLSCSUB5(ffgmcp,FTGMCP,ftgmcp,FITSUNIT,FITSUNIT,LONG,INT,PINT)
+FCALLSCSUB5(ffgmtf,FTGMTF,ftgmtf,FITSUNIT,FITSUNIT,LONG,INT,PINT)
+FCALLSCSUB4(ffgmrm,FTGMRM,ftgmrm,FITSUNIT,LONG,INT,PINT)
diff --git a/pkg/tbtables/cfitsio/fitscopy.c b/pkg/tbtables/cfitsio/fitscopy.c
new file mode 100644
index 00000000..cd73854e
--- /dev/null
+++ b/pkg/tbtables/cfitsio/fitscopy.c
@@ -0,0 +1,64 @@
+#include <stdio.h>
+#include "fitsio.h"
+
+int main(int argc, char *argv[])
+{
+ fitsfile *infptr, *outfptr; /* FITS file pointers defined in fitsio.h */
+ int status = 0, ii = 1; /* status must always be initialized = 0 */
+
+ if (argc != 3)
+ {
+ printf("Usage: fitscopy inputfile outputfile\n");
+ printf("\n");
+ printf("Copy an input file to an output file, optionally filtering\n");
+ printf("the file in the process. This seemingly simple program can\n");
+ printf("apply powerful filters which transform the input file as\n");
+ printf("it is being copied. Filters may be used to extract a\n");
+ printf("subimage from a larger image, select rows from a table,\n");
+ printf("filter a table with a GTI time extension or a SAO region file,\n");
+ printf("create or delete columns in a table, create an image by\n");
+ printf("binning (histogramming) 2 table columns, and convert IRAF\n");
+ printf("format *.imh or raw binary data files into FITS images.\n");
+ printf("See the CFITSIO User's Guide for a complete description of\n");
+ printf("the Extended File Name filtering syntax.\n");
+ printf("\n");
+ printf("Examples:\n");
+ printf("\n");
+ printf("fitscopy in.fit out.fit (simple file copy)\n");
+ printf("fitscopy - - (stdin to stdout)\n");
+ printf("fitscopy in.fit[11:50,21:60] out.fit (copy a subimage)\n");
+ printf("fitscopy iniraf.imh out.fit (IRAF image to FITS)\n");
+ printf("fitscopy in.dat[i512,512] out.fit (raw array to FITS)\n");
+ printf("fitscopy in.fit[events][pi>35] out.fit (copy rows with pi>35)\n");
+ printf("fitscopy in.fit[events][bin X,Y] out.fit (bin an image) \n");
+ printf("fitscopy in.fit[events][col x=.9*y] out.fit (new x column)\n");
+ printf("fitscopy in.fit[events][gtifilter()] out.fit (time filter)\n");
+ printf("fitscopy in.fit[2][regfilter(\"pow.reg\")] out.fit (spatial filter)\n");
+ printf("\n");
+ printf("Note that it may be necessary to enclose the input file name\n");
+ printf("in single quote characters on the Unix command line.\n");
+ return(0);
+ }
+
+ /* Open the input file */
+ if ( !fits_open_file(&infptr, argv[1], READONLY, &status) )
+ {
+ /* Create the output file */
+ if ( !fits_create_file(&outfptr, argv[2], &status) )
+ {
+ /* Copy every HDU until we get an error */
+ while( !fits_movabs_hdu(infptr, ii++, NULL, &status) )
+ fits_copy_hdu(infptr, outfptr, 0, &status);
+
+ /* Reset status after normal error */
+ if (status == END_OF_FILE) status = 0;
+
+ fits_close_file(outfptr, &status);
+ }
+ fits_close_file(infptr, &status);
+ }
+
+ /* if error occured, print out error message */
+ if (status) fits_report_error(stderr, status);
+ return(status);
+}
diff --git a/pkg/tbtables/cfitsio/fitscore.c b/pkg/tbtables/cfitsio/fitscore.c
new file mode 100644
index 00000000..bc02077b
--- /dev/null
+++ b/pkg/tbtables/cfitsio/fitscore.c
@@ -0,0 +1,7007 @@
+/* This file, fitscore.c, contains the core set of FITSIO routines. */
+
+/* The FITSIO software was written by William Pence at the High Energy */
+/* Astrophysic Science Archive Research Center (HEASARC) at the NASA */
+/* Goddard Space Flight Center. */
+/*
+
+Copyright (Unpublished--all rights reserved under the copyright laws of
+the United States), U.S. Government as represented by the Administrator
+of the National Aeronautics and Space Administration. No copyright is
+claimed in the United States under Title 17, U.S. Code.
+
+Permission to freely use, copy, modify, and distribute this software
+and its documentation without fee is hereby granted, provided that this
+copyright notice and disclaimer of warranty appears in all copies.
+
+DISCLAIMER:
+
+THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND,
+EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO,
+ANY WARRANTY THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY
+IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE, AND FREEDOM FROM INFRINGEMENT, AND ANY WARRANTY THAT THE
+DOCUMENTATION WILL CONFORM TO THE SOFTWARE, OR ANY WARRANTY THAT THE
+SOFTWARE WILL BE ERROR FREE. IN NO EVENT SHALL NASA BE LIABLE FOR ANY
+DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, INDIRECT, SPECIAL OR
+CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, OR IN ANY WAY
+CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY,
+CONTRACT, TORT , OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY
+PERSONS OR PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED
+FROM, OR AROSE OUT OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR
+SERVICES PROVIDED HEREUNDER."
+
+*/
+
+
+#include <string.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <math.h>
+#include <ctype.h>
+#include <errno.h>
+/* stddef.h is apparently needed to define size_t with some compilers ?? */
+#include <stddef.h>
+#include "fitsio2.h"
+
+#define errmsgsiz 25
+#define ESMARKER 27 /* Escape character is used as error stack marker */
+
+#define DelAll 1 /* delete all messages on the error stack */
+#define DelMark 2 /* delete newest messages back to and including marker */
+#define DelNewest 3 /* delete the newest message from the stack */
+#define GetMesg 4 /* pop and return oldest message, ignoring marks */
+#define PutMesg 5 /* add a new message to the stack */
+#define PutMark 6 /* add a marker to the stack */
+
+/*--------------------------------------------------------------------------*/
+float ffvers(float *version) /* IO - version number */
+/*
+ return the current version number of the FITSIO software
+*/
+{
+ *version = 2.51;
+
+/* 2 December 2004
+
+
+ Previous releases:
+ *version = 2.50 28 July 2004
+ *version = 2.49 11 Feb 2004
+ *version = 2.48 28 Jan 2004
+ *version = 2.470 18 Aug 2003
+ *version = 2.460 20 May 2003
+ *version = 2.450 30 Apr 2003 (internal release only)
+ *version = 2.440 8 Jan 2003
+ *version = 2.430; 4 Nov 2002
+ *version = 2.420; 19 Jul 2002
+ *version = 2.410; 22 Apr 2002 used in ftools v5.2
+ *version = 2.401; 28 Jan 2002
+ *version = 2.400; 18 Jan 2002
+ *version = 2.301; 7 Dec 2001
+ *version = 2.300; 23 Oct 2001
+ *version = 2.204; 26 Jul 2001
+ *version = 2.203; 19 Jul 2001 used in ftools v5.1
+ *version = 2.202; 22 May 2001
+ *version = 2.201; 15 Mar 2001
+ *version = 2.200; 26 Jan 2001
+ *version = 2.100; 26 Sep 2000
+ *version = 2.037; 6 Jul 2000
+ *version = 2.036; 1 Feb 2000
+ *version = 2.035; 7 Dec 1999 (internal release only)
+ *version = 2.034; 23 Nov 1999
+ *version = 2.033; 17 Sep 1999
+ *version = 2.032; 25 May 1999
+ *version = 2.031; 31 Mar 1999
+ *version = 2.030; 24 Feb 1999
+ *version = 2.029; 11 Feb 1999
+ *version = 2.028; 26 Jan 1999
+ *version = 2.027; 12 Jan 1999
+ *version = 2.026; 23 Dec 1998
+ *version = 2.025; 1 Dec 1998
+ *version = 2.024; 9 Nov 1998
+ *version = 2.023; 1 Nov 1998 first full release of V2.0
+ *version = 1.42; 30 Apr 1998
+ *version = 1.40; 6 Feb 1998
+ *version = 1.33; 16 Dec 1997 (internal release only)
+ *version = 1.32; 21 Nov 1997 (internal release only)
+ *version = 1.31; 4 Nov 1997 (internal release only)
+ *version = 1.30; 11 Sep 1997
+ *version = 1.27; 3 Sep 1997 (internal release only)
+ *version = 1.25; 2 Jul 1997
+ *version = 1.24; 2 May 1997
+ *version = 1.23; 24 Apr 1997
+ *version = 1.22; 18 Apr 1997
+ *version = 1.21; 26 Mar 1997
+ *version = 1.2; 29 Jan 1997
+ *version = 1.11; 04 Dec 1996
+ *version = 1.101; 13 Nov 1996
+ *version = 1.1; 6 Nov 1996
+ *version = 1.04; 17 Sep 1996
+ *version = 1.03; 20 Aug 1996
+ *version = 1.02; 15 Aug 1996
+ *version = 1.01; 12 Aug 1996
+*/
+
+ return(*version);
+}
+/*--------------------------------------------------------------------------*/
+int ffflnm(fitsfile *fptr, /* I - FITS file pointer */
+ char *filename, /* O - name of the file */
+ int *status) /* IO - error status */
+/*
+ return the name of the FITS file
+*/
+{
+ strcpy(filename,(fptr->Fptr)->filename);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffflmd(fitsfile *fptr, /* I - FITS file pointer */
+ int *filemode, /* O - open mode of the file */
+ int *status) /* IO - error status */
+/*
+ return the access mode of the FITS file
+*/
+{
+ *filemode = (fptr->Fptr)->writemode;
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+void ffgerr(int status, /* I - error status value */
+ char *errtext) /* O - error message (max 30 char long + null) */
+/*
+ Return a short descriptive error message that corresponds to the input
+ error status value. The message may be up to 30 characters long, plus
+ the terminating null character.
+*/
+{
+ errtext[0] = '\0';
+
+ if (status >= 0 && status < 300)
+ {
+ switch (status) {
+
+ case 0:
+ strcpy(errtext, "OK - no error");
+ break;
+ case 1:
+ strcpy(errtext, "non-CFITSIO program error");
+ break;
+ case 101:
+ strcpy(errtext, "same input and output files");
+ break;
+ case 103:
+ strcpy(errtext, "attempt to open too many files");
+ break;
+ case 104:
+ strcpy(errtext, "could not open the named file");
+ break;
+ case 105:
+ strcpy(errtext, "couldn't create the named file");
+ break;
+ case 106:
+ strcpy(errtext, "error writing to FITS file");
+ break;
+ case 107:
+ strcpy(errtext, "tried to move past end of file");
+ break;
+ case 108:
+ strcpy(errtext, "error reading from FITS file");
+ break;
+ case 110:
+ strcpy(errtext, "could not close the file");
+ break;
+ case 111:
+ strcpy(errtext, "array dimensions too big");
+ break;
+ case 112:
+ strcpy(errtext, "cannot write to readonly file");
+ break;
+ case 113:
+ strcpy(errtext, "could not allocate memory");
+ break;
+ case 114:
+ strcpy(errtext, "invalid fitsfile pointer");
+ break;
+ case 115:
+ strcpy(errtext, "NULL input pointer");
+ break;
+ case 116:
+ strcpy(errtext, "error seeking file position");
+ break;
+ case 121:
+ strcpy(errtext, "invalid URL prefix");
+ break;
+ case 122:
+ strcpy(errtext, "too many I/O drivers");
+ break;
+ case 123:
+ strcpy(errtext, "I/O driver init failed");
+ break;
+ case 124:
+ strcpy(errtext, "no I/O driver for this URLtype");
+ break;
+ case 125:
+ strcpy(errtext, "parse error in input file URL");
+ break;
+ case 126:
+ strcpy(errtext, "parse error in range list");
+ break;
+ case 151:
+ strcpy(errtext, "bad argument (shared mem drvr)");
+ break;
+ case 152:
+ strcpy(errtext, "null ptr arg (shared mem drvr)");
+ break;
+ case 153:
+ strcpy(errtext, "no free shared memory handles");
+ break;
+ case 154:
+ strcpy(errtext, "share mem drvr not initialized");
+ break;
+ case 155:
+ strcpy(errtext, "IPC system error (shared mem)");
+ break;
+ case 156:
+ strcpy(errtext, "no memory (shared mem drvr)");
+ break;
+ case 157:
+ strcpy(errtext, "share mem resource deadlock");
+ break;
+ case 158:
+ strcpy(errtext, "lock file open/create failed");
+ break;
+ case 159:
+ strcpy(errtext, "can't resize share mem block");
+ break;
+ case 201:
+ strcpy(errtext, "header already has keywords");
+ break;
+ case 202:
+ strcpy(errtext, "keyword not found in header");
+ break;
+ case 203:
+ strcpy(errtext, "keyword number out of bounds");
+ break;
+ case 204:
+ strcpy(errtext, "keyword value is undefined");
+ break;
+ case 205:
+ strcpy(errtext, "string missing closing quote");
+ break;
+ case 206:
+ strcpy(errtext, "error in indexed keyword name");
+ break;
+ case 207:
+ strcpy(errtext, "illegal character in keyword");
+ break;
+ case 208:
+ strcpy(errtext, "required keywords out of order");
+ break;
+ case 209:
+ strcpy(errtext, "keyword value not positive int");
+ break;
+ case 210:
+ strcpy(errtext, "END keyword not found");
+ break;
+ case 211:
+ strcpy(errtext, "illegal BITPIX keyword value");
+ break;
+ case 212:
+ strcpy(errtext, "illegal NAXIS keyword value");
+ break;
+ case 213:
+ strcpy(errtext, "illegal NAXISn keyword value");
+ break;
+ case 214:
+ strcpy(errtext, "illegal PCOUNT keyword value");
+ break;
+ case 215:
+ strcpy(errtext, "illegal GCOUNT keyword value");
+ break;
+ case 216:
+ strcpy(errtext, "illegal TFIELDS keyword value");
+ break;
+ case 217:
+ strcpy(errtext, "negative table row size");
+ break;
+ case 218:
+ strcpy(errtext, "negative number of rows");
+ break;
+ case 219:
+ strcpy(errtext, "named column not found");
+ break;
+ case 220:
+ strcpy(errtext, "illegal SIMPLE keyword value");
+ break;
+ case 221:
+ strcpy(errtext, "first keyword not SIMPLE");
+ break;
+ case 222:
+ strcpy(errtext, "second keyword not BITPIX");
+ break;
+ case 223:
+ strcpy(errtext, "third keyword not NAXIS");
+ break;
+ case 224:
+ strcpy(errtext, "missing NAXISn keywords");
+ break;
+ case 225:
+ strcpy(errtext, "first keyword not XTENSION");
+ break;
+ case 226:
+ strcpy(errtext, "CHDU not an ASCII table");
+ break;
+ case 227:
+ strcpy(errtext, "CHDU not a binary table");
+ break;
+ case 228:
+ strcpy(errtext, "PCOUNT keyword not found");
+ break;
+ case 229:
+ strcpy(errtext, "GCOUNT keyword not found");
+ break;
+ case 230:
+ strcpy(errtext, "TFIELDS keyword not found");
+ break;
+ case 231:
+ strcpy(errtext, "missing TBCOLn keyword");
+ break;
+ case 232:
+ strcpy(errtext, "missing TFORMn keyword");
+ break;
+ case 233:
+ strcpy(errtext, "CHDU not an IMAGE extension");
+ break;
+ case 234:
+ strcpy(errtext, "illegal TBCOLn keyword value");
+ break;
+ case 235:
+ strcpy(errtext, "CHDU not a table extension");
+ break;
+ case 236:
+ strcpy(errtext, "column exceeds width of table");
+ break;
+ case 237:
+ strcpy(errtext, "more than 1 matching col. name");
+ break;
+ case 241:
+ strcpy(errtext, "row width not = field widths");
+ break;
+ case 251:
+ strcpy(errtext, "unknown FITS extension type");
+ break;
+ case 252:
+ strcpy(errtext, "1st key not SIMPLE or XTENSION");
+ break;
+ case 253:
+ strcpy(errtext, "END keyword is not blank");
+ break;
+ case 254:
+ strcpy(errtext, "Header fill area not blank");
+ break;
+ case 255:
+ strcpy(errtext, "Data fill area invalid");
+ break;
+ case 261:
+ strcpy(errtext, "illegal TFORM format code");
+ break;
+ case 262:
+ strcpy(errtext, "unknown TFORM datatype code");
+ break;
+ case 263:
+ strcpy(errtext, "illegal TDIMn keyword value");
+ break;
+ case 264:
+ strcpy(errtext, "invalid BINTABLE heap pointer");
+ break;
+ default:
+ strcpy(errtext, "unknown error status");
+ break;
+ }
+ }
+ else if (status < 600)
+ {
+ switch(status) {
+
+ case 301:
+ strcpy(errtext, "illegal HDU number");
+ break;
+ case 302:
+ strcpy(errtext, "column number < 1 or > tfields");
+ break;
+ case 304:
+ strcpy(errtext, "negative byte address");
+ break;
+ case 306:
+ strcpy(errtext, "negative number of elements");
+ break;
+ case 307:
+ strcpy(errtext, "bad first row number");
+ break;
+ case 308:
+ strcpy(errtext, "bad first element number");
+ break;
+ case 309:
+ strcpy(errtext, "not an ASCII (A) column");
+ break;
+ case 310:
+ strcpy(errtext, "not a logical (L) column");
+ break;
+ case 311:
+ strcpy(errtext, "bad ASCII table datatype");
+ break;
+ case 312:
+ strcpy(errtext, "bad binary table datatype");
+ break;
+ case 314:
+ strcpy(errtext, "null value not defined");
+ break;
+ case 317:
+ strcpy(errtext, "not a variable length column");
+ break;
+ case 320:
+ strcpy(errtext, "illegal number of dimensions");
+ break;
+ case 321:
+ strcpy(errtext, "1st pixel no. > last pixel no.");
+ break;
+ case 322:
+ strcpy(errtext, "BSCALE or TSCALn = 0.");
+ break;
+ case 323:
+ strcpy(errtext, "illegal axis length < 1");
+ break;
+ case 340:
+ strcpy(errtext, "not group table");
+ break;
+ case 341:
+ strcpy(errtext, "HDU already member of group");
+ break;
+ case 342:
+ strcpy(errtext, "group member not found");
+ break;
+ case 343:
+ strcpy(errtext, "group not found");
+ break;
+ case 344:
+ strcpy(errtext, "bad group id");
+ break;
+ case 345:
+ strcpy(errtext, "too many HDUs tracked");
+ break;
+ case 346:
+ strcpy(errtext, "HDU alread tracked");
+ break;
+ case 347:
+ strcpy(errtext, "bad Grouping option");
+ break;
+ case 348:
+ strcpy(errtext, "identical pointers (groups)");
+ break;
+ case 360:
+ strcpy(errtext, "malloc failed in parser");
+ break;
+ case 361:
+ strcpy(errtext, "file read error in parser");
+ break;
+ case 362:
+ strcpy(errtext, "null pointer arg (parser)");
+ break;
+ case 363:
+ strcpy(errtext, "empty line (parser)");
+ break;
+ case 364:
+ strcpy(errtext, "cannot unread > 1 line");
+ break;
+ case 365:
+ strcpy(errtext, "parser too deeply nested");
+ break;
+ case 366:
+ strcpy(errtext, "file open failed (parser)");
+ break;
+ case 367:
+ strcpy(errtext, "hit EOF (parser)");
+ break;
+ case 368:
+ strcpy(errtext, "bad argument (parser)");
+ break;
+ case 369:
+ strcpy(errtext, "unexpected token (parser)");
+ break;
+ case 401:
+ strcpy(errtext, "bad int to string conversion");
+ break;
+ case 402:
+ strcpy(errtext, "bad float to string conversion");
+ break;
+ case 403:
+ strcpy(errtext, "keyword value not integer");
+ break;
+ case 404:
+ strcpy(errtext, "keyword value not logical");
+ break;
+ case 405:
+ strcpy(errtext, "keyword value not floating pt");
+ break;
+ case 406:
+ strcpy(errtext, "keyword value not double");
+ break;
+ case 407:
+ strcpy(errtext, "bad string to int conversion");
+ break;
+ case 408:
+ strcpy(errtext, "bad string to float conversion");
+ break;
+ case 409:
+ strcpy(errtext, "bad string to double convert");
+ break;
+ case 410:
+ strcpy(errtext, "illegal datatype code value");
+ break;
+ case 411:
+ strcpy(errtext, "illegal no. of decimals");
+ break;
+ case 412:
+ strcpy(errtext, "datatype conversion overflow");
+ break;
+ case 413:
+ strcpy(errtext, "error compressing image");
+ break;
+ case 414:
+ strcpy(errtext, "error uncompressing image");
+ break;
+ case 420:
+ strcpy(errtext, "bad date or time conversion");
+ break;
+ case 431:
+ strcpy(errtext, "syntax error in expression");
+ break;
+ case 432:
+ strcpy(errtext, "expression result wrong type");
+ break;
+ case 433:
+ strcpy(errtext, "vector result too large");
+ break;
+ case 434:
+ strcpy(errtext, "missing output column");
+ break;
+ case 435:
+ strcpy(errtext, "bad data in parsed column");
+ break;
+ case 436:
+ strcpy(errtext, "output extension of wrong type");
+ break;
+ case 501:
+ strcpy(errtext, "WCS angle too large");
+ break;
+ case 502:
+ strcpy(errtext, "bad WCS coordinate");
+ break;
+ case 503:
+ strcpy(errtext, "error in WCS calculation");
+ break;
+ case 504:
+ strcpy(errtext, "bad WCS projection type");
+ break;
+ case 505:
+ strcpy(errtext, "WCS keywords not found");
+ break;
+ default:
+ strcpy(errtext, "unknown error status");
+ break;
+ }
+ }
+ else
+ {
+ strcpy(errtext, "unknown error status");
+ }
+ return;
+}
+/*--------------------------------------------------------------------------*/
+void ffpmsg(const char *err_message)
+/*
+ put message on to error stack
+*/
+{
+ ffxmsg(PutMesg, (char *)err_message);
+ return;
+}
+/*--------------------------------------------------------------------------*/
+void ffpmrk(void)
+/*
+ write a marker to the stack. It is then possible to pop only those
+ messages following the marker off of the stack, leaving the previous
+ messages unaffected.
+
+ The marker is ignored by the ffgmsg routine.
+*/
+{
+ char *dummy = 0;
+
+ ffxmsg(PutMark, dummy);
+ return;
+}
+/*--------------------------------------------------------------------------*/
+int ffgmsg(char *err_message)
+/*
+ get oldest message from error stack, ignoring markers
+*/
+{
+ ffxmsg(GetMesg, err_message);
+ return(*err_message);
+}
+/*--------------------------------------------------------------------------*/
+void ffcmsg(void)
+/*
+ erase all messages in the error stack
+*/
+{
+ char *dummy = 0;
+
+ ffxmsg(DelAll, dummy);
+ return;
+}
+/*--------------------------------------------------------------------------*/
+void ffcmrk(void)
+/*
+ erase newest messages in the error stack, stopping if a marker is found.
+ The marker is also erased in this case.
+*/
+{
+ char *dummy = 0;
+
+ ffxmsg(DelMark, dummy);
+ return;
+}
+/*--------------------------------------------------------------------------*/
+void ffxmsg( int action,
+ char *errmsg)
+/*
+ general routine to get, put, or clear the error message stack.
+ Use a static array rather than allocating memory as needed for
+ the error messages because it is likely to be more efficient
+ and simpler to implement.
+
+ Action Code:
+DelAll 1 delete all messages on the error stack
+DelMark 2 delete messages back to and including the 1st marker
+DelNewest 3 delete the newest message from the stack
+GetMesg 4 pop and return oldest message, ignoring marks
+PutMesg 5 add a new message to the stack
+PutMark 6 add a marker to the stack
+
+*/
+{
+ int ii;
+ char markflag;
+ static char *txtbuff[errmsgsiz], *tmpbuff, *msgptr;
+ static char errbuff[errmsgsiz][81]; /* initialize all = \0 */
+ static int nummsg = 0;
+
+ if (action == DelAll) /* clear the whole message stack */
+ {
+ for (ii = 0; ii < nummsg; ii ++)
+ *txtbuff[ii] = '\0';
+
+ nummsg = 0;
+ }
+ else if (action == DelMark) /* clear up to and including first marker */
+ {
+ while (nummsg > 0) {
+ nummsg--;
+ markflag = *txtbuff[nummsg]; /* store possible marker character */
+ *txtbuff[nummsg] = '\0'; /* clear the buffer for this msg */
+
+ if (markflag == ESMARKER)
+ break; /* found a marker, so quit */
+ }
+ }
+ else if (action == DelNewest) /* remove newest message from stack */
+ {
+ if (nummsg > 0)
+ {
+ nummsg--;
+ *txtbuff[nummsg] = '\0'; /* clear the buffer for this msg */
+ }
+ }
+ else if (action == GetMesg) /* pop and return oldest message from stack */
+ { /* ignoring markers */
+ while (nummsg > 0)
+ {
+ strcpy(errmsg, txtbuff[0]); /* copy oldest message to output */
+
+ *txtbuff[0] = '\0'; /* clear the buffer for this msg */
+
+ nummsg--;
+ for (ii = 0; ii < nummsg; ii++)
+ txtbuff[ii] = txtbuff[ii + 1]; /* shift remaining pointers */
+
+ if (errmsg[0] != ESMARKER) /* quit if this is not a marker */
+ return;
+ }
+ errmsg[0] = '\0'; /* no messages in the stack */
+ }
+ else if (action == PutMesg) /* add new message to stack */
+ {
+ msgptr = errmsg;
+ while (strlen(msgptr))
+ {
+ if (nummsg == errmsgsiz)
+ {
+ tmpbuff = txtbuff[0]; /* buffers full; reuse oldest buffer */
+ *txtbuff[0] = '\0'; /* clear the buffer for this msg */
+
+ nummsg--;
+ for (ii = 0; ii < nummsg; ii++)
+ txtbuff[ii] = txtbuff[ii + 1]; /* shift remaining pointers */
+
+ txtbuff[nummsg] = tmpbuff; /* set pointer for the new message */
+ }
+ else
+ {
+ for (ii = 0; ii < errmsgsiz; ii++)
+ {
+ if (*errbuff[ii] == '\0') /* find first empty buffer */
+ {
+ txtbuff[nummsg] = errbuff[ii];
+ break;
+ }
+ }
+ }
+
+ strncat(txtbuff[nummsg], msgptr, 80);
+ nummsg++;
+
+ msgptr += minvalue(80, strlen(msgptr));
+ }
+ }
+ else if (action == PutMark) /* put a marker on the stack */
+ {
+ if (nummsg == errmsgsiz)
+ {
+ tmpbuff = txtbuff[0]; /* buffers full; reuse oldest buffer */
+ *txtbuff[0] = '\0'; /* clear the buffer for this msg */
+
+ nummsg--;
+ for (ii = 0; ii < nummsg; ii++)
+ txtbuff[ii] = txtbuff[ii + 1]; /* shift remaining pointers */
+
+ txtbuff[nummsg] = tmpbuff; /* set pointer for the new message */
+ }
+ else
+ {
+ for (ii = 0; ii < errmsgsiz; ii++)
+ {
+ if (*errbuff[ii] == '\0') /* find first empty buffer */
+ {
+ txtbuff[nummsg] = errbuff[ii];
+ break;
+ }
+ }
+ }
+
+ *txtbuff[nummsg] = ESMARKER; /* write the marker */
+ *(txtbuff[nummsg] + 1) = '\0';
+ nummsg++;
+
+ }
+ return;
+}
+/*--------------------------------------------------------------------------*/
+int ffpxsz(int datatype)
+/*
+ return the number of bytes per pixel associated with the datatype
+*/
+{
+ if (datatype == TBYTE)
+ return(sizeof(char));
+ else if (datatype == TUSHORT)
+ return(sizeof(short));
+ else if (datatype == TSHORT)
+ return(sizeof(short));
+ else if (datatype == TULONG)
+ return(sizeof(long));
+ else if (datatype == TLONG)
+ return(sizeof(long));
+ else if (datatype == TINT)
+ return(sizeof(int));
+ else if (datatype == TUINT)
+ return(sizeof(int));
+ else if (datatype == TFLOAT)
+ return(sizeof(float));
+ else if (datatype == TDOUBLE)
+ return(sizeof(double));
+ else if (datatype == TLOGICAL)
+ return(sizeof(char));
+ else
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int fftkey(char *keyword, /* I - keyword name */
+ int *status) /* IO - error status */
+/*
+ Test that the keyword name conforms to the FITS standard. Must contain
+ only capital letters, digits, minus or underscore chars. Trailing spaces
+ are allowed. If the input status value is less than zero, then the test
+ is modified so that upper or lower case letters are allowed, and no
+ error messages are printed if the keyword is not legal.
+*/
+{
+ size_t maxchr, ii;
+ int spaces=0;
+ char msg[81], testchar;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ maxchr=strlen(keyword);
+ if (maxchr > 8)
+ maxchr = 8;
+
+ for (ii = 0; ii < maxchr; ii++)
+ {
+ if (*status == 0)
+ testchar = keyword[ii];
+ else
+ testchar = toupper(keyword[ii]);
+
+ if ( (testchar >= 'A' && testchar <= 'Z') ||
+ (testchar >= '0' && testchar <= '9') ||
+ testchar == '-' || testchar == '_' )
+ {
+ if (spaces)
+ {
+ if (*status == 0)
+ {
+ /* don't print error message if status < 0 */
+ sprintf(msg,
+ "Keyword name contains embedded space(s): %.8s",
+ keyword);
+ ffpmsg(msg);
+ }
+ return(*status = BAD_KEYCHAR);
+ }
+ }
+ else if (keyword[ii] == ' ')
+ spaces = 1;
+
+ else
+ {
+ if (*status == 0)
+ {
+ /* don't print error message if status < 0 */
+ sprintf(msg, "Character %d in this keyword is illegal: %.8s",
+ (int) (ii+1), keyword);
+ ffpmsg(msg);
+
+ /* explicitly flag the 2 most common cases */
+ if (keyword[ii] == 0)
+ ffpmsg(" (This a NULL (0) character).");
+ else if (keyword[ii] == 9)
+ ffpmsg(" (This an ASCII TAB (9) character).");
+ }
+
+ return(*status = BAD_KEYCHAR);
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fftrec(char *card, /* I - keyword card to test */
+ int *status) /* IO - error status */
+/*
+ Test that the keyword card conforms to the FITS standard. Must contain
+ only printable ASCII characters;
+*/
+{
+ size_t ii, maxchr;
+ char msg[81];
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ maxchr = strlen(card);
+
+ for (ii = 8; ii < maxchr; ii++)
+ {
+ if (card[ii] < 32 || card[ii] > 126)
+ {
+ sprintf(msg,
+ "Character %d in this keyword is illegal. Hex Value = %X",
+ (int) (ii+1), (int) card[ii] );
+ ffpmsg(msg);
+
+ strncpy(msg, card, 80);
+ msg[80] = '\0';
+ ffpmsg(msg);
+ return(*status = BAD_KEYCHAR);
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+void ffupch(char *string)
+/*
+ convert string to upper case, in place.
+*/
+{
+ size_t len, ii;
+
+ len = strlen(string);
+ for (ii = 0; ii < len; ii++)
+ string[ii] = toupper(string[ii]);
+ return;
+}
+/*--------------------------------------------------------------------------*/
+int ffmkky(char *keyname, /* I - keyword name */
+ char *value, /* I - keyword value */
+ char *comm, /* I - keyword comment */
+ char *card, /* O - constructed keyword card */
+ int *status) /* IO - status value */
+/*
+ Make a complete FITS 80-byte keyword card from the input name, value and
+ comment strings. Output card is null terminated without any trailing blanks.
+*/
+{
+ size_t namelen, len, ii;
+ char tmpname[FLEN_KEYWORD], *cptr;
+ int tstatus = -1;
+
+ if (*status > 0)
+ return(*status);
+
+ *tmpname = '\0';
+ *card = '\0';
+
+ cptr = keyname;
+ while(*cptr == ' ') /* skip leading blanks in the name */
+ cptr++;
+
+ strncat(tmpname, cptr, FLEN_KEYWORD - 1);
+
+ namelen = strlen(tmpname);
+ if (namelen)
+ {
+ cptr = tmpname + namelen - 1;
+
+ while(*cptr == ' ') /* skip trailing blanks */
+ {
+ *cptr = '\0';
+ cptr--;
+ }
+
+ namelen = cptr - tmpname + 1;
+ }
+
+ if (namelen <= 8 && (fftkey(keyname, &tstatus) <= 0) )
+ {
+ /* a normal FITS keyword */
+ strcat(card, tmpname); /* copy keyword name to buffer */
+
+ for (ii = namelen; ii < 8; ii++)
+ card[ii] = ' '; /* pad keyword name with spaces */
+
+ card[8] = '='; /* append '= ' in columns 9-10 */
+ card[9] = ' ';
+ card[10] = '\0'; /* terminate the partial string */
+ namelen = 10;
+ }
+ else
+ {
+ /* use the ESO HIERARCH convention for longer keyword names */
+
+ /* check that the name does not contain an '=' (equals sign) */
+ if (strchr(tmpname, '=') )
+ {
+ ffpmsg("Illegal keyword name; contains an equals sign (=)");
+ ffpmsg(tmpname);
+ return(*status = BAD_KEYCHAR);
+ }
+
+ /* Don't repeat HIERARCH if the keyword already contains it */
+ if (FSTRNCMP(tmpname, "HIERARCH ", 9) &&
+ FSTRNCMP(tmpname, "hierarch ", 9))
+ strcat(card, "HIERARCH ");
+ else
+ namelen -= 9; /* deleted the string 'HIERARCH ' */
+
+ strcat(card, tmpname);
+ strcat(card, " = ");
+ namelen += 12;
+ }
+
+ len = strlen(value);
+ if (len > 0)
+ {
+ if (value[0] == '\'') /* is this a quoted string value? */
+ {
+ if (namelen > 77)
+ {
+ ffpmsg(
+ "The following keyword + value is too long to fit on a card:");
+ ffpmsg(keyname);
+ ffpmsg(value);
+ return(*status = BAD_KEYCHAR);
+ }
+
+ strncat(card, value, 80 - namelen); /* append the value string */
+ len = minvalue(80, namelen + len);
+
+ /* restore the closing quote if it got truncated */
+ if (len == 80)
+ {
+ card[79] = '\'';
+ }
+
+ if (comm)
+ {
+ if (comm[0] != 0)
+ {
+ if (len < 30)
+ {
+ for (ii = len; ii < 30; ii++)
+ card[ii] = ' '; /* fill with spaces to col 30 */
+
+ card[30] = '\0';
+ len = 30;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (namelen + len > 80)
+ {
+ ffpmsg(
+ "The following keyword + value is too long to fit on a card:");
+ ffpmsg(keyname);
+ ffpmsg(value);
+ return(*status = BAD_KEYCHAR);
+ }
+ else if (namelen + len < 30)
+ {
+ /* add spaces so field ends at least in col 30 */
+ strncat(card, " ", 30 - (namelen + len));
+ }
+
+ strncat(card, value, 80 - namelen); /* append the value string */
+ len = minvalue(80, namelen + len);
+ len = maxvalue(30, len);
+ }
+
+ if (comm)
+ {
+ if ((len < 77) && ( strlen(comm) > 0) ) /* room for a comment? */
+ {
+ strcat(card, " / "); /* append comment separator */
+ strncat(card, comm, 77 - len); /* append comment (what fits) */
+ }
+ }
+ }
+ else
+ {
+ if (namelen == 10) /* This case applies to normal keywords only */
+ {
+ card[8] = ' '; /* keywords with no value have no '=' */
+ if (comm)
+ {
+ strncat(card, comm, 80 - namelen); /* append comment (what fits) */
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffmkey(fitsfile *fptr, /* I - FITS file pointer */
+ char *card, /* I - card string value */
+ int *status) /* IO - error status */
+/*
+ replace the previously read card (i.e. starting 80 bytes before the
+ (fptr->Fptr)->nextkey position) with the contents of the input card.
+*/
+{
+ char tcard[81];
+ size_t len, ii;
+
+ /* reset position to the correct HDU if necessary */
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+
+ strncpy(tcard,card,80);
+ tcard[80] = '\0';
+
+ len = strlen(tcard);
+ for (ii=len; ii < 80; ii++) /* fill card with spaces if necessary */
+ tcard[ii] = ' ';
+
+ for (ii=0; ii < 8; ii++) /* make sure keyword name is uppercase */
+ tcard[ii] = toupper(tcard[ii]);
+
+ fftkey(tcard, status); /* test keyword name contains legal chars */
+ fftrec(tcard, status); /* test rest of keyword for legal chars */
+
+ /* move position of keyword to be over written */
+ ffmbyt(fptr, ((fptr->Fptr)->nextkey) - 80, REPORT_EOF, status);
+ ffpbyt(fptr, 80, tcard, status); /* write the 80 byte card */
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffkeyn(char *keyroot, /* I - root string for keyword name */
+ int value, /* I - index number to be appended to root name */
+ char *keyname, /* O - output root + index keyword name */
+ int *status) /* IO - error status */
+/*
+ Construct a keyword name string by appending the index number to the root.
+ e.g., if root = "TTYPE" and value = 12 then keyname = "TTYPE12".
+*/
+{
+ char suffix[16];
+ size_t rootlen;
+
+ keyname[0] = '\0'; /* initialize output name to null */
+ rootlen = strlen(keyroot);
+
+ if (rootlen == 0 || rootlen > 7 || value < 0 )
+ return(*status = 206);
+
+ sprintf(suffix, "%d", value); /* construct keyword suffix */
+
+ if ( strlen(suffix) + rootlen > 8)
+ return(*status = 206);
+
+ strcpy(keyname, keyroot); /* copy root string to name string */
+ strcat(keyname, suffix); /* append suffix to the root */
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffnkey(int value, /* I - index number to be appended to root name */
+ char *keyroot, /* I - root string for keyword name */
+ char *keyname, /* O - output root + index keyword name */
+ int *status) /* IO - error status */
+/*
+ Construct a keyword name string by appending the root string to the index
+ number. e.g., if root = "TTYPE" and value = 12 then keyname = "12TTYPE".
+*/
+{
+ size_t rootlen;
+
+ keyname[0] = '\0'; /* initialize output name to null */
+ rootlen = strlen(keyroot);
+
+ if (rootlen == 0 || rootlen > 7 || value < 0 )
+ return(*status = 206);
+
+ sprintf(keyname, "%d", value); /* construct keyword prefix */
+
+ if (rootlen + strlen(keyname) > 8)
+ return(*status = 206);
+
+ strcat(keyname, keyroot); /* append root to the prefix */
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpsvc(char *card, /* I - FITS header card (nominally 80 bytes long) */
+ char *value, /* O - value string parsed from the card */
+ char *comm, /* O - comment string parsed from the card */
+ int *status) /* IO - error status */
+/*
+ ParSe the Value and Comment strings from the input header card string.
+ If the card contains a quoted string value, the returned value string
+ includes the enclosing quote characters. If comm = NULL, don't return
+ the comment string.
+*/
+{
+ int jj;
+ size_t ii, cardlen, nblank, valpos;
+
+ if (*status > 0)
+ return(*status);
+
+ value[0] = '\0';
+ if (comm)
+ comm[0] = '\0';
+
+ cardlen = strlen(card);
+
+ /* support for ESO HIERARCH keywords; find the '=' */
+ if (FSTRNCMP(card, "HIERARCH ", 9) == 0)
+ {
+ valpos = strcspn(card, "=");
+
+ if (valpos == cardlen) /* no value indicator ??? */
+ {
+ if (comm != NULL)
+ {
+ if (cardlen > 8)
+ {
+ strcpy(comm, &card[8]);
+
+ jj=cardlen - 8;
+ for (jj--; jj >= 0; jj--) /* replace trailing blanks with nulls */
+ {
+ if (comm[jj] == ' ')
+ comm[jj] = '\0';
+ else
+ break;
+ }
+ }
+ }
+ return(*status); /* no value indicator */
+ }
+ valpos++; /* point to the position after the '=' */
+ }
+ else if (cardlen < 9 ||
+ FSTRNCMP(card, "COMMENT ", 8) == 0 || /* keywords with no value */
+ FSTRNCMP(card, "HISTORY ", 8) == 0 ||
+ FSTRNCMP(card, "END ", 8) == 0 ||
+ FSTRNCMP(card, " ", 8) == 0 ||
+ FSTRNCMP(&card[8], "= ", 2) != 0 ) /* no '= ' in cols 9-10 */
+ {
+ /* no value, so the comment extends from cols 9 - 80 */
+ if (comm != NULL)
+ {
+ if (cardlen > 8)
+ {
+ strcpy(comm, &card[8]);
+
+ jj=cardlen - 8;
+ for (jj--; jj >= 0; jj--) /* replace trailing blanks with nulls */
+ {
+ if (comm[jj] == ' ')
+ comm[jj] = '\0';
+ else
+ break;
+ }
+ }
+ }
+ return(*status);
+ }
+ else
+ {
+ valpos = 10; /* starting position of the value field */
+ }
+
+ nblank = strspn(&card[valpos], " "); /* find number of leading blanks */
+
+ if (nblank + valpos == cardlen)
+ {
+ /* the absence of a value string is legal, and simply indicates
+ that the keyword value is undefined. Don't write an error
+ message in this case.
+ */
+ return(*status);
+ }
+
+ ii = valpos + nblank;
+
+ if (card[ii] == '/' ) /* slash indicates start of the comment */
+ {
+ ii++;
+ }
+ else if (card[ii] == '\'' ) /* is this a quoted string value? */
+ {
+ value[0] = card[ii];
+ for (jj=1, ii++; ii < cardlen; ii++, jj++)
+ {
+ if (card[ii] == '\'') /* is this the closing quote? */
+ {
+ if (card[ii+1] == '\'') /* 2 successive quotes? */
+ {
+ value[jj] = card[ii];
+ ii++;
+ jj++;
+ }
+ else
+ {
+ value[jj] = card[ii];
+ break; /* found the closing quote, so exit this loop */
+ }
+ }
+ value[jj] = card[ii]; /* copy the next character to the output */
+ }
+
+ if (ii == cardlen)
+ {
+ value[jj] = '\0'; /* terminate the bad value string */
+ ffpmsg("This keyword string value has no closing quote:");
+ ffpmsg(card);
+ return(*status = NO_QUOTE);
+ }
+ else
+ {
+ value[jj+1] = '\0'; /* terminate the good value string */
+ ii++; /* point to the character following the value */
+ }
+ }
+ else if (card[ii] == '(' ) /* is this a complex value? */
+ {
+ nblank = strcspn(&card[ii], ")" ); /* find closing ) */
+ if (nblank == strlen( &card[ii] ) )
+ {
+ ffpmsg("This complex keyword value has no closing ')':");
+ ffpmsg(card);
+ return(*status = NO_QUOTE);
+ }
+
+ nblank++;
+ strncpy(value, &card[ii], nblank);
+ value[nblank] = '\0';
+ ii = ii + nblank;
+ }
+ else /* an integer, floating point, or logical FITS value string */
+ {
+ nblank = strcspn(&card[ii], " /"); /* find the end of the token */
+ strncpy(value, &card[ii], nblank);
+ value[nblank] = '\0';
+ ii = ii + nblank;
+ }
+
+ /* now find the comment string, if any */
+ if (comm)
+ {
+ nblank = strspn(&card[ii], " "); /* find next non-space character */
+ ii = ii + nblank;
+
+ if (ii < 80)
+ {
+ if (card[ii] == '/') /* ignore the slash separator */
+ {
+ ii++;
+ if (card[ii] == ' ') /* also ignore the following space */
+ ii++;
+ }
+ strcat(comm, &card[ii]); /* copy the remaining characters */
+
+ jj=strlen(comm);
+ for (jj--; jj >= 0; jj--) /* replace trailing blanks with nulls */
+ {
+ if (comm[jj] == ' ')
+ comm[jj] = '\0';
+ else
+ break;
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgthd(char *tmplt, /* I - input header template string */
+ char *card, /* O - returned FITS header record */
+ int *hdtype, /* O - how to interpreter the returned card string */
+ /*
+ -2 = modify the name of a keyword; the old keyword name
+ is returned starting at address chars[0]; the new name
+ is returned starting at address char[40] (to be consistent
+ with the Fortran version). Both names are null terminated.
+ -1 = card contains the name of a keyword that is to be deleted
+ 0 = append this keyword if it doesn't already exist, or
+ modify the value if the keyword already exists.
+ 1 = append this comment keyword ('HISTORY',
+ 'COMMENT', or blank keyword name)
+ 2 = this is the END keyword; do not write it to the header
+ */
+ int *status) /* IO - error status */
+/*
+ 'Get Template HeaDer'
+ parse a template header line and create a formated
+ character string which is suitable for appending to a FITS header
+*/
+{
+ char keyname[FLEN_KEYWORD], value[FLEN_VALUE], comment[FLEN_COMMENT];
+ char *tok, *suffix, *loc, tvalue[FLEN_VALUE];
+ int len, vlen, more, tstatus;
+ double dval;
+
+ if (*status > 0)
+ return(*status);
+
+ card[0] = '\0';
+ *hdtype = 0;
+
+ if (!FSTRNCMP(tmplt, " ", 8) )
+ {
+ /* if first 8 chars of template are blank, then this is a comment */
+ strncat(card, tmplt, 80);
+ *hdtype = 1;
+ return(*status);
+ }
+
+ tok = tmplt; /* point to start of template string */
+
+ keyname[0] = '\0';
+ value[0] = '\0';
+ comment[0] = '\0';
+
+ len = strspn(tok, " "); /* no. of spaces before keyword */
+ tok += len;
+
+ if (tok[0] == '-') /* is there a leading minus sign? */
+ {
+ /* first token is name of keyword to be deleted or renamed */
+ *hdtype = -1;
+ tok++;
+ len = strspn(tok, " "); /* no. of spaces before keyword */
+ tok += len;
+ if (len < 8) /* not a blank name? */
+ {
+ len = strcspn(tok, " ="); /* length of name */
+ if (len >= FLEN_KEYWORD)
+ return(*status = BAD_KEYCHAR);
+
+ strncat(card, tok, len);
+
+ /*
+ The HIERARCH convention supports non-standard characters
+ in the keyword name, so don't always convert to upper case or
+ abort if there are illegal characters in the name or if the
+ name is greater than 8 characters long.
+ */
+
+ if (len < 9) /* this is possibly a normal FITS keyword name */
+ {
+ ffupch(card);
+ tstatus = 0;
+ if (fftkey(card, &tstatus) > 0)
+ {
+ /* name contained non-standard characters, so reset */
+ card[0] = '\0';
+ strncat(card, tok, len);
+ }
+ }
+
+ tok += len;
+ }
+
+ /* second token, if present, is the new name for the keyword */
+
+ len = strspn(tok, " "); /* no. of spaces before next token */
+ tok += len;
+
+ if (tok[0] == '\0' || tok[0] == '=')
+ return(*status); /* no second token */
+
+ *hdtype = -2;
+ len = strcspn(tok, " "); /* length of new name */
+ if (len > 40) /* name has to fit on columns 41-80 of card */
+ return(*status = BAD_KEYCHAR);
+
+ /* copy the new name to card + 40; This is awkward, */
+ /* but is consistent with the way the Fortran FITSIO works */
+ strcat(card," ");
+ strncpy(&card[40], tok, len+1); /* copy len+1 to get terminator */
+
+ /*
+ The HIERARCH convention supports non-standard characters
+ in the keyword name, so don't always convert to upper case or
+ abort if there are illegal characters in the name or if the
+ name is greater than 8 characters long.
+ */
+
+ if (len < 9) /* this is possibly a normal FITS keyword name */
+ {
+ ffupch(&card[40]);
+ tstatus = 0;
+ if (fftkey(&card[40], &tstatus) > 0)
+ {
+ /* name contained non-standard characters, so reset */
+ strncpy(&card[40], tok, len);
+ }
+ }
+ }
+ else /* no negative sign at beginning of template */
+ {
+ /* get the keyword name token */
+
+ len = strcspn(tok, " ="); /* length of keyword name */
+ if (len >= FLEN_KEYWORD)
+ return(*status = BAD_KEYCHAR);
+
+ strncat(keyname, tok, len);
+
+ /*
+ The HIERARCH convention supports non-standard characters
+ in the keyword name, so don't always convert to upper case or
+ abort if there are illegal characters in the name or if the
+ name is greater than 8 characters long.
+ */
+
+ if (len < 9) /* this is possibly a normal FITS keyword name */
+ {
+ ffupch(keyname);
+ tstatus = 0;
+ if (fftkey(keyname, &tstatus) > 0)
+ {
+ /* name contained non-standard characters, so reset */
+ keyname[0] = '\0';
+ strncat(keyname, tok, len);
+ }
+ }
+
+ if (!FSTRCMP(keyname, "END") )
+ {
+ strcpy(card, "END");
+ *hdtype = 2;
+ return(*status);
+ }
+
+ tok += len; /* move token pointer to end of the keyword */
+
+ if (!FSTRCMP(keyname, "COMMENT") || !FSTRCMP(keyname, "HISTORY")
+ || !FSTRCMP(keyname, "HIERARCH") )
+ {
+ *hdtype = 1; /* simply append COMMENT and HISTORY keywords */
+ strcpy(card, keyname);
+ strncat(card, tok, 73);
+ return(*status);
+ }
+
+ /* look for the value token */
+ len = strspn(tok, " ="); /* spaces or = between name and value */
+ tok += len;
+
+ if (*tok == '\'') /* is value enclosed in quotes? */
+ {
+ more = TRUE;
+ while (more)
+ {
+ tok++; /* temporarily move past the quote char */
+ len = strcspn(tok, "'"); /* length of quoted string */
+ tok--;
+ strncat(value, tok, len + 2);
+
+ tok += len + 1;
+ if (tok[0] != '\'') /* check there is a closing quote */
+ return(*status = NO_QUOTE);
+
+ tok++;
+ if (tok[0] != '\'') /* 2 quote chars = literal quote */
+ more = FALSE;
+ }
+ }
+ else if (*tok == '/' || *tok == '\0') /* There is no value */
+ {
+ strcat(value, " ");
+ }
+ else /* not a quoted string value */
+ {
+ len = strcspn(tok, " /"); /* length of value string */
+
+ strncat(value, tok, len);
+ if (!( (tok[0] == 'T' || tok[0] == 'F') &&
+ (tok[1] == ' ' || tok[1] == '/' || tok[1] == '\0') ))
+ {
+ /* not a logical value */
+
+ dval = strtod(value, &suffix); /* try to read value as number */
+
+ if (*suffix != '\0' && *suffix != ' ' && *suffix != '/')
+ {
+ /* value not recognized as a number; might be because it */
+ /* contains a 'd' or 'D' exponent character */
+ strcpy(tvalue, value);
+ loc = strchr(tvalue, 'D');
+ if (loc)
+ {
+ *loc = 'E'; /* replace D's with E's. */
+ dval = strtod(tvalue, &suffix); /* read value again */
+ }
+ else
+ {
+ loc = strchr(tvalue, 'd');
+ if (loc)
+ {
+ *loc = 'E'; /* replace d's with E's. */
+ dval = strtod(tvalue, &suffix); /* read value again */
+ }
+ }
+ }
+
+ if (*suffix != '\0' && *suffix != ' ' && *suffix != '/')
+ {
+ /* value is not a number; must enclose it in quotes */
+ strcpy(value, "'");
+ strncat(value, tok, len);
+ strcat(value, "'");
+
+ /* the following useless statement stops the compiler warning */
+ /* that dval is not used anywhere */
+ if (dval == 0.)
+ len += (int) dval;
+ }
+ else
+ {
+ /* value is a number; convert any 'e' to 'E', or 'd' to 'D' */
+ loc = strchr(value, 'e');
+ if (loc)
+ {
+ *loc = 'E';
+ }
+ else
+ {
+ loc = strchr(value, 'd');
+ if (loc)
+ {
+ *loc = 'D';
+ }
+ }
+ }
+ }
+ tok += len;
+ }
+
+ len = strspn(tok, " /"); /* no. of spaces between value and comment */
+ tok += len;
+
+ vlen = strlen(value);
+ if (vlen > 0 && vlen < 10 && value[0] == '\'')
+ {
+ /* pad quoted string with blanks so it is at least 8 chars long */
+ value[vlen-1] = '\0';
+ strncat(value, " ", 10 - vlen);
+ strcat(&value[9], "'");
+ }
+
+ /* get the comment string */
+ strncat(comment, tok, 70);
+
+ /* construct the complete FITS header card */
+ ffmkky(keyname, value, comment, card, status);
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffasfm(char *tform, /* I - format code from the TFORMn keyword */
+ int *dtcode, /* O - numerical datatype code */
+ long *twidth, /* O - width of the field, in chars */
+ int *decimals, /* O - number of decimal places (F, E, D format) */
+ int *status) /* IO - error status */
+{
+/*
+ parse the ASCII table TFORM column format to determine the data
+ type, the field width, and number of decimal places (if relevant)
+*/
+ int ii, datacode;
+ long longval, width;
+ float fwidth;
+ char *form, temp[FLEN_VALUE], message[FLEN_ERRMSG];
+
+ if (*status > 0)
+ return(*status);
+
+ if (dtcode)
+ *dtcode = 0;
+
+ if (twidth)
+ *twidth = 0;
+
+ if (decimals)
+ *decimals = 0;
+
+ ii = 0;
+ while (tform[ii] != 0 && tform[ii] == ' ') /* find first non-blank char */
+ ii++;
+
+ strcpy(temp, &tform[ii]); /* copy format string */
+ ffupch(temp); /* make sure it is in upper case */
+ form = temp; /* point to start of format string */
+
+
+ if (form[0] == 0)
+ {
+ ffpmsg("Error: ASCII table TFORM code is blank");
+ return(*status = BAD_TFORM);
+ }
+
+ /*-----------------------------------------------*/
+ /* determine default datatype code */
+ /*-----------------------------------------------*/
+ if (form[0] == 'A')
+ datacode = TSTRING;
+ else if (form[0] == 'I')
+ datacode = TLONG;
+ else if (form[0] == 'F')
+ datacode = TFLOAT;
+ else if (form[0] == 'E')
+ datacode = TFLOAT;
+ else if (form[0] == 'D')
+ datacode = TDOUBLE;
+ else
+ {
+ sprintf(message,
+ "Illegal ASCII table TFORMn datatype: \'%s\'", tform);
+ ffpmsg(message);
+ return(*status = BAD_TFORM_DTYPE);
+ }
+
+ if (dtcode)
+ *dtcode = datacode;
+
+ form++; /* point to the start of field width */
+
+ if (datacode == TSTRING || datacode == TLONG)
+ {
+ /*-----------------------------------------------*/
+ /* A or I data formats: */
+ /*-----------------------------------------------*/
+
+ if (ffc2ii(form, &width, status) <= 0) /* read the width field */
+ {
+ if (width <= 0)
+ {
+ width = 0;
+ *status = BAD_TFORM;
+ }
+ else
+ {
+ /* set to shorter precision if I4 or less */
+ if (width <= 4 && datacode == TLONG)
+ datacode = TSHORT;
+ }
+ }
+ }
+ else
+ {
+ /*-----------------------------------------------*/
+ /* F, E or D data formats: */
+ /*-----------------------------------------------*/
+
+ if (ffc2rr(form, &fwidth, status) <= 0) /* read ww.dd width field */
+ {
+ if (fwidth <= 0.)
+ *status = BAD_TFORM;
+ else
+ {
+ width = (long) fwidth; /* convert from float to long */
+
+ if (width > 7 && *temp == 'F')
+ datacode = TDOUBLE; /* type double if >7 digits */
+
+ if (width < 10)
+ form = form + 1; /* skip 1 digit */
+ else
+ form = form + 2; /* skip 2 digits */
+
+ if (form[0] == '.') /* should be a decimal point here */
+ {
+ form++; /* point to start of decimals field */
+
+ if (ffc2ii(form, &longval, status) <= 0) /* read decimals */
+ {
+ if (decimals)
+ *decimals = longval; /* long to short convertion */
+
+ if (longval >= width) /* width < no. of decimals */
+ *status = BAD_TFORM;
+
+ if (longval > 6 && *temp == 'E')
+ datacode = TDOUBLE; /* type double if >6 digits */
+ }
+ }
+
+ }
+ }
+ }
+ if (*status > 0)
+ {
+ *status = BAD_TFORM;
+ sprintf(message,"Illegal ASCII table TFORMn code: \'%s\'", tform);
+ ffpmsg(message);
+ }
+
+ if (dtcode)
+ *dtcode = datacode;
+
+ if (twidth)
+ *twidth = width;
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffbnfm(char *tform, /* I - format code from the TFORMn keyword */
+ int *dtcode, /* O - numerical datatype code */
+ long *trepeat, /* O - repeat count of the field */
+ long *twidth, /* O - width of the field, in chars */
+ int *status) /* IO - error status */
+{
+/*
+ parse the binary table TFORM column format to determine the data
+ type, repeat count, and the field width (if it is an ASCII (A) field)
+*/
+ size_t ii, nchar;
+ int datacode, variable, iread;
+ long width, repeat;
+ char *form, temp[FLEN_VALUE], message[FLEN_ERRMSG];
+
+ if (*status > 0)
+ return(*status);
+
+ if (dtcode)
+ *dtcode = 0;
+
+ if (trepeat)
+ *trepeat = 0;
+
+ if (twidth)
+ *twidth = 0;
+
+ nchar = strlen(tform);
+
+ for (ii = 0; ii < nchar; ii++)
+ {
+ if (tform[ii] != ' ') /* find first non-space char */
+ break;
+ }
+
+ if (ii == nchar)
+ {
+ ffpmsg("Error: binary table TFORM code is blank (ffbnfm).");
+ return(*status = BAD_TFORM);
+ }
+
+ strcpy(temp, &tform[ii]); /* copy format string */
+ ffupch(temp); /* make sure it is in upper case */
+ form = temp; /* point to start of format string */
+
+ /*-----------------------------------------------*/
+ /* get the repeat count */
+ /*-----------------------------------------------*/
+
+ ii = 0;
+ while(isdigit((int) form[ii]))
+ ii++; /* look for leading digits in the field */
+
+ if (ii == 0)
+ repeat = 1; /* no explicit repeat count */
+ else
+ sscanf(form,"%ld", &repeat); /* read repeat count */
+
+ /*-----------------------------------------------*/
+ /* determine datatype code */
+ /*-----------------------------------------------*/
+
+ form = form + ii; /* skip over the repeat field */
+
+ if (form[0] == 'P')
+ {
+ variable = 1; /* this is a variable length column */
+ repeat = 1; /* disregard any other repeat value */
+ form++; /* move to the next data type code char */
+ }
+ else
+ variable = 0;
+
+ if (form[0] == 'U') /* internal code to signify unsigned integer */
+ {
+ datacode = TUSHORT;
+ width = 2;
+ }
+ else if (form[0] == 'I')
+ {
+ datacode = TSHORT;
+ width = 2;
+ }
+ else if (form[0] == 'V') /* internal code to signify unsigned integer */
+ {
+ datacode = TULONG;
+ width = 4;
+ }
+ else if (form[0] == 'J')
+ {
+ datacode = TLONG;
+ width = 4;
+ }
+ else if (form[0] == 'K')
+ {
+ datacode = TLONGLONG;
+ width = 8;
+ }
+ else if (form[0] == 'E')
+ {
+ datacode = TFLOAT;
+ width = 4;
+ }
+ else if (form[0] == 'D')
+ {
+ datacode = TDOUBLE;
+ width = 8;
+ }
+ else if (form[0] == 'A')
+ {
+ datacode = TSTRING;
+
+ /*
+ the following code is used to support the non-standard
+ datatype of the form rAw where r = total width of the field
+ and w = width of fixed-length substrings within the field.
+ */
+ iread = 0;
+ if (form[1] != 0)
+ {
+ if (form[1] == '(' ) /* skip parenthesis around */
+ form++; /* variable length column width */
+
+ iread = sscanf(&form[1],"%ld", &width);
+ }
+
+ if (iread != 1 || (!variable && (width > repeat)) )
+ width = repeat;
+
+ }
+ else if (form[0] == 'L')
+ {
+ datacode = TLOGICAL;
+ width = 1;
+ }
+ else if (form[0] == 'X')
+ {
+ datacode = TBIT;
+ width = 1;
+ }
+ else if (form[0] == 'B')
+ {
+ datacode = TBYTE;
+ width = 1;
+ }
+ else if (form[0] == 'S') /* internal code to signify signed byte */
+ {
+ datacode = TSBYTE;
+ width = 1;
+ }
+ else if (form[0] == 'C')
+ {
+ datacode = TCOMPLEX;
+ width = 8;
+ }
+ else if (form[0] == 'M')
+ {
+ datacode = TDBLCOMPLEX;
+ width = 16;
+ }
+ else
+ {
+ sprintf(message,
+ "Illegal binary table TFORMn datatype: \'%s\' ", tform);
+ ffpmsg(message);
+ return(*status = BAD_TFORM_DTYPE);
+ }
+
+ if (variable)
+ datacode = datacode * (-1); /* flag variable cols w/ neg type code */
+
+ if (dtcode)
+ *dtcode = datacode;
+
+ if (trepeat)
+ *trepeat = repeat;
+
+ if (twidth)
+ *twidth = width;
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+void ffcfmt(char *tform, /* value of an ASCII table TFORMn keyword */
+ char *cform) /* equivalent format code in C language syntax */
+/*
+ convert the FITS format string for an ASCII Table extension column into the
+ equivalent C format string that can be used in a printf statement, after
+ the values have been read as a double.
+*/
+{
+ int ii;
+
+ cform[0] = '\0';
+ ii = 0;
+ while (tform[ii] != 0 && tform[ii] == ' ') /* find first non-blank char */
+ ii++;
+
+ if (tform[ii] == 0)
+ return; /* input format string was blank */
+
+ cform[0] = '%'; /* start the format string */
+
+ strcpy(&cform[1], &tform[ii + 1]); /* append the width and decimal code */
+
+
+ if (tform[ii] == 'A')
+ strcat(cform, "s");
+ else if (tform[ii] == 'I')
+ strcat(cform, ".0f"); /* 0 precision to suppress decimal point */
+ if (tform[ii] == 'F')
+ strcat(cform, "f");
+ if (tform[ii] == 'E')
+ strcat(cform, "E");
+ if (tform[ii] == 'D')
+ strcat(cform, "E");
+
+ return;
+}
+/*--------------------------------------------------------------------------*/
+void ffcdsp(char *tform, /* value of an ASCII table TFORMn keyword */
+ char *cform) /* equivalent format code in C language syntax */
+/*
+ convert the FITS TDISPn display format into the equivalent C format
+ suitable for use in a printf statement.
+*/
+{
+ int ii;
+
+ cform[0] = '\0';
+ ii = 0;
+ while (tform[ii] != 0 && tform[ii] == ' ') /* find first non-blank char */
+ ii++;
+
+ if (tform[ii] == 0)
+ {
+ cform[0] = '\0';
+ return; /* input format string was blank */
+ }
+
+ cform[0] = '%'; /* start the format string */
+
+ strcpy(&cform[1], &tform[ii + 1]); /* append the width and decimal code */
+
+ if (tform[ii] == 'A' || tform[ii] == 'a')
+ strcat(cform, "s");
+ else if (tform[ii] == 'I' || tform[ii] == 'i')
+ strcat(cform, "d");
+ else if (tform[ii] == 'O' || tform[ii] == 'o')
+ strcat(cform, "o");
+ else if (tform[ii] == 'Z' || tform[ii] == 'z')
+ strcat(cform, "X");
+ else if (tform[ii] == 'F' || tform[ii] == 'f')
+ strcat(cform, "f");
+ else if (tform[ii] == 'E' || tform[ii] == 'e')
+ strcat(cform, "E");
+ else if (tform[ii] == 'D' || tform[ii] == 'd')
+ strcat(cform, "E");
+ else if (tform[ii] == 'G' || tform[ii] == 'g')
+ strcat(cform, "G");
+ else
+ cform[0] = '\0'; /* unrecognized tform code */
+
+ return;
+}
+/*--------------------------------------------------------------------------*/
+int ffgcno( fitsfile *fptr, /* I - FITS file pionter */
+ int casesen, /* I - case sensitive string comparison? 0=no */
+ char *templt, /* I - input name of column (w/wildcards) */
+ int *colnum, /* O - number of the named column; 1=first col */
+ int *status) /* IO - error status */
+/*
+ Determine the column number corresponding to an input column name.
+ The first column of the table = column 1;
+ This supports the * and ? wild cards in the input template.
+*/
+{
+ char colname[FLEN_VALUE]; /* temporary string to hold column name */
+
+ ffgcnn(fptr, casesen, templt, colname, colnum, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgcnn( fitsfile *fptr, /* I - FITS file pointer */
+ int casesen, /* I - case sensitive string comparison? 0=no */
+ char *templt, /* I - input name of column (w/wildcards) */
+ char *colname, /* O - full column name up to 68 + 1 chars long*/
+ int *colnum, /* O - number of the named column; 1=first col */
+ int *status) /* IO - error status */
+/*
+ Return the full column name and column number of the next column whose
+ TTYPEn keyword value matches the input template string.
+ The template may contain the * and ? wildcards. Status = 237 is
+ returned if the match is not unique. If so, one may call this routine
+ again with input status=237 to get the next match. A status value of
+ 219 is returned when there are no more matching columns.
+*/
+{
+ char errmsg[FLEN_ERRMSG];
+ static int startcol;
+ int tstatus, ii, founde, foundw, match, exact, unique;
+ long ivalue;
+ tcolumn *colptr;
+
+ if (*status <= 0)
+ {
+ startcol = 0; /* start search with first column */
+ tstatus = 0;
+ }
+ else if (*status == COL_NOT_UNIQUE) /* start search from previous spot */
+ {
+ tstatus = COL_NOT_UNIQUE;
+ *status = 0;
+ }
+ else
+ return(*status); /* bad input status value */
+
+ colname[0] = 0; /* initialize null return */
+ *colnum = 0;
+
+ /* reset position to the correct HDU if necessary */
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+ else if ((fptr->Fptr)->datastart == DATA_UNDEFINED)
+ if ( ffrdef(fptr, status) > 0) /* rescan header to get col struct */
+ return(*status);
+
+ colptr = (fptr->Fptr)->tableptr; /* pointer to first column */
+ colptr += (startcol); /* offset to starting column */
+
+ founde = FALSE; /* initialize 'found exact match' flag */
+ foundw = FALSE; /* initialize 'found wildcard match' flag */
+ unique = FALSE;
+
+ for (ii = startcol; ii < (fptr->Fptr)->tfield; ii++, colptr++)
+ {
+ ffcmps(templt, colptr->ttype, casesen, &match, &exact);
+ if (match)
+ {
+ if (founde && exact)
+ {
+ /* warning: this is the second exact match we've found */
+ /*reset pointer to first match so next search starts there */
+ startcol = *colnum;
+ return(*status = COL_NOT_UNIQUE);
+ }
+ else if (founde) /* a wildcard match */
+ {
+ /* already found exact match so ignore this non-exact match */
+ }
+ else if (exact)
+ {
+ /* this is the first exact match we have found, so save it. */
+ strcpy(colname, colptr->ttype);
+ *colnum = ii + 1;
+ founde = TRUE;
+ }
+ else if (foundw)
+ {
+ /* we have already found a wild card match, so not unique */
+ /* continue searching for other matches */
+ unique = FALSE;
+ }
+ else
+ {
+ /* this is the first wild card match we've found. save it */
+ strcpy(colname, colptr->ttype);
+ *colnum = ii + 1;
+ startcol = *colnum;
+ foundw = TRUE;
+ unique = TRUE;
+ }
+ }
+ }
+
+ /* OK, we've checked all the names now see if we got any matches */
+ if (founde)
+ {
+ if (tstatus == COL_NOT_UNIQUE) /* we did find 1 exact match but */
+ *status = COL_NOT_UNIQUE; /* there was a previous match too */
+ }
+ else if (foundw)
+ {
+ /* found one or more wildcard matches; report error if not unique */
+ if (!unique || tstatus == COL_NOT_UNIQUE)
+ *status = COL_NOT_UNIQUE;
+ }
+ else
+ {
+ /* didn't find a match; check if template is a positive integer */
+ ffc2ii(templt, &ivalue, &tstatus);
+ if (tstatus == 0 && ivalue <= (fptr->Fptr)->tfield && ivalue > 0)
+ {
+ *colnum = ivalue;
+
+ colptr = (fptr->Fptr)->tableptr; /* pointer to first column */
+ colptr += (ivalue - 1); /* offset to correct column */
+ strcpy(colname, colptr->ttype);
+ }
+ else
+ {
+ *status = COL_NOT_FOUND;
+ if (tstatus != COL_NOT_UNIQUE)
+ {
+ sprintf(errmsg, "ffgcnn could not find column: %.45s", templt);
+ ffpmsg(errmsg);
+ }
+ }
+ }
+
+ startcol = *colnum; /* save pointer for next time */
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+void ffcmps(char *templt, /* I - input template (may have wildcards) */
+ char *colname, /* I - full column name up to 68 + 1 chars long */
+ int casesen, /* I - case sensitive string comparison? 1=yes */
+ int *match, /* O - do template and colname match? 1=yes */
+ int *exact) /* O - do strings exactly match, or wildcards */
+/*
+ compare the template to the string and test if they match.
+ The strings are limited to 68 characters or less (the max. length
+ of a FITS string keyword value. This routine reports whether
+ the two strings match and whether the match is exact or
+ involves wildcards.
+
+ This algorithm is very similar to the way unix filename wildcards
+ work except that this first treats a wild card as a literal character
+ when looking for a match. If there is no literal match, then
+ it interpretes it as a wild card. So the template 'AB*DE'
+ is considered to be an exact rather than a wild card match to
+ the string 'AB*DE'. The '#' wild card in the template string will
+ match any consecutive string of decimal digits in the colname.
+
+*/
+{
+ int ii, found, t1, s1, wildsearch = 0, tsave = 0, ssave = 0;
+ char temp[FLEN_VALUE], col[FLEN_VALUE];
+
+ *match = FALSE;
+ *exact = TRUE;
+
+ strncpy(temp, templt, FLEN_VALUE); /* copy strings to work area */
+ strncpy(col, colname, FLEN_VALUE);
+ temp[FLEN_VALUE - 1] = '\0'; /* make sure strings are terminated */
+ col[FLEN_VALUE - 1] = '\0';
+
+ /* truncate trailing non-significant blanks */
+ for (ii = strlen(temp) - 1; ii >= 0 && temp[ii] == ' '; ii--)
+ temp[ii] = '\0';
+
+ for (ii = strlen(col) - 1; ii >= 0 && col[ii] == ' '; ii--)
+ col[ii] = '\0';
+
+ if (!casesen)
+ { /* convert both strings to uppercase before comparison */
+ ffupch(temp);
+ ffupch(col);
+ }
+
+ if (!FSTRCMP(temp, col) )
+ {
+ *match = TRUE; /* strings exactly match */
+ return;
+ }
+
+ *exact = FALSE; /* strings don't exactly match */
+
+ t1 = 0; /* start comparison with 1st char of each string */
+ s1 = 0;
+
+ while(1) /* compare corresponding chars in each string */
+ {
+ if (temp[t1] == '\0' && col[s1] == '\0')
+ {
+ /* completely scanned both strings so they match */
+ *match = TRUE;
+ return;
+ }
+ else if (temp[t1] == '\0')
+ {
+ if (wildsearch)
+ {
+ /*
+ the previous wildcard search may have been going down
+ a blind alley. Backtrack, and resume the wildcard
+ search with the next character in the string.
+ */
+ t1 = tsave;
+ s1 = ssave + 1;
+ }
+ else
+ {
+ /* reached end of template string so they don't match */
+ return;
+ }
+ }
+ else if (col[s1] == '\0')
+ {
+ /* reached end of other string; they match if the next */
+ /* character in the template string is a '*' wild card */
+
+ if (temp[t1] == '*' && temp[t1 + 1] == '\0')
+ {
+ *match = TRUE;
+ }
+
+ return;
+ }
+
+ if (temp[t1] == col[s1] || (temp[t1] == '?') )
+ {
+ s1++; /* corresponding chars in the 2 strings match */
+ t1++; /* increment both pointers and loop back again */
+ }
+ else if (temp[t1] == '#' && isdigit((int) col[s1]) )
+ {
+ s1++; /* corresponding chars in the 2 strings match */
+ t1++; /* increment both pointers */
+
+ /* find the end of the string of digits */
+ while (isdigit((int) col[s1]) )
+ s1++;
+ }
+ else if (temp[t1] == '*')
+ {
+
+ /* save current string locations, in case we need to restart */
+ wildsearch = 1;
+ tsave = t1;
+ ssave = s1;
+
+ /* get next char from template and look for it in the col name */
+ t1++;
+ if (temp[t1] == '\0' || temp[t1] == ' ')
+ {
+ /* reached end of template so strings match */
+ *match = TRUE;
+ return;
+ }
+
+ found = FALSE;
+ while (col[s1] && !found)
+ {
+ if (temp[t1] == col[s1])
+ {
+ t1++; /* found matching characters; incre both pointers */
+ s1++; /* and loop back to compare next chars */
+ found = TRUE;
+ }
+ else
+ s1++; /* increment the column name pointer and try again */
+ }
+
+ if (!found)
+ {
+ return; /* hit end of column name and failed to find a match */
+ }
+ }
+ else
+ {
+ if (wildsearch)
+ {
+ /*
+ the previous wildcard search may have been going down
+ a blind alley. Backtrack, and resume the wildcard
+ search with the next character in the string.
+ */
+ t1 = tsave;
+ s1 = ssave + 1;
+ }
+ else
+ {
+ return; /* strings don't match */
+ }
+ }
+ }
+}
+/*--------------------------------------------------------------------------*/
+int ffgtcl( fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - column number */
+ int *typecode, /* O - datatype code (21 = short, etc) */
+ long *repeat, /* O - repeat count of field */
+ long *width, /* O - if ASCII, width of field or unit string */
+ int *status) /* IO - error status */
+/*
+ Get Type of table column.
+ Returns the datatype code of the column, as well as the vector
+ repeat count and (if it is an ASCII character column) the
+ width of the field or a unit string within the field. This supports the
+ TFORMn = 'rAw' syntax for specifying arrays of substrings, so
+ if TFORMn = '60A12' then repeat = 60 and width = 12.
+*/
+{
+ tcolumn *colptr;
+ int hdutype, decims;
+
+ if (*status > 0)
+ return(*status);
+
+ /* reset position to the correct HDU if necessary */
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+ else if ((fptr->Fptr)->datastart == DATA_UNDEFINED)
+ if ( ffrdef(fptr, status) > 0) /* rescan header */
+ return(*status);
+
+ if (colnum < 1 || colnum > (fptr->Fptr)->tfield)
+ return(*status = BAD_COL_NUM);
+
+ colptr = (fptr->Fptr)->tableptr; /* pointer to first column */
+ colptr += (colnum - 1); /* offset to correct column */
+
+ if (ffghdt(fptr, &hdutype, status) > 0)
+ return(*status);
+
+ if (hdutype == ASCII_TBL)
+ {
+ ffasfm(colptr->tform, typecode, width, &decims, status);
+
+ if (repeat)
+ *repeat = 1;
+ }
+ else
+ {
+ if (typecode)
+ *typecode = colptr->tdatatype;
+
+ if (width)
+ *width = colptr->twidth;
+
+ if (repeat)
+ *repeat = (long) colptr->trepeat;
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffeqty( fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - column number */
+ int *typecode, /* O - datatype code (21 = short, etc) */
+ long *repeat, /* O - repeat count of field */
+ long *width, /* O - if ASCII, width of field or unit string */
+ int *status) /* IO - error status */
+/*
+ Get the 'equivalent' table column type.
+
+ This routine is similar to the ffgtcl routine (which returns the physical
+ datatype of the column, as stored in the FITS file) except that if the
+ TSCALn and TZEROn keywords are defined for the column, then it returns
+ the 'equivalent' datatype. Thus, if the column is defined as '1I' (short
+ integer) this routine may return the type as 'TUSHORT' or as 'TFLOAT'
+ depending on the TSCALn and TZEROn values.
+
+ Returns the datatype code of the column, as well as the vector
+ repeat count and (if it is an ASCII character column) the
+ width of the field or a unit string within the field. This supports the
+ TFORMn = 'rAw' syntax for specifying arrays of substrings, so
+ if TFORMn = '60A12' then repeat = 60 and width = 12.
+*/
+{
+ tcolumn *colptr;
+ int hdutype, decims, tcode, effcode;
+ double tscale, tzero, min_val, max_val;
+ long lngscale = 1, lngzero = 0;
+
+ if (*status > 0)
+ return(*status);
+
+ /* reset position to the correct HDU if necessary */
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+ else if ((fptr->Fptr)->datastart == DATA_UNDEFINED)
+ if ( ffrdef(fptr, status) > 0) /* rescan header */
+ return(*status);
+
+ if (colnum < 1 || colnum > (fptr->Fptr)->tfield)
+ return(*status = BAD_COL_NUM);
+
+ colptr = (fptr->Fptr)->tableptr; /* pointer to first column */
+ colptr += (colnum - 1); /* offset to correct column */
+
+ if (ffghdt(fptr, &hdutype, status) > 0)
+ return(*status);
+
+ if (hdutype == ASCII_TBL)
+ {
+ ffasfm(colptr->tform, typecode, width, &decims, status);
+
+ if (repeat)
+ *repeat = 1;
+ }
+ else
+ {
+ if (typecode)
+ *typecode = colptr->tdatatype;
+
+ if (width)
+ *width = colptr->twidth;
+
+ if (repeat)
+ *repeat = (long) colptr->trepeat;
+ }
+
+ /* return if caller is not interested in the typecode value */
+ if (!typecode)
+ return(*status);
+
+ /* check if the tscale and tzero keywords are defined, which might
+ change the effective datatype of the column */
+
+ tscale = colptr->tscale;
+ tzero = colptr->tzero;
+
+ if (tscale == 1.0 && tzero == 0.0) /* no scaling */
+ return(*status);
+
+ tcode = abs(*typecode);
+
+ switch (tcode)
+ {
+ case TBYTE: /* binary table 'rB' column */
+ min_val = 0.;
+ max_val = 255.0;
+ break;
+
+ case TSHORT:
+ min_val = -32768.0;
+ max_val = 32767.0;
+ break;
+
+ case TLONG:
+
+ min_val = -2147483648.0;
+ max_val = 2147483647.0;
+ break;
+
+ default: /* don't have to deal with other data types */
+ return(*status);
+ }
+
+ if (tscale >= 0.) {
+ min_val = tzero + tscale * min_val;
+ max_val = tzero + tscale * max_val;
+ } else {
+ max_val = tzero + tscale * min_val;
+ min_val = tzero + tscale * max_val;
+ }
+ if (tzero < 2147483648.) /* don't exceed range of 32-bit integer */
+ lngzero = tzero;
+ lngscale = tscale;
+
+ if ((tzero != 2147483648.) && /* special value that exceeds integer range */
+ (lngzero != tzero || lngscale != tscale)) { /* not integers? */
+ /* floating point scaled values; just decide on required precision */
+ if (tcode == TBYTE || tcode == TSHORT)
+ effcode = TFLOAT;
+ else
+ effcode = TDOUBLE;
+
+ /*
+ In all the remaining cases, TSCALn and TZEROn are integers,
+ and not equal to 1 and 0, respectively.
+ */
+
+ } else if ((min_val == -128.) && (max_val == 127.)) {
+ effcode = TSBYTE;
+
+ } else if ((min_val >= -32768.0) && (max_val <= 32767.0)) {
+ effcode = TSHORT;
+
+ } else if ((min_val >= 0.0) && (max_val <= 65535.0)) {
+ effcode = TUSHORT;
+
+ } else if ((min_val >= -2147483648.0) && (max_val <= 2147483647.0)) {
+ effcode = TLONG;
+
+ } else if ((min_val >= 0.0) && (max_val < 4294967296.0)) {
+ effcode = TULONG;
+
+ } else { /* exceeds the range of a 32-bit integer */
+ effcode = TDOUBLE;
+ }
+
+ /* return the effective datatype code (negative if variable length col.) */
+ if (*typecode < 0) /* variable length array column */
+ *typecode = -effcode;
+ else
+ *typecode = effcode;
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgncl( fitsfile *fptr, /* I - FITS file pointer */
+ int *ncols, /* O - number of columns in the table */
+ int *status) /* IO - error status */
+/*
+ Get the number of columns in the table (= TFIELDS keyword)
+*/
+{
+ if (*status > 0)
+ return(*status);
+
+ /* reset position to the correct HDU if necessary */
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+ else if ((fptr->Fptr)->datastart == DATA_UNDEFINED)
+ if ( ffrdef(fptr, status) > 0) /* rescan header */
+ return(*status);
+
+ if ((fptr->Fptr)->hdutype == IMAGE_HDU)
+ return(*status = NOT_TABLE);
+
+ *ncols = (fptr->Fptr)->tfield;
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgnrw( fitsfile *fptr, /* I - FITS file pointer */
+ long *nrows, /* O - number of rows in the table */
+ int *status) /* IO - error status */
+/*
+ Get the number of rows in the table (= NAXIS2 keyword)
+*/
+{
+ if (*status > 0)
+ return(*status);
+
+ /* reset position to the correct HDU if necessary */
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+ else if ((fptr->Fptr)->datastart == DATA_UNDEFINED)
+ if ( ffrdef(fptr, status) > 0) /* rescan header */
+ return(*status);
+
+ if ((fptr->Fptr)->hdutype == IMAGE_HDU)
+ return(*status = NOT_TABLE);
+
+ /* the NAXIS2 keyword may not be up to date, so use the structure value */
+ *nrows = (fptr->Fptr)->numrows;
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgacl( fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - column number */
+ char *ttype, /* O - TTYPEn keyword value */
+ long *tbcol, /* O - TBCOLn keyword value */
+ char *tunit, /* O - TUNITn keyword value */
+ char *tform, /* O - TFORMn keyword value */
+ double *tscal, /* O - TSCALn keyword value */
+ double *tzero, /* O - TZEROn keyword value */
+ char *tnull, /* O - TNULLn keyword value */
+ char *tdisp, /* O - TDISPn keyword value */
+ int *status) /* IO - error status */
+/*
+ get ASCII column keyword values
+*/
+{
+ char name[FLEN_KEYWORD], comm[FLEN_COMMENT];
+ tcolumn *colptr;
+ int tstatus;
+
+ if (*status > 0)
+ return(*status);
+
+ /* reset position to the correct HDU if necessary */
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+ else if ((fptr->Fptr)->datastart == DATA_UNDEFINED)
+ if ( ffrdef(fptr, status) > 0) /* rescan header */
+ return(*status);
+
+ if (colnum < 1 || colnum > (fptr->Fptr)->tfield)
+ return(*status = BAD_COL_NUM);
+
+ /* get what we can from the column structure */
+
+ colptr = (fptr->Fptr)->tableptr; /* pointer to first column */
+ colptr += (colnum -1); /* offset to correct column */
+
+ if (ttype)
+ strcpy(ttype, colptr->ttype);
+
+ if (tbcol)
+ *tbcol = (colptr->tbcol) + 1; /* first col is 1, not 0 */
+
+ if (tform)
+ strcpy(tform, colptr->tform);
+
+ if (tscal)
+ *tscal = colptr->tscale;
+
+ if (tzero)
+ *tzero = colptr->tzero;
+
+ if (tnull)
+ strcpy(tnull, colptr->strnull);
+
+ /* read keywords to get additional parameters */
+
+ if (tunit)
+ {
+ ffkeyn("TUNIT", colnum, name, status);
+ tstatus = 0;
+ *tunit = '\0';
+ ffgkys(fptr, name, tunit, comm, &tstatus);
+ }
+
+ if (tdisp)
+ {
+ ffkeyn("TDISP", colnum, name, status);
+ tstatus = 0;
+ *tdisp = '\0';
+ ffgkys(fptr, name, tdisp, comm, &tstatus);
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgbcl( fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - column number */
+ char *ttype, /* O - TTYPEn keyword value */
+ char *tunit, /* O - TUNITn keyword value */
+ char *dtype, /* O - datatype char: I, J, E, D, etc. */
+ long *repeat, /* O - vector column repeat count */
+ double *tscal, /* O - TSCALn keyword value */
+ double *tzero, /* O - TZEROn keyword value */
+ long *tnull, /* O - TNULLn keyword value integer cols only */
+ char *tdisp, /* O - TDISPn keyword value */
+ int *status) /* IO - error status */
+/*
+ get BINTABLE column keyword values
+*/
+{
+ char name[FLEN_KEYWORD], comm[FLEN_COMMENT];
+ tcolumn *colptr;
+ int tstatus;
+
+ if (*status > 0)
+ return(*status);
+
+ /* reset position to the correct HDU if necessary */
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+ else if ((fptr->Fptr)->datastart == DATA_UNDEFINED)
+ if ( ffrdef(fptr, status) > 0) /* rescan header */
+ return(*status);
+
+ if (colnum < 1 || colnum > (fptr->Fptr)->tfield)
+ return(*status = BAD_COL_NUM);
+
+ /* get what we can from the column structure */
+
+ colptr = (fptr->Fptr)->tableptr; /* pointer to first column */
+ colptr += (colnum -1); /* offset to correct column */
+
+ if (ttype)
+ strcpy(ttype, colptr->ttype);
+
+ if (dtype)
+ {
+ if (colptr->tdatatype < 0) /* add the "P" prefix for */
+ strcpy(dtype, "P"); /* variable length columns */
+ else
+ dtype[0] = 0;
+
+ if (abs(colptr->tdatatype) == TBIT)
+ strcat(dtype, "X");
+ else if (abs(colptr->tdatatype) == TBYTE)
+ strcat(dtype, "B");
+ else if (abs(colptr->tdatatype) == TLOGICAL)
+ strcat(dtype, "L");
+ else if (abs(colptr->tdatatype) == TSTRING)
+ strcat(dtype, "A");
+ else if (abs(colptr->tdatatype) == TSHORT)
+ strcat(dtype, "I");
+ else if (abs(colptr->tdatatype) == TLONG)
+ strcat(dtype, "J");
+ else if (abs(colptr->tdatatype) == TFLOAT)
+ strcat(dtype, "E");
+ else if (abs(colptr->tdatatype) == TDOUBLE)
+ strcat(dtype, "D");
+ else if (abs(colptr->tdatatype) == TCOMPLEX)
+ strcat(dtype, "C");
+ else if (abs(colptr->tdatatype) == TDBLCOMPLEX)
+ strcat(dtype, "M");
+ }
+
+ if (repeat)
+ *repeat = (long) colptr->trepeat;
+
+ if (tscal)
+ *tscal = colptr->tscale;
+
+ if (tzero)
+ *tzero = colptr->tzero;
+
+ if (tnull)
+ *tnull = colptr->tnull;
+
+ /* read keywords to get additional parameters */
+
+ if (tunit)
+ {
+ ffkeyn("TUNIT", colnum, name, status);
+ tstatus = 0;
+ *tunit = '\0';
+ ffgkys(fptr, name, tunit, comm, &tstatus);
+ }
+
+ if (tdisp)
+ {
+ ffkeyn("TDISP", colnum, name, status);
+ tstatus = 0;
+ *tdisp = '\0';
+ ffgkys(fptr, name, tdisp, comm, &tstatus);
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffghdn(fitsfile *fptr, /* I - FITS file pointer */
+ int *chdunum) /* O - number of the CHDU; 1 = primary array */
+/*
+ Return the number of the Current HDU in the FITS file. The primary array
+ is HDU number 1. Note that this is one of the few cfitsio routines that
+ does not return the error status value as the value of the function.
+*/
+{
+ *chdunum = (fptr->HDUposition) + 1;
+ return(*chdunum);
+}
+/*--------------------------------------------------------------------------*/
+int ffghof(fitsfile *fptr, /* I - FITS file pointer */
+ OFF_T *headstart, /* O - byte offset to beginning of CHDU */
+ OFF_T *datastart, /* O - byte offset to beginning of next HDU */
+ OFF_T *dataend, /* O - byte offset to beginning of next HDU */
+ int *status) /* IO - error status */
+/*
+ Return the address (= byte offset) in the FITS file to the beginning of
+ the current HDU, the beginning of the data unit, and the end of the data unit.
+*/
+{
+ if (*status > 0)
+ return(*status);
+
+ /* reset position to the correct HDU if necessary */
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ {
+ if (ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status) > 0)
+ return(*status);
+ }
+ else if ((fptr->Fptr)->datastart == DATA_UNDEFINED)
+ {
+ if (ffrdef(fptr, status) > 0) /* rescan header */
+ return(*status);
+ }
+
+ if (headstart)
+ *headstart = (fptr->Fptr)->headstart[(fptr->Fptr)->curhdu];
+
+ if (datastart)
+ *datastart = (fptr->Fptr)->datastart;
+
+ if (dataend)
+ *dataend = (fptr->Fptr)->headstart[((fptr->Fptr)->curhdu) + 1];
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffghad(fitsfile *fptr, /* I - FITS file pointer */
+ long *headstart, /* O - byte offset to beginning of CHDU */
+ long *datastart, /* O - byte offset to beginning of next HDU */
+ long *dataend, /* O - byte offset to beginning of next HDU */
+ int *status) /* IO - error status */
+/*
+ Return the address (= byte offset) in the FITS file to the beginning of
+ the current HDU, the beginning of the data unit, and the end of the data unit.
+*/
+{
+ OFF_T shead, sdata, edata;
+
+ if (*status > 0)
+ return(*status);
+
+ ffghof(fptr, &shead, &sdata, &edata, status);
+
+ if (headstart)
+ {
+ if (shead > LONG_MAX)
+ *status = NUM_OVERFLOW;
+ else
+ *headstart = (long) shead;
+ }
+
+ if (datastart)
+ {
+ if (sdata > LONG_MAX)
+ *status = NUM_OVERFLOW;
+ else
+ *datastart = (long) sdata;
+ }
+
+ if (dataend)
+ {
+ if (edata > LONG_MAX)
+ *status = NUM_OVERFLOW;
+ else
+ *dataend = (long) edata;
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffrhdu(fitsfile *fptr, /* I - FITS file pointer */
+ int *hdutype, /* O - type of HDU */
+ int *status) /* IO - error status */
+/*
+ read the required keywords of the CHDU and initialize the corresponding
+ structure elements that describe the format of the HDU
+*/
+{
+ int ii, tstatus;
+ char card[FLEN_CARD];
+ char name[FLEN_KEYWORD], value[FLEN_VALUE], comm[FLEN_COMMENT];
+ char xname[FLEN_VALUE], *xtension, urltype[20];
+
+ if (*status > 0)
+ return(*status);
+
+ if (ffgrec(fptr, 1, card, status) > 0 ) /* get the 80-byte card */
+ {
+ ffpmsg("Cannot read first keyword in header (ffrhdu).");
+ return(*status);
+ }
+ strncpy(name,card,8); /* first 8 characters = the keyword name */
+ name[8] = '\0';
+
+ for (ii=7; ii >= 0; ii--) /* replace trailing blanks with nulls */
+ {
+ if (name[ii] == ' ')
+ name[ii] = '\0';
+ else
+ break;
+ }
+
+ if (ffpsvc(card, value, comm, status) > 0) /* parse value and comment */
+ {
+ ffpmsg("Cannot read value of first keyword in header (ffrhdu):");
+ ffpmsg(card);
+ return(*status);
+ }
+
+ if (!strcmp(name, "SIMPLE")) /* this is the primary array */
+ {
+
+ ffpinit(fptr, status); /* initialize the primary array */
+
+ if (hdutype != NULL)
+ *hdutype = 0;
+ }
+
+ else if (!strcmp(name, "XTENSION")) /* this is an XTENSION keyword */
+ {
+ if (ffc2s(value, xname, status) > 0) /* get the value string */
+ {
+ ffpmsg("Bad value string for XTENSION keyword:");
+ ffpmsg(value);
+ return(*status);
+ }
+
+ xtension = xname;
+ while (*xtension == ' ') /* ignore any leading spaces in name */
+ xtension++;
+
+ if (!strcmp(xtension, "TABLE"))
+ {
+ ffainit(fptr, status); /* initialize the ASCII table */
+ if (hdutype != NULL)
+ *hdutype = 1;
+ }
+
+ else if (!strcmp(xtension, "BINTABLE") ||
+ !strcmp(xtension, "A3DTABLE") ||
+ !strcmp(xtension, "3DTABLE") )
+ {
+ ffbinit(fptr, status); /* initialize the binary table */
+ if (hdutype != NULL)
+ *hdutype = 2;
+ }
+
+ else
+ {
+ tstatus = 0;
+ ffpinit(fptr, &tstatus); /* probably an IMAGE extension */
+
+ if (tstatus == UNKNOWN_EXT && hdutype != NULL)
+ *hdutype = -1; /* don't recognize this extension type */
+ else
+ {
+ *status = tstatus;
+ if (hdutype != NULL)
+ *hdutype = 0;
+ }
+ }
+ }
+
+ else /* not the start of a new extension */
+ {
+ if (card[0] == 0 ||
+ card[0] == 10) /* some editors append this character to EOF */
+ {
+ *status = END_OF_FILE;
+ }
+ else
+ {
+ *status = UNKNOWN_REC; /* found unknown type of record */
+ ffpmsg
+ ("Extension doesn't start with SIMPLE or XTENSION keyword. (ffrhdu)");
+ ffpmsg(card);
+ }
+ }
+
+ /* compare the starting position of the next HDU (if any) with the size */
+ /* of the whole file to see if this is the last HDU in the file */
+
+ if ((fptr->Fptr)->headstart[ (fptr->Fptr)->curhdu + 1] <
+ (fptr->Fptr)->logfilesize )
+ {
+ (fptr->Fptr)->lasthdu = 0; /* no, not the last HDU */
+ }
+ else
+ {
+ (fptr->Fptr)->lasthdu = 1; /* yes, this is the last HDU */
+
+ /* special code for mem:// type files (FITS file in memory) */
+ /* Allocate enough memory to hold the entire HDU. */
+ /* Without this code, CFITSIO would repeatedly realloc memory */
+ /* to incrementally increase the size of the file by 2880 bytes */
+ /* at a time, until it reached the final size */
+
+ ffurlt(fptr, urltype, status);
+ if (!strcmp(urltype,"mem://") || !strcmp(urltype,"memkeep://"))
+ {
+ fftrun(fptr, (fptr->Fptr)->headstart[ (fptr->Fptr)->curhdu + 1],
+ status);
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpinit(fitsfile *fptr, /* I - FITS file pointer */
+ int *status) /* IO - error status */
+/*
+ initialize the parameters defining the structure of the primary array
+ or an Image extension
+*/
+{
+ int groups, tstatus, simple, bitpix, naxis, extend, nspace;
+ int ttype = 0, bytlen = 0, ii;
+ long naxes[999], pcount, gcount, blank;
+ OFF_T npix;
+ double bscale, bzero;
+ char comm[FLEN_COMMENT];
+ tcolumn *colptr;
+
+ if (*status > 0)
+ return(*status);
+
+ /* reset position to the correct HDU if necessary */
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+
+ (fptr->Fptr)->hdutype = IMAGE_HDU; /* primary array or IMAGE extension */
+ (fptr->Fptr)->headend = (fptr->Fptr)->logfilesize; /* set max size */
+
+ groups = 0;
+ tstatus = *status;
+
+ /* get all the descriptive info about this HDU */
+ ffgphd(fptr, 999, &simple, &bitpix, &naxis, naxes, &pcount, &gcount,
+ &extend, &bscale, &bzero, &blank, &nspace, status);
+
+ if (*status == NOT_IMAGE)
+ *status = tstatus; /* ignore 'unknown extension type' error */
+ else if (*status > 0)
+ return(*status);
+
+ /*
+ the logical end of the header is 80 bytes before the current position,
+ minus any trailing blank keywords just before the END keyword.
+ */
+ (fptr->Fptr)->headend = (fptr->Fptr)->nextkey - (80 * (nspace + 1));
+
+ /* the data unit begins at the beginning of the next logical block */
+ (fptr->Fptr)->datastart = (((fptr->Fptr)->nextkey - 80) / 2880 + 1)
+ * 2880;
+
+ if (naxis > 0 && naxes[0] == 0) /* test for 'random groups' */
+ {
+ tstatus = 0;
+ if (ffgkyl(fptr, "GROUPS", &groups, comm, &tstatus))
+ groups = 0; /* GROUPS keyword not found */
+ }
+
+ if (bitpix == BYTE_IMG) /* test bitpix and set the datatype code */
+ {
+ ttype=TBYTE;
+ bytlen=1;
+ }
+ else if (bitpix == SHORT_IMG)
+ {
+ ttype=TSHORT;
+ bytlen=2;
+ }
+ else if (bitpix == LONG_IMG)
+ {
+ ttype=TLONG;
+ bytlen=4;
+ }
+ else if (bitpix == LONGLONG_IMG)
+ {
+ ttype=TLONGLONG;
+ bytlen=8;
+ }
+ else if (bitpix == FLOAT_IMG)
+ {
+ ttype=TFLOAT;
+ bytlen=4;
+ }
+ else if (bitpix == DOUBLE_IMG)
+ {
+ ttype=TDOUBLE;
+ bytlen=8;
+ }
+
+ /* calculate the size of the primary array */
+ if (naxis == 0)
+ {
+ npix = 0;
+ }
+ else
+ {
+ if (groups)
+ {
+ npix = 1; /* NAXIS1 = 0 is a special flag for 'random groups' */
+ }
+ else
+ {
+ npix = naxes[0];
+ }
+
+ for (ii=1; ii < naxis; ii++)
+ {
+ npix = npix*naxes[ii]; /* calc number of pixels in the array */
+ }
+ }
+
+ /*
+ now we know everything about the array; just fill in the parameters:
+ the next HDU begins in the next logical block after the data
+ */
+
+ (fptr->Fptr)->headstart[ (fptr->Fptr)->curhdu + 1] =
+ (fptr->Fptr)->datastart +
+ ( (OFF_T)(pcount + npix) * bytlen * gcount + 2879) / 2880 * 2880;
+
+ /*
+ initialize the fictitious heap starting address (immediately following
+ the array data) and a zero length heap. This is used to find the
+ end of the data when checking the fill values in the last block.
+ */
+ (fptr->Fptr)->heapstart = (npix + pcount) * bytlen * gcount;
+ (fptr->Fptr)->heapsize = 0;
+
+ (fptr->Fptr)->compressimg = 0; /* this is not a compressed image */
+
+ if (naxis == 0)
+ {
+ (fptr->Fptr)->rowlength = 0; /* rows have zero length */
+ (fptr->Fptr)->tfield = 0; /* table has no fields */
+
+ if ((fptr->Fptr)->tableptr)
+ free((fptr->Fptr)->tableptr); /* free memory for the old CHDU */
+
+ (fptr->Fptr)->tableptr = 0; /* set a null table structure pointer */
+ (fptr->Fptr)->numrows = 0;
+ (fptr->Fptr)->origrows = 0;
+ }
+ else
+ {
+ /*
+ The primary array is actually interpreted as a binary table. There
+ are two columns: the first column contains the group parameters if any.
+ The second column contains the primary array of data as a single vector
+ column element. In the case of 'random grouped' format, each group
+ is stored in a separate row of the table.
+ */
+ /* the number of rows is equal to the number of groups */
+ (fptr->Fptr)->numrows = gcount;
+ (fptr->Fptr)->origrows = gcount;
+
+ (fptr->Fptr)->rowlength = (npix + pcount) * bytlen; /* total size */
+ (fptr->Fptr)->tfield = 2; /* 2 fields: group params and the image */
+
+ if ((fptr->Fptr)->tableptr)
+ free((fptr->Fptr)->tableptr); /* free memory for the old CHDU */
+
+ colptr = (tcolumn *) calloc(2, sizeof(tcolumn) ) ;
+
+ if (!colptr)
+ {
+ ffpmsg
+ ("malloc failed to get memory for FITS array descriptors (ffpinit)");
+ (fptr->Fptr)->tableptr = 0; /* set a null table structure pointer */
+ return(*status = ARRAY_TOO_BIG);
+ }
+
+ /* copy the table structure address to the fitsfile structure */
+ (fptr->Fptr)->tableptr = colptr;
+
+ /* the first column represents the group parameters, if any */
+ colptr->tbcol = 0;
+ colptr->tdatatype = ttype;
+ colptr->twidth = bytlen;
+ colptr->trepeat = (OFF_T) pcount;
+ colptr->tscale = 1.;
+ colptr->tzero = 0.;
+ colptr->tnull = blank;
+
+ colptr++; /* increment pointer to the second column */
+
+ /* the second column represents the image array */
+ colptr->tbcol = pcount * bytlen; /* col starts after the group parms */
+ colptr->tdatatype = ttype;
+ colptr->twidth = bytlen;
+ colptr->trepeat = npix;
+ colptr->tscale = bscale;
+ colptr->tzero = bzero;
+ colptr->tnull = blank;
+ }
+
+ /* reset next keyword pointer to the start of the header */
+ (fptr->Fptr)->nextkey = (fptr->Fptr)->headstart[ (fptr->Fptr)->curhdu ];
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffainit(fitsfile *fptr, /* I - FITS file pointer */
+ int *status) /* IO - error status */
+{
+/*
+ initialize the parameters defining the structure of an ASCII table
+*/
+ int ii, nspace, tbcoln;
+ long nrows, rowlen, pcount, tfield;
+ tcolumn *colptr = 0;
+ char name[FLEN_KEYWORD], value[FLEN_VALUE], comm[FLEN_COMMENT];
+ char message[FLEN_ERRMSG], errmsg[81];
+
+ if (*status > 0)
+ return(*status);
+
+ /* reset position to the correct HDU if necessary */
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+
+ (fptr->Fptr)->hdutype = ASCII_TBL; /* set that this is an ASCII table */
+ (fptr->Fptr)->headend = (fptr->Fptr)->logfilesize; /* set max size */
+
+ /* get table parameters and test that the header is a valid: */
+ if (ffgttb(fptr, &rowlen, &nrows, &pcount, &tfield, status) > 0)
+ return(*status);
+
+ if (pcount != 0)
+ {
+ ffpmsg("PCOUNT keyword not equal to 0 in ASCII table (ffainit).");
+ sprintf(errmsg, " PCOUNT = %ld", pcount);
+ ffpmsg(errmsg);
+ return(*status = BAD_PCOUNT);
+ }
+
+ (fptr->Fptr)->rowlength = (OFF_T) rowlen; /* store length of a row */
+ (fptr->Fptr)->tfield = tfield; /* store number of table fields in row */
+
+ if ((fptr->Fptr)->tableptr)
+ free((fptr->Fptr)->tableptr); /* free memory for the old CHDU */
+
+ /* mem for column structures ; space is initialized = 0 */
+ if (tfield > 0)
+ {
+ colptr = (tcolumn *) calloc(tfield, sizeof(tcolumn) );
+ if (!colptr)
+ {
+ ffpmsg
+ ("malloc failed to get memory for FITS table descriptors (ffainit)");
+ (fptr->Fptr)->tableptr = 0; /* set a null table structure pointer */
+ return(*status = ARRAY_TOO_BIG);
+ }
+ }
+
+ /* copy the table structure address to the fitsfile structure */
+ (fptr->Fptr)->tableptr = colptr;
+
+ /* initialize the table field parameters */
+ for (ii = 0; ii < tfield; ii++, colptr++)
+ {
+ colptr->ttype[0] = '\0'; /* null column name */
+ colptr->tscale = 1.;
+ colptr->tzero = 0.;
+ colptr->strnull[0] = ASCII_NULL_UNDEFINED; /* null value undefined */
+ colptr->tbcol = -1; /* initialize to illegal value */
+ colptr->tdatatype = -9999; /* initialize to illegal value */
+ }
+
+ /*
+ Initialize the fictitious heap starting address (immediately following
+ the table data) and a zero length heap. This is used to find the
+ end of the table data when checking the fill values in the last block.
+ There is no special data following an ASCII table.
+ */
+ (fptr->Fptr)->numrows = nrows;
+ (fptr->Fptr)->origrows = nrows;
+ (fptr->Fptr)->heapstart = (OFF_T)rowlen * nrows;
+ (fptr->Fptr)->heapsize = 0;
+
+ (fptr->Fptr)->compressimg = 0; /* this is not a compressed image */
+
+ /* now search for the table column keywords and the END keyword */
+
+ for (nspace = 0, ii = 8; 1; ii++) /* infinite loop */
+ {
+ ffgkyn(fptr, ii, name, value, comm, status);
+
+ /* try to ignore minor syntax errors */
+ if (*status == NO_QUOTE)
+ {
+ strcat(value, "'");
+ *status = 0;
+ }
+ else if (*status == BAD_KEYCHAR)
+ {
+ *status = 0;
+ }
+
+ if (*status == END_OF_FILE)
+ {
+ ffpmsg("END keyword not found in ASCII table header (ffainit).");
+ return(*status = NO_END);
+ }
+ else if (*status > 0)
+ return(*status);
+
+ else if (name[0] == 'T') /* keyword starts with 'T' ? */
+ ffgtbp(fptr, name, value, status); /* test if column keyword */
+
+ else if (!FSTRCMP(name, "END")) /* is this the END keyword? */
+ break;
+
+ if (!name[0] && !value[0] && !comm[0]) /* a blank keyword? */
+ nspace++;
+
+ else
+ nspace = 0;
+ }
+
+ /* test that all required keywords were found and have legal values */
+ colptr = (fptr->Fptr)->tableptr;
+ for (ii = 0; ii < tfield; ii++, colptr++)
+ {
+ tbcoln = colptr->tbcol; /* the starting column number (zero based) */
+
+ if (colptr->tdatatype == -9999)
+ {
+ ffkeyn("TFORM", ii+1, name, status); /* construct keyword name */
+ sprintf(message,"Required %s keyword not found (ffainit).", name);
+ ffpmsg(message);
+ return(*status = NO_TFORM);
+ }
+
+ else if (tbcoln == -1)
+ {
+ ffkeyn("TBCOL", ii+1, name, status); /* construct keyword name */
+ sprintf(message,"Required %s keyword not found (ffainit).", name);
+ ffpmsg(message);
+ return(*status = NO_TBCOL);
+ }
+
+ else if ((fptr->Fptr)->rowlength != 0 &&
+ (tbcoln < 0 || tbcoln >= (fptr->Fptr)->rowlength ) )
+ {
+ ffkeyn("TBCOL", ii+1, name, status); /* construct keyword name */
+ sprintf(message,"Value of %s keyword out of range: %d (ffainit).",
+ name, tbcoln);
+ ffpmsg(message);
+ return(*status = BAD_TBCOL);
+ }
+
+ else if ((fptr->Fptr)->rowlength != 0 &&
+ tbcoln + colptr->twidth > (fptr->Fptr)->rowlength )
+ {
+ sprintf(message,"Column %d is too wide to fit in table (ffainit)",
+ ii+1);
+ ffpmsg(message);
+ sprintf(message, " TFORM = %s and NAXIS1 = %ld",
+ colptr->tform, (long) (fptr->Fptr)->rowlength);
+ ffpmsg(message);
+ return(*status = COL_TOO_WIDE);
+ }
+ }
+
+ /*
+ now we know everything about the table; just fill in the parameters:
+ the 'END' record is 80 bytes before the current position, minus
+ any trailing blank keywords just before the END keyword.
+ */
+ (fptr->Fptr)->headend = (fptr->Fptr)->nextkey - (80 * (nspace + 1));
+
+ /* the data unit begins at the beginning of the next logical block */
+ (fptr->Fptr)->datastart = (((fptr->Fptr)->nextkey - 80) / 2880 + 1)
+ * 2880;
+
+ /* the next HDU begins in the next logical block after the data */
+ (fptr->Fptr)->headstart[ (fptr->Fptr)->curhdu + 1] =
+ (fptr->Fptr)->datastart +
+ ( ((OFF_T)rowlen * nrows + 2879) / 2880 * 2880 );
+
+ /* reset next keyword pointer to the start of the header */
+ (fptr->Fptr)->nextkey = (fptr->Fptr)->headstart[ (fptr->Fptr)->curhdu ];
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffbinit(fitsfile *fptr, /* I - FITS file pointer */
+ int *status) /* IO - error status */
+{
+/*
+ initialize the parameters defining the structure of a binary table
+*/
+ int ii, nspace;
+ long nrows, rowlen, tfield, pcount, totalwidth;
+ tcolumn *colptr = 0;
+ char name[FLEN_KEYWORD], value[FLEN_VALUE], comm[FLEN_COMMENT];
+ char message[FLEN_ERRMSG];
+
+ if (*status > 0)
+ return(*status);
+
+ /* reset position to the correct HDU if necessary */
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+
+ (fptr->Fptr)->hdutype = BINARY_TBL; /* set that this is a binary table */
+ (fptr->Fptr)->headend = (fptr->Fptr)->logfilesize; /* set max size */
+
+ /* get table parameters and test that the header is valid: */
+ if (ffgttb(fptr, &rowlen, &nrows, &pcount, &tfield, status) > 0)
+ return(*status);
+
+ (fptr->Fptr)->rowlength = (OFF_T) rowlen; /* store length of a row */
+ (fptr->Fptr)->tfield = tfield; /* store number of table fields in row */
+
+ if ((fptr->Fptr)->tableptr)
+ free((fptr->Fptr)->tableptr); /* free memory for the old CHDU */
+
+ /* mem for column structures ; space is initialized = 0 */
+ if (tfield > 0)
+ {
+ colptr = (tcolumn *) calloc(tfield, sizeof(tcolumn) );
+ if (!colptr)
+ {
+ ffpmsg
+ ("malloc failed to get memory for FITS table descriptors (ffbinit)");
+ (fptr->Fptr)->tableptr = 0; /* set a null table structure pointer */
+ return(*status = ARRAY_TOO_BIG);
+ }
+ }
+
+ /* copy the table structure address to the fitsfile structure */
+ (fptr->Fptr)->tableptr = colptr;
+
+ /* initialize the table field parameters */
+ for (ii = 0; ii < tfield; ii++, colptr++)
+ {
+ colptr->ttype[0] = '\0'; /* null column name */
+ colptr->tscale = 1.;
+ colptr->tzero = 0.;
+ colptr->tnull = NULL_UNDEFINED; /* (integer) null value undefined */
+ colptr->tdatatype = -9999; /* initialize to illegal value */
+ colptr->trepeat = 1;
+ colptr->strnull[0] = '\0'; /* for ASCII string columns (TFORM = rA) */
+ }
+
+ /*
+ Initialize the heap starting address (immediately following
+ the table data) and the size of the heap. This is used to find the
+ end of the table data when checking the fill values in the last block.
+ */
+ (fptr->Fptr)->numrows = nrows;
+ (fptr->Fptr)->origrows = nrows;
+ (fptr->Fptr)->heapstart = (OFF_T)rowlen * nrows;
+ (fptr->Fptr)->heapsize = pcount;
+
+ (fptr->Fptr)->compressimg = 0; /* initialize as not a compressed image */
+
+ /* now search for the table column keywords and the END keyword */
+
+ for (nspace = 0, ii = 8; 1; ii++) /* infinite loop */
+ {
+ ffgkyn(fptr, ii, name, value, comm, status);
+
+ /* try to ignore minor syntax errors */
+ if (*status == NO_QUOTE)
+ {
+ strcat(value, "'");
+ *status = 0;
+ }
+ else if (*status == BAD_KEYCHAR)
+ {
+ *status = 0;
+ }
+
+ if (*status == END_OF_FILE)
+ {
+ ffpmsg("END keyword not found in binary table header (ffbinit).");
+ return(*status = NO_END);
+ }
+ else if (*status > 0)
+ return(*status);
+
+ else if (name[0] == 'T') /* keyword starts with 'T' ? */
+ ffgtbp(fptr, name, value, status); /* test if column keyword */
+
+ else if (!FSTRCMP(name, "ZIMAGE"))
+ {
+ if (value[0] == 'T')
+ (fptr->Fptr)->compressimg = 1; /* this is a compressed image */
+ }
+ else if (!FSTRCMP(name, "END")) /* is this the END keyword? */
+ break;
+
+
+ if (!name[0] && !value[0] && !comm[0]) /* a blank keyword? */
+ nspace++;
+
+ else
+ nspace = 0; /* reset number of consecutive spaces before END */
+ }
+
+ /* test that all the required keywords were found and have legal values */
+ colptr = (fptr->Fptr)->tableptr; /* set pointer to first column */
+
+ for (ii = 0; ii < tfield; ii++, colptr++)
+ {
+ if (colptr->tdatatype == -9999)
+ {
+ ffkeyn("TFORM", ii+1, name, status); /* construct keyword name */
+ sprintf(message,"Required %s keyword not found (ffbinit).", name);
+ ffpmsg(message);
+ return(*status = NO_TFORM);
+ }
+ }
+
+ /*
+ now we know everything about the table; just fill in the parameters:
+ the 'END' record is 80 bytes before the current position, minus
+ any trailing blank keywords just before the END keyword.
+ */
+
+ (fptr->Fptr)->headend = (fptr->Fptr)->nextkey - (80 * (nspace + 1));
+
+ /* the data unit begins at the beginning of the next logical block */
+ (fptr->Fptr)->datastart = (((fptr->Fptr)->nextkey - 80) / 2880 + 1)
+ * 2880;
+
+ /* the next HDU begins in the next logical block after the data */
+ (fptr->Fptr)->headstart[ (fptr->Fptr)->curhdu + 1] =
+ (fptr->Fptr)->datastart +
+ ( ((OFF_T)rowlen * nrows + pcount + 2879) / 2880 * 2880 );
+
+ /* determine the byte offset to the beginning of each column */
+ ffgtbc(fptr, &totalwidth, status);
+
+ if (totalwidth != rowlen)
+ {
+ sprintf(message,
+ "NAXIS1 = %ld is not equal to the sum of column widths: %ld",
+ rowlen, totalwidth);
+ ffpmsg(message);
+ *status = BAD_ROW_WIDTH;
+ }
+
+ /* reset next keyword pointer to the start of the header */
+ (fptr->Fptr)->nextkey = (fptr->Fptr)->headstart[ (fptr->Fptr)->curhdu ];
+
+ if ( (fptr->Fptr)->compressimg == 1) /* Is this a compressed image */
+ imcomp_get_compressed_image_par(fptr, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgabc(int tfields, /* I - number of columns in the table */
+ char **tform, /* I - value of TFORMn keyword for each column */
+ int space, /* I - number of spaces to leave between cols */
+ long *rowlen, /* O - total width of a table row */
+ long *tbcol, /* O - starting byte in row for each column */
+ int *status) /* IO - error status */
+/*
+ calculate the starting byte offset of each column of an ASCII table
+ and the total length of a row, in bytes. The input space value determines
+ how many blank spaces to leave between each column (1 is recommended).
+*/
+{
+ int ii, datacode, decims;
+ long width;
+
+ if (*status > 0)
+ return(*status);
+
+ *rowlen=0;
+
+ if (tfields <= 0)
+ return(*status);
+
+ tbcol[0] = 1;
+
+ for (ii = 0; ii < tfields; ii++)
+ {
+ tbcol[ii] = *rowlen + 1; /* starting byte in row of column */
+
+ ffasfm(tform[ii], &datacode, &width, &decims, status);
+
+ *rowlen += (width + space); /* total length of row */
+ }
+
+ *rowlen -= space; /* don't add space after the last field */
+
+ return (*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgtbc(fitsfile *fptr, /* I - FITS file pointer */
+ long *totalwidth, /* O - total width of a table row */
+ int *status) /* IO - error status */
+{
+/*
+ calculate the starting byte offset of each column of a binary table.
+ Use the values of the datatype code and repeat counts in the
+ column structure. Return the total length of a row, in bytes.
+*/
+ int tfields, ii;
+ long nbytes;
+ tcolumn *colptr;
+
+ if (*status > 0)
+ return(*status);
+
+ /* reset position to the correct HDU if necessary */
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+ else if ((fptr->Fptr)->datastart == DATA_UNDEFINED)
+ if ( ffrdef(fptr, status) > 0) /* rescan header */
+ return(*status);
+
+ tfields = (fptr->Fptr)->tfield;
+ colptr = (fptr->Fptr)->tableptr; /* point to first column structure */
+
+ *totalwidth = 0;
+
+ for (ii = 0; ii < tfields; ii++, colptr++)
+ {
+ colptr->tbcol = *totalwidth; /* byte offset in row to this column */
+
+ if (colptr->tdatatype == TSTRING)
+ {
+ nbytes = (long) colptr->trepeat; /* one byte per char */
+ }
+ else if (colptr->tdatatype == TBIT)
+ {
+ nbytes = ((long) colptr->trepeat + 7) / 8;
+ }
+ else if (colptr->tdatatype > 0)
+ {
+ nbytes = (long) colptr->trepeat * (colptr->tdatatype / 10);
+ }
+ else /* this is a variable length descriptor (neg. tdatatype) */
+ nbytes = 8;
+
+ *totalwidth = *totalwidth + nbytes;
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgtbp(fitsfile *fptr, /* I - FITS file pointer */
+ char *name, /* I - name of the keyword */
+ char *value, /* I - value string of the keyword */
+ int *status) /* IO - error status */
+{
+/*
+ Get TaBle Parameter. The input keyword name begins with the letter T.
+ Test if the keyword is one of the table column definition keywords
+ of an ASCII or binary table. If so, decode it and update the value
+ in the structure.
+*/
+ int tstatus, datacode, decimals;
+ long width, repeat, nfield, ivalue;
+ double dvalue;
+ char tvalue[FLEN_VALUE];
+ char message[FLEN_ERRMSG];
+ tcolumn *colptr;
+
+ if (*status > 0)
+ return(*status);
+
+ tstatus = 0;
+
+ /* reset position to the correct HDU if necessary */
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+
+ if(!FSTRNCMP(name + 1, "TYPE", 4) )
+ {
+ /* get the index number */
+ if( ffc2ii(name + 5, &nfield, &tstatus) > 0) /* read index no. */
+ return(*status); /* must not be an indexed keyword */
+
+ if (nfield < 1 || nfield > (fptr->Fptr)->tfield ) /* out of range */
+ return(*status);
+
+ colptr = (fptr->Fptr)->tableptr; /* get pointer to columns */
+ colptr = colptr + nfield - 1; /* point to the correct column */
+
+ if (ffc2s(value, tvalue, &tstatus) > 0) /* remove quotes */
+ return(*status);
+
+ strcpy(colptr->ttype, tvalue); /* copy col name to structure */
+ }
+ else if(!FSTRNCMP(name + 1, "FORM", 4) )
+ {
+ /* get the index number */
+ if( ffc2ii(name + 5, &nfield, &tstatus) > 0) /* read index no. */
+ return(*status); /* must not be an indexed keyword */
+
+ if (nfield < 1 || nfield > (fptr->Fptr)->tfield ) /* out of range */
+ return(*status);
+
+ colptr = (fptr->Fptr)->tableptr; /* get pointer to columns */
+ colptr = colptr + nfield - 1; /* point to the correct column */
+
+ if (ffc2s(value, tvalue, &tstatus) > 0) /* remove quotes */
+ return(*status);
+
+ strncpy(colptr->tform, tvalue, 9); /* copy TFORM to structure */
+ colptr->tform[9] = '\0'; /* make sure it is terminated */
+
+ if ((fptr->Fptr)->hdutype == ASCII_TBL) /* ASCII table */
+ {
+ if (ffasfm(tvalue, &datacode, &width, &decimals, status) > 0)
+ return(*status); /* bad format code */
+
+ colptr->tdatatype = TSTRING; /* store datatype code */
+ colptr->trepeat = 1; /* field repeat count == 1 */
+ colptr->twidth = width; /* the width of the field, in bytes */
+ }
+ else /* binary table */
+ {
+ if (ffbnfm(tvalue, &datacode, &repeat, &width, status) > 0)
+ return(*status); /* bad format code */
+
+ colptr->tdatatype = datacode; /* store datatype code */
+ colptr->trepeat = (OFF_T) repeat; /* field repeat count */
+ colptr->twidth = width; /* width of a unit value in chars */
+ }
+ }
+ else if(!FSTRNCMP(name + 1, "BCOL", 4) )
+ {
+ /* get the index number */
+ if( ffc2ii(name + 5, &nfield, &tstatus) > 0) /* read index no. */
+ return(*status); /* must not be an indexed keyword */
+
+ if (nfield < 1 || nfield > (fptr->Fptr)->tfield ) /* out of range */
+ return(*status);
+
+ colptr = (fptr->Fptr)->tableptr; /* get pointer to columns */
+ colptr = colptr + nfield - 1; /* point to the correct column */
+
+ if ((fptr->Fptr)->hdutype == BINARY_TBL)
+ return(*status); /* binary tables don't have TBCOL keywords */
+
+ if (ffc2ii(value, &ivalue, status) > 0)
+ {
+ sprintf(message,
+ "Error reading value of %s as an integer: %s", name, value);
+ ffpmsg(message);
+ return(*status);
+ }
+ colptr->tbcol = ivalue - 1; /* convert to zero base */
+ }
+ else if(!FSTRNCMP(name + 1, "SCAL", 4) )
+ {
+ /* get the index number */
+ if( ffc2ii(name + 5, &nfield, &tstatus) > 0) /* read index no. */
+ return(*status); /* must not be an indexed keyword */
+
+ if (nfield < 1 || nfield > (fptr->Fptr)->tfield ) /* out of range */
+ return(*status);
+
+ colptr = (fptr->Fptr)->tableptr; /* get pointer to columns */
+ colptr = colptr + nfield - 1; /* point to the correct column */
+
+ if (ffc2dd(value, &dvalue, &tstatus) > 0)
+ {
+ sprintf(message,
+ "Error reading value of %s as a double: %s", name, value);
+ ffpmsg(message);
+
+ /* ignore this error, so don't return error status */
+ return(*status);
+ }
+ colptr->tscale = dvalue;
+ }
+ else if(!FSTRNCMP(name + 1, "ZERO", 4) )
+ {
+ /* get the index number */
+ if( ffc2ii(name + 5, &nfield, &tstatus) > 0) /* read index no. */
+ return(*status); /* must not be an indexed keyword */
+
+ if (nfield < 1 || nfield > (fptr->Fptr)->tfield ) /* out of range */
+ return(*status);
+
+ colptr = (fptr->Fptr)->tableptr; /* get pointer to columns */
+ colptr = colptr + nfield - 1; /* point to the correct column */
+
+ if (ffc2dd(value, &dvalue, &tstatus) > 0)
+ {
+ sprintf(message,
+ "Error reading value of %s as a double: %s", name, value);
+ ffpmsg(message);
+
+ /* ignore this error, so don't return error status */
+ return(*status);
+ }
+ colptr->tzero = dvalue;
+ }
+ else if(!FSTRNCMP(name + 1, "NULL", 4) )
+ {
+ /* get the index number */
+ if( ffc2ii(name + 5, &nfield, &tstatus) > 0) /* read index no. */
+ return(*status); /* must not be an indexed keyword */
+
+ if (nfield < 1 || nfield > (fptr->Fptr)->tfield ) /* out of range */
+ return(*status);
+
+ colptr = (fptr->Fptr)->tableptr; /* get pointer to columns */
+ colptr = colptr + nfield - 1; /* point to the correct column */
+
+ if ((fptr->Fptr)->hdutype == ASCII_TBL) /* ASCII table */
+ {
+ if (ffc2s(value, tvalue, &tstatus) > 0) /* remove quotes */
+ return(*status);
+
+ strncpy(colptr->strnull, tvalue, 17); /* copy TNULL string */
+ colptr->strnull[17] = '\0'; /* terminate the strnull field */
+
+ }
+ else /* binary table */
+ {
+ if (ffc2ii(value, &ivalue, &tstatus) > 0)
+ {
+ sprintf(message,
+ "Error reading value of %s as an integer: %s", name, value);
+ ffpmsg(message);
+
+ /* ignore this error, so don't return error status */
+ return(*status);
+ }
+ colptr->tnull = ivalue; /* null value for integer column */
+ }
+ }
+ else if (!FSTRNCMP(name + 1, "HEAP", 4) )
+ {
+ if ((fptr->Fptr)->hdutype == ASCII_TBL) /* ASCII table */
+ return(*status); /* ASCII tables don't have a heap */
+
+ if (ffc2ii(value, &ivalue, &tstatus) > 0)
+ {
+ sprintf(message,
+ "Error reading value of %s as an integer: %s", name, value);
+ ffpmsg(message);
+
+ /* ignore this error, so don't return error status */
+ return(*status);
+ }
+ (fptr->Fptr)->heapstart = (OFF_T)ivalue; /* starting byte of the heap */
+ return(*status);
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgcpr( fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - column number (1 = 1st column of table) */
+ long firstrow, /* I - first row (1 = 1st row of table) */
+ OFF_T firstelem, /* I - first element within vector (1 = 1st) */
+ long nelem, /* I - number of elements to read or write */
+ int writemode, /* I - = 1 if writing data, = 0 if reading data */
+ /* If = 2, then writing data, but don't modify */
+ /* the returned values of repeat and incre. */
+ /* If = -1, then reading data in reverse */
+ /* direction. */
+ double *scale, /* O - FITS scaling factor (TSCALn keyword value) */
+ double *zero, /* O - FITS scaling zero pt (TZEROn keyword value) */
+ char *tform, /* O - ASCII column format: value of TFORMn keyword */
+ long *twidth, /* O - width of ASCII column (characters) */
+ int *tcode, /* O - column datatype code: I*4=41, R*4=42, etc */
+ int *maxelem, /* O - max number of elements that fit in buffer */
+ OFF_T *startpos,/* O - offset in file to starting row & column */
+ OFF_T *elemnum, /* O - starting element number ( 0 = 1st element) */
+ long *incre, /* O - byte offset between elements within a row */
+ OFF_T *repeat, /* O - number of elements in a row (vector column) */
+ OFF_T *rowlen, /* O - length of a row, in bytes */
+ int *hdutype, /* O - HDU type: 0, 1, 2 = primary, table, bintable */
+ long *tnull, /* O - null value for integer columns */
+ char *snull, /* O - null value for ASCII table columns */
+ int *status) /* IO - error status */
+/*
+ Get Column PaRameters, and test starting row and element numbers for
+ validity. This is a workhorse routine that is call by nearly every
+ other routine that reads or writes to FITS files.
+*/
+{
+ int nulpos, rangecheck = 1, tstatus = 0;
+ OFF_T datastart, endpos;
+ long tbcol, endrow, nrows, nblock, heapoffset, lrepeat;
+ char message[81];
+ tcolumn *colptr;
+
+ /* reset position to the correct HDU if necessary */
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+
+ /* rescan header if data structure is undefined */
+ else if ((fptr->Fptr)->datastart == DATA_UNDEFINED)
+ if ( ffrdef(fptr, status) > 0)
+ return(*status);
+
+ /* Do sanity check of input parameters */
+ if (firstrow < 1)
+ {
+ if ((fptr->Fptr)->hdutype == IMAGE_HDU) /* Primary Array or IMAGE */
+ {
+ sprintf(message, "Image group number is less than 1: %ld",
+ firstrow);
+ ffpmsg(message);
+ return(*status = BAD_ROW_NUM);
+ }
+ else
+ {
+ sprintf(message, "Starting row number is less than 1: %ld",
+ firstrow);
+ ffpmsg(message);
+ return(*status = BAD_ROW_NUM);
+ }
+ }
+ else if ((fptr->Fptr)->hdutype != ASCII_TBL && firstelem < 1)
+ {
+ sprintf(message, "Starting element number less than 1: %ld",
+ (long) firstelem);
+ ffpmsg(message);
+ return(*status = BAD_ELEM_NUM);
+ }
+ else if (nelem < 0)
+ {
+ sprintf(message, "Tried to read or write less than 0 elements: %ld",
+ nelem);
+ ffpmsg(message);
+ return(*status = NEG_BYTES);
+ }
+ else if (colnum < 1 || colnum > (fptr->Fptr)->tfield)
+ {
+ sprintf(message, "Specified column number is out of range: %d",
+ colnum);
+ ffpmsg(message);
+ sprintf(message, " There are %d columns in this table.",
+ (fptr->Fptr)->tfield );
+ ffpmsg(message);
+
+ return(*status = BAD_COL_NUM);
+ }
+
+ /* copy relevant parameters from the structure */
+
+ *hdutype = (fptr->Fptr)->hdutype; /* image, ASCII table, or BINTABLE */
+ *rowlen = (fptr->Fptr)->rowlength; /* width of the table, in bytes */
+ datastart = (fptr->Fptr)->datastart; /* offset in file to start of table */
+
+ colptr = (fptr->Fptr)->tableptr; /* point to first column */
+ colptr += (colnum - 1); /* offset to correct column structure */
+
+ *scale = colptr->tscale; /* value scaling factor; default = 1.0 */
+ *zero = colptr->tzero; /* value scaling zeropoint; default = 0.0 */
+ *tnull = colptr->tnull; /* null value for integer columns */
+ tbcol = colptr->tbcol; /* offset to start of column within row */
+ *twidth = colptr->twidth; /* width of a single datum, in bytes */
+ *incre = colptr->twidth; /* increment between datums, in bytes */
+ *tcode = colptr->tdatatype;
+ *repeat = colptr->trepeat;
+
+#if (!SUPPORT_64BIT_INTEGERS)
+ if (*tcode == TLONGLONG)
+ {
+ /* experimental 64-bit integer data type */
+ sprintf(message,
+ "BITPIX=64 or TTYPE = 'K' is not supported in this version of CFITSIO");
+ ffpmsg(message);
+ return(*status = BAD_BITPIX);
+ }
+#endif
+
+ strcpy(tform, colptr->tform); /* value of TFORMn keyword */
+ strcpy(snull, colptr->strnull); /* null value for ASCII table columns */
+
+ if (*hdutype == ASCII_TBL && snull[0] == '\0')
+ {
+ /* In ASCII tables, a null value is equivalent to all spaces */
+
+ strcpy(snull, " "); /* maximum of 17 spaces */
+ nulpos = minvalue(17, *twidth); /* truncate to width of column */
+ snull[nulpos] = '\0';
+ }
+
+ /* Special case: interpret writemode = -1 as reading data, but */
+ /* don't do error check for exceeding the range of pixels */
+ if (writemode == -1)
+ {
+ writemode = 0;
+ rangecheck = 0;
+ }
+
+ /* Special case: interprete 'X' column as 'B' */
+ if (abs(*tcode) == TBIT)
+ {
+ *tcode = *tcode / TBIT * TBYTE;
+ *repeat = (*repeat + 7) / 8;
+ }
+
+ /* Special case: support the 'rAw' format in BINTABLEs */
+ if (*hdutype == BINARY_TBL && *tcode == TSTRING)
+ *repeat = *repeat / *twidth; /* repeat = # of unit strings in field */
+
+ if (*hdutype == ASCII_TBL)
+ *elemnum = 0; /* ASCII tables don't have vector elements */
+ else
+ *elemnum = firstelem - 1;
+
+ /* interprete complex and double complex as pairs of floats or doubles */
+ if (abs(*tcode) >= TCOMPLEX)
+ {
+ if (*tcode > 0)
+ *tcode = (*tcode + 1) / 2;
+ else
+ *tcode = (*tcode - 1) / 2;
+
+ *repeat = *repeat * 2;
+ *twidth = *twidth / 2;
+ *incre = *incre / 2;
+ }
+
+ /* calculate no. of pixels that fit in buffer */
+ /* allow for case where floats are 8 bytes long */
+ if (abs(*tcode) == TFLOAT)
+ *maxelem = DBUFFSIZE / sizeof(float);
+ else if (abs(*tcode) == TDOUBLE)
+ *maxelem = DBUFFSIZE / sizeof(double);
+ else if (abs(*tcode) == TSTRING)
+ {
+ *maxelem = (DBUFFSIZE - 1)/ *twidth; /* leave room for final \0 */
+ if (*maxelem == 0) {
+ sprintf(message,
+ "ASCII string column is too wide: %ld; max supported width is %d",
+ *twidth, DBUFFSIZE - 1);
+ ffpmsg(message);
+ return(*status = COL_TOO_WIDE);
+ }
+ }
+ else
+ *maxelem = DBUFFSIZE / *twidth;
+
+ /* calc starting byte position to 1st element of col */
+ /* (this does not apply to variable length columns) */
+ *startpos = datastart + ((OFF_T)(firstrow - 1) * *rowlen) + tbcol;
+
+ if (*hdutype == IMAGE_HDU && writemode) /* Primary Array or IMAGE */
+ { /*
+ For primary arrays, set the repeat count greater than the total
+ number of pixels to be written. This prevents an out-of-range
+ error message in cases where the final image array size is not
+ yet known or defined.
+ */
+ if (*repeat < *elemnum + nelem)
+ *repeat = *elemnum + nelem;
+ }
+ else if (*tcode > 0) /* Fixed length table column */
+ {
+ if (*elemnum >= *repeat)
+ {
+ sprintf(message,
+ "First element to write is too large: %ld; max allowed value is %ld",
+ (long) ((*elemnum) + 1), (long) *repeat);
+ ffpmsg(message);
+ return(*status = BAD_ELEM_NUM);
+ }
+
+ /* last row number to be read or written */
+ endrow = ((*elemnum + nelem - 1) / *repeat) + firstrow;
+
+ if (writemode)
+ {
+ /* check if we are writing beyond the current end of table */
+ if ((endrow > (fptr->Fptr)->numrows) && (nelem > 0) )
+ {
+ /* if there are more HDUs following the current one, or */
+ /* if there is a data heap, then we must insert space */
+ /* for the new rows. */
+ if ( !((fptr->Fptr)->lasthdu) || (fptr->Fptr)->heapsize > 0)
+ {
+ nrows = endrow - ((fptr->Fptr)->numrows);
+ if (ffirow(fptr, (fptr->Fptr)->numrows, nrows, status) > 0)
+ {
+ sprintf(message,
+ "Failed to add space for %ld new rows in table.",
+ nrows);
+ ffpmsg(message);
+ return(*status);
+ }
+ }
+ else
+ {
+ /* update heap starting address */
+ (fptr->Fptr)->heapstart +=
+ ((OFF_T)(endrow - (fptr->Fptr)->numrows) *
+ (fptr->Fptr)->rowlength );
+
+ (fptr->Fptr)->numrows = endrow; /* update number of rows */
+ }
+ }
+ }
+ else /* reading from the file */
+ {
+ if ( endrow > (fptr->Fptr)->numrows && rangecheck)
+ {
+ if (*hdutype == IMAGE_HDU) /* Primary Array or IMAGE */
+ {
+ if (firstrow > (fptr->Fptr)->numrows)
+ {
+ sprintf(message,
+ "Attempted to read from group %ld of the HDU,", firstrow);
+ ffpmsg(message);
+
+ sprintf(message,
+ "however the HDU only contains %ld group(s).",
+ (fptr->Fptr)->numrows );
+ ffpmsg(message);
+ }
+ else
+ {
+ ffpmsg("Attempt to read past end of array:");
+ sprintf(message,
+ " Image has %ld elements;", (long) *repeat);
+ ffpmsg(message);
+
+ sprintf(message,
+ " Tried to read %ld elements starting at element %ld.",
+ nelem, (long) firstelem);
+ ffpmsg(message);
+ }
+ }
+ else
+ {
+ ffpmsg("Attempt to read past end of table:");
+ sprintf(message,
+ " Table has %ld rows with %ld elements per row;",
+ (fptr->Fptr)->numrows, (long) *repeat);
+ ffpmsg(message);
+
+ sprintf(message,
+ " Tried to read %ld elements starting at row %ld, element %ld.",
+ nelem, firstrow, (long) ((*elemnum) + 1));
+ ffpmsg(message);
+
+ }
+ return(*status = BAD_ROW_NUM);
+ }
+ }
+
+ if (*repeat == 1 && nelem > 1 && writemode != 2)
+ { /*
+ When accessing a scalar column, fool the calling routine into
+ thinking that this is a vector column with very big elements.
+ This allows multiple values (up to the maxelem number of elements
+ that will fit in the buffer) to be read or written with a single
+ routine call, which increases the efficiency.
+
+ If writemode == 2, then the calling program does not want to
+ have this efficiency trick applied.
+ */
+ *incre = *rowlen;
+ *repeat = nelem;
+ }
+ }
+ else /* Variable length Binary Table column */
+ {
+ *tcode *= (-1);
+
+ if (writemode) /* return next empty heap address for writing */
+ {
+
+ *repeat = nelem + *elemnum; /* total no. of elements in the field */
+
+ /* first, check if we are overwriting an existing row, and */
+ /* if so, if the existing space is big enough for the new vector */
+
+ if ( firstrow <= (fptr->Fptr)->numrows )
+ {
+ ffgdes(fptr, colnum, firstrow, &lrepeat, &heapoffset, &tstatus);
+ if (!tstatus)
+ {
+ if (colptr->tdatatype <= -TCOMPLEX)
+ lrepeat = lrepeat * 2; /* no. of float or double values */
+ else if (colptr->tdatatype == -TBIT)
+ lrepeat = (lrepeat + 7) / 8; /* convert from bits to bytes */
+
+ if (lrepeat >= *repeat) /* enough existing space? */
+ {
+ *startpos = datastart + heapoffset + (fptr->Fptr)->heapstart;
+
+ /* write the descriptor into the fixed length part of table */
+ if (colptr->tdatatype <= -TCOMPLEX)
+ {
+ /* divide repeat count by 2 to get no. of complex values */
+ ffpdes(fptr, colnum, firstrow, (long) *repeat / 2,
+ heapoffset, status);
+ }
+ else
+ {
+ ffpdes(fptr, colnum, firstrow, (long) *repeat,
+ heapoffset, status);
+ }
+ return(*status);
+ }
+ }
+ }
+
+ /* Add more rows to the table, if writing beyond the end. */
+ /* It is necessary to shift the heap down in this case */
+ if ( firstrow > (fptr->Fptr)->numrows)
+ {
+ nrows = firstrow - ((fptr->Fptr)->numrows);
+ if (ffirow(fptr, (fptr->Fptr)->numrows, nrows, status) > 0)
+ {
+ sprintf(message,
+ "Failed to add space for %ld new rows in table.",
+ nrows);
+ ffpmsg(message);
+ return(*status);
+ }
+ }
+
+ /* calculate starting position (for writing new data) in the heap */
+ *startpos = datastart + (fptr->Fptr)->heapstart +
+ (fptr->Fptr)->heapsize;
+
+ /* write the descriptor into the fixed length part of table */
+ if (colptr->tdatatype <= -TCOMPLEX)
+ {
+ /* divide repeat count by 2 to get no. of complex values */
+ ffpdes(fptr, colnum, firstrow, (long) *repeat / 2,
+ (fptr->Fptr)->heapsize, status);
+ }
+ else
+ {
+ ffpdes(fptr, colnum, firstrow, (long) *repeat, (fptr->Fptr)->heapsize,
+ status);
+ }
+
+ /* If this is not the last HDU in the file, then check if */
+ /* extending the heap would overwrite the following header. */
+ /* If so, then have to insert more blocks. */
+ if ( !((fptr->Fptr)->lasthdu) )
+ {
+ endpos = datastart + (fptr->Fptr)->heapstart +
+ (fptr->Fptr)->heapsize + ((long) *repeat * (*incre));
+
+ if (endpos > (fptr->Fptr)->headstart[ (fptr->Fptr)->curhdu + 1])
+ {
+ /* calc the number of blocks that need to be added */
+ nblock = ((endpos - 1 -
+ (fptr->Fptr)->headstart[ (fptr->Fptr)->curhdu + 1] )
+ / 2880) + 1;
+
+ if (ffiblk(fptr, nblock, 1, status) > 0) /* insert blocks */
+ {
+ sprintf(message,
+ "Failed to extend the size of the variable length heap by %ld blocks.",
+ nblock);
+ ffpmsg(message);
+ return(*status);
+ }
+ }
+ }
+
+ /* increment the address to the next empty heap position */
+ (fptr->Fptr)->heapsize += ((long) *repeat * (*incre));
+ }
+ else /* get the read start position in the heap */
+ {
+ if ( firstrow > (fptr->Fptr)->numrows)
+ {
+ ffpmsg("Attempt to read past end of table");
+ sprintf(message,
+ " Table has %ld rows and tried to read row %ld.",
+ (fptr->Fptr)->numrows, firstrow);
+ ffpmsg(message);
+ return(*status = BAD_ROW_NUM);
+ }
+
+ ffgdes(fptr, colnum, firstrow, &lrepeat, &heapoffset, status);
+ *repeat = (OFF_T) lrepeat;
+
+ if (colptr->tdatatype <= -TCOMPLEX)
+ *repeat = *repeat * 2; /* no. of float or double values */
+ else if (colptr->tdatatype == -TBIT)
+ *repeat = (*repeat + 7) / 8; /* convert from bits to bytes */
+
+ if (*elemnum >= *repeat)
+ {
+ sprintf(message,
+ "Starting element to read in variable length column is too large: %ld",
+ (long) firstelem);
+ ffpmsg(message);
+ sprintf(message,
+ " This row only contains %ld elements", (long) *repeat);
+ ffpmsg(message);
+ return(*status = BAD_ELEM_NUM);
+ }
+
+ *startpos = datastart + heapoffset + (fptr->Fptr)->heapstart;
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fftheap(fitsfile *fptr, /* I - FITS file pointer */
+ long *heapsz, /* O - current size of the heap */
+ long *unused, /* O - no. of unused bytes in the heap */
+ long *overlap, /* O - no. of bytes shared by > 1 descriptors */
+ int *valid, /* O - are all the heap addresses valid? */
+ int *status) /* IO - error status */
+/*
+ Tests the contents of the binary table variable length array heap.
+ Returns the number of bytes that are currently not pointed to by any
+ of the descriptors, and also the number of bytes that are pointed to
+ by more than one descriptor. It returns valid = FALSE if any of the
+ descriptors point to addresses that are out of the bounds of the
+ heap.
+*/
+{
+ int jj, typecode, pixsize;
+ long ii, kk, repeat, offset, nbytes, theapsz, tunused = 0, toverlap = 0;
+ char *buffer, message[81];
+
+ if (*status > 0)
+ return(*status);
+
+ /* reset position to the correct HDU if necessary */
+ if ( fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+
+ /* rescan header to make sure everything is up to date */
+ else if ( ffrdef(fptr, status) > 0)
+ return(*status);
+
+ if (valid) *valid = TRUE;
+ if (heapsz) *heapsz = (fptr->Fptr)->heapsize;
+ if (unused) *unused = 0;
+ if (overlap) *overlap = 0;
+
+ /* return if this is not a binary table HDU or if the heap is empty */
+ if ( (fptr->Fptr)->hdutype != BINARY_TBL || (fptr->Fptr)->heapsize == 0 )
+ return(*status);
+
+ theapsz = (fptr->Fptr)->heapsize;
+ buffer = calloc(1, theapsz); /* allocate temp space */
+ if (!buffer)
+ {
+ sprintf(message,"Failed to allocate buffer to test the heap");
+ ffpmsg(message);
+ return(*status = MEMORY_ALLOCATION);
+ }
+
+ /* loop over all cols */
+ for (jj = 1; jj <= (fptr->Fptr)->tfield && *status <= 0; jj++)
+ {
+ ffgtcl(fptr, jj, &typecode, NULL, NULL, status);
+ if (typecode > 0)
+ continue; /* ignore fixed length columns */
+
+ pixsize = -typecode / 10;
+
+ /* copy heap data, row by row */
+ for (ii = 1; ii <= (fptr->Fptr)->numrows; ii++)
+ {
+ ffgdes(fptr, jj, ii, &repeat, &offset, status);
+ if (typecode == -TBIT)
+ nbytes = (repeat + 7) / 8;
+ else
+ nbytes = repeat * pixsize;
+
+ if (offset < 0 || offset + nbytes > theapsz)
+ {
+ if (valid) *valid = FALSE; /* address out of bounds */
+ sprintf(message,
+ "Descriptor in row %ld, column %d has invalid heap address",
+ ii, jj);
+ ffpmsg(message);
+ }
+ else
+ {
+ for (kk = 0; kk < nbytes; kk++)
+ buffer[kk + offset]++; /* increment every used byte */
+ }
+ }
+ }
+
+ for (kk = 0; kk < theapsz; kk++)
+ {
+ if (buffer[kk] == 0)
+ tunused++;
+ else if (buffer[kk] > 1)
+ toverlap++;
+ }
+
+ if (heapsz) *heapsz = theapsz;
+ if (unused) *unused = tunused;
+ if (overlap) *overlap = toverlap;
+
+ free(buffer);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffcmph(fitsfile *fptr, /* I -FITS file pointer */
+ int *status) /* IO - error status */
+/*
+ compress the binary table heap by reordering the contents heap and
+ recovering any unused space
+*/
+{
+ fitsfile *tptr;
+ int jj, typecode, pixsize, valid;
+ long ii, repeat, offset, buffsize = 10000, nblock, pcount, nbytes;
+ long unused, overlap;
+ char *buffer, *tbuff = 0, comm[FLEN_COMMENT], valstring[FLEN_CARD];
+ char message[81], card[FLEN_CARD];
+ OFF_T readheapstart, writeheapstart, endpos, t1heapsize, t2heapsize;
+
+ if (*status > 0)
+ return(*status);
+
+ /* get information about the current heap */
+ fftheap(fptr, NULL, &unused, &overlap, &valid, status);
+
+ if (!valid)
+ return(*status = BAD_HEAP_PTR); /* bad heap pointers */
+
+ /* return if this is not a binary table HDU or if the heap is OK as is */
+ if ( (fptr->Fptr)->hdutype != BINARY_TBL || (fptr->Fptr)->heapsize == 0 ||
+ (unused == 0 && overlap == 0) || *status > 0 )
+ return(*status);
+
+ /* copy the current HDU to a temporary file in memory */
+ if (ffinit( &tptr, "mem://tempheapfile", status) )
+ {
+ sprintf(message,"Failed to create temporary file for the heap");
+ ffpmsg(message);
+ return(*status);
+ }
+ if ( ffcopy(fptr, tptr, 0, status) )
+ {
+ sprintf(message,"Failed to create copy of the heap");
+ ffpmsg(message);
+ ffclos(tptr, status);
+ return(*status);
+ }
+
+ buffer = malloc(buffsize); /* allocate initial buffer */
+ if (!buffer)
+ {
+ sprintf(message,"Failed to allocate buffer to copy the heap");
+ ffpmsg(message);
+ ffclos(tptr, status);
+ return(*status = MEMORY_ALLOCATION);
+ }
+
+ readheapstart = (tptr->Fptr)->datastart + (tptr->Fptr)->heapstart;
+ writeheapstart = (fptr->Fptr)->datastart + (fptr->Fptr)->heapstart;
+
+ t1heapsize = (fptr->Fptr)->heapsize; /* save original heap size */
+ (fptr->Fptr)->heapsize = 0; /* reset heap to zero */
+
+ /* loop over all cols */
+ for (jj = 1; jj <= (fptr->Fptr)->tfield && *status <= 0; jj++)
+ {
+ ffgtcl(tptr, jj, &typecode, NULL, NULL, status);
+ if (typecode > 0)
+ continue; /* ignore fixed length columns */
+
+ pixsize = -typecode / 10;
+
+ /* copy heap data, row by row */
+ for (ii = 1; ii <= (fptr->Fptr)->numrows; ii++)
+ {
+ ffgdes(tptr, jj, ii, &repeat, &offset, status);
+ if (typecode == -TBIT)
+ nbytes = (repeat + 7) / 8;
+ else
+ nbytes = repeat * pixsize;
+
+ /* increase size of buffer if necessary to read whole array */
+ if (nbytes > buffsize)
+ {
+ tbuff = realloc(buffer, nbytes);
+
+ if (tbuff)
+ {
+ buffer = tbuff;
+ buffsize = nbytes;
+ }
+ else
+ *status = MEMORY_ALLOCATION;
+ }
+
+ /* If this is not the last HDU in the file, then check if */
+ /* extending the heap would overwrite the following header. */
+ /* If so, then have to insert more blocks. */
+ if ( !((fptr->Fptr)->lasthdu) )
+ {
+ endpos = writeheapstart + (fptr->Fptr)->heapsize + nbytes;
+
+ if (endpos > (fptr->Fptr)->headstart[ (fptr->Fptr)->curhdu + 1])
+ {
+ /* calc the number of blocks that need to be added */
+ nblock = ((endpos - 1 -
+ (fptr->Fptr)->headstart[ (fptr->Fptr)->curhdu + 1] )
+ / 2880) + 1;
+
+ if (ffiblk(fptr, nblock, 1, status) > 0) /* insert blocks */
+ {
+ sprintf(message,
+ "Failed to extend the size of the variable length heap by %ld blocks.",
+ nblock);
+ ffpmsg(message);
+ }
+ }
+ }
+
+ /* read arrray of bytes from temporary copy */
+ ffmbyt(tptr, readheapstart + offset, REPORT_EOF, status);
+ ffgbyt(tptr, nbytes, buffer, status);
+
+ /* write arrray of bytes back to original file */
+ ffmbyt(fptr, writeheapstart + (fptr->Fptr)->heapsize,
+ IGNORE_EOF, status);
+ ffpbyt(fptr, nbytes, buffer, status);
+
+ /* write descriptor */
+ ffpdes(fptr, jj, ii, repeat,
+ (fptr->Fptr)->heapsize, status);
+
+ (fptr->Fptr)->heapsize += nbytes; /* update heapsize */
+
+ if (*status > 0)
+ {
+ free(buffer);
+ ffclos(tptr, status);
+ return(*status);
+ }
+ }
+ }
+
+ free(buffer);
+ ffclos(tptr, status);
+
+ /* delete any empty blocks at the end of the HDU */
+ nblock = ( (fptr->Fptr)->headstart[ (fptr->Fptr)->curhdu + 1] -
+ (writeheapstart + (fptr->Fptr)->heapsize) ) / 2880;
+
+ if (nblock > 0)
+ {
+ t2heapsize = (fptr->Fptr)->heapsize; /* save new heap size */
+ (fptr->Fptr)->heapsize = t1heapsize; /* restore original heap size */
+
+ ffdblk(fptr, nblock, status);
+ (fptr->Fptr)->heapsize = t2heapsize; /* reset correct heap size */
+ }
+
+ /* update the PCOUNT value (size of heap) */
+ ffgkyj(fptr, "PCOUNT", &pcount, comm, status);
+ if ((fptr->Fptr)->heapsize != pcount)
+ {
+ sprintf(valstring, "%ld", (fptr->Fptr)->heapsize);
+ ffmkky("PCOUNT", valstring, comm, card, status);
+ ffmkey(fptr, card, status);
+ }
+ ffrdef(fptr, status); /* rescan new HDU structure */
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgdes(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - column number (1 = 1st column of table) */
+ long rownum, /* I - row number (1 = 1st row of table) */
+ long *length, /* O - number of elements in the row */
+ long *heapaddr, /* O - heap pointer to the data */
+ int *status) /* IO - error status */
+/*
+ get (read) the variable length vector descriptor from the table.
+*/
+{
+ OFF_T bytepos;
+ INT32BIT descript[2] = {0,0};
+ tcolumn *colptr;
+
+ /* reset position to the correct HDU if necessary */
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+ else if ((fptr->Fptr)->datastart == DATA_UNDEFINED)
+ if ( ffrdef(fptr, status) > 0) /* rescan header */
+ return(*status);
+
+ colptr = (fptr->Fptr)->tableptr; /* point to first column structure */
+ colptr += (colnum - 1); /* offset to the correct column */
+
+ if (colptr->tdatatype >= 0)
+ *status = NOT_VARI_LEN;
+
+ else
+ {
+ bytepos = (fptr->Fptr)->datastart +
+ ((fptr->Fptr)->rowlength * (rownum - 1)) +
+ colptr->tbcol;
+
+ /* read descriptor */
+ if (ffgi4b(fptr, bytepos, 2, 4, descript, status) <= 0)
+ {
+ if (length)
+ *length = (long) descript[0]; /* 1st word is the length */
+ if (heapaddr)
+ *heapaddr = (long) descript[1]; /* 2nd word is the address */
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgdess(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - column number (1 = 1st column of table) */
+ long firstrow, /* I - first row (1 = 1st row of table) */
+ long nrows, /* I - number or rows to read */
+ long *length, /* O - number of elements in the row */
+ long *heapaddr, /* O - heap pointer to the data */
+ int *status) /* IO - error status */
+/*
+ get (read) a range of variable length vector descriptors from the table.
+*/
+{
+ OFF_T rowsize, bytepos;
+ long ii;
+ INT32BIT descript[2];
+ tcolumn *colptr;
+
+ /* reset position to the correct HDU if necessary */
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+ else if ((fptr->Fptr)->datastart == DATA_UNDEFINED)
+ if ( ffrdef(fptr, status) > 0) /* rescan header */
+ return(*status);
+
+ colptr = (fptr->Fptr)->tableptr; /* point to first column structure */
+ colptr += (colnum - 1); /* offset to the correct column */
+
+ if (colptr->tdatatype >= 0)
+ *status = NOT_VARI_LEN;
+
+ else
+ {
+ rowsize = (fptr->Fptr)->rowlength;
+ bytepos = (fptr->Fptr)->datastart +
+ (rowsize * (firstrow - 1)) +
+ colptr->tbcol;
+
+ for (ii = 0; ii < nrows; ii++)
+ {
+ ffgi4b(fptr, bytepos, 2, 4, descript, status); /* read descriptor */
+
+ *length = (long) descript[0]; /* 1st word is the length */
+ *heapaddr = (long) descript[1]; /* 2nd word is the address */
+
+ length++;
+ heapaddr++;
+ bytepos += rowsize;
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpdes(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - column number (1 = 1st column of table) */
+ long rownum, /* I - row number (1 = 1st row of table) */
+ long length, /* I - number of elements in the row */
+ long heapaddr, /* I - heap pointer to the data */
+ int *status) /* IO - error status */
+/*
+ put (write) the variable length vector descriptor to the table.
+*/
+{
+ OFF_T bytepos;
+ INT32BIT descript[2];
+ tcolumn *colptr;
+
+ if (*status > 0)
+ return(*status);
+
+ /* reset position to the correct HDU if necessary */
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+ else if ((fptr->Fptr)->datastart == DATA_UNDEFINED)
+ if ( ffrdef(fptr, status) > 0) /* rescan header */
+ return(*status);
+
+ colptr = (fptr->Fptr)->tableptr; /* point to first column structure */
+ colptr += (colnum - 1); /* offset to the correct column */
+
+ if (colptr->tdatatype >= 0)
+ *status = NOT_VARI_LEN;
+
+ else
+ {
+ bytepos = (fptr->Fptr)->datastart +
+ ((fptr->Fptr)->rowlength * (rownum - 1)) +
+ colptr->tbcol;
+
+ ffmbyt(fptr, bytepos, IGNORE_EOF, status); /* move to element */
+
+ descript[0] = (INT32BIT) length; /* 1st word is the length */
+ descript[1] = (INT32BIT) heapaddr; /* 2nd word is the address */
+
+ ffpi4b(fptr, 2, 4, descript, status); /* write the descriptor */
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffchdu(fitsfile *fptr, /* I - FITS file pointer */
+ int *status) /* IO - error status */
+{
+/*
+ close the current HDU. If we have write access to the file, then:
+ - write the END keyword and pad header with blanks if necessary
+ - check the data fill values, and rewrite them if not correct
+*/
+ char message[FLEN_ERRMSG];
+
+ /* reset position to the correct HDU if necessary */
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ {
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+ /* no need to do any further updating of the HDU */
+ }
+ else if ((fptr->Fptr)->writemode == 1)
+ {
+ ffrdef(fptr, status); /* scan header to redefine structure */
+ if ((fptr->Fptr)->heapsize > 0)
+ ffuptf(fptr, status); /* update the variable length TFORM values */
+ ffpdfl(fptr, status); /* insure correct data file values */
+ }
+
+ if ((fptr->Fptr)->open_count == 1)
+ {
+ /* free memory for the CHDU structure only if no other files are using it */
+ if ((fptr->Fptr)->tableptr)
+ {
+ free((fptr->Fptr)->tableptr);
+ (fptr->Fptr)->tableptr = NULL;
+ }
+ }
+
+ if (*status > 0 && *status != NO_CLOSE_ERROR)
+ {
+ sprintf(message,
+ "Error while closing HDU number %d (ffchdu).", (fptr->Fptr)->curhdu);
+ ffpmsg(message);
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffuptf(fitsfile *fptr, /* I - FITS file pointer */
+ int *status) /* IO - error status */
+/*
+ Update the value of the TFORM keywords for the variable length array
+ columns to make sure they all have the form 1Px(len) or Px(len) where
+ 'len' is the maximum length of the vector in the table (e.g., '1PE(400)')
+*/
+{
+ int ii;
+ long tflds, naxis2, maxlen, jj, length, addr;
+ char comment[FLEN_COMMENT], keyname[FLEN_KEYWORD];
+ char tform[FLEN_VALUE], newform[FLEN_VALUE], lenval[40];
+ char card[FLEN_CARD];
+ char message[FLEN_ERRMSG];
+
+ ffgkyj(fptr, "TFIELDS", &tflds, comment, status);
+ ffgkyj(fptr, "NAXIS2", &naxis2, comment, status);
+
+ for (ii = 1; ii <= tflds; ii++) /* loop over all the columns */
+ {
+ ffkeyn("TFORM", ii, keyname, status); /* construct name */
+ if (ffgkys(fptr, keyname, tform, comment, status) > 0)
+ {
+ sprintf(message,
+ "Error while updating variable length vector TFORMn values (ffuptf).");
+ ffpmsg(message);
+ return(*status);
+ }
+ /* is this a variable array length column ? */
+ if (tform[0] == 'P' || tform[1] == 'P')
+ {
+ if (strlen(tform) < 5) /* is maxlen field missing? */
+ {
+ /* get the max length */
+ maxlen = 0;
+ for (jj=1; jj <= naxis2; jj++)
+ {
+ ffgdes(fptr, ii, jj, &length, &addr, status);
+ maxlen = maxvalue(maxlen, length);
+ }
+
+ /* construct the new keyword value */
+ strcpy(newform, "'");
+ strcat(newform, tform);
+ sprintf(lenval, "(%ld)", maxlen);
+ strcat(newform,lenval);
+ while(strlen(newform) < 9)
+ strcat(newform," "); /* append spaces 'till length = 8 */
+ strcat(newform,"'" ); /* append closing parenthesis */
+ /* would be simpler to just call ffmkyj here, but this */
+ /* would force linking in all the modkey & putkey routines */
+ ffmkky(keyname, newform, comment, card, status); /* make new card */
+ ffmkey(fptr, card, status); /* replace last read keyword */
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffrdef(fitsfile *fptr, /* I - FITS file pointer */
+ int *status) /* IO - error status */
+/*
+ ReDEFine the structure of a data unit. This routine re-reads
+ the CHDU header keywords to determine the structure and length of the
+ current data unit. This redefines the start of the next HDU.
+*/
+{
+ int dummy, tstatus = 0;
+ long naxis2, pcount;
+ char card[FLEN_CARD], comm[FLEN_COMMENT], valstring[FLEN_VALUE];
+
+ if (*status > 0)
+ return(*status);
+
+ /* reset position to the correct HDU if necessary */
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ {
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+ }
+ else if ((fptr->Fptr)->writemode == 1) /* write access to the file? */
+ {
+ /* don't need to check NAXIS2 and PCOUNT if data hasn't been written */
+ if ((fptr->Fptr)->datastart != DATA_UNDEFINED)
+ {
+ /* update NAXIS2 keyword if more rows were written to the table */
+ /* and if the user has not explicitly reset the NAXIS2 value */
+ if ((fptr->Fptr)->hdutype != IMAGE_HDU)
+ {
+ if (ffgkyj(fptr, "NAXIS2", &naxis2, comm, &tstatus) > 0)
+ {
+ /* Couldn't read NAXIS2 (odd!); in certain circumstances */
+ /* this may be normal, so ignore the error. */
+ naxis2 = (fptr->Fptr)->numrows;
+ }
+
+ if ((fptr->Fptr)->numrows > naxis2
+ && (fptr->Fptr)->origrows == naxis2)
+ /* if origrows is not equal to naxis2, then the user must */
+ /* have manually modified the NAXIS2 keyword value, and */
+ /* we will assume that the current value is correct. */
+ {
+ /* would be simpler to just call ffmkyj here, but this */
+ /* would force linking in all the modkey & putkey routines */
+ sprintf(valstring, "%ld", (fptr->Fptr)->numrows);
+ ffmkky("NAXIS2", valstring, comm, card, status);
+ ffmkey(fptr, card, status);
+ }
+ }
+
+ /* if data has been written to variable length columns in a */
+ /* binary table, then we may need to update the PCOUNT value */
+ if ((fptr->Fptr)->heapsize > 0)
+ {
+ ffgkyj(fptr, "PCOUNT", &pcount, comm, status);
+ if ((fptr->Fptr)->heapsize > pcount)
+ {
+ /* would be simpler to just call ffmkyj here, but this */
+ /* would force linking in all the modkey & putkey routines */
+ sprintf(valstring, "%ld", (fptr->Fptr)->heapsize);
+ ffmkky("PCOUNT", valstring, comm, card, status);
+ ffmkey(fptr, card, status);
+ }
+ }
+ }
+
+ if (ffwend(fptr, status) <= 0) /* rewrite END keyword and fill */
+ {
+ ffrhdu(fptr, &dummy, status); /* re-scan the header keywords */
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffhdef(fitsfile *fptr, /* I - FITS file pointer */
+ int morekeys, /* I - reserve space for this many keywords */
+ int *status) /* IO - error status */
+/*
+ based on the number of keywords which have already been written,
+ plus the number of keywords to reserve space for, we then can
+ define where the data unit should start (it must start at the
+ beginning of a 2880-byte logical block).
+
+ This routine will only have any effect if the starting location of the
+ data unit following the header is not already defined. In any case,
+ it is always possible to add more keywords to the header even if the
+ data has already been written. It is just more efficient to reserve
+ the space in advance.
+*/
+{
+ OFF_T delta;
+
+ if (*status > 0 || morekeys < 1)
+ return(*status);
+
+ /* reset position to the correct HDU if necessary */
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ {
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+ }
+ else if ((fptr->Fptr)->datastart == DATA_UNDEFINED)
+ {
+ ffrdef(fptr, status);
+
+ /* ffrdef defines the offset to datastart and the start of */
+ /* the next HDU based on the number of existing keywords. */
+ /* We need to increment both of these values based on */
+ /* the number of new keywords to be added. */
+
+ delta = (((fptr->Fptr)->headend + (morekeys * 80)) / 2880 + 1)
+ * 2880 - (fptr->Fptr)->datastart;
+
+ (fptr->Fptr)->datastart += delta;
+
+ (fptr->Fptr)->headstart[ (fptr->Fptr)->curhdu + 1] += delta;
+
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffwend(fitsfile *fptr, /* I - FITS file pointer */
+ int *status) /* IO - error status */
+/*
+ write the END card and following fill (space chars) in the current header
+*/
+{
+ int ii, tstatus;
+ OFF_T endpos;
+ long nspace;
+ char blankkey[FLEN_CARD], endkey[FLEN_CARD], keyrec[FLEN_CARD];
+
+ if (*status > 0)
+ return(*status);
+
+ endpos = (fptr->Fptr)->headend;
+
+ /* we assume that the HDUposition == curhdu in all cases */
+
+ /* calc the data starting position if not currently defined */
+ if ((fptr->Fptr)->datastart == DATA_UNDEFINED)
+ (fptr->Fptr)->datastart = ( endpos / 2880 + 1 ) * 2880;
+
+ /* calculate the number of blank keyword slots in the header */
+ nspace = ( (fptr->Fptr)->datastart - endpos ) / 80;
+
+ /* construct a blank and END keyword (80 spaces ) */
+ strcpy(blankkey, " ");
+ strcat(blankkey, " ");
+ strcpy(endkey, "END ");
+ strcat(endkey, " ");
+
+ /* check if header is already correctly terminated with END and fill */
+ tstatus=0;
+ ffmbyt(fptr, endpos, REPORT_EOF, &tstatus); /* move to header end */
+ for (ii=0; ii < nspace; ii++)
+ {
+ ffgbyt(fptr, 80, keyrec, &tstatus); /* get next keyword */
+ if (strncmp(keyrec, blankkey, 80) && strncmp(keyrec, endkey, 80))
+ break;
+ }
+
+ if (ii == nspace && !tstatus)
+ {
+ /* check if the END keyword exists at the correct position */
+ endpos=maxvalue( endpos, ( (fptr->Fptr)->datastart - 2880 ) );
+ ffmbyt(fptr, endpos, REPORT_EOF, &tstatus); /* move to END position */
+ ffgbyt(fptr, 80, keyrec, &tstatus); /* read the END keyword */
+ if ( !strncmp(keyrec, endkey, 80) && !tstatus)
+ return(*status); /* END card was already correct */
+ }
+
+ /* header was not correctly terminated, so write the END and blank fill */
+ endpos = (fptr->Fptr)->headend;
+ ffmbyt(fptr, endpos, IGNORE_EOF, status); /* move to header end */
+ for (ii=0; ii < nspace; ii++)
+ ffpbyt(fptr, 80, blankkey, status); /* write the blank keywords */
+
+ /*
+ The END keyword must either be placed immediately after the last
+ keyword that was written (as indicated by the headend value), or
+ must be in the first 80 bytes of the 2880-byte FITS record immediately
+ preceeding the data unit, whichever is further in the file. The
+ latter will occur if space has been reserved for more header keywords
+ which have not yet been written.
+ */
+
+ endpos=maxvalue( endpos, ( (fptr->Fptr)->datastart - 2880 ) );
+ ffmbyt(fptr, endpos, REPORT_EOF, status); /* move to END position */
+
+ ffpbyt(fptr, 80, endkey, status); /* write the END keyword to header */
+
+ if (*status > 0)
+ ffpmsg("Error while writing END card (ffwend).");
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpdfl(fitsfile *fptr, /* I - FITS file pointer */
+ int *status) /* IO - error status */
+/*
+ Write the Data Unit Fill values if they are not already correct.
+ The fill values are used to fill out the last 2880 byte block of the HDU.
+ Fill the data unit with zeros or blanks depending on the type of HDU
+ from the end of the data to the end of the current FITS 2880 byte block
+*/
+{
+ char chfill, fill[2880];
+ OFF_T fillstart;
+ int nfill, tstatus, ii;
+
+ if (*status > 0)
+ return(*status);
+
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ return(*status); /* fill has already been correctly written */
+
+ if ((fptr->Fptr)->heapstart == 0)
+ return(*status); /* null data unit, so there is no fill */
+
+ fillstart = (fptr->Fptr)->datastart + (fptr->Fptr)->heapstart +
+ (fptr->Fptr)->heapsize;
+
+ nfill = (fillstart + 2879) / 2880 * 2880 - fillstart;
+
+ if ((fptr->Fptr)->hdutype == ASCII_TBL)
+ chfill = 32; /* ASCII tables are filled with spaces */
+ else
+ chfill = 0; /* all other extensions are filled with zeros */
+
+ tstatus = 0;
+
+ if (!nfill) /* no fill bytes; just check that entire table exists */
+ {
+ fillstart--;
+ nfill = 1;
+ ffmbyt(fptr, fillstart, REPORT_EOF, &tstatus); /* move to last byte */
+ ffgbyt(fptr, nfill, fill, &tstatus); /* get the last byte */
+
+ if (tstatus == 0)
+ return(*status); /* no EOF error, so everything is OK */
+ }
+ else
+ {
+ ffmbyt(fptr, fillstart, REPORT_EOF, &tstatus); /* move to fill area */
+ ffgbyt(fptr, nfill, fill, &tstatus); /* get the fill bytes */
+
+ if (tstatus == 0)
+ {
+ for (ii = 0; ii < nfill; ii++)
+ {
+ if (fill[ii] != chfill)
+ break;
+ }
+
+ if (ii == nfill)
+ return(*status); /* all the fill values were correct */
+ }
+ }
+
+ /* fill values are incorrect or have not been written, so write them */
+
+ memset(fill, chfill, nfill); /* fill the buffer with the fill value */
+
+ ffmbyt(fptr, fillstart, IGNORE_EOF, status); /* move to fill area */
+ ffpbyt(fptr, nfill, fill, status); /* write the fill bytes */
+
+ if (*status > 0)
+ ffpmsg("Error writing Data Unit fill bytes (ffpdfl).");
+
+ return(*status);
+}
+/**********************************************************************
+ ffchfl : Check Header Fill values
+
+ Check that the header unit is correctly filled with blanks from
+ the END card to the end of the current FITS 2880-byte block
+
+ Function parameters:
+ fptr Fits file pointer
+ status output error status
+
+ Translated ftchfl into C by Peter Wilson, Oct. 1997
+**********************************************************************/
+int ffchfl( fitsfile *fptr, int *status)
+{
+ int nblank,i,gotend;
+ OFF_T endpos;
+ char rec[FLEN_CARD];
+ char *blanks=" "; /* 80 spaces */
+
+ if( *status > 0 ) return (*status);
+
+ /* reset position to the correct HDU if necessary */
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+
+ /* calculate the number of blank keyword slots in the header */
+
+ endpos=(fptr->Fptr)->headend;
+ nblank=((fptr->Fptr)->datastart-endpos)/80;
+
+ /* move the i/o pointer to the end of the header keywords */
+
+ ffmbyt(fptr,endpos,TRUE,status);
+
+ /* find the END card (there may be blank keywords perceeding it) */
+
+ gotend=FALSE;
+ for(i=0;i<nblank;i++) {
+ ffgbyt(fptr,80,rec,status);
+ if( !strncmp(rec, "END ", 8) ) {
+ if( gotend ) {
+ /* There is a duplicate END record */
+ *status=BAD_HEADER_FILL;
+ ffpmsg("Warning: Header fill area contains duplicate END card:");
+ }
+ gotend=TRUE;
+ if( strncmp( rec+8, blanks+8, 72) ) {
+ /* END keyword has extra characters */
+ *status=END_JUNK;
+ ffpmsg(
+ "Warning: END keyword contains extraneous non-blank characters:");
+ }
+ } else if( gotend ) {
+ if( strncmp( rec, blanks, 80 ) ) {
+ /* The fill area contains extraneous characters */
+ *status=BAD_HEADER_FILL;
+ ffpmsg(
+ "Warning: Header fill area contains extraneous non-blank characters:");
+ }
+ }
+
+ if( *status > 0 ) {
+ rec[FLEN_CARD - 1] = '\0'; /* make sure string is null terminated */
+ ffpmsg(rec);
+ return( *status );
+ }
+ }
+ return( *status );
+}
+
+/**********************************************************************
+ ffcdfl : Check Data Unit Fill values
+
+ Check that the data unit is correctly filled with zeros or
+ blanks from the end of the data to the end of the current
+ FITS 2880 byte block
+
+ Function parameters:
+ fptr Fits file pointer
+ status output error status
+
+ Translated ftcdfl into C by Peter Wilson, Oct. 1997
+**********************************************************************/
+int ffcdfl( fitsfile *fptr, int *status)
+{
+ int nfill,i;
+ OFF_T filpos;
+ char chfill,chbuff[2880];
+
+ if( *status > 0 ) return( *status );
+
+ /* reset position to the correct HDU if necessary */
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+
+ /* check if the data unit is null */
+ if( (fptr->Fptr)->heapstart==0 ) return( *status );
+
+ /* calculate starting position of the fill bytes, if any */
+ filpos = (fptr->Fptr)->datastart
+ + (fptr->Fptr)->heapstart
+ + (fptr->Fptr)->heapsize;
+
+ /* calculate the number of fill bytes */
+ nfill = (filpos + 2879) / 2880 * 2880 - filpos;
+ if( nfill == 0 ) return( *status );
+
+ /* move to the beginning of the fill bytes */
+ ffmbyt(fptr, filpos, FALSE, status);
+
+ if( ffgbyt(fptr, nfill, chbuff, status) > 0)
+ {
+ ffpmsg("Error reading data unit fill bytes (ffcdfl).");
+ return( *status );
+ }
+
+ if( (fptr->Fptr)->hdutype==ASCII_TBL )
+ chfill = 32; /* ASCII tables are filled with spaces */
+ else
+ chfill = 0; /* all other extensions are filled with zeros */
+
+ /* check for all zeros or blanks */
+
+ for(i=0;i<nfill;i++) {
+ if( chbuff[i] != chfill ) {
+ *status=BAD_DATA_FILL;
+ if( (fptr->Fptr)->hdutype==ASCII_TBL )
+ ffpmsg("Warning: remaining bytes following ASCII table data are not filled with blanks.");
+ else
+ ffpmsg("Warning: remaining bytes following data are not filled with zeros.");
+ return( *status );
+ }
+ }
+ return( *status );
+}
+/*--------------------------------------------------------------------------*/
+int ffcrhd(fitsfile *fptr, /* I - FITS file pointer */
+ int *status) /* IO - error status */
+/*
+ CReate Header Data unit: Create, initialize, and move the i/o pointer
+ to a new extension appended to the end of the FITS file.
+*/
+{
+ int tstatus = 0;
+ OFF_T bytepos, *ptr;
+
+ if (*status > 0)
+ return(*status);
+
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+
+ /* If the current header is empty, we don't have to do anything */
+ if ((fptr->Fptr)->headend == (fptr->Fptr)->headstart[(fptr->Fptr)->curhdu] )
+ return(*status);
+
+ while (ffmrhd(fptr, 1, 0, &tstatus) == 0); /* move to end of file */
+
+ if ((fptr->Fptr)->maxhdu == (fptr->Fptr)->MAXHDU)
+ {
+ /* allocate more space for the headstart array */
+ ptr = (OFF_T*) realloc( (fptr->Fptr)->headstart,
+ ((fptr->Fptr)->MAXHDU + 1001) * sizeof(OFF_T) );
+
+ if (ptr == NULL)
+ return (*status = MEMORY_ALLOCATION);
+ else {
+ (fptr->Fptr)->MAXHDU = (fptr->Fptr)->MAXHDU + 1000;
+ (fptr->Fptr)->headstart = ptr;
+ }
+ }
+
+ if (ffchdu(fptr, status) <= 0) /* close the current HDU */
+ {
+ bytepos = (fptr->Fptr)->headstart[(fptr->Fptr)->maxhdu + 1]; /* last */
+ ffmbyt(fptr, bytepos, IGNORE_EOF, status); /* move file ptr to it */
+ (fptr->Fptr)->maxhdu++; /* increment the known number of HDUs */
+ (fptr->Fptr)->curhdu = (fptr->Fptr)->maxhdu; /* set current HDU loc */
+ fptr->HDUposition = (fptr->Fptr)->maxhdu; /* set current HDU loc */
+ (fptr->Fptr)->nextkey = bytepos; /* next keyword = start of header */
+ (fptr->Fptr)->headend = bytepos; /* end of header */
+ (fptr->Fptr)->datastart = DATA_UNDEFINED; /* start data unit undefined */
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffdblk(fitsfile *fptr, /* I - FITS file pointer */
+ long nblocks, /* I - number of 2880-byte blocks to delete */
+ int *status) /* IO - error status */
+/*
+ Delete the specified number of 2880-byte blocks from the end
+ of the CHDU by shifting all following extensions up this
+ number of blocks.
+*/
+{
+ char buffer[2880];
+ int tstatus, ii;
+ OFF_T readpos, writepos;
+
+ if (*status > 0 || nblocks <= 0)
+ return(*status);
+
+ tstatus = 0;
+ /* pointers to the read and write positions */
+
+ readpos = (fptr->Fptr)->datastart +
+ (fptr->Fptr)->heapstart +
+ (fptr->Fptr)->heapsize;
+ readpos = ((readpos + 2879) / 2880) * 2880; /* start of block */
+
+/* the following formula is wrong because the current data unit
+ may have been extended without updating the headstart value
+ of the following HDU.
+
+ readpos = (fptr->Fptr)->headstart[((fptr->Fptr)->curhdu) + 1];
+*/
+ writepos = readpos - ((OFF_T)nblocks * 2880);
+
+ while ( !ffmbyt(fptr, readpos, REPORT_EOF, &tstatus) &&
+ !ffgbyt(fptr, 2880L, buffer, &tstatus) )
+ {
+ ffmbyt(fptr, writepos, REPORT_EOF, status);
+ ffpbyt(fptr, 2880L, buffer, status);
+
+ if (*status > 0)
+ {
+ ffpmsg("Error deleting FITS blocks (ffdblk)");
+ return(*status);
+ }
+ readpos += 2880; /* increment to next block to transfer */
+ writepos += 2880;
+ }
+
+ /* now fill the last nblock blocks with zeros */
+ memset(buffer, 0, 2880);
+ ffmbyt(fptr, writepos, REPORT_EOF, status);
+
+ for (ii = 0; ii < nblocks; ii++)
+ ffpbyt(fptr, 2880L, buffer, status);
+
+ /* move back before the deleted blocks, since they may be deleted */
+ /* and we do not want to delete the current active buffer */
+ ffmbyt(fptr, writepos - 1, REPORT_EOF, status);
+
+ /* truncate the file to the new size, if supported on this device */
+ fftrun(fptr, writepos, status);
+
+ /* recalculate the starting location of all subsequent HDUs */
+ for (ii = (fptr->Fptr)->curhdu; ii <= (fptr->Fptr)->maxhdu; ii++)
+ (fptr->Fptr)->headstart[ii + 1] -= ((OFF_T)nblocks * 2880);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffghdt(fitsfile *fptr, /* I - FITS file pointer */
+ int *exttype, /* O - type of extension, 0, 1, or 2 */
+ /* for IMAGE_HDU, ASCII_TBL, or BINARY_TBL */
+ int *status) /* IO - error status */
+/*
+ Return the type of the CHDU. This returns the 'logical' type of the HDU,
+ not necessarily the physical type, so in the case of a compressed image
+ stored in a binary table, this will return the type as an Image, not a
+ binary table.
+*/
+{
+ if (*status > 0)
+ return(*status);
+
+ if (fptr->HDUposition == 0 && (fptr->Fptr)->headend == 0) {
+ /* empty primary array is alway an IMAGE_HDU */
+ *exttype = IMAGE_HDU;
+ }
+ else {
+
+ /* reset position to the correct HDU if necessary */
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ {
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+ }
+ else if ((fptr->Fptr)->datastart == DATA_UNDEFINED)
+ {
+ /* rescan header if data structure is undefined */
+ if ( ffrdef(fptr, status) > 0)
+ return(*status);
+ }
+
+ *exttype = (fptr->Fptr)->hdutype; /* return the type of HDU */
+
+ /* check if this is a compressed image */
+ if ((fptr->Fptr)->compressimg)
+ *exttype = IMAGE_HDU;
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fits_is_compressed_image(fitsfile *fptr, /* I - FITS file pointer */
+ int *status) /* IO - error status */
+/*
+ Returns TRUE if the CHDU is a compressed image, else returns zero.
+*/
+{
+ if (*status > 0)
+ return(0);
+
+ /* reset position to the correct HDU if necessary */
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ {
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+ }
+ else if ((fptr->Fptr)->datastart == DATA_UNDEFINED)
+ {
+ /* rescan header if data structure is undefined */
+ if ( ffrdef(fptr, status) > 0)
+ return(*status);
+ }
+
+ /* check if this is a compressed image */
+ if ((fptr->Fptr)->compressimg)
+ return(1);
+
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int ffgipr(fitsfile *infptr, /* I - FITS file pointer */
+ int maxaxis, /* I - max number of axes to return */
+ int *bitpix, /* O - image data type */
+ int *naxis, /* O - image dimension (NAXIS value) */
+ long *naxes, /* O - size of image dimensions */
+ int *status) /* IO - error status */
+
+/*
+ get the datatype and size of the input image
+*/
+{
+
+ if (*status > 0)
+ return(*status);
+
+ /* don't return the parameter if a null pointer was given */
+
+ if (bitpix)
+ fits_get_img_type(infptr, bitpix, status); /* get BITPIX value */
+
+ if (naxis)
+ fits_get_img_dim(infptr, naxis, status); /* get NAXIS value */
+
+ if (naxes)
+ fits_get_img_size(infptr, maxaxis, naxes, status); /* get NAXISn values */
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgidt( fitsfile *fptr, /* I - FITS file pointer */
+ int *imgtype, /* O - image data type */
+ int *status) /* IO - error status */
+/*
+ Get the datatype of the image (= BITPIX keyword for normal image, or
+ ZBITPIX for a compressed image)
+*/
+{
+ if (*status > 0)
+ return(*status);
+
+ /* reset position to the correct HDU if necessary */
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+ else if ((fptr->Fptr)->datastart == DATA_UNDEFINED)
+ if ( ffrdef(fptr, status) > 0) /* rescan header */
+ return(*status);
+
+ if ((fptr->Fptr)->hdutype == IMAGE_HDU)
+ {
+ ffgky(fptr, TINT, "BITPIX", imgtype, NULL, status);
+ }
+ else if ((fptr->Fptr)->compressimg)
+ {
+ /* this is a binary table containing a compressed image */
+ ffgky(fptr, TINT, "ZBITPIX", imgtype, NULL, status);
+ }
+ else
+ {
+ *status = NOT_IMAGE;
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgiet( fitsfile *fptr, /* I - FITS file pointer */
+ int *imgtype, /* O - image data type */
+ int *status) /* IO - error status */
+/*
+ Get the effective datatype of the image (= BITPIX keyword for normal image,
+ or ZBITPIX for a compressed image)
+*/
+{
+ int tstatus;
+ long lngscale = 1, lngzero = 0;
+ double bscale, bzero, min_val, max_val;
+
+ if (*status > 0)
+ return(*status);
+
+ /* reset position to the correct HDU if necessary */
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+ else if ((fptr->Fptr)->datastart == DATA_UNDEFINED)
+ if ( ffrdef(fptr, status) > 0) /* rescan header */
+ return(*status);
+
+ if ((fptr->Fptr)->hdutype == IMAGE_HDU)
+ {
+ ffgky(fptr, TINT, "BITPIX", imgtype, NULL, status);
+ tstatus = 0;
+ ffgky(fptr, TDOUBLE, "BSCALE", &bscale, NULL, &tstatus);
+ if (tstatus)
+ bscale = 1.0;
+
+ tstatus = 0;
+ ffgky(fptr, TDOUBLE, "BZERO", &bzero, NULL, &tstatus);
+ if (tstatus)
+ bzero = 0.0;
+
+ }
+ else if ((fptr->Fptr)->compressimg)
+ {
+ /* this is a binary table containing a compressed image */
+ ffgky(fptr, TINT, "ZBITPIX", imgtype, NULL, status);
+ }
+ else
+ {
+ *status = NOT_IMAGE;
+ return(*status);
+
+ }
+
+ /* check if the BSCALE and BZERO keywords are defined, which might
+ change the effective datatype of the image */
+ tstatus = 0;
+ ffgky(fptr, TDOUBLE, "BSCALE", &bscale, NULL, &tstatus);
+ if (tstatus)
+ bscale = 1.0;
+
+ tstatus = 0;
+ ffgky(fptr, TDOUBLE, "BZERO", &bzero, NULL, &tstatus);
+ if (tstatus)
+ bzero = 0.0;
+
+ if (bscale == 1.0 && bzero == 0.0) /* no scaling */
+ return(*status);
+
+ switch (*imgtype)
+ {
+ case BYTE_IMG: /* 8-bit image */
+ min_val = 0.;
+ max_val = 255.0;
+ break;
+
+ case SHORT_IMG:
+ min_val = -32768.0;
+ max_val = 32767.0;
+ break;
+
+ case LONG_IMG:
+
+ min_val = -2147483648.0;
+ max_val = 2147483647.0;
+ break;
+
+ default: /* don't have to deal with other data types */
+ return(*status);
+ }
+
+ if (bscale >= 0.) {
+ min_val = bzero + bscale * min_val;
+ max_val = bzero + bscale * max_val;
+ } else {
+ max_val = bzero + bscale * min_val;
+ min_val = bzero + bscale * max_val;
+ }
+ if (bzero < 2147483648.) /* don't exceed range of 32-bit integer */
+ lngzero = bzero;
+ lngscale = bscale;
+
+ if ((bzero != 2147483648.) && /* special value that exceeds integer range */
+ (lngzero != bzero || lngscale != bscale)) { /* not integers? */
+ /* floating point scaled values; just decide on required precision */
+ if (*imgtype == BYTE_IMG || *imgtype == SHORT_IMG)
+ *imgtype = FLOAT_IMG;
+ else
+ *imgtype = DOUBLE_IMG;
+
+ /*
+ In all the remaining cases, BSCALE and BZERO are integers,
+ and not equal to 1 and 0, respectively.
+ */
+
+ } else if ((min_val == -128.) && (max_val == 127.)) {
+ *imgtype = SBYTE_IMG;
+
+ } else if ((min_val >= -32768.0) && (max_val <= 32767.0)) {
+ *imgtype = SHORT_IMG;
+
+ } else if ((min_val >= 0.0) && (max_val <= 65535.0)) {
+ *imgtype = USHORT_IMG;
+
+ } else if ((min_val >= -2147483648.0) && (max_val <= 2147483647.0)) {
+ *imgtype = LONG_IMG;
+
+ } else if ((min_val >= 0.0) && (max_val < 4294967296.0)) {
+ *imgtype = ULONG_IMG;
+
+ } else { /* exceeds the range of a 32-bit integer */
+ *imgtype = DOUBLE_IMG;
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgidm( fitsfile *fptr, /* I - FITS file pointer */
+ int *naxis , /* O - image dimension (NAXIS value) */
+ int *status) /* IO - error status */
+/*
+ Get the dimension of the image (= NAXIS keyword for normal image, or
+ ZNAXIS for a compressed image)
+*/
+{
+ if (*status > 0)
+ return(*status);
+
+ /* reset position to the correct HDU if necessary */
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+ else if ((fptr->Fptr)->datastart == DATA_UNDEFINED)
+ if ( ffrdef(fptr, status) > 0) /* rescan header */
+ return(*status);
+
+ if ((fptr->Fptr)->hdutype == IMAGE_HDU)
+ {
+ ffgky(fptr, TINT, "NAXIS", naxis, NULL, status);
+ }
+ else if ((fptr->Fptr)->compressimg)
+ {
+ /* this is a binary table containing a compressed image */
+ ffgky(fptr, TINT, "ZNAXIS", naxis, NULL, status);
+ }
+ else
+ {
+ *status = NOT_IMAGE;
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgisz( fitsfile *fptr, /* I - FITS file pointer */
+ int nlen, /* I - number of axes to return */
+ long *naxes , /* O - size of image dimensions */
+ int *status) /* IO - error status */
+/*
+ Get the size of the image dimensions (= NAXISn keywords for normal image, or
+ ZNAXISn for a compressed image)
+*/
+{
+ int ii, naxis;
+ char keyroot[FLEN_KEYWORD], keyname[FLEN_KEYWORD];
+
+ if (*status > 0)
+ return(*status);
+
+ /* reset position to the correct HDU if necessary */
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+ else if ((fptr->Fptr)->datastart == DATA_UNDEFINED)
+ if ( ffrdef(fptr, status) > 0) /* rescan header */
+ return(*status);
+
+ if ((fptr->Fptr)->hdutype == IMAGE_HDU)
+ {
+ strcpy(keyroot, "NAXIS");
+ }
+ else if ((fptr->Fptr)->compressimg)
+ {
+ /* this is a binary table containing a compressed image */
+ strcpy(keyroot, "ZNAXIS");
+ }
+ else
+ {
+ return(*status = NOT_IMAGE);
+ }
+
+ /* initialize to 1 */
+ for (ii = 0; ii < nlen; ii++)
+ naxes[ii] = 1;
+
+ /* get number of dimensions */
+ fits_get_img_dim(fptr, &naxis, status);
+ naxis = minvalue(naxis, nlen);
+
+ for (ii = 0; ii < naxis; ii++)
+ {
+ ffkeyn(keyroot, ii + 1, keyname, status);
+ ffgkyj(fptr, keyname, naxes + ii, NULL, status);
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffmahd(fitsfile *fptr, /* I - FITS file pointer */
+ int hdunum, /* I - number of the HDU to move to */
+ int *exttype, /* O - type of extension, 0, 1, or 2 */
+ int *status) /* IO - error status */
+/*
+ Move to Absolute Header Data unit. Move to the specified HDU
+ and read the header to initialize the table structure. Note that extnum
+ is one based, so the primary array is extnum = 1.
+*/
+{
+ int moveto, tstatus;
+ char message[FLEN_ERRMSG];
+ OFF_T *ptr;
+
+ if (*status > 0)
+ return(*status);
+ else if (hdunum < 1 )
+ return(*status = BAD_HDU_NUM);
+ else if (hdunum >= (fptr->Fptr)->MAXHDU )
+ {
+ /* allocate more space for the headstart array */
+ ptr = (OFF_T*) realloc( (fptr->Fptr)->headstart,
+ (hdunum + 1001) * sizeof(OFF_T) );
+
+ if (ptr == NULL)
+ return (*status = MEMORY_ALLOCATION);
+ else {
+ (fptr->Fptr)->MAXHDU = hdunum + 1000;
+ (fptr->Fptr)->headstart = ptr;
+ }
+ }
+
+ /* set logical HDU position to the actual position, in case they differ */
+ fptr->HDUposition = (fptr->Fptr)->curhdu;
+
+ while( ((fptr->Fptr)->curhdu) + 1 != hdunum) /* at the correct HDU? */
+ {
+ /* move directly to the extension if we know that it exists,
+ otherwise move to the highest known extension. */
+
+ moveto = minvalue(hdunum - 1, ((fptr->Fptr)->maxhdu) + 1);
+
+ /* test if HDU exists */
+ if ((fptr->Fptr)->headstart[moveto] < (fptr->Fptr)->logfilesize )
+ {
+ if (ffchdu(fptr, status) <= 0) /* close out the current HDU */
+ {
+ if (ffgext(fptr, moveto, exttype, status) > 0)
+ { /* failed to get the requested extension */
+
+ tstatus = 0;
+ ffrhdu(fptr, exttype, &tstatus); /* restore the CHDU */
+ }
+ }
+ }
+ else
+ *status = END_OF_FILE;
+
+ if (*status > 0)
+ {
+ if (*status != END_OF_FILE)
+ {
+ /* don't clutter up the message stack in the common case of */
+ /* simply hitting the end of file (often an expected error) */
+
+ sprintf(message,
+ "Failed to move to HDU number %d (ffmahd).", hdunum);
+ ffpmsg(message);
+ }
+ return(*status);
+ }
+ }
+
+ /* return the type of HDU; tile compressed images which are stored */
+ /* in a binary table will return exttype = IMAGE_HDU, not BINARY_TBL */
+ if (exttype != NULL)
+ ffghdt(fptr, exttype, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffmrhd(fitsfile *fptr, /* I - FITS file pointer */
+ int hdumov, /* I - rel. no. of HDUs to move by (+ or -) */
+ int *exttype, /* O - type of extension, 0, 1, or 2 */
+ int *status) /* IO - error status */
+/*
+ Move a Relative number of Header Data units. Offset to the specified
+ extension and read the header to initialize the HDU structure.
+*/
+{
+ int extnum;
+
+ if (*status > 0)
+ return(*status);
+
+ extnum = fptr->HDUposition + 1 + hdumov; /* the absolute HDU number */
+ ffmahd(fptr, extnum, exttype, status); /* move to the HDU */
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffmnhd(fitsfile *fptr, /* I - FITS file pointer */
+ int exttype, /* I - desired extension type */
+ char *hduname, /* I - desired EXTNAME value for the HDU */
+ int hduver, /* I - desired EXTVERS value for the HDU */
+ int *status) /* IO - error status */
+/*
+ Move to the next HDU with a given extension type (IMAGE_HDU, ASCII_TBL,
+ BINARY_TBL, or ANY_HDU), extension name (EXTNAME or HDUNAME keyword),
+ and EXTVERS keyword values. If hduvers = 0, then move to the first HDU
+ with the given type and name regardless of EXTVERS value. If no matching
+ HDU is found in the file, then the current open HDU will remain unchanged.
+*/
+{
+ char extname[FLEN_VALUE];
+ int ii, hdutype, alttype, extnum, tstatus, match, exact;
+ long extver;
+
+ if (*status > 0)
+ return(*status);
+
+ extnum = fptr->HDUposition + 1; /* save the current HDU number */
+
+ for (ii=1; 1; ii++) /* loop until EOF */
+ {
+ tstatus = 0;
+ if (ffmahd(fptr, ii, &hdutype, &tstatus)) /* move to next HDU */
+ {
+ ffmahd(fptr, extnum, 0, status); /* restore file position */
+ return(*status = BAD_HDU_NUM); /* couldn't find desired HDU */
+ }
+
+ alttype = -1;
+ if (fits_is_compressed_image(fptr, status))
+ alttype = BINARY_TBL;
+
+ /* matching type? */
+ if (exttype == ANY_HDU || hdutype == exttype || hdutype == alttype)
+ {
+ if (ffgkys(fptr, "EXTNAME", extname, 0, &tstatus) > 0) /* name */
+ {
+ tstatus = 0;
+ /* look for HDUNAME, since EXTNAME didn't exist */
+ ffgkys(fptr, "HDUNAME", extname, 0, &tstatus);
+ }
+ else
+ {
+ /* check if EXTNAME is the name we are looking for. */
+ /* If not, try reading the HDUNAME keyword. */
+ ffcmps(extname, hduname, CASEINSEN, &match, &exact);
+ if (!exact)
+ ffgkys(fptr, "HDUNAME", extname, 0, &tstatus);
+ }
+
+ if (tstatus <= 0)
+ {
+ ffcmps(extname, hduname, CASEINSEN, &match, &exact);
+ if (exact) /* names match? */
+ {
+ if (hduver) /* need to check if version numbers match? */
+ {
+ if (ffgkyj(fptr, "EXTVER", &extver, 0, &tstatus) > 0)
+ extver = 1; /* assume default EXTVER value */
+
+ if ( (int) extver == hduver)
+ {
+ return(*status); /* found matching name and vers */
+ }
+ }
+ else
+ {
+ return(*status); /* found matching name */
+ }
+ }
+ }
+ }
+ }
+}
+/*--------------------------------------------------------------------------*/
+int ffthdu(fitsfile *fptr, /* I - FITS file pointer */
+ int *nhdu, /* O - number of HDUs in the file */
+ int *status) /* IO - error status */
+/*
+ Return the number of HDUs that currently exist in the file.
+*/
+{
+ int ii, extnum, tstatus;
+
+ if (*status > 0)
+ return(*status);
+
+ extnum = fptr->HDUposition + 1; /* save the current HDU number */
+ *nhdu = extnum - 1;
+
+ /* if the CHDU is empty or not completely defined, just return */
+ if ((fptr->Fptr)->datastart == DATA_UNDEFINED)
+ return(*status);
+
+ tstatus = 0;
+
+ /* loop until EOF */
+ for (ii=extnum; ffmahd(fptr, ii, 0, &tstatus) <= 0; ii++)
+ {
+ *nhdu = ii;
+ }
+
+ ffmahd(fptr, extnum, 0, status); /* restore orig file position */
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgext(fitsfile *fptr, /* I - FITS file pointer */
+ int hdunum, /* I - no. of HDU to move get (0 based) */
+ int *exttype, /* O - type of extension, 0, 1, or 2 */
+ int *status) /* IO - error status */
+/*
+ Get Extension. Move to the specified extension and initialize the
+ HDU structure.
+*/
+{
+ int xcurhdu, xmaxhdu;
+ OFF_T xheadend;
+
+ if (*status > 0)
+ return(*status);
+
+ if (ffmbyt(fptr, (fptr->Fptr)->headstart[hdunum], REPORT_EOF, status) <= 0)
+ {
+ /* temporarily save current values, in case of error */
+ xcurhdu = (fptr->Fptr)->curhdu;
+ xmaxhdu = (fptr->Fptr)->maxhdu;
+ xheadend = (fptr->Fptr)->headend;
+
+ /* set new parameter values */
+ (fptr->Fptr)->curhdu = hdunum;
+ fptr->HDUposition = hdunum;
+ (fptr->Fptr)->maxhdu = maxvalue((fptr->Fptr)->maxhdu, hdunum);
+ (fptr->Fptr)->headend = (fptr->Fptr)->logfilesize; /* set max size */
+
+ if (ffrhdu(fptr, exttype, status) > 0)
+ { /* failed to get the new HDU, so restore previous values */
+ (fptr->Fptr)->curhdu = xcurhdu;
+ fptr->HDUposition = xcurhdu;
+ (fptr->Fptr)->maxhdu = xmaxhdu;
+ (fptr->Fptr)->headend = xheadend;
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffiblk(fitsfile *fptr, /* I - FITS file pointer */
+ long nblock, /* I - no. of blocks to insert */
+ int headdata, /* I - insert where? 0=header, 1=data */
+ /* -1=beginning of file */
+ int *status) /* IO - error status */
+/*
+ insert 2880-byte blocks at the end of the current header or data unit
+*/
+{
+ int tstatus, savehdu, typhdu;
+ OFF_T insertpt, jpoint;
+ long ii, nshift;
+ char charfill;
+ char buff1[2880], buff2[2880];
+ char *inbuff, *outbuff, *tmpbuff;
+ char card[FLEN_CARD];
+
+ if (*status > 0 || nblock <= 0)
+ return(*status);
+
+ tstatus = *status;
+
+ if (headdata == 0 || (fptr->Fptr)->hdutype == ASCII_TBL)
+ charfill = 32; /* headers and ASCII tables have space (32) fill */
+ else
+ charfill = 0; /* images and binary tables have zero fill */
+
+ if (headdata == 0)
+ insertpt = (fptr->Fptr)->datastart; /* insert just before data, or */
+ else if (headdata == -1)
+ {
+ insertpt = 0;
+ strcpy(card, "XTENSION= 'IMAGE ' / IMAGE extension");
+ }
+ else /* at end of data, */
+ {
+ insertpt = (fptr->Fptr)->datastart +
+ (fptr->Fptr)->heapstart +
+ (fptr->Fptr)->heapsize;
+ insertpt = ((insertpt + 2879) / 2880) * 2880; /* start of block */
+
+ /* the following formula is wrong because the current data unit
+ may have been extended without updating the headstart value
+ of the following HDU.
+ */
+ /* insertpt = (fptr->Fptr)->headstart[(fptr->Fptr)->curhdu + 1]; */
+ }
+
+ inbuff = buff1; /* set pointers to input and output buffers */
+ outbuff = buff2;
+
+ memset(outbuff, charfill, 2880); /* initialize buffer with fill */
+
+ if (nblock == 1) /* insert one block */
+ {
+ if (headdata == -1)
+ ffmrec(fptr, 1, card, status); /* change SIMPLE -> XTENSION */
+
+ ffmbyt(fptr, insertpt, REPORT_EOF, status); /* move to 1st point */
+ ffgbyt(fptr, 2880, inbuff, status); /* read first block of bytes */
+
+ while (*status <= 0)
+ {
+ ffmbyt(fptr, insertpt, REPORT_EOF, status); /* insert point */
+ ffpbyt(fptr, 2880, outbuff, status); /* write the output buffer */
+
+ if (*status > 0)
+ return(*status);
+
+ tmpbuff = inbuff; /* swap input and output pointers */
+ inbuff = outbuff;
+ outbuff = tmpbuff;
+ insertpt += 2880; /* increment insert point by 1 block */
+
+ ffmbyt(fptr, insertpt, REPORT_EOF, status); /* move to next block */
+ ffgbyt(fptr, 2880, inbuff, status); /* read block of bytes */
+ }
+
+ *status = tstatus; /* reset status value */
+ ffmbyt(fptr, insertpt, IGNORE_EOF, status); /* move back to insert pt */
+ ffpbyt(fptr, 2880, outbuff, status); /* write the final block */
+ }
+
+ else /* inserting more than 1 block */
+
+ {
+ savehdu = (fptr->Fptr)->curhdu; /* save the current HDU number */
+ tstatus = *status;
+ while(*status <= 0) /* find the last HDU in file */
+ ffmrhd(fptr, 1, &typhdu, status);
+
+ if (*status == END_OF_FILE)
+ {
+ *status = tstatus;
+ }
+
+ ffmahd(fptr, savehdu + 1, &typhdu, status); /* move back to CHDU */
+ if (headdata == -1)
+ ffmrec(fptr, 1, card, status); /* NOW change SIMPLE -> XTENSION */
+
+ /* number of 2880-byte blocks that have to be shifted down */
+ nshift = ((fptr->Fptr)->headstart[(fptr->Fptr)->maxhdu + 1] - insertpt)
+ / 2880;
+ /* position of last block in file to be shifted */
+ jpoint = (fptr->Fptr)->headstart[(fptr->Fptr)->maxhdu + 1] - 2880;
+
+ /* move all the blocks starting at end of file working backwards */
+ for (ii = 0; ii < nshift; ii++)
+ {
+ /* move to the read start position */
+ if (ffmbyt(fptr, jpoint, REPORT_EOF, status) > 0)
+ return(*status);
+
+ ffgbyt(fptr, 2880, inbuff,status); /* read one record */
+
+ /* move forward to the write postion */
+ ffmbyt(fptr, jpoint + (nblock * 2880), IGNORE_EOF, status);
+
+ ffpbyt(fptr, 2880, inbuff, status); /* write the record */
+
+ jpoint -= 2880;
+ }
+
+ /* move back to the write start postion (might be EOF) */
+ ffmbyt(fptr, insertpt, IGNORE_EOF, status);
+
+ for (ii = 0; ii < nblock; ii++) /* insert correct fill value */
+ ffpbyt(fptr, 2880, outbuff, status);
+ }
+
+ if (headdata == 0) /* update data start address */
+ (fptr->Fptr)->datastart += ((OFF_T)nblock * 2880);
+
+ /* update following HDU addresses */
+ for (ii = (fptr->Fptr)->curhdu; ii <= (fptr->Fptr)->maxhdu; ii++)
+ (fptr->Fptr)->headstart[ii + 1] += ((OFF_T)nblock * 2880);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgkcl(char *tcard)
+
+/*
+ Return the type classification of the input header record
+
+ TYP_STRUC_KEY: SIMPLE, BITPIX, NAXIS, NAXISn, EXTEND, BLOCKED,
+ GROUPS, PCOUNT, GCOUNT, END
+ XTENSION, TFIELDS, TTYPEn, TBCOLn, TFORMn, THEAP,
+ and the first 4 COMMENT keywords in the primary array
+ that define the FITS format.
+
+ TYP_CMPRS_KEY:
+ The experimental keywords used in the compressed image format
+ ZIMAGE, ZCMPTYPE, ZNAMEn, ZVALn, ZTILEn,
+ ZBITPIX, ZNAXISn, ZSCALE, ZZERO, ZBLANK,
+ EXTNAME = 'COMPRESSED_IMAGE'
+
+ TYP_SCAL_KEY: BSCALE, BZERO, TSCALn, TZEROn
+
+ TYP_NULL_KEY: BLANK, TNULLn
+
+ TYP_DIM_KEY: TDIMn
+
+ TYP_RANG_KEY: TLMINn, TLMAXn, TDMINn, TDMAXn, DATAMIN, DATAMAX
+
+ TYP_UNIT_KEY: BUNIT, TUNITn
+
+ TYP_DISP_KEY: TDISPn
+
+ TYP_HDUID_KEY: EXTNAME, EXTVER, EXTLEVEL, HDUNAME, HDUVER, HDULEVEL
+
+ TYP_CKSUM_KEY CHECKSUM, DATASUM
+
+ TYP_WCS_KEY:
+ Primary array:
+ CTYPEn, CUNITn, CRVALn, CRPIXn, CROTAn, CDELTn
+ CDj_is, PVj_ms, LONPOLEs, LATPOLEs
+
+ Pixel list:
+ TCTYPn, TCTYns, TCUNIn, TCUNns, TCRVLn, TCRVns, TCRPXn, TCRPks,
+ TCDn_k, TCn_ks, TPVn_m, TPn_ms, TCDLTn, TCROTn
+
+ Bintable vector:
+ jCTYPn, jCTYns, jCUNIn, jCUNns, jCRVLn, jCRVns, iCRPXn, iCRPns,
+ jiCDn, jiCDns, jPVn_m, jPn_ms, jCDLTn, jCROTn
+
+ TYP_REFSYS_KEY:
+ EQUINOXs, EPOCH, MJD-OBSs, RADECSYS, RADESYSs
+
+ TYP_COMM_KEY: COMMENT, HISTORY, (blank keyword)
+
+ TYP_CONT_KEY: CONTINUE
+
+ TYP_USER_KEY: all other keywords
+
+*/
+{
+ char card[20], *card1, *card5;
+
+ card[0] = '\0';
+ strncat(card, tcard, 8); /* copy the keyword name */
+ strcat(card, " "); /* append blanks to make at least 8 chars long */
+ ffupch(card); /* make sure it is in upper case */
+
+ card1 = card + 1; /* pointer to 2nd character */
+ card5 = card + 5; /* pointer to 6th character */
+
+ /* the strncmp function is slow, so try to be more efficient */
+ if (*card == 'Z')
+ {
+ if (FSTRNCMP (card1, "IMAGE ", 7) == 0)
+ return (TYP_CMPRS_KEY);
+ else if (FSTRNCMP (card1, "CMPTYPE", 7) == 0)
+ return (TYP_CMPRS_KEY);
+ else if (FSTRNCMP (card1, "NAME", 4) == 0)
+ {
+ if (*card5 >= '0' && *card5 <= '9')
+ return (TYP_CMPRS_KEY);
+ }
+ else if (FSTRNCMP (card1, "VAL", 3) == 0)
+ {
+ if (*(card + 4) >= '0' && *(card + 4) <= '9')
+ return (TYP_CMPRS_KEY);
+ }
+ else if (FSTRNCMP (card1, "TILE", 4) == 0)
+ {
+ if (*card5 >= '0' && *card5 <= '9')
+ return (TYP_CMPRS_KEY);
+ }
+ else if (FSTRNCMP (card1, "BITPIX ", 7) == 0)
+ return (TYP_CMPRS_KEY);
+ else if (FSTRNCMP (card1, "NAXIS", 5) == 0)
+ {
+ if ( ( *(card + 6) >= '0' && *(card + 6) <= '9' )
+ || (*(card + 6) == ' ') )
+ return (TYP_CMPRS_KEY);
+ }
+ else if (FSTRNCMP (card1, "SCALE ", 7) == 0)
+ return (TYP_CMPRS_KEY);
+ else if (FSTRNCMP (card1, "ZERO ", 7) == 0)
+ return (TYP_CMPRS_KEY);
+ else if (FSTRNCMP (card1, "BLANK ", 7) == 0)
+ return (TYP_CMPRS_KEY);
+ }
+ else if (*card == ' ')
+ {
+ return (TYP_COMM_KEY);
+ }
+ else if (*card == '\0')
+ {
+ return (TYP_COMM_KEY);
+ }
+ else if (*card == 'B')
+ {
+ if (FSTRNCMP (card1, "ITPIX ", 7) == 0)
+ return (TYP_STRUC_KEY);
+ if (FSTRNCMP (card1, "LOCKED ", 7) == 0)
+ return (TYP_STRUC_KEY);
+
+ if (FSTRNCMP (card1, "LANK ", 7) == 0)
+ return (TYP_NULL_KEY);
+
+ if (FSTRNCMP (card1, "SCALE ", 7) == 0)
+ return (TYP_SCAL_KEY);
+ if (FSTRNCMP (card1, "ZERO ", 7) == 0)
+ return (TYP_SCAL_KEY);
+
+ if (FSTRNCMP (card1, "UNIT ", 7) == 0)
+ return (TYP_UNIT_KEY);
+ }
+ else if (*card == 'C')
+ {
+ if (FSTRNCMP (card1, "OMMENT",6) == 0)
+ {
+ /* new comment string starting Oct 2001 */
+ if (FSTRNCMP (card1, "OMMENT and Astrophysics', volume 376, page 3",
+ 46) == 0)
+ return (TYP_STRUC_KEY);
+
+ /* original COMMENT strings from 1993 - 2001 */
+ if (FSTRNCMP (card1, "OMMENT FITS (Flexible Image Transport System",
+ 46) == 0)
+ return (TYP_STRUC_KEY);
+ if (FSTRNCMP (card1, "OMMENT Astrophysics Supplement Series v44/p3",
+ 46) == 0)
+ return (TYP_STRUC_KEY);
+ if (FSTRNCMP (card1, "OMMENT Contact the NASA Science Office of St",
+ 46) == 0)
+ return (TYP_STRUC_KEY);
+ if (FSTRNCMP (card1, "OMMENT FITS Definition document #100 and oth",
+ 46) == 0)
+ return (TYP_STRUC_KEY);
+
+ if (*(card + 7) == ' ' || *(card + 7) == '\0')
+ return (TYP_COMM_KEY);
+ else
+ return (TYP_USER_KEY);
+ }
+
+ if (FSTRNCMP (card1, "HECKSUM", 7) == 0)
+ return (TYP_CKSUM_KEY);
+
+ if (FSTRNCMP (card1, "ONTINUE", 7) == 0)
+ return (TYP_CONT_KEY);
+
+ if (FSTRNCMP (card1, "TYPE",4) == 0)
+ {
+ if (*card5 >= '0' && *card5 <= '9')
+ return (TYP_WCS_KEY);
+ }
+ else if (FSTRNCMP (card1, "UNIT",4) == 0)
+ {
+ if (*card5 >= '0' && *card5 <= '9')
+ return (TYP_WCS_KEY);
+ }
+ else if (FSTRNCMP (card1, "RVAL",4) == 0)
+ {
+ if (*card5 >= '0' && *card5 <= '9')
+ return (TYP_WCS_KEY);
+ }
+ else if (FSTRNCMP (card1, "RPIX",4) == 0)
+ {
+ if (*card5 >= '0' && *card5 <= '9')
+ return (TYP_WCS_KEY);
+ }
+ else if (FSTRNCMP (card1, "ROTA",4) == 0)
+ {
+ if (*card5 >= '0' && *card5 <= '9')
+ return (TYP_WCS_KEY);
+ }
+ else if (FSTRNCMP (card1, "DELT",4) == 0)
+ {
+ if (*card5 >= '0' && *card5 <= '9')
+ return (TYP_WCS_KEY);
+ }
+ else if (*card1 == 'D')
+ {
+ if (*(card + 2) >= '0' && *(card + 2) <= '9')
+ return (TYP_WCS_KEY);
+ }
+ }
+ else if (*card == 'D')
+ {
+ if (FSTRNCMP (card1, "ATASUM ", 7) == 0)
+ return (TYP_CKSUM_KEY);
+ if (FSTRNCMP (card1, "ATAMIN ", 7) == 0)
+ return (TYP_RANG_KEY);
+ if (FSTRNCMP (card1, "ATAMAX ", 7) == 0)
+ return (TYP_RANG_KEY);
+ }
+ else if (*card == 'E')
+ {
+ if (FSTRNCMP (card1, "XTEND ", 7) == 0)
+ return (TYP_STRUC_KEY);
+ if (FSTRNCMP (card1, "ND ", 7) == 0)
+ return (TYP_STRUC_KEY);
+ if (FSTRNCMP (card1, "XTNAME ", 7) == 0)
+ {
+ /* check for special compressed image value */
+ if (FSTRNCMP(tcard, "EXTNAME = 'COMPRESSED_IMAGE'", 28) == 0)
+ return (TYP_CMPRS_KEY);
+ else
+ return (TYP_HDUID_KEY);
+ }
+ if (FSTRNCMP (card1, "XTVER ", 7) == 0)
+ return (TYP_HDUID_KEY);
+ if (FSTRNCMP (card1, "XTLEVEL", 7) == 0)
+ return (TYP_HDUID_KEY);
+
+ if (FSTRNCMP (card1, "QUINOX", 6) == 0)
+ return (TYP_REFSYS_KEY);
+ if (FSTRNCMP (card1, "POCH ", 7) == 0)
+ return (TYP_REFSYS_KEY);
+ }
+ else if (*card == 'G')
+ {
+ if (FSTRNCMP (card1, "COUNT ", 7) == 0)
+ return (TYP_STRUC_KEY);
+ if (FSTRNCMP (card1, "ROUPS ", 7) == 0)
+ return (TYP_STRUC_KEY);
+ }
+ else if (*card == 'H')
+ {
+ if (FSTRNCMP (card1, "DUNAME ", 7) == 0)
+ return (TYP_HDUID_KEY);
+ if (FSTRNCMP (card1, "DUVER ", 7) == 0)
+ return (TYP_HDUID_KEY);
+ if (FSTRNCMP (card1, "DULEVEL", 7) == 0)
+ return (TYP_HDUID_KEY);
+
+ if (FSTRNCMP (card1, "ISTORY",6) == 0)
+ {
+ if (*(card + 7) == ' ' || *(card + 7) == '\0')
+ return (TYP_COMM_KEY);
+ else
+ return (TYP_USER_KEY);
+ }
+ }
+ else if (*card == 'L')
+ {
+ if (FSTRNCMP (card1, "ONPOLE",6) == 0)
+ return (TYP_WCS_KEY);
+ if (FSTRNCMP (card1, "ATPOLE",6) == 0)
+ return (TYP_WCS_KEY);
+ }
+ else if (*card == 'M')
+ {
+ if (FSTRNCMP (card1, "JD_OBS ", 7) == 0)
+ return (TYP_REFSYS_KEY);
+ }
+ else if (*card == 'N')
+ {
+ if (FSTRNCMP (card1, "AXIS", 4) == 0)
+ {
+ if ((*card5 >= '0' && *card5 <= '9')
+ || (*card5 == ' '))
+ return (TYP_STRUC_KEY);
+ }
+ }
+ else if (*card == 'P')
+ {
+ if (FSTRNCMP (card1, "COUNT ", 7) == 0)
+ return (TYP_STRUC_KEY);
+ }
+ else if (*card == 'R')
+ {
+ if (FSTRNCMP (card1, "ADECSYS", 7) == 0)
+ return (TYP_REFSYS_KEY);
+ if (FSTRNCMP (card1, "ADESYS", 6) == 0)
+ return (TYP_REFSYS_KEY);
+ }
+ else if (*card == 'S')
+ {
+ if (FSTRNCMP (card1, "IMPLE ", 7) == 0)
+ return (TYP_STRUC_KEY);
+ }
+ else if (*card == 'T')
+ {
+ if (FSTRNCMP (card1, "TYPE", 4) == 0)
+ {
+ if (*card5 >= '0' && *card5 <= '9')
+ return (TYP_STRUC_KEY);
+ }
+ else if (FSTRNCMP (card1, "FORM", 4) == 0)
+ {
+ if (*card5 >= '0' && *card5 <= '9')
+ return (TYP_STRUC_KEY);
+ }
+ else if (FSTRNCMP (card1, "BCOL", 4) == 0)
+ {
+ if (*card5 >= '0' && *card5 <= '9')
+ return (TYP_STRUC_KEY);
+ }
+ else if (FSTRNCMP (card1, "FIELDS ", 7) == 0)
+ return (TYP_STRUC_KEY);
+ else if (FSTRNCMP (card1, "HEAP ", 7) == 0)
+ return (TYP_STRUC_KEY);
+
+ else if (FSTRNCMP (card1, "NULL", 4) == 0)
+ {
+ if (*card5 >= '0' && *card5 <= '9')
+ return (TYP_NULL_KEY);
+ }
+
+ else if (FSTRNCMP (card1, "DIM", 3) == 0)
+ {
+ if (*(card + 4) >= '0' && *(card + 4) <= '9')
+ return (TYP_DIM_KEY);
+ }
+
+ else if (FSTRNCMP (card1, "UNIT", 4) == 0)
+ {
+ if (*card5 >= '0' && *card5 <= '9')
+ return (TYP_UNIT_KEY);
+ }
+
+ else if (FSTRNCMP (card1, "DISP", 4) == 0)
+ {
+ if (*card5 >= '0' && *card5 <= '9')
+ return (TYP_DISP_KEY);
+ }
+
+ else if (FSTRNCMP (card1, "SCAL", 4) == 0)
+ {
+ if (*card5 >= '0' && *card5 <= '9')
+ return (TYP_SCAL_KEY);
+ }
+ else if (FSTRNCMP (card1, "ZERO", 4) == 0)
+ {
+ if (*card5 >= '0' && *card5 <= '9')
+ return (TYP_SCAL_KEY);
+ }
+
+ else if (FSTRNCMP (card1, "LMIN", 4) == 0)
+ {
+ if (*card5 >= '0' && *card5 <= '9')
+ return (TYP_RANG_KEY);
+ }
+ else if (FSTRNCMP (card1, "LMAX", 4) == 0)
+ {
+ if (*card5 >= '0' && *card5 <= '9')
+ return (TYP_RANG_KEY);
+ }
+ else if (FSTRNCMP (card1, "DMIN", 4) == 0)
+ {
+ if (*card5 >= '0' && *card5 <= '9')
+ return (TYP_RANG_KEY);
+ }
+ else if (FSTRNCMP (card1, "DMAX", 4) == 0)
+ {
+ if (*card5 >= '0' && *card5 <= '9')
+ return (TYP_RANG_KEY);
+ }
+
+ else if (FSTRNCMP (card1, "CTYP",4) == 0)
+ {
+ if (*card5 >= '0' && *card5 <= '9')
+ return (TYP_WCS_KEY);
+ }
+ else if (FSTRNCMP (card1, "CUNI",4) == 0)
+ {
+ if (*card5 >= '0' && *card5 <= '9')
+ return (TYP_WCS_KEY);
+ }
+ else if (FSTRNCMP (card1, "CRVL",4) == 0)
+ {
+ if (*card5 >= '0' && *card5 <= '9')
+ return (TYP_WCS_KEY);
+ }
+ else if (FSTRNCMP (card1, "CRPX",4) == 0)
+ {
+ if (*card5 >= '0' && *card5 <= '9')
+ return (TYP_WCS_KEY);
+ }
+ else if (FSTRNCMP (card1, "CROT",4) == 0)
+ {
+ if (*card5 >= '0' && *card5 <= '9')
+ return (TYP_WCS_KEY);
+ }
+ else if (FSTRNCMP (card1, "CDLT",4) == 0)
+ {
+ if (*card5 >= '0' && *card5 <= '9')
+ return (TYP_WCS_KEY);
+ }
+ else if (FSTRNCMP (card1, "CD",2) == 0)
+ {
+ if (*(card + 3) >= '0' && *(card + 3) <= '9')
+ return (TYP_WCS_KEY);
+ }
+ }
+ else if (*card == 'X')
+ {
+ if (FSTRNCMP (card1, "TENSION", 7) == 0)
+ return (TYP_STRUC_KEY);
+ }
+
+ return (TYP_USER_KEY); /* by default all others are user keywords */
+}
+/*--------------------------------------------------------------------------*/
+int ffdtyp(char *cval, /* I - formatted string representation of the value */
+ char *dtype, /* O - datatype code: C, L, F, I, or X */
+ int *status) /* IO - error status */
+/*
+ determine implicit datatype of input string.
+ This assumes that the string conforms to the FITS standard
+ for keyword values, so may not detect all invalid formats.
+*/
+{
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ if (cval[0] == '\0')
+ return(*status = VALUE_UNDEFINED);
+ else if (cval[0] == '\'')
+ *dtype = 'C'; /* character string starts with a quote */
+ else if (cval[0] == 'T' || cval[0] == 'F')
+ *dtype = 'L'; /* logical = T or F character */
+ else if (cval[0] == '(')
+ *dtype = 'X'; /* complex datatype "(1.2, -3.4)" */
+ else if (strchr(cval,'.'))
+ *dtype = 'F'; /* float usualy contains a decimal point */
+ else if (strchr(cval,'E') || strchr(cval,'D') )
+ *dtype = 'F'; /* exponential contains a E or D */
+ else
+ *dtype = 'I'; /* if none of the above assume it is integer */
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffc2x(char *cval, /* I - formatted string representation of the value */
+ char *dtype, /* O - datatype code: C, L, F, I or X */
+
+ /* Only one of the following will be defined, depending on datatype */
+ long *ival, /* O - integer value */
+ int *lval, /* O - logical value */
+ char *sval, /* O - string value */
+ double *dval, /* O - double value */
+
+ int *status) /* IO - error status */
+/*
+ high level routine to convert formatted character string to its
+ intrinsic data type
+*/
+{
+ ffdtyp(cval, dtype, status); /* determine the datatype */
+
+ if (*dtype == 'I')
+ ffc2ii(cval, ival, status);
+ else if (*dtype == 'F')
+ ffc2dd(cval, dval, status);
+ else if (*dtype == 'L')
+ ffc2ll(cval, lval, status);
+ else
+ ffc2s(cval, sval, status); /* C and X formats */
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffc2i(char *cval, /* I - string representation of the value */
+ long *ival, /* O - numerical value of the input string */
+ int *status) /* IO - error status */
+/*
+ convert formatted string to an integer value, doing implicit
+ datatype conversion if necessary.
+*/
+{
+ char dtype, sval[81], msg[81];
+ int lval;
+ double dval;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ if (cval[0] == '\0')
+ return(*status = VALUE_UNDEFINED); /* null value string */
+
+ /* convert the keyword to its native datatype */
+ ffc2x(cval, &dtype, ival, &lval, sval, &dval, status);
+
+ if (dtype == 'X' )
+ {
+ *status = BAD_INTKEY;
+ }
+ else if (dtype == 'C')
+ {
+ /* try reading the string as a number */
+ if (ffc2dd(sval, &dval, status) <= 0)
+ {
+ if (dval > (double) LONG_MAX || dval < (double) LONG_MIN)
+ *status = NUM_OVERFLOW;
+ else
+ *ival = (long) dval;
+ }
+ }
+ else if (dtype == 'F')
+ {
+ if (dval > (double) LONG_MAX || dval < (double) LONG_MIN)
+ *status = NUM_OVERFLOW;
+ else
+ *ival = (long) dval;
+ }
+ else if (dtype == 'L')
+ {
+ *ival = (long) lval;
+ }
+
+ if (*status > 0)
+ {
+ *ival = 0;
+ strcpy(msg,"Error in ffc2i evaluating string as an integer: ");
+ strncat(msg,cval,30);
+ ffpmsg(msg);
+ return(*status);
+ }
+
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffc2l(char *cval, /* I - string representation of the value */
+ int *lval, /* O - numerical value of the input string */
+ int *status) /* IO - error status */
+/*
+ convert formatted string to a logical value, doing implicit
+ datatype conversion if necessary
+*/
+{
+ char dtype, sval[81], msg[81];
+ long ival;
+ double dval;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ if (cval[0] == '\0')
+ return(*status = VALUE_UNDEFINED); /* null value string */
+
+ /* convert the keyword to its native datatype */
+ ffc2x(cval, &dtype, &ival, lval, sval, &dval, status);
+
+ if (dtype == 'C' || dtype == 'X' )
+ *status = BAD_LOGICALKEY;
+
+ if (*status > 0)
+ {
+ *lval = 0;
+ strcpy(msg,"Error in ffc2l evaluating string as a logical: ");
+ strncat(msg,cval,30);
+ ffpmsg(msg);
+ return(*status);
+ }
+
+ if (dtype == 'I')
+ {
+ if (ival)
+ *lval = 1;
+ else
+ *lval = 0;
+ }
+ else if (dtype == 'F')
+ {
+ if (dval)
+ *lval = 1;
+ else
+ *lval = 0;
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffc2r(char *cval, /* I - string representation of the value */
+ float *fval, /* O - numerical value of the input string */
+ int *status) /* IO - error status */
+/*
+ convert formatted string to a real float value, doing implicit
+ datatype conversion if necessary
+*/
+{
+ char dtype, sval[81], msg[81];
+ int lval;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ if (cval[0] == '\0')
+ return(*status = VALUE_UNDEFINED); /* null value string */
+
+ ffdtyp(cval, &dtype, status); /* determine the datatype */
+
+ if (dtype == 'I' || dtype == 'F')
+ ffc2rr(cval, fval, status);
+ else if (dtype == 'L')
+ {
+ ffc2ll(cval, &lval, status);
+ *fval = (float) lval;
+ }
+ else if (dtype == 'C')
+ {
+ /* try reading the string as a number */
+ ffc2s(cval, sval, status);
+ ffc2rr(sval, fval, status);
+ }
+ else
+ *status = BAD_FLOATKEY;
+
+ if (*status > 0)
+ {
+ *fval = 0.;
+ strcpy(msg,"Error in ffc2r evaluating string as a float: ");
+ strncat(msg,cval,30);
+ ffpmsg(msg);
+ return(*status);
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffc2d(char *cval, /* I - string representation of the value */
+ double *dval, /* O - numerical value of the input string */
+ int *status) /* IO - error status */
+/*
+ convert formatted string to a double value, doing implicit
+ datatype conversion if necessary
+*/
+{
+ char dtype, sval[81], msg[81];
+ int lval;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ if (cval[0] == '\0')
+ return(*status = VALUE_UNDEFINED); /* null value string */
+
+ ffdtyp(cval, &dtype, status); /* determine the datatype */
+
+ if (dtype == 'I' || dtype == 'F')
+ ffc2dd(cval, dval, status);
+ else if (dtype == 'L')
+ {
+ ffc2ll(cval, &lval, status);
+ *dval = (double) lval;
+ }
+ else if (dtype == 'C')
+ {
+ /* try reading the string as a number */
+ ffc2s(cval, sval, status);
+ ffc2dd(sval, dval, status);
+ }
+ else
+ *status = BAD_DOUBLEKEY;
+
+ if (*status > 0)
+ {
+ *dval = 0.;
+ strcpy(msg,"Error in ffc2d evaluating string as a double: ");
+ strncat(msg,cval,30);
+ ffpmsg(msg);
+ return(*status);
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffc2ii(char *cval, /* I - string representation of the value */
+ long *ival, /* O - numerical value of the input string */
+ int *status) /* IO - error status */
+/*
+ convert null-terminated formatted string to an integer value
+*/
+{
+ char *loc, msg[81];
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ errno = 0;
+ *ival = 0;
+ *ival = strtol(cval, &loc, 10); /* read the string as an integer */
+
+ /* check for read error, or junk following the integer */
+ if (*loc != '\0' && *loc != ' ' )
+ *status = BAD_C2I;
+
+ if (errno == ERANGE)
+ {
+ strcpy(msg,"Range Error in ffc2ii converting string to long int: ");
+ strncat(msg,cval,25);
+ ffpmsg(msg);
+
+ *status = NUM_OVERFLOW;
+ errno = 0;
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffc2ll(char *cval, /* I - string representation of the value: T or F */
+ int *lval, /* O - numerical value of the input string: 1 or 0 */
+ int *status) /* IO - error status */
+/*
+ convert null-terminated formatted string to a logical value
+*/
+{
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ if (cval[0] == 'T')
+ *lval = 1;
+ else
+ *lval = 0; /* any character besides T is considered false */
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffc2s(char *instr, /* I - null terminated quoted input string */
+ char *outstr, /* O - null terminated output string without quotes */
+ int *status) /* IO - error status */
+/*
+ convert an input quoted string to an unquoted string by removing
+ the leading and trailing quote character. Also, replace any
+ pairs of single quote characters with just a single quote
+ character (FITS used a pair of single quotes to represent
+ a literal quote character within the string).
+*/
+{
+ int jj;
+ size_t len, ii;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ if (instr[0] != '\'')
+ {
+ strcpy(outstr, instr); /* no leading quote, so return input string */
+ return(*status);
+ }
+
+ len = strlen(instr);
+
+ for (ii=1, jj=0; ii < len; ii++, jj++)
+ {
+ if (instr[ii] == '\'') /* is this the closing quote? */
+ {
+ if (instr[ii+1] == '\'') /* 2 successive quotes? */
+ ii++; /* copy only one of the quotes */
+ else
+ break; /* found the closing quote, so exit this loop */
+ }
+ outstr[jj] = instr[ii]; /* copy the next character to the output */
+ }
+
+ outstr[jj] = '\0'; /* terminate the output string */
+
+ if (ii == len)
+ {
+ ffpmsg("This string value has no closing quote (ffc2s):");
+ ffpmsg(instr);
+ return(*status = 205);
+ }
+
+ for (jj--; jj >= 0; jj--) /* replace trailing blanks with nulls */
+ {
+ if (outstr[jj] == ' ')
+ outstr[jj] = 0;
+ else
+ break;
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffc2rr(char *cval, /* I - string representation of the value */
+ float *fval, /* O - numerical value of the input string */
+ int *status) /* IO - error status */
+/*
+ convert null-terminated formatted string to a float value
+*/
+{
+ char *loc, msg[81];
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ errno = 0;
+ *fval = 0.;
+ *fval = (float) strtod(cval, &loc); /* read the string as an float */
+
+ /* check for read error, or junk following the value */
+ if (*loc != '\0' && *loc != ' ' )
+ {
+ strcpy(msg,"Error in ffc2rr converting string to float: ");
+ strncat(msg,cval,30);
+ ffpmsg(msg);
+
+ *status = BAD_C2F;
+ }
+
+ if (errno == ERANGE)
+ {
+ strcpy(msg,"Error in ffc2rr converting string to float: ");
+ strncat(msg,cval,30);
+ ffpmsg(msg);
+
+ *status = NUM_OVERFLOW;
+ errno = 0;
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffc2dd(char *cval, /* I - string representation of the value */
+ double *dval, /* O - numerical value of the input string */
+ int *status) /* IO - error status */
+/*
+ convert null-terminated formatted string to a double value
+*/
+{
+ char msg[81], tval[73], *loc;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+
+ strcpy(tval, cval);
+ loc = strchr(tval, 'D');
+
+ if (loc) /* The C language does not support a 'D' */
+ *loc = 'E'; /* exponent so replace any D's with E's. */
+ errno = 0;
+ *dval = 0.;
+ *dval = strtod(tval, &loc); /* read the string as an double */
+
+ /* check for read error, or junk following the value */
+ if (*loc != '\0' && *loc != ' ' )
+ {
+ strcpy(msg,"Error in ffc2dd converting string to double: ");
+ strncat(msg,cval,30);
+ ffpmsg(msg);
+
+ *status = BAD_C2D;
+ }
+
+ if (errno == ERANGE)
+ {
+ strcpy(msg,"Error in ffc2dd converting string to double: ");
+ strncat(msg,cval,30);
+ ffpmsg(msg);
+
+ *status = NUM_OVERFLOW;
+ errno = 0;
+ }
+
+ return(*status);
+}
+
diff --git a/pkg/tbtables/cfitsio/fitsio.doc b/pkg/tbtables/cfitsio/fitsio.doc
new file mode 100644
index 00000000..4f639330
--- /dev/null
+++ b/pkg/tbtables/cfitsio/fitsio.doc
@@ -0,0 +1,6137 @@
+ FITSIO - An Interface to FITS Format Files for Fortran Programmers
+
+ William D Pence, HEASARC, NASA/GSFC
+ Version 2.4
+
+
+[Note: This file contains various formatting command symbols in the first
+column which are used when generating the LATeX version of this document.]
+
+*I. Introduction
+
+This document describes the Fortran-callable subroutine interface that
+is provided as part of the CFITSIO library (which is written in ANSI
+C). This is a companion document to the CFITSIO User's Guide which
+should be consulted for further information about the underlying
+CFITSIO library. In the remainder of this document, the terms FITSIO
+and CFITSIO are interchangeable and refer to the same library.
+
+FITSIO/CFITSIO is a machine-independent library of routines for reading
+and writing data files in the FITS (Flexible Image Transport System)
+data format. It can also read IRAF format image files and raw binary
+data arrays by converting them on the fly into a virtual FITS format
+file. This library was written to provide a powerful yet simple
+interface for accessing FITS files which will run on most commonly used
+computers and workstations. FITSIO supports all the features described
+in the official NOST definition of the FITS format and can read and
+write all the currently defined types of extensions, including ASCII
+tables (TABLE), Binary tables (BINTABLE) and IMAGE extensions. The
+FITSIO subroutines insulate the programmer from having to deal with the
+complicated formatting details in the FITS file, however, it is assumed
+that users have a general knowledge about the structure and usage of
+FITS files.
+
+The CFITSIO package was initially developed by the HEASARC (High Energy
+Astrophysics Science Archive Research Center) at the NASA Goddard Space
+Flight Center to convert various existing and newly acquired
+astronomical data sets into FITS format and to further analyze data
+already in FITS format. New features continue to be added to CFITSIO
+in large part due to contributions of ideas or actual code from users
+of the package. The Integral Science Data Center in Switzerland, and
+the XMM/ESTEC project in The Netherlands made especially significant
+contributions that resulted in many of the new features that appeared
+in v2.0 of CFITSIO.
+
+The latest version of the CFITSIO source code, documentation, and
+example programs are available on the World-Wide Web or via anonymous
+ftp from:
+-
+ http://heasarc.gsfc.nasa.gov/fitsio
+ ftp://legacy.gsfc.nasa.gov/software/fitsio/c
+-
+\newpage
+Any questions, bug reports, or suggested enhancements related to the CFITSIO
+package should be sent to the primary author:
+-
+ Dr. William Pence Telephone: (301) 286-4599
+ HEASARC, Code 662 E-mail: pence@tetra.gsfc.nasa.gov
+ NASA/Goddard Space Flight Center
+ Greenbelt, MD 20771, USA
+-
+This User's Guide assumes that readers already have a general
+understanding of the definition and structure of FITS format files.
+Further information about FITS formats is available from the FITS Support
+Office at {\tt http://fits.gsfc.nasa.gov}. In particular, the
+'NOST FITS Standard' gives the authoritative definition of the FITS data
+format, and the `FITS User's Guide' provides additional historical background
+and practical advice on using FITS files.
+
+CFITSIO users may also be interested in the FTOOLS package of programs
+that can be used to manipulate and analyze FITS format files.
+Information about FTOOLS can be obtained on the Web or via anonymous
+ftp at:
+-
+ http://heasarc.gsfc.nasa.gov/ftools
+ ftp://legacy.gsfc.nasa.gov/software/ftools/release
+-
+
+*II. Creating FITSIO/CFITSIO
+
+**A. Building the Library
+
+To use the FITSIO subroutines one must first build the CFITSIO library,
+which requires a C compiler. gcc is ideal, or most other ANSI-C
+compilers will also work. The CFITSIO code is contained in about 40 C
+source files (*.c) and header files (*.h). On VAX/VMS systems 2
+assembly-code files (vmsieeed.mar and vmsieeer.mar) are also needed.
+
+The Fortran interface subroutines to the C CFITSIO routines are located
+in the f77\_wrap1.c, through f77\_wrap4.c files. These are relatively simple
+'wrappers' that translate the arguments in the Fortran subroutine into
+the appropriate format for the corresponding C routine. This
+translation is performed transparently to the user by a set of C macros
+located in the cfortran.h file. Unfortunately cfortran.h does not
+support every combination of C and Fortran compilers so the Fortran
+interface is not supported on all platforms. (see further notes below).
+
+A standard combination of C and Fortran compilers will be assumed by
+default, but one may also specify a particular Fortran compiler by
+doing:
+-
+ > setenv CFLAGS -DcompilerName=1
+-
+(where 'compilerName' is the name of the compiler) before running
+the configure command. The currently recognized compiler
+names are:
+-
+ g77Fortran
+ IBMR2Fortran
+ CLIPPERFortran
+ pgiFortran
+ NAGf90Fortran
+ f2cFortran
+ hpuxFortran
+ apolloFortran
+ sunFortran
+ CRAYFortran
+ mipsFortran
+ DECFortran
+ vmsFortran
+ CONVEXFortran
+ PowerStationFortran
+ AbsoftUNIXFortran
+ AbsoftProFortran
+ SXFortran
+-
+Alternatively, one may edit the CFLAGS line in the Makefile to add the
+'-DcompilerName' flag after running the './configure' command.
+
+The CFITSIO library is built on Unix systems by typing:
+-
+ > ./configure [--prefix=/target/installation/path]
+ > make (or 'make shared')
+ > make install (this step is optional)
+-
+at the operating system prompt. The configure command customizes the
+Makefile for the particular system, then the `make' command compiles the
+source files and builds the library. Type `./configure' and not simply
+`configure' to ensure that the configure script in the current directory
+is run and not some other system-wide configure script. The optional
+'prefix' argument to configure gives the path to the directory where
+the CFITSIO library and include files should be installed via the later
+'make install' command. For example,
+-
+ > ./configure --prefix=/usr1/local
+-
+will cause the 'make install' command to copy the CFITSIO libcfitsio file
+to /usr1/local/lib and the necessary include file to /usr1/local/include
+(assuming of course that the process has permission to write to these
+directories).
+
+By default this also builds the set of Fortran-callable
+wrapper routines whose calling sequences are described later in this
+document.
+
+The 'make shared' option builds a shared or dynamic version of the
+CFITSIO library. When using the shared library the executable code is
+not copied into your program at link time and instead the program
+locates the necessary library code at run time, normally through
+LD\_LIBRARY\_PATH or some other method. The advantages of using a shared
+library are:
+-
+ 1. Less disk space if you build more than 1 program
+ 2. Less memory if more than one copy of a program using the shared
+ library is running at the same time since the system is smart
+ enough to share copies of the shared library at run time.
+ 3. Possibly easier maintenance since a new version of the shared
+ library can be installed without relinking all the software
+ that uses it (as long as the subroutine names and calling
+ sequences remain unchanged).
+ 4. No run-time penalty.
+-
+The disadvantages are:
+-
+ 1. More hassle at runtime. You have to either build the programs
+ specially or have LD_LIBRARY_PATH set right.
+ 2. There may be a slight start up penalty, depending on where you are
+ reading the shared library and the program from and if your CPU is
+ either really slow or really heavily loaded.
+-
+
+On HP/UX systems, the environment variable CFLAGS should be set
+to -Ae before running configure to enable "extended ANSI" features.
+
+It may not be possible to staticly link programs that use CFITSIO on
+some platforms (namely, on Solaris 2.6) due to the network drivers
+(which provide FTP and HTTP access to FITS files). It is possible to
+make both a dynamic and a static version of the CFITSIO library, but
+network file access will not be possible using the static version.
+
+On VAX/VMS and ALPHA/VMS systems the make\_gfloat.com command file may
+be executed to build the cfitsio.olb object library using the default
+G-floating point option for double variables. The make\_dfloat.com and
+make\_ieee.com files may be used instead to build the library with the
+other floating point options. Note that the getcwd function that is
+used in the group.c module may require that programs using CFITSIO be
+linked with the ALPHA\$LIBRARY:VAXCRTL.OLB library. See the example
+link line in the next section of this document.
+
+On Windows IBM-PC type platforms the situation is more complicated
+because of the wide variety of Fortran compilers that are available and
+because of the inherent complexities of calling the CFITSIO C routines
+from Fortran. Two different versions of the CFITSIO dll library are
+available, compiled with the Borland C++ compiler and the Microsoft
+Visual C++ compiler, respectively, in the files
+cfitsiodll\_2xxx\_borland.zip and cfitsiodll\_2xxx\_vcc.zip, where
+'2xxx' represents the current release number. Both these dll libraries
+contain a set of Fortran wrapper routines which may be compatible with
+some, but probably not all, available Fortran compilers. To test if
+they are compatible, compile the program testf77.f and try linking to
+these dll libraries. If these libraries do not work with a particular
+Fortran compiler, then there are 2 possible solutions. The first
+solution would be to modify the file cfortran.h for that particular
+combination of C and Fortran compilers, and then rebuild the CFITSIO
+dll library. This will require, however, a some expertise in
+mixed language programming.
+The other solution is to use the older v5.03 Fortran-77 implementation
+of FITSIO that is still available from the FITSIO web-site. This
+version is no longer supported, but it does provide the basic functions
+for reading and writing FITS files and should be compatible with most
+Fortran compilers.
+
+CFITSIO has currently been tested on the following platforms:
+-
+ OPERATING SYSTEM COMPILER
+ Sun OS gcc and cc (3.0.1)
+ Sun Solaris gcc and cc
+ Silicon Graphics IRIX gcc and cc
+ Silicon Graphics IRIX64 MIPS
+ Dec Alpha OSF/1 gcc and cc
+ DECstation Ultrix gcc
+ Dec Alpha OpenVMS cc
+ DEC VAX/VMS gcc and cc
+ HP-UX gcc
+ IBM AIX gcc
+ Linux gcc
+ MkLinux DR3
+ Windows 95/98/NT Borland C++ V4.5
+ Windows 95/98/NT/ME/XP Microsoft/Compaq Visual C++ v5.0, v6.0
+ Windows 95/98/NT Cygwin gcc
+ OS/2 gcc + EMX
+ MacOS 7.1 or greater Metrowerks 10.+
+-
+CFITSIO will probably run on most other Unix platforms. Cray
+supercomputers are currently not supported.
+
+**B. Testing the Library
+
+The CFITSIO library should be tested by building and running
+the testprog.c program that is included with the release.
+On Unix systems type:
+-
+ % make testprog
+ % testprog > testprog.lis
+ % diff testprog.lis testprog.out
+ % cmp testprog.fit testprog.std
+-
+ On VMS systems,
+(assuming cc is the name of the C compiler command), type:
+-
+ $ cc testprog.c
+ $ link testprog, cfitsio/lib, alpha$library:vaxcrtl/lib
+ $ run testprog
+-
+The testprog program should produce a FITS file called `testprog.fit'
+that is identical to the `testprog.std' FITS file included with this
+release. The diagnostic messages (which were piped to the file
+testprog.lis in the Unix example) should be identical to the listing
+contained in the file testprog.out. The 'diff' and 'cmp' commands
+shown above should not report any differences in the files. (There
+may be some minor formatting differences, such as the presence or
+absence of leading zeros, or 3 digit exponents in numbers,
+which can be ignored).
+
+The Fortran wrappers in CFITSIO may be tested with the testf77
+program. On Unix systems the fortran compilation and link command
+may be called 'f77' or 'g77', depending on the system.
+-
+ % f77 -o testf77 testf77.f -L. -lcfitsio -lnsl -lsocket
+ or
+ % f77 -f -o testf77 testf77.f -L. -lcfitsio (under SUN O/S)
+ or
+ % f77 -o testf77 testf77.f -Wl,-L. -lcfitsio -lm -lnsl -lsocket (HP/UX)
+ or
+ % g77 -o testf77 -s testf77.f -lcfitsio -lcc_dynamic -lncurses (Mac OS-X)
+
+ % testf77 > testf77.lis
+ % diff testf77.lis testf77.out
+ % cmp testf77.fit testf77.std
+-
+On machines running SUN O/S, Fortran programs must be compiled with the
+'-f' option to force double precision variables to be aligned on 8-byte
+boundarys to make the fortran-declared variables compatible with C. A
+similar compiler option may be required on other platforms. Failing to
+use this option may cause the program to crash on FITSIO routines that
+read or write double precision variables.
+
+Also note that on some systems, the output listing of the testf77
+program may differ slightly from the testf77.std template, if leading
+zeros are not printed by default before the decimal point when using F
+format.
+
+A few other utility programs are included with CFITSIO:
+-
+ speed - measures the maximum throughput (in MB per second)
+ for writing and reading FITS files with CFITSIO
+
+ listhead - lists all the header keywords in any FITS file
+
+ fitscopy - copies any FITS file (especially useful in conjunction
+ with the CFITSIO's extended input filename syntax)
+
+ cookbook - a sample program that peforms common read and
+ write operations on a FITS file.
+
+ iter_a, iter_b, iter_c - examples of the CFITSIO iterator routine
+-
+
+The first 4 of these utility programs can be compiled and linked by typing
+-
+ % make program_name
+-
+
+**C. Linking Programs with FITSIO
+
+When linking applications software with the FITSIO library, several system libraries usually need to be specified on the link command line. On
+Unix systems, the most reliable way to determine what libraries are required
+is to type 'make testprog' and see what libraries the configure script has
+added. The typical libraries that may need to be added are -lm (the math
+library) and -lnsl and -lsocket (needed only for FTP and HTTP file access).
+These latter 2 libraries are not needed on VMS and Windows platforms,
+because FTP file access is not currently supported on those platforms.
+
+Note that when upgrading to a newer version of CFITSIO it is usually
+necessay to recompile, as well as relink, the programs that use CFITSIO,
+because the definitions in fitsio.h often change.
+
+**D. Getting Started with FITSIO
+
+In order to effectively use the FITSIO library as quickly as possible,
+it is recommended that new users follow these steps:
+
+1. Read the following `FITS Primer' chapter for a brief
+overview of the structure of FITS files. This is especially important
+for users who have not previously dealt with the FITS table and image
+extensions.
+
+2. Write a simple program to read or write a FITS file using the Basic
+Interface routines.
+
+3. Refer to the cookbook.f program that is included with this release
+for examples of routines that perform various common FITS file
+operations.
+
+4. Read Chapters 4 and 5 to become familiar with the conventions and
+advanced features of the FITSIO interface.
+
+5. Scan through the more extensive set of routines that are provided
+in the `Advanced Interface'. These routines perform more specialized
+functions than are provided by the Basic Interface routines.
+
+**E. Example Program
+
+The following listing shows an example of how to use the FITSIO
+routines in a Fortran program. Refer to the cookbook.f program that
+is included with the FITSIO distribution for examples of other
+FITS programs.
+-
+ program writeimage
+
+C Create a FITS primary array containing a 2-D image
+
+ integer status,unit,blocksize,bitpix,naxis,naxes(2)
+ integer i,j,group,fpixel,nelements,array(300,200)
+ character filename*80
+ logical simple,extend
+
+ status=0
+C Name of the FITS file to be created:
+ filename='ATESTFILE.FITS'
+
+C Get an unused Logical Unit Number to use to create the FITS file
+ call ftgiou(unit,status)
+
+C create the new empty FITS file
+ blocksize=1
+ call ftinit(unit,filename,blocksize,status)
+
+C initialize parameters about the FITS image (300 x 200 16-bit integers)
+ simple=.true.
+ bitpix=16
+ naxis=2
+ naxes(1)=300
+ naxes(2)=200
+ extend=.true.
+
+C write the required header keywords
+ call ftphpr(unit,simple,bitpix,naxis,naxes,0,1,extend,status)
+
+C initialize the values in the image with a linear ramp function
+ do j=1,naxes(2)
+ do i=1,naxes(1)
+ array(i,j)=i+j
+ end do
+ end do
+
+C write the array to the FITS file
+ group=1
+ fpixel=1
+ nelements=naxes(1)*naxes(2)
+ call ftpprj(unit,group,fpixel,nelements,array,status)
+
+C write another optional keyword to the header
+ call ftpkyj(unit,'EXPOSURE',1500,'Total Exposure Time',status)
+
+C close the file and free the unit number
+ call ftclos(unit, status)
+ call ftfiou(unit, status)
+ end
+-
+
+**F. Legal Stuff
+
+Copyright (Unpublished--all rights reserved under the copyright laws of
+the United States), U.S. Government as represented by the Administrator
+of the National Aeronautics and Space Administration. No copyright is
+claimed in the United States under Title 17, U.S. Code.
+
+Permission to freely use, copy, modify, and distribute this software
+and its documentation without fee is hereby granted, provided that this
+copyright notice and disclaimer of warranty appears in all copies.
+(However, see the restriction on the use of the gzip compression code,
+below).
+
+DISCLAIMER:
+
+THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND,
+EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO,
+ANY WARRANTY THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY
+IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE, AND FREEDOM FROM INFRINGEMENT, AND ANY WARRANTY THAT THE
+DOCUMENTATION WILL CONFORM TO THE SOFTWARE, OR ANY WARRANTY THAT THE
+SOFTWARE WILL BE ERROR FREE. IN NO EVENT SHALL NASA BE LIABLE FOR ANY
+DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, INDIRECT, SPECIAL OR
+CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, OR IN ANY WAY
+CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY,
+CONTRACT, TORT , OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY
+PERSONS OR PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED
+FROM, OR AROSE OUT OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR
+SERVICES PROVIDED HEREUNDER."
+
+The file compress.c contains (slightly modified) source code that
+originally came from gzip-1.2.4, copyright (C) 1992-1993 by Jean-loup
+Gailly. This gzip code is distributed under the GNU General Public
+License and thus requires that any software that uses the CFITSIO
+library (which in turn uses the gzip code) must conform to the
+provisions in the GNU General Public License. A copy of the GNU
+license is included at the beginning of compress.c file.
+
+An alternate version of the compress.c file (called
+compress\_alternate.c) is provided for users who want to use the CFITSIO
+library but are unwilling or unable to publicly release their software
+under the terms of the GNU General Public License. This alternate
+version contains non-functional stubs for the file compression and
+uncompression routines used by CFITSIO. Replace the file `compress.c'
+with `compress\_alternate.c' before compiling the CFITSIO library. This
+will produce a version of CFITSIO which does not support reading or
+writing compressed FITS files but is otherwise identical to the
+standard version.
+
+**G. Acknowledgements
+
+The development of many of the powerful features in CFITSIO was made
+possible through collaborations with many people or organizations from
+around the world. The following, in particular, have made especially
+significant contributions:
+
+Programmers from the Integral Science Data Center, Switzerland (namely,
+Jurek Borkowski, Bruce O'Neel, and Don Jennings), designed the concept
+for the plug-in I/O drivers that was introduced with CFITSIO 2.0. The
+use of `drivers' greatly simplified the low-level I/O, which in turn
+made other new features in CFITSIO (e.g., support for compressed FITS
+files and support for IRAF format image files) much easier to
+implement. Jurek Borkowski wrote the Shared Memory driver, and Bruce
+O'Neel wrote the drivers for accessing FITS files over the network
+using the FTP, HTTP, and ROOT protocols.
+
+The ISDC also provided the template parsing routines (written by Jurek
+Borkowski) and the hierarchical grouping routines (written by Don
+Jennings). The ISDC DAL (Data Access Layer) routines are layered on
+top of CFITSIO and make extensive use of these features.
+
+Uwe Lammers (XMM/ESA/ESTEC, The Netherlands) designed the
+high-performance lexical parsing algorithm that is used to do
+on-the-fly filtering of FITS tables. This algorithm essentially
+pre-compiles the user-supplied selection expression into a form that
+can be rapidly evaluated for each row. Peter Wilson (RSTX, NASA/GSFC)
+then wrote the parsing routines used by CFITSIO based on Lammers'
+design, combined with other techniques such as the CFITSIO iterator
+routine to further enhance the data processing throughput. This effort
+also benefited from a much earlier lexical parsing routine that was
+developed by Kent Blackburn (NASA/GSFC). More recently, Craig Markwardt
+(NASA/GSFC) implemented additional functions (median, average, stddev)
+and other enhancements to the lexical parser.
+
+The CFITSIO iterator function is loosely based on similar ideas
+developed for the XMM Data Access Layer.
+
+Peter Wilson (RSTX, NASA/GSFC) wrote the complete set of
+Fortran-callable wrappers for all the CFITSIO routines, which in turn
+rely on the CFORTRAN macro developed by Burkhard Burow.
+
+The syntax used by CFITSIO for filtering or binning input FITS files is
+based on ideas developed for the AXAF Science Center Data Model by
+Jonathan McDowell, Antonella Fruscione, Aneta Siemiginowska and Bill
+Joye. See http://heasarc.gsfc.nasa.gov/docs/journal/axaf7.html for
+further description of the AXAF Data Model.
+
+The file decompression code were taken directly from the gzip (GNU zip)
+program developed by Jean-loup Gailly and others.
+
+Doug Mink, SAO, provided the routines for converting IRAF format
+images into FITS format.
+
+In addition, many other people have made valuable contributions to the
+development of CFITSIO. These include (with apologies to others that may
+have inadvertently been omitted):
+
+Steve Allen, Carl Akerlof, Keith Arnaud, Morten Krabbe Barfoed, Kent
+Blackburn, G Bodammer, Romke Bontekoe, Lucio Chiappetti, Keith Costorf,
+Robin Corbet, John Davis, Richard Fink, Ning Gan, Emily Greene, Joe
+Harrington, Cheng Ho, Phil Hodge, Jim Ingham, Yoshitaka Ishisaki, Diab
+Jerius, Mark Levine, Todd Karakaskian, Edward King, Scott Koch, Claire
+Larkin, Rob Managan, Eric Mandel, John Mattox, Carsten Meyer, Emi
+Miyata, Stefan Mochnacki, Mike Noble, Oliver Oberdorf, Clive Page,
+Arvind Parmar, Jeff Pedelty, Tim Pearson, Maren Purves, Scott Randall,
+Chris Rogers, Arnold Rots, Barry Schlesinger, Robin Stebbins, Andrew
+Szymkowiak, Allyn Tennant, Peter Teuben, James Theiler, Doug Tody,
+Shiro Ueno, Steve Walton, Archie Warnock, Alan Watson, Dan Whipple, Wim
+Wimmers, Peter Young, Jianjun Xu, and Nelson Zarate.
+
+
+*III. A FITS Primer
+
+This section gives a brief overview of the structure of FITS files.
+Users should refer to the documentation available from the NOST, as
+described in the introduction, for more detailed information on FITS
+formats.
+
+FITS was first developed in the late 1970's as a standard data
+interchange format between various astronomical observatories. Since
+then FITS has become the defacto standard data format supported by most
+astronomical data analysis software packages.
+
+A FITS file consists of one or more Header + Data Units (HDUs), where
+the first HDU is called the `Primary HDU', or `Primary Array'. The
+primary array contains an N-dimensional array of pixels, such as a 1-D
+spectrum, a 2-D image, or a 3-D data cube. Five different primary
+datatypes are supported: Unsigned 8-bit bytes, 16 and 32-bit signed
+integers, and 32 and 64-bit floating point reals. FITS also has a
+convention for storing 16 and 32-bit unsigned integers (see the later
+section entitled `Unsigned Integers' for more details). The primary HDU
+may also consist of only a header with a null array containing no
+data pixels.
+
+Any number of additional HDUs may follow the primary array; these
+additional HDUs are called FITS `extensions'. There are currently 3
+types of extensions defined by the FITS standard:
+
+\begin{itemize}
+\item
+ Image Extension - a N-dimensional array of pixels, like in a primary array
+\item
+ ASCII Table Extension - rows and columns of data in ASCII character format
+\item
+ Binary Table Extension - rows and columns of data in binary representation
+\end{itemize}
+
+In each case the HDU consists of an ASCII Header Unit followed by an optional
+Data Unit. For historical reasons, each Header or Data unit must be an
+exact multiple of 2880 8-bit bytes long. Any unused space is padded
+with fill characters (ASCII blanks or zeros).
+
+Each Header Unit consists of any number of 80-character keyword records
+or `card images' which have the general form:
+-
+ KEYNAME = value / comment string
+ NULLKEY = / comment: This keyword has no value
+-
+The keyword names may be up to 8 characters long and can only contain
+uppercase letters, the digits 0-9, the hyphen, and the underscore
+character. The keyword name is (usually) followed by an equals sign and
+a space character (= ) in columns 9 - 10 of the record, followed by the
+value of the keyword which may be either an integer, a floating point
+number, a character string (enclosed in single quotes), or a boolean
+value (the letter T or F). A keyword may also have a null or undefined
+value if there is no specified value string, as in the second example.
+
+The last keyword in the header is always the `END' keyword which has no
+value or comment fields. There are many rules governing the exact
+format of a keyword record (see the NOST FITS Standard) so it is better
+to rely on standard interface software like FITSIO to correctly
+construct or to parse the keyword records rather than try to deal
+directly with the raw FITS formats.
+
+Each Header Unit begins with a series of required keywords which depend
+on the type of HDU. These required keywords specify the size and
+format of the following Data Unit. The header may contain other
+optional keywords to describe other aspects of the data, such as the
+units or scaling values. Other COMMENT or HISTORY keywords are also
+frequently added to further document the data file.
+
+The optional Data Unit immediately follows the last 2880-byte block in
+the Header Unit. Some HDUs do not have a Data Unit and only consist of
+the Header Unit.
+
+If there is more than one HDU in the FITS file, then the Header Unit of
+the next HDU immediately follows the last 2880-byte block of the
+previous Data Unit (or Header Unit if there is no Data Unit).
+
+The main required keywords in FITS primary arrays or image extensions are:
+\begin{itemize}
+\item
+BITPIX -- defines the datatype of the array: 8, 16, 32, -32, -64 for
+unsigned 8--bit byte, 16--bit signed integer, 32--bit signed integer,
+32--bit IEEE floating point, and 64--bit IEEE double precision floating
+point, respectively.
+\item
+NAXIS -- the number of dimensions in the array, usually 0, 1, 2, 3, or 4.
+\item
+NAXISn -- (n ranges from 1 to NAXIS) defines the size of each dimension.
+\end{itemize}
+
+FITS tables start with the keyword XTENSION = `TABLE' (for ASCII
+tables) or XTENSION = `BINTABLE' (for binary tables) and have the
+following main keywords:
+\begin{itemize}
+\item
+TFIELDS -- number of fields or columns in the table
+\item
+NAXIS2 -- number of rows in the table
+\item
+TTYPEn -- for each column (n ranges from 1 to TFIELDS) gives the
+name of the column
+\item
+TFORMn -- the datatype of the column
+\item
+TUNITn -- the physical units of the column (optional)
+\end{itemize}
+
+Users should refer to the FITS Support Office at {\tt http://fits.gsfc.nasa.gov}
+for futher information about the FITS format and related software
+packages.
+
+
+*IV. Extended File Name Syntax
+
+**A. Overview
+
+CFITSIO supports an extended syntax when specifying the name of the
+data file to be opened or created that includes the following
+features:
+
+\begin{itemize}
+\item
+CFITSIO can read IRAF format images which have header file names that
+end with the '.imh' extension, as well as reading and writing FITS
+files, This feature is implemented in CFITSIO by first converting the
+IRAF image into a temporary FITS format file in memory, then opening
+the FITS file. Any of the usual CFITSIO routines then may be used to
+read the image header or data. Similarly, raw binary data arrays can
+be read by converting them on the fly into virtual FITS images.
+
+\item
+FITS files on the internet can be read (and sometimes written) using the FTP,
+HTTP, or ROOT protocols.
+
+\item
+FITS files can be piped between tasks on the stdin and stdout streams.
+
+\item
+FITS files can be read and written in shared memory. This can potentially
+achieve much better data I/O performance compared to reading and
+writing the same FITS files on magnetic disk.
+
+\item
+Compressed FITS files in gzip or Unix COMPRESS format can be directly read.
+
+\item
+Output FITS files can be written directly in compressed gzip format,
+thus saving disk space.
+
+\item
+FITS table columns can be created, modified, or deleted 'on-the-fly' as
+the table is opened by CFITSIO. This creates a virtual FITS file containing
+the modifications that is then opened by the application program.
+
+\item
+Table rows may be selected, or filtered out, on the fly when the table
+is opened by CFITSIO, based on an arbitrary user-specified expression.
+Only rows for which the expression evaluates to 'TRUE' are retained
+in the copy of the table that is opened by the application program.
+
+\item
+Histogram images may be created on the fly by binning the values in
+table columns, resulting in a virtual N-dimensional FITS image. The
+application program then only sees the FITS image (in the primary
+array) instead of the original FITS table.
+\end{itemize}
+
+The latter 3 features in particular add very powerful data processing
+capabilities directly into CFITSIO, and hence into every task that uses
+CFITSIO to read or write FITS files. For example, these features
+transform a very simple program that just copies an input FITS file to
+a new output file (like the `fitscopy' program that is distributed with
+CFITSIO) into a multipurpose FITS file processing tool. By appending
+fairly simple qualifiers onto the name of the input FITS file, the user
+can perform quite complex table editing operations (e.g., create new
+columns, or filter out rows in a table) or create FITS images by
+binning or histogramming the values in table columns. In addition,
+these functions have been coded using new state-of-the art algorithms
+that are, in some cases, 10 - 100 times faster than previous widely
+used implementations.
+
+Before describing the complete syntax for the extended FITS file names
+in the next section, here are a few examples of FITS file names that
+give a quick overview of the allowed syntax:
+
+\begin{itemize}
+\item
+{\tt 'myfile.fits'}: the simplest case of a FITS file on disk in the current
+directory.
+
+\item
+{\tt 'myfile.imh'}: opens an IRAF format image file and converts it on the
+fly into a temporary FITS format image in memory which can then be read with
+any other CFITSIO routine.
+
+\item
+{\tt rawfile.dat[i512,512]}: opens a raw binary data array (a 512 x 512
+short integer array in this case) and converts it on the fly into a
+temporary FITS format image in memory which can then be read with any
+other CFITSIO routine.
+
+\item
+{\tt myfile.fits.gz}: if this is the name of a new output file, the '.gz'
+suffix will cause it to be compressed in gzip format when it is written to
+disk.
+
+\item
+{\tt 'myfile.fits.gz[events, 2]'}: opens and uncompresses the gzipped file
+myfile.fits then moves to the extension which has the keywords EXTNAME
+= 'EVENTS' and EXTVER = 2.
+
+\item
+{\tt '-'}: a dash (minus sign) signifies that the input file is to be read
+from the stdin file stream, or that the output file is to be written to
+the stdout stream.
+
+\item
+{\tt 'ftp://legacy.gsfc.nasa.gov/test/vela.fits'}: FITS files in any ftp
+archive site on the internet may be directly opened with read-only
+access.
+
+\item
+{\tt 'http://legacy.gsfc.nasa.gov/software/test.fits'}: any valid URL to a
+FITS file on the Web may be opened with read-only access.
+
+\item
+{\tt 'root://legacy.gsfc.nasa.gov/test/vela.fits'}: similar to ftp access
+except that it provides write as well as read access to the files
+across the network. This uses the root protocol developed at CERN.
+
+\item
+{\tt 'shmem://h2[events]'}: opens the FITS file in a shared memory segment and
+moves to the EVENTS extension.
+
+\item
+{\tt 'mem://'}: creates a scratch output file in core computer memory. The
+resulting 'file' will disappear when the program exits, so this
+is mainly useful for testing purposes when one does not want a
+permanent copy of the output file.
+
+\item
+{\tt 'myfile.fits[3; Images(10)]'}: opens a copy of the image contained in the
+10th row of the 'Images' column in the binary table in the 3th extension
+of the FITS file. The application just sees this single image as the
+primary array.
+
+\item
+{\tt 'myfile.fits[1:512:2, 1:512:2]'}: opens a section of the input image
+ranging from the 1st to the 512th pixel in X and Y, and selects every
+second pixel in both dimensions, resulting in a 256 x 256 pixel image
+in this case.
+
+\item
+{\tt 'myfile.fits[EVENTS][col Rad = sqrt(X**2 + Y**2)]'}: creates and opens
+a temporary file on the fly (in memory or on disk) that is identical to
+myfile.fits except that it will contain a new column in the EVENTS
+extension called 'Rad' whose value is computed using the indicated
+expresson which is a function of the values in the X and Y columns.
+
+\item
+{\tt 'myfile.fits[EVENTS][PHA > 5]'}: creates and opens a temporary FITS
+files that is identical to 'myfile.fits' except that the EVENTS table
+will only contain the rows that have values of the PHA column greater
+than 5. In general, any arbitrary boolean expression using a C or
+Fortran-like syntax, which may combine AND and OR operators,
+may be used to select rows from a table.
+
+\item
+{\tt 'myfile.fits[EVENTS][bin (X,Y)=1,2048,4]'}: creates a temporary FITS
+primary array image which is computed on the fly by binning (i.e,
+computing the 2-dimensional histogram) of the values in the X and Y
+columns of the EVENTS extension. In this case the X and Y coordinates
+range from 1 to 2048 and the image pixel size is 4 units in both
+dimensions, so the resulting image is 512 x 512 pixels in size.
+
+\item
+The final example combines many of these feature into one complex
+expression (it is broken into several lines for clarity):
+-
+ 'ftp://legacy.gsfc.nasa.gov/data/sample.fits.gz[EVENTS]
+ [col phacorr = pha * 1.1 - 0.3][phacorr >= 5.0 && phacorr <= 14.0]
+ [bin (X,Y)=32]'
+-
+In this case, CFITSIO (1) copies and uncompresses the FITS file from
+the ftp site on the legacy machine, (2) moves to the 'EVENTS'
+extension, (3) calculates a new column called 'phacorr', (4) selects
+the rows in the table that have phacorr in the range 5 to 14, and
+finally (5) bins the remaining rows on the X and Y column coordinates,
+using a pixel size = 32 to create a 2D image. All this processing is
+completely transparent to the application program, which simply sees
+the final 2-D image in the primary array of the opened file.
+\end{itemize}
+
+The full extended CFITSIO FITS file name can contain several different
+components depending on the context. These components are described in
+the following sections:
+-
+When creating a new file:
+ filetype://BaseFilename(templateName)
+
+When opening an existing primary array or image HDU:
+ filetype://BaseFilename(outName)[HDUlocation][ImageSection]
+
+When opening an existing table HDU:
+ filetype://BaseFilename(outName)[HDUlocation][colFilter][rowFilter][binSpec]
+-
+The filetype, BaseFilename, outName, HDUlocation, and ImageSection
+components, if present, must be given in that order, but the colFilter,
+rowFilter, and binSpec specifiers may follow in any order. Regardless
+of the order, however, the colFilter specifier, if present, will be
+processed first by CFITSIO, followed by the rowFilter specifier, and
+finally by the binSpec specifier.
+
+**A. Filetype
+
+The type of file determines the medium on which the file is located
+(e.g., disk or network) and, hence, which internal device driver is used by
+CFITSIO to read and/or write the file. Currently supported types are
+-
+ file:// - file on local magnetic disk (default)
+ ftp:// - a readonly file accessed with the anonymous FTP protocol.
+ It also supports ftp://username:password@hostname/...
+ for accessing password-protected ftp sites.
+ http:// - a readonly file accessed with the HTTP protocol. It
+ does not support username:password like the ftp driver.
+ Proxy HTTP servers are supported using the http_proxy
+ environment variable.
+ root:// - uses the CERN root protocol for writing as well as
+ reading files over the network.
+ shmem:// - opens or creates a file which persists in the computer's
+ shared memory.
+ mem:// - opens a temporary file in core memory. The file
+ disappears when the program exits so this is mainly
+ useful for test purposes when a permanent output file
+ is not desired.
+-
+If the filetype is not specified, then type file:// is assumed.
+The double slashes '//' are optional and may be omitted in most cases.
+
+***1. Notes about HTTP proxy servers
+
+A proxy HTTP server may be used by defining the address (URL) and port
+number of the proxy server with the http\_proxy environment variable.
+For example
+-
+ setenv http_proxy http://heasarc.gsfc.nasa.gov:3128
+-
+will cause CFITSIO to use port 3128 on the heasarc proxy server whenever
+reading a FITS file with HTTP.
+
+***2. Notes about the root filetype
+
+The original rootd server can be obtained from:
+\verb-ftp://root.cern.ch/root/rootd.tar.gz-
+but, for it to work correctly with CFITSIO one has to use a modified
+version which supports a command to return the length of the file.
+This modified version is available in rootd subdirectory
+in the CFITSIO ftp area at
+-
+ ftp://legacy.gsfc.nasa.gov/software/fitsio/c/root/rootd.tar.gz.
+-
+
+This small server is started either by inetd when a client requests a
+connection to a rootd server or by hand (i.e. from the command line).
+The rootd server works with the ROOT TNetFile class. It allows remote
+access to ROOT database files in either read or write mode. By default
+TNetFile assumes port 432 (which requires rootd to be started as root).
+To run rootd via inetd add the following line to /etc/services:
+-
+ rootd 432/tcp
+-
+and to /etc/inetd.conf, add the following line:
+-
+ rootd stream tcp nowait root /user/rdm/root/bin/rootd rootd -i
+-
+Force inetd to reread its conf file with "kill -HUP <pid inetd>".
+You can also start rootd by hand running directly under your private
+account (no root system privileges needed). For example to start
+rootd listening on port 5151 just type: \verb+rootd -p 5151+
+Notice: no \& is needed. Rootd will go into background by itself.
+-
+ Rootd arguments:
+ -i says we were started by inetd
+ -p port# specifies a different port to listen on
+ -d level level of debug info written to syslog
+ 0 = no debug (default)
+ 1 = minimum
+ 2 = medium
+ 3 = maximum
+-
+Rootd can also be configured for anonymous usage (like anonymous ftp).
+To setup rootd to accept anonymous logins do the following (while being
+logged in as root):
+-
+ - Add the following line to /etc/passwd:
+
+ rootd:*:71:72:Anonymous rootd:/var/spool/rootd:/bin/false
+
+ where you may modify the uid, gid (71, 72) and the home directory
+ to suite your system.
+
+ - Add the following line to /etc/group:
+
+ rootd:*:72:rootd
+
+ where the gid must match the gid in /etc/passwd.
+
+ - Create the directories:
+
+ mkdir /var/spool/rootd
+ mkdir /var/spool/rootd/tmp
+ chmod 777 /var/spool/rootd/tmp
+
+ Where /var/spool/rootd must match the rootd home directory as
+ specified in the rootd /etc/passwd entry.
+
+ - To make writeable directories for anonymous do, for example:
+
+ mkdir /var/spool/rootd/pub
+ chown rootd:rootd /var/spool/rootd/pub
+-
+That's all. Several additional remarks: you can login to an anonymous
+server either with the names "anonymous" or "rootd". The password should
+be of type user@host.do.main. Only the @ is enforced for the time
+being. In anonymous mode the top of the file tree is set to the rootd
+home directory, therefore only files below the home directory can be
+accessed. Anonymous mode only works when the server is started via
+inetd.
+
+***3. Notes about the shmem filetype:
+
+Shared memory files are currently supported on most Unix platforms,
+where the shared memory segments are managed by the operating system
+kernel and `live' independently of processes. They are not deleted (by
+default) when the process which created them terminates, although they
+will disappear if the system is rebooted. Applications can create
+shared memory files in CFITSIO by calling:
+-
+ fit_create_file(&fitsfileptr, "shmem://h2", &status);
+-
+where the root `file' names are currently restricted to be 'h0', 'h1',
+'h2', 'h3', etc., up to a maximumn number defined by the the value of
+SHARED\_MAXSEG (equal to 16 by default). This is a prototype
+implementation of the shared memory interface and a more robust
+interface, which will have fewer restrictions on the number of files
+and on their names, may be developed in the future.
+
+When opening an already existing FITS file in shared memory one calls
+the usual CFITSIO routine:
+-
+ fits_open_file(&fitsfileptr, "shmem://h7", mode, &status)
+-
+The file mode can be READWRITE or READONLY just as with disk files.
+More than one process can operate on READONLY mode files at the same
+time. CFITSIO supports proper file locking (both in READONLY and
+READWRITE modes), so calls to fits\_open\_file may be locked out until
+another other process closes the file.
+
+When an application is finished accessing a FITS file in a shared
+memory segment, it may close it (and the file will remain in the
+system) with fits\_close\_file, or delete it with fits\_delete\_file.
+Physical deletion is postponed until the last process calls
+ffclos/ffdelt. fits\_delete\_file tries to obtain a READWRITE lock on
+the file to be deleted, thus it can be blocked if the object was not
+opened in READWRITE mode.
+
+A shared memory management utility program called `smem', is included
+with the CFITSIO distribution. It can be built by typing `make smem';
+then type `smem -h' to get a list of valid options. Executing smem
+without any options causes it to list all the shared memory segments
+currently residing in the system and managed by the shared memory
+driver. To get a list of all the shared memory objects, run the system
+utility program `ipcs [-a]'.
+
+**B. Base Filename
+
+The base filename is the name of the file optionally including the
+director/subdirectory path, and in the case of `ftp', `http', and `root'
+filetypes, the machine identifier. Examples:
+-
+ myfile.fits
+ !data.fits
+ /data/myfile.fits
+ fits.gsfc.nasa.gov/ftp/sampledata/myfile.fits.gz
+-
+
+When creating a new output file on magnetic disk (of type file://) if
+the base filename begins with an exclamation point (!) then any
+existing file with that same basename will be deleted prior to creating
+the new FITS file. Otherwise if the file to be created already exists,
+then CFITSIO will return an error and will not overwrite the existing
+file. Note that the exclamation point, '!', is a special UNIX character,
+so if it is used on the command line rather than entered at a task
+prompt, it must be preceded by a backslash to force the UNIX
+shell to pass it verbatim to the application program.
+
+If the output disk file name ends with the suffix '.gz', then CFITSIO
+will compress the file using the gzip compression algorithm before
+writing it to disk. This can reduce the amount of disk space used by
+the file. Note that this feature requires that the uncompressed file
+be constructed in memory before it is compressed and written to disk,
+so it can fail if there is insufficient available memory.
+
+An input FITS file may be compressed with the gzip or Unix compress
+algorithms, in which case CFITSIO will uncompress the file on the fly
+into a temporary file (in memory or on disk). Compressed files may
+only be opened with read-only permission. When specifying the name of
+a compressed FITS file it is not necessary to append the file suffix
+(e.g., `.gz' or `.Z'). If CFITSIO cannot find the input file name
+without the suffix, then it will automatically search for a compressed
+file with the same root name. In the case of reading ftp and http type
+files, CFITSIO generally looks for a compressed version of the file
+first, before trying to open the uncompressed file. By default,
+CFITSIO copies (and uncompressed if necessary) the ftp or http FITS
+file into memory on the local machine before opening it. This will
+fail if the local machine does not have enough memory to hold the whole
+FITS file, so in this case, the output filename specifier (see the next
+section) can be used to further control how CFITSIO reads ftp and http
+files.
+
+If the input file is an IRAF image file (*.imh file) then CFITSIO will
+automatically convert it on the fly into a virtual FITS image before it
+is opened by the application program. IRAF images can only be opened
+with READONLY file access.
+
+Similarly, if the input file is a raw binary data array, then CFITSIO
+will convert it on the fly into a virtual FITS image with the basic set
+of required header keywords before it is opened by the application
+program (with READONLY access). In this case the data type and
+dimensions of the image must be specified in square brackets following
+the filename (e.g. rawfile.dat[ib512,512]). The first character (case
+insensitive) defines the datatype of the array:
+-
+ b 8-bit unsigned byte
+ i 16-bit signed integer
+ u 16-bit unsigned integer
+ j 32-bit signed integer
+ r or f 32-bit floating point
+ d 64-bit floating point
+-
+An optional second character specifies the byte order of the array
+values: b or B indicates big endian (as in FITS files and the native
+format of SUN UNIX workstations and Mac PCs) and l or L indicates
+little endian (native format of DEC OSF workstations and IBM PCs). If
+this character is omitted then the array is assumed to have the native
+byte order of the local machine. These datatype characters are then
+followed by a series of one or more integer values separated by commas
+which define the size of each dimension of the raw array. Arrays with
+up to 5 dimensions are currently supported. Finally, a byte offset to
+the position of the first pixel in the data file may be specified by
+separating it with a ':' from the last dimension value. If omitted, it
+is assumed that the offset = 0. This parameter may be used to skip
+over any header information in the file that precedes the binary data.
+Further examples:
+-
+ raw.dat[b10000] 1-dimensional 10000 pixel byte array
+ raw.dat[rb400,400,12] 3-dimensional floating point big-endian array
+ img.fits[ib512,512:2880] reads the 512 x 512 short integer array in
+ a FITS file, skipping over the 2880 byte header
+-
+
+One special case of input file is where the filename = `-' (a dash or
+minus sign) or 'stdin' or 'stdout', which signifies that the input file
+is to be read from the stdin stream, or written to the stdout stream if
+a new output file is being created. In the case of reading from stdin,
+CFITSIO first copies the whole stream into a temporary FITS file (in
+memory or on disk), and subsequent reading of the FITS file occurs in
+this copy. When writing to stdout, CFITSIO first constructs the whole
+file in memory (since random access is required), then flushes it out
+to the stdout stream when the file is closed. In addition, if the
+output filename = '-.gz' or 'stdout.gz' then it will be gzip compressed
+before being written to stdout.
+
+This ability to read and write on the stdin and stdout steams allows
+FITS files to be piped between tasks in memory rather than having to
+create temporary intermediate FITS files on disk. For example if task1
+creates an output FITS file, and task2 reads an input FITS file, the
+FITS file may be piped between the 2 tasks by specifying
+-
+ task1 - | task2 -
+-
+where the vertical bar is the Unix piping symbol. This assumes that the 2
+tasks read the name of the FITS file off of the command line.
+
+**C. Output File Name when Opening an Existing File
+
+An optional output filename may be specified in parentheses immediately
+following the base file name to be opened. This is mainly useful in
+those cases where CFITSIO creates a temporary copy of the input FITS
+file before it is opened and passed to the application program. This
+happens by default when opening a network FTP or HTTP-type file, when
+reading a compressed FITS file on a local disk, when reading from the
+stdin stream, or when a column filter, row filter, or binning specifier
+is included as part of the input file specification. By default this
+temporary file is created in memory. If there is not enough memory to
+create the file copy, then CFITSIO will exit with an error. In these
+cases one can force a permanent file to be created on disk, instead of
+a temporary file in memory, by supplying the name in parentheses
+immediately following the base file name. The output filename can
+include the '!' clobber flag.
+
+Thus, if the input filename to CFITSIO is:
+\verb+file1.fits.gz(file2.fits)+
+then CFITSIO will uncompress `file1.fits.gz' into the local disk file
+`file2.fits' before opening it. CFITSIO does not automatically delete
+the output file, so it will still exist after the application program
+exits.
+
+In some cases, several different temporary FITS files will be created
+in sequence, for instance, if one opens a remote file using FTP, then
+filters rows in a binary table extension, then create an image by
+binning a pair of columns. In this case, the remote file will be
+copied to a temporary local file, then a second temporary file will be
+created containing the filtered rows of the table, and finally a third
+temporary file containing the binned image will be created. In cases
+like this where multiple files are created, the outfile specifier will
+be interpreted the name of the final file as described below, in descending
+priority:
+
+\begin{itemize}
+\item
+as the name of the final image file if an image within a single binary
+table cell is opened or if an image is created by binning a table column.
+\item
+as the name of the file containing the filtered table if a column filter
+and/or a row filter are specified.
+\item
+as the name of the local copy of the remote FTP or HTTP file.
+\item
+as the name of the uncompressed version of the FITS file, if a
+compressed FITS file on local disk has been opened.
+\item
+otherwise, the output filename is ignored.
+\end{itemize}
+
+
+The output file specifier is useful when reading FTP or HTTP-type
+FITS files since it can be used to create a local disk copy of the file
+that can be reused in the future. If the output file name = `*' then a
+local file with the same name as the network file will be created.
+Note that CFITSIO will behave differently depending on whether the
+remote file is compressed or not as shown by the following examples:
+\begin{itemize}
+\item
+`ftp://remote.machine/tmp/myfile.fits.gz(*)' - the remote compressed
+file is copied to the local compressed file `myfile.fits.gz', which
+is then uncompressed in local memory before being opened and passed
+to the application program.
+
+\item
+`ftp://remote.machine/tmp/myfile.fits.gz(myfile.fits)' - the remote
+compressed file is copied and uncompressed into the local file
+`myfile.fits'. This example requires less local memory than the
+previous example since the file is uncompressed on disk instead of
+in memory.
+
+\item
+`ftp://remote.machine/tmp/myfile.fits(myfile.fits.gz)' - this will
+usually produce an error since CFITSIO itself cannot compress files.
+\end{itemize}
+
+The exact behavior of CFITSIO in the latter case depends on the type of
+ftp server running on the remote machine and how it is configured. In
+some cases, if the file `myfile.fits.gz' exists on the remote machine,
+then the server will copy it to the local machine. In other cases the
+ftp server will automatically create and transmit a compressed version
+of the file if only the uncompressed version exists. This can get
+rather confusing, so users should use a certain amount of caution when
+using the output file specifier with FTP or HTTP file types, to make
+sure they get the behavior that they expect.
+
+**D. Template File Name when Creating a New File
+
+When a new FITS file is created with a call to fits\_create\_file, the
+name of a template file may be supplied in parentheses immediately
+following the name of the new file to be created. This template is
+used to define the structure of one or more HDUs in the new file. The
+template file may be another FITS file, in which case the newly created
+file will have exactly the same keywords in each HDU as in the template
+FITS file, but all the data units will be filled with zeros. The
+template file may also be an ASCII text file, where each line (in
+general) describes one FITS keyword record. The format of the ASCII
+template file is described below.
+
+**E. HDU Location Specification
+
+The optional HDU location specifier defines which HDU (Header-Data
+Unit, also known as an `extension') within the FITS file to initially
+open. It must immediately follow the base file name (or the output
+file name if present). If it is not specified then the first HDU (the
+primary array) is opened. The HDU location specifier is required if
+the colFilter, rowFilter, or binSpec specifiers are present, because
+the primary array is not a valid HDU for these operations. The HDU may
+be specified either by absolute position number, starting with 0 for
+the primary array, or by reference to the HDU name, and optionally, the
+version number and the HDU type of the desired extension. The location
+of an image within a single cell of a binary table may also be
+specified, as described below.
+
+The absolute position of the extension is specified either by enclosed
+the number in square brackets (e.g., `[1]' = the first extension
+following the primary array) or by preceded the number with a plus sign
+(`+1'). To specify the HDU by name, give the name of the desired HDU
+(the value of the EXTNAME or HDUNAME keyword) and optionally the
+extension version number (value of the EXTVER keyword) and the
+extension type (value of the XTENSION keyword: IMAGE, ASCII or TABLE,
+or BINTABLE), separated by commas and all enclosed in square brackets.
+If the value of EXTVER and XTENSION are not specified, then the first
+extension with the correct value of EXTNAME is opened. The extension
+name and type are not case sensitive, and the extension type may be
+abbreviated to a single letter (e.g., I = IMAGE extension or primary
+array, A or T = ASCII table extension, and B = binary table BINTABLE
+extension). If the HDU location specifier is equal to `[PRIMARY]' or
+`[P]', then the primary array (the first HDU) will be opened.
+
+FITS images are most commonly stored in the primary array or an image
+extension, but images can also be stored as a vector in a single cell
+of a binary table (i.e. each row of the vector column contains a
+different image). Such an image can be opened with CFITSIO by
+specifying the desired column name and the row number after the binary
+table HDU specifier as shown in the following examples. The column name
+is separated from the HDU specifier by a semicolon and the row number
+is enclosed in parentheses. In this case CFITSIO copies the image from
+the table cell into a temporary primary array before it is opened. The
+application program then just sees the image in the primary array,
+without any extensions. The particular row to be opened may be
+specified either by giving an absolute integer row number (starting
+with 1 for the first row), or by specifying a boolean expression that
+evaluates to TRUE for the desired row. The first row that satisfies
+the expression will be used. The row selection expression has the same
+syntax as described in the Row Filter Specifier section, below.
+
+ Examples:
+-
+ myfile.fits[3] - open the 3rd HDU following the primary array
+ myfile.fits+3 - same as above, but using the FTOOLS-style notation
+ myfile.fits[EVENTS] - open the extension that has EXTNAME = 'EVENTS'
+ myfile.fits[EVENTS, 2] - same as above, but also requires EXTVER = 2
+ myfile.fits[events,2,b] - same, but also requires XTENSION = 'BINTABLE'
+ myfile.fits[3; images(17)] - opens the image in row 17 of the 'images'
+ column in the 3rd extension of the file.
+ myfile.fits[3; images(exposure > 100)] - as above, but opens the image
+ in the first row that has an 'exposure' column value
+ greater than 100.
+-
+
+**F. Image Section
+
+A virtual file containing a rectangular subsection of an image can be
+extracted and opened by specifying the range of pixels (start:end)
+along each axis to be extracted from the original image. One can also
+specify an optional pixel increment (start:end:step) for each axis of
+the input image. A pixel step = 1 will be assumed if it is not
+specified. If the start pixel is larger then the end pixel, then the
+image will be flipped (producing a mirror image) along that dimension.
+An asterisk, '*', may be used to specify the entire range of an axis,
+and '-*' will flip the entire axis. The input image can be in the
+primary array, in an image extension, or contained in a vector cell of
+a binary table. In the later 2 cases the extension name or number must
+be specified before the image section specifier.
+
+ Examples:
+-
+ myfile.fits[1:512:2, 2:512:2] - open a 256x256 pixel image
+ consisting of the odd numbered columns (1st axis) and
+ the even numbered rows (2nd axis) of the image in the
+ primary array of the file.
+
+ myfile.fits[*, 512:256] - open an image consisting of all the columns
+ in the input image, but only rows 256 through 512.
+ The image will be flipped along the 2nd axis since
+ the starting pixel is greater than the ending pixel.
+
+ myfile.fits[*:2, 512:256:2] - same as above but keeping only
+ every other row and column in the input image.
+
+ myfile.fits[-*, *] - copy the entire image, flipping it along
+ the first axis.
+
+ myfile.fits[3][1:256,1:256] - opens a subsection of the image that
+ is in the 3rd extension of the file.
+
+ myfile.fits[4; images(12)][1:10,1:10] - open an image consisting
+ of the first 10 pixels in both dimensions. The original
+ image resides in the 12th row of the 'images' vector
+ column in the table in the 4th extension of the file.
+-
+
+When CFITSIO opens an image section it first creates a temporary file
+containing the image section plus a copy of any other HDUs in the
+file. This temporary file is then opened by the application program,
+so it is not possible to write to or modify the input file when
+specifying an image section. Note that CFITSIO automatically updates
+the world coordinate system keywords in the header of the image
+section, if they exist, so that the coordinate associated with each
+pixel in the image section will be computed correctly.
+
+**G. Column and Keyword Filtering Specification
+
+The optional column/keyword filtering specifier is used to modify the
+column structure and/or the header keywords in the HDU that was
+selected with the previous HDU location specifier. This filtering
+specifier must be enclosed in square brackets and can be distinguished
+from a general row filter specifier (described below) by the fact that
+it begins with the string 'col ' and is not immediately followed by an
+equals sign. The original file is not changed by this filtering
+operation, and instead the modifications are made on a copy of the
+input FITS file (usually in memory), which also contains a copy of all
+the other HDUs in the file. This temporary file is passed to the
+application program and will persist only until the file is closed or
+until the program exits, unless the outfile specifier (see above) is
+also supplied.
+
+The column/keyword filter can be used to perform the following
+operations. More than one operation may be specified by separating
+them with semi-colons.
+
+\begin{itemize}
+
+\item
+Copy only a specified list of columns columns to the filtered input file.
+The list of column name should be separated by semi-colons. Wild card
+characters may be used in the column names to match multiple columns.
+If the expression contains both a list of columns to be included and
+columns to be deleted, then all the columns in the original table
+except the explicitly deleted columns will appear in the filtered
+table (i.e., there is no need to explicitly list the columns to
+be included if any columns are being deleted).
+
+\item
+Delete a column or keyword by listing the name preceded by a minus
+sign or an exclamation mark (!), e.g., '-TIME' will delete the TIME
+column if it exists, otherwise the TIME keyword. An error is returned
+if neither a column nor keyword with this name exists. Note that the
+exclamation point, '!', is a special UNIX character, so if it is used
+on the command line rather than entered at a task prompt, it must be
+preceded by a backslash to force the UNIX shell to ignore it.
+
+\item
+Rename an existing column or keyword with the syntax 'NewName ==
+OldName'. An error is returned if neither a column nor keyword with
+this name exists.
+
+\item
+Append a new column or keyword to the table. To create a column,
+give the new name, optionally followed by the datatype in parentheses,
+followed by a single equals sign and an expression to be used to
+compute the value (e.g., 'newcol(1J) = 0' will create a new 32-bit
+integer column called 'newcol' filled with zeros). The datatype is
+specified using the same syntax that is allowed for the value of the
+FITS TFORMn keyword (e.g., 'I', 'J', 'E', 'D', etc. for binary tables,
+and 'I8', F12.3', 'E20.12', etc. for ASCII tables). If the datatype is
+not specified then an appropriate datatype will be chosen depending on
+the form of the expression (may be a character string, logical, bit, long
+integer, or double column). An appropriate vector count (in the case
+of binary tables) will also be added if not explicitly specified.
+
+When creating a new keyword, the keyword name must be preceded by a
+pound sign '\#', and the expression must evaluate to a scalar
+(i.e., cannot have a column name in the expression). The comment
+string for the keyword may be specified in parentheses immediately
+following the keyword name (instead of supplying a datatype as in
+the case of creating a new column).
+
+\item
+Recompute (overwrite) the values in an existing column or keyword by
+giving the name followed by an equals sign and an arithmetic
+expression.
+\end{itemize}
+
+The expression that is used when appending or recomputing columns or
+keywords can be arbitrarily complex and may be a function of other
+header keyword values and other columns (in the same row). The full
+syntax and available functions for the expression are described below
+in the row filter specification section.
+
+If the expression contains both a list of columns to be included and
+columns to be deleted, then all the columns in the original table
+except the explicitly deleted columns will appear in the filtered
+table.
+
+For complex or commonly used operations, one can also place the
+operations into an external text file and import it into the column
+filter using the syntax '[col @filename.txt]'. The operations can
+extend over multiple lines of the file, but multiple operations must
+still be separated by semicolons. Any lines in the external text file
+that begin with 2 slash characters ('//') will be ignored and may be
+used to add comments into the file.
+
+Examples:
+-
+ [col Time;rate] - only the Time and rate columns will
+ appear in the filtered input file.
+
+ [col Time;*raw] - include the Time column and any other
+ columns whose name ends with 'raw'.
+
+ [col -TIME; Good == STATUS] - deletes the TIME column and
+ renames the status column to 'Good'
+
+ [col PI=PHA * 1.1 + 0.2] - creates new PI column from PHA values
+
+ [col rate = rate/exposure] - recomputes the rate column by dividing
+ it by the EXPOSURE keyword value.
+-
+
+**H. Row Filtering Specification
+
+ When entering the name of a FITS table that is to be opened by a
+ program, an optional row filter may be specified to select a subset
+ of the rows in the table. A temporary new FITS file is created on
+ the fly which contains only those rows for which the row filter
+ expression evaluates to true. (The primary array and any other
+ extensions in the input file are also copied to the temporary
+ file). The original FITS file is closed and the new virtual file
+ is opened by the application program. The row filter expression is
+ enclosed in square brackets following the file name and extension
+ name (e.g., 'file.fits[events][GRADE==50]' selects only those rows
+ where the GRADE column value equals 50). When dealing with tables
+ where each row has an associated time and/or 2D spatial position,
+ the row filter expression can also be used to select rows based on
+ the times in a Good Time Intervals (GTI) extension, or on spatial
+ position as given in a SAO-style region file.
+
+***1. General Syntax
+
+ The row filtering expression can be an arbitrarily complex series
+ of operations performed on constants, keyword values, and column
+ data taken from the specified FITS TABLE extension. The expression
+ must evaluate to a boolean value for each row of the table, where
+ a value of FALSE means that the row will be excluded.
+
+ For complex or commonly used filters, one can place the expression
+ into a text file and import it into the row filter using the syntax
+ '[@filename.txt]'. The expression can be arbitrarily complex and
+ extend over multiple lines of the file. Any lines in the external
+ text file that begin with 2 slash characters ('//') will be ignored
+ and may be used to add comments into the file.
+
+ Keyword and column data are referenced by name. Any string of
+ characters not surrounded by quotes (ie, a constant string) or
+ followed by an open parentheses (ie, a function name) will be
+ initially interpreted as a column name and its contents for the
+ current row inserted into the expression. If no such column exists,
+ a keyword of that name will be searched for and its value used, if
+ found. To force the name to be interpreted as a keyword (in case
+ there is both a column and keyword with the same name), precede the
+ keyword name with a single pound sign, '\#', as in '\#NAXIS2'. Due to
+ the generalities of FITS column and keyword names, if the column or
+ keyword name contains a space or a character which might appear as
+ an arithmetic term then inclose the name in '\$' characters as in
+ \$MAX PHA\$ or \#\$MAX-PHA\$. Names are case insensitive.
+
+ To access a table entry in a row other than the current one, follow
+ the column's name with a row offset within curly braces. For
+ example, 'PHA\{-3\}' will evaluate to the value of column PHA, 3 rows
+ above the row currently being processed. One cannot specify an
+ absolute row number, only a relative offset. Rows that fall outside
+ the table will be treated as undefined, or NULLs.
+
+ Boolean operators can be used in the expression in either their
+ Fortran or C forms. The following boolean operators are available:
+-
+ "equal" .eq. .EQ. == "not equal" .ne. .NE. !=
+ "less than" .lt. .LT. < "less than/equal" .le. .LE. <= =<
+ "greater than" .gt. .GT. > "greater than/equal" .ge. .GE. >= =>
+ "or" .or. .OR. || "and" .and. .AND. &&
+ "negation" .not. .NOT. ! "approx. equal(1e-7)" ~
+-
+
+Note that the exclamation
+point, '!', is a special UNIX character, so if it is used on the
+command line rather than entered at a task prompt, it must be preceded
+by a backslash to force the UNIX shell to ignore it.
+
+ The expression may also include arithmetic operators and functions.
+ Trigonometric functions use radians, not degrees. The following
+ arithmetic operators and functions can be used in the expression
+ (function names are case insensitive). A null value will be returned
+ in case of illegal operations such as divide by zero, sqrt(negative)
+ log(negative), log10(negative), arccos(.gt. 1), arcsin(.gt. 1).
+
+-
+ "addition" + "subtraction" -
+ "multiplication" * "division" /
+ "negation" - "exponentiation" ** ^
+ "absolute value" abs(x) "cosine" cos(x)
+ "sine" sin(x) "tangent" tan(x)
+ "arc cosine" arccos(x) "arc sine" arcsin(x)
+ "arc tangent" arctan(x) "arc tangent" arctan2(x,y)
+ "hyperbolic cos" cosh(x) "hyperbolic sin" sinh(x)
+ "hyperbolic tan" tanh(x) "round to nearest int" round(x)
+ "round down to int" floor(x) "round up to int" ceil(x)
+ "exponential" exp(x) "square root" sqrt(x)
+ "natural log" log(x) "common log" log10(x)
+ "modulus" i % j "random # [0.0,1.0)" random()
+ "minimum" min(x,y) "maximum" max(x,y)
+ "cumulative sum" accum(x) "sequential difference" seqdiff(x)
+ "if-then-else" b?x:y
+-
+
+ An alternate syntax for the min and max functions has only a single
+ argument which should be a vector value (see below). The result
+ will be the minimum/maximum element contained within the vector.
+
+ The accum(x) function forms the cumulative sum of x, element by element.
+ Vector columns are supported simply by performing the summation process
+ through all the values. Null values are treated as 0. The seqdiff(x)
+ function forms the sequential difference of x, element by element.
+ The first value of seqdiff is the first value of x. A single null
+ value in x causes a pair of nulls in the output. The seqdiff and
+ accum functions are functional inverses, i.e., seqdiff(accum(x)) == x
+ as long as no null values are present.
+
+ The following type casting operators are available, where the
+ inclosing parentheses are required and taken from the C language
+ usage. Also, the integer to real casts values to double precision:
+-
+ "real to integer" (int) x (INT) x
+ "integer to real" (float) i (FLOAT) i
+-
+
+ In addition, several constants are built in for use in numerical
+ expressions:
+
+-
+ #pi 3.1415... #e 2.7182...
+ #deg #pi/180 #row current row number
+ #null undefined value #snull undefined string
+-
+
+ A string constant must be enclosed in quotes as in 'Crab'. The
+ "null" constants are useful for conditionally setting table values
+ to a NULL, or undefined, value (eg., "col1==-99 ? \#NULL : col1").
+
+ There is also a function for testing if two values are close to
+ each other, i.e., if they are "near" each other to within a user
+ specified tolerance. The arguments, value\_1 and value\_2 can be
+ integer or real and represent the two values who's proximity is
+ being tested to be within the specified tolerance, also an integer
+ or real:
+-
+ near(value_1, value_2, tolerance)
+-
+ When a NULL, or undefined, value is encountered in the FITS table,
+ the expression will evaluate to NULL unless the undefined value is
+ not actually required for evaluation, e.g. "TRUE .or. NULL"
+ evaluates to TRUE. The following two functions allow some NULL
+ detection and handling:
+-
+ "a null value?" ISNULL(x)
+ "define a value for null" DEFNULL(x,y)
+-
+ The former
+ returns a boolean value of TRUE if the argument x is NULL. The
+ later "defines" a value to be substituted for NULL values; it
+ returns the value of x if x is not NULL, otherwise it returns the
+ value of y.
+
+***2. Bit Masks
+
+ Bit masks can be used to select out rows from bit columns (TFORMn =
+ \#X) in FITS files. To represent the mask, binary, octal, and hex
+ formats are allowed:
+
+-
+ binary: b0110xx1010000101xxxx0001
+ octal: o720x1 -> (b111010000xxx001)
+ hex: h0FxD -> (b00001111xxxx1101)
+-
+
+ In all the representations, an x or X is allowed in the mask as a
+ wild card. Note that the x represents a different number of wild
+ card bits in each representation. All representations are case
+ insensitive.
+
+ To construct the boolean expression using the mask as the boolean
+ equal operator described above on a bit table column. For example,
+ if you had a 7 bit column named flags in a FITS table and wanted
+ all rows having the bit pattern 0010011, the selection expression
+ would be:
+
+-
+ flags == b0010011
+ or
+ flags .eq. b10011
+-
+
+ It is also possible to test if a range of bits is less than, less
+ than equal, greater than and greater than equal to a particular
+ boolean value:
+
+-
+ flags <= bxxx010xx
+ flags .gt. bxxx100xx
+ flags .le. b1xxxxxxx
+-
+
+ Notice the use of the x bit value to limit the range of bits being
+ compared.
+
+ It is not necessary to specify the leading (most significant) zero
+ (0) bits in the mask, as shown in the second expression above.
+
+ Bit wise AND, OR and NOT operations are also possible on two or
+ more bit fields using the '\&'(AND), '$|$'(OR), and the '!'(NOT)
+ operators. All of these operators result in a bit field which can
+ then be used with the equal operator. For example:
+
+-
+ (!flags) == b1101100
+ (flags & b1000001) == bx000001
+-
+
+ Bit fields can be appended as well using the '+' operator. Strings
+ can be concatenated this way, too.
+
+***3. Vector Columns
+
+ Vector columns can also be used in building the expression. No
+ special syntax is required if one wants to operate on all elements
+ of the vector. Simply use the column name as for a scalar column.
+ Vector columns can be freely intermixed with scalar columns or
+ constants in virtually all expressions. The result will be of the
+ same dimension as the vector. Two vectors in an expression, though,
+ need to have the same number of elements and have the same
+ dimensions. The only places a vector column cannot be used (for
+ now, anyway) are the SAO region functions and the NEAR boolean
+ function.
+
+ Arithmetic and logical operations are all performed on an element by
+ element basis. Comparing two vector columns, eg "COL1 == COL2",
+ thus results in another vector of boolean values indicating which
+ elements of the two vectors are equal.
+
+ Eight functions are available that operate on a vector and return a
+ scalar result:
+-
+ "minimum" MIN(V) "maximum" MAX(V)
+ "average" AVERAGE(V) "median" MEDIAN(V)
+ "sumation" SUM(V) "standard deviation" STDDEV(V)
+ "# of values" NELEM(V) "# of non-null values" NVALID(V)
+-
+ where V represents the name of a vector column or a manually
+ constructed vector using curly brackets as described below. The
+ first 6 of these functions ignore any null values in the vector when
+ computing the result.
+
+ The SUM function literally sums all the elements in x, returning a
+ scalar value. If x is a boolean vector, SUM returns the number
+ of TRUE elements. The NELEM function returns the number of elements
+ in vector x whereas NVALID return the number of non-null elements in
+ the vector. (NELEM also operates on bit and string columns,
+ returning their column widths.) As an example, to test whether all
+ elements of two vectors satisfy a given logical comparison, one can
+ use the expression
+-
+ SUM( COL1 > COL2 ) == NELEM( COL1 )
+-
+
+ which will return TRUE if all elements of COL1 are greater than
+ their corresponding elements in COL2.
+
+ To specify a single element of a vector, give the column name
+ followed by a comma-separated list of coordinates enclosed in
+ square brackets. For example, if a vector column named PHAS exists
+ in the table as a one dimensional, 256 component list of numbers
+ from which you wanted to select the 57th component for use in the
+ expression, then PHAS[57] would do the trick. Higher dimensional
+ arrays of data may appear in a column. But in order to interpret
+ them, the TDIMn keyword must appear in the header. Assuming that a
+ (4,4,4,4) array is packed into each row of a column named ARRAY4D,
+ the (1,2,3,4) component element of each row is accessed by
+ ARRAY4D[1,2,3,4]. Arrays up to dimension 5 are currently
+ supported. Each vector index can itself be an expression, although
+ it must evaluate to an integer value within the bounds of the
+ vector. Vector columns which contain spaces or arithmetic operators
+ must have their names enclosed in "\$" characters as with
+ \$ARRAY-4D\$[1,2,3,4].
+
+ A more C-like syntax for specifying vector indices is also
+ available. The element used in the preceding example alternatively
+ could be specified with the syntax ARRAY4D[4][3][2][1]. Note the
+ reverse order of indices (as in C), as well as the fact that the
+ values are still ones-based (as in Fortran -- adopted to avoid
+ ambiguity for 1D vectors). With this syntax, one does not need to
+ specify all of the indices. To extract a 3D slice of this 4D
+ array, use ARRAY4D[4].
+
+ Variable-length vector columns are not supported.
+
+ Vectors can be manually constructed within the expression using a
+ comma-separated list of elements surrounded by curly braces ('\{\}').
+ For example, '\{1,3,6,1\}' is a 4-element vector containing the values
+ 1, 3, 6, and 1. The vector can contain only boolean, integer, and
+ real values (or expressions). The elements will be promoted to the
+ highest datatype present. Any elements which are themselves
+ vectors, will be expanded out with each of its elements becoming an
+ element in the constructed vector.
+
+***4. Good Time Interval Filtering
+
+ A common filtering method involves selecting rows which have a time
+ value which lies within what is called a Good Time Interval or GTI.
+ The time intervals are defined in a separate FITS table extension
+ which contains 2 columns giving the start and stop time of each
+ good interval. The filtering operation accepts only those rows of
+ the input table which have an associated time which falls within
+ one of the time intervals defined in the GTI extension. A high
+ level function, gtifilter(a,b,c,d), is available which evaluates
+ each row of the input table and returns TRUE or FALSE depending
+ whether the row is inside or outside the good time interval. The
+ syntax is
+-
+ gtifilter( [ "gtifile" [, expr [, "STARTCOL", "STOPCOL" ] ] ] )
+-
+ where each "[]" demarks optional parameters. Note that the quotes
+ around the gtifile and START/STOP column are required. Either single
+ or double quotes may be used. In cases where this expression is
+ entered on the Unix command line, enclose the entire expression in
+ double quotes, and then use single quotes within the expression to
+ enclose the 'gtifile' and other terms. It is also usually possible
+ to do the reverse, and enclose the whole expression in single quotes
+ and then use double quotes within the expression. The gtifile,
+ if specified, can be blank ("") which will mean to use the first
+ extension with the name "*GTI*" in the current file, a plain
+ extension specifier (eg, "+2", "[2]", or "[STDGTI]") which will be
+ used to select an extension in the current file, or a regular
+ filename with or without an extension specifier which in the latter
+ case will mean to use the first extension with an extension name
+ "*GTI*". Expr can be any arithmetic expression, including simply
+ the time column name. A vector time expression will produce a
+ vector boolean result. STARTCOL and STOPCOL are the names of the
+ START/STOP columns in the GTI extension. If one of them is
+ specified, they both must be.
+
+ In its simplest form, no parameters need to be provided -- default
+ values will be used. The expression "gtifilter()" is equivalent to
+-
+ gtifilter( "", TIME, "*START*", "*STOP*" )
+-
+ This will search the current file for a GTI extension, filter the
+ TIME column in the current table, using START/STOP times taken from
+ columns in the GTI extension with names containing the strings
+ "START" and "STOP". The wildcards ('*') allow slight variations in
+ naming conventions such as "TSTART" or "STARTTIME". The same
+ default values apply for unspecified parameters when the first one
+ or two parameters are specified. The function automatically
+ searches for TIMEZERO/I/F keywords in the current and GTI
+ extensions, applying a relative time offset, if necessary.
+
+***5. Spatial Region Filtering
+
+ Another common filtering method selects rows based on whether the
+ spatial position associated with each row is located within a given
+ 2-dimensional region. The syntax for this high-level filter is
+-
+ regfilter( "regfilename" [ , Xexpr, Yexpr [ , "wcs cols" ] ] )
+-
+ where each "[]" demarks optional parameters. The region file name
+ is required and must be enclosed in quotes. The remaining
+ parameters are optional. The region file is an ASCII text file
+ which contains a list of one or more geometric shapes (circle,
+ ellipse, box, etc.) which defines a region on the celestial sphere
+ or an area within a particular 2D image. The region file is
+ typically generated using an image display program such as fv/POW
+ (distribute by the HEASARC), or ds9 (distributed by the Smithsonian
+ Astrophysical Observatory). Users should refer to the documentation
+ provided with these programs for more details on the syntax used in
+ the region files.
+
+ In its simpliest form, (e.g., regfilter("region.reg") ) the
+ coordinates in the default 'X' and 'Y' columns will be used to
+ determine if each row is inside or outside the area specified in
+ the region file. Alternate position column names, or expressions,
+ may be entered if needed, as in
+-
+ regfilter("region.reg", XPOS, YPOS)
+-
+ Region filtering can be applied most unambiguously if the positions
+ in the region file and in the table to be filtered are both give in
+ terms of absolute celestial coordinate units. In this case the
+ locations and sizes of the geometric shapes in the region file are
+ specified in angular units on the sky (e.g., positions given in
+ R.A. and Dec. and sizes in arcseconds or arcminutes). Similarly,
+ each row of the filtered table will have a celestial coordinate
+ associated with it. This association is usually implemented using
+ a set of so-called 'World Coordinate System' (or WCS) FITS keywords
+ that define the coordinate transformation that must be applied to
+ the values in the 'X' and 'Y' columns to calculate the coordinate.
+
+ Alternatively, one can perform spatial filtering using unitless
+ 'pixel' coordinates for the regions and row positions. In this
+ case the user must be careful to ensure that the positions in the 2
+ files are self-consistent. A typical problem is that the region
+ file may be generated using a binned image, but the unbinned
+ coordinates are given in the event table. The ROSAT events files,
+ for example, have X and Y pixel coordinates that range from 1 -
+ 15360. These coordinates are typically binned by a factor of 32 to
+ produce a 480x480 pixel image. If one then uses a region file
+ generated from this image (in image pixel units) to filter the
+ ROSAT events file, then the X and Y column values must be converted
+ to corresponding pixel units as in:
+-
+ regfilter("rosat.reg", X/32.+.5, Y/32.+.5)
+-
+ Note that this binning conversion is not necessary if the region
+ file is specified using celestial coordinate units instead of pixel
+ units because CFITSIO is then able to directly compare the
+ celestial coordinate of each row in the table with the celestial
+ coordinates in the region file without having to know anything
+ about how the image may have been binned.
+
+ The last "wcs cols" parameter should rarely be needed. If supplied,
+ this string contains the names of the 2 columns (space or comma
+ separated) which have the associated WCS keywords. If not supplied,
+ the filter will scan the X and Y expressions for column names.
+ If only one is found in each expression, those columns will be
+ used, otherwise an error will be returned.
+
+ These region shapes are supported (names are case insensitive):
+-
+ Point ( X1, Y1 ) <- One pixel square region
+ Line ( X1, Y1, X2, Y2 ) <- One pixel wide region
+ Polygon ( X1, Y1, X2, Y2, ... ) <- Rest are interiors with
+ Rectangle ( X1, Y1, X2, Y2, A ) | boundaries considered
+ Box ( Xc, Yc, Wdth, Hght, A ) V within the region
+ Diamond ( Xc, Yc, Wdth, Hght, A )
+ Circle ( Xc, Yc, R )
+ Annulus ( Xc, Yc, Rin, Rout )
+ Ellipse ( Xc, Yc, Rx, Ry, A )
+ Elliptannulus ( Xc, Yc, Rinx, Riny, Routx, Routy, Ain, Aout )
+ Sector ( Xc, Yc, Amin, Amax )
+-
+ where (Xc,Yc) is the coordinate of the shape's center; (X\#,Y\#) are
+ the coordinates of the shape's edges; Rxxx are the shapes' various
+ Radii or semimajor/minor axes; and Axxx are the angles of rotation
+ (or bounding angles for Sector) in degrees. For rotated shapes, the
+ rotation angle can be left off, indicating no rotation. Common
+ alternate names for the regions can also be used: rotbox = box;
+ rotrectangle = rectangle; (rot)rhombus = (rot)diamond; and pie
+ = sector. When a shape's name is preceded by a minus sign, '-',
+ the defined region is instead the area *outside* its boundary (ie,
+ the region is inverted). All the shapes within a single region
+ file are OR'd together to create the region, and the order is
+ significant. The overall way of looking at region files is that if
+ the first region is an excluded region then a dummy included region
+ of the whole detector is inserted in the front. Then each region
+ specification as it is processed overrides any selections inside of
+ that region specified by previous regions. Another way of thinking
+ about this is that if a previous excluded region is completely
+ inside of a subsequent included region the excluded region is
+ ignored.
+
+ The positional coordinates may be given either in pixel units,
+ decimal degrees or hh:mm:ss.s, dd:mm:ss.s units. The shape sizes
+ may be given in pixels, degrees, arcminutes, or arcseconds. Look
+ at examples of region file produced by fv/POW or ds9 for further
+ details of the region file format.
+
+ There are three functions that are primarily for use with SAO region
+ files and the FSAOI task, but they can be used directly. They
+ return a boolean true or false depending on whether a two
+ dimensional point is in the region or not:
+-
+ "point in a circular region"
+ circle(xcntr,ycntr,radius,Xcolumn,Ycolumn)
+
+ "point in an elliptical region"
+ ellipse(xcntr,ycntr,xhlf_wdth,yhlf_wdth,rotation,Xcolumn,Ycolumn)
+
+ "point in a rectangular region"
+ box(xcntr,ycntr,xfll_wdth,yfll_wdth,rotation,Xcolumn,Ycolumn)
+
+ where
+ (xcntr,ycntr) are the (x,y) position of the center of the region
+ (xhlf_wdth,yhlf_wdth) are the (x,y) half widths of the region
+ (xfll_wdth,yfll_wdth) are the (x,y) full widths of the region
+ (radius) is half the diameter of the circle
+ (rotation) is the angle(degrees) that the region is rotated with
+ respect to (xcntr,ycntr)
+ (Xcoord,Ycoord) are the (x,y) coordinates to test, usually column
+ names
+ NOTE: each parameter can itself be an expression, not merely a
+ column name or constant.
+-
+
+***5. Example Row Filters
+-
+ [ binary && mag <= 5.0] - Extract all binary stars brighter
+ than fifth magnitude (note that
+ the initial space is necessary to
+ prevent it from being treated as a
+ binning specification)
+
+ [#row >= 125 && #row <= 175] - Extract row numbers 125 through 175
+
+ [IMAGE[4,5] .gt. 100] - Extract all rows that have the
+ (4,5) component of the IMAGE column
+ greater than 100
+
+ [abs(sin(theta * #deg)) < 0.5] - Extract all rows having the
+ absolute value of the sine of theta
+ less than a half where the angles
+ are tabulated in degrees
+
+ [SUM( SPEC > 3*BACKGRND )>=1] - Extract all rows containing a
+ spectrum, held in vector column
+ SPEC, with at least one value 3
+ times greater than the background
+ level held in a keyword, BACKGRND
+
+ [VCOL=={1,4,2}] - Extract all rows whose vector column
+ VCOL contains the 3-elements 1, 4, and
+ 2.
+
+ [@rowFilter.txt] - Extract rows using the expression
+ contained within the text file
+ rowFilter.txt
+
+ [gtifilter()] - Search the current file for a GTI
+ extension, filter the TIME
+ column in the current table, using
+ START/STOP times taken from
+ columns in the GTI extension
+
+ [regfilter("pow.reg")] - Extract rows which have a coordinate
+ (as given in the X and Y columns)
+ within the spatial region specified
+ in the pow.reg region file.
+
+ [regfilter("pow.reg", Xs, Ys)] - Same as above, except that the
+ Xs and Ys columns will be used to
+ determine the coordinate of each
+ row in the table.
+-
+
+**I. Binning or Histogramming Specification
+
+The optional binning specifier is enclosed in square brackets and can
+be distinguished from a general row filter specification by the fact
+that it begins with the keyword 'bin' not immediately followed by an
+equals sign. When binning is specified, a temporary N-dimensional FITS
+primary array is created by computing the histogram of the values in
+the specified columns of a FITS table extension. After the histogram
+is computed the input FITS file containing the table is then closed and
+the temporary FITS primary array is opened and passed to the
+application program. Thus, the application program never sees the
+original FITS table and only sees the image in the new temporary file
+(which has no additional extensions). Obviously, the application
+program must be expecting to open a FITS image and not a FITS table in
+this case.
+
+The data type of the FITS histogram image may be specified by appending
+'b' (for 8-bit byte), 'i' (for 16-bit integers), 'j' (for 32-bit
+integer), 'r' (for 32-bit floating points), or 'd' (for 64-bit double
+precision floating point) to the 'bin' keyword (e.g. '[binr X]'
+creates a real floating point image). If the datatype is not
+explicitly specified then a 32-bit integer image will be created by
+default, unless the weighting option is also specified in which case
+the image will have a 32-bit floating point data type by default.
+
+The histogram image may have from 1 to 4 dimensions (axes), depending
+on the number of columns that are specified. The general form of the
+binning specification is:
+-
+ [bin{bijrd} Xcol=min:max:binsize, Ycol= ..., Zcol=..., Tcol=...; weight]
+-
+in which up to 4 columns, each corresponding to an axis of the image,
+are listed. The column names are case insensitive, and the column
+number may be given instead of the name, preceded by a pound sign
+(e.g., [bin \#4=1:512]). If the column name is not specified, then
+CFITSIO will first try to use the 'preferred column' as specified by
+the CPREF keyword if it exists (e.g., 'CPREF = 'DETX,DETY'), otherwise
+column names 'X', 'Y', 'Z', and 'T' will be assumed for each of the 4
+axes, respectively. In cases where the column name could be confused
+with an arithmetic expression, enclose the column name in parentheses to
+force the name to be interpreted literally.
+
+Each column name may be followed by an equals sign and then the lower
+and upper range of the histogram, and the size of the histogram bins,
+separated by colons. Spaces are allowed before and after the equals
+sign but not within the 'min:max:binsize' string. The min, max and
+binsize values may be integer or floating point numbers, or they may be
+the names of keywords in the header of the table. If the latter, then
+the value of that keyword is substituted into the expression.
+
+Default values for the min, max and binsize quantities will be
+used if not explicitly given in the binning expression as shown
+in these examples:
+-
+ [bin x = :512:2] - use default minimum value
+ [bin x = 1::2] - use default maximum value
+ [bin x = 1:512] - use default bin size
+ [bin x = 1:] - use default maximum value and bin size
+ [bin x = :512] - use default minimum value and bin size
+ [bin x = 2] - use default minimum and maximum values
+ [bin x] - use default minimum, maximum and bin size
+ [bin 4] - default 2-D image, bin size = 4 in both axes
+ [bin] - default 2-D image
+-
+CFITSIO will use the value of the TLMINn, TLMAXn, and TDBINn keywords,
+if they exist, for the default min, max, and binsize, respectively. If
+they do not exist then CFITSIO will use the actual minimum and maximum
+values in the column for the histogram min and max values. The default
+binsize will be set to 1, or (max - min) / 10., whichever is smaller,
+so that the histogram will have at least 10 bins along each axis.
+
+A shortcut notation is allowed if all the columns/axes have the same
+binning specification. In this case all the column names may be listed
+within parentheses, followed by the (single) binning specification, as
+in:
+-
+ [bin (X,Y)=1:512:2]
+ [bin (X,Y) = 5]
+-
+
+The optional weighting factor is the last item in the binning specifier
+and, if present, is separated from the list of columns by a
+semi-colon. As the histogram is accumulated, this weight is used to
+incremented the value of the appropriated bin in the histogram. If the
+weighting factor is not specified, then the default weight = 1 is
+assumed. The weighting factor may be a constant integer or floating
+point number, or the name of a keyword containing the weighting value.
+Or the weighting factor may be the name of a table column in which case
+the value in that column, on a row by row basis, will be used.
+
+In some cases, the column or keyword may give the reciprocal of the
+actual weight value that is needed. In this case, precede the weight
+keyword or column name by a slash '/' to tell CFITSIO to use the
+reciprocal of the value when constructing the histogram.
+
+For complex or commonly used histograms, one can also place its
+description into a text file and import it into the binning
+specification using the syntax '[bin @filename.txt]'. The file's
+contents can extend over multiple lines, although it must still
+conform to the no-spaces rule for the min:max:binsize syntax and each
+axis specification must still be comma-separated. Any lines in the
+external text file that begin with 2 slash characters ('//') will be
+ignored and may be used to add comments into the file.
+
+ Examples:
+
+-
+ [bini detx, dety] - 2-D, 16-bit integer histogram
+ of DETX and DETY columns, using
+ default values for the histogram
+ range and binsize
+
+ [bin (detx, dety)=16; /exposure] - 2-D, 32-bit real histogram of DETX
+ and DETY columns with a bin size = 16
+ in both axes. The histogram values
+ are divided by the EXPOSURE keyword
+ value.
+
+ [bin time=TSTART:TSTOP:0.1] - 1-D lightcurve, range determined by
+ the TSTART and TSTOP keywords,
+ with 0.1 unit size bins.
+
+ [bin pha, time=8000.:8100.:0.1] - 2-D image using default binning
+ of the PHA column for the X axis,
+ and 1000 bins in the range
+ 8000. to 8100. for the Y axis.
+
+ [bin @binFilter.txt] - Use the contents of the text file
+ binFilter.txt for the binning
+ specifications.
+
+-
+
+
+*V. Template Files
+
+When a new FITS file is created with a call to fits\_create\_file, the
+name of a template file may be supplied in parentheses immediately
+following the name of the new file to be created. This template is
+used to define the structure of one or more HDUs in the new file. The
+template file may be another FITS file, in which case the newly created
+file will have exactly the same keywords in each HDU as in the template
+FITS file, but all the data units will be filled with zeros. The
+template file may also be an ASCII text file, where each line (in
+general) describes one FITS keyword record. The format of the ASCII
+template file is described in the following sections.
+
+**A Detailed Template Line Format
+
+The format of each ASCII template line closely follows the format of a
+FITS keyword record:
+-
+ KEYWORD = KEYVALUE / COMMENT
+-
+except that free format may be used (e.g., the equals sign may appear
+at any position in the line) and TAB characters are allowed and are
+treated the same as space characters. The KEYVALUE and COMMENT fields
+are optional. The equals sign character is also optional, but it is
+recommended that it be included for clarity. Any template line that
+begins with the pound '\#' character is ignored by the template parser
+and may be use to insert comments into the template file itself.
+
+The KEYWORD name field is limited to 8 characters in length and only
+the letters A-Z, digits 0-9, and the hyphen and underscore characters
+may be used, without any embedded spaces. Lowercase letters in the
+template keyword name will be converted to uppercase. Leading spaces
+in the template line preceding the keyword name are generally ignored,
+except if the first 8 characters of a template line are all blank, then
+the entire line is treated as a FITS comment keyword (with a blank
+keyword name) and is copied verbatim into the FITS header.
+
+The KEYVALUE field may have any allowed FITS data type: character
+string, logical, integer, real, complex integer, or complex real. The
+character string values need not be enclosed in single quote characters
+unless they are necessary to distinguish the string from a different
+data type (e.g. 2.0 is a real but '2.0' is a string). The keyword has
+an undefined (null) value if the template record only contains blanks
+following the "=" or between the "=" and the "/" comment field
+delimiter.
+
+String keyword values longer than 68 characters (the maximum length
+that will fit in a single FITS keyword record) are permitted using the
+CFITSIO long string convention. They can either be specified as a
+single long line in the template, or by using multiple lines where the
+continuing lines contain the 'CONTINUE' keyword, as in this example:
+-
+ LONGKEY = 'This is a long string value that is contin&'
+ CONTINUE 'ued over 2 records' / comment field goes here
+-
+The format of template lines with CONTINUE keyword is very strict: 3
+spaces must follow CONTINUE and the rest of the line is copied verbatim
+to the FITS file.
+
+The start of the optional COMMENT field must be preceded by "/", which
+is used to separate it from the keyword value field. Exceptions are if
+the KEYWORD name field contains COMMENT, HISTORY, CONTINUE, or if the
+first 8 characters of the template line are blanks.
+
+More than one Header-Data Unit (HDU) may be defined in the template
+file. The start of an HDU definition is denoted with a SIMPLE or
+XTENSION template line:
+
+1) SIMPLE begins a Primary HDU definition. SIMPLE may only appear as
+the first keyword in the template file. If the template file begins
+with XTENSION instead of SIMPLE, then a default empty Primary HDU is
+created, and the template is then assumed to define the keywords
+starting with the first extension following the Primary HDU.
+
+2) XTENSION marks the beginning of a new extension HDU definition. The
+previous HDU will be closed at this point and processing of the next
+extension begins.
+
+**B Auto-indexing of Keywords
+
+If a template keyword name ends with a "\#" character, it is said to be
+'auto-indexed'. Each "\#" character will be replaced by the current
+integer index value, which gets reset = 1 at the start of each new HDU
+in the file (or 7 in the special case of a GROUP definition). The
+FIRST indexed keyword in each template HDU definition is used as the
+'incrementor'; each subsequent occurrence of this SAME keyword will
+cause the index value to be incremented. This behavior can be rather
+subtle, as illustrated in the following examples in which the TTYPE
+keyword is the incrementor in both cases:
+-
+ TTYPE# = TIME
+ TFORM# = 1D
+ TTYPE# = RATE
+ TFORM# = 1E
+-
+will create TTYPE1, TFORM1, TTYPE2, and TFORM2 keywords. But if the
+template looks like,
+-
+ TTYPE# = TIME
+ TTYPE# = RATE
+ TFORM# = 1D
+ TFORM# = 1E
+-
+this results in a FITS files with TTYPE1, TTYPE2, TFORM2, and TFORM2,
+which is probably not what was intended!
+
+**C Template Parser Directives
+
+In addition to the template lines which define individual keywords, the
+template parser recognizes 3 special directives which are each preceded
+by the backslash character: \verb+ \include, \group+, and \verb+ \end+.
+
+The 'include' directive must be followed by a filename. It forces the
+parser to temporarily stop reading the current template file and begin
+reading the include file. Once the parser reaches the end of the
+include file it continues parsing the current template file. Include
+files can be nested, and HDU definitions can span multiple template
+files.
+
+The start of a GROUP definition is denoted with the 'group' directive,
+and the end of a GROUP definition is denoted with the 'end' directive.
+Each GROUP contains 0 or more member blocks (HDUs or GROUPs). Member
+blocks of type GROUP can contain their own member blocks. The GROUP
+definition itself occupies one FITS file HDU of special type (GROUP
+HDU), so if a template specifies 1 group with 1 member HDU like:
+-
+\group
+grpdescr = 'demo'
+xtension bintable
+# this bintable has 0 cols, 0 rows
+\end
+-
+then the parser creates a FITS file with 3 HDUs :
+-
+1) dummy PHDU
+2) GROUP HDU (has 1 member, which is bintable in HDU number 3)
+3) bintable (member of GROUP in HDU number 2)
+-
+Technically speaking, the GROUP HDU is a BINTABLE with 6 columns. Applications
+can define additional columns in a GROUP HDU using TFORMn and TTYPEn
+(where n is 7, 8, ....) keywords or their auto-indexing equivalents.
+
+For a more complicated example of a template file using the group directives,
+look at the sample.tpl file that is included in the CFITSIO distribution.
+
+**D Formal Template Syntax
+
+The template syntax can formally be defined as follows:
+-
+ TEMPLATE = BLOCK [ BLOCK ... ]
+
+ BLOCK = { HDU | GROUP }
+
+ GROUP = \GROUP [ BLOCK ... ] \END
+
+ HDU = XTENSION [ LINE ... ] { XTENSION | \GROUP | \END | EOF }
+
+ LINE = [ KEYWORD [ = ] ] [ VALUE ] [ / COMMENT ]
+
+ X ... - X can be present 1 or more times
+ { X | Y } - X or Y
+ [ X ] - X is optional
+-
+
+At the topmost level, the template defines 1 or more template blocks. Blocks
+can be either HDU (Header Data Unit) or a GROUP. For each block the parser
+creates 1 (or more for GROUPs) FITS file HDUs.
+
+
+**E Errors
+
+In general the fits\_execute\_template() function tries to be as atomic
+as possible, so either everything is done or nothing is done. If an
+error occurs during parsing of the template, fits\_execute\_template()
+will (try to) delete the top level BLOCK (with all its children if any)
+in which the error occurred, then it will stop reading the template file
+and it will return with an error.
+
+**F Examples
+
+1. This template file will create a 200 x 300 pixel image, with 4-byte
+integer pixel values, in the primary HDU:
+-
+ SIMPLE = T
+ BITPIX = 32
+ NAXIS = 2 / number of dimensions
+ NAXIS1 = 100 / length of first axis
+ NAXIS2 = 200 / length of second axis
+ OBJECT = NGC 253 / name of observed object
+-
+The allowed values of BITPIX are 8, 16, 32, -32, or -64,
+representing, respectively, 8-bit integer, 16-bit integer, 32-bit
+integer, 32-bit floating point, or 64 bit floating point pixels.
+
+2. To create a FITS table, the template first needs to include
+XTENSION = TABLE or BINTABLE to define whether it is an ASCII or binary
+table, and NAXIS2 to define the number of rows in the table. Two
+template lines are then needed to define the name (TTYPEn) and FITS data
+format (TFORMn) of the columns, as in this example:
+-
+ xtension = bintable
+ naxis2 = 40
+ ttype# = Name
+ tform# = 10a
+ ttype# = Npoints
+ tform# = j
+ ttype# = Rate
+ tunit# = counts/s
+ tform# = e
+-
+The above example defines a null primary array followed by a 40-row
+binary table extension with 3 columns called 'Name', 'Npoints', and
+'Rate', with data formats of '10A' (ASCII character string), '1J'
+(integer) and '1E' (floating point), respectively. Note that the other
+required FITS keywords (BITPIX, NAXIS, NAXIS1, PCOUNT, GCOUNT, TFIELDS,
+and END) do not need to be explicitly defined in the template because
+their values can be inferred from the other keywords in the template.
+This example also illustrates that the templates are generally
+case-insensitive (the keyword names and TFORMn values are converted to
+upper-case in the FITS file) and that string keyword values generally
+do not need to be enclosed in quotes.
+
+*V. FITSIO Conventions and Guidelines
+
+**A. CFITSIO Size Limitations
+
+CFITSIO places few restrictions on the size of FITS files that it
+reads or writes. There are a few limits, however, which may affect
+some extreme cases:
+
+1. The maximum number of FITS files that may be simultaneously opened
+by CFITSIO is set by NMAXFILES as defined in fitsio2.h. It is currently
+set = 300 by default. CFITSIO will allocate about 80 * NMAXFILES bytes
+of memory for internal use. Note that the underlying C compiler or
+operating system, may have a smaller limit on the number of opened files.
+The C symbolic constant FOPEN\_MAX is intended to define the maximum
+number of files that may open at once (including any other text or
+binary files that may be open, not just FITS files). On some systems it
+has been found that gcc supports a maximum of 255 opened files.
+
+Note that opening and operating on many FITS files simultaneously in
+parallel may be less efficient than operating on smaller groups of files
+in series. CFITSIO only has NIOBUF number of internal buffers (set = 40
+by default) that are used for temporary storage of the most recent data
+records that have been read or written in the FITS files. If the number
+of opened files is greater than NIOBUF, then CFITSIO may waste more time
+flushing and re-reading or re-writing the same records in the FITS files.
+
+2. By default, CFITSIO can handle FITS files up to 2.1 GB in size (2**31
+bytes). This file size limit is often imposed by 32-bit operating
+systems. More recently, as 64-bit operating systems become more common, an
+industry-wide standard (at least on Unix systems) has been developed to
+support larger sized files (see http://ftp.sas.com/standards/large.file/).
+Starting with version 2.1 of CFITSIO, larger FITS files up to 6 terabytes
+in size may be read and written on supported platforms. In order
+to support these larger files, CFITSIO must be compiled with the
+'-D\_LARGEFILE\_SOURCE' and `-D\_FILE\_OFFSET\_BITS=64' compiler flags.
+Some platforms may also require the `-D\_LARGE\_FILES' compiler flag.
+ This causes the compiler to allocate 8-bytes instead of
+4-bytes for the `off\_t' datatype which is used to store file offset
+positions. It appears that in most cases it is not necessary to
+also include these compiler flags when compiling programs that link to
+the CFITSIO library.
+
+If CFITSIO is compiled with the -D\_LARGEFILE\_SOURCE
+and -D\_FILE\_OFFSET\_BITS=64 flags on a
+platform that supports large files, then it can read and write FITS
+files that contain up to 2**31 2880-byte FITS records, or approximately
+6 terabytes in size. It is still required that the value of the NAXISn
+and PCOUNT keywords in each extension be within the range of a signed
+4-byte integer (max value = 2,147,483,648). Thus, each dimension of an
+image (given by the NAXISn keywords), the total width of a table
+(NAXIS1 keyword), the number of rows in a table (NAXIS2 keyword), and
+the total size of the variable-length array heap in binary tables
+(PCOUNT keyword) must be less than this limit.
+
+Currently, support for large files within CFITSIO has been tested
+on the Linux, Solaris, and IBM AIX operating systems.
+
+**B. Multiple Access to the Same FITS File
+
+CFITSIO supports simultaneous read and write access to multiple HDUs in
+the same FITS file. Thus, one can open the same FITS file twice within
+a single program and move to 2 different HDUs in the file, and then
+read and write data or keywords to the 2 extensions just as if one were
+accessing 2 completely separate FITS files. Since in general it is
+not possible to physically open the same file twice and then expect to
+be able to simultaneously (or in alternating succession) write to 2
+different locations in the file, CFITSIO recognizes when the file to be
+opened (in the call to fits\_open\_file) has already been opened and
+instead of actually opening the file again, just logically links the
+new file to the old file. (This only applies if the file is opened
+more than once within the same program, and does not prevent the same
+file from being simultaneously opened by more than one program). Then
+before CFITSIO reads or writes to either (logical) file, it makes sure
+that any modifications made to the other file have been completely
+flushed from the internal buffers to the file. Thus, in principle, one
+could open a file twice, in one case pointing to the first extension
+and in the other pointing to the 2nd extension and then write data to
+both extensions, in any order, without danger of corrupting the file,
+There may be some efficiency penalties in doing this however, since
+CFITSIO has to flush all the internal buffers related to one file
+before switching to the other, so it would still be prudent to
+minimize the number of times one switches back and forth between doing
+I/O to different HDUs in the same file.
+
+**C. Current Header Data Unit (CHDU)
+
+In general, a FITS file can contain multiple Header Data Units, also
+called extensions. CFITSIO only operates within one HDU at any given
+time, and the currently selected HDU is called the Current Header Data
+Unit (CHDU). When a FITS file is first created or opened the CHDU is
+automatically defined to be the first HDU (i.e., the primary array).
+CFITSIO routines are provided to move to and open any other existing
+HDU within the FITS file or to append or insert a new HDU in the FITS
+file which then becomes the CHDU.
+
+**D. Subroutine Names
+
+All FITSIO subroutine names begin with the letters 'ft' to distinguish
+them from other subroutines and are 5 or 6 characters long. Users should
+not name their own subroutines beginning with 'ft' to avoid conflicts.
+(The SPP interface routines all begin with 'fs'). Subroutines which read
+or get information from the FITS file have names beginning with
+'ftg...'. Subroutines which write or put information into the FITS file
+have names beginning with 'ftp...'.
+
+**E. Subroutine Families and Datatypes
+
+Many of the subroutines come in families which differ only in the
+datatype of the associated parameter(s) . The datatype of these
+subroutines is indicated by the last letter of the subroutine name
+(e.g., 'j' in 'ftpkyj') as follows:
+-
+ x - bit
+ b - character*1 (unsigned byte)
+ i - short integer (I*2)
+ j - integer (I*4)
+ e - real exponential floating point (R*4)
+ f - real fixed-format floating point (R*4)
+ d - double precision real floating-point (R*8)
+ g - double precision fixed-format floating point (R*8)
+ c - complex reals (pairs of R*4 values)
+ m - double precision complex (pairs of R*8 values)
+ l - logical (L*4)
+ s - character string
+-
+
+When dealing with the FITS byte datatype, it is important to remember
+that the raw values (before any scaling by the BSCALE and BZERO, or
+TSCALn and TZEROn keyword values) in byte arrays (BITPIX = 8) or byte
+columns (TFORMn = 'B') are interpreted as unsigned bytes with values
+ranging from 0 to 255. Some Fortran compilers support a non-standard
+byte datatype such as INTEGER*1, LOGICAL*1, or BYTE, which can sometimes
+be used instead of CHARACTER*1 variables. Many machines permit passing a
+numeric datatype (such as INTEGER*1) to the FITSIO subroutines which are
+expecting a CHARACTER*1 datatype, but this technically violates the
+Fortran-77 standard and is not supported on all machines (e.g., on a VAX/VMS
+machine one must use the VAX-specific \%DESCR function).
+
+One feature of the CFITSIO routines is that they can operate on a `X'
+(bit) column in a binary table as though it were a `B' (byte) column.
+For example a `11X' datatype column can be interpreted the same as a
+`2B' column (i.e., 2 unsigned 8-bit bytes). In some instances, it can
+be more efficient to read and write whole bytes at a time, rather than
+reading or writing each individual bit.
+
+The double precision complex datatype is not a standard Fortran-77
+datatype. If a particular Fortran compiler does not directly support
+this datatype, then one may instead pass an array of pairs of double
+precision values to these subroutines. The first value in each pair
+is the real part, and the second is the imaginary part.
+
+**F. Implicit Data Type Conversion
+
+The FITSIO routines that read and write numerical data can perform
+implicit data type conversion. This means that the data type of the
+variable or array in the program does not need to be the same as the
+data type of the value in the FITS file. Data type conversion is
+supported for numerical and string data types (if the string contains a
+valid number enclosed in quotes) when reading a FITS header keyword
+value and for numeric values when reading or writing values in the
+primary array or a table column. CFITSIO returns status =
+NUM\_OVERFLOW if the converted data value exceeds the range of the
+output data type. Implicit data type conversion is not supported
+within binary tables for string, logical, complex, or double complex
+data types.
+
+In addition, any table column may be read as if it contained string values.
+In the case of numeric columns the returned string will be formatted
+using the TDISPn display format if it exists.
+
+**G. Data Scaling
+
+When reading numerical data values in the primary array or a
+table column, the values will be scaled automatically by the BSCALE and
+BZERO (or TSCALn and TZEROn) header keyword values if they are
+present in the header. The scaled data that is returned to the reading
+program will have
+-
+ output value = (FITS value) * BSCALE + BZERO
+-
+(a corresponding formula using TSCALn and TZEROn is used when reading
+from table columns). In the case of integer output values the floating
+point scaled value is truncated to an integer (not rounded to the
+nearest integer). The ftpscl and fttscl subroutines may be used to
+override the scaling parameters defined in the header (e.g., to turn
+off the scaling so that the program can read the raw unscaled values
+from the FITS file).
+
+When writing numerical data to the primary array or to a table
+column the data values will generally be automatically inversely scaled
+by the value of the BSCALE and BZERO (or TSCALn and TZEROn) header
+keyword values if they they exist in the header. These keywords must
+have been written to the header before any data is written for them to
+have any effect. Otherwise, one may use the ftpscl and fttscl
+subroutines to define or override the scaling keywords in the header
+(e.g., to turn off the scaling so that the program can write the raw
+unscaled values into the FITS file). If scaling is performed, the
+inverse scaled output value that is written into the FITS file will
+have
+-
+ FITS value = ((input value) - BZERO) / BSCALE
+-
+(a corresponding formula using TSCALn and TZEROn is used when
+writing to table columns). Rounding to the nearest integer, rather
+than truncation, is performed when writing integer datatypes to the
+FITS file.
+
+**H. Error Status Values and the Error Message Stack
+
+The last parameter in nearly every FITSIO subroutine is the error
+status value which is both an input and an output parameter. A
+returned positive value for this parameter indicates an error was
+detected. A listing of all the FITSIO status code values is given at
+the end of this document.
+
+The FITSIO library uses an `inherited status' convention for the status
+parameter which means that if a subroutine is called with a positive
+input value of the status parameter, then the subroutine will exit
+immediately without changing the value of the status parameter. Thus,
+if one passes the status value returned from each FITSIO routine as
+input to the next FITSIO subroutine, then whenever an error is detected
+all further FITSIO processing will cease. This convention can simplify
+the error checking in application programs because it is not necessary
+to check the value of the status parameter after every single FITSIO
+subroutine call. If a program contains a sequence of several FITSIO
+calls, one can just check the status value after the last call. Since
+the returned status values are generally distinctive, it should be
+possible to determine which subroutine originally returned the error
+status.
+
+FITSIO also maintains an internal stack of error messages (80-character
+maximum length) which in many cases provide a more detailed explanation
+of the cause of the error than is provided by the error status number
+alone. It is recommended that the error message stack be printed out
+whenever a program detects a FITSIO error. To do this, call the FTGMSG
+routine repeatedly to get the successive messages on the stack. When the
+stack is empty FTGMSG will return a blank string. Note that this is a
+`First In -- First Out' stack, so the oldest error message is returned
+first by ftgmsg.
+
+**I. Variable-Length Array Facility in Binary Tables
+
+FITSIO provides easy-to-use support for reading and writing data in
+variable length fields of a binary table. The variable length columns
+have TFORMn keyword values of the form `1Pt(len)' where `t' is the
+datatype code (e.g., I, J, E, D, etc.) and `len' is an integer
+specifying the maximum length of the vector in the table. If the value
+of `len' is not specified when the table is created (e.g., if the TFORM
+keyword value is simply specified as '1PE' instead of '1PE(400) ), then
+FITSIO will automatically scan the table when it is closed to
+determine the maximum length of the vector and will append this value
+to the TFORMn value.
+
+The same routines which read and write data in an ordinary fixed length
+binary table extension are also used for variable length fields,
+however, the subroutine parameters take on a slightly different
+interpretation as described below.
+
+All the data in a variable length field is written into an area called
+the `heap' which follows the main fixed-length FITS binary table. The
+size of the heap, in bytes, is specified with the PCOUNT keyword in the
+FITS header. When creating a new binary table, the initial value of
+PCOUNT should usually be set to zero. FITSIO will recompute the size
+of the heap as the data is written and will automatically update the
+PCOUNT keyword value when the table is closed. When writing variable
+length data to a table, CFITSIO will automatically extend the size
+of the heap area if necessary, so that any following HDUs do not
+get overwritten.
+
+By default the heap data area starts immediately after the last row of
+the fixed-length table. This default starting location may be
+overridden by the THEAP keyword, but this is not recommended.
+If additional rows of data are added to the table, CFITSIO will
+automatically shift the the heap down to make room for the new
+rows, but it is obviously be more efficient to initially
+create the table with the necessary number of blank rows, so that
+the heap does not needed to be constantly moved.
+
+When writing to a variable length field, the entire array of values for
+a given row of the table must be written with a single call to FTPCLx.
+The total length of the array is calculated from (NELEM+FELEM-1). One
+cannot append more elements to an existing field at a later time; any
+attempt to do so will simply overwrite all the data which was previously
+written. Note also that the new data will be written to a new area of
+the heap and the heap space used by the previous write cannot be
+reclaimed. For this reason it is advised that each row of a variable
+length field only be written once. An exception to this general rule
+occurs when setting elements of an array as undefined. One must first
+write a dummy value into the array with FTPCLx, and then call FTPCLU to
+flag the desired elements as undefined. (Do not use the FTPCNx family
+of routines with variable length fields). Note that the rows of a table,
+whether fixed or variable length, do not have to be written
+consecutively and may be written in any order.
+
+When writing to a variable length ASCII character field (e.g., TFORM =
+'1PA') only a single character string written. FTPCLS writes the whole
+length of the input string (minus any trailing blank characters), thus
+the NELEM and FELEM parameters are ignored. If the input string is
+completely blank then FITSIO will write one blank character to the FITS
+file. Similarly, FTGCVS and FTGCFS read the entire string (truncated
+to the width of the character string argument in the subroutine call)
+and also ignore the NELEM and FELEM parameters.
+
+The FTPDES subroutine is useful in situations where multiple rows of a
+variable length column have the identical array of values. One can
+simply write the array once for the first row, and then use FTPDES to
+write the same descriptor values into the other rows (use the FTGDES
+routine to read the first descriptor value); all the rows will then
+point to the same storage location thus saving disk space.
+
+When reading from a variable length array field one can only read as
+many elements as actually exist in that row of the table; reading does
+not automatically continue with the next row of the table as occurs
+when reading an ordinary fixed length table field. Attempts to read
+more than this will cause an error status to be returned. One can
+determine the number of elements in each row of a variable column with
+the FTGDES subroutine.
+
+**I. Support for IEEE Special Values
+
+The ANSI/IEEE-754 floating-point number standard defines certain
+special values that are used to represent such quantities as
+Not-a-Number (NaN), denormalized, underflow, overflow, and infinity.
+(See the Appendix in the NOST FITS standard or the NOST FITS User's
+Guide for a list of these values). The FITSIO subroutines that read
+floating point data in FITS files recognize these IEEE special values
+and by default interpret the overflow and infinity values as being
+equivalent to a NaN, and convert the underflow and denormalized values
+into zeros. In some cases programmers may want access to the raw IEEE
+values, without any modification by FITSIO. This can be done by
+calling the FTGPVx or FTGCVx routines while specifying 0.0 as the value
+of the NULLVAL parameter. This will force FITSIO to simply pass the
+IEEE values through to the application program, without any
+modification. This does not work for double precision values on
+VAX/VMS machines, however, where there is no easy way to bypass the
+default interpretation of the IEEE special values.
+
+**J. When the Final Size of the FITS HDU is Unknown
+
+It is not required to know the total size of a FITS data array or table
+before beginning to write the data to the FITS file. In the case of
+the primary array or an image extension, one should initially create
+the array with the size of the highest dimension (largest NAXISn
+keyword) set to a dummy value, such as 1. Then after all the data have
+been written and the true dimensions are known, then the NAXISn value
+should be updated using the fits\_ update\_key routine before moving to
+another extension or closing the FITS file.
+
+When writing to FITS tables, CFITSIO automatically keeps track of the
+highest row number that is written to, and will increase the size of
+the table if necessary. CFITSIO will also automatically insert space
+in the FITS file if necessary, to ensure that the data 'heap', if it
+exists, and/or any additional HDUs that follow the table do not get
+overwritten as new rows are written to the table.
+
+As a general rule it is best to specify the initial number of rows = 0
+when the table is created, then let CFITSIO keep track of the number of
+rows that are actually written. The application program should not
+manually update the number of rows in the table (as given by the NAXIS2
+keyword) since CFITSIO does this automatically. If a table is
+initially created with more than zero rows, then this will usually be
+considered as the minimum size of the table, even if fewer rows are
+actually written to the table. Thus, if a table is initially created
+with NAXIS2 = 20, and CFITSIO only writes 10 rows of data before
+closing the table, then NAXIS2 will remain equal to 20. If however, 30
+rows of data are written to this table, then NAXIS2 will be increased
+from 20 to 30. The one exception to this automatic updating of the
+NAXIS2 keyword is if the application program directly modifies the
+value of NAXIS2 (up or down) itself just before closing the table. In this
+case, CFITSIO does not update NAXIS2 again, since it assumes that the
+application program must have had a good reason for changing the value
+directly. This is not recommended, however, and is only provided for
+backward compatibility with software that initially creates a table
+with a large number of rows, than decreases the NAXIS2 value to the
+actual smaller value just before closing the table.
+
+**K. Local FITS Conventions supported by FITSIO
+
+CFITSIO supports several local FITS conventions which are not
+defined in the official NOST FITS standard and which are not
+necessarily recognized or supported by other FITS software packages.
+Programmers should be cautious about using these features, especially
+if the FITS files that are produced are expected to be processed by
+other software systems which do not use the CFITSIO interface.
+
+***1. Support for Long String Keyword Values.
+
+The length of a standard FITS string keyword is limited to 68
+characters because it must fit entirely within a single FITS header
+keyword record. In some instances it is necessary to encode strings
+longer than this limit, so FITSIO supports a local convention in which
+the string value is continued over multiple keywords. This
+continuation convention uses an ampersand character at the end of each
+substring to indicate that it is continued on the next keyword, and the
+continuation keywords all have the name CONTINUE without an equal sign
+in column 9. The string value may be continued in this way over as many
+additional CONTINUE keywords as is required. The following lines
+illustrate this continuation convention which is used in the value of
+the STRKEY keyword:
+-
+LONGSTRN= 'OGIP 1.0' / The OGIP Long String Convention may be used.
+STRKEY = 'This is a very long string keyword&' / Optional Comment
+CONTINUE ' value that is continued over 3 keywords in the & '
+CONTINUE 'FITS header.' / This is another optional comment.
+-
+It is recommended that the LONGSTRN keyword, as shown
+here, always be included in any HDU that uses this longstring
+convention. A subroutine called FTPLSW
+has been provided in CFITSIO to write this keyword if it does not
+already exist.
+
+This long string convention is supported by the following FITSIO
+subroutines that deal with string-valued keywords:
+-
+ ftgkys - read a string keyword
+ ftpkls - write (append) a string keyword
+ ftikls - insert a string keyword
+ ftmkls - modify the value of an existing string keyword
+ ftukls - update an existing keyword, or write a new keyword
+ ftdkey - delete a keyword
+-
+These routines will transparently read, write, or delete a long string
+value in the FITS file, so programmers in general do not have to be
+concerned about the details of the convention that is used to encode
+the long string in the FITS header. When reading a long string, one
+must ensure that the character string parameter used in these
+subroutine calls has been declared long enough to hold the entire
+string, otherwise the returned string value will be truncated.
+
+Note that the more commonly used FITSIO subroutine to write string
+valued keywords (FTPKYS) does NOT support this long string convention
+and only supports strings up to 68 characters in length. This has been
+done deliberately to prevent programs from inadvertently writing
+keywords using this non-standard convention without the explicit intent
+of the programmer or user. The FTPKLS subroutine must be called
+instead to write long strings. This routine can also be used to write
+ordinary string values less than 68 characters in length.
+
+***2. Arrays of Fixed-Length Strings in Binary Tables
+
+The definition of the FITS binary table extension format does not
+provide a simple way to specify that a character column contains an
+array of fixed-length strings. To support this feature, FITSIO uses a
+local convention for the format of the TFORMn keyword value of the form
+'rAw' where 'r' is an integer specifying the total width in characters
+of the column, and 'w' is an integer specifying the (fixed) length of
+an individual unit string within the vector. For example, TFORM1 =
+'120A10' would indicate that the binary table column is 120 characters
+wide and consists of 12 10-character length strings. This convention
+is recognized by the FITSIO subroutines that read or write strings in
+binary tables. The Binary Table definition document specifies that
+other optional characters may follow the datatype code in the TFORM
+keyword, so this local convention is in compliance with the
+FITS standard, although other FITS readers are not required to
+recognize this convention.
+
+The Binary Table definition document that was approved by the IAU in
+1994 contains an appendix describing an alternate convention for
+specifying arrays of fixed or variable length strings in a binary table
+character column (with the form 'rA:SSTRw/nnn)'. This appendix was not
+officially voted on by the IAU and hence is still provisional. FITSIO
+does not currently support this proposal.
+
+***3. Keyword Units Strings
+
+One deficiency of the current FITS Standard is that it does not define
+a specific convention for recording the physical units of a keyword
+value. The TUNITn keyword can be used to specify the physical units of
+the values in a table column, but there is no analogous convention for
+keyword values. The comment field of the keyword is often used for
+this purpose, but the units are usually not specified in a well defined
+format that FITS readers can easily recognize and extract.
+
+To solve this deficiency, FITSIO uses a local convention in which the
+keyword units are enclosed in square brackets as the first token in the
+keyword comment field; more specifically, the opening square bracket
+immediately follows the slash '/' comment field delimiter and a single
+space character. The following examples illustrate keywords that use
+this convention:
+
+-
+EXPOSURE= 1800.0 / [s] elapsed exposure time
+V_HELIO = 16.23 / [km s**(-1)] heliocentric velocity
+LAMBDA = 5400. / [angstrom] central wavelength
+FLUX = 4.9033487787637465E-30 / [J/cm**2/s] average flux
+-
+
+In general, the units named in the IAU(1988) Style Guide are
+recommended, with the main exception that the preferred unit for angle
+is 'deg' for degrees.
+
+The FTPUNT and FTGUNT subroutines in FITSIO write and read,
+respectively, the keyword unit strings in an existing keyword.
+
+***4. HIERARCH Convention for Extended Keyword Names
+
+CFITSIO supports the HIERARCH keyword convention which allows keyword
+names that are longer then 8 characters and may contain the full range
+of printable ASCII text characters. This convention
+was developed at the European Southern Observatory (ESO) to support
+hierarchical FITS keyword such as:
+-
+HIERARCH ESO INS FOCU POS = -0.00002500 / Focus position
+-
+Basically, this convention uses the FITS keyword 'HIERARCH' to indicate
+that this convention is being used, then the actual keyword name
+({\tt'ESO INS FOCU POS'} in this example) begins in column 10 and can
+contain any printable ASCII text characters, including spaces. The
+equals sign marks the end of the keyword name and is followed by the
+usual value and comment fields just as in standard FITS keywords.
+Further details of this convention are described at
+http://arcdev.hq.eso.org/dicb/dicd/dic-1-1.4.html (search for
+HIERARCH).
+
+This convention allows a much broader range of keyword names
+than is allowed by the FITS Standard. Here are more examples
+of such keywords:
+-
+HIERARCH LongKeyword = 47.5 / Keyword has > 8 characters, and mixed case
+HIERARCH XTE$TEMP = 98.6 / Keyword contains the '$' character
+HIERARCH Earth is a star = F / Keyword contains embedded spaces
+-
+CFITSIO will transparently read and write these keywords, so application
+programs do not in general need to know anything about the specific
+implementation details of the HIERARCH convention. In particular,
+application programs do not need to specify the `HIERARCH' part of the
+keyword name when reading or writing keywords (although it
+may be included if desired). When writing a keyword, CFITSIO first
+checks to see if the keyword name is legal as a standard FITS keyword
+(no more than 8 characters long and containing only letters, digits, or
+a minus sign or underscore). If so it writes it as a standard FITS
+keyword, otherwise it uses the hierarch convention to write the
+keyword. The maximum keyword name length is 67 characters, which
+leaves only 1 space for the value field. A more practical limit is
+about 40 characters, which leaves enough room for most keyword values.
+CFITSIO returns an error if there is not enough room for both the
+keyword name and the keyword value on the 80-character card, except for
+string-valued keywords which are simply truncated so that the closing
+quote character falls in column 80. In the current implementation,
+CFITSIO preserves the case of the letters when writing the keyword
+name, but it is case-insensitive when reading or searching for a
+keyword. The current implementation allows any ASCII text character
+(ASCII 32 to ASCII 126) in the keyword name except for the '='
+character. A space is also required on either side of the equal sign.
+
+**L. Optimizing Code for Maximum Processing Speed
+
+CFITSIO has been carefully designed to obtain the highest possible
+speed when reading and writing FITS files. In order to achieve the
+best performance, however, application programmers must be careful to
+call the CFITSIO routines appropriately and in an efficient sequence;
+inappropriate usage of CFITSIO routines can greatly slow down the
+execution speed of a program.
+
+The maximum possible I/O speed of CFITSIO depends of course on the type
+of computer system that it is running on. As a rough guide, the
+current generation of workstations can achieve speeds of 2 -- 10 MB/s
+when reading or writing FITS images and similar, or slightly slower
+speeds with FITS binary tables. Reading of FITS files can occur at
+even higher rates (30MB/s or more) if the FITS file is still cached in
+system memory following a previous read or write operation on the same
+file. To more accurately predict the best performance that is possible
+on any particular system, a diagnostic program called ``speed.c'' is
+included with the CFITSIO distribution which can be run to
+approximately measure the maximum possible speed of writing and reading
+a test FITS file.
+
+The following 2 sections provide some background on how CFITSIO
+internally manages the data I/O and describes some strategies that may
+be used to optimize the processing speed of software that uses
+CFITSIO.
+
+***1. Background Information: How CFITSIO Manages Data I/O
+
+Many CFITSIO operations involve transferring only a small number of
+bytes to or from the FITS file (e.g, reading a keyword, or writing a
+row in a table); it would be very inefficient to physically read or
+write such small blocks of data directly in the FITS file on disk,
+therefore CFITSIO maintains a set of internal Input--Output (IO)
+buffers in RAM memory that each contain one FITS block (2880 bytes) of
+data. Whenever CFITSIO needs to access data in the FITS file, it first
+transfers the FITS block containing those bytes into one of the IO
+buffers in memory. The next time CFITSIO needs to access bytes in the
+same block it can then go to the fast IO buffer rather than using a
+much slower system disk access routine. The number of available IO
+buffers is determined by the NIOBUF parameter (in fitsio2.h) and is
+currently set to 40.
+
+Whenever CFITSIO reads or writes data it first checks to see if that
+block of the FITS file is already loaded into one of the IO buffers.
+If not, and if there is an empty IO buffer available, then it will load
+that block into the IO buffer (when reading a FITS file) or will
+initialize a new block (when writing to a FITS file). If all the IO
+buffers are already full, it must decide which one to reuse (generally
+the one that has been accessed least recently), and flush the contents
+back to disk if it has been modified before loading the new block.
+
+The one major exception to the above process occurs whenever a large
+contiguous set of bytes are accessed, as might occur when reading or
+writing a FITS image. In this case CFITSIO bypasses the internal IO
+buffers and simply reads or writes the desired bytes directly in the
+disk file with a single call to a low-level file read or write
+routine. The minimum threshold for the number of bytes to read or
+write this way is set by the MINDIRECT parameter and is currently set
+to 3 FITS blocks = 8640 bytes. This is the most efficient way to read
+or write large chunks of data and can achieve IO transfer rates of
+5 -- 10MB/s or greater. Note that this fast direct IO process is not
+applicable when accessing columns of data in a FITS table because the
+bytes are generally not contiguous since they are interleaved by the
+other columns of data in the table. This explains why the speed for
+accessing FITS tables is generally slower than accessing
+FITS images.
+
+Given this background information, the general strategy for efficiently
+accessing FITS files should now be apparent: when dealing with FITS
+images, read or write large chunks of data at a time so that the direct
+IO mechanism will be invoked; when accessing FITS headers or FITS
+tables, on the other hand, once a particular FITS block has been
+loading into one of the IO buffers, try to access all the needed
+information in that block before it gets flushed out of the IO buffer.
+It is important to avoid the situation where the same FITS block is
+being read then flushed from a IO buffer multiple times.
+
+The following section gives more specific suggestions for optimizing
+the use of CFITSIO.
+
+1. When dealing with a FITS primary array or IMAGE extension, it is
+more efficient to read or write large chunks of the image at a time
+(at least 3 FITS blocks = 8640 bytes) so that the direct IO mechanism
+will be used as described in the previous section. Smaller chunks of
+data are read or written via the IO buffers, which is somewhat less
+efficient because of the extra copy operation and additional
+bookkeeping steps that are required. In principle it is more efficient
+to read or write as big an array of image pixels at one time as
+possible, however, if the array becomes so large that the operating
+system cannot store it all in RAM, then the performance may be degraded
+because of the increased swapping of virtual memory to disk.
+
+2. When dealing with FITS tables, the most important efficiency factor
+in the software design is to read or write the data in the FITS file in
+a single pass through the file. An example of poor program design
+would be to read a large, 3-column table by sequentially reading the
+entire first column, then going back to read the 2nd column, and
+finally the 3rd column; this obviously requires 3 passes through the
+file which could triple the execution time of an I/O limited program.
+For small tables this is not important, but when reading multi-megabyte
+sized tables these inefficiencies can become significant. The more
+efficient procedure in this case is to read or write only as many rows
+of the table as will fit into the available internal I/O buffers, then
+access all the necessary columns of data within that range of rows.
+Then after the program is completely finished with the data in those
+rows it can move on to the next range of rows that will fit in the
+buffers, continuing in this way until the entire file has been
+processed. By using this procedure of accessing all the columns of a
+table in parallel rather than sequentially, each block of the FITS file
+will only be read or written once.
+
+The optimal number of rows to read or write at one time in a given
+table depends on the width of the table row, on the number of I/O
+buffers that have been allocated in FITSIO, and also on the number of
+other FITS files that are open at the same time (since one I/O buffer
+is always reserved for each open FITS file). Fortunately, a FITSIO
+routine is available that will return the optimal number of rows for a
+given table: call ftgrsz(unit, nrows, status). It is not critical to
+use exactly the value of nrows returned by this routine, as long as one
+does not exceed it. Using a very small value however can also lead to
+poor performance because of the overhead from the larger number of
+subroutine calls.
+
+The optimal number of rows returned by ftgrsz is valid only as long as
+the application program is only reading or writing data in the
+specified table. Any other calls to access data in the table header or
+in any other FITS file would cause additional blocks of data to be
+loaded into the I/O buffers displacing data from the original table,
+and should be avoided during the critical period while the table is
+being read or written.
+
+Occasionally it is necessary to simultaneously access more than one
+FITS table, for example when transferring values from an input table to
+an output table. In cases like this, one should call ftgrsz to get the
+optimal number of rows for each table separately, than reduce the
+number of rows proportionally. For example, if the optimal number of
+rows in the input table is 3600 and is 1400 in the output table, then
+these values should be cut in half to 1800 and 700, respectively, if
+both tables are going to be accessed at the same time.
+
+3. Use binary table extensions rather than ASCII table
+extensions for better efficiency when dealing with tabular data. The
+I/O to ASCII tables is slower because of the overhead in formatting or
+parsing the ASCII data fields, and because ASCII tables are about twice
+as large as binary tables with the same information content.
+
+4. Design software so that it reads the FITS header keywords in the
+same order in which they occur in the file. When reading keywords,
+FITSIO searches forward starting from the position of the last keyword
+that was read. If it reaches the end of the header without finding the
+keyword, it then goes back to the start of the header and continues the
+search down to the position where it started. In practice, as long as
+the entire FITS header can fit at one time in the available internal I/O
+buffers, then the header keyword access will be very fast and it makes
+little difference which order they are accessed.
+
+5. Avoid the use of scaling (by using the BSCALE and BZERO or TSCAL and
+TZERO keywords) in FITS files since the scaling operations add to the
+processing time needed to read or write the data. In some cases it may
+be more efficient to temporarily turn off the scaling (using ftpscl or
+fttscl) and then read or write the raw unscaled values in the FITS
+file.
+
+6. Avoid using the 'implicit datatype conversion' capability in
+FITSIO. For instance, when reading a FITS image with BITPIX = -32
+(32-bit floating point pixels), read the data into a single precision
+floating point data array in the program. Forcing FITSIO to convert
+the data to a different datatype can significantly slow the program.
+
+7. Where feasible, design FITS binary tables using vector column
+elements so that the data are written as a contiguous set of bytes,
+rather than as single elements in multiple rows. For example, it is
+faster to access the data in a table that contains a single row
+and 2 columns with TFORM keywords equal to '10000E' and '10000J', than
+it is to access the same amount of data in a table with 10000 rows
+which has columns with the TFORM keywords equal to '1E' and '1J'. In
+the former case the 10000 floating point values in the first column are
+all written in a contiguous block of the file which can be read or
+written quickly, whereas in the second case each floating point value
+in the first column is interleaved with the integer value in the second
+column of the same row so CFITSIO has to explicitly move to the
+position of each element to be read or written.
+
+8. Avoid the use of variable length vector columns in binary tables,
+since any reading or writing of these data requires that CFITSIO first
+look up or compute the starting address of each row of data in the
+heap.
+
+9. When copying data from one FITS table to another, it is faster to
+transfer the raw bytes instead of reading then writing each column of
+the table. The FITSIO subroutines FTGTBS and FTPTBS (for ASCII
+tables), and FTGTBB and FTPTBB (for binary tables) will perform
+low-level reads or writes of any contiguous range of bytes in a table
+extension. These routines can be used to read or write a whole row (or
+multiple rows) of a table with a single subroutine call. These
+routines are fast because they bypass all the usual data scaling, error
+checking and machine dependent data conversion that is normally done by
+FITSIO, and they allow the program to write the data to the output file
+in exactly the same byte order. For these same reasons, use of these
+routines can be somewhat risky because no validation or machine
+dependent conversion is performed by these routines. In general these
+routines are only recommended for optimizing critical pieces of code
+and should only be used by programmers who thoroughly understand the
+internal byte structure of the FITS tables they are reading or
+writing.
+
+10. Another strategy for improving the speed of writing a FITS table,
+similar to the previous one, is to directly construct the entire byte
+stream for a whole table row (or multiple rows) within the application
+program and then write it to the FITS file with
+ftptbb. This avoids all the overhead normally present
+in the column-oriented CFITSIO write routines. This technique should
+only be used for critical applications, because it makes the code more
+difficult to understand and maintain, and it makes the code more system
+dependent (e.g., do the bytes need to be swapped before writing to the
+FITS file?).
+
+11. Finally, external factors such as the type of magnetic disk
+controller (SCSI or IDE), the size of the disk cache, the average seek
+speed of the disk, the amount of disk fragmentation, and the amount of
+RAM available on the system can all have a significant impact on
+overall I/O efficiency. For critical applications, a system
+administrator should review the proposed system hardware to identify any
+potential I/O bottlenecks.
+
+
+*VI. The CFITSIO Iterator Function
+
+The fits\_iterate\_data function in CFITSIO provides a unique method of
+executing an arbitrary user-supplied `work' function that operates on
+rows of data in FITS tables or on pixels in FITS images. Rather than
+explicitly reading and writing the FITS images or columns of data, one
+instead calls the CFITSIO iterator routine, passing to it the name of
+the user's work function that is to be executed along with a list of
+all the table columns or image arrays that are to be passed to the work
+function. The CFITSIO iterator function then does all the work of
+allocating memory for the arrays, reading the input data from the FITS
+file, passing them to the work function, and then writing any output
+data back to the FITS file after the work function exits. Because
+it is often more efficient to process only a subset of the total table
+rows at one time, the iterator function can determine the optimum
+amount of data to pass in each iteration and repeatly call the work
+function until the entire table been processed.
+
+For many applications this single CFITSIO iterator function can
+effectively replace all the other CFITSIO routines for reading or
+writing data in FITS images or tables. Using the iterator has several
+important advantages over the traditional method of reading and writing
+FITS data files:
+
+\begin{itemize}
+\item
+It cleanly separates the data I/O from the routine that operates on
+the data. This leads to a more modular and `object oriented'
+programming style.
+
+\item
+It simplifies the application program by eliminating the need to allocate
+memory for the data arrays and eliminates most of the calls to the CFITSIO
+routines that explicitly read and write the data.
+
+\item
+It ensures that the data are processed as efficiently as possible.
+This is especially important when processing tabular data since
+the iterator function will calculate the most efficient number
+of rows in the table to be passed at one time to the user's work
+function on each iteration.
+
+\item
+Makes it possible for larger projects to develop a library of work
+functions that all have a uniform calling sequence and are all
+independent of the details of the FITS file format.
+
+\end{itemize}
+
+There are basically 2 steps in using the CFITSIO iterator function.
+The first step is to design the work function itself which must have a
+prescribed set of input parameters. One of these parameters is a
+structure containing pointers to the arrays of data; the work function
+can perform any desired operations on these arrays and does not need to
+worry about how the input data were read from the file or how the
+output data get written back to the file.
+
+The second step is to design the driver routine that opens all the
+necessary FITS files and initializes the input parameters to the
+iterator function. The driver program calls the CFITSIO iterator
+function which then reads the data and passes it to the user's work
+function.
+
+Further details on using the iterator function can be found in the
+companion CFITSIO User's Guide, and in the iter\_a.f, iter\_b.f and
+iter\_c.f example programs.
+
+
+
+*VII. Basic Interface Routines
+
+This section defines a basic set of subroutines that can be
+used to perform the most common types of read and write operations
+on FITS files. New users should start with these subroutines and
+then, as needed, explore the more advance routines described in
+the following chapter to perform more complex or specialized operations.
+
+A right arrow symbol ($>$) is used to separate the input parameters from
+the output parameters in the definition of each routine. This symbol
+is not actually part of the calling sequence. Note that
+the status parameter is both an input and an output parameter
+and must be initialized = 0 prior to calling the FITSIO subroutines.
+
+Refer to Chapter 9 for the definition of all the parameters
+used by these interface routines.
+
+**A. FITSIO Error Status Routines \label{FTVERS}
+
+>1 Return the current version number of the fitsio library.
+ The version number will be incremented with each new
+> release of CFITSIO.
+-
+ FTVERS( > version)
+-
+>2 Return the descriptive text string corresponding to a FITSIO error
+ status code. The 30-character length string contains a brief
+> description of the cause of the error.
+-
+ FTGERR(status, > errtext)
+-
+>3 Return the top (oldest) 80-character error message from the
+ internal FITSIO stack of error messages and shift any remaining
+ messages on the stack up one level. Any FITSIO error will
+ generate one or more messages on the stack. Call this routine
+ repeatedly to get each message in sequence. The error stack is empty
+> when a blank string is returned.
+-
+ FTGMSG( > errmsg)
+-
+>4 The FTPMRK routine puts an invisible marker on the
+ CFITSIO error stack. The FTCMRK routine can then be
+ used to delete any more recent error messages on the stack, back to
+ the position of the marker. This preserves any older error messages
+ on the stack. FTCMSG simply clears the entire error message stack.
+> These routines are called without any arguments.
+-
+ FTPMRK
+ FTCMRK
+ FTCMSG
+-
+
+>5 Print out the error message corresponding to the input status
+ value and all the error messages on the FITSIO stack to the specified
+ file stream (stream can be either the string 'STDOUT' or 'STDERR').
+> If the input status value = 0 then this routine does nothing.
+-
+ FTRPRT (stream, > status)
+-
+>6 Write an 80-character message to the FITSIO error stack. Application
+ programs should not normally write to the stack, but there may be
+> some situations where this is desirable.
+-
+ FTPMSG(errmsg)
+-
+
+**B. File I/O Routines
+
+>1 Open an existing FITS file with readonly or readwrite access.
+ This routine always opens the primary array (the first HDU) of
+ the file, and does not move to a following extension, if one was
+ specified as part of the filename. Use the FTNOPN routine to
+ automatically move to the extension. This routine will also
+ open IRAF images (.imh format files) and raw binary data arrays
+ with READONLY access by first converting them on the fly into
+ virtual FITS images. See the `Extended File Name Syntax' chapter
+ for more details. The second routine simply opens the specified
+ file without trying to interpret the filename using the extended
+> filename syntax.
+-
+ FTOPEN(unit,filename,rwmode, > blocksize,status)
+ FTDKOPEN(unit,filename,rwmode, > blocksize,status)
+-
+>2 Open an existing FITS file with readonly or readwrite access
+ and move to a following extension, if one was specified as
+ part of the filename. (e.g., 'filename.fits+2' or
+ 'filename.fits[2]' will move to the 3rd HDU in the file).
+ Note that this routine differs from FTOPEN in that it does not
+> have the redundant blocksize argument.
+-
+ FTNOPN(unit,filename,rwmode, > status)
+-
+>3 Open an existing FITS file with readonly or readwrite access
+ and then move to the first HDU containing significant data, if a) an HDU
+ name or number to open was not explicitly specified as part of the
+ filename, and b) if the FITS file contains a null primary array (i.e.,
+ NAXIS = 0). In this case, it will look for the first IMAGE HDU with
+ NAXIS > 0, or the first table that does not contain the strings `GTI'
+ (Good Time Interval) or `OBSTABLE' in the EXTNAME keyword value. FTTOPN
+ is similar, except it will move to the first significant table HDU
+ (skipping over any image HDUs) in the file if a specific HDU name
+ or number is not specified. FTIOPN will move to the first non-null
+> image HDU, skipping over any tables.
+-
+ FTDOPN(unit,filename,rwmode, > status)
+ FTTOPN(unit,filename,rwmode, > status)
+ FTIOPN(unit,filename,rwmode, > status)
+-
+>4 Open and initialize a new empty FITS file. A template file may also be
+ specified to define the structure of the new file (see section 4.2.4).
+ The second routine simply creates the specified
+ file without trying to interpret the filename using the extended
+> filename syntax.
+-
+ FTINIT(unit,filename,blocksize, > status)
+ FTDKINIT(unit,filename,blocksize, > status)
+-
+>>5 Close a FITS file previously opened with ftopen or ftinit
+-
+ FTCLOS(unit, > status)
+-
+>6 Move to a specified (absolute) HDU in the FITS file (nhdu = 1 for the
+> FITS primary array)
+-
+ FTMAHD(unit,nhdu, > hdutype,status)
+-
+>7 Create a primary array (if none already exists), or insert a
+ new IMAGE extension immediately following the CHDU, or
+ insert a new Primary Array at the beginning of the file. Any
+ following extensions in the file will be shifted down to make room
+ for the new extension. If the CHDU is the last HDU in the file
+ then the new image extension will simply be appended to the end of
+ the file. One can force a new primary array to be inserted at the
+ beginning of the FITS file by setting status = -9 prior
+ to calling the routine. In this case the old primary array will be
+ converted to an IMAGE extension. The new extension (or primary
+> array) will become the CHDU.
+-
+ FTIIMG(unit,bitpix,naxis,naxes, > status)
+-
+>8 Insert a new ASCII TABLE extension immediately following the CHDU.
+ Any following extensions will be shifted down to make room for
+ the new extension. If there are no other following extensions
+ then the new table extension will simply be appended to the
+> end of the file. The new extension will become the CHDU.
+-
+ FTITAB(unit,rowlen,nrows,tfields,ttype,tbcol,tform,tunit,extname, >
+ status)
+-
+>9 Insert a new binary table extension immediately following the CHDU.
+ Any following extensions will be shifted down to make room for
+ the new extension. If there are no other following extensions
+ then the new bintable extension will simply be appended to the
+> end of the file. The new extension will become the CHDU.
+-
+ FTIBIN(unit,nrows,tfields,ttype,tform,tunit,extname,varidat > status)
+-
+**C. Keyword I/O Routines
+
+>>1 Put (append) an 80-character record into the CHU.
+-
+ FTPREC(unit,card, > status)
+-
+>2 Put (append) a new keyword of the appropriate datatype into the CHU.
+ The E and D versions of this routine have the added feature that
+ if the 'decimals' parameter is negative, then the 'G' display
+ format rather then the 'E' format will be used when constructing
+ the keyword value, taking the absolute value of 'decimals' for the
+ precision. This will suppress trailing zeros, and will use a
+ fixed format rather than an exponential format,
+> depending on the magnitude of the value.
+-
+ FTPKY[JLS](unit,keyword,keyval,comment, > status)
+ FTPKY[EDFG](unit,keyword,keyval,decimals,comment, > status)
+-
+>3 Get the nth 80-character header record from the CHU. The first keyword
+ in the header is at key\_no = 1; if key\_no = 0 then this subroutine
+ simple moves the internal pointer to the beginning of the header
+ so that subsequent keyword operations will start at the top of
+> the header; it also returns a blank card value in this case.
+-
+ FTGREC(unit,key_no, > card,status)
+-
+>4 Get a keyword value (with the appropriate datatype) and comment from
+> the CHU
+-
+ FTGKY[EDJLS](unit,keyword, > keyval,comment,status)
+-
+>>5 Delete an existing keyword record.
+-
+ FTDKEY(unit,keyword, > status)
+-
+
+**D. Data I/O Routines
+
+The following routines read or write data values in the current HDU of
+the FITS file. Automatic datatype conversion
+will be attempted for numerical datatypes if the specified datatype is
+different from the actual datatype of the FITS array or table column.
+
+>>1 Write elements into the primary data array or image extension.
+-
+ FTPPR[BIJED](unit,group,fpixel,nelements,values, > status)
+-
+>2 Read elements from the primary data array or image extension.
+ Undefined array elements will be
+ returned with a value = nullval, unless nullval = 0 in which case no
+ checks for undefined pixels will be performed. The anyf parameter is
+ set to true (= .true.) if any of the returned
+> elements were undefined.
+-
+ FTGPV[BIJED](unit,group,fpixel,nelements,nullval, > values,anyf,status)
+-
+>3 Write elements into an ASCII or binary table column. The `felem'
+ parameter applies only to vector columns in binary tables and is
+> ignored when writing to ASCII tables.
+-
+ FTPCL[SLBIJEDCM](unit,colnum,frow,felem,nelements,values, > status)
+-
+>4 Read elements from an ASCII or binary table column. Undefined
+ array elements will be returned with a value = nullval, unless nullval = 0
+ (or = ' ' for ftgcvs) in which case no checking for undefined values will
+ be performed. The ANYF parameter is set to true if any of the returned
+ elements are undefined.
+
+ Any column, regardless of it's intrinsic datatype, may be read as a
+ string. It should be noted however that reading a numeric column
+ as a string is 10 - 100 times slower than reading the same column
+ as a number due to the large overhead in constructing the formatted
+ strings. The display format of the returned strings will be
+ determined by the TDISPn keyword, if it exists, otherwise by the
+ datatype of the column. The length of the returned strings can be
+ determined with the ftgcdw routine. The following TDISPn display
+ formats are currently supported:
+-
+ Iw.m Integer
+ Ow.m Octal integer
+ Zw.m Hexadecimal integer
+ Fw.d Fixed floating point
+ Ew.d Exponential floating point
+ Dw.d Exponential floating point
+ Gw.d General; uses Fw.d if significance not lost, else Ew.d
+-
+ where w is the width in characters of the displayed values, m is the minimum
+ number of digits displayed, and d is the number of digits to the right of the
+> decimal. The .m field is optional.
+
+-
+ FTGCV[SBIJEDCM](unit,colnum,frow,felem,nelements,nullval, >
+ values,anyf,status)
+-
+>5 Get the table column number and full name of the column whose name
+ matches the input template string. See the `Advanced Interface Routines'
+> chapter for a full description of this routine.
+-
+ FTGCNN(unit,casesen,coltemplate, > colname,colnum,status)
+-
+
+
+*VIII Advanced Interface Subroutines
+
+This chapter defines all the available subroutines in the FITSIO user
+interface. For completeness, the basic subroutines described in the
+previous chapter are also repeated here. A right arrow symbol is used
+here to separate the input parameters from the output parameters in the
+definition of each subroutine. This symbol is not actually part of the
+calling sequence. An alphabetical list and definition of all the
+parameters is given at the end of this section.
+
+**A. FITS File Open and Close Subroutines: \label{FTOPEN}
+
+>1 Open an existing FITS file with readonly or readwrite access. FTDOPN
+also moves to the first HDU containing significant data, if no specific
+HDU is specified as part of the filename. FTTOPN and FTIOPN are similar
+except that they will move to the first table HDU or image HDU, respectively,
+>if a HDU name or number is not specified as part of the filename.
+-
+ FTOPEN(unit,filename,rwmode, > blocksize,status)
+ FTDOPN(unit,filename,rwmode, > status)
+ FTTOPN(unit,filename,rwmode, > status)
+ FTIOPN(unit,filename,rwmode, > status)
+-
+
+>2 Open an existing FITS file with readonly or readwrite access
+ and move to a following extension, if one was specified as
+ part of the filename. (e.g., 'filename.fits+2' or
+ 'filename.fits[2]' will move to the 3rd HDU in the file).
+ Note that this routine differs from FTOPEN in that it does not
+> have the redundant blocksize argument.
+-
+ FTNOPN(unit,filename,rwmode, > status)
+-
+>3 Reopen a FITS file that was previously opened with
+ FTOPEN, FTNOPN, or FTINIT. The newunit number
+ may then be treated as a separate file, and one may
+ simultaneously read or write to 2 (or more) different extensions in
+ the same file. The FTOPEN and FTNOPN routines (above) automatically
+ detects cases where a previously opened file is being opened again,
+ and then internally call FTREOPEN, so programs should rarely
+> need to explicitly call this routine.
+-
+ FTREOPEN(unit, > newunit, status)
+-
+>>4 Open and initialize a new empty FITS file
+-
+ FTINIT(unit,filename,blocksize, > status)
+-
+>5 Create a new FITS file, using a template file to define its
+ initial size and structure. The template may be another FITS HDU
+ or an ASCII template file. If the input template file name
+ is blank, then this routine behaves the same as FTINIT.
+ The currently supported format of the ASCII template file is described
+ under the fits\_parse\_template routine (in the general Utilities
+ section), but this may change slightly later releases of
+> CFITSIO.
+-
+ FTTPLT(unit, filename, tplfilename, > status)
+-
+>6 Flush internal buffers of data to the output FITS file
+ previously opened with ftopen or ftinit. The routine usually
+ never needs to be called, but doing so will ensure that
+ if the program subsequently aborts, then the FITS file will
+> have at least been closed properly.
+-
+ FTFLUS(unit, > status)
+-
+>>7 Close a FITS file previously opened with ftopen or ftinit
+-
+ FTCLOS(unit, > status)
+-
+>8 Close and DELETE a FITS file previously opened with ftopen or ftinit.
+ This routine may be useful in cases where a FITS file is created, but
+> an error occurs which prevents the complete file from being written.
+-
+ FTDELT(unit, > status)
+-
+>9 Get the value of an unused I/O unit number which may then be used
+ as input to FTOPEN or FTINIT. This routine searches for the first
+ unused unit number in the range from with 99 down to 50. This
+ routine just keeps an internal list of the allocated unit numbers
+ and does not physically check that the Fortran unit is available (to be
+ compatible with the SPP version of FITSIO). Thus users must not
+ independently allocate any unit numbers in the range 50 - 99
+ if this routine is also to be used in the same program. This
+ routine is provided for convenience only, and it is not required
+> that the unit numbers used by FITSIO be allocated by this routine.
+-
+ FTGIOU( > iounit, status)
+-
+>10 Free (deallocate) an I/O unit number which was previously allocated
+ with FTGIOU. All previously allocated unit numbers may be
+> deallocated at once by calling FTFIOU with iounit = -1.
+-
+ FTFIOU(iounit, > status)
+-
+>11 Return the Fortran unit number that corresponds to the C fitsfile
+pointer value, or vice versa. These 2 C routines may be useful in
+mixed language programs where both C and Fortran subroutines need
+to access the same file. For example, if a FITS file is opened
+with unit 12 by a Fortran subroutine, then a C routine within the
+same program could get the fitfile pointer value to access the same file
+by calling 'fptr = CUnit2FITS(12)'. These routines return a value
+>of zero if an error occurs.
+-
+ int CFITS2Unit(fitsfile *ptr);
+ fitsfile* CUnit2FITS(int unit);
+-
+
+>11 Parse the input filename and return the HDU number that would be
+moved to if the file were opened with FTNOPN. The returned HDU
+number begins with 1 for the primary array, so for example, if the
+input filename = `myfile.fits[2]' then hdunum = 3 will be returned.
+FITSIO does not open the file to check if the extension actually exists
+if an extension number is specified. If an extension *name* is included
+in the file name specification (e.g. `myfile.fits[EVENTS]' then this
+routine will have to open the FITS file and look for the position of
+the named extension, then close file again. This is not possible if
+the file is being read from the stdin stream, and an error will be
+returned in this case. If the filename does not specify an explicit
+extension (e.g. 'myfile.fits') then hdunum = -99 will be returned,
+which is functionally equivalent to hdunum = 1. This routine is mainly
+used for backward compatibility in the ftools software package and is
+not recommended for general use. It is generally better and more
+efficient to first open the FITS file with FTNOPN, then use FTGHDN to
+determine which HDU in the file has been opened, rather than calling
+> FTEXTN followed by a call to FTNOPN.
+-
+ FTEXTN(filename, > nhdu, status)
+-
+>>12 Return the name of the opened FITS file.
+-
+ FTFLNM(unit, > filename, status)
+-
+>>13 Return the I/O mode of the open FITS file (READONLY = 0, READWRITE = 1).
+-
+ FTFLMD(unit, > iomode, status)
+-
+>14 Return the file type of the opened FITS file (e.g. 'file://', 'ftp://',
+> etc.).
+-
+ FTURLT(unit, > urltype, status)
+-
+>15 Parse the input filename or URL into its component parts: the file
+type (file://, ftp://, http://, etc), the base input file name, the
+name of the output file that the input file is to be copied to prior
+to opening, the HDU or extension specification, the filtering
+specifier, the binning specifier, and the column specifier. Blank
+strings will be returned for any components that are not present
+>in the input file name.
+-
+ FTIURL(filename, > filetype, infile, outfile, extspec, filter,
+ binspec, colspec, status)
+-
+>16 Parse the input file name and return the root file name. The root
+name includes the file type if specified, (e.g. 'ftp://' or 'http://')
+and the full path name, to the extent that it is specified in the input
+filename. It does not include the HDU name or number, or any filtering
+>specifications.
+-
+ FTRTNM(filename, > rootname, status)
+-
+
+>16 Test if the input file or a compressed version of the file (with
+a .gz, .Z, .z, or .zip extension) exists on disk. The returned value of
+the 'exists' parameter will have 1 of the 4 following values:
+-
+ 2: the file does not exist, but a compressed version does exist
+ 1: the disk file does exist
+ 0: neither the file nor a compressed version of the file exist
+ -1: the input file name is not a disk file (could be a ftp, http,
+ smem, or mem file, or a file piped in on the STDIN stream)
+-
+>
+-
+ FTEXIST(filename, > exists, status);
+-
+**B. HDU-Level Operations \label{FTMAHD}
+
+When a FITS file is first opened or created, the internal buffers in
+FITSIO automatically point to the first HDU in the file. The following
+routines may be used to move to another HDU in the file. Note that
+the HDU numbering convention used in FITSIO denotes the primary array
+as the first HDU, the first extension in a FITS file is the second HDU,
+and so on.
+
+>1 Move to a specified (absolute) HDU in the FITS file (nhdu = 1 for the
+> FITS primary array)
+-
+ FTMAHD(unit,nhdu, > hdutype,status)
+-
+>>2 Move to a new (existing) HDU forward or backwards relative to the CHDU
+-
+ FTMRHD(unit,nmove, > hdutype,status)
+-
+>3 Move to the (first) HDU which has the specified extension type and
+ EXTNAME (or HDUNAME) and EXTVER keyword values. The hdutype parameter
+ may have
+ a value of IMAGE\_HDU, ASCII\_TBL, BINARY\_TBL, or ANY\_HDU where
+ ANY\_HDU means that only the extname and extver values will be
+ used to locate the correct extension. If the input value of
+ extver is 0 then the EXTVER keyword is ignored and the first HDU
+ with a matching EXTNAME (or HDUNAME) keyword will be found. If no
+ matching HDU is found in the file then the current HDU will remain
+ unchanged
+> and a status = BAD\_HDU\_NUM (301) will be returned.
+-
+ FTMNHD(unit, hdutype, extname, extver, > status)
+-
+>>4 Get the number of the current HDU in the FITS file (primary array = 1)
+-
+ FTGHDN(unit, > nhdu)
+-
+>5 Return the type of the current HDU in the FITS file. The possible
+> values for hdutype are IMAGE\_HDU (0), ASCII\_TBL (1), or BINARY\_TBL (2).
+-
+ FTGHDT(unit, > hdutype, status)
+-
+>6 Return the total number of HDUs in the FITS file.
+> The CHDU remains unchanged.
+-
+ FTTHDU(unit, > hdunum, status)
+-
+>7 Create (append) a new empty HDU following the last extension that
+ has been previously accessed by the program. This will overwrite
+ any extensions in an existing FITS file if the program has not already
+ moved to that (or a later) extension using the FTMAHD or FTMRHD routines.
+ For example, if an existing FITS file contains a primary array and 5
+ extensions and a program (1) opens the FITS file, (2) moves to
+ extension 4, (3) moves back to the primary array, and (4) then calls
+ FTCRHD, then the new extension will be written following the 4th
+> extension, overwriting the existing 5th extension.
+-
+ FTCRHD(unit, > status)
+-
+>8 Insert a new IMAGE extension immediately following the CHDU.
+ Any following extensions will be shifted down to make room for
+ the new extension. If there are no other following extensions
+ then the new image extension will simply be appended to the
+> end of the file. The new extension will become the CHDU.
+-
+ FTIIMG(unit,bitpix,naxis,naxes, > status)
+-
+>9 Insert a new ASCII TABLE extension immediately following the CHDU.
+ Any following extensions will be shifted down to make room for
+ the new extension. If there are no other following extensions
+ then the new table extension will simply be appended to the
+> end of the file. The new extension will become the CHDU.
+-
+ FTITAB(unit,rowlen,nrows,tfields,ttype,tbcol,tform,tunit,extname, >
+ status)
+-
+>10 Insert a new binary table extension immediately following the CHDU.
+ Any following extensions will be shifted down to make room for
+ the new extension. If there are no other following extensions
+ then the new bintable extension will simply be appended to the
+> end of the file. The new extension will become the CHDU.
+-
+ FTIBIN(unit,nrows,tfields,ttype,tform,tunit,extname,varidat > status)
+-
+>11 Resize an image by modifing the size, dimensions, and/or datatype of the
+ current primary array or image extension. If the new image, as specified
+ by the input arguments, is larger than the current existing image
+ in the FITS file then zero fill data will be inserted at the end
+ of the current image and any following extensions will be moved
+ further back in the file. Similarly, if the new image is
+ smaller than the current image then any following extensions
+ will be shifted up towards the beginning of the FITS file
+ and the image data will be truncated to the new size.
+ This routine rewrites the BITPIX, NAXIS, and NAXISn keywords
+> with the appropriate values for new image.
+-
+ FTRSIM(unit,bitpix,naxis,naxes,status)
+-
+>12 Delete the CHDU in the FITS file. Any following HDUs will be shifted
+ forward in the file, to fill in the gap created by the deleted
+ HDU. In the case of deleting the primary array (the first HDU in
+ the file) then the current primary array will be replace by a null
+ primary array containing the minimum set of required keywords and
+ no data. If there are more extensions in the file following the
+ one that is deleted, then the the CHDU will be redefined to point
+ to the following extension. If there are no following extensions
+ then the CHDU will be redefined to point to the previous HDU. The
+ output HDUTYPE parameter indicates the type of the new CHDU after
+> the previous CHDU has been deleted.
+-
+ FTDHDU(unit, > hdutype,status)
+-
+>13 Copy all or part of the input FITS file and append it
+ to the end of the output FITS file. If 'previous' is
+ true (not 0), then any HDUs preceding the current HDU in the input file
+ will be copied to the output file. Similarly, 'current' and 'following'
+ determine whether the current HDU, and/or any following HDUs in the
+ input file will be copied to the output file. If all 3 parameters are
+ true, then the entire input file will be copied. On return, the current
+ HDU in the input file will be unchanged, and the last copied HDU will be the
+> current HDU in the output file.
+-
+ FTCPFL(iunit, ounit, previous, current, following, > status)
+-
+>14 Copy the entire CHDU from the FITS file associated with IUNIT to the CHDU
+ of the FITS file associated with OUNIT. The output HDU must be empty and
+ not already contain any keywords. Space will be reserved for MOREKEYS
+ additional keywords in the output header if there is not already enough
+> space.
+-
+ FTCOPY(iunit,ounit,morekeys, > status)
+-
+>15 Copy the header (and not the data) from the CHDU associated with inunit
+ to the CHDU associated with outunit. If the current output HDU
+ is not completely empty, then the CHDU will be closed and a new
+ HDU will be appended to the output file. This routine will automatically
+ transform the necessary keywords when copying a primary array to
+ and image extension, or an image extension to a primary array.
+> An empty output data unit will be created (all values = 0).
+-
+ FTCPHD(inunit, outunit, > status)
+-
+>16 Copy just the data from the CHDU associated with IUNIT
+ to the CHDU associated with OUNIT. This will overwrite
+ any data previously in the OUNIT CHDU. This low level routine is used
+ by FTCOPY, but it may also be useful in certain application programs
+ which want to copy the data from one FITS file to another but also
+ want to modify the header keywords in the process. all the required
+ header keywords must be written to the OUNIT CHDU before calling
+> this routine
+-
+ FTCPDT(iunit,ounit, > status)
+-
+
+**C. Define or Redefine the structure of the CHDU \label{FTRDEF}
+
+It should rarely be necessary to call the subroutines in this section.
+FITSIO internally calls these routines whenever necessary, so any calls
+to these routines by application programs will likely be redundant.
+
+>1 This routine forces FITSIO to scan the current header keywords that
+ define the structure of the HDU (such as the NAXISn, PCOUNT and GCOUNT
+ keywords) so that it can initialize the internal buffers that describe
+ the HDU structure. This routine may be used instead of the more
+ complicated calls to ftpdef, ftadef or ftbdef. This routine is
+ also very useful for reinitializing the structure of an HDU,
+ if the number of rows in a table, as specified by the NAXIS2 keyword,
+> has been modified from its initial value.
+-
+ FTRDEF(unit, > status) (DEPRECATED)
+-
+>2 Define the structure of the primary array or IMAGE extension. When
+ writing GROUPed FITS files that by convention set the NAXIS1 keyword
+ equal to 0, ftpdef must be called with naxes(1) = 1, NOT 0, otherwise
+ FITSIO will report an error status=308 when trying to write data
+ to a group. Note: it is usually simpler to call FTRDEF rather
+> than this routine.
+-
+ FTPDEF(unit,bitpix,naxis,naxes,pcount,gcount, > status) (DEPRECATED)
+-
+>3 Define the structure of an ASCII table (TABLE) extension. Note: it
+> is usually simpler to call FTRDEF rather than this routine.
+-
+ FTADEF(unit,rowlen,tfields,tbcol,tform,nrows > status) (DEPRECATED)
+-
+>4 Define the structure of a binary table (BINTABLE) extension. Note: it
+> is usually simpler to call FTRDEF rather than this routine.
+-
+ FTBDEF(unit,tfields,tform,varidat,nrows > status) (DEPRECATED)
+-
+>5 Define the size of the Current Data Unit, overriding the length
+ of the data unit as previously defined by ftpdef, ftadef, or ftbdef.
+ This is useful if one does not know the total size of the data unit until
+ after the data have been written. The size (in bytes) of an ASCII or
+ Binary table is given by NAXIS1 * NAXIS2. (Note that to determine the
+ value of NAXIS1 it is often more convenient to read the value of the
+ NAXIS1 keyword from the output file, rather than computing the row
+ length directly from all the TFORM keyword values). Note: it
+> is usually simpler to call FTRDEF rather than this routine.
+-
+ FTDDEF(unit,bytlen, > status) (DEPRECATED)
+-
+>6 Define the zero indexed byte offset of the 'heap' measured from
+ the start of the binary table data. By default the heap is assumed
+ to start immediately following the regular table data, i.e., at
+ location NAXIS1 x NAXIS2. This routine is only relevant for
+ binary tables which contain variable length array columns (with
+ TFORMn = 'Pt'). This subroutine also automatically writes
+ the value of theap to a keyword in the extension header. This
+ subroutine must be called after the required keywords have been
+ written (with ftphbn) and after the table structure has been defined
+> (with ftbdef) but before any data is written to the table.
+-
+ FTPTHP(unit,theap, > status)
+-
+
+**D. FITS Header I/O Subroutines
+
+***1. Header Space and Position Routines \label{FTHDEF}
+
+>1 Reserve space in the CHU for MOREKEYS more header keywords.
+ This subroutine may be called to reserve space for keywords which are
+ to be written at a later time, after the data unit or subsequent
+ extensions have been written to the FITS file. If this subroutine is
+ not explicitly called, then the initial size of the FITS header will be
+ limited to the space available at the time that the first data is written
+ to the associated data unit. FITSIO has the ability to dynamically
+ add more space to the header if needed, however it is more efficient
+> to preallocate the required space if the size is known in advance.
+-
+ FTHDEF(unit,morekeys, > status)
+-
+>2 Return the number of existing keywords in the CHU (NOT including the
+ END keyword which is not considered a real keyword) and the remaining
+ space available to write additional keywords in the CHU. (returns
+ KEYSADD = -1 if the header has not yet been closed).
+ Note that FITSIO will attempt to dynamically add space for more
+> keywords if required when appending new keywords to a header.
+-
+ FTGHSP(iunit, > keysexist,keysadd,status)
+-
+>3 Return the number of keywords in the header and the current position
+ in the header. This returns the number of the keyword record that
+ will be read next (or one greater than the position of the last keyword
+ that was read or written). A value of 1 is returned if the pointer is
+> positioned at the beginning of the header.
+-
+ FTGHPS(iunit, > keysexist,key_no,status)
+-
+***2. Read or Write Standard Header Routines \label{FTPHPR}
+
+These subroutines provide a simple method of reading or writing most of
+the keyword values that are normally required in a FITS files. These
+subroutines are provided for convenience only and are not required to
+be used. If preferred, users may call the lower-level subroutines
+described in the previous section to individually read or write the
+required keywords. Note that in most cases, the required keywords such
+as NAXIS, TFIELD, TTYPEn, etc, which define the structure of the HDU
+must be written to the header before any data can be written to the
+image or table.
+
+>1 Put the primary header or IMAGE extension keywords into the CHU.
+There are 2 available routines: The simpler FTPHPS routine is
+equivalent to calling ftphpr with the default values of SIMPLE = true,
+pcount = 0, gcount = 1, and EXTEND = true. PCOUNT, GCOUNT and EXTEND
+keywords are not required in the primary header and are only written if
+pcount is not equal to zero, gcount is not equal to zero or one, and if
+extend is TRUE, respectively. When writing to an IMAGE extension, the
+>SIMPLE and EXTEND parameters are ignored.
+-
+ FTPHPS(unit,bitpix,naxis,naxes, > status)
+
+ FTPHPR(unit,simple,bitpix,naxis,naxes,pcount,gcount,extend, > status)
+-
+>2 Get primary header or IMAGE extension keywords from the CHU. When
+ reading from an IMAGE extension the SIMPLE and EXTEND parameters are
+> ignored.
+-
+ FTGHPR(unit,maxdim, > simple,bitpix,naxis,naxes,pcount,gcount,extend,
+ status)
+-
+>3 Put the ASCII table header keywords into the CHU. The optional
+TUNITn and EXTNAME keywords are written only if the input string
+>values are not blank.
+-
+ FTPHTB(unit,rowlen,nrows,tfields,ttype,tbcol,tform,tunit,extname, >
+ status)
+-
+>>4 Get the ASCII table header keywords from the CHU
+-
+ FTGHTB(unit,maxdim, > rowlen,nrows,tfields,ttype,tbcol,tform,tunit,
+ extname,status)
+-
+>5 Put the binary table header keywords into the CHU. The optional
+ TUNITn and EXTNAME keywords are written only if the input string
+ values are not blank. The pcount parameter, which specifies the
+ size of the variable length array heap, should initially = 0;
+ FITSIO will automatically update the PCOUNT keyword value if any
+ variable length array data is written to the heap. The TFORM keyword
+ value for variable length vector columns should have the form 'Pt(len)'
+ or '1Pt(len)' where `t' is the data type code letter (A,I,J,E,D, etc.)
+ and `len' is an integer specifying the maximum length of the vectors
+ in that column (len must be greater than or equal to the longest
+ vector in the column). If `len' is not specified when the table is
+ created (e.g., the input TFORMn value is just '1Pt') then FITSIO will
+ scan the column when the table is first closed and will append the
+ maximum length to the TFORM keyword value. Note that if the table
+ is subsequently modified to increase the maximum length of the vectors
+ then the modifying program is responsible for also updating the TFORM
+> keyword value.
+
+-
+ FTPHBN(unit,nrows,tfields,ttype,tform,tunit,extname,varidat, > status)
+-
+>>6 Get the binary table header keywords from the CHU
+-
+ FTGHBN(unit,maxdim, > nrows,tfields,ttype,tform,tunit,extname,varidat,
+ status)
+-
+***3. Write Keyword Subroutines \label{FTPREC}
+
+>>1 Put (append) an 80-character record into the CHU.
+-
+ FTPREC(unit,card, > status)
+-
+>2 Put (append) a COMMENT keyword into the CHU. Multiple COMMENT keywords
+> will be written if the input comment string is longer than 72 characters.
+-
+ FTPCOM(unit,comment, > status)
+-
+>3 Put (append) a HISTORY keyword into the CHU. Multiple HISTORY keywords
+> will be written if the input history string is longer than 72 characters.
+-
+ FTPHIS(unit,history, > status)
+-
+>4 Put (append) the DATE keyword into the CHU. The keyword value will contain
+ the current system date as a character string in 'dd/mm/yy' format. If
+ a DATE keyword already exists in the header, then this subroutine will
+> simply update the keyword value in-place with the current date.
+-
+ FTPDAT(unit, > status)
+-
+>5 Put (append) a new keyword of the appropriate datatype into the CHU.
+ Note that FTPKYS will only write string values up to 68 characters in
+ length; longer strings will be truncated. The FTPKLS routine can be
+ used to write longer strings, using a non-standard FITS convention.
+ The E and D versions of this routine have the added feature that
+ if the 'decimals' parameter is negative, then the 'G' display
+ format rather then the 'E' format will be used when constructing
+ the keyword value, taking the absolute value of 'decimals' for the
+ precision. This will suppress trailing zeros, and will use a
+ fixed format rather than an exponential format,
+> depending on the magnitude of the value.
+-
+ FTPKY[JLS](unit,keyword,keyval,comment, > status)
+ FTPKY[EDFG](unit,keyword,keyval,decimals,comment, > status)
+-
+>6 Put (append) a string valued keyword into the CHU which may be longer
+ than 68 characters in length. This uses the Long String Keyword
+ convention that is described in the "Usage Guidelines and Suggestions"
+ section of this document. Since this uses a non-standard FITS
+ convention to encode the long keyword string, programs which use
+ this routine should also call the FTPLSW routine to add some COMMENT
+ keywords to warn users of the FITS file that this convention is
+ being used. FTPLSW also writes a keyword called LONGSTRN to record
+ the version of the longstring convention that has been used, in case
+ a new convention is adopted at some point in the future. If the
+ LONGSTRN keyword is already present in the header, then FTPLSW will
+> simply return and will not write duplicate keywords.
+-
+ FTPKLS(unit,keyword,keyval,comment, > status)
+ FTPLSW(unit, > status)
+-
+>7 Put (append) a new keyword with an undefined, or null, value into the CHU.
+> The value string of the keyword is left blank in this case.
+-
+ FTPKYU(unit,keyword,comment, > status)
+-
+>8 Put (append) a numbered sequence of keywords into the CHU. One may
+ append the same comment to every keyword (and eliminate the need
+ to have an array of identical comment strings, one for each keyword) by
+ including the ampersand character as the last non-blank character in the
+ (first) COMMENTS string parameter. This same string
+ will then be used for the comment field in all the keywords. (Note
+ that the SPP version of these routines only supports a single comment
+> string).
+-
+ FTPKN[JLS](unit,keyroot,startno,no_keys,keyvals,comments, > status)
+ FTPKN[EDFG](unit,keyroot,startno,no_keys,keyvals,decimals,comments, >
+ status)
+-
+>9 Copy an indexed keyword from one HDU to another, modifying
+ the index number of the keyword name in the process. For example,
+ this routine could read the TLMIN3 keyword from the input HDU
+ (by giving keyroot = "TLMIN" and innum = 3) and write it to the
+ output HDU with the keyword name TLMIN4 (by setting outnum = 4).
+ If the input keyword does not exist, then this routine simply
+> returns without indicating an error.
+-
+ FTCPKYinunit, outunit, innum, outnum, keyroot, > status)
+-
+>10 Put (append) a 'triple precision' keyword into the CHU in F28.16 format.
+ The floating point keyword value is constructed by concatenating the
+ input integer value with the input double precision fraction value
+ (which must have a value between 0.0 and 1.0). The FTGKYT routine should
+ be used to read this keyword value, because the other keyword reading
+> subroutines will not preserve the full precision of the value.
+-
+ FTPKYT(unit,keyword,intval,dblval,comment, > status)
+-
+>11 Write keywords to the CHDU that are defined in an ASCII template file.
+ The format of the template file is described under the ftgthd
+> routine below.
+-
+ FTPKTP(unit, filename, > status)
+-
+>12 Append the physical units string to an existing keyword. This
+ routine uses a local convention, shown in the following example,
+ in which the keyword units are enclosed in square brackets in the
+> beginning of the keyword comment field.
+
+-
+ VELOCITY= 12.3 / [km/s] orbital speed
+
+ FTPUNT(unit,keyword,units, > status)
+-
+***4. Insert Keyword Subroutines \label{FTIREC}
+
+>1 Insert a new keyword record into the CHU at the specified position
+ (i.e., immediately preceding the (keyno)th keyword in the header.)
+ This 'insert record' subroutine is somewhat less efficient
+ then the 'append record' subroutine (FTPREC) described above because
+> the remaining keywords in the header have to be shifted down one slot.
+-
+ FTIREC(unit,key_no,card, > status)
+-
+>2 Insert a new keyword into the CHU. The new keyword is inserted
+ immediately following the last keyword that has been read from the header.
+ The FTIKLS subroutine works the same as the FTIKYS subroutine, except
+ it also supports long string values greater than 68 characters in length.
+ These 'insert keyword' subroutines are somewhat less efficient then
+ the 'append keyword' subroutines described above because the remaining
+> keywords in the header have to be shifted down one slot.
+-
+ FTIKEY(unit, card, > status)
+ FTIKY[JLS](unit,keyword,keyval,comment, > status)
+ FTIKLS(unit,keyword,keyval,comment, > status)
+ FTIKY[EDFG](unit,keyword,keyval,decimals,comment, > status)
+-
+>3 Insert a new keyword with an undefined, or null, value into the CHU.
+> The value string of the keyword is left blank in this case.
+-
+ FTIKYU(unit,keyword,comment, > status)
+-
+***5. Read Keyword Subroutines \label{FTGREC}
+
+These routines return the value of the specified keyword(s). Wild card
+characters (*, ?, or \#) may be used when specifying the name of the keyword
+to be read: a '?' will match any single character at that position in the
+keyword name and a '*' will match any length (including zero) string of
+characters. The '\#' character will match any consecutive string of
+decimal digits (0 - 9). Note that when a wild card is used in the input
+keyword name, the routine will only search for a match from the current
+header position to the end of the header. It will not resume the search
+from the top of the header back to the original header position as is done
+when no wildcards are included in the keyword name. If the desired
+keyword string is 8-characters long (the maximum length of a keyword
+name) then a '*' may be appended as the ninth character of the input
+name to force the keyword search to stop at the end of the header
+(e.g., 'COMMENT *' will search for the next COMMENT keyword). The
+ffgrec routine may be used to set the starting position when doing
+wild card searches.
+
+>1 Get the nth 80-character header record from the CHU. The first keyword
+ in the header is at key\_no = 1; if key\_no = 0 then this subroutine
+ simple moves the internal pointer to the beginning of the header
+ so that subsequent keyword operations will start at the top of
+> the header; it also returns a blank card value in this case.
+-
+ FTGREC(unit,key_no, > card,status)
+-
+>2 Get the name, value (as a string), and comment of the nth keyword in CHU.
+ This routine also checks that the returned keyword name (KEYWORD) contains
+ only legal ASCII characters. Call FTGREC and FTPSVC to bypass this error
+> check.
+-
+ FTGKYN(unit,key_no, > keyword,value,comment,status)
+-
+>>3 Get the 80-character header record for the named keyword
+-
+ FTGCRD(unit,keyword, > card,status)
+-
+>4 Get the next keyword whose name matches one of the strings in
+ 'inclist' but does not match any of the strings in 'exclist'.
+ The strings in inclist and exclist may contain wild card characters
+ (*, ?, and \#) as described at the beginning of this section.
+ This routine searches from the current header position to the
+ end of the header, only, and does not continue the search from
+ the top of the header back to the original position. The current
+ header position may be reset with the ftgrec routine. Note
+ that nexc may be set = 0 if there are no keywords to be excluded.
+ This routine returns status = 202 if a matching
+> keyword is not found.
+-
+ FTGNXK(unit,inclist,ninc,exclist,nexc, > card,status)
+-
+>5 Get the literal keyword value as a character string. Regardless
+ of the datatype of the keyword, this routine simply returns the
+ string of characters in the value field of the keyword along with
+> the comment field.
+-
+ FTGKEY(unit,keyword, > value,comment,status)
+-
+>6 Get a keyword value (with the appropriate datatype) and comment from
+> the CHU
+-
+ FTGKY[EDJLS](unit,keyword, > keyval,comment,status)
+-
+>7 Get a sequence of numbered keyword values. These
+> routines do not support wild card characters in the root name.
+-
+ FTGKN[EDJLS](unit,keyroot,startno,max_keys, > keyvals,nfound,status)
+-
+>8 Get the value of a floating point keyword, returning the integer and
+ fractional parts of the value in separate subroutine arguments.
+ This subroutine may be used to read any keyword but is especially
+> useful for reading the 'triple precision' keywords written by FTPKYT.
+-
+ FTGKYT(unit,keyword, > intval,dblval,comment,status)
+-
+>9 Get the physical units string in an existing keyword. This
+ routine uses a local convention, shown in the following example,
+ in which the keyword units are
+ enclosed in square brackets in the beginning of the keyword comment
+ field. A blank string is returned if no units are defined
+> for the keyword.
+-
+ VELOCITY= 12.3 / [km/s] orbital speed
+
+ FTGUNT(unit,keyword, > units,status)
+-
+***6. Modify Keyword Subroutines \label{FTMREC}
+
+Wild card characters, as described in the Read Keyword section, above,
+may be used when specifying the name of the keyword to be modified.
+
+>>1 Modify (overwrite) the nth 80-character header record in the CHU
+-
+ FTMREC(unit,key_no,card, > status)
+-
+>2 Modify (overwrite) the 80-character header record for the named keyword
+ in the CHU. This can be used to overwrite the name of the keyword as
+> well as its value and comment fields.
+-
+ FTMCRD(unit,keyword,card, > status)
+-
+>3 Modify (overwrite) the name of an existing keyword in the CHU
+> preserving the current value and comment fields.
+-
+ FTMNAM(unit,oldkey,keyword, > status)
+-
+>>4 Modify (overwrite) the comment field of an existing keyword in the CHU
+-
+ FTMCOM(unit,keyword,comment, > status)
+-
+>5 Modify the value and comment fields of an existing keyword in the CHU.
+ The FTMKLS subroutine works the same as the FTMKYS subroutine, except
+ it also supports long string values greater than 68 characters in length.
+ Optionally, one may modify only the value field and leave the comment
+ field unchanged by setting the input COMMENT parameter equal to
+ the ampersand character (\&).
+ The E and D versions of this routine have the added feature that
+ if the 'decimals' parameter is negative, then the 'G' display
+ format rather then the 'E' format will be used when constructing
+ the keyword value, taking the absolute value of 'decimals' for the
+ precision. This will suppress trailing zeros, and will use a
+ fixed format rather than an exponential format,
+> depending on the magnitude of the value.
+-
+ FTMKY[JLS](unit,keyword,keyval,comment, > status)
+ FTMKLS(unit,keyword,keyval,comment, > status)
+ FTMKY[EDFG](unit,keyword,keyval,decimals,comment, > status)
+-
+>6 Modify the value of an existing keyword to be undefined, or null.
+ The value string of the keyword is set to blank.
+ Optionally, one may leave the comment field unchanged by setting the
+> input COMMENT parameter equal to the ampersand character (\&).
+-
+ FTMKYU(unit,keyword,comment, > status)
+-
+***7. Update Keyword Subroutines \label{FTUCRD}
+
+>1 Update an 80-character record in the CHU. If the specified keyword
+ already exists then that header record will be replaced with
+ the input CARD string. If it does not exist then the new record will
+ be added to the header.
+ The FTUKLS subroutine works the same as the FTUKYS subroutine, except
+> it also supports long string values greater than 68 characters in length.
+-
+ FTUCRD(unit,keyword,card, > status)
+-
+>2 Update the value and comment fields of a keyword in the CHU.
+ The specified keyword is modified if it already exists (by calling
+ FTMKYx) otherwise a new keyword is created by calling FTPKYx.
+ The E and D versions of this routine have the added feature that
+ if the 'decimals' parameter is negative, then the 'G' display
+ format rather then the 'E' format will be used when constructing
+ the keyword value, taking the absolute value of 'decimals' for the
+ precision. This will suppress trailing zeros, and will use a
+ fixed format rather than an exponential format,
+> depending on the magnitude of the value.
+-
+ FTUKY[JLS](unit,keyword,keyval,comment, > status)
+ FTUKLS(unit,keyword,keyval,comment, > status)
+ FTUKY[EDFG](unit,keyword,keyval,decimals,comment, > status)
+-
+>3 Update the value of an existing keyword to be undefined, or null,
+ or insert a new undefined-value keyword if it doesn't already exist.
+> The value string of the keyword is left blank in this case.
+-
+ FTUKYU(unit,keyword,comment, > status)
+-
+***8. Delete Keyword Subroutines \label{FTDREC}
+
+>1 Delete an existing keyword record. The space previously occupied by
+ the keyword is reclaimed by moving all the following header records up
+ one row in the header. The first routine deletes a keyword at a
+ specified position in the header (the first keyword is at position 1),
+ whereas the second routine deletes a specifically named keyword.
+ Wild card characters, as described in the Read Keyword section, above,
+ may be used when specifying the name of the keyword to be deleted
+> (be careful!).
+-
+ FTDREC(unit,key_no, > status)
+ FTDKEY(unit,keyword, > status)
+-
+
+**F. Data Scaling and Undefined Pixel Parameters \label{FTPSCL}
+
+These subroutines define or modify the internal parameters used by
+FITSIO to either scale the data or to represent undefined pixels.
+Generally FITSIO will scale the data according to the values of the BSCALE
+and BZERO (or TSCALn and TZEROn) keywords, however these subroutines
+may be used to override the keyword values. This may be useful when
+one wants to read or write the raw unscaled values in the FITS file.
+Similarly, FITSIO generally uses the value of the BLANK or TNULLn
+keyword to signify an undefined pixel, but these routines may be used
+to override this value. These subroutines do not create or modify the
+corresponding header keyword values.
+
+>1 Reset the scaling factors in the primary array or image extension; does
+ not change the BSCALE and BZERO keyword values and only affects the
+ automatic scaling performed when the data elements are written/read
+ to/from the FITS file. When reading from a FITS file the returned
+ data value = (the value given in the FITS array) * BSCALE + BZERO.
+ The inverse formula is used when writing data values to the FITS
+ file. (NOTE: BSCALE and BZERO must be declared as Double Precision
+> variables).
+-
+ FTPSCL(unit,bscale,bzero, > status)
+-
+>2 Reset the scaling parameters for a table column; does not change
+ the TSCALn or TZEROn keyword values and only affects the automatic
+ scaling performed when the data elements are written/read to/from
+ the FITS file. When reading from a FITS file the returned data
+ value = (the value given in the FITS array) * TSCAL + TZERO. The
+ inverse formula is used when writing data values to the FITS file.
+ (NOTE: TSCAL and TZERO must be declared as Double Precision
+> variables).
+-
+ FTTSCL(unit,colnum,tscal,tzero, > status)
+-
+>3 Define the integer value to be used to signify undefined pixels in the
+ primary array or image extension. This is only used if BITPIX = 8, 16,
+ or 32. This does not create or change the value of the BLANK keyword in
+> the header.
+-
+ FTPNUL(unit,blank, > status)
+-
+>4 Define the string to be used to signify undefined pixels in
+ a column in an ASCII table. This does not create or change the value
+> of the TNULLn keyword.
+-
+ FTSNUL(unit,colnum,snull > status)
+-
+>5 Define the value to be used to signify undefined pixels in
+ an integer column in a binary table (where TFORMn = 'B', 'I', or 'J').
+> This does not create or change the value of the TNULLn keyword.
+-
+ FTTNUL(unit,colnum,tnull > status)
+-
+
+**G. FITS Primary Array or IMAGE Extension I/O Subroutines \label{FTPPR}
+
+ These subroutines put or get data values in the primary data array
+(i.e., the first HDU in the FITS file) or an IMAGE extension. The
+data array is represented as a single one-dimensional array of
+pixels regardless of the actual dimensionality of the array, and the
+FPIXEL parameter gives the position within this 1-D array of the first
+pixel to read or write. Automatic data type conversion is performed
+for numeric data (except for complex data types) if the data type of
+the primary array (defined by the BITPIX keyword) differs from the data
+type of the array in the calling subroutine. The data values are also
+scaled by the BSCALE and BZERO header values as they are being written
+or read from the FITS array. The ftpscl subroutine MUST be
+called to define the scaling parameters when writing data to the FITS
+array or to override the default scaling value given in the header when
+reading the FITS array.
+
+ Two sets of subroutines are provided to read the data array which
+differ in the way undefined pixels are handled. The first set of
+routines (FTGPVx) simply return an array of data elements in which
+undefined pixels are set equal to a value specified by the user in the
+'nullval' parameter. An additional feature of these subroutines is
+that if the user sets nullval = 0, then no checks for undefined pixels
+will be performed, thus increasing the speed of the program. The
+second set of routines (FTGPFx) returns the data element array and, in
+addition, a logical array which defines whether the corresponding data
+pixel is undefined. The latter set of subroutines may be more
+convenient to use in some circumstances, however, it requires an
+additional array of logical values which can be unwieldy when working
+with large data arrays. Also for programmer convenience, sets of
+subroutines to directly read or write 2 and 3 dimensional arrays have
+been provided, as well as a set of subroutines to read or write any
+contiguous rectangular subset of pixels within the n-dimensional array.
+
+>1 Get the data type of the image (= BITPIX value). Possible returned
+ values are: 8, 16, 32, -32, or -64 corresponding to unsigned byte,
+ signed 2-byte integer, signed 4-byte integer, real, and double.
+
+ The second subroutine is similar to FTGIDT, except that if the image
+ pixel values are scaled, with non-default values for the BZERO and
+ BSCALE keywords, then this routine will return the 'equivalent'
+ data type that is needed to store the scaled values. For example,
+ if BITPIX = 16 and BSCALE = 0.1 then the equivalent data type is
+ floating point, and -32 will be returned. There are 2 special cases:
+ if the image contains unsigned 2-byte integer values, with BITPIX =
+ 16, BSCALE = 1, and BZERO = 32768, then this routine will return
+ a non-standard value of 20 for the bitpix value. Similarly if the
+ image contains unsigned 4-byte integers, then bitpix will
+> be returned with a value of 40.
+
+-
+ FTGIDT(unit, > bitpix,status)
+ FTGIET(unit, > bitpix,status)
+-
+>>2 Get the dimension (number of axes = NAXIS) of the image
+-
+ FTGIDM(unit, > naxis,status)
+-
+>>3 Get the size of all the dimensions of the image
+-
+ FTGISZ(unit, maxdim, > naxes,status)
+-
+>4 Get the parameters that define the type and size of the image. This
+> routine simply combines calls to the above 3 routines.
+-
+ FTGIPR(unit, maxdim, > bitpix, naxis, naxes, int *status)
+-
+>>5 Put elements into the data array
+-
+ FTPPR[BIJED](unit,group,fpixel,nelements,values, > status)
+-
+>6 Put elements into the data array, substituting the appropriate FITS null
+ value for all elements which are equal to the value of NULLVAL. For
+ integer FITS arrays, the null value defined by the previous call to FTPNUL
+ will be substituted; for floating point FITS arrays (BITPIX = -32
+ or -64) then the special IEEE NaN (Not-a-Number) value will be
+> substituted.
+-
+ FTPPN[BIJED](unit,group,fpixel,nelements,values,nullval > status)
+-
+>>7 Set data array elements as undefined
+-
+ FTPPRU(unit,group,fpixel,nelements, > status)
+-
+>8 Get elements from the data array. Undefined array elements will be
+ returned with a value = nullval, unless nullval = 0 in which case no
+> checks for undefined pixels will be performed.
+-
+ FTGPV[BIJED](unit,group,fpixel,nelements,nullval, > values,anyf,status)
+-
+>9 Get elements and nullflags from data array.
+ Any undefined array elements will have the corresponding flagvals element
+> set equal to .TRUE.
+-
+ FTGPF[BIJED](unit,group,fpixel,nelements, > values,flagvals,anyf,status)
+-
+>>10 Put values into group parameters
+-
+ FTPGP[BIJED](unit,group,fparm,nparm,values, > status)
+-
+>>11 Get values from group parameters
+-
+ FTGGP[BIJED](unit,group,fparm,nparm, > values,status)
+-
+The following 4 subroutines transfer FITS images with 2 or 3 dimensions
+to or from a data array which has been declared in the calling program.
+The dimensionality of the FITS image is passed by the naxis1, naxis2,
+and naxis3 parameters and the declared dimensions of the program array
+are passed in the dim1 and dim2 parameters. Note that the program array
+does not have to have the same dimensions as the FITS array, but must
+be at least as big. For example if a FITS image with NAXIS1 = NAXIS2 = 400
+is read into a program array which is dimensioned as 512 x 512 pixels,
+then the image will just fill the lower left corner of the array
+with pixels in the range 1 - 400 in the X an Y directions. This has
+the effect of taking a contiguous set of pixel value in the FITS array
+and writing them to a non-contiguous array in program memory
+(i.e., there are now some blank pixels around the edge of the image
+in the program array).
+
+>>11 Put 2-D image into the data array
+-
+ FTP2D[BIJED](unit,group,dim1,naxis1,naxis2,image, > status)
+-
+>>12 Put 3-D cube into the data array
+-
+ FTP3D[BIJED](unit,group,dim1,dim2,naxis1,naxis2,naxis3,cube, > status)
+-
+>13 Get 2-D image from the data array. Undefined
+ pixels in the array will be set equal to the value of 'nullval',
+ unless nullval=0 in which case no testing for undefined pixels will
+> be performed.
+-
+ FTG2D[BIJED](unit,group,nullval,dim1,naxis1,naxis2, > image,anyf,status)
+-
+>14 Get 3-D cube from the data array. Undefined
+ pixels in the array will be set equal to the value of 'nullval',
+ unless nullval=0 in which case no testing for undefined pixels will
+> be performed.
+-
+ FTG3D[BIJED](unit,group,nullval,dim1,dim2,naxis1,naxis2,naxis3, >
+ cube,anyf,status)
+-
+
+The following subroutines transfer a rectangular subset of the pixels
+in a FITS N-dimensional image to or from an array which has been
+declared in the calling program. The fpixels and lpixels parameters
+are integer arrays which specify the starting and ending pixels in each
+dimension of the FITS image that are to be read or written. (Note that
+these are the starting and ending pixels in the FITS image, not in the
+declared array). The array parameter is treated simply as a large
+one-dimensional array of the appropriate datatype containing the pixel
+values; The pixel values in the FITS array are read/written from/to
+this program array in strict sequence without any gaps; it is up to
+the calling routine to correctly interpret the dimensionality of this
+array. The two families of FITS reading routines (FTGSVx and FTGSFx
+subroutines) also have an 'incs' parameter which defines the
+data sampling interval in each dimension of the FITS array. For
+example, if incs(1)=2 and incs(2)=3 when reading a 2-dimensional
+FITS image, then only every other pixel in the first dimension
+and every 3rd pixel in the second dimension will be returned in
+the 'array' parameter. [Note: the FTGSSx family of routines which
+were present in previous versions of FITSIO have been superseded
+by the more general FTGSVx family of routines.]
+
+>>15 Put an arbitrary data subsection into the data array.
+-
+ FTPSS[BIJED](unit,group,naxis,naxes,fpixels,lpixels,array, > status)
+-
+>16 Get an arbitrary data subsection from the data array. Undefined
+ pixels in the array will be set equal to the value of 'nullval',
+ unless nullval=0 in which case no testing for undefined pixels will
+> be performed.
+-
+ FTGSV[BIJED](unit,group,naxis,naxes,fpixels,lpixels,incs,nullval, >
+ array,anyf,status)
+-
+>17 Get an arbitrary data subsection from the data array. Any Undefined
+ pixels in the array will have the corresponding 'flagvals'
+> element set equal to .TRUE.
+-
+ FTGSF[BIJED](unit,group,naxis,naxes,fpixels,lpixels,incs, >
+ array,flagvals,anyf,status)
+-
+
+**H. FITS ASCII and Binary Table Data I/O Subroutines
+
+***1. Column Information Subroutines \label{FTGCNO}
+
+>1 Get the number of rows or columns in the current FITS table.
+ The number of rows is given by the NAXIS2 keyword and the
+ number of columns is given by the TFIELDS keyword in the header
+> of the table.
+-
+ FTGNRW(unit, > nrows, status)
+ FTGNCL(unit, > ncols, status)
+-
+>2 Get the table column number (and name) of the column whose name
+matches an input template name. The table column names are defined by
+the TTYPEn keywords in the FITS header. If a column does not have a
+TTYPEn keyword, then these routines assume that the name consists of
+all blank characters. These 2 subroutines perform the same function
+except that FTGCNO only returns the number of the matching column whereas
+FTGCNN also returns the name of the column. If CASESEN = .true. then
+the column name match will be case-sensitive.
+
+The input column name template (COLTEMPLATE) is (1) either the exact
+name of the column to be searched for, or (2) it may contain wild cards
+characters (*, ?, or \#), or (3) it may contain the number of the desired
+column (where the number is expressed as ASCII digits). The first 2 wild
+cards behave similarly to UNIX filename matching: the '*' character matches
+any sequence of characters (including zero characters) and the '?'
+character matches any single character. The \# wildcard will match
+any consecutive string of decimal digits (0-9). As an example, the template
+strings 'AB?DE', 'AB*E', and 'AB*CDE' will all match the string
+'ABCDE'. If more than one column name in the table matches the
+template string, then the first match is returned and the status value
+will be set to 237 as a warning that a unique match was not found. To
+find the other cases that match the template, simply call the
+subroutine again leaving the input status value equal to 237 and the
+next matching name will then be returned. Repeat this process until a
+status = 219 (column name not found) is returned. If these subroutines
+fail to match the template to any of the columns in the table, they
+lastly check if the template can be interpreted as a simple positive
+integer (e.g., '7', or '512') and if so, they return that column
+number. If no matches are found then a status = 219 error is
+returned.
+
+Note that the FITS Standard recommends that only letters, digits, and
+the underscore character be used in column names (with no embedded
+spaces in the name). Trailing blank characters are not significant.
+It is recommended that the column names in a given table be unique
+>within the first 8 characters.
+-
+ FTGCNO(unit,casesen,coltemplate, > colnum,status)
+ FTGCNN(unit,casesen,coltemplate, > colname,colnum,status)
+-
+>3 Get the datatype of a column in an ASCII or binary table. This
+ routine returns an integer code value corresponding to the datatype
+ of the column. (See the FTBNFM and FTASFM subroutines in the Utilities
+ section of this document for a list of the code values). The vector
+ repeat count (which is alway 1 for ASCII table columns) is also returned.
+ If the specified column has an ASCII character datatype (code = 16) then
+ the width of a unit string in the column is also returned. Note that
+ this routine supports the local convention for specifying arrays of
+ strings within a binary table character column, using the syntax
+ TFORM = 'rAw' where 'r' is the total number of characters (= the width
+ of the column) and 'w' is the width of a unit string within the column.
+ Thus if the column has TFORM = '60A12' then this routine will return
+ datacode = 16, repeat = 60, and width = 12.
+
+ The second routine, FTEQTY is similar except that in
+ the case of scaled integer columns it returns the 'equivalent' data
+ type that is needed to store the scaled values, and not necessarily
+ the physical data type of the unscaled values as stored in the FITS
+ table. For example if a '1I' column in a binary table has TSCALn =
+ 1 and TZEROn = 32768, then this column effectively contains unsigned
+ short integer values, and thus the returned value of typecode will
+ be the code for an unsigned short integer, not a signed short integer.
+ Similarly, if a column has TTYPEn = '1I'
+ and TSCALn = 0.12, then the returned typecode
+> will be the code for a 'real' column.
+-
+ FTGTCL(unit,colnum, > datacode,repeat,width,status)
+ FTEQTY(unit,colnum, > datacode,repeat,width,status)
+-
+>4 Return the display width of a column. This is the length
+ of the string that will be returned
+ when reading the column as a formatted string. The display width is
+ determined by the TDISPn keyword, if present, otherwise by the data
+> type of the column.
+-
+ FTGCDW(unit, colnum, > dispwidth, status)
+-
+>5 Get information about an existing ASCII table column. (NOTE: TSCAL and
+ TZERO must be declared as Double Precision variables). All the
+> returned parameters are scalar quantities.
+-
+ FTGACL(unit,colnum, >
+ ttype,tbcol,tunit,tform,tscal,tzero,snull,tdisp,status)
+-
+>6 Get information about an existing binary table column. (NOTE: TSCAL and
+ TZERO must be declared as Double Precision variables). DATATYPE is a
+ character string which returns the datatype of the column as defined
+ by the TFORMn keyword (e.g., 'I', 'J','E', 'D', etc.). In the case
+ of an ASCII character column, DATATYPE will have a value of the
+ form 'An' where 'n' is an integer expressing the width of the field
+ in characters. For example, if TFORM = '160A8' then FTGBCL will return
+ DATATYPE='A8' and REPEAT=20. All the returned parameters are scalar
+> quantities.
+-
+ FTGBCL(unit,colnum, >
+ ttype,tunit,datatype,repeat,tscal,tzero,tnull,tdisp,status)
+-
+>7 Put (append) a TDIMn keyword whose value has the form '(l,m,n...)'
+ where l, m, n... are the dimensions of a multidimension array
+> column in a binary table.
+-
+ FTPTDM(unit,colnum,naxis,naxes, > status)
+-
+>8 Return the number of and size of the dimensions of a table column.
+ Normally this information is given by the TDIMn keyword, but if
+ this keyword is not present then this routine returns NAXIS = 1
+> and NAXES(1) equal to the repeat count in the TFORM keyword.
+-
+ FTGTDM(unit,colnum,maxdim, > naxis,naxes,status)
+-
+>9 Decode the input TDIMn keyword string (e.g. '(100,200)') and return the
+ number of and size of the dimensions of a binary table column. If the input
+ tdimstr character string is null, then this routine returns naxis = 1
+ and naxes[0] equal to the repeat count in the TFORM keyword. This routine
+> is called by FTGTDM.
+-
+ FTDTDM(unit,tdimstr,colnum,maxdim, > naxis,naxes, status)
+-
+>10 Return the optimal number of rows to read or write at one time for
+ maximum I/O efficiency. Refer to the ``Optimizing Code'' section
+> in Chapter 5 for more discussion on how to use this routine.
+
+-
+ FFGRSZ(unit, > nrows,status)
+-
+
+***2. Low-Level Table Access Subroutines \label{FTGTBS}
+
+The following subroutines provide low-level access to the data in ASCII
+or binary tables and are mainly useful as an efficient way to copy all
+or part of a table from one location to another. These routines simply
+read or write the specified number of consecutive bytes in an ASCII or
+binary table, without regard for column boundaries or the row length in
+the table. The first two subroutines read or write consecutive bytes
+in a table to or from a character string variable, while the last two
+subroutines read or write consecutive bytes to or from a variable
+declared as a numeric data type (e.g., INTEGER, INTEGER*2, REAL, DOUBLE
+PRECISION). These routines do not perform any machine dependent data
+conversion or byte swapping, except that conversion to/from ASCII
+format is performed by the FTGTBS and FTPTBS routines on machines which
+do not use ASCII character codes in the internal data representations
+(e.g., on IBM mainframe computers).
+
+>1 Read a consecutive string of characters from an ASCII table
+ into a character variable (spanning columns and multiple rows if necessary)
+ This routine should not be used with binary tables because of
+> complications related to passing string variables between C and Fortran.
+-
+ FTGTBS(unit,frow,startchar,nchars, > string,status)
+-
+>2 Write a consecutive string of characters to an ASCII table
+ from a character variable (spanning columns and multiple rows if necessary)
+ This routine should not be used with binary tables because of
+> complications related to passing string variables between C and Fortran.
+-
+ FTPTBS(unit,frow,startchar,nchars,string, > status)
+-
+>3 Read a consecutive array of bytes from an ASCII or binary table
+ into a numeric variable (spanning columns and multiple rows if necessary).
+ The array parameter may be declared as any numerical datatype as long
+ as the array is at least 'nchars' bytes long, e.g., if nchars = 17,
+> then declare the array as INTEGER*4 ARRAY(5).
+-
+ FTGTBB(unit,frow,startchar,nchars, > array,status)
+-
+>4 Write a consecutive array of bytes to an ASCII or binary table
+ from a numeric variable (spanning columns and multiple rows if necessary)
+ The array parameter may be declared as any numerical datatype as long
+ as the array is at least 'nchars' bytes long, e.g., if nchars = 17,
+> then declare the array as INTEGER*4 ARRAY(5).
+-
+ FTPTBB(unit,frow,startchar,nchars,array, > status)
+-
+
+***3. Edit Rows or Columns \label{FTIROW}
+
+>1 Insert blank rows into an existing ASCII or binary table (in the CDU).
+ All the rows FOLLOWING row FROW are shifted down by NROWS rows. If
+ FROW = 0 then the blank rows are inserted at the beginning of the
+ table. This routine modifies the NAXIS2 keyword to reflect the new
+> number of rows in the table.
+-
+ FTIROW(unit,frow,nrows, > status)
+-
+>2 Delete rows from an existing ASCII or binary table (in the CDU).
+ The NROWS number of rows are deleted, starting with row FROW, and
+ any remaining rows in the table are shifted up to fill in the space.
+ This routine modifies the NAXIS2 keyword to reflect the new number
+> of rows in the table.
+-
+ FTDROW(unit,frow,nrows, > status)
+-
+>3 Delete a list of rows from an ASCII or binary table (in the CDU).
+ In the first routine, 'rowrange' is a character string listing the
+ rows or row ranges to delete (e.g., '2-4, 5, 8-9'). In the second
+ routine, 'rowlist' is an integer array of row numbers to be deleted
+ from the table. nrows is the number of row numbers in the list.
+ The first row in the table is 1 not 0. The list of row numbers
+> must be sorted in ascending order.
+-
+ FTDRRG(unit,rowrange, > status)
+ FTDRWS(unit,rowlist,nrows, > status)
+-
+>4 Insert a blank column (or columns) into an existing ASCII or binary
+ table (in the CDU). COLNUM specifies the column number that the (first)
+ new column should occupy in the table. NCOLS specifies how many
+ columns are to be inserted. Any existing columns from this position and
+ higher are moved over to allow room for the new column(s).
+ The index number on all the following keywords will be incremented
+ if necessary to reflect the new position of the column(s) in the table:
+ TBCOLn, TFORMn, TTYPEn, TUNITn, TNULLn, TSCALn, TZEROn, TDISPn, TDIMn,
+ TLMINn, TLMAXn, TDMINn, TDMAXn, TCTYPn, TCRPXn, TCRVLn, TCDLTn, TCROTn,
+> and TCUNIn.
+-
+ FTICOL(unit,colnum,ttype,tform, > status)
+ FTICLS(unit,colnum,ncols,ttype,tform, > status)
+-
+>5 Modify the vector length of a binary table column (e.g.,
+ change a column from TFORMn = '1E' to '20E'). The vector
+> length may be increased or decreased from the current value.
+-
+ FTMVEC(unit,colnum,newveclen, > status)
+-
+>6 Delete a column from an existing ASCII or binary table (in the CDU).
+ The index number of all the keywords listed above (for FTICOL) will be
+ decremented if necessary to reflect the new position of the column(s) in
+ the table. Those index keywords that refer to the deleted column will
+ also be deleted. Note that the physical size of the FITS file will
+ not be reduced by this operation, and the empty FITS blocks if any
+> at the end of the file will be padded with zeros.
+-
+ FTDCOL(unit,colnum, > status)
+-
+>7 Copy a column from one HDU to another (or to the same HDU). If
+ createcol = TRUE, then a new column will be inserted in the output
+ table, at position `outcolumn', otherwise the existing output column will
+ be overwritten (in which case it must have a compatible datatype).
+> Note that the first column in a table is at colnum = 1.
+-
+ FTCPCL(inunit,outunit,incolnum,outcolnum,createcol, > status);
+-
+***4. Read and Write Column Data Routines \label{FTPCLS}
+
+These subroutines put or get data values in the current ASCII or Binary table
+extension. Automatic data type conversion is performed for numerical data
+types (B,I,J,E,D) if the data type of the column (defined by the TFORM keyword)
+differs from the data type of the calling subroutine. The data values are also
+scaled by the TSCALn and TZEROn header values as they are being written to
+or read from the FITS array. The fttscl subroutine MUST be used to define the
+scaling parameters when writing data to the table or to override the default
+scaling values given in the header
+when reading from the table.
+
+ In the case of binary tables with vector elements, the 'felem'
+parameter defines the starting pixel within the element vector. This
+parameter is ignored with ASCII tables. Similarly, in the case of
+binary tables the 'nelements' parameter specifies the total number of
+vector values read or written (continuing on subsequent rows if
+required) and not the number of table elements. Two sets of
+subroutines are provided to get the column data which differ in the way
+undefined pixels are handled. The first set of routines (FTGCV)
+simply return an array of data elements in which undefined pixels are
+set equal to a value specified by the user in the 'nullval' parameter.
+An additional feature of these subroutines is that if the user sets
+nullval = 0, then no checks for undefined pixels will be performed,
+thus increasing the speed of the program. The second set of routines
+(FTGCF) returns the data element array and in addition a logical array
+of flags which defines whether the corresponding data pixel is undefined.
+
+ Any column, regardless of it's intrinsic datatype, may be read as a
+ string. It should be noted however that reading a numeric column
+ as a string is 10 - 100 times slower than reading the same column as
+ a number due to the large overhead in constructing the formatted
+ strings. The display format of the returned strings will be
+ determined by the TDISPn keyword, if it exists, otherwise by the
+ datatype of the column. The length of the returned strings can be
+ determined with the ftgcdw routine. The following TDISPn display
+ formats are currently supported:
+-
+ Iw.m Integer
+ Ow.m Octal integer
+ Zw.m Hexadecimal integer
+ Fw.d Fixed floating point
+ Ew.d Exponential floating point
+ Dw.d Exponential floating point
+ Gw.d General; uses Fw.d if significance not lost, else Ew.d
+-
+ where w is the width in characters of the displayed values, m is the minimum
+ number of digits displayed, and d is the number of digits to the right of the
+ decimal. The .m field is optional.
+
+>1 Put elements into an ASCII or binary table column (in the CDU).
+ (The SPP FSPCLS routine has an additional integer argument after
+ the VALUES character string which specifies the size of the 1st
+> dimension of this 2-D CHAR array).
+-
+ FTPCL[SLBIJEDCM](unit,colnum,frow,felem,nelements,values, > status)
+-
+>2 Put elements into an ASCII or binary table column (in the CDU)
+ substituting the appropriate FITS null value for any elements that
+ are equal to NULLVAL. This family of routines must NOT be used to
+ write to variable length array columns. For ASCII TABLE extensions, the
+ null value defined by the previous call to FTSNUL will be substituted;
+ For integer FITS columns, in a binary table the null value
+ defined by the previous call to FTTNUL will be substituted;
+ For floating point FITS columns a special IEEE NaN (Not-a-Number)
+> value will be substituted.
+-
+ FTPCN[BIJED](unit,colnum,frow,felem,nelements,values,nullval > status)
+-
+>3 Put bit values into a binary byte ('B') or bit ('X') table column (in the
+ CDU). LRAY is an array of logical values corresponding to the sequence of
+ bits to be written. If LRAY is true then the corresponding bit is
+ set to 1, otherwise the bit is set to 0. Note that in the case of
+ 'X' columns, FITSIO will write to all 8 bits of each byte whether
+ they are formally valid or not. Thus if the column is defined as
+ '4X', and one calls FTPCLX with fbit=1 and nbit=8, then all 8 bits
+ will be written into the first byte (as opposed to writing the
+ first 4 bits into the first row and then the next 4 bits into the
+ next row), even though the last 4 bits of each byte are formally
+> not defined.
+-
+ FTPCLX(unit,colnum,frow,fbit,nbit,lray, > status)
+-
+>>4 Set table elements in a column as undefined
+-
+ FTPCLU(unit,colnum,frow,felem,nelements, > status)
+-
+>5 Get elements from an ASCII or binary table column (in the CDU). These
+ routines return the values of the table column array elements. Undefined
+ array elements will be returned with a value = nullval, unless nullval = 0
+ (or = ' ' for ftgcvs) in which case no checking for undefined values will
+ be performed. The ANYF parameter is set to true if any of the returned
+ elements are undefined. (Note: the ftgcl routine simple gets an array
+ of logical data values without any checks for undefined values; use
+ the ftgcfl routine to check for undefined logical elements).
+ (The SPP FSGCVS routine has an additional integer argument after
+ the VALUES character string which specifies the size of the 1st
+> dimension of this 2-D CHAR array).
+-
+ FTGCL(unit,colnum,frow,felem,nelements, > values,status)
+ FTGCV[SBIJEDCM](unit,colnum,frow,felem,nelements,nullval, >
+ values,anyf,status)
+-
+>6 Get elements and null flags from an ASCII or binary table column (in the
+ CHDU). These routines return the values of the table column array elements.
+ Any undefined array elements will have the corresponding flagvals element
+ set equal to .TRUE. The ANYF parameter is set to true if any of the
+ returned elements are undefined.
+ (The SPP FSGCFS routine has an additional integer argument after
+ the VALUES character string which specifies the size of the 1st
+> dimension of this 2-D CHAR array).
+-
+ FTGCF[SLBIJEDCM](unit,colnum,frow,felem,nelements, >
+ values,flagvals,anyf,status)
+-
+>7 Get an arbitrary data subsection from an N-dimensional array
+ in a binary table vector column. Undefined pixels
+ in the array will be set equal to the value of 'nullval',
+ unless nullval=0 in which case no testing for undefined pixels will
+ be performed. The first and last rows in the table to be read
+ are specified by fpixels(naxis+1) and lpixels(naxis+1), and hence
+ are treated as the next higher dimension of the FITS N-dimensional
+ array. The INCS parameter specifies the sampling interval in
+> each dimension between the data elements that will be returned.
+-
+ FTGSV[BIJED](unit,colnum,naxis,naxes,fpixels,lpixels,incs,nullval, >
+ array,anyf,status)
+-
+>8 Get an arbitrary data subsection from an N-dimensional array
+ in a binary table vector column. Any Undefined
+ pixels in the array will have the corresponding 'flagvals'
+ element set equal to .TRUE. The first and last rows in the table
+ to be read are specified by fpixels(naxis+1) and lpixels(naxis+1),
+ and hence are treated as the next higher dimension of the FITS
+ N-dimensional array. The INCS parameter specifies the sampling
+ interval in each dimension between the data elements that will be
+> returned.
+-
+ FTGSF[BIJED](unit,colnum,naxis,naxes,fpixels,lpixels,incs, >
+ array,flagvals,anyf,status)
+-
+>9 Get bit values from a byte ('B') or bit (`X`) table column (in the
+ CDU). LRAY is an array of logical values corresponding to the
+ sequence of bits to be read. If LRAY is true then the
+ corresponding bit was set to 1, otherwise the bit was set to 0.
+ Note that in the case of 'X' columns, FITSIO will read all 8 bits
+ of each byte whether they are formally valid or not. Thus if the
+ column is defined as '4X', and one calls FTGCX with fbit=1 and
+ nbit=8, then all 8 bits will be read from the first byte (as
+ opposed to reading the first 4 bits from the first row and then the
+ first 4 bits from the next row), even though the last 4 bits of
+> each byte are formally not defined.
+-
+ FTGCX(unit,colnum,frow,fbit,nbit, > lray,status)
+-
+>10 Read any consecutive set of bits from an 'X' or 'B' column and
+ interpret them as an unsigned n-bit integer. NBIT must be less than
+ or equal to 16 when calling FTGCXI, and less than or equal to 32 when
+ calling FTGCXJ; there is no limit on the value of NBIT for FTGCXD, but
+ the returned double precision value only has 48 bits of precision on
+ most 32-bit word machines. The NBITS bits are interpreted as an
+ unsigned integer unless NBITS = 16 (in FTGCXI) or 32 (in FTGCXJ) in which
+ case the string of bits are interpreted as 16-bit or 32-bit 2's
+ complement signed integers. If NROWS is greater than 1 then the
+ same set of bits will be read from sequential rows in the table
+ starting with row FROW. Note that the numbering convention
+ used here for the FBIT parameter adopts 1 for the first element of the
+> vector of bits; this is the Most Significant Bit of the integer value.
+-
+ FTGCX[IJD](unit,colnum,frow,nrows,fbit,nbit, > array,status)
+-
+>11 Get the descriptor for a variable length column in a binary table.
+ The descriptor consists of 2 integer parameters: the number of elements
+ in the array and the starting offset relative to the start of the heap.
+ The first routine returns a single descriptor whereas the second routine
+> returns the descriptors for a range of rows in the table.
+-
+ FTGDES(unit,colnum,rownum, > nelements,offset,status)
+ FFGDESSunit,colnum,firstrow,nrows > nelements,offset, status)
+-
+>12 Put the descriptor for a variable length column in a binary table.
+ This subroutine can be used in conjunction with FTGDES to enable
+ 2 or more arrays to point to the same storage location to save
+> storage space if the arrays are identical.
+-
+ FTPDES(unit,colnum,rownum,nelements,offset, > status)
+-
+
+**I. Row Selection and Calculator Routines \label{FTFROW}
+
+These routines all parse and evaluate an input string containing a user
+defined arithmetic expression. The first 3 routines select rows in a
+FITS table, based on whether the expression evaluates to true (not
+equal to zero) or false (zero). The other routines evaluate the
+expression and calculate a value for each row of the table. The
+allowed expression syntax is described in the row filter section in the
+earlier `Extended File Name Syntax' chapter of this document. The
+expression may also be written to a text file, and the name of the
+file, prepended with a '@' character may be supplied for the 'expr'
+parameter (e.g. '@filename.txt'). The expression in the file can
+be arbitrarily complex and extend over multiple lines of the file.
+Lines that begin with 2 slash characters ('//') will be ignored and
+may be used to add comments to the file.
+
+>1 Evaluate a boolean expression over the indicated rows, returning an
+> array of flags indicating which rows evaluated to TRUE/FALSE
+-
+ FTFROW(unit,expr,firstrow, nrows, > n_good_rows, row_status, status)
+-
+>>2 Find the first row which satisfies the input boolean expression
+-
+ FTFFRW(unit, expr, > rownum, status)
+-
+>3 Evaluate an expression on all rows of a table. If the input and output
+files are not the same, copy the TRUE rows to the output file. If the
+>files are the same, delete the FALSE rows (preserve the TRUE rows).
+-
+ FTSROW(inunit, outunit, expr, > status)
+-
+>4 Calculate an expression for the indicated rows of a table, returning
+the results, cast as datatype (TSHORT, TDOUBLE, etc), in array. If
+nulval==NULL, UNDEFs will be zeroed out. For vector results, the number
+of elements returned may be less than nelements if nelements is not an
+even multiple of the result dimension. Call FTTEXP to obtain
+>the dimensions of the results.
+-
+ FTCROW(unit,datatype,expr,firstrow,nelements,nulval, >
+ array,anynul,status)
+-
+>5 Evaluate an expression and write the result either to a column (if
+the expression is a function of other columns in the table) or to a
+keyword (if the expression evaluates to a constant and is not a
+function of other columns in the table). In the former case, the
+parName parameter is the name of the column (which may or may not already
+exist) into which to write the results, and parInfo contains an
+optional TFORM keyword value if a new column is being created. If a
+TFORM value is not specified then a default format will be used,
+depending on the expression. If the expression evaluates to a constant,
+then the result will be written to the keyword name given by the
+parName parameter, and the parInfo parameter may be used to supply an
+optional comment for the keyword. If the keyword does not already
+exist, then the name of the keyword must be preceded with a '\#' character,
+>otherwise the result will be written to a column with that name.
+
+-
+ FTCALC(inunit, expr, outunit, parName, parInfo, > status)
+-
+>6 This calculator routine is similar to the previous routine, except
+that the expression is only evaluated over the specified
+row ranges. nranges specifies the number of row ranges, and firstrow
+>and lastrow give the starting and ending row number of each range.
+-
+ FTCALC_RNG(inunit, expr, outunit, parName, parInfo,
+ nranges, firstrow, lastrow, > status)
+-
+>>7 Evaluate the given expression and return information on the result.
+-
+ FTTEXP(unit, expr, > datatype, nelem, naxis, naxes, status)
+-
+
+
+**J. Celestial Coordinate System Subroutines \label{FTGICS}
+
+The FITS community has adopted a set of keyword conventions that define
+the transformations needed to convert between pixel locations in an
+image and the corresponding celestial coordinates on the sky, or more
+generally, that define world coordinates that are to be associated with
+any pixel location in an n-dimensional FITS array. CFITSIO is distributed
+with a couple of self-contained World Coordinate System (WCS) routines,
+however, these routines DO NOT support all the latest WCS conventions,
+so it is STRONGLY RECOMMENDED that software developers use a more robust
+external WCS library. Several recommended libraries are:
+-
+ WCSLIB - supported by Mark Calabretta
+ WCSTools - supported by Doug Mink
+ AST library - developed by the U.K. Starlink project
+-
+
+More information about the WCS keyword conventions and links to all of
+these WCS libraries can be found on the FITS Support Office web site at
+http://fits.gsfc.nasa.gov under the WCS link.
+
+The functions provided in these external WCS libraries will need access to
+the WCS information contained in the FITS file headers. One convenient
+way to pass this information to the extermal library is to use FITSIO
+to copy the header keywords into one long character string, and then
+pass this string to an interface routine in the external library that
+will extract the necessary WCS information (e.g., see the astFitsChan
+and astPutCards routines in the Starlink AST library).
+
+The following FITSIO routines DO NOT support the more recent WCS conventions
+that have been approved as part of the FITS standard. Consequently,
+the following routines ARE NOW DEPRECATED. It is STRONGLY RECOMMENDED
+that software developers not use these routines, and instead use an
+external WCS library, as described above.
+
+These routines are included mainly for backward compatibility with
+existing software. They support the following standard map
+projections: -SIN, -TAN, -ARC, -NCP, -GLS, -MER, and -AIT (these are the
+legal values for the coordtype parameter). These routines are based
+on similar functions in Classic AIPS. All the angular quantities are
+given in units of degrees.
+
+>1 Get the values of all the standard FITS celestial coordinate system
+ keywords from the header of a FITS image (i.e., the primary array or
+ an image extension). These values may then be passed to the subroutines
+ that perform the coordinate transformations. If any or all of the WCS
+ keywords are not present, then default values will be returned. If
+ the first coordinate axis is the declination-like coordinate, then
+ this routine will swap them so that the longitudinal-like coordinate
+ is returned as the first axis.
+
+ If the file uses the newer 'CDj\_i' WCS transformation matrix
+ keywords instead of old style 'CDELTn' and 'CROTA2' keywords, then
+ this routine will calculate and return the values of the equivalent
+ old-style keywords. Note that the conversion from the new-style
+ keywords to the old-style values is sometimes only an
+ approximation, so if the approximation is larger than an internally
+ defined threshold level, then CFITSIO will still return the
+ approximate WCS keyword values, but will also return with status =
+ 506, to warn the calling program that approximations have been
+ made. It is then up to the calling program to decide whether the
+ approximations are sufficiently accurate for the particular
+ application, or whether more precise WCS transformations must be
+> performed using new-style WCS keywords directly.
+-
+ FTGICS(unit, > xrval,yrval,xrpix,yrpix,xinc,yinc,rot,coordtype,status)
+-
+>2 Get the values of all the standard FITS celestial coordinate system
+ keywords from the header of a FITS table where the X and Y (or RA and
+ DEC coordinates are stored in 2 separate columns of the table.
+ These values may then be passed to the subroutines that perform the
+> coordinate transformations.
+-
+ FTGTCS(unit,xcol,ycol, >
+ xrval,yrval,xrpix,yrpix,xinc,yinc,rot,coordtype,status)
+-
+>3 Calculate the celestial coordinate corresponding to the input
+> X and Y pixel location in the image.
+-
+ FTWLDP(xpix,ypix,xrval,yrval,xrpix,yrpix,xinc,yinc,rot,
+ coordtype, > xpos,ypos,status)
+-
+>4 Calculate the X and Y pixel location corresponding to the input
+> celestial coordinate in the image.
+-
+ FTXYPX(xpos,ypos,xrval,yrval,xrpix,yrpix,xinc,yinc,rot,
+ coordtype, > xpix,ypix,status)
+-
+
+**K. File Checksum Subroutines \label{FTPCKS}
+
+The following routines either compute or validate the checksums for the
+CHDU. The DATASUM keyword is used to store the numerical value of the
+32-bit, 1's complement checksum for the data unit alone. If there is
+no data unit then the value is set to zero. The numerical value is
+stored as an ASCII string of digits, enclosed in quotes, because the
+value may be too large to represent as a 32-bit signed integer. The
+CHECKSUM keyword is used to store the ASCII encoded COMPLEMENT of the
+checksum for the entire HDU. Storing the complement, rather than the
+actual checksum, forces the checksum for the whole HDU to equal zero.
+If the file has been modified since the checksums were computed, then
+the HDU checksum will usually not equal zero. These checksum keyword
+conventions are based on a paper by Rob Seaman published in the
+proceedings of the ADASS IV conference in Baltimore in November 1994
+and a later revision in June 1995.
+
+>1 Compute and write the DATASUM and CHECKSUM keyword values for the CHDU
+ into the current header. The DATASUM value is the 32-bit checksum
+ for the data unit, expressed as a decimal integer enclosed in single
+ quotes. The CHECKSUM keyword value is a 16-character string which
+ is the ASCII-encoded value for the complement of the checksum for
+ the whole HDU. If these keywords already exist, their values
+ will be updated only if necessary (i.e., if the file has been modified
+> since the original keyword values were computed).
+-
+ FTPCKS(unit, > status)
+-
+>2 Update the CHECKSUM keyword value in the CHDU, assuming that the
+ DATASUM keyword exists and already has the correct value. This routine
+ calculates the new checksum for the current header unit, adds it to the
+ data unit checksum, encodes the value into an ASCII string, and writes
+> the string to the CHECKSUM keyword.
+-
+ FTUCKS(unit, > status)
+-
+>3 Verify the CHDU by computing the checksums and comparing
+ them with the keywords. The data unit is verified correctly
+ if the computed checksum equals the value of the DATASUM
+ keyword. The checksum for the entire HDU (header plus data unit) is
+ correct if it equals zero. The output DATAOK and HDUOK parameters
+ in this subroutine are integers which will have a value = 1
+ if the data or HDU is verified correctly, a value = 0
+ if the DATASUM or CHECKSUM keyword is not present, or value = -1
+> if the computed checksum is not correct.
+-
+ FTVCKS(unit, > dataok,hduok,status)
+-
+>4 Compute and return the checksum values for the CHDU (as
+ double precision variables) without creating or modifying the
+ CHECKSUM and DATASUM keywords. This routine is used internally by
+> FTVCKS, but may be useful in other situations as well.
+-
+ FTGCKS(unit, > datasum,hdusum,status)
+-
+>5 Encode a checksum value (stored in a double precision variable)
+ into a 16-character string. If COMPLEMENT = .true. then the 32-bit
+> sum value will be complemented before encoding.
+-
+ FTESUM(sum,complement, > checksum)
+-
+>6 Decode a 16 character checksum string into a double precision value.
+ If COMPLEMENT = .true. then the 32-bit sum value will be complemented
+> after decoding.
+-
+ FTDSUM(checksum,complement, > sum)
+-
+
+**L. Date and Time Utility Routines \label{FTGSDT}
+
+The following routines help to construct or parse the FITS date/time
+strings. Starting in the year 2000, the FITS DATE keyword values (and
+the values of other `DATE-' keywords) must have the form 'YYYY-MM-DD'
+(date only) or 'YYYY-MM-DDThh:mm:ss.ddd...' (date and time) where the
+number of decimal places in the seconds value is optional. These times
+are in UTC. The older 'dd/mm/yy' date format may not be used for dates
+after 01 January 2000.
+
+>1 Get the current system date. The returned year has 4 digits
+> (1999, 2000, etc.)
+-
+ FTGSDT( > day, month, year, status )
+-
+
+>2 Get the current system date and time string ('YYYY-MM-DDThh:mm:ss').
+The time will be in UTC/GMT if available, as indicated by a returned timeref
+value = 0. If the returned value of timeref = 1 then this indicates that
+it was not possible to convert the local time to UTC, and thus the local
+>time was returned.
+-
+ FTGSTM(> datestr, timeref, status)
+-
+
+>3 Construct a date string from the input date values. If the year
+is between 1900 and 1998, inclusive, then the returned date string will
+have the old FITS format ('dd/mm/yy'), otherwise the date string will
+have the new FITS format ('YYYY-MM-DD'). Use FTTM2S instead
+> to always return a date string using the new FITS format.
+-
+ FTDT2S( year, month, day, > datestr, status)
+-
+
+>4 Construct a new-format date + time string ('YYYY-MM-DDThh:mm:ss.ddd...').
+ If the year, month, and day values all = 0 then only the time is encoded
+ with format 'hh:mm:ss.ddd...'. The decimals parameter specifies how many
+ decimal places of fractional seconds to include in the string. If `decimals'
+> is negative, then only the date will be return ('YYYY-MM-DD').
+-
+ FTTM2S( year, month, day, hour, minute, second, decimals,
+ > datestr, status)
+-
+
+>5 Return the date as read from the input string, where the string may be
+in either the old ('dd/mm/yy') or new ('YYYY-MM-DDThh:mm:ss' or
+>'YYYY-MM-DD') FITS format.
+-
+ FTS2DT(datestr, > year, month, day, status)
+-
+
+>6 Return the date and time as read from the input string, where the
+string may be in either the old or new FITS format. The returned hours,
+minutes, and seconds values will be set to zero if the input string
+does not include the time ('dd/mm/yy' or 'YYYY-MM-DD') . Similarly,
+the returned year, month, and date values will be set to zero if the
+>date is not included in the input string ('hh:mm:ss.ddd...').
+-
+ FTS2TM(datestr, > year, month, day, hour, minute, second, status)
+-
+
+**M. General Utility Subroutines \label{FTGHAD}
+
+The following utility subroutines may be useful for certain applications:
+
+>>1 Return the starting byte address of the CHDU and the next HDU.
+-
+ FTGHAD(iunit, > curaddr,nextaddr)
+-
+>>2 Convert a character string to uppercase (operates in place).
+-
+ FTUPCH(string)
+-
+>3 Compare the input template string against the reference string
+ to see if they match. The template string may contain wildcard
+ characters: '*' will match any sequence of characters (including
+ zero characters) and '%' will match any single character in the
+ reference string. If CASESN = .true. then the match will be
+ case sensitive. The returned MATCH parameter will be .true. if
+ the 2 strings match, and EXACT will be .true. if the match is
+ exact (i.e., if no wildcard characters were used in the match).
+> Both strings must be 68 characters or less in length.
+-
+ FTCMPS(str_template,string,casesen, > match,exact)
+-
+
+>4 Test that the keyword name contains only legal characters: A-Z,0-9,
+> hyphen, and underscore.
+-
+ FTTKEY(keyword, > status)
+-
+>5 Test that the keyword record contains only legal printable ASCII
+> characters
+-
+ FTTREC(card, > status)
+-
+>6 Test whether the current header contains any NULL (ASCII 0) characters.
+ These characters are illegal in the header, but they will go undetected
+ by most of the CFITSIO keyword header routines, because the null is
+ interpreted as the normal end-of-string terminator. This routine returns
+ the position of the first null character in the header, or zero if there
+ are no nulls. For example a returned value of 110 would indicate that
+ the first NULL is located in the 30th character of the second keyword
+ in the header (recall that each header record is 80 characters long).
+ Note that this is one of the few FITSIO routines in which the returned
+> value is not necessarily equal to the status value).
+-
+ FTNCHK(unit, > status)
+-
+>7 Parse a header keyword record and return the name of the keyword
+ and the length of the name.
+ The keyword name normally occupies the first 8 characters of the
+ record, except under the HIERARCH convention where the name can
+> be up to 70 characters in length.
+-
+ FTGKNM(card, > keyname, keylength, status)
+-
+>8 Parse a header keyword record.
+ This subroutine parses the input header record to return the value (as
+ a character string) and comment strings. If the keyword has no
+ value (columns 9-10 not equal to '= '), then the value string is returned
+ blank and the comment string is set equal to column 9 - 80 of the
+> input string.
+-
+ FTPSVC(card, > value,comment,status)
+-
+>9 Construct a sequence keyword name (ROOT + nnn).
+ This subroutine appends the sequence number to the root string to create
+> a keyword name (e.g., 'NAXIS' + 2 = 'NAXIS2')
+-
+ FTKEYN(keyroot,seq_no, > keyword,status)
+-
+>10 Construct a sequence keyword name (n + ROOT).
+ This subroutine concatenates the sequence number to the front of the
+> root string to create a keyword name (e.g., 1 + 'CTYP' = '1CTYP')
+-
+ FTNKEY(seq_no,keyroot, > keyword,status)
+-
+>11 Determine the datatype of a keyword value string.
+ This subroutine parses the keyword value string (usually columns 11-30
+> of the header record) to determine its datatype.
+-
+ FTDTYP(value, > dtype,status)
+-
+>11 Return the class of input header record. The record is classified
+ into one of the following categories (the class values are
+ defined in fitsio.h). Note that this is one of the few FITSIO
+> routines that does not return a status value.
+-
+ Class Value Keywords
+ TYP_STRUC_KEY 10 SIMPLE, BITPIX, NAXIS, NAXISn, EXTEND, BLOCKED,
+ GROUPS, PCOUNT, GCOUNT, END
+ XTENSION, TFIELDS, TTYPEn, TBCOLn, TFORMn, THEAP,
+ and the first 4 COMMENT keywords in the primary array
+ that define the FITS format.
+ TYP_CMPRS_KEY 20 The experimental keywords used in the compressed
+ image format ZIMAGE, ZCMPTYPE, ZNAMEn, ZVALn,
+ ZTILEn, ZBITPIX, ZNAXISn, ZSCALE, ZZERO, ZBLANK
+ TYP_SCAL_KEY 30 BSCALE, BZERO, TSCALn, TZEROn
+ TYP_NULL_KEY 40 BLANK, TNULLn
+ TYP_DIM_KEY 50 TDIMn
+ TYP_RANG_KEY 60 TLMINn, TLMAXn, TDMINn, TDMAXn, DATAMIN, DATAMAX
+ TYP_UNIT_KEY 70 BUNIT, TUNITn
+ TYP_DISP_KEY 80 TDISPn
+ TYP_HDUID_KEY 90 EXTNAME, EXTVER, EXTLEVEL, HDUNAME, HDUVER, HDULEVEL
+ TYP_CKSUM_KEY 100 CHECKSUM, DATASUM
+ TYP_WCS_KEY 110 CTYPEn, CUNITn, CRVALn, CRPIXn, CROTAn, CDELTn
+ CDj_is, PVj_ms, LONPOLEs, LATPOLEs
+ TCTYPn, TCTYns, TCUNIn, TCUNns, TCRVLn, TCRVns, TCRPXn,
+ TCRPks, TCDn_k, TCn_ks, TPVn_m, TPn_ms, TCDLTn, TCROTn
+ jCTYPn, jCTYns, jCUNIn, jCUNns, jCRVLn, jCRVns, iCRPXn,
+ iCRPns, jiCDn, jiCDns, jPVn_m, jPn_ms, jCDLTn, jCROTn
+ (i,j,m,n are integers, s is any letter)
+ TYP_REFSYS_KEY 120 EQUINOXs, EPOCH, MJD-OBSs, RADECSYS, RADESYSs
+ TYP_COMM_KEY 130 COMMENT, HISTORY, (blank keyword)
+ TYP_CONT_KEY 140 CONTINUE
+ TYP_USER_KEY 150 all other keywords
+
+ class = FTGKCL (char *card)
+-
+>12 Parse the 'TFORM' binary table column format string.
+ This subroutine parses the input TFORM character string and returns the
+ integer datatype code, the repeat count of the field, and, in the case
+ of character string fields, the length of the unit string. The following
+ datatype codes are returned (the negative of the value is returned
+> if the column contains variable-length arrays):
+-
+ Datatype DATACODE value
+ bit, X 1
+ byte, B 11
+ logical, L 14
+ ASCII character, A 16
+ short integer, I 21
+ integer, J 41
+ real, E 42
+ double precision, D 82
+ complex 83
+ double complex 163
+
+ FTBNFM(tform, > datacode,repeat,width,status)
+-
+>13 Parse the 'TFORM' keyword value that defines the column format in
+ an ASCII table. This routine parses the input TFORM character
+ string and returns the datatype code, the width of the column,
+ and (if it is a floating point column) the number of decimal places
+ to the right of the decimal point. The returned datatype codes are
+ the same as for the binary table, listed above, with the following
+ additional rules: integer columns that are between 1 and 4 characters
+ wide are defined to be short integers (code = 21). Wider integer
+ columns are defined to be regular integers (code = 41). Similarly,
+ Fixed decimal point columns (with TFORM = 'Fw.d') are defined to
+ be single precision reals (code = 42) if w is between 1 and 7 characters
+ wide, inclusive. Wider 'F' columns will return a double precision
+ data code (= 82). 'Ew.d' format columns will have datacode = 42,
+> and 'Dw.d' format columns will have datacode = 82.
+-
+ FTASFM(tform, > datacode,width,decimals,status)
+-
+>14 Calculate the starting column positions and total ASCII table width
+ based on the input array of ASCII table TFORM values. The SPACE input
+ parameter defines how many blank spaces to leave between each column
+ (it is recommended to have one space between columns for better human
+> readability).
+-
+ FTGABC(tfields,tform,space, > rowlen,tbcol,status)
+-
+>15 Parse a template string and return a formatted 80-character string
+ suitable for appending to (or deleting from) a FITS header file.
+ This subroutine is useful for parsing lines from an ASCII template file
+ and reformatting them into legal FITS header records. The formatted
+ string may then be passed to the FTPREC, FTMCRD, or FTDKEY subroutines
+> to append or modify a FITS header record.
+-
+ FTGTHD(template, > card,hdtype,status)
+-
+ The input TEMPLATE character string generally should contain 3 tokens:
+ (1) the KEYNAME, (2) the VALUE, and (3) the COMMENT string. The
+ TEMPLATE string must adhere to the following format:
+
+>- The KEYNAME token must begin in columns 1-8 and be a maximum of 8
+ characters long. If the first 8 characters of the template line are
+ blank then the remainder of the line is considered to be a FITS comment
+ (with a blank keyword name). A legal FITS keyword name may only
+ contain the characters A-Z, 0-9, and '-' (minus sign) and
+ underscore. This subroutine will automatically convert any lowercase
+ characters to uppercase in the output string. If KEYNAME = 'COMMENT'
+ or 'HISTORY' then the remainder of the line is considered to be a FITS
+> COMMENT or HISTORY record, respectively.
+
+>- The VALUE token must be separated from the KEYNAME token by one or more
+ spaces and/or an '=' character. The datatype of the VALUE token
+ (numeric, logical, or character string) is automatically determined
+ and the output CARD string is formatted accordingly. The value
+ token may be forced to be interpreted as a string (e.g. if it is a
+> string of numeric digits) by enclosing it in single quotes.
+
+>- The COMMENT token is optional, but if present must be separated from
+ the VALUE token by at least one blank space. A leading '/' character
+ may be used to mark the beginning of the comment field, otherwise the
+ comment field begins with the first non-blank character following the
+> value token.
+
+>- One exception to the above rules is that if the first non-blank
+ character in the template string is a minus sign ('-') followed
+ by a single token, or a single token followed by an equal sign,
+ then it is interpreted as the name of a keyword which is to be
+> deleted from the FITS header.
+
+>- The second exception is that if the template string starts with
+ a minus sign and is followed by 2 tokens then the second token
+ is interpreted as the new name for the keyword specified by
+ first token. In this case the old keyword name (first token)
+ is returned in characters 1-8 of the returned CARD string, and
+ the new keyword name (the second token) is returned in characters
+ 41-48 of the returned CARD string. These old and new names
+ may then be passed to the FTMNAM subroutine which will change
+> the keyword name.
+
+ The HDTYPE output parameter indicates how the returned CARD string
+ should be interpreted:
+-
+ hdtype interpretation
+ ------ -------------------------------------------------
+ -2 Modify the name of the keyword given in CARD(1:8)
+ to the new name given in CARD(41:48)
+
+ -1 CARD(1:8) contains the name of a keyword to be deleted
+ from the FITS header.
+
+ 0 append the CARD string to the FITS header if the
+ keyword does not already exist, otherwise update
+ the value/comment if the keyword is already present
+ in the header.
+
+ 1 simply append this keyword to the FITS header (CARD
+ is either a HISTORY or COMMENT keyword).
+
+ 2 This is a FITS END record; it should not be written
+ to the FITS header because FITSIO automatically
+ appends the END record when the header is closed.
+-
+ EXAMPLES: The following lines illustrate valid input template strings:
+-
+ INTVAL 7 This is an integer keyword
+ RVAL 34.6 / This is a floating point keyword
+ EVAL=-12.45E-03 This is a floating point keyword in exponential notation
+ lval F This is a boolean keyword
+ This is a comment keyword with a blank keyword name
+ SVAL1 = 'Hello world' / this is a string keyword
+ SVAL2 '123.5' this is also a string keyword
+ sval3 123+ / this is also a string keyword with the value '123+ '
+ # the following template line deletes the DATE keyword
+ - DATE
+ # the following template line modifies the NAME keyword to OBJECT
+ - NAME OBJECT
+-
+>16 Parse the input string containing a list of rows or row ranges, and
+ return integer arrays containing the first and last row in each
+ range. For example, if rowlist = "3-5, 6, 8-9" then it will
+ return numranges = 3, rangemin = 3, 6, 8 and rangemax = 5, 6, 9.
+ At most, 'maxranges' number of ranges will be returned. 'maxrows'
+ is the maximum number of rows in the table; any rows or ranges
+ larger than this will be ignored. The rows must be specified in
+ increasing order, and the ranges must not overlap. A minus sign
+ may be use to specify all the rows to the upper or lower bound, so
+ "50-" means all the rows from 50 to the end of the table, and "-"
+> means all the rows in the table, from 1 - maxrows.
+-
+ FTRWRG(rowlist, maxrows, maxranges, >
+ numranges, rangemin, rangemax, status)
+-
+
+
+*IX Summary of all FITSIO User-Interface Subroutines
+
+ Error Status Routines page~\pageref{FTVERS}
+-
+ FTVERS( > version)
+ FTGERR(status, > errtext)
+ FTGMSG( > errmsg)
+ FTRPRT (stream, > status)
+ FTPMSG(errmsg)
+ FTPMRK
+ FTCMSG
+ FTCMRK
+-
+ FITS File Open and Close Subroutines: page~\pageref{FTOPEN}
+-
+ FTOPEN(unit,filename,rwmode, > blocksize,status)
+ FTDKOPEN(unit,filename,rwmode, > blocksize,status)
+ FTNOPN(unit,filename,rwmode, > status)
+ FTDOPN(unit,filename,rwmode, > status)
+ FTTOPN(unit,filename,rwmode, > status)
+ FTIOPN(unit,filename,rwmode, > status)
+ FTREOPEN(unit, > newunit, status)
+ FTINIT(unit,filename,blocksize, > status)
+ FTDKINIT(unit,filename,blocksize, > status)
+ FTTPLT(unit, filename, tplfilename, > status)
+ FTFLUS(unit, > status)
+ FTCLOS(unit, > status)
+ FTDELT(unit, > status)
+ FTGIOU( > iounit, status)
+ FTFIOU(iounit, > status)
+ CFITS2Unit(fitsfile *ptr) (C routine)
+ CUnit2FITS(int unit) (C routine)
+ FTEXTN(filename, > nhdu, status)
+ FTFLNM(unit, > filename, status)
+ FTFLMD(unit, > iomode, status)
+ FFURLT(unit, > urltype, status)
+ FTIURL(filename, > filetype, infile, outfile, extspec, filter,
+ binspec, colspec, status)
+ FTRTNM(filename, > rootname, status)
+ FTEXIST(filename, > exist, status)
+-
+ HDU-Level Operations: page~\pageref{FTMAHD}
+-
+ FTMAHD(unit,nhdu, > hdutype,status)
+ FTMRHD(unit,nmove, > hdutype,status)
+ FTGHDN(unit, > nhdu)
+ FTMNHD(unit, hdutype, extname, extver, > status)
+ FTGHDT(unit, > hdutype, status)
+ FTTHDU(unit, > hdunum, status)
+ FTCRHD(unit, > status)
+ FTIIMG(unit,bitpix,naxis,naxes, > status)
+ FTITAB(unit,rowlen,nrows,tfields,ttype,tbcol,tform,tunit,extname, >
+ status)
+ FTIBIN(unit,nrows,tfields,ttype,tform,tunit,extname,varidat > status)
+ FTRSIM(unit,bitpix,naxis,naxes,status)
+ FTDHDU(unit, > hdutype,status)
+ FTCPFL(iunit,ounit,previous, current, following, > status)
+ FTCOPY(iunit,ounit,morekeys, > status)
+ FTCPHD(inunit, outunit, > status)
+ FTCPDT(iunit,ounit, > status)
+-
+ Subroutines to specify or modify the structure of the CHDU: page~\pageref{FTRDEF}
+-
+ FTRDEF(unit, > status) (DEPRECATED)
+ FTPDEF(unit,bitpix,naxis,naxes,pcount,gcount, > status) (DEPRECATED)
+ FTADEF(unit,rowlen,tfields,tbcol,tform,nrows > status) (DEPRECATED)
+ FTBDEF(unit,tfields,tform,varidat,nrows > status) (DEPRECATED)
+ FTDDEF(unit,bytlen, > status) (DEPRECATED)
+ FTPTHP(unit,theap, > status)
+-
+ Header Space and Position Subroutines: page~\pageref{FTHDEF}
+-
+ FTHDEF(unit,morekeys, > status)
+ FTGHSP(iunit, > keysexist,keysadd,status)
+ FTGHPS(iunit, > keysexist,key_no,status)
+-
+ Read or Write Standard Header Subroutines: page~\pageref{FTPHPR}
+-
+ FTPHPS(unit,bitpix,naxis,naxes, > status)
+ FTPHPR(unit,simple,bitpix,naxis,naxes,pcount,gcount,extend, > status)
+ FTGHPR(unit,maxdim, > simple,bitpix,naxis,naxes,pcount,gcount,extend,
+ status)
+ FTPHTB(unit,rowlen,nrows,tfields,ttype,tbcol,tform,tunit,extname, >
+ status)
+ FTGHTB(unit,maxdim, > rowlen,nrows,tfields,ttype,tbcol,tform,tunit,
+ extname,status)
+ FTPHBN(unit,nrows,tfields,ttype,tform,tunit,extname,varidat > status)
+ FTGHBN(unit,maxdim, > nrows,tfields,ttype,tform,tunit,extname,varidat,
+ status)
+-
+ Write Keyword Subroutines: page~\pageref{FTPREC}
+-
+ FTPREC(unit,card, > status)
+ FTPCOM(unit,comment, > status)
+ FTPHIS(unit,history, > status)
+ FTPDAT(unit, > status)
+ FTPKY[JLS](unit,keyword,keyval,comment, > status)
+ FTPKY[EDFG](unit,keyword,keyval,decimals,comment, > status)
+ FTPKLS(unit,keyword,keyval,comment, > status)
+ FTPLSW(unit, > status)
+ FTPKYU(unit,keyword,comment, > status)
+ FTPKN[JLS](unit,keyroot,startno,no_keys,keyvals,comments, > status)
+ FTPKN[EDFG](unit,keyroot,startno,no_keys,keyvals,decimals,comments, >
+ status)
+ FTCPKYinunit, outunit, innum, outnum, keyroot, > status)
+ FTPKYT(unit,keyword,intval,dblval,comment, > status)
+ FTPKTP(unit, filename, > status)
+ FTPUNT(unit,keyword,units, > status)
+-
+ Insert Keyword Subroutines: page~\pageref{FTIREC}
+-
+ FTIREC(unit,key_no,card, > status)
+ FTIKY[JLS](unit,keyword,keyval,comment, > status)
+ FTIKLS(unit,keyword,keyval,comment, > status)
+ FTIKY[EDFG](unit,keyword,keyval,decimals,comment, > status)
+ FTIKYU(unit,keyword,comment, > status)
+-
+ Read Keyword Subroutines: page~\pageref{FTGREC}
+-
+ FTGREC(unit,key_no, > card,status)
+ FTGKYN(unit,key_no, > keyword,value,comment,status)
+ FTGCRD(unit,keyword, > card,status)
+ FTGNXK(unit,inclist,ninc,exclist,nexc, > card,status)
+ FTGKEY(unit,keyword, > value,comment,status)
+ FTGKY[EDJLS](unit,keyword, > keyval,comment,status)
+ FTGKN[EDJLS](unit,keyroot,startno,max_keys, > keyvals,nfound,status)
+ FTGKYT(unit,keyword, > intval,dblval,comment,status)
+ FTGUNT(unit,keyword, > units,status)
+-
+ Modify Keyword Subroutines: page~\pageref{FTMREC}
+-
+ FTMREC(unit,key_no,card, > status)
+ FTMCRD(unit,keyword,card, > status)
+ FTMNAM(unit,oldkey,keyword, > status)
+ FTMCOM(unit,keyword,comment, > status)
+ FTMKY[JLS](unit,keyword,keyval,comment, > status)
+ FTMKLS(unit,keyword,keyval,comment, > status)
+ FTMKY[EDFG](unit,keyword,keyval,decimals,comment, > status)
+ FTMKYU(unit,keyword,comment, > status)
+-
+ Update Keyword Subroutines: page~\pageref{FTUCRD}
+-
+ FTUCRD(unit,keyword,card, > status)
+ FTUKY[JLS](unit,keyword,keyval,comment, > status)
+ FTUKLS(unit,keyword,keyval,comment, > status)
+ FTUKY[EDFG](unit,keyword,keyval,decimals,comment, > status)
+ FTUKYU(unit,keyword,comment, > status)
+-
+ Delete Keyword Subroutines: page~\pageref{FTDREC}
+-
+ FTDREC(unit,key_no, > status)
+ FTDKEY(unit,keyword, > status)
+-
+ Define Data Scaling Parameters and Undefined Pixel Flags: page~\pageref{FTPSCL}
+-
+ FTPSCL(unit,bscale,bzero, > status)
+ FTTSCL(unit,colnum,tscal,tzero, > status)
+ FTPNUL(unit,blank, > status)
+ FTSNUL(unit,colnum,snull > status)
+ FTTNUL(unit,colnum,tnull > status)
+-
+ FITS Primary Array or IMAGE Extension I/O Subroutines: page~\pageref{FTPPR}
+-
+ FTGIDT(unit, > bitpix,status)
+ FTGIET(unit, > bitpix,status)
+ FTGIDM(unit, > naxis,status)
+ FTGISZ(unit, maxdim, > naxes,status)
+ FTGIPR(unit, maxdim, > bitpix,naxis,naxes,status)
+ FTPPR[BIJED](unit,group,fpixel,nelements,values, > status)
+ FTPPN[BIJED](unit,group,fpixel,nelements,values,nullval > status)
+ FTPPRU(unit,group,fpixel,nelements, > status)
+ FTGPV[BIJED](unit,group,fpixel,nelements,nullval, > values,anyf,status)
+ FTGPF[BIJED](unit,group,fpixel,nelements, > values,flagvals,anyf,status)
+ FTPGP[BIJED](unit,group,fparm,nparm,values, > status)
+ FTGGP[BIJED](unit,group,fparm,nparm, > values,status)
+ FTP2D[BIJED](unit,group,dim1,naxis1,naxis2,image, > status)
+ FTP3D[BIJED](unit,group,dim1,dim2,naxis1,naxis2,naxis3,cube, > status)
+ FTG2D[BIJED](unit,group,nullval,dim1,naxis1,naxis2, > image,anyf,status)
+ FTG3D[BIJED](unit,group,nullval,dim1,dim2,naxis1,naxis2,naxis3, >
+ cube,anyf,status)
+ FTPSS[BIJED](unit,group,naxis,naxes,fpixels,lpixels,array, > status)
+ FTGSV[BIJED](unit,group,naxis,naxes,fpixels,lpixels,incs,nullval, >
+ array,anyf,status)
+ FTGSF[BIJED](unit,group,naxis,naxes,fpixels,lpixels,incs, >
+ array,flagvals,anyf,status)
+-
+ Table Column Information Subroutines: page~\pageref{FTGCNO}
+-
+ FTGNRW(unit, > nrows, status)
+ FTGNCL(unit, > ncols, status)
+ FTGCNO(unit,casesen,coltemplate, > colnum,status)
+ FTGCNN(unit,casesen,coltemplate, > colnam,colnum,status)
+ FTGTCL(unit,colnum, > datacode,repeat,width,status)
+ FTEQTY(unit,colnum, > datacode,repeat,width,status)
+ FTGCDW(unit,colnum, > dispwidth,status)
+ FTGACL(unit,colnum, >
+ ttype,tbcol,tunit,tform,tscal,tzero,snull,tdisp,status)
+ FTGBCL(unit,colnum, >
+ ttype,tunit,datatype,repeat,tscal,tzero,tnull,tdisp,status)
+ FTPTDM(unit,colnum,naxis,naxes, > status)
+ FTGTDM(unit,colnum,maxdim, > naxis,naxes,status)
+ FTDTDM(unit,tdimstr,colnum,maxdim, > naxis,naxes, status)
+ FFGRSZ(unit, > nrows,status)
+-
+ Low-Level Table Access Subroutines: page~\pageref{FTGTBS}
+-
+ FTGTBS(unit,frow,startchar,nchars, > string,status)
+ FTPTBS(unit,frow,startchar,nchars,string, > status)
+ FTGTBB(unit,frow,startchar,nchars, > array,status)
+ FTPTBB(unit,frow,startchar,nchars,array, > status)
+-
+ Edit Rows or Columns page~\pageref{FTIROW}
+-
+ FTIROW(unit,frow,nrows, > status)
+ FTDROW(unit,frow,nrows, > status)
+ FTDRRG(unit,rowrange, > status)
+ FTDRWS(unit,rowlist,nrows, > status)
+ FTICOL(unit,colnum,ttype,tform, > status)
+ FTICLS(unit,colnum,ncols,ttype,tform, > status)
+ FTMVEC(unit,colnum,newveclen, > status)
+ FTDCOL(unit,colnum, > status)
+ FTCPCL(inunit,outunit,incolnum,outcolnum,createcol, > status);
+-
+ Read and Write Column Data Routines page~\pageref{FTPCLS}
+-
+ FTPCL[SLBIJEDCM](unit,colnum,frow,felem,nelements,values, > status)
+ FTPCN[BIJED](unit,colnum,frow,felem,nelements,values,nullval > status)
+ FTPCLX(unit,colnum,frow,fbit,nbit,lray, > status)
+ FTPCLU(unit,colnum,frow,felem,nelements, > status)
+ FTGCL(unit,colnum,frow,felem,nelements, > values,status)
+ FTGCV[SBIJEDCM](unit,colnum,frow,felem,nelements,nullval, >
+ values,anyf,status)
+ FTGCF[SLBIJEDCM](unit,colnum,frow,felem,nelements, >
+ values,flagvals,anyf,status)
+ FTGSV[BIJED](unit,colnum,naxis,naxes,fpixels,lpixels,incs,nullval, >
+ array,anyf,status)
+ FTGSF[BIJED](unit,colnum,naxis,naxes,fpixels,lpixels,incs, >
+ array,flagvals,anyf,status)
+ FTGCX(unit,colnum,frow,fbit,nbit, > lray,status)
+ FTGCX[IJD](unit,colnum,frow,nrows,fbit,nbit, > array,status)
+ FTGDES(unit,colnum,rownum, > nelements,offset,status)
+ FTPDES(unit,colnum,rownum,nelements,offset, > status)
+-
+ Row Selection and Calculator Routines: page~\pageref{FTFROW}
+-
+ FTFROW(unit,expr,firstrow, nrows, > n_good_rows, row_status, status)
+ FTFFRW(unit, expr, > rownum, status)
+ FTSROW(inunit, outunit, expr, > status )
+ FTCROW(unit,datatype,expr,firstrow,nelements,nulval, >
+ array,anynul,status)
+ FTCALC(inunit, expr, outunit, parName, parInfo, > status)
+ FTCALC_RNG(inunit, expr, outunit, parName, parInfo,
+ nranges, firstrow, lastrow, > status)
+ FTTEXP(unit, expr, > datatype, nelem, naxis, naxes, status)
+-
+ Celestial Coordinate System Subroutines: page~\pageref{FTGICS}
+-
+ FTGICS(unit, > xrval,yrval,xrpix,yrpix,xinc,yinc,rot,coordtype,status)
+ FTGTCS(unit,xcol,ycol, >
+ xrval,yrval,xrpix,yrpix,xinc,yinc,rot,coordtype,status)
+ FTWLDP(xpix,ypix,xrval,yrval,xrpix,yrpix,xinc,yinc,rot,
+ coordtype, > xpos,ypos,status)
+ FTXYPX(xpos,ypos,xrval,yrval,xrpix,yrpix,xinc,yinc,rot,
+ coordtype, > xpix,ypix,status)
+-
+ File Checksum Subroutines: page~\pageref{FTPCKS}
+-
+ FTPCKS(unit, > status)
+ FTUCKS(unit, > status)
+ FTVCKS(unit, > dataok,hduok,status)
+ FTGCKS(unit, > datasum,hdusum,status)
+ FTESUM(sum,complement, > checksum)
+ FTDSUM(checksum,complement, > sum)
+
+-
+ Time and Date Utility Subroutines: page~\pageref{FTGSDT}
+-
+ FTGSDT( > day, month, year, status )
+ FTGSTM(> datestr, timeref, status)
+ FTDT2S( year, month, day, > datestr, status)
+ FTTM2S( year, month, day, hour, minute, second, decimals,
+ > datestr, status)
+ FTS2DT(datestr, > year, month, day, status)
+ FTS2TM(datestr, > year, month, day, hour, minute, second, status)
+-
+ General Utility Subroutines: page~\pageref{FTGHAD}
+-
+ FTGHAD(unit, > curaddr,nextaddr)
+ FTUPCH(string)
+ FTCMPS(str_template,string,casesen, > match,exact)
+ FTTKEY(keyword, > status)
+ FTTREC(card, > status)
+ FTNCHK(unit, > status)
+ FTGKNM(unit, > keyword, keylength, status)
+ FTPSVC(card, > value,comment,status)
+ FTKEYN(keyroot,seq_no, > keyword,status)
+ FTNKEY(seq_no,keyroot, > keyword,status)
+ FTDTYP(value, > dtype,status)
+ class = FTGKCL(card)
+ FTASFM(tform, > datacode,width,decimals,status)
+ FTBNFM(tform, > datacode,repeat,width,status)
+ FTGABC(tfields,tform,space, > rowlen,tbcol,status)
+ FTGTHD(template, > card,hdtype,status)
+ FTRWRG(rowlist, maxrows, maxranges, > numranges, rangemin,
+ rangemax, status)
+-
+
+*X. Parameter Definitions
+-
+anyf - (logical) set to TRUE if any of the returned data values are undefined
+array - (any datatype except character) array of bytes to be read or written.
+bitpix - (integer) bits per pixel: 8, 16, 32, -32, or -64
+blank - (integer) value used for undefined pixels in integer primary array
+blocksize - (integer) 2880-byte logical record blocking factor
+ (if 0 < blocksize < 11) or the actual block size in bytes
+ (if 10 < blocksize < 28800). As of version 3.3 of FITSIO,
+ blocksizes greater than 2880 are no longer supported.
+bscale - (double precision) scaling factor for the primary array
+bytlen - (integer) length of the data unit, in bytes
+bzero - (double precision) zero point for primary array scaling
+card - (character*80) header record to be read or written
+casesen - (logical) will string matching be case sensitive?
+checksum - (character*16) encoded checksum string
+colname - (character) ASCII name of the column
+colnum - (integer) number of the column (first column = 1)
+coltemplate - (character) template string to be matched to column names
+comment - (character) the keyword comment field
+comments - (character array) keyword comment fields
+compid - (integer) the type of computer that the program is running on
+complement - (logical) should the checksum be complemented?
+coordtype - (character) type of coordinate projection (-SIN, -TAN, -ARC,
+ -NCP, -GLS, -MER, or -AIT)
+cube - 3D data cube of the appropriate datatype
+curaddr - (integer) starting address (in bytes) of the CHDU
+datacode - (integer) symbolic code of the binary table column datatype
+dataok - (integer) was the data unit verification successful (=1) or
+ not (= -1). Equals zero if the DATASUM keyword is not present.
+datasum - (double precision) 32-bit 1's complement checksum for the data unit
+datatype - (character) datatype (format) of the binary table column
+datestr - (string) FITS date/time string: 'YYYY-MM-DDThh:mm:ss.ddd',
+ 'YYYY-MM-dd', or 'dd/mm/yy'
+day - (integer) current day of the month
+dblval - (double precision) fractional part of the keyword value
+decimals - (integer) number of decimal places to be displayed
+dim1 - (integer) actual size of the first dimension of the image or cube array
+dim2 - (integer) actual size of the second dimension of the cube array
+dispwidth - (integer) - the display width (length of string) for a column
+dtype - (character) datatype of the keyword ('C', 'L', 'I', or 'F')
+ C = character string
+ L = logical
+ I = integer
+ F = floating point number
+errmsg - (character*80) oldest error message on the internal stack
+errtext - (character*30) descriptive error message corresponding to error number
+casesen - (logical) true if column name matching is case sensitive
+exact - (logical) do the strings match exactly, or were wildcards used?
+exclist (character array) list of names to be excluded from search
+exists - flag indicating whether the file or compressed file exists on disk
+extend - (logical) true if there may be extensions following the primary data
+extname - (character) value of the EXTNAME keyword (if not blank)
+fbit - (integer) first bit in the field to be read or written
+felem - (integer) first pixel of the element vector (ignored for ASCII tables)
+filename - (character) name of the FITS file
+flagvals - (logical array) True if corresponding data element is undefined
+fparm - (integer) sequence number of the first group parameter to read or write
+fpixel - (integer) the first pixel position
+fpixels - (integer array) the first included pixel in each dimension
+frow - (integer) beginning row number (first row of table = 1)
+gcount - (integer) value of the GCOUNT keyword (usually = 1)
+group - (integer) sequence number of the data group (=0 for non-grouped data)
+hdtype - (integer) header record type: -1=delete; 0=append or replace;
+ 1=append; 2=this is the END keyword
+hduok - (integer) was the HDU verification successful (=1) or
+ not (= -1). Equals zero if the CHECKSUM keyword is not present.
+hdusum - (double precision) 32 bit 1's complement checksum for the entire CHDU
+hdutype - (integer) type of HDU: 0 = primary array or IMAGE, 1 = ASCII table,
+ 2 = binary table, -1 = unknown
+history - (character) the HISTORY keyword comment string
+hour - (integer) hour from 0 - 23
+image - 2D image of the appropriate datatype
+inclist (character array) list of names to be included in search
+incs - (integer array) sampling interval for pixels in each FITS dimension
+intval - (integer) integer part of the keyword value
+iounit - (integer) value of an unused I/O unit number
+iunit - (integer) logical unit number associated with the input FITS file, 1-199
+key_no - (integer) sequence number (starting with 1) of the keyword record
+keylength - (integer) length of the keyword name
+keyroot - (character) root string for the keyword name
+keysadd -(integer) number of new keyword records which can fit in the CHU
+keysexist - (integer) number of existing keyword records in the CHU
+keyval - value of the keyword in the appropriate datatype
+keyvals - (array) value of the keywords in the appropriate datatype
+keyword - (character*8) name of a keyword
+lray - (logical array) array of logical values corresponding to the bit array
+lpixels - (integer array) the last included pixel in each dimension
+match - (logical) do the 2 strings match?
+maxdim - (integer) dimensioned size of the NAXES, TTYPE, TFORM or TUNIT arrays
+max_keys - (integer) maximum number of keywords to search for
+minute - (integer) minute of an hour (0 - 59)
+month - (integer) current month of the year (1 - 12)
+morekeys - (integer) will leave space in the header for this many more keywords
+naxes - (integer array) size of each dimension in the FITS array
+naxis - (integer) number of dimensions in the FITS array
+naxis1 - (integer) length of the X/first axis of the FITS array
+naxis2 - (integer) length of the Y/second axis of the FITS array
+naxis3 - (integer) length of the Z/third axis of the FITS array
+nbit - (integer) number of bits in the field to read or write
+nchars - (integer) number of characters to read and return
+ncols - (integer) number of columns
+nelements - (integer) number of data elements to read or write
+nexc (integer) number of names in the exclusion list (may = 0)
+nhdu - (integer) absolute number of the HDU (1st HDU = 1)
+ninc (integer) number of names in the inclusion list
+nmove - (integer) number of HDUs to move (+ or -), relative to current position
+nfound - (integer) number of keywords found (highest keyword number)
+no_keys - (integer) number of keywords to write in the sequence
+nparm - (integer) number of group parameters to read or write
+nrows - (integer) number of rows in the table
+nullval - value to represent undefined pixels, of the appropriate datatype
+nextaddr - (integer) starting address (in bytes) of the HDU following the CHDU
+offset - (integer) byte offset in the heap to the first element of the array
+oldkey - (character) old name of keyword to be modified
+ounit - (integer) logical unit number associated with the output FITS file 1-199
+pcount - (integer) value of the PCOUNT keyword (usually = 0)
+repeat - (integer) length of element vector (e.g. 12J); ignored for ASCII table
+rot - (double precision) celestial coordinate rotation angle (degrees)
+rowlen - (integer) length of a table row, in characters or bytes
+rowlist - (integer array) list of row numbers to be deleted in increasing order
+rownum - (integer) number of the row (first row = 1)
+rowrange- (string) list of rows or row ranges to be deleted
+rwmode - (integer) file access mode: 0 = readonly, 1 = readwrite
+second (double)- second within minute (0 - 60.9999999999) (leap second!)
+seq_no - (integer) the sequence number to append to the keyword root name
+simple - (logical) does the FITS file conform to all the FITS standards
+snull - (character) value used to represent undefined values in ASCII table
+space - (integer) number of blank spaces to leave between ASCII table columns
+startchar - (integer) first character in the row to be read
+startno - (integer) value of the first keyword sequence number (usually 1)
+status - (integer) returned error status code (0 = OK)
+str_template (character) template string to be matched to reference string
+stream - (character) output stream for the report: either 'STDOUT' or 'STDERR'
+string - (character) character string
+sum - (double precision) 32 bit unsigned checksum value
+tbcol - (integer array) column number of the first character in the field(s)
+tdisp - (character) Fortran type display format for the table column
+template-(character) template string for a FITS header record
+tfields - (integer) number of fields (columns) in the table
+tform - (character array) format of the column(s); allowed values are:
+ For ASCII tables: Iw, Aw, Fww.dd, Eww.dd, or Dww.dd
+ For binary tables: rL, rX, rB, rI, rJ, rA, rAw, rE, rD, rC, rM
+ where 'w'=width of the field, 'd'=no. of decimals, 'r'=repeat count
+ Note that the 'rAw' form is non-standard extension to the
+ TFORM keyword syntax that is not specifically defined in the
+ Binary Tables definition document.
+theap - (integer) zero indexed byte offset of starting address of the heap
+ relative to the beginning of the binary table data
+tnull - (integer) value used to represent undefined values in binary table
+ttype - (character array) label for table column(s)
+tscal - (double precision) scaling factor for table column
+tunit - (character array) physical unit for table column(s)
+tzero - (double precision) scaling zero point for table column
+unit - (integer) logical unit number associated with the FITS file (1-199)
+units - (character) the keyword units string (e.g., 'km/s')
+value - (character) the keyword value string
+values - array of data values of the appropriate datatype
+varidat - (integer) size in bytes of the 'variable length data area'
+ following the binary table data (usually = 0)
+version - (real) current revision number of the library
+width - (integer) width of the character string field
+xcol - (integer) number of the column containing the X coordinate values
+xinc - (double precision) X axis coordinate increment at reference pixel (deg)
+xpix - (double precision) X axis pixel location
+xpos - (double precision) X axis celestial coordinate (usually RA) (deg)
+xrpix - (double precision) X axis reference pixel array location
+xrval - (double precision) X axis coordinate value at the reference pixel (deg)
+ycol - (integer) number of the column containing the X coordinate values
+year - (integer) last 2 digits of the year (00 - 99)
+yinc - (double precision) Y axis coordinate increment at reference pixel (deg)
+ypix - (double precision) y axis pixel location
+ypos - (double precision) y axis celestial coordinate (usually DEC) (deg)
+yrpix - (double precision) Y axis reference pixel array location
+yrval - (double precision) Y axis coordinate value at the reference pixel (deg)
+-
+
+*XI. FITSIO Error Status Codes
+-
+Status codes in the range -99 to -999 and 1 to 999 are reserved for future
+FITSIO use.
+
+ 0 OK, no error
+101 input and output files are the same
+103 too many FITS files open at once; all internal buffers full
+104 error opening existing file
+105 error creating new FITS file; (does a file with this name already exist?)
+106 error writing record to FITS file
+107 end-of-file encountered while reading record from FITS file
+108 error reading record from file
+110 error closing FITS file
+111 internal array dimensions exceeded
+112 Cannot modify file with readonly access
+113 Could not allocate memory
+114 illegal logical unit number; must be between 1 - 199, inclusive
+115 NULL input pointer to routine
+116 error seeking position in file
+
+121 invalid URL prefix on file name
+122 tried to register too many IO drivers
+123 driver initialization failed
+124 matching driver is not registered
+125 failed to parse input file URL
+126 parse error in range list
+
+151 bad argument in shared memory driver
+152 null pointer passed as an argument
+153 no more free shared memory handles
+154 shared memory driver is not initialized
+155 IPC error returned by a system call
+156 no memory in shared memory driver
+157 resource deadlock would occur
+158 attempt to open/create lock file failed
+159 shared memory block cannot be resized at the moment
+
+
+201 header not empty; can't write required keywords
+202 specified keyword name was not found in the header
+203 specified header record number is out of bounds
+204 keyword value field is blank
+205 keyword value string is missing the closing quote character
+207 illegal character in keyword name or header record
+208 keyword does not have expected name. Keyword out of sequence?
+209 keyword does not have expected integer value
+210 could not find the required END header keyword
+211 illegal BITPIX keyword value
+212 illegal NAXIS keyword value
+213 illegal NAXISn keyword value: must be 0 or positive integer
+214 illegal PCOUNT keyword value
+215 illegal GCOUNT keyword value
+216 illegal TFIELDS keyword value
+217 negative ASCII or binary table width value (NAXIS1)
+218 negative number of rows in ASCII or binary table (NAXIS2)
+219 column name (TTYPE keyword) not found
+220 illegal SIMPLE keyword value
+221 could not find the required SIMPLE header keyword
+222 could not find the required BITPIX header keyword
+223 could not find the required NAXIS header keyword
+224 could not find all the required NAXISn keywords in the header
+225 could not find the required XTENSION header keyword
+226 the CHDU is not an ASCII table extension
+227 the CHDU is not a binary table extension
+228 could not find the required PCOUNT header keyword
+229 could not find the required GCOUNT header keyword
+230 could not find the required TFIELDS header keyword
+231 could not find all the required TBCOLn keywords in the header
+232 could not find all the required TFORMn keywords in the header
+233 the CHDU is not an IMAGE extension
+234 illegal TBCOL keyword value; out of range
+235 this operation only allowed for ASCII or BINARY table extension
+236 column is too wide to fit within the specified width of the ASCII table
+237 the specified column name template matched more than one column name
+241 binary table row width is not equal to the sum of the field widths
+251 unrecognizable type of FITS extension
+252 unrecognizable FITS record
+253 END keyword contains non-blank characters in columns 9-80
+254 Header fill area contains non-blank characters
+255 Data fill area contains non-blank on non-zero values
+261 unable to parse the TFORM keyword value string
+262 unrecognizable TFORM datatype code
+263 illegal TDIMn keyword value
+
+301 illegal HDU number; less than 1 or greater than internal buffer size
+302 column number out of range (1 - 999)
+304 attempt to move to negative file record number
+306 attempted to read or write a negative number of bytes in the FITS file
+307 illegal starting row number for table read or write operation
+308 illegal starting element number for table read or write operation
+309 attempted to read or write character string in non-character table column
+310 attempted to read or write logical value in non-logical table column
+311 illegal ASCII table TFORM format code for attempted operation
+312 illegal binary table TFORM format code for attempted operation
+314 value for undefined pixels has not been defined
+317 attempted to read or write descriptor in a non-descriptor field
+320 number of array dimensions out of range
+321 first pixel number is greater than the last pixel number
+322 attempt to set BSCALE or TSCALn scaling parameter = 0
+323 illegal axis length less than 1
+
+340 NOT_GROUP_TABLE 340 Grouping function error
+341 HDU_ALREADY_MEMBER
+342 MEMBER_NOT_FOUND
+343 GROUP_NOT_FOUND
+344 BAD_GROUP_ID
+345 TOO_MANY_HDUS_TRACKED
+346 HDU_ALREADY_TRACKED
+347 BAD_OPTION
+348 IDENTICAL_POINTERS
+349 BAD_GROUP_ATTACH
+350 BAD_GROUP_DETACH
+
+360 NGP_NO_MEMORY malloc failed
+361 NGP_READ_ERR read error from file
+362 NGP_NUL_PTR null pointer passed as an argument.
+ Passing null pointer as a name of
+ template file raises this error
+363 NGP_EMPTY_CURLINE line read seems to be empty (used
+ internally)
+364 NGP_UNREAD_QUEUE_FULL cannot unread more then 1 line (or single
+ line twice)
+365 NGP_INC_NESTING too deep include file nesting (infinite
+ loop, template includes itself ?)
+366 NGP_ERR_FOPEN fopen() failed, cannot open template file
+367 NGP_EOF end of file encountered and not expected
+368 NGP_BAD_ARG bad arguments passed. Usually means
+ internal parser error. Should not happen
+369 NGP_TOKEN_NOT_EXPECT token not expected here
+
+401 error attempting to convert an integer to a formatted character string
+402 error attempting to convert a real value to a formatted character string
+403 cannot convert a quoted string keyword to an integer
+404 attempted to read a non-logical keyword value as a logical value
+405 cannot convert a quoted string keyword to a real value
+406 cannot convert a quoted string keyword to a double precision value
+407 error attempting to read character string as an integer
+408 error attempting to read character string as a real value
+409 error attempting to read character string as a double precision value
+410 bad keyword datatype code
+411 illegal number of decimal places while formatting floating point value
+412 numerical overflow during implicit datatype conversion
+413 error compressing image
+414 error uncompressing image
+420 error in date or time conversion
+
+431 syntax error in parser expression
+432 expression did not evaluate to desired type
+433 vector result too large to return in array
+434 data parser failed not sent an out column
+435 bad data encounter while parsing column
+436 parse error: output file not of proper type
+
+501 celestial angle too large for projection
+502 bad celestial coordinate or pixel value
+503 error in celestial coordinate calculation
+504 unsupported type of celestial projection
+505 required celestial coordinate keywords not found
+506 approximate wcs keyword values were returned
+-
+\end{document}
diff --git a/pkg/tbtables/cfitsio/fitsio.h b/pkg/tbtables/cfitsio/fitsio.h
new file mode 100644
index 00000000..f38f8ad6
--- /dev/null
+++ b/pkg/tbtables/cfitsio/fitsio.h
@@ -0,0 +1,1565 @@
+/* Version Info: This file is distributed with version 2.510 of CFITSIO */
+
+/* The FITSIO software was written by William Pence at the High Energy */
+/* Astrophysic Science Archive Research Center (HEASARC) at the NASA */
+/* Goddard Space Flight Center. */
+/*
+
+Copyright (Unpublished--all rights reserved under the copyright laws of
+the United States), U.S. Government as represented by the Administrator
+of the National Aeronautics and Space Administration. No copyright is
+claimed in the United States under Title 17, U.S. Code.
+
+Permission to freely use, copy, modify, and distribute this software
+and its documentation without fee is hereby granted, provided that this
+copyright notice and disclaimer of warranty appears in all copies.
+
+DISCLAIMER:
+
+THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND,
+EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO,
+ANY WARRANTY THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY
+IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE, AND FREEDOM FROM INFRINGEMENT, AND ANY WARRANTY THAT THE
+DOCUMENTATION WILL CONFORM TO THE SOFTWARE, OR ANY WARRANTY THAT THE
+SOFTWARE WILL BE ERROR FREE. IN NO EVENT SHALL NASA BE LIABLE FOR ANY
+DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, INDIRECT, SPECIAL OR
+CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, OR IN ANY WAY
+CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY,
+CONTRACT, TORT , OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY
+PERSONS OR PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED
+FROM, OR AROSE OUT OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR
+SERVICES PROVIDED HEREUNDER."
+
+*/
+
+#ifndef _FITSIO_H
+#define _FITSIO_H
+
+#include <stdio.h>
+
+#if defined(linux) || defined(__APPLE__)
+# include <sys/types.h> /* apparently needed on debian linux systems */
+#endif /* to define off_t */
+
+#include <stdlib.h> /* apparently needed to define size_t with gcc 2.8.1 */
+#include <limits.h> /* needed for LLONG_MAX and INT64_MAX definitions */
+
+/* Define the datatype for variables which store file offset values. */
+/* The new 'off_t' datatype should be used for this purpose, but some */
+/* older compilers do not recognize this type, in which case we use 'long' */
+/* instead. Note that _OFF_T is defined (or not) in stdio.h depending */
+/* on whether _LARGEFILE_SOURCE is defined in sys/feature_tests.h */
+/* (at least on Solaris platforms using cc) */
+
+/* Debian systems require the 2nd test, below, */
+/* i.e, "(defined(linux) && defined(__off_t_defined))" */
+#if defined(_OFF_T) || (defined(linux) && defined(__off_t_defined)) || defined(_MIPS_SZLONG) || defined(__APPLE__) || defined(_AIX)
+# define OFF_T off_t
+#else
+# define OFF_T long
+#endif
+
+/* typedef the 'LONGLONG' data type to the intrinsice 8-byte integer type */
+
+#if defined(HAVE_LONGLONG) || defined(__APPLE__)
+ typedef long long LONGLONG;
+# ifndef HAVE_LONGLONG
+# define HAVE_LONGLONG 1
+# endif
+#elif defined(_MSC_VER) /* Windows PCs; Visual C++, but not Borland C++ */
+ typedef __int64 LONGLONG;
+# ifndef HAVE_LONGLONG
+# define HAVE_LONGLONG 1
+# endif
+#else
+ typedef long LONGLONG; /* intrinsic 8-byte integer not supported */
+#endif
+
+/* The following exclusion if __CINT__ is defined is needed for ROOT */
+#ifndef __CINT__
+#include "longnam.h"
+#endif
+
+/* global variables */
+
+#define FLEN_FILENAME 1025 /* max length of a filename */
+#define FLEN_KEYWORD 72 /* max length of a keyword (HIERARCH convention) */
+#define FLEN_CARD 81 /* length of a FITS header card */
+#define FLEN_VALUE 71 /* max length of a keyword value string */
+#define FLEN_COMMENT 73 /* max length of a keyword comment string */
+#define FLEN_ERRMSG 81 /* max length of a FITSIO error message */
+#define FLEN_STATUS 31 /* max length of a FITSIO status text string */
+
+#define TBIT 1 /* codes for FITS table data types */
+#define TBYTE 11
+#define TSBYTE 12
+#define TLOGICAL 14
+#define TSTRING 16
+#define TUSHORT 20
+#define TSHORT 21
+#define TUINT 30
+#define TINT 31
+#define TULONG 40
+#define TLONG 41
+#define TINT32BIT 41 /* used when returning datatype of a column */
+#define TFLOAT 42
+#define TLONGLONG 81
+#define TDOUBLE 82
+#define TCOMPLEX 83
+#define TDBLCOMPLEX 163
+
+#define TYP_STRUC_KEY 10
+#define TYP_CMPRS_KEY 20
+#define TYP_SCAL_KEY 30
+#define TYP_NULL_KEY 40
+#define TYP_DIM_KEY 50
+#define TYP_RANG_KEY 60
+#define TYP_UNIT_KEY 70
+#define TYP_DISP_KEY 80
+#define TYP_HDUID_KEY 90
+#define TYP_CKSUM_KEY 100
+#define TYP_WCS_KEY 110
+#define TYP_REFSYS_KEY 120
+#define TYP_COMM_KEY 130
+#define TYP_CONT_KEY 140
+#define TYP_USER_KEY 150
+
+
+#define INT32BIT int /* 32-bit integer datatype. Currently this */
+ /* datatype is an 'int' on all useful platforms */
+ /* however, it is possible that that are cases */
+ /* where 'int' is a 2-byte integer, in which case */
+ /* INT32BIT would need to be defined as 'long'. */
+
+#define BYTE_IMG 8 /* BITPIX code values for FITS image types */
+#define SHORT_IMG 16
+#define LONG_IMG 32
+#define LONGLONG_IMG 64
+#define FLOAT_IMG -32
+#define DOUBLE_IMG -64
+ /* The following 2 codes are not true FITS */
+ /* datatypes; these codes are only used internally */
+ /* within cfitsio to make it easier for users */
+ /* to deal with unsigned integers. */
+#define SBYTE_IMG 10
+#define USHORT_IMG 20
+#define ULONG_IMG 40
+
+#define IMAGE_HDU 0 /* Primary Array or IMAGE HDU */
+#define ASCII_TBL 1 /* ASCII table HDU */
+#define BINARY_TBL 2 /* Binary table HDU */
+#define ANY_HDU -1 /* matches any HDU type */
+
+#define READONLY 0 /* options when opening a file */
+#define READWRITE 1
+
+/* adopt a hopefully obscure number to use as a null value flag */
+/* could be problems if the FITS files contain data with these values */
+#define FLOATNULLVALUE -9.11912E-36F
+#define DOUBLENULLVALUE -9.1191291391491E-36
+
+/* Image compression algorithm types */
+#define MAX_COMPRESS_DIM 6
+#define RICE_1 11
+#define GZIP_1 21
+#define PLIO_1 31
+#define HCOMPRESS_1 41
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#define CASESEN 1 /* do case-sensitive string match */
+#define CASEINSEN 0 /* do case-insensitive string match */
+
+#define GT_ID_ALL_URI 0 /* hierarchical grouping parameters */
+#define GT_ID_REF 1
+#define GT_ID_POS 2
+#define GT_ID_ALL 3
+#define GT_ID_REF_URI 11
+#define GT_ID_POS_URI 12
+
+#define OPT_RM_GPT 0
+#define OPT_RM_ENTRY 1
+#define OPT_RM_MBR 2
+#define OPT_RM_ALL 3
+
+#define OPT_GCP_GPT 0
+#define OPT_GCP_MBR 1
+#define OPT_GCP_ALL 2
+
+#define OPT_MCP_ADD 0
+#define OPT_MCP_NADD 1
+#define OPT_MCP_REPL 2
+#define OPT_MCP_MOV 3
+
+#define OPT_MRG_COPY 0
+#define OPT_MRG_MOV 1
+
+#define OPT_CMT_MBR 1
+#define OPT_CMT_MBR_DEL 11
+
+typedef struct /* structure used to store table column information */
+{
+ char ttype[70]; /* column name = FITS TTYPEn keyword; */
+ long tbcol; /* offset in row to first byte of each column */
+ int tdatatype; /* datatype code of each column */
+ OFF_T trepeat; /* repeat count of column; number of elements */
+ double tscale; /* FITS TSCALn linear scaling factor */
+ double tzero; /* FITS TZEROn linear scaling zero point */
+ long tnull; /* FITS null value for int image or binary table cols */
+ char strnull[20]; /* FITS null value string for ASCII table columns */
+ char tform[10]; /* FITS tform keyword value */
+ long twidth; /* width of each ASCII table column */
+}tcolumn;
+
+#define VALIDSTRUC 555 /* magic value used to identify if structure is valid */
+
+typedef struct /* structure used to store basic FITS file information */
+{
+ int filehandle; /* handle returned by the file open function */
+ int driver; /* defines which set of I/O drivers should be used */
+ int open_count; /* number of opened 'fitsfiles' using this structure */
+ char *filename; /* file name */
+ int validcode; /* magic value used to verify that structure is valid */
+ OFF_T filesize; /* current size of the physical disk file in bytes */
+ OFF_T logfilesize; /* logical size of file, including unflushed buffers */
+ int lasthdu; /* is this the last HDU in the file? 0 = no, else yes */
+ OFF_T bytepos; /* current logical I/O pointer position in file */
+ OFF_T io_pos; /* current I/O pointer position in the physical file */
+ int curbuf; /* number of I/O buffer currently in use */
+ int curhdu; /* current HDU number; 0 = primary array */
+ int hdutype; /* 0 = primary array, 1 = ASCII table, 2 = binary table */
+ int writemode; /* 0 = readonly, 1 = readwrite */
+ int maxhdu; /* highest numbered HDU known to exist in the file */
+ int MAXHDU; /* dynamically allocated dimension of headstart array */
+ OFF_T *headstart; /* byte offset in file to start of each HDU */
+ OFF_T headend; /* byte offest in file to end of the current HDU header */
+ OFF_T nextkey; /* byte offset in file to beginning of next keyword */
+ OFF_T datastart;/* byte offset in file to start of the current data unit */
+ int tfield; /* number of fields in the table (primary array has 2 */
+ long origrows; /* original number of rows (value of NAXIS2 keyword) */
+ long numrows; /* number of rows in the table (dynamically updated) */
+ OFF_T rowlength; /* length of a table row or image size (bytes) */
+ tcolumn *tableptr; /* pointer to the table structure */
+ OFF_T heapstart; /* heap start byte relative to start of data unit */
+ long heapsize; /* size of the heap, in bytes */
+
+ /* the following elements are related to compressed images */
+ int request_compress_type; /* requested image compression algorithm */
+ long request_tilesize[MAX_COMPRESS_DIM]; /* requested tiling size */
+ int request_rice_nbits; /* requested noise bit parameter value */
+
+ int compressimg; /* 1 if HDU contains a compressed image, else 0 */
+ char zcmptype[12]; /* compression type string */
+ int compress_type; /* type of compression algorithm */
+ int zbitpix; /* FITS data type of image (BITPIX) */
+ int zndim; /* dimension of image */
+ long znaxis[MAX_COMPRESS_DIM]; /* length of each axis */
+ long tilesize[MAX_COMPRESS_DIM]; /* size of compression tiles */
+ long maxtilelen; /* max number of pixels in each image tile */
+ long maxelem; /* maximum length of variable length arrays */
+
+ int cn_compressed; /* column number for COMPRESSED_DATA column */
+ int cn_uncompressed; /* column number for UNCOMPRESSED_DATA column */
+ int cn_zscale; /* column number for ZSCALE column */
+ int cn_zzero; /* column number for ZZERO column */
+ int cn_zblank; /* column number for the ZBLANK column */
+
+ double zscale; /* scaling value, if same for all tiles */
+ double zzero; /* zero pt, if same for all tiles */
+ double cn_bscale; /* value of the BSCALE keyword in header */
+ double cn_bzero; /* value of the BZERO keyword in header */
+ int zblank; /* value for null pixels, if not a column */
+
+ int rice_blocksize; /* first compression parameter */
+ int rice_nbits; /* second compression parameter */
+} FITSfile;
+
+typedef struct /* structure used to store basic HDU information */
+{
+ int HDUposition; /* HDU position in file; 0 = first HDU */
+ FITSfile *Fptr; /* pointer to FITS file structure */
+}fitsfile;
+
+typedef struct /* structure for the iterator function column information */
+{
+ /* elements required as input to fits_iterate_data: */
+
+ fitsfile *fptr; /* pointer to the HDU containing the column */
+ int colnum; /* column number in the table (use name if < 1) */
+ char colname[70]; /* name (= TTYPEn value) of the column (optional) */
+ int datatype; /* output datatype (converted if necessary */
+ int iotype; /* = InputCol, InputOutputCol, or OutputCol */
+
+ /* output elements that may be useful for the work function: */
+
+ void *array; /* pointer to the array (and the null value) */
+ long repeat; /* binary table vector repeat value */
+ long tlmin; /* legal minimum data value */
+ long tlmax; /* legal maximum data value */
+ char tunit[70]; /* physical unit string */
+ char tdisp[70]; /* suggested display format */
+
+} iteratorCol;
+
+#define InputCol 0 /* flag for input only iterator column */
+#define InputOutputCol 1 /* flag for input and output iterator column */
+#define OutputCol 2 /* flag for output only iterator column */
+
+/* error status codes */
+
+#define CREATE_DISK_FILE -106 /* create disk file, without extended filename syntax */
+#define OPEN_DISK_FILE -105 /* open disk file, without extended filename syntax */
+#define SKIP_TABLE -104 /* move to 1st image when opening file */
+#define SKIP_IMAGE -103 /* move to 1st table when opening file */
+#define SKIP_NULL_PRIMARY -102 /* skip null primary array when opening file */
+#define USE_MEM_BUFF -101 /* use memory buffer when opening file */
+#define OVERFLOW_ERR -11 /* overflow during datatype conversion */
+#define PREPEND_PRIMARY -9 /* used in ffiimg to insert new primary array */
+#define SAME_FILE 101 /* input and output files are the same */
+#define TOO_MANY_FILES 103 /* tried to open too many FITS files */
+#define FILE_NOT_OPENED 104 /* could not open the named file */
+#define FILE_NOT_CREATED 105 /* could not create the named file */
+#define WRITE_ERROR 106 /* error writing to FITS file */
+#define END_OF_FILE 107 /* tried to move past end of file */
+#define READ_ERROR 108 /* error reading from FITS file */
+#define FILE_NOT_CLOSED 110 /* could not close the file */
+#define ARRAY_TOO_BIG 111 /* array dimensions exceed internal limit */
+#define READONLY_FILE 112 /* Cannot write to readonly file */
+#define MEMORY_ALLOCATION 113 /* Could not allocate memory */
+#define BAD_FILEPTR 114 /* invalid fitsfile pointer */
+#define NULL_INPUT_PTR 115 /* NULL input pointer to routine */
+#define SEEK_ERROR 116 /* error seeking position in file */
+
+#define BAD_URL_PREFIX 121 /* invalid URL prefix on file name */
+#define TOO_MANY_DRIVERS 122 /* tried to register too many IO drivers */
+#define DRIVER_INIT_FAILED 123 /* driver initialization failed */
+#define NO_MATCHING_DRIVER 124 /* matching driver is not registered */
+#define URL_PARSE_ERROR 125 /* failed to parse input file URL */
+#define RANGE_PARSE_ERROR 126 /* failed to parse input file URL */
+
+#define SHARED_ERRBASE (150)
+#define SHARED_BADARG (SHARED_ERRBASE + 1)
+#define SHARED_NULPTR (SHARED_ERRBASE + 2)
+#define SHARED_TABFULL (SHARED_ERRBASE + 3)
+#define SHARED_NOTINIT (SHARED_ERRBASE + 4)
+#define SHARED_IPCERR (SHARED_ERRBASE + 5)
+#define SHARED_NOMEM (SHARED_ERRBASE + 6)
+#define SHARED_AGAIN (SHARED_ERRBASE + 7)
+#define SHARED_NOFILE (SHARED_ERRBASE + 8)
+#define SHARED_NORESIZE (SHARED_ERRBASE + 9)
+
+#define HEADER_NOT_EMPTY 201 /* header already contains keywords */
+#define KEY_NO_EXIST 202 /* keyword not found in header */
+#define KEY_OUT_BOUNDS 203 /* keyword record number is out of bounds */
+#define VALUE_UNDEFINED 204 /* keyword value field is blank */
+#define NO_QUOTE 205 /* string is missing the closing quote */
+#define BAD_KEYCHAR 207 /* illegal character in keyword name or card */
+#define BAD_ORDER 208 /* required keywords out of order */
+#define NOT_POS_INT 209 /* keyword value is not a positive integer */
+#define NO_END 210 /* couldn't find END keyword */
+#define BAD_BITPIX 211 /* illegal BITPIX keyword value*/
+#define BAD_NAXIS 212 /* illegal NAXIS keyword value */
+#define BAD_NAXES 213 /* illegal NAXISn keyword value */
+#define BAD_PCOUNT 214 /* illegal PCOUNT keyword value */
+#define BAD_GCOUNT 215 /* illegal GCOUNT keyword value */
+#define BAD_TFIELDS 216 /* illegal TFIELDS keyword value */
+#define NEG_WIDTH 217 /* negative table row size */
+#define NEG_ROWS 218 /* negative number of rows in table */
+#define COL_NOT_FOUND 219 /* column with this name not found in table */
+#define BAD_SIMPLE 220 /* illegal value of SIMPLE keyword */
+#define NO_SIMPLE 221 /* Primary array doesn't start with SIMPLE */
+#define NO_BITPIX 222 /* Second keyword not BITPIX */
+#define NO_NAXIS 223 /* Third keyword not NAXIS */
+#define NO_NAXES 224 /* Couldn't find all the NAXISn keywords */
+#define NO_XTENSION 225 /* HDU doesn't start with XTENSION keyword */
+#define NOT_ATABLE 226 /* the CHDU is not an ASCII table extension */
+#define NOT_BTABLE 227 /* the CHDU is not a binary table extension */
+#define NO_PCOUNT 228 /* couldn't find PCOUNT keyword */
+#define NO_GCOUNT 229 /* couldn't find GCOUNT keyword */
+#define NO_TFIELDS 230 /* couldn't find TFIELDS keyword */
+#define NO_TBCOL 231 /* couldn't find TBCOLn keyword */
+#define NO_TFORM 232 /* couldn't find TFORMn keyword */
+#define NOT_IMAGE 233 /* the CHDU is not an IMAGE extension */
+#define BAD_TBCOL 234 /* TBCOLn keyword value < 0 or > rowlength */
+#define NOT_TABLE 235 /* the CHDU is not a table */
+#define COL_TOO_WIDE 236 /* column is too wide to fit in table */
+#define COL_NOT_UNIQUE 237 /* more than 1 column name matches template */
+#define BAD_ROW_WIDTH 241 /* sum of column widths not = NAXIS1 */
+#define UNKNOWN_EXT 251 /* unrecognizable FITS extension type */
+#define UNKNOWN_REC 252 /* unrecognizable FITS record */
+#define END_JUNK 253 /* END keyword is not blank */
+#define BAD_HEADER_FILL 254 /* Header fill area not blank */
+#define BAD_DATA_FILL 255 /* Data fill area not blank or zero */
+#define BAD_TFORM 261 /* illegal TFORM format code */
+#define BAD_TFORM_DTYPE 262 /* unrecognizable TFORM datatype code */
+#define BAD_TDIM 263 /* illegal TDIMn keyword value */
+#define BAD_HEAP_PTR 264 /* invalid BINTABLE heap address */
+
+#define BAD_HDU_NUM 301 /* HDU number < 1 or > MAXHDU */
+#define BAD_COL_NUM 302 /* column number < 1 or > tfields */
+#define NEG_FILE_POS 304 /* tried to move before beginning of file */
+#define NEG_BYTES 306 /* tried to read or write negative bytes */
+#define BAD_ROW_NUM 307 /* illegal starting row number in table */
+#define BAD_ELEM_NUM 308 /* illegal starting element number in vector */
+#define NOT_ASCII_COL 309 /* this is not an ASCII string column */
+#define NOT_LOGICAL_COL 310 /* this is not a logical datatype column */
+#define BAD_ATABLE_FORMAT 311 /* ASCII table column has wrong format */
+#define BAD_BTABLE_FORMAT 312 /* Binary table column has wrong format */
+#define NO_NULL 314 /* null value has not been defined */
+#define NOT_VARI_LEN 317 /* this is not a variable length column */
+#define BAD_DIMEN 320 /* illegal number of dimensions in array */
+#define BAD_PIX_NUM 321 /* first pixel number greater than last pixel */
+#define ZERO_SCALE 322 /* illegal BSCALE or TSCALn keyword = 0 */
+#define NEG_AXIS 323 /* illegal axis length < 1 */
+
+#define NOT_GROUP_TABLE 340
+#define HDU_ALREADY_MEMBER 341
+#define MEMBER_NOT_FOUND 342
+#define GROUP_NOT_FOUND 343
+#define BAD_GROUP_ID 344
+#define TOO_MANY_HDUS_TRACKED 345
+#define HDU_ALREADY_TRACKED 346
+#define BAD_OPTION 347
+#define IDENTICAL_POINTERS 348
+#define BAD_GROUP_ATTACH 349
+#define BAD_GROUP_DETACH 350
+
+#define BAD_I2C 401 /* bad int to formatted string conversion */
+#define BAD_F2C 402 /* bad float to formatted string conversion */
+#define BAD_INTKEY 403 /* can't interprete keyword value as integer */
+#define BAD_LOGICALKEY 404 /* can't interprete keyword value as logical */
+#define BAD_FLOATKEY 405 /* can't interprete keyword value as float */
+#define BAD_DOUBLEKEY 406 /* can't interprete keyword value as double */
+#define BAD_C2I 407 /* bad formatted string to int conversion */
+#define BAD_C2F 408 /* bad formatted string to float conversion */
+#define BAD_C2D 409 /* bad formatted string to double conversion */
+#define BAD_DATATYPE 410 /* bad keyword datatype code */
+#define BAD_DECIM 411 /* bad number of decimal places specified */
+#define NUM_OVERFLOW 412 /* overflow during datatype conversion */
+
+# define DATA_COMPRESSION_ERR 413 /* error in imcompress routines */
+# define DATA_DECOMPRESSION_ERR 414 /* error in imcompress routines */
+# define NO_COMPRESSED_TILE 415 /* compressed tile doesn't exist */
+
+#define BAD_DATE 420 /* error in date or time conversion */
+
+#define PARSE_SYNTAX_ERR 431 /* syntax error in parser expression */
+#define PARSE_BAD_TYPE 432 /* expression did not evaluate to desired type */
+#define PARSE_LRG_VECTOR 433 /* vector result too large to return in array */
+#define PARSE_NO_OUTPUT 434 /* data parser failed not sent an out column */
+#define PARSE_BAD_COL 435 /* bad data encounter while parsing column */
+#define PARSE_BAD_OUTPUT 436 /* Output file not of proper type */
+
+#define ANGLE_TOO_BIG 501 /* celestial angle too large for projection */
+#define BAD_WCS_VAL 502 /* bad celestial coordinate or pixel value */
+#define WCS_ERROR 503 /* error in celestial coordinate calculation */
+#define BAD_WCS_PROJ 504 /* unsupported type of celestial projection */
+#define NO_WCS_KEY 505 /* celestial coordinate keywords not found */
+#define APPROX_WCS_KEY 506 /* approximate WCS keywords were calculated */
+
+#define NO_CLOSE_ERROR 999 /* special value used internally to switch off */
+ /* the error message from ffclos and ffchdu */
+
+/*------- following error codes are used in the grparser.c file -----------*/
+#define NGP_ERRBASE (360) /* base chosen so not to interfere with CFITSIO */
+#define NGP_OK (0)
+#define NGP_NO_MEMORY (NGP_ERRBASE + 0) /* malloc failed */
+#define NGP_READ_ERR (NGP_ERRBASE + 1) /* read error from file */
+#define NGP_NUL_PTR (NGP_ERRBASE + 2) /* null pointer passed as argument */
+#define NGP_EMPTY_CURLINE (NGP_ERRBASE + 3) /* line read seems to be empty */
+#define NGP_UNREAD_QUEUE_FULL (NGP_ERRBASE + 4) /* cannot unread more then 1 line (or single line twice) */
+#define NGP_INC_NESTING (NGP_ERRBASE + 5) /* too deep include file nesting (inf. loop ?) */
+#define NGP_ERR_FOPEN (NGP_ERRBASE + 6) /* fopen() failed, cannot open file */
+#define NGP_EOF (NGP_ERRBASE + 7) /* end of file encountered */
+#define NGP_BAD_ARG (NGP_ERRBASE + 8) /* bad arguments passed */
+#define NGP_TOKEN_NOT_EXPECT (NGP_ERRBASE + 9) /* token not expected here */
+
+/* The following exclusion if __CINT__ is defined is needed for ROOT */
+#ifndef __CINT__
+/* the following 3 lines are needed to support C++ compilers */
+#ifdef __cplusplus
+extern "C" {
+#endif
+#endif
+
+int CFITS2Unit( fitsfile *fptr );
+fitsfile* CUnit2FITS(int unit);
+
+/*---------------- FITS file URL parsing routines -------------*/
+int fits_get_token(char **ptr, char *delimiter, char *token, int *isanumber);
+char *fits_split_names(char *list);
+int ffiurl(char *url, char *urltype, char *infile,
+ char *outfile, char *extspec, char *rowfilter,
+ char *binspec, char *colspec, int *status);
+int ffrtnm(char *url, char *rootname, int *status);
+int ffexist(const char *infile, int *exists, int *status);
+int ffexts(char *extspec, int *extnum, char *extname, int *extvers,
+ int *hdutype, char *colname, char *rowexpress, int *status);
+int ffextn(char *url, int *extension_num, int *status);
+int ffurlt(fitsfile *fptr, char *urlType, int *status);
+int ffbins(char *binspec, int *imagetype, int *haxis,
+ char colname[4][FLEN_VALUE], double *minin,
+ double *maxin, double *binsizein,
+ char minname[4][FLEN_VALUE], char maxname[4][FLEN_VALUE],
+ char binname[4][FLEN_VALUE], double *weight, char *wtname,
+ int *recip, int *status);
+int ffbinr(char **binspec, char *colname, double *minin,
+ double *maxin, double *binsizein, char *minname,
+ char *maxname, char *binname, int *status);
+int ffimport_file( char *filename, char **contents, int *status );
+int ffrwrg( char *rowlist, long maxrows, int maxranges, int *numranges,
+ long *minrow, long *maxrow, int *status);
+
+/*---------------- FITS file I/O routines -------------*/
+int ffomem(fitsfile **fptr, const char *name, int mode, void **buffptr,
+ size_t *buffsize, size_t deltasize,
+ void *(*mem_realloc)(void *p, size_t newsize),
+ int *status);
+int ffopen(fitsfile **fptr, const char *filename, int iomode, int *status);
+int ffdopn(fitsfile **fptr, const char *filename, int iomode, int *status);
+int fftopn(fitsfile **fptr, const char *filename, int iomode, int *status);
+int ffiopn(fitsfile **fptr, const char *filename, int iomode, int *status);
+int ffdkopn(fitsfile **fptr, const char *filename, int iomode, int *status);
+int ffreopen(fitsfile *openfptr, fitsfile **newfptr, int *status);
+int ffinit( fitsfile **fptr, const char *filename, int *status);
+int ffdkinit(fitsfile **fptr, const char *filename, int *status);
+int ffimem(fitsfile **fptr, void **buffptr,
+ size_t *buffsize, size_t deltasize,
+ void *(*mem_realloc)(void *p, size_t newsize),
+ int *status);
+int fftplt(fitsfile **fptr, const char *filename, const char *tempname,
+ int *status);
+int ffflus(fitsfile *fptr, int *status);
+int ffflsh(fitsfile *fptr, int clearbuf, int *status);
+int ffclos(fitsfile *fptr, int *status);
+int ffdelt(fitsfile *fptr, int *status);
+int ffflnm(fitsfile *fptr, char *filename, int *status);
+int ffflmd(fitsfile *fptr, int *filemode, int *status);
+
+/*---------------- utility routines -------------*/
+float ffvers(float *version);
+void ffupch(char *string);
+void ffgerr(int status, char *errtext);
+void ffpmsg(const char *err_message);
+void ffpmrk(void);
+int ffgmsg(char *err_message);
+void ffcmsg(void);
+void ffcmrk(void);
+void ffrprt(FILE *stream, int status);
+void ffcmps(char *templt, char *colname, int casesen, int *match,
+ int *exact);
+int fftkey(char *keyword, int *status);
+int fftrec(char *card, int *status);
+int ffnchk(fitsfile *fptr, int *status);
+int ffkeyn(char *keyroot, int value, char *keyname, int *status);
+int ffnkey(int value, char *keyroot, char *keyname, int *status);
+int ffgkcl(char *card);
+int ffdtyp(char *cval, char *dtype, int *status);
+int ffpsvc(char *card, char *value, char *comm, int *status);
+int ffgknm(char *card, char *name, int *length, int *status);
+int ffgthd(char *tmplt, char *card, int *hdtype, int *status);
+int ffasfm(char *tform, int *datacode, long *width, int *decim, int *status);
+int ffbnfm(char *tform, int *datacode, long *repeat, long *width, int *status);
+int ffgabc(int tfields, char **tform, int space, long *rowlen, long *tbcol,
+ int *status);
+int fits_get_section_range(char **ptr,long *secmin,long *secmax,long *incre,
+ int *status);
+
+/*----------------- write single keywords --------------*/
+int ffpky(fitsfile *fptr, int datatype, char *keyname, void *value,
+ char *comm, int *status);
+int ffprec(fitsfile *fptr, const char *card, int *status);
+int ffpcom(fitsfile *fptr, const char *comm, int *status);
+int ffpunt(fitsfile *fptr, char *keyname, char *unit, int *status);
+int ffphis(fitsfile *fptr, const char *history, int *status);
+int ffpdat(fitsfile *fptr, int *status);
+int ffgstm(char *timestr, int *timeref, int *status);
+int ffgsdt(int *day, int *month, int *year, int *status);
+int ffdt2s(int year, int month, int day, char *datestr, int *status);
+int fftm2s(int year, int month, int day, int hour, int minute, double second,
+ int decimals, char *datestr, int *status);
+int ffs2dt(char *datestr, int *year, int *month, int *day, int *status);
+int ffs2tm(char *datestr, int *year, int *month, int *day, int *hour,
+ int *minute, double *second, int *status);
+int ffpkyu(fitsfile *fptr, char *keyname, char *comm, int *status);
+int ffpkys(fitsfile *fptr, char *keyname, char *value, char *comm,int *status);
+int ffpkls(fitsfile *fptr, char *keyname, char *value, char *comm,int *status);
+int ffplsw(fitsfile *fptr, int *status);
+int ffpkyl(fitsfile *fptr, char *keyname, int value, char *comm, int *status);
+int ffpkyj(fitsfile *fptr, char *keyname, long value, char *comm, int *status);
+int ffpkyf(fitsfile *fptr, char *keyname, float value, int decim, char *comm,
+ int *status);
+int ffpkye(fitsfile *fptr, char *keyname, float value, int decim, char *comm,
+ int *status);
+int ffpkyg(fitsfile *fptr, char *keyname, double value, int decim, char *comm,
+ int *status);
+int ffpkyd(fitsfile *fptr, char *keyname, double value, int decim, char *comm,
+ int *status);
+int ffpkyc(fitsfile *fptr, char *keyname, float *value, int decim, char *comm,
+ int *status);
+int ffpkym(fitsfile *fptr, char *keyname, double *value, int decim, char *comm,
+ int *status);
+int ffpkfc(fitsfile *fptr, char *keyname, float *value, int decim, char *comm,
+ int *status);
+int ffpkfm(fitsfile *fptr, char *keyname, double *value, int decim, char *comm,
+ int *status);
+int ffpkyt(fitsfile *fptr, char *keyname, long intval, double frac, char *comm,
+ int *status);
+int ffptdm( fitsfile *fptr, int colnum, int naxis, long naxes[], int *status);
+
+/*----------------- write array of keywords --------------*/
+int ffpkns(fitsfile *fptr, char *keyroot, int nstart, int nkey, char *value[],
+ char *comm[], int *status);
+int ffpknl(fitsfile *fptr, char *keyroot, int nstart, int nkey, int *value,
+ char *comm[], int *status);
+int ffpknj(fitsfile *fptr, char *keyroot, int nstart, int nkey, long *value,
+ char *comm[], int *status);
+int ffpknf(fitsfile *fptr, char *keyroot, int nstart, int nkey, float *value,
+ int decim, char *comm[], int *status);
+int ffpkne(fitsfile *fptr, char *keyroot, int nstart, int nkey, float *value,
+ int decim, char *comm[], int *status);
+int ffpkng(fitsfile *fptr, char *keyroot, int nstart, int nkey, double *value,
+ int decim, char *comm[], int *status);
+int ffpknd(fitsfile *fptr, char *keyroot, int nstart, int nkey, double *value,
+ int decim, char *comm[], int *status);
+int ffcpky(fitsfile *infptr,fitsfile *outfptr,int incol,int outcol,
+ char *rootname, int *status);
+
+/*----------------- write required header keywords --------------*/
+int ffphps( fitsfile *fptr, int bitpix, int naxis, long naxes[], int *status);
+int ffphpr( fitsfile *fptr, int simple, int bitpix, int naxis, long naxes[],
+ long pcount, long gcount, int extend, int *status);
+int ffphtb(fitsfile *fptr, long naxis1, long naxis2, int tfields, char **ttype,
+ long *tbcol, char **tform, char **tunit, char *extname, int *status);
+int ffphbn(fitsfile *fptr, long naxis2, int tfields, char **ttype,
+ char **tform, char **tunit, char *extname, long pcount, int *status);
+
+/*----------------- write template keywords --------------*/
+int ffpktp(fitsfile *fptr, const char *filename, int *status);
+
+/*------------------ get header information --------------*/
+int ffghsp(fitsfile *fptr, int *nexist, int *nmore, int *status);
+int ffghps(fitsfile *fptr, int *nexist, int *position, int *status);
+
+/*------------------ move position in header -------------*/
+int ffmaky(fitsfile *fptr, int nrec, int *status);
+int ffmrky(fitsfile *fptr, int nrec, int *status);
+
+/*------------------ read single keywords -----------------*/
+int ffgnxk(fitsfile *fptr, char **inclist, int ninc, char **exclist,
+ int nexc, char *card, int *status);
+int ffgrec(fitsfile *fptr, int nrec, char *card, int *status);
+int ffgcrd(fitsfile *fptr, char *keyname, char *card, int *status);
+int ffgunt(fitsfile *fptr, char *keyname, char *unit, int *status);
+int ffgkyn(fitsfile *fptr, int nkey, char *keyname, char *keyval, char *comm,
+ int *status);
+int ffgkey(fitsfile *fptr, char *keyname, char *keyval, char *comm,
+ int *status);
+
+int ffgky( fitsfile *fptr, int datatype, char *keyname, void *value,
+ char *comm, int *status);
+int ffgkys(fitsfile *fptr, char *keyname, char *value, char *comm, int *status);
+int ffgkls(fitsfile *fptr, char *keyname, char **value, char *comm, int *status)
+;
+int ffgkyl(fitsfile *fptr, char *keyname, int *value, char *comm, int *status);
+int ffgkyj(fitsfile *fptr, char *keyname, long *value, char *comm, int *status);
+int ffgkye(fitsfile *fptr, char *keyname, float *value, char *comm,int *status);
+int ffgkyd(fitsfile *fptr, char *keyname, double *value,char *comm,int *status);
+int ffgkyc(fitsfile *fptr, char *keyname, float *value, char *comm,int *status);
+int ffgkym(fitsfile *fptr, char *keyname, double *value,char *comm,int *status);
+int ffgkyt(fitsfile *fptr, char *keyname, long *ivalue, double *dvalue,
+ char *comm, int *status);
+int ffgtdm(fitsfile *fptr, int colnum, int maxdim, int *naxis, long naxes[],
+ int *status);
+int ffdtdm(fitsfile *fptr, char *tdimstr, int colnum, int maxdim,
+ int *naxis, long naxes[], int *status);
+
+/*------------------ read array of keywords -----------------*/
+int ffgkns(fitsfile *fptr, char *keyname, int nstart, int nmax, char *value[],
+ int *nfound, int *status);
+int ffgknl(fitsfile *fptr, char *keyname, int nstart, int nmax, int *value,
+ int *nfound, int *status);
+int ffgknj(fitsfile *fptr, char *keyname, int nstart, int nmax, long *value,
+ int *nfound, int *status);
+int ffgkne(fitsfile *fptr, char *keyname, int nstart, int nmax, float *value,
+ int *nfound, int *status);
+int ffgknd(fitsfile *fptr, char *keyname, int nstart, int nmax, double *value,
+ int *nfound, int *status);
+int ffh2st(fitsfile *fptr, char **header, int *status);
+int ffhdr2str( fitsfile *fptr, int exclude_comm, char **exclist,
+ int nexc, char **header, int *nkeys, int *status);
+
+/*----------------- read required header keywords --------------*/
+int ffghpr(fitsfile *fptr, int maxdim, int *simple, int *bitpix, int *naxis,
+ long naxes[], long *pcount, long *gcount, int *extend, int *status);
+
+int ffghtb(fitsfile *fptr,int maxfield, long *naxis1, long *naxis2,
+ int *tfields, char **ttype, long *tbcol, char **tform, char **tunit,
+ char *extname, int *status);
+
+int ffghbn(fitsfile *fptr, int maxfield, long *naxis2, int *tfields,
+ char **ttype, char **tform, char **tunit, char *extname,
+ long *pcount, int *status);
+
+/*--------------------- update keywords ---------------*/
+int ffuky(fitsfile *fptr, int datatype, char *keyname, void *value,
+ char *comm, int *status);
+int ffucrd(fitsfile *fptr, char *keyname, char *card, int *status);
+int ffukyu(fitsfile *fptr, char *keyname, char *comm, int *status);
+int ffukys(fitsfile *fptr, char *keyname, char *value, char *comm, int *status);
+int ffukls(fitsfile *fptr, char *keyname, char *value, char *comm, int *status);
+int ffukyl(fitsfile *fptr, char *keyname, int value, char *comm, int *status);
+int ffukyj(fitsfile *fptr, char *keyname, long value, char *comm, int *status);
+int ffukyf(fitsfile *fptr, char *keyname, float value, int decim, char *comm,
+ int *status);
+int ffukye(fitsfile *fptr, char *keyname, float value, int decim, char *comm,
+ int *status);
+int ffukyg(fitsfile *fptr, char *keyname, double value, int decim, char *comm,
+ int *status);
+int ffukyd(fitsfile *fptr, char *keyname, double value, int decim, char *comm,
+ int *status);
+int ffukyc(fitsfile *fptr, char *keyname, float *value, int decim, char *comm,
+ int *status);
+int ffukym(fitsfile *fptr, char *keyname, double *value, int decim, char *comm,
+ int *status);
+int ffukfc(fitsfile *fptr, char *keyname, float *value, int decim, char *comm,
+ int *status);
+int ffukfm(fitsfile *fptr, char *keyname, double *value, int decim, char *comm,
+ int *status);
+
+/*--------------------- modify keywords ---------------*/
+int ffmrec(fitsfile *fptr, int nkey, char *card, int *status);
+int ffmcrd(fitsfile *fptr, char *keyname, char *card, int *status);
+int ffmnam(fitsfile *fptr, char *oldname, char *newname, int *status);
+int ffmcom(fitsfile *fptr, char *keyname, char *comm, int *status);
+int ffmkyu(fitsfile *fptr, char *keyname, char *comm, int *status);
+int ffmkys(fitsfile *fptr, char *keyname, char *value, char *comm,int *status);
+int ffmkls(fitsfile *fptr, char *keyname, char *value, char *comm,int *status);
+int ffmkyl(fitsfile *fptr, char *keyname, int value, char *comm, int *status);
+int ffmkyj(fitsfile *fptr, char *keyname, long value, char *comm, int *status);
+int ffmkyf(fitsfile *fptr, char *keyname, float value, int decim, char *comm,
+ int *status);
+int ffmkye(fitsfile *fptr, char *keyname, float value, int decim, char *comm,
+ int *status);
+int ffmkyg(fitsfile *fptr, char *keyname, double value, int decim, char *comm,
+ int *status);
+int ffmkyd(fitsfile *fptr, char *keyname, double value, int decim, char *comm,
+ int *status);
+int ffmkyc(fitsfile *fptr, char *keyname, float *value, int decim, char *comm,
+ int *status);
+int ffmkym(fitsfile *fptr, char *keyname, double *value, int decim, char *comm,
+ int *status);
+int ffmkfc(fitsfile *fptr, char *keyname, float *value, int decim, char *comm,
+ int *status);
+int ffmkfm(fitsfile *fptr, char *keyname, double *value, int decim, char *comm,
+ int *status);
+
+/*--------------------- insert keywords ---------------*/
+int ffirec(fitsfile *fptr, int nkey, char *card, int *status);
+int ffikey(fitsfile *fptr, char *card, int *status);
+int ffikyu(fitsfile *fptr, char *keyname, char *comm, int *status);
+int ffikys(fitsfile *fptr, char *keyname, char *value, char *comm,int *status);
+int ffikls(fitsfile *fptr, char *keyname, char *value, char *comm,int *status);
+int ffikyl(fitsfile *fptr, char *keyname, int value, char *comm, int *status);
+int ffikyj(fitsfile *fptr, char *keyname, long value, char *comm, int *status);
+int ffikyf(fitsfile *fptr, char *keyname, float value, int decim, char *comm,
+ int *status);
+int ffikye(fitsfile *fptr, char *keyname, float value, int decim, char *comm,
+ int *status);
+int ffikyg(fitsfile *fptr, char *keyname, double value, int decim, char *comm,
+ int *status);
+int ffikyd(fitsfile *fptr, char *keyname, double value, int decim, char *comm,
+ int *status);
+int ffikyc(fitsfile *fptr, char *keyname, float *value, int decim, char *comm,
+ int *status);
+int ffikym(fitsfile *fptr, char *keyname, double *value, int decim, char *comm,
+ int *status);
+int ffikfc(fitsfile *fptr, char *keyname, float *value, int decim, char *comm,
+ int *status);
+int ffikfm(fitsfile *fptr, char *keyname, double *value, int decim, char *comm,
+ int *status);
+
+/*--------------------- delete keywords ---------------*/
+int ffdkey(fitsfile *fptr, char *keyname, int *status);
+int ffdrec(fitsfile *fptr, int keypos, int *status);
+
+/*--------------------- get HDU information -------------*/
+int ffghdn(fitsfile *fptr, int *chdunum);
+int ffghdt(fitsfile *fptr, int *exttype, int *status);
+int ffghad(fitsfile *fptr, long *headstart, long *datastart, long *dataend,
+ int *status);
+int ffghof(fitsfile *fptr, OFF_T *headstart, OFF_T *datastart, OFF_T *dataend,
+ int *status);
+int ffgipr(fitsfile *fptr, int maxaxis, int *imgtype, int *naxis,
+ long *naxes, int *status);
+int ffgidt(fitsfile *fptr, int *imgtype, int *status);
+int ffgiet(fitsfile *fptr, int *imgtype, int *status);
+int ffgidm(fitsfile *fptr, int *naxis, int *status);
+int ffgisz(fitsfile *fptr, int nlen, long *naxes, int *status);
+
+/*--------------------- HDU operations -------------*/
+int ffmahd(fitsfile *fptr, int hdunum, int *exttype, int *status);
+int ffmrhd(fitsfile *fptr, int hdumov, int *exttype, int *status);
+int ffmnhd(fitsfile *fptr, int exttype, char *hduname, int hduvers,
+ int *status);
+int ffthdu(fitsfile *fptr, int *nhdu, int *status);
+int ffcrhd(fitsfile *fptr, int *status);
+int ffcrim(fitsfile *fptr, int bitpix, int naxis, long *naxes, int *status);
+int ffcrtb(fitsfile *fptr, int tbltype, long naxis2, int tfields, char **ttype,
+ char **tform, char **tunit, char *extname, int *status);
+int ffiimg(fitsfile *fptr, int bitpix, int naxis, long *naxes, int *status);
+int ffitab(fitsfile *fptr, long naxis1, long naxis2, int tfields, char **ttype,
+ long *tbcol, char **tform, char **tunit, char *extname, int *status);
+int ffibin(fitsfile *fptr,long naxis2, int tfields, char **ttype, char **tform,
+ char **tunit, char *extname, long pcount, int *status);
+int ffrsim(fitsfile *fptr, int bitpix, int naxis, long *naxes, int *status);
+int ffdhdu(fitsfile *fptr, int *hdutype, int *status);
+int ffcopy(fitsfile *infptr, fitsfile *outfptr, int morekeys, int *status);
+int ffcpfl(fitsfile *infptr, fitsfile *outfptr, int prev, int cur, int follow,
+ int *status);
+int ffcphd(fitsfile *infptr, fitsfile *outfptr, int *status);
+int ffcpdt(fitsfile *infptr, fitsfile *outfptr, int *status);
+int ffchfl(fitsfile *fptr, int *status);
+int ffcdfl(fitsfile *fptr, int *status);
+
+int ffrdef(fitsfile *fptr, int *status);
+int ffhdef(fitsfile *fptr, int morekeys, int *status);
+int ffpthp(fitsfile *fptr, long theap, int *status);
+
+int ffcsum(fitsfile *fptr, long nrec, unsigned long *sum, int *status);
+void ffesum(unsigned long sum, int complm, char *ascii);
+unsigned long ffdsum(char *ascii, int complm, unsigned long *sum);
+int ffpcks(fitsfile *fptr, int *status);
+int ffupck(fitsfile *fptr, int *status);
+int ffvcks(fitsfile *fptr, int *datastatus, int *hdustatus, int *status);
+int ffgcks(fitsfile *fptr, unsigned long *datasum, unsigned long *hdusum,
+ int *status);
+
+/*--------------------- define scaling or null values -------------*/
+int ffpscl(fitsfile *fptr, double scale, double zero, int *status);
+int ffpnul(fitsfile *fptr, long nulvalue, int *status);
+int fftscl(fitsfile *fptr, int colnum, double scale, double zero, int *status);
+int fftnul(fitsfile *fptr, int colnum, long nulvalue, int *status);
+int ffsnul(fitsfile *fptr, int colnum, char *nulstring, int *status);
+
+/*--------------------- get column information -------------*/
+int ffgcno(fitsfile *fptr, int casesen, char *templt, int *colnum,
+ int *status);
+int ffgcnn(fitsfile *fptr, int casesen, char *templt, char *colname,
+ int *colnum, int *status);
+
+int ffgtcl(fitsfile *fptr, int colnum, int *typecode, long *repeat,
+ long *width, int *status);
+int ffeqty(fitsfile *fptr, int colnum, int *typecode, long *repeat,
+ long *width, int *status);
+int ffgncl(fitsfile *fptr, int *ncols, int *status);
+int ffgnrw(fitsfile *fptr, long *nrows, int *status);
+int ffgacl(fitsfile *fptr, int colnum, char *ttype, long *tbcol,
+ char *tunit, char *tform, double *tscal, double *tzero,
+ char *tnull, char *tdisp, int *status);
+int ffgbcl(fitsfile *fptr, int colnum, char *ttype, char *tunit,
+ char *dtype, long *repeat, double *tscal, double *tzero,
+ long *tnull, char *tdisp, int *status);
+int ffgrsz(fitsfile *fptr, long *nrows, int *status);
+int ffgcdw(fitsfile *fptr, int colnum, int *width, int *status);
+
+/*--------------------- read primary array or image elements -------------*/
+int ffgpxv(fitsfile *fptr, int datatype, long *firstpix, long nelem,
+ void *nulval, void *array, int *anynul, int *status);
+int ffgpxf(fitsfile *fptr, int datatype, long *firstpix, long nelem,
+ void *array, char *nullarray, int *anynul, int *status);
+int ffgsv(fitsfile *fptr, int datatype, long *blc, long *trc, long *inc,
+ void *nulval, void *array, int *anynul, int *status);
+int ffgpv(fitsfile *fptr, int datatype, long firstelem, long nelem,
+ void *nulval, void *array, int *anynul, int *status);
+int ffgpf(fitsfile *fptr, int datatype, long firstelem, long nelem,
+ void *array, char *nullarray, int *anynul, int *status);
+int ffgpvb(fitsfile *fptr, long group, long firstelem, long nelem, unsigned
+ char nulval, unsigned char *array, int *anynul, int *status);
+int ffgpvsb(fitsfile *fptr, long group, long firstelem, long nelem, signed
+ char nulval, signed char *array, int *anynul, int *status);
+int ffgpvui(fitsfile *fptr, long group, long firstelem, long nelem,
+ unsigned short nulval, unsigned short *array, int *anynul,
+ int *status);
+int ffgpvi(fitsfile *fptr, long group, long firstelem, long nelem,
+ short nulval, short *array, int *anynul, int *status);
+int ffgpvuj(fitsfile *fptr, long group, long firstelem, long nelem,
+ unsigned long nulval, unsigned long *array, int *anynul,
+ int *status);
+int ffgpvj(fitsfile *fptr, long group, long firstelem, long nelem,
+ long nulval, long *array, int *anynul, int *status);
+int ffgpvjj(fitsfile *fptr, long group, long firstelem, long nelem,
+ LONGLONG nulval, LONGLONG *array, int *anynul, int *status);
+int ffgpvuk(fitsfile *fptr, long group, long firstelem, long nelem,
+ unsigned int nulval, unsigned int *array, int *anynul, int *status);
+int ffgpvk(fitsfile *fptr, long group, long firstelem, long nelem,
+ int nulval, int *array, int *anynul, int *status);
+int ffgpve(fitsfile *fptr, long group, long firstelem, long nelem,
+ float nulval, float *array, int *anynul, int *status);
+int ffgpvd(fitsfile *fptr, long group, long firstelem, long nelem,
+ double nulval, double *array, int *anynul, int *status);
+
+int ffgpfb(fitsfile *fptr, long group, long firstelem, long nelem,
+ unsigned char *array, char *nularray, int *anynul, int *status);
+int ffgpfsb(fitsfile *fptr, long group, long firstelem, long nelem,
+ signed char *array, char *nularray, int *anynul, int *status);
+int ffgpfui(fitsfile *fptr, long group, long firstelem, long nelem,
+ unsigned short *array, char *nularray, int *anynul, int *status);
+int ffgpfi(fitsfile *fptr, long group, long firstelem, long nelem,
+ short *array, char *nularray, int *anynul, int *status);
+int ffgpfuj(fitsfile *fptr, long group, long firstelem, long nelem,
+ unsigned long *array, char *nularray, int *anynul, int *status);
+int ffgpfj(fitsfile *fptr, long group, long firstelem, long nelem,
+ long *array, char *nularray, int *anynul, int *status);
+int ffgpfjj(fitsfile *fptr, long group, long firstelem, long nelem,
+ LONGLONG *array, char *nularray, int *anynul, int *status);
+int ffgpfuk(fitsfile *fptr, long group, long firstelem, long nelem,
+ unsigned int *array, char *nularray, int *anynul, int *status);
+int ffgpfk(fitsfile *fptr, long group, long firstelem, long nelem,
+ int *array, char *nularray, int *anynul, int *status);
+int ffgpfe(fitsfile *fptr, long group, long firstelem, long nelem,
+ float *array, char *nularray, int *anynul, int *status);
+int ffgpfd(fitsfile *fptr, long group, long firstelem, long nelem,
+ double *array, char *nularray, int *anynul, int *status);
+
+int ffg2db(fitsfile *fptr, long group, unsigned char nulval, long ncols,
+ long naxis1, long naxis2, unsigned char *array,
+ int *anynul, int *status);
+int ffg2dsb(fitsfile *fptr, long group, signed char nulval, long ncols,
+ long naxis1, long naxis2, signed char *array,
+ int *anynul, int *status);
+int ffg2dui(fitsfile *fptr, long group, unsigned short nulval, long ncols,
+ long naxis1, long naxis2, unsigned short *array,
+ int *anynul, int *status);
+int ffg2di(fitsfile *fptr, long group, short nulval, long ncols,
+ long naxis1, long naxis2, short *array,
+ int *anynul, int *status);
+int ffg2duj(fitsfile *fptr, long group, unsigned long nulval, long ncols,
+ long naxis1, long naxis2, unsigned long *array,
+ int *anynul, int *status);
+int ffg2dj(fitsfile *fptr, long group, long nulval, long ncols,
+ long naxis1, long naxis2, long *array,
+ int *anynul, int *status);
+int ffg2djj(fitsfile *fptr, long group, LONGLONG nulval, long ncols,
+ long naxis1, long naxis2, LONGLONG *array,
+ int *anynul, int *status);
+int ffg2duk(fitsfile *fptr, long group, unsigned int nulval, long ncols,
+ long naxis1, long naxis2, unsigned int *array,
+ int *anynul, int *status);
+int ffg2dk(fitsfile *fptr, long group, int nulval, long ncols,
+ long naxis1, long naxis2, int *array,
+ int *anynul, int *status);
+int ffg2de(fitsfile *fptr, long group, float nulval, long ncols,
+ long naxis1, long naxis2, float *array,
+ int *anynul, int *status);
+int ffg2dd(fitsfile *fptr, long group, double nulval, long ncols,
+ long naxis1, long naxis2, double *array,
+ int *anynul, int *status);
+
+int ffg3db(fitsfile *fptr, long group, unsigned char nulval, long ncols,
+ long nrows, long naxis1, long naxis2, long naxis3,
+ unsigned char *array, int *anynul, int *status);
+int ffg3dsb(fitsfile *fptr, long group, signed char nulval, long ncols,
+ long nrows, long naxis1, long naxis2, long naxis3,
+ signed char *array, int *anynul, int *status);
+int ffg3dui(fitsfile *fptr, long group, unsigned short nulval, long ncols,
+ long nrows, long naxis1, long naxis2, long naxis3,
+ unsigned short *array, int *anynul, int *status);
+int ffg3di(fitsfile *fptr, long group, short nulval, long ncols,
+ long nrows, long naxis1, long naxis2, long naxis3,
+ short *array, int *anynul, int *status);
+int ffg3duj(fitsfile *fptr, long group, unsigned long nulval, long ncols,
+ long nrows, long naxis1, long naxis2, long naxis3,
+ unsigned long *array, int *anynul, int *status);
+int ffg3dj(fitsfile *fptr, long group, long nulval, long ncols,
+ long nrows, long naxis1, long naxis2, long naxis3,
+ long *array, int *anynul, int *status);
+int ffg3djj(fitsfile *fptr, long group, LONGLONG nulval, long ncols,
+ long nrows, long naxis1, long naxis2, long naxis3,
+ LONGLONG *array, int *anynul, int *status);
+int ffg3duk(fitsfile *fptr, long group, unsigned int nulval, long ncols,
+ long nrows, long naxis1, long naxis2, long naxis3,
+ unsigned int *array, int *anynul, int *status);
+int ffg3dk(fitsfile *fptr, long group, int nulval, long ncols,
+ long nrows, long naxis1, long naxis2, long naxis3,
+ int *array, int *anynul, int *status);
+int ffg3de(fitsfile *fptr, long group, float nulval, long ncols,
+ long nrows, long naxis1, long naxis2, long naxis3,
+ float *array, int *anynul, int *status);
+int ffg3dd(fitsfile *fptr, long group, double nulval, long ncols,
+ long nrows, long naxis1, long naxis2, long naxis3,
+ double *array, int *anynul, int *status);
+
+int ffgsvb(fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc,
+ long *trc, long *inc, unsigned char nulval, unsigned char *array,
+ int *anynul, int *status);
+int ffgsvsb(fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc,
+ long *trc, long *inc, signed char nulval, signed char *array,
+ int *anynul, int *status);
+int ffgsvui(fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc,
+ long *trc, long *inc, unsigned short nulval, unsigned short *array,
+ int *anynul, int *status);
+int ffgsvi(fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc,
+ long *trc, long *inc, short nulval, short *array, int *anynul, int *status);
+int ffgsvuj(fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc,
+ long *trc, long *inc, unsigned long nulval, unsigned long *array,
+ int *anynul, int *status);
+int ffgsvj(fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc,
+ long *trc, long *inc, long nulval, long *array, int *anynul, int *status);
+int ffgsvjj(fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc,
+ long *trc, long *inc, LONGLONG nulval, LONGLONG *array, int *anynul,
+ int *status);
+int ffgsvuk(fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc,
+ long *trc, long *inc, unsigned int nulval, unsigned int *array,
+ int *anynul, int *status);
+int ffgsvk(fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc,
+ long *trc, long *inc, int nulval, int *array, int *anynul, int *status);
+int ffgsve(fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc,
+ long *trc, long *inc, float nulval, float *array, int *anynul, int *status);
+int ffgsvd(fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc,
+ long *trc, long *inc, double nulval, double *array, int *anynul,
+ int *status);
+
+int ffgsfb(fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc,
+ long *trc, long *inc, unsigned char *array, char *flagval,
+ int *anynul, int *status);
+int ffgsfsb(fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc,
+ long *trc, long *inc, signed char *array, char *flagval,
+ int *anynul, int *status);
+int ffgsfui(fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc,
+ long *trc, long *inc, unsigned short *array, char *flagval, int *anynul,
+ int *status);
+int ffgsfi(fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc,
+ long *trc, long *inc, short *array, char *flagval, int *anynul, int *status);
+int ffgsfuj(fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc,
+ long *trc, long *inc, unsigned long *array, char *flagval, int *anynul,
+ int *status);
+int ffgsfj(fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc,
+ long *trc, long *inc, long *array, char *flagval, int *anynul, int *status);
+int ffgsfjj(fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc,
+ long *trc, long *inc, LONGLONG *array, char *flagval, int *anynul,
+ int *status);
+int ffgsfuk(fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc,
+ long *trc, long *inc, unsigned int *array, char *flagval, int *anynul,
+ int *status);
+int ffgsfk(fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc,
+ long *trc, long *inc, int *array, char *flagval, int *anynul, int *status);
+int ffgsfe(fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc,
+ long *trc, long *inc, float *array, char *flagval, int *anynul, int *status);
+int ffgsfd(fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc,
+ long *trc, long *inc, double *array, char *flagval, int *anynul,
+ int *status);
+
+int ffggpb(fitsfile *fptr, long group, long firstelem, long nelem,
+ unsigned char *array, int *status);
+int ffggpsb(fitsfile *fptr, long group, long firstelem, long nelem,
+ signed char *array, int *status);
+int ffggpui(fitsfile *fptr, long group, long firstelem, long nelem,
+ unsigned short *array, int *status);
+int ffggpi(fitsfile *fptr, long group, long firstelem, long nelem,
+ short *array, int *status);
+int ffggpuj(fitsfile *fptr, long group, long firstelem, long nelem,
+ unsigned long *array, int *status);
+int ffggpj(fitsfile *fptr, long group, long firstelem, long nelem,
+ long *array, int *status);
+int ffggpjj(fitsfile *fptr, long group, long firstelem, long nelem,
+ LONGLONG *array, int *status);
+int ffggpuk(fitsfile *fptr, long group, long firstelem, long nelem,
+ unsigned int *array, int *status);
+int ffggpk(fitsfile *fptr, long group, long firstelem, long nelem,
+ int *array, int *status);
+int ffggpe(fitsfile *fptr, long group, long firstelem, long nelem,
+ float *array, int *status);
+int ffggpd(fitsfile *fptr, long group, long firstelem, long nelem,
+ double *array, int *status);
+
+/*--------------------- read column elements -------------*/
+int ffgcv( fitsfile *fptr, int datatype, int colnum, long firstrow,
+ long firstelem, long nelem, void *nulval, void *array, int *anynul,
+ int *status);
+int ffgcf( fitsfile *fptr, int datatype, int colnum, long firstrow,
+ long firstelem, long nelem, void *array, char *nullarray,
+ int *anynul, int *status);
+int ffgcvs(fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelem, char *nulval, char **array, int *anynul, int *status);
+int ffgcl (fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelem, char *array, int *status);
+int ffgcvl (fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelem, char nulval, char *array, int *anynul, int *status);
+int ffgcvb(fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelem, unsigned char nulval, unsigned char *array,
+ int *anynul, int *status);
+int ffgcvsb(fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelem, signed char nulval, signed char *array,
+ int *anynul, int *status);
+int ffgcvui(fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelem, unsigned short nulval, unsigned short *array,
+ int *anynul, int *status);
+int ffgcvi(fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelem, short nulval, short *array, int *anynul, int *status);
+int ffgcvuj(fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelem, unsigned long nulval, unsigned long *array, int *anynul,
+ int *status);
+int ffgcvj(fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelem, long nulval, long *array, int *anynul, int *status);
+int ffgcvjj(fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelem, LONGLONG nulval, LONGLONG *array, int *anynul,
+ int *status);
+int ffgcvuk(fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelem, unsigned int nulval, unsigned int *array, int *anynul,
+ int *status);
+int ffgcvk(fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelem, int nulval, int *array, int *anynul, int *status);
+int ffgcve(fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelem, float nulval, float *array, int *anynul, int *status);
+int ffgcvd(fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelem, double nulval, double *array, int *anynul, int *status);
+int ffgcvc(fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelem, float nulval, float *array, int *anynul, int *status);
+int ffgcvm(fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelem, double nulval, double *array, int *anynul, int *status);
+int ffgcx(fitsfile *fptr, int colnum, long firstrow, long firstbit,
+ long nbits, char *larray, int *status);
+int ffgcxui(fitsfile *fptr, int colnum, long firstrow, long nrows,
+ long firstbit, int nbits, unsigned short *array, int *status);
+int ffgcxuk(fitsfile *fptr, int colnum, long firstrow, long nrows,
+ long firstbit, int nbits, unsigned int *array, int *status);
+
+int ffgcfs(fitsfile *fptr, int colnum, long firstrow, long firstelem, long
+ nelem, char **array, char *nularray, int *anynul, int *status);
+int ffgcfl(fitsfile *fptr, int colnum, long firstrow, long firstelem, long
+ nelem, char *array, char *nularray, int *anynul, int *status);
+int ffgcfb(fitsfile *fptr, int colnum, long firstrow, long firstelem, long
+ nelem, unsigned char *array, char *nularray, int *anynul, int *status);
+int ffgcfsb(fitsfile *fptr, int colnum, long firstrow, long firstelem, long
+ nelem, signed char *array, char *nularray, int *anynul, int *status);
+int ffgcfui(fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelem, unsigned short *array, char *nularray, int *anynul,
+ int *status);
+int ffgcfi(fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelem, short *array, char *nularray, int *anynul, int *status);
+int ffgcfuj(fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelem, unsigned long *array, char *nularray, int *anynul,
+ int *status);
+int ffgcfj(fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelem, long *array, char *nularray, int *anynul, int *status);
+int ffgcfjj(fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelem, LONGLONG *array, char *nularray, int *anynul, int *status);
+int ffgcfuk(fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelem, unsigned int *array, char *nularray, int *anynul,
+ int *status);
+int ffgcfk(fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelem, int *array, char *nularray, int *anynul, int *status);
+int ffgcfe(fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelem, float *array, char *nularray, int *anynul, int *status);
+int ffgcfd(fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelem, double *array, char *nularray, int *anynul, int *status);
+int ffgcfc(fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelem, float *array, char *nularray, int *anynul, int *status);
+int ffgcfm(fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelem, double *array, char *nularray, int *anynul, int *status);
+
+int ffgdes(fitsfile *fptr, int colnum, long rownum, long *length,
+ long *heapaddr, int *status);
+
+int ffgdess(fitsfile *fptr, int colnum, long firstrow, long nrows, long *length,
+ long *heapaddr, int *status);
+
+int fftheap(fitsfile *fptr, long *heapsize, long *unused, long *overlap,
+ int *valid, int *status);
+int ffcmph(fitsfile *fptr, int *status);
+
+int ffgtbb(fitsfile *fptr, long firstrow, long firstchar, long nchars,
+ unsigned char *values, int *status);
+
+/*------------ write primary array or image elements -------------*/
+int ffppx(fitsfile *fptr, int datatype, long *firstpix, long nelem,
+ void *array, int *status);
+int ffppxn(fitsfile *fptr, int datatype, long *firstpix, long nelem,
+ void *array, void *nulval, int *status);
+int ffppr(fitsfile *fptr, int datatype, long firstelem, long nelem,
+ void *array, int *status);
+int ffpprb(fitsfile *fptr, long group, long firstelem,
+ long nelem, unsigned char *array, int *status);
+int ffpprsb(fitsfile *fptr, long group, long firstelem,
+ long nelem, signed char *array, int *status);
+int ffpprui(fitsfile *fptr, long group, long firstelem,
+ long nelem, unsigned short *array, int *status);
+int ffppri(fitsfile *fptr, long group, long firstelem,
+ long nelem, short *array, int *status);
+int ffppruj(fitsfile *fptr, long group, long firstelem,
+ long nelem, unsigned long *array, int *status);
+int ffpprj(fitsfile *fptr, long group, long firstelem,
+ long nelem, long *array, int *status);
+int ffppruk(fitsfile *fptr, long group, long firstelem,
+ long nelem, unsigned int *array, int *status);
+int ffpprk(fitsfile *fptr, long group, long firstelem,
+ long nelem, int *array, int *status);
+int ffppre(fitsfile *fptr, long group, long firstelem,
+ long nelem, float *array, int *status);
+int ffpprd(fitsfile *fptr, long group, long firstelem,
+ long nelem, double *array, int *status);
+int ffpprjj(fitsfile *fptr, long group, long firstelem,
+ long nelem, LONGLONG *array, int *status);
+
+int ffppru(fitsfile *fptr, long group, long firstelem, long nelem,
+ int *status);
+int ffpprn(fitsfile *fptr, long firstelem, long nelem, int *status);
+
+int ffppn(fitsfile *fptr, int datatype, long firstelem, long nelem,
+ void *array, void *nulval, int *status);
+int ffppnb(fitsfile *fptr, long group, long firstelem, long nelem,
+ unsigned char *array, unsigned char nulval, int *status);
+int ffppnsb(fitsfile *fptr, long group, long firstelem, long nelem,
+ signed char *array, signed char nulval, int *status);
+int ffppnui(fitsfile *fptr, long group, long firstelem,
+ long nelem, unsigned short *array, unsigned short nulval,
+ int *status);
+int ffppni(fitsfile *fptr, long group, long firstelem,
+ long nelem, short *array, short nulval, int *status);
+int ffppnj(fitsfile *fptr, long group, long firstelem,
+ long nelem, long *array, long nulval, int *status);
+int ffppnuj(fitsfile *fptr, long group, long firstelem, long nelem,
+ unsigned long *array, unsigned long nulval, int *status);
+int ffppnuk(fitsfile *fptr, long group, long firstelem, long nelem,
+ unsigned int *array, unsigned int nulval, int *status);
+int ffppnk(fitsfile *fptr, long group, long firstelem,
+ long nelem, int *array, int nulval, int *status);
+int ffppne(fitsfile *fptr, long group, long firstelem,
+ long nelem, float *array, float nulval, int *status);
+int ffppnd(fitsfile *fptr, long group, long firstelem,
+ long nelem, double *array, double nulval, int *status);
+int ffppnjj(fitsfile *fptr, long group, long firstelem,
+ long nelem, LONGLONG *array, long nulval, int *status);
+
+int ffp2db(fitsfile *fptr, long group, long ncols, long naxis1,
+ long naxis2, unsigned char *array, int *status);
+int ffp2dsb(fitsfile *fptr, long group, long ncols, long naxis1,
+ long naxis2, signed char *array, int *status);
+int ffp2dui(fitsfile *fptr, long group, long ncols, long naxis1,
+ long naxis2, unsigned short *array, int *status);
+int ffp2di(fitsfile *fptr, long group, long ncols, long naxis1,
+ long naxis2, short *array, int *status);
+int ffp2duj(fitsfile *fptr, long group, long ncols, long naxis1,
+ long naxis2, unsigned long *array, int *status);
+int ffp2dj(fitsfile *fptr, long group, long ncols, long naxis1,
+ long naxis2, long *array, int *status);
+int ffp2duk(fitsfile *fptr, long group, long ncols, long naxis1,
+ long naxis2, unsigned int *array, int *status);
+int ffp2dk(fitsfile *fptr, long group, long ncols, long naxis1,
+ long naxis2, int *array, int *status);
+int ffp2de(fitsfile *fptr, long group, long ncols, long naxis1,
+ long naxis2, float *array, int *status);
+int ffp2dd(fitsfile *fptr, long group, long ncols, long naxis1,
+ long naxis2, double *array, int *status);
+int ffp2djj(fitsfile *fptr, long group, long ncols, long naxis1,
+ long naxis2, LONGLONG *array, int *status);
+
+int ffp3db(fitsfile *fptr, long group, long ncols, long nrows, long naxis1,
+ long naxis2, long naxis3, unsigned char *array, int *status);
+int ffp3dsb(fitsfile *fptr, long group, long ncols, long nrows, long naxis1,
+ long naxis2, long naxis3, signed char *array, int *status);
+int ffp3dui(fitsfile *fptr, long group, long ncols, long nrows, long naxis1,
+ long naxis2, long naxis3, unsigned short *array, int *status);
+int ffp3di(fitsfile *fptr, long group, long ncols, long nrows, long naxis1,
+ long naxis2, long naxis3, short *array, int *status);
+int ffp3duj(fitsfile *fptr, long group, long ncols, long nrows, long naxis1,
+ long naxis2, long naxis3, unsigned long *array, int *status);
+int ffp3dj(fitsfile *fptr, long group, long ncols, long nrows, long naxis1,
+ long naxis2, long naxis3, long *array, int *status);
+int ffp3duk(fitsfile *fptr, long group, long ncols, long nrows, long naxis1,
+ long naxis2, long naxis3, unsigned int *array, int *status);
+int ffp3dk(fitsfile *fptr, long group, long ncols, long nrows, long naxis1,
+ long naxis2, long naxis3, int *array, int *status);
+int ffp3de(fitsfile *fptr, long group, long ncols, long nrows, long naxis1,
+ long naxis2, long naxis3, float *array, int *status);
+int ffp3dd(fitsfile *fptr, long group, long ncols, long nrows, long naxis1,
+ long naxis2, long naxis3, double *array, int *status);
+int ffp3djj(fitsfile *fptr, long group, long ncols, long nrows, long naxis1,
+ long naxis2, long naxis3, LONGLONG *array, int *status);
+
+int ffpss(fitsfile *fptr, int datatype,
+ long *fpixel, long *lpixel, void *array, int *status);
+int ffpssb(fitsfile *fptr, long group, long naxis, long *naxes,
+ long *fpixel, long *lpixel, unsigned char *array, int *status);
+int ffpsssb(fitsfile *fptr, long group, long naxis, long *naxes,
+ long *fpixel, long *lpixel, signed char *array, int *status);
+int ffpssui(fitsfile *fptr, long group, long naxis, long *naxes,
+ long *fpixel, long *lpixel, unsigned short *array, int *status);
+int ffpssi(fitsfile *fptr, long group, long naxis, long *naxes,
+ long *fpixel, long *lpixel, short *array, int *status);
+int ffpssuj(fitsfile *fptr, long group, long naxis, long *naxes,
+ long *fpixel, long *lpixel, unsigned long *array, int *status);
+int ffpssj(fitsfile *fptr, long group, long naxis, long *naxes,
+ long *fpixel, long *lpixel, long *array, int *status);
+int ffpssuk(fitsfile *fptr, long group, long naxis, long *naxes,
+ long *fpixel, long *lpixel, unsigned int *array, int *status);
+int ffpssk(fitsfile *fptr, long group, long naxis, long *naxes,
+ long *fpixel, long *lpixel, int *array, int *status);
+int ffpsse(fitsfile *fptr, long group, long naxis, long *naxes,
+ long *fpixel, long *lpixel, float *array, int *status);
+int ffpssd(fitsfile *fptr, long group, long naxis, long *naxes,
+ long *fpixel, long *lpixel, double *array, int *status);
+int ffpssjj(fitsfile *fptr, long group, long naxis, long *naxes,
+ long *fpixel, long *lpixel, LONGLONG *array, int *status);
+
+int ffpgpb(fitsfile *fptr, long group, long firstelem,
+ long nelem, unsigned char *array, int *status);
+int ffpgpsb(fitsfile *fptr, long group, long firstelem,
+ long nelem, signed char *array, int *status);
+int ffpgpui(fitsfile *fptr, long group, long firstelem,
+ long nelem, unsigned short *array, int *status);
+int ffpgpi(fitsfile *fptr, long group, long firstelem,
+ long nelem, short *array, int *status);
+int ffpgpuj(fitsfile *fptr, long group, long firstelem,
+ long nelem, unsigned long *array, int *status);
+int ffpgpj(fitsfile *fptr, long group, long firstelem,
+ long nelem, long *array, int *status);
+int ffpgpuk(fitsfile *fptr, long group, long firstelem,
+ long nelem, unsigned int *array, int *status);
+int ffpgpk(fitsfile *fptr, long group, long firstelem,
+ long nelem, int *array, int *status);
+int ffpgpe(fitsfile *fptr, long group, long firstelem,
+ long nelem, float *array, int *status);
+int ffpgpd(fitsfile *fptr, long group, long firstelem,
+ long nelem, double *array, int *status);
+int ffpgpjj(fitsfile *fptr, long group, long firstelem,
+ long nelem, LONGLONG *array, int *status);
+
+/*--------------------- iterator functions -------------*/
+int fits_iter_set_by_name(iteratorCol *col, fitsfile *fptr, char *colname,
+ int datatype, int iotype);
+int fits_iter_set_by_num(iteratorCol *col, fitsfile *fptr, int colnum,
+ int datatype, int iotype);
+int fits_iter_set_file(iteratorCol *col, fitsfile *fptr);
+int fits_iter_set_colname(iteratorCol *col, char *colname);
+int fits_iter_set_colnum(iteratorCol *col, int colnum);
+int fits_iter_set_datatype(iteratorCol *col, int datatype);
+int fits_iter_set_iotype(iteratorCol *col, int iotype);
+
+fitsfile * fits_iter_get_file(iteratorCol *col);
+char * fits_iter_get_colname(iteratorCol *col);
+int fits_iter_get_colnum(iteratorCol *col);
+int fits_iter_get_datatype(iteratorCol *col);
+int fits_iter_get_iotype(iteratorCol *col);
+void * fits_iter_get_array(iteratorCol *col);
+long fits_iter_get_tlmin(iteratorCol *col);
+long fits_iter_get_tlmax(iteratorCol *col);
+long fits_iter_get_repeat(iteratorCol *col);
+char * fits_iter_get_tunit(iteratorCol *col);
+char * fits_iter_get_tdisp(iteratorCol *col);
+
+int ffiter(int ncols, iteratorCol *data, long offset, long nPerLoop,
+ int (*workFn)( long totaln, long offset, long firstn,
+ long nvalues, int narrays, iteratorCol *data, void *userPointer),
+ void *userPointer, int *status);
+
+/*--------------------- write column elements -------------*/
+int ffpcl(fitsfile *fptr, int datatype, int colnum, long firstrow,
+ long firstelem, long nelem, void *array, int *status);
+int ffpcls(fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelem, char **array, int *status);
+int ffpcll(fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelem, char *array, int *status);
+int ffpclb(fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelem, unsigned char *array, int *status);
+int ffpclsb(fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelem, signed char *array, int *status);
+int ffpclui(fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelem, unsigned short *array, int *status);
+int ffpcli(fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelem, short *array, int *status);
+int ffpcluj(fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelem, unsigned long *array, int *status);
+int ffpclj(fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelem, long *array, int *status);
+int ffpcluk(fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelem, unsigned int *array, int *status);
+int ffpclk(fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelem, int *array, int *status);
+int ffpcle(fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelem, float *array, int *status);
+int ffpcld(fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelem, double *array, int *status);
+int ffpclc(fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelem, float *array, int *status);
+int ffpclm(fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelem, double *array, int *status);
+int ffpclu(fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelem, int *status);
+int ffpclx(fitsfile *fptr, int colnum, long frow, long fbit, long nbit,
+ char *larray, int *status);
+int ffpcljj(fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelem, LONGLONG *array, int *status);
+
+int ffpcn(fitsfile *fptr, int datatype, int colnum, long firstrow,
+ long firstelem, long nelem, void *array, void *nulval, int *status);
+int ffpcns( fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelem, char **array, char *nulvalue, int *status);
+int ffpcnl( fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelem, char *array, char nulvalue, int *status);
+int ffpcnb(fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelem, unsigned char *array, unsigned char nulvalue,
+ int *status);
+int ffpcnsb(fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelem, signed char *array, signed char nulvalue,
+ int *status);
+int ffpcnui(fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelem, unsigned short *array, unsigned short nulvalue,
+ int *status);
+int ffpcni(fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelem, short *array, short nulvalue, int *status);
+int ffpcnuj(fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelem, unsigned long *array, unsigned long nulvalue,
+ int *status);
+int ffpcnj(fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelem, long *array, long nulvalue, int *status);
+int ffpcnuk(fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelem, unsigned int *array, unsigned int nulvalue,
+ int *status);
+int ffpcnk(fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelem, int *array, int nulvalue, int *status);
+int ffpcne(fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelem, float *array, float nulvalue, int *status);
+int ffpcnd(fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelem, double *array, double nulvalue, int *status);
+int ffpcnjj(fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelem, LONGLONG *array, LONGLONG nulvalue, int *status);
+
+int ffpdes(fitsfile *fptr, int colnum, long rownum, long length,
+ long heapaddr, int *status);
+
+int ffptbb(fitsfile *fptr, long firstrow, long firstchar, long nchars,
+ unsigned char *values, int *status);
+
+int ffirow(fitsfile *fptr, long firstrow, long nrows, int *status);
+int ffdrow(fitsfile *fptr, long firstrow, long nrows, int *status);
+int ffdrrg(fitsfile *fptr, char *ranges, int *status);
+int ffdrws(fitsfile *fptr, long *rownum, long nrows, int *status);
+int fficol(fitsfile *fptr, int numcol, char *ttype, char *tform, int *status);
+int fficls(fitsfile *fptr, int firstcol, int ncols, char **ttype,
+ char **tform, int *status);
+int ffmvec(fitsfile *fptr, int colnum, long newveclen, int *status);
+int ffdcol(fitsfile *fptr, int numcol, int *status);
+int ffcpcl(fitsfile *infptr, fitsfile *outfptr, int incol, int outcol,
+ int create_col, int *status);
+
+/*--------------------- WCS Utilities ------------------*/
+int ffgics(fitsfile *fptr, double *xrval, double *yrval, double *xrpix,
+ double *yrpix, double *xinc, double *yinc, double *rot,
+ char *type, int *status);
+int ffgtcs(fitsfile *fptr, int xcol, int ycol, double *xrval,
+ double *yrval, double *xrpix, double *yrpix, double *xinc,
+ double *yinc, double *rot, char *type, int *status);
+int ffwldp(double xpix, double ypix, double xref, double yref,
+ double xrefpix, double yrefpix, double xinc, double yinc,
+ double rot, char *type, double *xpos, double *ypos, int *status);
+int ffxypx(double xpos, double ypos, double xref, double yref,
+ double xrefpix, double yrefpix, double xinc, double yinc,
+ double rot, char *type, double *xpix, double *ypix, int *status);
+
+/* WCS support routines (provide interface to Doug Mink's WCS library */
+int ffgiwcs(fitsfile *fptr, char **header, int *status);
+int ffgtwcs(fitsfile *fptr, int xcol, int ycol, char **header, int *status);
+
+/*--------------------- lexical parsing routines ------------------*/
+int fftexp( fitsfile *fptr, char *expr, int maxdim,
+ int *datatype, long *nelem, int *naxis,
+ long *naxes, int *status );
+
+int fffrow( fitsfile *infptr, char *expr,
+ long firstrow, long nrows,
+ long *n_good_rows, char *row_status, int *status);
+
+int ffffrw( fitsfile *fptr, char *expr, long *rownum, int *status);
+
+int fffrwc( fitsfile *fptr, char *expr, char *timeCol,
+ char *parCol, char *valCol, long ntimes,
+ double *times, char *time_status, int *status );
+
+int ffsrow( fitsfile *infptr, fitsfile *outfptr, char *expr,
+ int *status);
+
+int ffcrow( fitsfile *fptr, int datatype, char *expr,
+ long firstrow, long nelements, void *nulval,
+ void *array, int *anynul, int *status );
+
+int ffcalc_rng( fitsfile *infptr, char *expr, fitsfile *outfptr,
+ char *parName, char *parInfo, int nRngs,
+ long *start, long *end, int *status );
+
+int ffcalc( fitsfile *infptr, char *expr, fitsfile *outfptr,
+ char *parName, char *parInfo, int *status );
+
+ /* ffhist is not really intended as a user-callable routine */
+ /* but it may be useful for some specialized applications */
+
+int ffhist(fitsfile **fptr, char *outfile, int imagetype, int naxis,
+ char colname[4][FLEN_VALUE],
+ double *minin, double *maxin, double *binsizein,
+ char minname[4][FLEN_VALUE], char maxname[4][FLEN_VALUE],
+ char binname[4][FLEN_VALUE],
+ double weightin, char wtcol[FLEN_VALUE],
+ int recip, char *rowselect, int *status);
+
+int fits_select_image_section(fitsfile **fptr, char *outfile,
+ char *imagesection, int *status);
+int fits_select_section( fitsfile *infptr, fitsfile *outfptr,
+ char *imagesection, int *status);
+
+/*--------------------- grouping routines ------------------*/
+
+int ffgtcr(fitsfile *fptr, char *grpname, int grouptype, int *status);
+int ffgtis(fitsfile *fptr, char *grpname, int grouptype, int *status);
+int ffgtch(fitsfile *gfptr, int grouptype, int *status);
+int ffgtrm(fitsfile *gfptr, int rmopt, int *status);
+int ffgtcp(fitsfile *infptr, fitsfile *outfptr, int cpopt, int *status);
+int ffgtmg(fitsfile *infptr, fitsfile *outfptr, int mgopt, int *status);
+int ffgtcm(fitsfile *gfptr, int cmopt, int *status);
+int ffgtvf(fitsfile *gfptr, long *firstfailed, int *status);
+int ffgtop(fitsfile *mfptr,int group,fitsfile **gfptr,int *status);
+int ffgtam(fitsfile *gfptr, fitsfile *mfptr, int hdupos, int *status);
+int ffgtnm(fitsfile *gfptr, long *nmembers, int *status);
+int ffgmng(fitsfile *mfptr, long *nmembers, int *status);
+int ffgmop(fitsfile *gfptr, long member, fitsfile **mfptr, int *status);
+int ffgmcp(fitsfile *gfptr, fitsfile *mfptr, long member, int cpopt,
+ int *status);
+int ffgmtf(fitsfile *infptr, fitsfile *outfptr, long member, int tfopt,
+ int *status);
+int ffgmrm(fitsfile *fptr, long member, int rmopt, int *status);
+
+/*--------------------- group template parser routines ------------------*/
+
+int fits_execute_template(fitsfile *ff, char *ngp_template, int *status);
+
+/*--------------------- image compression routines ------------------*/
+
+int fits_set_compression_type(fitsfile *fptr, int ctype, int *status);
+int fits_set_tile_dim(fitsfile *fptr, int ndim, long *dims, int *status);
+int fits_set_noise_bits(fitsfile *fptr, int noisebits, int *status);
+
+int fits_get_compression_type(fitsfile *fptr, int *ctype, int *status);
+int fits_get_tile_dim(fitsfile *fptr, int ndim, long *dims, int *status);
+int fits_get_noise_bits(fitsfile *fptr, int *noisebits, int *status);
+
+int fits_compress_img(fitsfile *infptr, fitsfile *outfptr, int compress_type,
+ long *tilesize, int parm1, int parm2, int *status);
+int fits_is_compressed_image(fitsfile *fptr, int *status);
+int fits_decompress_img (fitsfile *infptr, fitsfile *outfptr, int *status);
+
+/* The following exclusion if __CINT__ is defined is needed for ROOT */
+#ifndef __CINT__
+#ifdef __cplusplus
+}
+#endif
+#endif
+
+#endif
+
diff --git a/pkg/tbtables/cfitsio/fitsio.ps b/pkg/tbtables/cfitsio/fitsio.ps
new file mode 100644
index 00000000..ec62e304
--- /dev/null
+++ b/pkg/tbtables/cfitsio/fitsio.ps
@@ -0,0 +1,9852 @@
+%!PS-Adobe-2.0
+%%Creator: dvips(k) 5.86 Copyright 1999 Radical Eye Software
+%%Title: fitsio.dvi
+%%Pages: 132
+%%PageOrder: Ascend
+%%BoundingBox: 0 0 612 792
+%%EndComments
+%DVIPSWebPage: (www.radicaleye.com)
+%DVIPSCommandLine: dvips -N0 fitsio
+%DVIPSParameters: dpi=600, compressed
+%DVIPSSource: TeX output 2004.12.03:1404
+%%BeginProcSet: texc.pro
+%!
+/TeXDict 300 dict def TeXDict begin/N{def}def/B{bind def}N/S{exch}N/X{S
+N}B/A{dup}B/TR{translate}N/isls false N/vsize 11 72 mul N/hsize 8.5 72
+mul N/landplus90{false}def/@rigin{isls{[0 landplus90{1 -1}{-1 1}ifelse 0
+0 0]concat}if 72 Resolution div 72 VResolution div neg scale isls{
+landplus90{VResolution 72 div vsize mul 0 exch}{Resolution -72 div hsize
+mul 0}ifelse TR}if Resolution VResolution vsize -72 div 1 add mul TR[
+matrix currentmatrix{A A round sub abs 0.00001 lt{round}if}forall round
+exch round exch]setmatrix}N/@landscape{/isls true N}B/@manualfeed{
+statusdict/manualfeed true put}B/@copies{/#copies X}B/FMat[1 0 0 -1 0 0]
+N/FBB[0 0 0 0]N/nn 0 N/IEn 0 N/ctr 0 N/df-tail{/nn 8 dict N nn begin
+/FontType 3 N/FontMatrix fntrx N/FontBBox FBB N string/base X array
+/BitMaps X/BuildChar{CharBuilder}N/Encoding IEn N end A{/foo setfont}2
+array copy cvx N load 0 nn put/ctr 0 N[}B/sf 0 N/df{/sf 1 N/fntrx FMat N
+df-tail}B/dfs{div/sf X/fntrx[sf 0 0 sf neg 0 0]N df-tail}B/E{pop nn A
+definefont setfont}B/Cw{Cd A length 5 sub get}B/Ch{Cd A length 4 sub get
+}B/Cx{128 Cd A length 3 sub get sub}B/Cy{Cd A length 2 sub get 127 sub}
+B/Cdx{Cd A length 1 sub get}B/Ci{Cd A type/stringtype ne{ctr get/ctr ctr
+1 add N}if}B/id 0 N/rw 0 N/rc 0 N/gp 0 N/cp 0 N/G 0 N/CharBuilder{save 3
+1 roll S A/base get 2 index get S/BitMaps get S get/Cd X pop/ctr 0 N Cdx
+0 Cx Cy Ch sub Cx Cw add Cy setcachedevice Cw Ch true[1 0 0 -1 -.1 Cx
+sub Cy .1 sub]/id Ci N/rw Cw 7 add 8 idiv string N/rc 0 N/gp 0 N/cp 0 N{
+rc 0 ne{rc 1 sub/rc X rw}{G}ifelse}imagemask restore}B/G{{id gp get/gp
+gp 1 add N A 18 mod S 18 idiv pl S get exec}loop}B/adv{cp add/cp X}B
+/chg{rw cp id gp 4 index getinterval putinterval A gp add/gp X adv}B/nd{
+/cp 0 N rw exit}B/lsh{rw cp 2 copy get A 0 eq{pop 1}{A 255 eq{pop 254}{
+A A add 255 and S 1 and or}ifelse}ifelse put 1 adv}B/rsh{rw cp 2 copy
+get A 0 eq{pop 128}{A 255 eq{pop 127}{A 2 idiv S 128 and or}ifelse}
+ifelse put 1 adv}B/clr{rw cp 2 index string putinterval adv}B/set{rw cp
+fillstr 0 4 index getinterval putinterval adv}B/fillstr 18 string 0 1 17
+{2 copy 255 put pop}for N/pl[{adv 1 chg}{adv 1 chg nd}{1 add chg}{1 add
+chg nd}{adv lsh}{adv lsh nd}{adv rsh}{adv rsh nd}{1 add adv}{/rc X nd}{
+1 add set}{1 add clr}{adv 2 chg}{adv 2 chg nd}{pop nd}]A{bind pop}
+forall N/D{/cc X A type/stringtype ne{]}if nn/base get cc ctr put nn
+/BitMaps get S ctr S sf 1 ne{A A length 1 sub A 2 index S get sf div put
+}if put/ctr ctr 1 add N}B/I{cc 1 add D}B/bop{userdict/bop-hook known{
+bop-hook}if/SI save N @rigin 0 0 moveto/V matrix currentmatrix A 1 get A
+mul exch 0 get A mul add .99 lt{/QV}{/RV}ifelse load def pop pop}N/eop{
+SI restore userdict/eop-hook known{eop-hook}if showpage}N/@start{
+userdict/start-hook known{start-hook}if pop/VResolution X/Resolution X
+1000 div/DVImag X/IEn 256 array N 2 string 0 1 255{IEn S A 360 add 36 4
+index cvrs cvn put}for pop 65781.76 div/vsize X 65781.76 div/hsize X}N
+/p{show}N/RMat[1 0 0 -1 0 0]N/BDot 260 string N/Rx 0 N/Ry 0 N/V{}B/RV/v{
+/Ry X/Rx X V}B statusdict begin/product where{pop false[(Display)(NeXT)
+(LaserWriter 16/600)]{A length product length le{A length product exch 0
+exch getinterval eq{pop true exit}if}{pop}ifelse}forall}{false}ifelse
+end{{gsave TR -.1 .1 TR 1 1 scale Rx Ry false RMat{BDot}imagemask
+grestore}}{{gsave TR -.1 .1 TR Rx Ry scale 1 1 false RMat{BDot}
+imagemask grestore}}ifelse B/QV{gsave newpath transform round exch round
+exch itransform moveto Rx 0 rlineto 0 Ry neg rlineto Rx neg 0 rlineto
+fill grestore}B/a{moveto}B/delta 0 N/tail{A/delta X 0 rmoveto}B/M{S p
+delta add tail}B/b{S p tail}B/c{-4 M}B/d{-3 M}B/e{-2 M}B/f{-1 M}B/g{0 M}
+B/h{1 M}B/i{2 M}B/j{3 M}B/k{4 M}B/w{0 rmoveto}B/l{p -4 w}B/m{p -3 w}B/n{
+p -2 w}B/o{p -1 w}B/q{p 1 w}B/r{p 2 w}B/s{p 3 w}B/t{p 4 w}B/x{0 S
+rmoveto}B/y{3 2 roll p a}B/bos{/SS save N}B/eos{SS restore}B end
+
+%%EndProcSet
+TeXDict begin 40258431 52099146 1000 600 600 (fitsio.dvi)
+@start
+%DVIPSBitmapFont: Fa cmmi10 10.95 1
+/Fa 1 63 df<126012F8B4FCEA7FC0EA1FF0EA07FCEA01FF38007FC0EB1FF0EB07FCEB01
+FF9038007FC0EC1FF0EC07FCEC01FF9138007FC0ED1FF0ED07FCED01FF9238007FC0EE1F
+F0EE07FCEE01FF9338007FC0EF1FF0EF07F8EF01FCA2EF07F8EF1FF0EF7FC0933801FF00
+EE07FCEE1FF0EE7FC04B48C7FCED07FCED1FF0ED7FC04A48C8FCEC07FCEC1FF0EC7FC049
+48C9FCEB07FCEB1FF0EB7FC04848CAFCEA07FCEA1FF0EA7FC048CBFC12FC1270363678B1
+47>62 D E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fb cmbx12 12 58
+/Fb 58 122 df<ED0FFF4AB512C0020F14F0027F80903A01FFF803FC499038C000FE010F
+EB00034948497E49485B5C495A4C138001FF6E13005CA3705AEE01F893C8FCA74BB51280
+B9FCA5C69038E00003B3B0007FD9FFC1B6FCA538467EC53E>12 D<B612F8A91D097F9A25
+>45 D<EA07C0EA1FF0EA3FF8EA7FFCEAFFFEA7EA7FFCEA3FF8EA1FF0EA07C00F0F788E1F
+>I<EE01C0EE03E01607A2160F17C0161F1780A2163F17005E167EA216FE5E15015EA215
+035EA215075E150F5EA2151F5E153F93C7FCA25D157E15FE5DA214015D14035DA214075D
+140F5DA2141F5D143F92C8FCA25C147EA214FE5C13015CA213035C13075CA2130F5C131F
+5CA2133F91C9FC5B137EA213FE5B12015BA212035BA212075B120F5BA2121F5B123F90CA
+FCA25A127E12FE5AA25A12782B647ACA38>I<EC03C01407141F147FEB03FF133FB6FCA4
+13C3EA0003B3B3ADB712FCA5264177C038>49 D<ECFFE0010F13FE013F6D7E90B612E000
+0315F82607FC0313FE3A0FE0007FFFD81F806D138048C7000F13C0488001C015E001F07F
+00FF6E13F07F17F881A46C5A6C5A6C5AC9FC17F05DA217E05D17C04B13804B1300A2ED1F
+FC4B5A5E4B5A4B5A4A90C7FC4A5A4A5AEC0FF04A5AEC3F804AC7127814FE495A494814F8
+D907E014F0495A495A49C8FC017C140149140348B7FC4816E05A5A5A5A5AB8FC17C0A42D
+417BC038>I<ECFFF0010713FF011F14C0017F14F049C66C7ED803F8EB3FFED807E06D7E
+81D80FF86D138013FE001F16C07FA66C5A6C4815806C485BC814005D5E4B5A4B5A4B5A4A
+5B020F1380902607FFFEC7FC15F815FF16C090C713F0ED3FFCED0FFEEEFF80816F13C017
+E0A26F13F0A217F8A3EA0FC0EA3FF0487EA2487EA217F0A25D17E06C5A494913C05BD83F
+80491380D81FF0491300D80FFEEBFFFE6CB612F800015D6C6C14C0011F49C7FC010113E0
+2D427BC038>I<163FA25E5E5D5DA25D5D5D5DA25D92B5FCEC01F7EC03E7140715C7EC0F
+87EC1F07143E147E147C14F8EB01F0EB03E0130714C0EB0F80EB1F00133E5BA25B485A48
+5A485A120F5B48C7FC123E5A12FCB91280A5C8000F90C7FCAC027FB61280A531417DC038
+>I<0007150301E0143F01FFEB07FF91B6FC5E5E5E5E5E16804BC7FC5D15E092C8FC01C0
+C9FCAAEC3FF001C1B5FC01C714C001DF14F09039FFE03FFC9138000FFE01FC6D7E01F06D
+13804915C0497F6C4815E0C8FC6F13F0A317F8A4EA0F80EA3FE0487E12FF7FA317F05B5D
+6C4815E05B007EC74813C0123E003F4A1380D81FC0491300D80FF0495AD807FEEBFFFC6C
+B612F0C65D013F1480010F01FCC7FC010113C02D427BC038>I<4AB47E021F13F0027F13
+FC49B6FC01079038807F8090390FFC001FD93FF014C04948137F4948EBFFE048495A5A14
+00485A120FA248486D13C0EE7F80EE1E00003F92C7FCA25B127FA2EC07FC91381FFF8000
+FF017F13E091B512F89039F9F01FFC9039FBC007FE9039FF8003FF17804A6C13C05B6F13
+E0A24915F0A317F85BA4127FA5123FA217F07F121FA2000F4A13E0A26C6C15C06D491380
+6C018014006C6D485A6C9038E01FFC6DB55A011F5C010714C0010191C7FC9038003FF02D
+427BC038>I<121E121F13FC90B712FEA45A17FC17F817F017E017C0A2481680007EC8EA
+3F00007C157E5E00785D15014B5A00F84A5A484A5A5E151FC848C7FC157E5DA24A5A1403
+5D14074A5AA2141F5D143FA2147F5D14FFA25BA35B92C8FCA35BA55BAA6D5A6D5A6D5A2F
+447AC238>I<EC7FF00103B5FC010F14C0013F14F090397F801FFC3A01FC0003FE48486D
+7E497F4848EC7F80163F484815C0A2001F151FA27FA27F7F01FE143F6D158002C0137F02
+F014006C01FC5B6E485A6C9038FF83FCEDE7F86CECFFE06C5D6C92C7FC6D14C06D80010F
+14F882013F8090B7FC48013F14802607FC0F14C0260FF80314E04848C6FC496D13F0003F
+141F48481307496D13F8150000FF157F90C8123F161F160FA21607A36D15F0127F160F6D
+15E06C6C141F6DEC3FC06C6CEC7F80D80FFE903801FF003A07FFC00FFE6C90B55AC615F0
+013F14C0010F91C7FC010013F02D427BC038>I<EC7FF0903807FFFE011F6D7E017F14E0
+9039FFE03FF0489038800FF848496C7E48488048486D7E001F80003F1680A2484815C081
+17E0A212FF17F0A617F8A45D127FA3003F5CA26C7E5D6C6C5B12076C6C133E6CEBC07C6C
+EBFFF8013F5B010F01C013F00101130090C8FCA217E05DA2EA03C0D80FF015C0487E486C
+491380A217004B5A150F5E49495A6C48495A01C0EBFFE0260FF0035B6CB65A6C4AC7FC6C
+14F86C6C13E0D907FEC8FC2D427BC038>I<EA07C0EA1FF0EA3FF8EA7FFCEAFFFEA7EA7F
+FCEA3FF8EA1FF0EA07C0C7FCAEEA07C0EA1FF0EA3FF8EA7FFCEAFFFEA7EA7FFCEA3FF8EA
+1FF0EA07C00F2C78AB1F>I<EE1F80A24C7EA24C7EA34C7EA24B7FA34B7FA24B7FA34B7F
+169F031F80161F82033F80ED3E07037E80157C8203FC804B7E02018115F0820203814B13
+7F0207815D173F020F814B7F021F8292C77EA24A82023E80027E82027FB7FCA291B87EA2
+498302F0C8FCA20103834A157F0107834A153FA249488284011F8491C97E4984133E017E
+82B6020FB612F0A54C457CC455>65 D<B9FC18F018FE727E19E026003FFCC700077F0501
+7F716C7E727E727EA2721380A37213C0A74E1380A24E1300A24E5A4E5A4E5A4D5B05075B
+94B5128091B700FCC7FC18F018FF19E002FCC7000113F8716C7EF01FFE727E7213801AC0
+7213E0A27213F0A31AF8A71AF0A2601AE0604E13C0604E138095B5120005075BBA12F861
+19C04EC7FC18E045447CC350>I<DCFFF01470031F01FF14F04AB6EAE0010207EDF80302
+3FEDFE0791B539E001FF0F4949C7EA3F9F010701F0EC0FFF4901C0804990C87E49488149
+48814948167F4849163F4849161F5A4A160F485B19074890CAFC19035A5BA2007F1801A3
+4994C7FC12FFAE127F7F1AF0A2123FA27F6C18011AE06C7F19036C6D17C06E16077E6C6D
+EE0F806C6DEE1F006D6C5E6D6C167E6D6C6C5D6D6D4A5A6D01F0EC07F0010101FEEC1FE0
+6D903AFFF001FF80023F90B6C7FC020715FC020115F0DA001F1480030001F8C8FC44467A
+C451>I<B9FC18F018FE727E19E026003FFEC7001F13F805017F9438003FFF060F7F727F
+727F727F84737E737EA2737EA2737EA21B80A2851BC0A51BE0AD1BC0A51B8061A21B0061
+62193F624F5A19FF624E5B06075B4E5B063F90C7FC4DB45A050F13F8BA5A19C04EC8FC18
+F095C9FC4B447CC356>I<BA12F8A485D8001F90C71201EF003F180F180318011800A219
+7E193EA3191EA21778A285A405F890C7FCA316011603161F92B5FCA5ED001F1603160116
+00A2F101E01778A2F103C0A494C7FC1907A21A80A2190FA2191FA2193FF17F0061601807
+181F4DB5FCBBFC61A443447DC34A>I<BA1280A419C026003FFEC7121F1701EF007F183F
+181F180F180719E01803A31801A3EE01E0F000F0A419001603A31607160F167F91B6FCA5
+9138FE007F160F16071603A31601A693C9FCAFB712F0A53C447CC346>I<DCFFF0147003
+1F01FF14F04AB6EAE0010207EDF803023FEDFE0791B539E001FF0F4949C7EA3F9F010701
+F0EC0FFF4901C0804990C87E4948814948814948167F4849163F4849161F5A4A160F485B
+19074890CAFC19035A5BA2007F1801A34994C8FC12FFAD057FB612F0127F7FA3003FDC00
+01EBF000A27F7EA26C7FA26C7F807E6C7F6C7F6D7E6D6C5D6D6C7E6D6D5C6D01F05C0101
+01FE143F6D903AFFF001FF9F023F90B6120F0207EDFC030201EDF000DA001F02C0133003
+0001FCC9FC4C467AC458>I<B7D88003B612FEA526003FFEC9EBF800B3A791B9FCA54AC9
+FCB3AAB7D88003B612FEA54F447CC358>I<B712E0A5D8001F90C7FCB3B3B3A4B712E0A5
+23447DC32A>I<B76C0103B512F8A526003FFEC93807E0004F5A4F5A077EC7FC614E5A4E
+5A4E5AF01F804EC8FC187E604D5AEF07F0EF0FC04D5A4DC9FC177E4C5AEE03F04C5A4C5A
+4C7EEE7FF04C7E5D4B7F4B7F4B7FED3F3FDB7E1F7F03FC806E486C7F4B7E4B6C7F038080
+4B6C7F4A7F717E84717F83717F85717F83717F85717F187F727E86727F84727F86727F84
+B76C90B612FCA54E447CC358>75 D<B712F0A526003FFECAFCB3B1F00780A4180F1900A4
+60A360A2187EA218FE170117031707171F177FEE03FFB95AA539447CC343>I<B500FE06
+7FB512806E95B6FCA26F5EA2D8003F50C7FC013D6DEE03DFA2013C6DEE079FA26E6CEE0F
+1FA26E6C161EA26E6C163CA36E6C1678A26E6C16F0A26E6DEC01E0A26E6DEC03C0A36E6D
+EC0780A26F6CEC0F00A26F6C141EA26F6C5CA36F6C5CA26F6C5CA26F6D485AA26F6D485A
+A26F6D485AA3706C48C7FCA293383FF81EA2706C5AA2706C5AA3706C5AA2705BA2705BA2
+705BA2B6057FB6128071C7FCA2173E171C61447CC36A>I<B64BB512FE8181A281D8003F
+6D91C7EA780081013D7F81133C6E7E6E7F6E7F6E7F6E7F82806E7F6E7F6F7E6F7F83816F
+7F6F7F6F7F6F7F6F7F8382707F707F707F707F8482707F707F717E7113807113C019E083
+7113F07113F87113FC7113FE19FF847213F884848484A28484197F193F191FA2190F1907
+B61603190119001A78A24F447CC358>I<923807FFC092B512FE0207ECFFC0021F15F091
+267FFE0013FC902601FFF0EB1FFF01070180010313C04990C76C7FD91FFC6E6C7E49486F
+7E49486F7E01FF8348496F7E48496F1380A248496F13C0A24890C96C13E0A24819F04982
+003F19F8A3007F19FC49177FA400FF19FEAD007F19FC6D17FFA3003F19F8A26D5E6C19F0
+A26E5D6C19E0A26C6D4B13C06C19806E5D6C6D4B13006C6D4B5A6D6C4B5A6D6C4B5A6D6C
+4A5B6D01C001075B6D01F0011F5B010101FE90B5C7FC6D90B65A023F15F8020715C00200
+4AC8FC030713C047467AC454>I<B9FC18F018FE727E19E0D8001F90C7000F7F05017F71
+6C7E727E727E721380A21AC084A21AE0A91AC0A24E1380A21A00604E5A4E5A4D485A050F
+5B92B712C096C7FC18FC18C092CBFCB3A7B712E0A543447DC34D>I<B812F8EFFFC018F8
+18FE727ED8001F90C7003F13E005037F05007F727E727E727EA28684A286A762A24E90C7
+FCA24E5A61187F943801FFF005075B053F138092B7C8FC18F818E018F892C77FEF3FFF05
+0F7F717F717FA2717FA2717FA785A61B0F85A2187F73131F72141EB700E06DEB803E72EB
+E0FC72EBFFF8060114F0726C13E0CC0007138050457DC354>82 D<DAFFE0131C010701FE
+133C013F9038FF807C90B6EAE0FC4815F9489038801FFF3907FC00014848EB007F484814
+3F4848140F491407007F15035B1601160012FF177CA27FA26D153C7F7F6D92C7FC6C7EEB
+FFE014FE6CEBFFF015FF6C15E016FC6C816C6F7E6C826C826C6C81011F81010781130002
+0F80140003077FED007F82040F1380828212F082A282A27EA218007EA26C5D6C5E6D1403
+6D5D6D140701F84A5A01FFEC3FF002F8EBFFE0486CB65AD8FC1F92C7FCD8F80714FC48C6
+14F0480107138031467AC43E>I<003FBA12E0A59026FE000FEB8003D87FE09338003FF0
+49171F90C71607A2007E1803007C1801A300781800A400F819F8481978A5C81700B3B3A2
+0107B8FCA545437CC24E>I<B76C010FB512F8A526003FFEC93803E000B3B3A9011F1707
+6280190F6D606F151F6D95C7FC6D6D5D197E6D6D5D6D6D1403DA7FFC4A5A6EB4EC3FF002
+0F9039F003FFE06E90B61280020193C8FC6E6C14FC030F14E09226007FFEC9FC4D457CC3
+56>I<B792B6FCA526003FFECAEAFC00806D606F15016D608119036D606F15076D606F15
+0F6D6081191F6D6D93C7FC61027F163E6F157E023F167C8119FC6E6D5C18016E5E701303
+6E5E8218076E6D5C180F6E5E70131F6E93C8FC705B037F143E82187E033F147C7013FC6F
+5C17816F5C17C117C36F5C17E76F5C17FF6F5CA36F91C9FCA2705AA2705AA3705AA2705A
+A2705AA250457EC355>I<B600FE017FB691B512FEA526007FFCC8D83FFEC9EA7C006E82
+013F701778807415F86D705F6F7014016D705FA26F7014036D64814E6D14076D646F7014
+0F6D041E94C7FCA26F023E6D5C6DDC3C7F151E81027F037C6D5CF0783F6F70147C023F4B
+6C1578A26F01016F13F86E4B6C5D16806E02036F485A4E7E04C0EEE0036E4A486C5DA2DC
+E00FEDF0076E4B6C5D16F06E4A6F48C8FC051E7F04F8705A6E4A027F131EA2DCFC7CEDFE
+3E037F0178023F133C04FE16FF033F01F85E4D8004FF17F86F496E5BA36F496E5BA26F60
+4D80A26F90C86C5BA36F486F90C9FCA26F48167EA30478163C6F457EC374>I<903801FF
+E0011F13FE017F6D7E48B612E03A03FE007FF84848EB1FFC6D6D7E486C6D7EA26F7FA36F
+7F6C5A6C5AEA00F090C7FCA40203B5FC91B6FC1307013F13F19038FFFC01000313E0000F
+1380381FFE00485A5B127F5B12FF5BA35DA26D5B6C6C5B4B13F0D83FFE013EEBFFC03A1F
+FF80FC7F0007EBFFF86CECE01FC66CEB8007D90FFCC9FC322F7DAD36>97
+D<EB7FC0B5FCA512037EB1ED0FF892B57E02C314E002CF14F89139DFC03FFC9139FF000F
+FE02FCEB03FF4A6D13804A15C04A6D13E05CEF7FF0A218F8173FA318FCAC18F8A2177F18
+F0A3EFFFE06E15C06E5B6E491380027C491300496C495A903AFC1FC07FFC496CB512F0D9
+F00314C049C691C7FCC8EA1FF036467DC43E>I<EC3FFC49B512C0010F14F0013F14FC90
+397FF003FE9039FFC001FF0003495A48494813805B120F485AA2485A6F1300007F6E5AED
+00784991C7FCA212FFAC6C7EA3123F6DEC03C0A26C6C1407000F16806D140F6C6DEB1F00
+6C6D133E6C01F05B3A007FFC03F86DB55A010F14C0010391C7FC9038003FF82A2F7CAD32
+>I<EE03FEED07FFA5ED001F160FB1EC3FE0903803FFFC010FEBFF8F013F14CF9039FFF8
+07FF48EBC00148903880007F4890C7123F4848141F49140F121F485AA3127F5BA212FFAC
+127FA37F123FA26C6C141FA26C6C143F0007157F6C6C91B5FC6CD9C00314FC6C9038F01F
+EF6DB5128F011FEBFE0F010713F89026007FC0EBF80036467CC43E>I<EC3FF80103B57E
+010F14E0013F8090397FF83FF89039FFC007FC48496C7E48496C7E48486D1380485A001F
+ED7FC05B003FED3FE0A2127F5B17F0161F12FFA290B7FCA401F0C9FCA5127FA27FA2123F
+17F06C7E16016C6C15E06C6C14036C6DEB07C06C6DEB0F806C01F0EB3F0090397FFE01FE
+011FB55A010714F0010114C09026001FFEC7FC2C2F7DAD33>I<EDFF80020F13E0027F13
+F049B512F849EB8FFC90390FFE0FFE90381FFC1F14F8133FEB7FF0A2ED0FFCEBFFE0ED03
+F0ED00C01600ABB612F8A5C601E0C7FCB3B0007FEBFFE0A527467DC522>I<DAFFE0137E
+010F9039FE03FF80013FEBFF8F90B812C048D9C07F133F489038001FF84848EB0FFC4848
+903907FE1F80001F9238FF0F00496D90C7FCA2003F82A8001F93C7FCA26D5B000F5D6C6C
+495A6C6C495A6C9038C07FF04890B55A1680D8078F49C8FC018013E0000F90CAFCA47F7F
+7F90B612C016FC6CEDFF8017E06C826C16FC7E000382000F82D81FF0C77ED83FC0140748
+48020113808248C9FC177FA46D15FF007F17006D5C6C6C4A5A6C6C4A5AD80FFEEC3FF83B
+07FFC001FFF0000190B612C06C6C92C7FC010F14F8D9007F90C8FC32427DAC38>I<EB7F
+C0B5FCA512037EB1ED07FE92383FFF8092B512E002C114F89139C7F03FFC9138CF801F91
+39DF000FFE14DE14FC4A6D7E5CA25CA35CB3A7B60083B512FEA537457CC43E>I<137C48
+B4FC4813804813C0A24813E0A56C13C0A26C13806C1300EA007C90C7FCAAEB7FC0EA7FFF
+A512037EB3AFB6FCA518467CC520>I<EB7FC0B5FCA512037EB293387FFFE0A593380FE0
+004C5A4CC7FC167E5EED03F8ED07E04B5A4B5A037FC8FC15FEECC1FCECC3FE14C7ECDFFF
+91B57E82A202F97F02E17F02C07FEC807F6F7E826F7E816F7F836F7F816F7F83707E163F
+B60003B512F8A535457DC43B>107 D<EB7FC0B5FCA512037EB3B3B3A3B61280A519457C
+C420>I<90277F8007FEEC0FFCB590263FFFC090387FFF8092B5D8F001B512E002816E48
+80913D87F01FFC0FE03FF8913D8FC00FFE1F801FFC0003D99F009026FF3E007F6C019E6D
+013C130F02BC5D02F86D496D7EA24A5D4A5DA34A5DB3A7B60081B60003B512FEA5572D7C
+AC5E>I<90397F8007FEB590383FFF8092B512E0028114F8913987F03FFC91388F801F00
+0390399F000FFE6C139E14BC02F86D7E5CA25CA35CB3A7B60083B512FEA5372D7CAC3E>
+I<EC1FFC49B512C0010714F0011F14FC90397FF80FFF9026FFC0017F48496C7F4848C7EA
+3FE000078248486E7E49140F001F82A2003F82491407007F82A400FF1780AA007F1700A4
+6C6C4A5AA2001F5E6D141F000F5E6C6C4A5AA26C6C6CEBFFE06C6D485B27007FF80F90C7
+FC6DB55A010F14F8010114C09026001FFCC8FC312F7DAD38>I<90397FC00FF8B590B57E
+02C314E002CF14F89139DFC03FFC9139FF001FFE000301FCEB07FF6C496D13804A15C04A
+6D13E05C7013F0A2EF7FF8A4EF3FFCACEF7FF8A318F017FFA24C13E06E15C06E5B6E4913
+806E4913006E495A9139DFC07FFC02CFB512F002C314C002C091C7FCED1FF092C9FCADB6
+7EA536407DAC3E>I<90387F807FB53881FFE0028313F0028F13F8ED8FFC91389F1FFE00
+0313BE6C13BC14F8A214F0ED0FFC9138E007F8ED01E092C7FCA35CB3A5B612E0A5272D7D
+AC2E>114 D<90391FFC038090B51287000314FF120F381FF003383FC00049133F48C712
+1F127E00FE140FA215077EA27F01E090C7FC13FE387FFFF014FF6C14C015F06C14FC6C80
+0003806C15806C7E010F14C0EB003F020313E0140000F0143FA26C141F150FA27EA26C15
+C06C141FA26DEB3F8001E0EB7F009038F803FE90B55A00FC5CD8F03F13E026E007FEC7FC
+232F7CAD2C>I<EB01E0A51303A41307A2130FA2131FA2133F137F13FF1203000F90B512
+80B7FCA4C601E0C7FCB3A3ED01E0A9150302F013C0137F150790393FF80F8090391FFC1F
+006DB5FC6D13FC01015B9038003FE023407EBE2C>I<D97FC049B4FCB50103B5FCA50003
+EC000F6C81B3A85EA25EA25E7E6E491380017FD901F713FE9138F807E76DB512C7010F14
+07010313FE9026007FF0EBFC00372E7CAC3E>I<B6903803FFFCA5000101E09038003E00
+6C163C80017F5D8017F8013F5D6E1301011F5D6E1303010F5D6E13076D5DED800F6D92C7
+FC15C05E6DEBE01E163E6D143CEDF07C027F1378EDF8F8023F5B15FD021F5B15FF6E5BA3
+6E5BA26E90C8FCA26E5AA26E5AA21578362C7EAB3B>I<B5D8FE1FB539801FFFF0A50001
+9027C0003FE0C7EA7C007114786E17F86C6F6C5C6E1601017F6E6C5CA26E011F1403013F
+6F5C6E013F1407011F6F5CA26E0179140F010F048090C7FC6E01F95C6D02F0EBC01E1580
+6D902681E07F5B18E003C3157C6D9139C03FF07815E76DDA801F5B18F803FF14F96E9039
+000FFDE018FF6E486D5BA36E486D5BA26E486D90C8FCA24B7F02075DA26E48147C4B143C
+4C2C7EAB51>I<B500FE90383FFFF0A5C601F0903803E0006D6C495A013F4A5A6D6C49C7
+FC6E5B6D6C137E6DEB807C6D6D5A6DEBC1F0EDE3E06DEBF7C06EB45A806E90C8FC5D6E7E
+6E7F6E7FA24A7F4A7F8291381F3FFCEC3E1F027C7F4A6C7E49486C7F01036D7F49487E02
+C08049486C7F49C76C7E013E6E7E017E141FB500E090B512FCA5362C7EAB3B>I<B69038
+03FFFCA5000101E09038003E006C163C80017F5D8017F8013F5D6E1301011F5D6E130301
+0F5D6E13076D5DED800F6D92C7FC15C05E6DEBE01E163E6D143CEDF07C027F1378EDF8F8
+023F5B15FD021F5B15FF6E5BA36E5BA26E90C8FCA26E5AA26E5AA21578A215F85D14015D
+001F1303D83F805B387FC007D8FFE05B140F92C9FC5C143E495A387FC1F8EB07F06CB45A
+6C5B000790CAFCEA01FC36407EAB3B>I E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fc cmsy10 10.95 4
+/Fc 4 107 df<EB0FFCEB3FFF90B512C0000314F04880488048804880A2481580A3B712
+C0AA6C1580A36C1500A26C5C6C5C6C5C6C5CC614C0013F90C7FCEB0FFC22227BA72D>15
+D<153FEC03FFEC0FE0EC3F80EC7E00495A5C495AA2495AB3AA130F5C131F495A91C7FC13
+FEEA03F8EA7FE048C8FCEA7FE0EA03F8EA00FE133F806D7E130F801307B3AA6D7EA26D7E
+80EB007EEC3F80EC0FE0EC03FFEC003F205B7AC32D>102 D<12FCEAFFC0EA07F0EA01FC
+EA007E6D7E131F6D7EA26D7EB3AA801303806D7E1300147FEC1FC0EC07FEEC00FFEC07FE
+EC1FC0EC7F0014FC1301495A5C13075CB3AA495AA2495A133F017EC7FC485AEA07F0EAFF
+C000FCC8FC205B7AC32D>I<126012F0B3B3B3B3B11260045B76C319>106
+D E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fd cmbx12 14.4 63
+/Fd 63 123 df<922601FFFC903801FFE0033F9026FF801F13F84AB6D8E07F13FE020F03
+F9B6FC023FD9C00FB500C0138091277FFC0003D9FE0113C0902601FFE049495A49494949
+4813E04990C714F049484A13E0495A19C0495A7413C0017F17804A6E6E1380719138007E
+007192C7FCAEBCFCA526007FF8C7000301C0C8FCB3B3A7007FB5D8F803B612F0A553547D
+D34E>11 D<EEFFFC031FEBFF804AB612E0020781021F9038C00FF8913A7FFE0003FCDAFF
+F0EB00FE4949EB03FF4901805B4990C7487F49485CA2495A4D7F013F6F5B5CA37190C7FC
+715AEF01F894C9FCA90403B512C0BAFCA526003FFCC7120783B3B3A6003FB5D8FC03B612
+C0A542547DD34B>I<151E153E157E15FCEC01F8EC07F0EC0FE0EC1FC01580143FEC7F00
+14FE1301495A5C1307495AA2495A133F5C137FA2495AA24890C7FCA25A5BA21207A2485A
+A3121F5BA3123FA25BA3127FA55B12FFB3A3127F7FA5123FA37FA2121FA37F120FA36C7E
+A21203A27F7EA26C7FA26D7EA2133F80131F6D7EA26D7E1303806D7E1300147FEC3F8014
+1F15C0EC0FE0EC07F0EC01F8EC00FC157E153E151E1F7973D934>40
+D<127012F8127C127E7EEA1FC06C7E6C7E12037F6C7E6C7E7F6D7E133F806D7EA26D7E80
+130780A26D7EA26D7EA215807FA215C0A2EC7FE0A315F0143FA315F8A2141FA315FCA514
+0F15FEB3A315FC141FA515F8A3143FA215F0A3147F15E0A3ECFFC0A21580A25B1500A249
+5AA2495AA25C130F5C495AA2495A5C137F49C7FC5B485A485A5B1207485A485A48C8FC12
+7E127C5A12701F7979D934>I<B712F0AB240B7F9F2D>45 D<EA07F0487E487E487E487E
+B51280A76C13006C5A6C5A6C5A6C5A1111769025>I<EF01E01703EF07F0A2170FA2EF1F
+E0A218C0173FA2EF7F80A218005FA24C5AA25F1603A24C5AA25F160FA24C5AA25F163FA2
+4C5AA294C7FC5EA24B5AA25E1503A24B5AA25E150FA24B5AA25E153FA24B5AA293C8FC5D
+A24A5AA25D1403A25D1407A24A5AA25D141FA24A5AA25D147FA24AC9FCA25C1301A2495A
+A25C1307A2495AA25C131FA2495AA25C137FA249CAFCA25B1201A2485AA25B1207A2485A
+A25B121FA2485AA25B127FA248CBFCA25AA2127CA2347879D943>I<913803FFC0023F13
+FC91B6FC010315C0010F018113F0903A1FFC003FF849486D7E49486D7E49486D7E48496D
+138048496D13C0A24817E04890C813F0A34817F8A24817FC49157FA3007F17FEA600FF17
+FFB3A5007F17FEA6003F17FCA26D15FFA26C17F8A36C17F0A26C6D4913E0A26C6D4913C0
+6C17806E5B6C6D4913006D6C495AD91FFCEB3FF8903A0FFF81FFF06D90B55A01011580D9
+003F01FCC7FC020313C0384F7BCD43>I<157815FC14031407141F14FF130F0007B5FCB6
+FCA2147F13F0EAF800C7FCB3B3B3A6007FB712FEA52F4E76CD43>I<EC3FFE0103B512E0
+010F14FC013F14FF90B712C048D9C07F7F2703FE000F13F8D807F801037FD80FE06D7F48
+486D7F48488001F01680486C6E13C07F486C6E13E07FA27013F0A56C5AA26C5AEA0FF0EA
+03C0C914E05EA218C05E1880A24C13005F4C5A4B5B5F4B5B5F4B5B4B90C7FC4B5A5E4B5A
+ED7FE04B5A4A5B4A48C8FC4A5A5D4A48EB01F04A5AEC3F804AC7FC02FEEC03E0495A495A
+495A495AD91F80140749C8FC013E150F017FB7FC90B812C05A5A5A5A5A5A5AB9FC1880A4
+344E79CD43>I<91380FFFC091B512FC0107ECFF80011F15E090263FF8077F9026FF8001
+13FC4848C76C7ED803F86E7E491680D807FC8048B416C080486D15E0A4805CA36C17C06C
+5B6C90C75AD801FC1680C9FC4C13005FA24C5A4B5B4B5B4B13C04B5BDBFFFEC7FC91B512
+F816E016FCEEFF80DA000713E0030113F89238007FFE707E7013807013C018E07013F0A2
+18F8A27013FCA218FEA2EA03E0EA0FF8487E487E487EB57EA318FCA25E18F891C7FC6C17
+F0495C6C4816E001F04A13C06C484A1380D80FF84A13006CB44A5A6CD9F0075BC690B612
+F06D5D011F1580010302FCC7FCD9001F1380374F7ACD43>I<177C17FEA2160116031607
+160FA2161F163F167FA216FF5D5DA25D5DED1FBFED3F3F153E157C15FCEC01F815F0EC03
+E01407EC0FC01580EC1F005C147E147C5C1301495A495A5C495A131F49C7FC133E5B13FC
+485A5B485A1207485A485A90C8FC123E127E5ABA12C0A5C96C48C7FCAF020FB712C0A53A
+4F7CCE43>I<D80380150ED807E0157E01FEEC03FED9FFF0137F91B65A5F5F5F5F5F94C7
+FC5E5E16F016C093C8FC15F801E190C9FC01E0CAFCABEC0FFF027F13F001E3B512FE01E7
+6E7E9026FFF8077FDAC0017F49C713F8496E7E49143F4981496E7E6C481680C9FC18C082
+18E0A418F0A3EA0FE0487E487E487E487EA418E0A35B6C484A13C05B491680003EC85A00
+3F17006C6C4A5A6D5D6C6C4A5AD807F8495BD803FE01075B2701FFC03F5B6C90B65A013F
+4AC7FC6D14F8010314C09026007FF8C8FC344F79CD43>I<ED0FFF92B512E0020780021F
+14FC91397FFE03FE903A01FFF0007F4901C0EB3F804990C7121F4948EC7FC0494814FF49
+484913E049485B01FF5C485BA2485B5AA2486F13C04A6D1380486F1300177E94C7FC5AA2
+91CAFC5AA21508913801FFF8020713FFB54814C04A14F04AC66C7E023C6D7E4A6D7E4A6D
+7E7013804A15C0A24A15E07013F05C18F8A491C714FCA37EA67EA46C17F880A27E18F06C
+5D18E06C6D15C07E6E4913806C6D15006D6C495A6D6CEB7FFC6DB448485A6D90B55A0103
+15C0010092C7FC023F13FC020713C0364F7ACD43>I<121F7F7FEBFF8091B81280A45A19
+00606060A2606060485F0180C86CC7FC007EC95A4C5A007C4B5A5F4C5A160F4C5A484B5A
+4C5A94C8FC16FEC812014B5A5E4B5A150F4B5AA24B5AA24B5A15FFA24A90C9FCA25C5D14
+07A2140FA25D141FA2143FA4147F5DA314FFA55BAC6D5BA2EC3FC06E5A395279D043>I<
+913807FFC0027F13FC0103B67E010F15E090261FFC0113F8903A3FE0003FFCD97F80EB0F
+FE49C76C7E48488048486E1380000717C04980120F18E0177FA2121F7FA27F7F6E14FF02
+E015C014F802FE4913806C7FDBC00313009238F007FE6C02F85B9238FE1FF86C9138FFBF
+F06CEDFFE017806C4BC7FC6D806D81010F15E06D81010115FC010781011F81491680EBFF
+E748018115C048D9007F14E04848011F14F048487F48481303030014F8484880161F4848
+020713FC1601824848157F173FA2171FA2170FA218F8A27F007F17F06D151FA26C6CED3F
+E0001F17C06D157F6C6CEDFF806C6C6C010313006C01E0EB0FFE6C01FCEBFFFC6C6CB612
+F06D5D010F1580010102FCC7FCD9000F13C0364F7ACD43>I<91380FFF8091B512F80103
+14FE010F6E7E4901037F90267FF8007F4948EB3FF048496D7E484980486F7E4849808248
+17805A91C714C05A7013E0A218F0B5FCA318F8A618FCA46C5DA37EA25E6C7F6C5DA26C5D
+6C7F6C6D137B6C6D13F390387FF803011FB512E36D14C30103028313F89039007FFE03EC
+00401500A218F05EA3D801F816E0487E486C16C0487E486D491380A218005E5F4C5A91C7
+FC6C484A5A494A5A49495B6C48495BD803FC010F5B9027FF807FFEC7FC6C90B55A6C6C14
+F06D14C0010F49C8FC010013F0364F7ACD43>I<EA07F0487E487E487E487EB51280A76C
+13006C5A6C5A6C5A6C5AC8FCB3EA07F0487E487E487E487EB51280A76C13006C5A6C5A6C
+5A6C5A113576B425>I<171F4D7E4D7EA24D7EA34C7FA24C7FA34C7FA34C7FA24C7FA34C
+8083047F80167E8304FE804C7E03018116F8830303814C7E03078116E083030F814C7E03
+1F81168083033F8293C77E4B82157E8403FE824B800201835D840203834B800207835D84
+4AB87EA24A83A3DA3F80C88092C97E4A84A2027E8202FE844A82010185A24A820103854A
+82010785A24A82010F855C011F717FEBFFFCB600F8020FB712E0A55B547BD366>65
+D<BA12C019FEF1FFC01AF01AFCD8000701F0C7000313FFDE007F7F737F070F7F737F8785
+87858785A287A84F5BA263616361634F5B4F5B077F90C7FC4E485A060713F892B812E097
+C8FC861AF003F0C7000313FE9539003FFF80070F13E0737F07017F87737F747E1C807413
+C0A27413E0A31CF0A386A362A31CE0A2621CC0A250138097B5FC1C004F5B19074F5B073F
+13F04EB55ABC128098C7FC1AF81AC007F8C8FC54527CD160>I<932601FFFCEC01C0047F
+D9FFC013030307B600F81307033F03FE131F92B8EA803F0203DAE003EBC07F020F01FCC7
+383FF0FF023F01E0EC0FF94A01800203B5FC494848C9FC4901F882494982494982494982
+4949824990CA7E494883A2484983485B1B7F485B481A3FA24849181FA3485B1B0FA25AA2
+98C7FC5CA2B5FCAE7EA280A2F307C07EA36C7FA21B0F6C6D1980A26C1A1F6C7F1C006C6D
+606C6D187EA26D6C606D6D4C5A6D6D16036D6D4C5A6D6D4C5A6D01FC4C5A6D6DEE7F806D
+6C6C6C4BC7FC6E01E0EC07FE020F01FEEC1FF80203903AFFE001FFF0020091B612C0033F
+93C8FC030715FCDB007F14E0040101FCC9FC525479D261>I<BA7E19FCF1FF801AF01AFC
+D8000701F0C7000F13FF060014C0071F7F070713F807017F737F747E747F747F86747F74
+7F8886888688A2757EA31D8087A21DC0A51DE0A387A963A31DC0A51D80A2631D00A3515A
+A2646264505B6264505B505B5090C7FCF2FFFE4F5B07075B071F5B96B512C0060F91C8FC
+BB5A1AF01AC007FCC9FC19805B527CD167>I<BC1280A5D8000701F8C7000114C0F0001F
+19071901851A7F1A3F1A1FA2F20FE0A21A07A31A03A318F81BF01A01A497C7FC1701A317
+031707170F177F92B6FCA59238F8007F170F170717031701A317001B3EA31B7CA395C8FC
+A21BFCA21BF8A21A01A31A031BF01A071A0FA21A1F1A3FF27FE0F101FF1907191F0603B5
+FCBCFCA21BC0A34F517CD058>I<BB12FEA5D8000701F8C700077FF0007F191F19078585
+8586861B80A21A1FA31A0FA41BC006F81307A497C7FCA31701A317031707170F177F92B6
+FCA59238F8007F170F170717031701A31700A795C9FCB3B812F8A54A517CD055>I<9326
+01FFFCEC01C0047FD9FFC013030307B600F81307033F03FE131F92B8EA803F0203DAE003
+EBC07F020F01FCC7383FF0FF023F01E0EC0FF94A01800203B5FC494848C9FC4901F88249
+49824949824949824949824990CA7E494883A2484983485B1B7F485B481A3FA24849181F
+A3485B1B0FA25AA298C8FC5CA2B5FCAE6C057FB712E0A280A36C94C7003FEBC000A36C7F
+A36C7FA27E6C7FA26C7F6C7FA26D7E6D7F6D7F6D6D5E6D7F6D01FC93B5FC6D13FF6D6C6D
+5C6E01F0EC07FB020F01FEEC1FF10203903AFFF001FFE0020091B6EAC07F033FEE001F03
+0703FC1307DB007F02E01301040149CAFC5B5479D26A>I<B8D8C003B8FCA5D8000701F8
+C9001FEBE000B3AE92BAFCA503F8C9121FB3B1B8D8C003B8FCA560527CD169>I<B812C0
+A5D8000701F8C7FCB3B3B3B2B812C0A52A527CD132>I<B800C091B612F8A5D8000701F8
+C90003EBF8009738007F8051C7FC505AF203F8F20FF0505A505A505A50C8FCF101FCF107
+F84F5A4F5A4F5A4F5A07FEC9FCF003FC4E5A4E5A4E5A4E5A4E5ADD01FECAFC4D5A4D5A4D
+5A4D7E173F4D7E4C487E4C7F5E4C804C804C80EEFF7F9226F9FE3F7FDBFBFC809226FFF8
+1F7F4C7EDCC0077F0480804C7E4B6D804B6D804B8284727F727F8684727F727F87847280
+87737F85737F87737F85737F88857380747F888697B512FCB800C0013FECFFFEA55F527C
+D169>75 D<B812F8A5D8000701F8CAFCB3B3A91A7CA41AFC1AF8A51901A31903A219071A
+F0190FA2191F193F197F19FF180360183F4DB5FCBB12E0A546527CD151>I<B600FC073F
+B512FE6F61A26F96B6FCA2D80007F5C00070EF01EFA202EF6DEF03CFA202E76DEF078FA2
+02E36DEF0F0FA202E16D171EA302E06D173CA26F6C1778A26F6C17F0A26F6DED01E0A26F
+6DED03C0A36F6DED0780A26F6DED0F00A26F6D151EA26F6D5DA3706C5DA2706C5DA2706D
+495AA2706D495AA2706D495AA3706D49C7FCA2706D131EA2706D5BA2716C5BA3716C5BA2
+71EB81E0A271EBC3C0A271EBE780A27101FFC8FCA3715BA2715BA2725AA2725AA2D93FFC
+6F5AB74DB712FEA2725AA2725A77527CD180>I<B600FC93B7FC8181A282D800076E9239
+003FFC0070EE07E08282A28202EF7F02E77F02E380A202E18002E0806F7F6F7F6F7FA26F
+7F6F7F6F806F80A26F80707F707F707F707FA2707F7080708070808583717F717F717F71
+7FA27114807114C07114E07213F07213F8A27213FC7213FE7213FF721487A27214C77214
+E77313F77313FF85A285858585A28586868686A286868686A2D93FFC187FB7173F1B1F1B
+0F1B07755A60527CD169>I<93380FFFC00303B6FC031F15E092B712FC0203D9FC0013FF
+020F01C0010F13C0023F90C7000313F0DA7FFC02007F494848ED7FFE4901E0ED1FFF4949
+6F7F49496F7F4990C96C7F49854948707F4948707FA24849717E48864A83481B804A8348
+1BC0A2481BE04A83A2481BF0A348497113F8A5B51AFCAF6C1BF86E5FA46C1BF0A26E5F6C
+1BE0A36C6D4D13C0A26C6D4D1380A26C1B006C6D4D5A6E5E6C626D6C4C5B6D6D4B5B6D6D
+4B5B6D6D4B5B6D6D4B5B6D6D4B90C7FC6D6D4B5A6D01FF02035B023F01E0011F13F0020F
+01FC90B512C0020390B7C8FC020016FC031F15E0030392C9FCDB001F13E0565479D265>
+I<BAFC19F819FF1AE086D8000701F0C7001F13FC060113FF726C13807313C0070F13E01B
+F0857313F81BFCA27313FEA41BFFA81BFEA31BFC61A21BF84F13F04F13E0614F13C04F13
+004E485A061F5B92B812F01AC04FC7FC19E003F8CBFCB3AEB812C0A550527CD15C>I<B9
+12F0F0FF8019F819FF1AC0D8000701F0C714F0060F7F060113FE727F737F737F85737F87
+A2737FA387A863A2616363A24F5B4F5B4F90C8FC4F5A06035B060F13F095B512C092B8C9
+FC19F819E019F89226F0000313FE9439007FFF80727F727F727F727F727F8684A28684A7
+87A71D1C75133EA38575137E73157C7513FC731401B86C6D9038F803F807039038FE07F0
+7390B512E0736C14C0080F1400CEEA7FFC5F537CD164>82 D<91260FFF80130791B500F8
+5B010702FF5B011FEDC03F49EDF07F9026FFFC006D5A4801E0EB0FFD4801800101B5FC48
+48C87E48488149150F001F824981123F4981007F82A28412FF84A27FA26D82A27F7F6D93
+C7FC14C06C13F014FF15F86CECFF8016FC6CEDFFC017F06C16FC6C16FF6C17C06C836C83
+6D826D82010F821303010082021F16801400030F15C0ED007F040714E01600173F050F13
+F08383A200788200F882A3187FA27EA219E07EA26CEFFFC0A27F6D4B13806D17006D5D01
+FC4B5A01FF4B5A02C04A5A02F8EC7FF0903B1FFFC003FFE0486C90B65AD8FC0393C7FC48
+C66C14FC48010F14F048D9007F90C8FC3C5479D24B>I<003FBC1280A59126C0003F9038
+C0007F49C71607D87FF8060113C001E08449197F49193F90C8171FA2007E1A0FA3007C1A
+07A500FC1BE0481A03A6C994C7FCB3B3AC91B912F0A553517BD05E>I<B800C00103B612
+FCA5D8000701F8CAEBF000F31F80B3B3B11B3FA26D97C7FC81637F1B7E6D6D17FE505A6E
+7E505A6E6D15076E4D5A6E6D4B5A6E6D4B5A6E01F84B5A6E6DDA03FFC8FC6E6CB46CEB0F
+FE6F9039F001FFF8030F90B65A030316C0DB007F92C9FC040F14F8DC007F13805E537CD1
+67>I<B700FE031FB512FEA5D8001F01F0CA383FFE00F307F06D626F170F6D62811B1F6D
+6D601B3F6D97C7FC6F5F6D197E821BFE6E6D5E1A016E6D5E1A036E60701507A26E6D5E1A
+0F6E6D5E1A1F6E6070153FA26E6D93C8FC626E6E147E1AFE6F5E711301A26F6D5C19036F
+6D5C19076F5E71130FA26F6D5C191F6F6D5C193F6F93C9FC715BA26FEC807E19FE706D5A
+18C1705C18E3705C18F318F770EBFFE0A2705CA2705CA37091CAFCA2705BA2715AA3715A
+A2715AA2715A715A5F537DD166>I<B700FC017FB600FE91B612F0A5D8003F01C0C8001F
+01E0C9EBF8006F71EE0FC06D7161876F1C1F6D7196C7FC6F8373606D1E3E6F836D716087
+6F1CFC6D666F4B801F016D66704A806E525A88704A17076E059F5F70021F80080F160F6E
+6570023F806EDC3E074CC8FC8870027E5F6EDC7C03163E7002FC804F6C167E6E1C7C7001
+01814F6C16FC6E745B70010317016E4C6D5D060716C00580496D14036F63DDC00F16E04F
+6D14076F07F05BDDE01F170F6F92C76C5D1DF8DDF03E6E141F6F98C9FCDDF87E16FC067C
+6E5C6FF1FE3EDDFCFC177E6F4A6E147C1DFFDDFFF06E14FC6F62A24E816F62A270496F5B
+A24E817061A295C97E7061A270487090CAFCA37048705AA24D1601040360A27048705A84
+537DD18B>I<EC7FFF0107B512F0013F14FE90B77E48D9E00F7F2703FE000113F0486C6D
+7F6EEB3FFC48826E131F83707FA36C496D7FA26C90C7FC6C5AC9FCA6037FB5FC020FB6FC
+91B7FC01071487013FEBF0074913803901FFFC004813F0485B485B485B4890C7FC5A5BA2
+485AA45EA26D5C007F151D163D6C6C02797F6C6D01F113F86C9026C003E1EBFFE06C9026
+F81FC014F06C90B5487EC6ED001F011F01FC010713E0010101E090C8FC3C387CB641>97
+D<EB3FF0B5FCA51203C6FCB3A4923801FFE0030F13FE033FEBFFC092B612F002F301017F
+913AF7F8003FFEDAFFE0EB0FFF03806D7F92C76C7F4A6E7F4A824A6E7FA2727EA285A285
+84A31A80AC1A00A44E5AA36118FF616E4A5BA26E4A5B6E4A5B6F495BDACFC04990C7FCDA
+87F0EB7FFC913A03FE03FFF849C6B612E0496D148049011F01FCC8FC90C7000313C04154
+7BD24B>I<913801FFF8021FEBFF8091B612F0010315FC010F9038C00FFE903A1FFE0001
+FFD97FFC491380D9FFF05B4817C048495B5C5A485BA2486F138091C7FC486F1300705A48
+92C8FC5BA312FFAD127F7FA27EA2EF03E06C7F17076C6D15C07E6E140F6CEE1F806C6DEC
+3F006C6D147ED97FFE5C6D6CEB03F8010F9038E01FF0010390B55A01001580023F49C7FC
+020113E033387CB63C>I<4DB47E0407B5FCA5EE001F1707B3A4913801FFE0021F13FC91
+B6FC010315C7010F9038E03FE74990380007F7D97FFC0101B5FC49487F4849143F484980
+485B83485B5A91C8FC5AA3485AA412FFAC127FA36C7EA37EA26C7F5F6C6D5C7E6C6D5C6C
+6D49B5FC6D6C4914E0D93FFED90FEFEBFF80903A0FFFC07FCF6D90B5128F0101ECFE0FD9
+003F13F8020301C049C7FC41547CD24B>I<913803FFC0023F13FC49B6FC010715C04901
+817F903A3FFC007FF849486D7E49486D7E4849130F48496D7E48178048497F18C0488191
+C7FC4817E0A248815B18F0A212FFA490B8FCA318E049CAFCA6127FA27F7EA218E06CEE01
+F06E14037E6C6DEC07E0A26C6DEC0FC06C6D141F6C6DEC3F806D6CECFF00D91FFEEB03FE
+903A0FFFC03FF8010390B55A010015C0021F49C7FC020113F034387CB63D>I<ED3FFC02
+03B5FC020F14C0023F14E09139FFF81FF0499038C03FF849EB807F49903800FFFC495A49
+5AA2495AA2EE7FF8495AEE3FF0EE0FC093C7FCAEB712E0A526007FF8C8FCB3B3A7007FB5
+12FEA52E547CD329>I<DA3FFF14FF0103B5D8F00713C0010FDAFC1F13E0013FECFF7F90
+267FFC0F9038FF9FF09026FFE001EBF83F48496C13E0484990387FF01F4890C7D83FF813
+E0489338FC0FC0F0078048486E6CC7FCA2003F82A9001F5EA26C6C4A5AA26C5E6C6D495A
+6C6D495A6C6D485BDAFC0F5B4890B6C8FCD803EF14FC01C314F02607C03F90C9FC91CBFC
+A2120FA37FA213F813FE90B7FC6C16F817FF18C06C836C836C836D828448B9FC12074848
+C700031480D81FF8EC003F4848150748486F13C083485A83A56D5D007F18806D5D003F18
+006C6C4B5AD80FFEED1FFC6C6C6CEC7FF86C01E049485A6C01FE011F5B6C6CB71280010F
+03FCC7FC010115E0D9000F01FCC8FC3C4F7CB543>I<EB3FF0B5FCA51203C6FCB3A4EE1F
+FC93B512C0030314F0030F8092391FE07FFC92393F001FFE037C8003F07FDAF1E081ECF3
+C0DAF7807F8502FFC7FC5CA25CA45CB3ACB6D8F807B612C0A542537BD24B>I<137F497E
+000313E0487FA2487FA76C5BA26C5BC613806DC7FC90C8FCADEB3FF0B5FCA512017EB3B3
+A6B612E0A51B547BD325>I<EB3FF0B5FCA51203C6FCB3A54CB512F8A59339003FFE00EF
+1FF0EF3FC04D5A4DC7FCEE03FEEE07F84C5A4C5AEE7FC04CC8FC4B5A4B5AED0FF8ED1FE0
+4B7E4B7EECF1FF02F37F02F77F91B6FC83159F030F7F02FE80DAF8077F4A7E6F7F6F7F83
+707E82707F84707F707F82707F84707F177F717E4D13C0B6D8F003B6FCA540537CD247>
+107 D<EB3FF0B5FCA512017EB3B3B3B1B612F0A51C537BD225>I<D93FF0D91FFCEDFFE0
+B591B500C0010713FE030302F0011F6D7E030F6E017F8092271FE07FFCD9FF037F922A3F
+001FFE01F8007F0003027C9126FF03E080C602F06DD90780137FDAF1E0038FC77FDAF3C0
+159EDAF7806D01BC143F07FC8102FFC75C4A5EA24A5EA44A5EB3ACB6D8F807B6D8C03FB5
+12FEA567367BB570>I<D93FF0EB1FFCB591B512C0030314F0030F8092391FE07FFC9239
+3F001FFE0003027C80C602F07FDAF1E081ECF3C0DAF7807F8502FFC7FC5CA25CA45CB3AC
+B6D8F807B612C0A542367BB54B>I<913801FFE0021F13FE91B612C0010315F0010F9038
+807FFC903A1FFC000FFED97FF86D6C7E49486D7F48496D7F48496D7F4A147F48834890C8
+6C7EA24883A248486F7EA3007F1880A400FF18C0AC007F1880A3003F18006D5DA26C5FA2
+6C5F6E147F6C5F6C6D4A5A6C6D495B6C6D495B6D6C495BD93FFE011F90C7FC903A0FFF80
+7FFC6D90B55A010015C0023F91C8FC020113E03A387CB643>I<903A3FF001FFE0B5010F
+13FE033FEBFFC092B612F002F301017F913AF7F8007FFE0003D9FFE0EB1FFFC602806D7F
+92C76C7F4A824A6E7F4A6E7FA2717FA285187F85A4721380AC1A0060A36118FFA2615F61
+6E4A5BA26E4A5B6E4A5B6F495B6F4990C7FC03F0EBFFFC9126FBFE075B02F8B612E06F14
+80031F01FCC8FC030313C092CBFCB1B612F8A5414D7BB54B>I<90397FE003FEB590380F
+FF80033F13E04B13F09238FE1FF89139E1F83FFC0003D9E3E013FEC6ECC07FECE78014EF
+150014EE02FEEB3FFC5CEE1FF8EE0FF04A90C7FCA55CB3AAB612FCA52F367CB537>114
+D<903903FFF00F013FEBFE1F90B7FC120348EB003FD80FF81307D81FE0130148487F4980
+127F90C87EA24881A27FA27F01F091C7FC13FCEBFFC06C13FF15F86C14FF16C06C15F06C
+816C816C81C681013F1580010F15C01300020714E0EC003F030713F015010078EC007F00
+F8153F161F7E160FA27E17E07E6D141F17C07F6DEC3F8001F8EC7F0001FEEB01FE9039FF
+C00FFC6DB55AD8FC1F14E0D8F807148048C601F8C7FC2C387CB635>I<143EA6147EA414
+FEA21301A313031307A2130F131F133F13FF5A000F90B6FCB8FCA426003FFEC8FCB3A9EE
+07C0AB011FEC0F8080A26DEC1F0015806DEBC03E6DEBF0FC6DEBFFF86D6C5B021F5B0203
+13802A4D7ECB34>I<D93FF8913801FFC0B50207B5FCA50003ED001FC61607B3AE5FA35F
+A2017F5D173B177B6D6C14F3DC01E313F06D6CD907C3EBFFC0903A0FFFC03F836D90B512
+03010114FE6D6C13F8020701E091C7FC42377BB54B>I<B600F00107B5FCA5000101F8C8
+EA7FE06C6DED3F00A2017F163E6E157E013F167C6E15FC6D5E6F13016D5E8117036D5E6F
+13076D5E6F130F6D5E6F131F6D93C7FC815F6E6C133E177E023F147C6F13FC6E5C16816E
+5C16C3A26EEBE3E016E76E5C16FF6E5CA26E91C8FCA26F5AA36F5AA26F5AA26F5AA26F5A
+6F5A40367DB447>I<B6D8E07FB5D8C003B512C0A5000101F0C701F0C7381FF8006E027F
+ED07E06C715DA26E023F150F017F705DA26E181F013F4B6C92C7FC6E606D70143E94B5FC
+6F177E6D4A6E137C03C001F315FC6D715B160303E001E114016D020702E05B03F013C06D
+71485A160F03F8D9807F13076D05F85B93381F003F03FC160F027F4902FC5BDBFE3E011F
+131F023F04FE90C8FC167EDBFF7C010F5B6E01FCECFF3E4C6D137E6E5FA24C7F6E5F4C7F
+6E5FA24C7F6E5F4C147FA26E5F93C8123F6F5EA2033E6FC9FC5A367DB461>I<007FB500
+F090387FFFFEA5C66C48C7000F90C7FC6D6CEC07F86D6D5C6D6D495A6D4B5A6F495A6D6D
+91C8FC6D6D137E6D6D5B91387FFE014C5A6E6C485A6EEB8FE06EEBCFC06EEBFF806E91C9
+FCA26E5B6E5B6F7E6F7EA26F7F834B7F4B7F92B5FCDA01FD7F03F87F4A486C7E4A486C7E
+020F7FDA1FC0804A486C7F4A486C7F02FE6D7F4A6D7F495A49486D7F01076F7E49486E7E
+49486E7FEBFFF0B500FE49B612C0A542357EB447>I<B600F00107B5FCA5C601F8C8EA7F
+E06EED3F00A26D6C153E187E013F167C6E15FC6D5E6F13016D5E6F13036D5E8117076D6D
+5C170F6D6D5C171F6D93C7FC6F5B027F143E6F137E023F147C6F13FCA26E6D5A16816EEB
+C1F016C36E5C16E76E5C16FF6E5CA26E91C8FCA36F5AA26F5AA26F5AA26F5AA26F5AA35E
+150F5E151F93C9FC5DD81FC0133E486C137E486C137C486C13FC5D14015D14034A5A6C48
+485A49485A263FC07FCAFCEB81FE6CB45A6C13F000035BC690CBFC404D7DB447>I<001F
+B8FC1880A3912680007F130001FCC7B5FC01F0495B495D49495B495B4B5B48C75C5D4B5B
+5F003E4A90C7FC92B5FC4A5B5E4A5B5CC7485B5E4A5B5C4A5B93C8FC91B5FC495B5D4949
+EB0F805B495B5D495B49151F4949140092C7FC495A485E485B5C485E485B4A5C48495B48
+15074849495A91C712FFB8FCA37E31357CB43C>I E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fe cmtt10 10.95 93
+/Fe 93 127 df<121C127FEAFF80B3EA7F00B2123EC7FCA8121C127FA2EAFF80A3EA7F00
+A2121C09396DB830>33 D<00101304007C131F00FEEB3F80A26C137FA248133FB2007E14
+00007C7F003C131E00101304191C75B830>I<903907C007C0A2496C487EA8011F131FA2
+02C05BA3007FB7FCA2B81280A36C16006C5D3A007F807F80A2020090C7FCA9495BA2003F
+90B512FE4881B81280A36C1600A22701FC01FCC7FCA300031303A201F85BA76C486C5AA2
+29387DB730>I<1438147C14FCA4EB03FF011F13E090B512FC4880000780481580261FFE
+FD13C09039F0FC3FE0D83FC0131FD87F80EB0FF001001307007E15F800FE14035A1507A3
+6CEC03F0A2007F91C7FC138013C0EA3FF0EA1FFE13FF6C13FF6C14E0000114F86C6C7F01
+1F7F01037F0100148002FD13C09138FC7FE0151FED0FF015070018EC03F8127E1501B4FC
+A35AA26CEC03F07E01801307ED0FE0D83FC0131F01F0EB7FC0D81FFEB512806CB612006C
+5C6C5CC614F0013F13C0D907FEC7FCEB00FCA5147C143825477BBE30>I<D803C0EB01E0
+D80FF01303486C497E487E150F487ED87E7E495AEAFE7F5E486C133FA25E157FA24BC7FC
+6C5A5D387E7E01EA7FFED83FFC5B1403EA1FF86C48485AEA03C0C75B140FA25D141FA24A
+5AA25D147FA292C8FC5CA2495AA25C1303A25C1307A290390FF001E0ED07F84A487E011F
+497EA24A487E133F163F90267F807F1380ED7E1F14005BA25B1201A24848EB7F3F033F13
+004914FF12076F5A5B6F5A6C486D5A0001EC01E029477DBE30>I<EB07E0EB1FF8497E13
+7F497E803801FC7F497E810003131F13F0A6143F92C8FC91387F0FFF9026F87E1F138000
+0113FEEBF9FC13FB4A6C1300D9FFF013C06C13E0151F02C05BEB7F809038FF003F4892C7
+FC485C48EB807E5A15FE391FDFC0FC383F8FE014E1397F07F1F8EB03F300FEEBFBF0EB01
+FF5D7FEDC006027F130F91393F801F8015C06C137F6CEBFFE049EBF83F018701FC130026
+3FFFFBB5FC6C01F15B14E06C9038C03FFC00039038001FF8D801FCEB07E0293A7DB830>
+I<EA07C0EA0FF0EA1FF8A213FCA213FE120F1207EA007EA513FE13FCA2120113F81203EA
+07F0120FEA1FE0127FEAFFC013801300127C12380F1D70B730>I<141E147F14FF5BEB03
+FEEB07FCEB0FF0EB1FE0EB3FC0EB7F80EBFF00485A5B12035B485A120F5BA2485AA2123F
+5BA2127F90C7FCA412FEAD127FA47F123FA27F121FA26C7EA27F12076C7E7F12017F6C7E
+EB7F80EB3FC0EB1FE0EB0FF0EB07FCEB03FEEB01FF7F147F141E184771BE30>I<127812
+FE7E7F6C7E6C7EEA0FF06C7E6C7E6C7E6C7EEB7F80133F14C0131FEB0FE014F01307A2EB
+03F8A214FC1301A214FE1300A4147FAD14FEA4130114FCA2130314F8A2EB07F0A2130F14
+E0EB1FC0133F1480137FEBFF00485A485A485A485AEA3FE0485A485A90C7FC5A12781847
+78BE30>I<14E0497E497EA60038EC0380007EEC0FC0D8FF83EB3FE001C3137F9038F3F9
+FF267FFBFB13C06CB61280000FECFE00000314F86C5C6C6C13C0011F90C7FC017F13C048
+B512F04880000F14FE003FECFF80267FFBFB13C026FFF3F913E09038C3F87F0183133FD8
+7E03EB0FC00038EC0380000091C7FCA66D5A6D5A23277AAE30>I<143EA2147FAF007FB7
+FCA2B81280A36C1600A2C76CC8FCAF143EA229297DAF30>I<EA03E0EA0FF0EA1FF813FC
+EA3FFEA213FFA27EA27E1203EA007FA2137E13FEEA01FC1203EA07F8EA3FF0127FEAFFE0
+EA7F801300123C1019708B30>I<007FB612F0A2B712F8A36C15F0A225077B9E30>I<120F
+EA3FC0EA7FE0A2EAFFF0A4EA7FE0A2EA3FC0EA0F000C0C6E8B30>I<16F01501ED03F8A2
+1507A2ED0FF0A2ED1FE0A2ED3FC0A2ED7F80A2EDFF00A24A5AA25D1403A24A5AA24A5AA2
+4A5AA24A5AA24A5AA24AC7FCA2495AA25C1303A2495AA2495AA2495AA2495AA2495AA249
+C8FCA2485AA25B1203A2485AA2485AA2485AA2485AA2485AA248C9FCA25AA2127CA22547
+7BBE30>I<14FE903807FFC0497F013F13F8497F90B57E48EB83FF4848C6138049137F48
+48EB3FC04848EB1FE049130F001F15F0491307A24848EB03F8A290C712014815FCA400FE
+EC00FEAD6C14016C15FCA36D1303003F15F8A26D1307001F15F0A26D130F6C6CEB1FE0A2
+6C6CEB3FC06C6CEB7F806D13FF2601FF8313006CEBFFFE6D5B6D5B010F13E06D5BD900FE
+C7FC273A7CB830>I<EB03C0497EA2130FA2131FA2133F137F13FF1203123FB5FCA213EF
+138FEA7E0F1200B3B0003FB512F84814FCB612FEA26C14FC6C14F81F3977B830>I<EB07
+FC90383FFFC090B512F00003804814FE4880261FF80F1380263FE00113C09038C0007F48
+48EB3FE090C7121FED0FF04814075A6C15F81503A3127E1218C8FCA2150716F0150F16E0
+151F16C0153FED7F8015FF4A13005DEC07FC4A5A4A5A4A5A4A5A4A5A4990C7FC495A495A
+EB0FF0EB3FE0495A495A4890C8FC4848EB01F04848EB03F8485AEA1FE048B6FCB7FCA37E
+6C15F025397BB830>I<EB03FF013F13E090B512F84814FE4880481580260FFE0113C090
+38F0007F4848EB1FE0150F16F01507A26C5A6C5AC8FC150F16E0A2151FED3FC0157FEDFF
+8002071300903807FFFE495B5D8115FF6D1480D9000113C09138003FE0ED1FF0ED07F815
+0316FC150116FE1500A21218127EB4FCA2150116FC4814036C15F86C6C13076DEB1FF0D8
+3FF0133F3A1FFE01FFE06CB612C06C15806CECFE00C65C013F13F001031380273A7CB830
+>I<EC03FC4A7E140F141FA2143F147F157E14FEA2EB01FCEB03F8A2EB07F0A2EB0FE0EB
+1FC0A2EB3F80A2EB7F0013FEA2485A485AA2485AA2485A485AA2485AA248C7FC12FEB8FC
+1780A46C1600C8007EC7FCAA91387FFFFE91B6FCA46E5B29397DB830>I<000FB6128048
+15C05AA316800180C8FCAEEB83FF019F13C090B512F015FC8181D9FE0313809039F0007F
+C049133F0180EB1FE06CC7120F000E15F0C81207A216F81503A31218127EA2B4FC150716
+F048140F6C15E06C141F6DEB3FC06D137F3A3FE001FF80261FFC0F13006CB55A6C5C6C5C
+6C14E06C6C1380D90FFCC7FC25397BB730>I<EC0FF8EC7FFF49B51280010714E0131F49
+14F090387FF80F9039FFC007F84813803803FE005B485A4848EB03F0ED01E0484890C7FC
+5B123F5BA2127FEB000C903803FFE0010F13F8D8FF3F13FE48B6FCB7128016C09039FE00
+7FE001F8EB1FF001E0130F49EB07F849EB03FCA290C7120116FE1500A37EA46C7E15016D
+14FC121F6D1303000FEC07F86D130F6C6CEB1FF06DEB3FE03A03FF81FFC06C90B512806C
+15006D5B011F13F8010713E001011380273A7CB830>I<127CB712FC16FEA416FC48C7EA
+0FF816F0ED1FE0007CEC3FC0C8EA7F80EDFF00A24A5A4A5A5D14075D140F5D4A5AA24A5A
+A24AC7FCA25C5C13015CA213035CA213075CA4495AA6131F5CA96D5A6DC8FC273A7CB830
+>I<49B4FC011F13F0017F13FC90B57E0003ECFF804815C048010113E03A1FF8003FF049
+131FD83FC0EB07F8A24848EB03FC90C71201A56D1303003F15F86D13076C6CEB0FF06C6C
+EB1FE0D807FCEB7FC03A03FF83FF806C90B512006C6C13FC011F13F0497F90B512FE4880
+2607FE0013C0D80FF8EB3FE0D81FE0EB0FF04848EB07F8491303007F15FC90C712014815
+FE481400A66C14016C15FC6D1303003F15F86D1307D81FF0EB1FF06D133F3A0FFF01FFE0
+6C90B512C06C1580C6ECFE006D5B011F13F0010190C7FC273A7CB830>I<49B4FC010F13
+E0013F13F890B57E4880488048010113803A0FFC007FC0D81FF0EB3FE04848131F49EB0F
+F048481307A290C7EA03F85A4815FC1501A416FEA37E7E6D1303A26C6C13076C6C130F6D
+133FD80FFC13FF6CB6FC7E6C14FE6C14F9013FEBE1FC010F138190380060011400ED03F8
+A2150716F0150F000F15E0486C131F486CEB3FC0157FEDFF804A1300EC07FE391FF01FFC
+90B55A6C5C6C5C6C1480C649C7FCEB3FF0273A7CB830>I<120FEA3FC0EA7FE0A2EAFFF0
+A4EA7FE0A2EA3FC0EA0F00C7FCAF120FEA3FC0EA7FE0A2EAFFF0A4EA7FE0A2EA3FC0EA0F
+000C276EA630>I<EA03C0EA0FF0EA1FF8A2EA3FFCA4EA1FF8A2EA0FF0EA03C0C7FCAFEA
+03C0EA0FF0121F13F8123F13FCA3121FA2120F12031200120113F8120313F01207EA1FE0
+123FEA7FC0EAFF80EA7F00127E12380E3470A630>I<16F01503ED07F8151F157FEDFFF0
+14034A13C0021F138091383FFE00ECFFF8495B010713C0495BD93FFEC7FC495A3801FFF0
+485B000F13804890C8FCEA7FFC5BEAFFE05B7FEA7FF87FEA1FFF6C7F000313E06C7F3800
+7FFC6D7E90380FFF806D7F010113F06D7FEC3FFE91381FFF80020713C06E13F01400ED7F
+F8151F1507ED03F01500252F7BB230>I<007FB7FCA2B81280A36C16006C5DCBFCA7003F
+B612FE4881B81280A36C1600A229157DA530>I<1278127EB4FC13C07FEA7FF813FEEA1F
+FF6C13C000037F6C13F86C6C7EEB1FFF6D7F010313E06D7F9038007FFC6E7E91380FFF80
+6E13C0020113F080ED3FF8151F153FEDFFF05C020713C04A138091383FFE004A5A903801
+FFF0495B010F13804990C7FCEB7FFC48485A4813E0000F5B4890C8FCEA7FFE13F8EAFFE0
+5B90C9FC127E1278252F7BB230>I<EB1FFE90B512E0000314F8000F14FE488048158026
+7FF80313C09038C0007F48C7121F16E0150FA3127E151F0018EC7FC0C812FF020313804A
+13004A5AEC1FF84A5AEC7FC04A5A92C7FC495AA2495A5CA213075CA86D5A90C9FCA8EB01
+C0EB07F0A2497EA36D5AA2EB01C023397AB830>I<EC1FE0ECFFF8010313FE010F7F4914
+804914C090397FF03FE09038FF800F4890380007F0D803FC13033A07F801FBF89038F007
+FF380FE01F4A13FCEA1FC0495A003FEBFF0F903800FE07903901FC03FE007FEBF801EA7E
+03ECF000A2EAFE0700FC49137EAA00FE6D13FED87E0314FCA2ECF801D87F0114F8003FEB
+FC03903900FE07F0903880FF0F001F90387FFFE06D6C13C0EA0FE06E13803A07F007FE00
+9038F801F86C6CC7127C6CB414FE6CEB800390387FF01F6DB512FC6D14F86D14E0010314
+C00100EBFE00EC1FF0273A7CB830>I<147F4A7EA2497FA4497F14F7A401077F14E3A301
+0F7FA314C1A2011F7FA490383F80FEA590387F007FA4498049133F90B6FCA34881A39038
+FC001F00038149130FA4000781491307A2D87FFFEB7FFFB56CB51280A46C496C13002939
+7DB830>I<007FB512F0B612FE6F7E82826C813A03F8001FF815076F7E1501A26F7EA615
+015EA24B5A1507ED1FF0ED7FE090B65A5E4BC7FC6F7E16E0829039F8000FF8ED03FC6F7E
+1500167FA3EE3F80A6167F1700A25E4B5A1503ED1FFC007FB6FCB75A5E16C05E6C02FCC7
+FC29387EB730>I<91387F803C903903FFF03E49EBFC7E011F13FE49EBFFFE5B9038FFE0
+7F48EB801F3903FE000F484813075B48481303A2484813015B123F491300A2127F90C8FC
+167C16005A5AAC7E7EA2167C6D14FE123FA27F121F6D13016C6C14FCA26C6CEB03F86D13
+076C6CEB0FF03901FF801F6C9038E07FE06DB512C06D14806D1400010713FC6D13F09038
+007FC0273A7CB830>I<003FB512E04814FCB67E6F7E6C816C813A03F8007FF0ED1FF815
+0F6F7E6F7E15016F7EA2EE7F80A2163F17C0161FA4EE0FE0AC161F17C0A3163F1780A216
+7F17005E4B5A15034B5A150F4B5AED7FF0003FB65A485DB75A93C7FC6C14FC6C14E02B38
+7FB730>I<007FB7FCB81280A47ED803F8C7123FA8EE1F0093C7FCA4157C15FEA490B5FC
+A6EBF800A4157C92C8FCA5EE07C0EE0FE0A9007FB7FCB8FCA46C16C02B387EB730>I<00
+3FB712804816C0B8FCA27E7ED801FCC7121FA8EE0F8093C7FCA5153E157FA490B6FCA690
+38FC007FA4153E92C8FCAE383FFFF8487FB5FCA27E6C5B2A387EB730>I<02FF13F00103
+EBC0F8010F13F1013F13FD4913FF90B6FC4813C1EC007F4848133F4848131F49130F485A
+491307121F5B123F491303A2127F90C7FC6F5A92C8FC5A5AA892B5FC4A14805CA26C7F6C
+6D1400ED03F8A27F003F1407A27F121F6D130F120F7F6C6C131FA2D803FE133F6C6C137F
+ECC1FF6C90B5FC7F6D13FB010F13F30103EBC1F0010090C8FC293A7DB830>I<3B3FFF80
+0FFFE0486D4813F0B56C4813F8A26C496C13F06C496C13E0D803F8C7EAFE00B290B6FCA6
+01F8C7FCB3A23B3FFF800FFFE0486D4813F0B56C4813F8A26C496C13F06C496C13E02D38
+7FB730>I<007FB6FCB71280A46C1500260007F0C7FCB3B3A8007FB6FCB71280A46C1500
+213879B730>I<49B512F04914F85BA27F6D14F090C7EAFE00B3B3123C127EB4FCA24A5A
+1403EB8007397FF01FF86CB55A5D6C5C00075C000149C7FC38003FF025397AB730>I<D8
+3FFF90380FFF80486D4813C0B56C5AA26C497E6C496C1380D803F0903803F8004B5A4B5A
+151F4B5A5E4BC7FC15FE14014A5A5D4A5A4A5A141F5D4A5A4AC8FC5C13F18101F37F13F7
+90B57E14EFECC7F01483EC03F8140101FE7F496C7E5B157F497F82151F82150F826F7EA2
+6F7E1501821500D83FFF903803FFC0486D4813E0B56C5AA26C497E6C496C13C02B387FB7
+30>I<383FFFF8487FB57EA26C5B6C5BD801FCC9FCB3B0EE0F80EE1FC0A9003FB7FC5AB8
+FCA27E6C16802A387EB730>I<D83FF8ECFFE0486C4913F0486C4913F8A2007F16F06C6C
+4913E00007160001EF14BFEC800FA39039E7C01F3FA4ECE03F01E3133EA2ECF07EA201E1
+137CA2ECF8FCA201E013F8A214FDEC7DF0A3147FEC3FE0A3EC1FC0A2EC070091C7FCADD8
+3FFC903801FFE0486C4913F0B54913F8A26C486D13F06C486D13E02D387FB730>I<D83F
+FC90381FFF80486C4913C0B54913E0A26C6D6C13C06C6E13800003913801F800EBF7C0A3
+EBF3E0A314F013F1A214F8A213F014FCA2147C147EA2143E143FA2141FA21581A2140F15
+C1A2140715E1A2140315F1A21401A215F91400A3157DA3153FEA3FFF481380B5EAC01FA2
+6CEB800F6C496C5A2B387EB730>I<90383FFFE048B512FC000714FF4815804815C04815
+E0EBF80001E0133FD87F80EB0FF0A290C71207A44815F8481403B3A96C1407A26C15F0A3
+6D130FA26D131F6C6CEB3FE001F813FF90B6FC6C15C06C15806C1500000114FCD8003F13
+E0253A7BB830>I<007FB512F0B612FE6F7E16E0826C813903F8003FED0FFCED03FE1501
+6F7EA2821780163FA6167F17005EA24B5A1503ED0FFCED3FF890B6FC5E5E16804BC7FC15
+F001F8C9FCB0387FFFC0B57EA46C5B29387EB730>I<90383FFFE048B512FC000714FF48
+15804815C04815E0EBF80001E0133F4848EB1FF049130F90C71207A44815F8481403B3A8
+147E14FE6CEBFF076C15F0EC7F87A2EC3FC7018013CF9038C01FFFD83FE014E0EBF80F90
+B6FC6C15C06C15806C1500000114FCD8003F7FEB00016E7EA21680157F16C0153F16E015
+1F16F0150FED07E025467BB830>I<003FB57E4814F0B612FC15FF6C816C812603F8017F
+9138003FF0151F6F7E15071503821501A515035E1507150F4B5A153F4AB45A90B65A5E93
+C7FC5D8182D9F8007FED3FE0151F150F821507A817F8EEF1FCA53A3FFF8003FB4801C0EB
+FFF8B56C7E17F06C496C13E06C49EB7FC0C9EA1F002E397FB730>I<90390FF803C0D97F
+FF13E048B512C74814F74814FF5A381FF80F383FE001497E4848137F90C7123F5A48141F
+A2150FA37EED07C06C91C7FC7F7FEA3FF0EA1FFEEBFFF06C13FF6C14E0000114F86C8001
+1F13FF01031480D9003F13C014019138007FE0151FED0FF0A2ED07F8A2007C140312FEA5
+6C140716F07F6DEB0FE06D131F01F8EB3FC001FF13FF91B51280160000FD5CD8FC7F13F8
+D8F81F5BD878011380253A7BB830>I<003FB712C04816E0B8FCA43AFE003F800FA8007C
+ED07C0C791C7FCB3B1011FB5FC4980A46D91C7FC2B387EB730>I<3B7FFFC007FFFCB56C
+4813FEA46C496C13FCD803F8C7EA3F80B3B16D147F00011600A36C6C14FE6D13016D5CEC
+800390393FE00FF890391FF83FF06DB55A6D5C6D5C6D91C7FC9038007FFCEC1FF02F3980
+B730>I<D87FFE90380FFFC0B54913E06E5AA24A7E6C486D13C0D807F0903801FC00A26D
+130300035DA46C6C495AA46C6C495AA46D131F6D5CA3EC803F013F5CA46D6C48C7FCA490
+380FE0FEA401075B14F1A301035BA314FB01015BA314FFA26D5BA46E5A6E5A2B397EB730
+>I<D83FFC903801FFE0486C4913F000FF16F8A2007F16F06C486D13E0D81FC09038001F
+C0000F1680A76D143F00071600A7000390380F803E9039F01FC07EEC3FE0A3EC7FF0A214
+7D0001157CA29039F8FDF8FCA314F8A300005D01F913FCA2ECF07CA201FD137DA2017D5C
+ECE03DA3017F133FA2ECC01FA2013F5CA2EC800F6D486C5A2D397FB730>I<3A3FFF01FF
+F84801837F02C77FA202835B6C01015B3A01FC007F806D91C7FC00005C6D5BEB7F01EC81
+FCEB3F8314C3011F5B14E7010F5B14FF6D5BA26D5BA26D5BA26D90C8FCA4497FA2497FA2
+815B81EB0FE781EB1FC381EB3F8181EB7F0081497F49800001143F49800003141F498000
+07140FD87FFEEB7FFFB590B5128080A25C6C486D130029387DB730>I<D87FFF90381FFF
+C0B56C4813E0A46C496C13C0D803F8903803F8006D1307A26C6C495AA26C6C5C151F6D5C
+EC803F013F5CECC07F011F91C7FCA290380FE0FEA214F101075BA2903803FBF8A201015B
+14FF6D5BA26E5AA36E5AB1903803FFF8497F497FA26D5B6D5B2B387EB730>I<001FB612
+FC4815FE5AA490C7EA03FCED07F816F0150FED1FE016C0153FED7F80003E1500C85A4A5A
+5D14034A5A5D140F4A5A5D143F4A5A92C7FC5C495A5C1303495A5C130F495A5C133F495A
+91C8FC5B4848147C4914FE1203485A5B120F485A5B123F485A90B6FCB7FCA46C15FC2738
+7CB730>I<007FB5FCB61280A4150048C8FCB3B3B3A5B6FC1580A46C140019476DBE30>I<
+127CA212FEA27EA26C7EA26C7EA26C7EA26C7EA26C7EA26C7EA212017FA26C7EA26D7EA2
+6D7EA26D7EA26D7EA26D7EA26D7EA2130180A26D7EA26E7EA26E7EA26E7EA26E7EA26E7E
+A26E7EA2140181A26E7EA2ED7F80A2ED3FC0A2ED1FE0A2ED0FF0A2ED07F8A21503A2ED01
+F0150025477BBE30>I<007FB5FCB61280A47EC7123FB3B3B3A5007FB5FCB6FCA46C1400
+19477DBE30>I<1307EB1FC0EB7FF0497E000313FE000FEBFF80003F14E0D87FFD13F039
+FFF07FF8EBC01FEB800F38FE0003007CEB01F00010EB00401D0E77B730>I<007FB612F0
+A2B712F8A36C15F0A225077B7D30>I<EB7FF80003B5FC4814C04880488048809038E01F
+FC9038C003FE14016E7E6C487F6CC77FC8123FA491B5FC130F137F48B6FC12075A48EB80
+3F383FF800EA7FE0138048C7FC5AA4157F7E6C6C13FFEBC003263FF01FEBFF8090B712C0
+7E6C14EF000314876CD9FE01138026003FE0C8FC2A2A7BA830>97
+D<EA3FFC487E12FFA2127F123F1200AAEC03FE91381FFF80027F13E091B57E90B612FC82
+ECFE079138F001FF4A6C13804A137F4AEB3FC091C7121F17E049140FA217F01607A8160F
+A217E07F161F6EEB3FC0A26EEB7F806E13FFDAF00313009138FC0FFE91B55A5E495CD97E
+7F13C0D93C1F90C7FC90380003FC2C3980B730>I<ECFFE0010713FC011F7F017F7F90B6
+12804815C048EB807F3907FC003F485A485A49EB1F804848EB0F004990C7FC127F90C9FC
+A25A5AA87E7EA27F003FEC07C06DEB0FE06C7E6D131F6C6C14C0D807FE133F9039FFC0FF
+806C90B5FCC615006D5B011F13F801075B01011380232A7AA830>I<913801FFE04A7F5C
+A28080EC0007AAEB03FE90381FFF874913E790B6FC5A5A481303380FFC00D81FF0133F49
+131F485A150F4848130790C7FCA25AA25AA87E6C140FA27F003F141F6D133F6C7E6D137F
+390FF801FF2607FE07EBFFC06CB712E06C16F06C14F76D01C713E0011F010313C0D907FC
+C8FC2C397DB730>I<49B4FC010713E0011F13F8017F7F90B57E488048018113803A07FC
+007FC04848133FD81FE0EB1FE0150F484814F0491307127F90C7FCED03F85A5AB7FCA516
+F048C9FC7E7EA27F003FEC01F06DEB03F86C7E6C7E6D1307D807FEEB1FF03A03FFC07FE0
+6C90B5FC6C15C0013F14806DEBFE00010713F8010013C0252A7CA830>I<EDFF80020713
+E0021F13F05C4A13F891B5FC491387903803FE079138FC03F0903907F800C04A1300A800
+3FB612C04815E0B7FCA36C15C0260007F0C7FCB3A9003FB512FE4880B71280A26C15006C
+5C25397DB830>I<D903FC13FF90261FFF8713C04913DF90B712E05A5A2607FE07138F90
+3AF801FE07C048486C6CC7FCA2497F001F8149133FA56D137F000F92C7FC6D5BA26C6C48
+5AEBFE0790B55A5D485C15C001DF5BD9C3FCC8FC01C0C9FCA37F7F6CB512F015FF6C15C0
+4815F0488148813A3FE0001FFE0180130148C8127F007E8100FE168048151FA56C153F00
+7FED7F006D5C6C6C495A01F013076CB4EB7FFC6C90B55A6C5D000115C06C6C91C7FC011F
+13FC010113C02B3E7DA730>I<EA3FFC487E12FFA2127F123F1200AAEC01FE91380FFF80
+023F13E091B57E90B67EA29138FE07FCECF8039138E001FE14C0EC8000A291C7FCA25BB3
+A23B3FFFF81FFFF8486D4813FCB500FE14FEA26C01FC14FC6C496C13F82F3880B730>I<
+14E0EB03F8A2497EA36D5AA2EB00E091C8FCA9381FFFF8487F5AA27E7EEA0001B3A9003F
+B612C04815E0B7FCA27E6C15C023397AB830>I<EC01C0EC07F0A2EC0FF8A3EC07F0A2EC
+01C091C7FCA990B512F04814F8A47EEB0003B3B3A5EC07F0A2123C007EEB0FE0B4131FEC
+3FC0147F90B512806C14005C6C5B000F13F0000313C01D4E7CB830>I<EA7FF8487EA412
+7F1200AB0203B512804A14C017E0A217C06E14809139001FE0004B5A4B5A4BC7FC4A5A4A
+5AEC0FF84A5A4A5A4A5A4A5A01FD7F90B57E8114F7ECE3F8ECC1FCEC81FEEC00FF497F49
+6D7E6F7E826F7E15076F7E6F7E3B7FFFF81FFFE0B56C4813F017F8A217F06C496C13E02D
+387FB730>I<387FFFF8B57EA47EEA0001B3B3A8007FB612F0B712F8A46C15F025387BB7
+30>I<02FC137E3B7FC3FF01FF80D8FFEF01877F90B500CF7F15DF92B57E6C010F138726
+07FE07EB03F801FC13FE9039F803FC01A201F013F8A301E013F0B3A23C7FFE0FFF07FF80
+B548018F13C0A46C486C01071380322881A730>I<EC01FE3A3FFC0FFF80267FFE3F13E0
+00FF90B57E90B67E7E6C9038FE07FCC6EBF8039138E001FE14C0EC8000A291C7FCA25BB3
+A23B3FFFF81FFFF8486D4813FCB500FE14FEA26C01FC14FC6C496C13F82F2880A730>I<
+49B4FC010F13E0013F13F8497F90B57E0003ECFF8014013A07FC007FC04848EB3FE0D81F
+E0EB0FF0A24848EB07F8491303007F15FC90C71201A300FEEC00FEA86C14016C15FCA26D
+1303003F15F86D13076D130F6C6CEB1FF06C6CEB3FE06D137F3A07FF01FFC06C90B51280
+6C15006C6C13FC6D5B010F13E0010190C7FC272A7CA830>I<EC03FE3A3FFC1FFF80267F
+FE7F13E000FF90B57E90B612FC6C816CEBFE07C69038F001FF4A6C13804A137F4AEB3FC0
+91C7121F17E049140FA217F01607A8160FA217E07F161F6EEB3FC0A26EEB7F806E13FFDA
+F00313009138FC0FFE91B55A5E495C6E13C0021F90C7FCEC03FC91C9FCAD383FFFF8487F
+B57EA26C5B6C5B2C3C80A730>I<49B413F8010FEBC1FC013F13F14913FD48B6FC5A4813
+81390FFC007F49131F4848130F491307485A491303127F90C7FC15015A5AA77E7E15037F
+A26C6C1307150F6C6C131F6C6C133F01FC137F3907FF01FF6C90B5FC6C14FD6C14F9013F
+13F1010F13C1903803FE0190C7FCAD92B512F84A14FCA46E14F82E3C7DA730>I<ED07F8
+3A3FFF803FFF486DB51280B512C302CF14C06C13DF6C9038FFFC3FD8001F13E09238801F
+809238000F004A90C7FC5C5C5CA25CA45CAF003FB512FC4880B7FCA26C5C6C5C2A287EA7
+30>I<90381FFC1E48B5129F000714FF5A5A5A387FF007EB800100FEC7FC4880A46C143E
+007F91C7FC13E06CB4FC6C13FC6CEBFF806C14E0000114F86C6C7F01037F9038000FFF02
+001380007C147F00FEEC1FC0A2150F7EA27F151F6DEB3F806D137F9039FC03FF0090B6FC
+5D5D00FC14F0D8F83F13C026780FFEC7FC222A79A830>I<EB0780497E131FA9003FB612
+E04815F0B7FCA36C15E026001FC0C7FCB216F8ED01FCA5ECE003010FEB07F814F09138FC
+1FF06DB512E06D14C016806D14009038007FFCEC1FF026337EB130>I<D83FFCEB3FFC48
+6C497E00FF14FFA2007F147F003F143F00001400B3A41501A2150315076D130F903A7FC0
+7FFFF891B612FC6D15FE7F6D4913FC6D9038F87FF8010001C0C7FC2F2880A630>I<3B3F
+FFC07FFF80486DB512C0B515E0A26C16C06C496C13803B01F80003F000A26D130700005D
+A26D130F017E5CA2017F131F6D5CA2EC803F011F91C7FCA26E5A010F137EA2ECE0FE0107
+5BA214F101035BA3903801FBF0A314FF6D5BA36E5A6E5A2B277EA630>I<3B3FFFC01FFF
+E0486D4813F0B515F8A26C16F06C496C13E0D807E0C7EA3F00A26D5C0003157EA56D14FE
+00015DEC0F80EC1FC0EC3FE0A33A00FC7FF1F8A2147DA2ECFDF9017C5C14F8A3017E13FB
+A290393FF07FE0A3ECE03FA2011F5C90390F800F802D277FA630>I<3A3FFF81FFFC4801
+C37FB580A26C5D6C01815BC648C66CC7FC137FEC80FE90383F81FC90381FC3F8EB0FE3EC
+E7F06DB45A6D5B7F6D5B92C8FC147E147F5C497F81903803F7E0EB07E790380FE3F0ECC1
+F890381F81FC90383F80FE90387F007E017E137F01FE6D7E48486D7E267FFF80B5FCB500
+C1148014E3A214C16C0180140029277DA630>I<3B3FFFC07FFF80486DB512C0B515E0A2
+6C16C06C496C13803B01FC0003F000A2000014076D5C137E150F017F5C7F151FD91F805B
+A214C0010F49C7FCA214E00107137EA2EB03F0157C15FCEB01F85DA2EB00F9ECFDF0147D
+147FA26E5AA36E5AA35DA2143F92C8FCA25C147EA2000F13FE486C5AEA3FC1EBC3F81387
+EB8FF0EBFFE06C5B5C6C90C9FC6C5AEA01F02B3C7EA630>I<001FB612FC4815FE5AA316
+FC90C7EA0FF8ED1FF0ED3FE0ED7FC0EDFF80003E491300C7485A4A5A4A5A4A5A4A5A4A5A
+4A5A4990C7FC495A495A495A495A495A495A4948133E4890C7127F485A485A485A485A48
+5A48B7FCB8FCA46C15FE28277DA630>I<ED3FF0913803FFF8140F5C147F16F09138FFF0
+0092C7FC495A5CB3A21303495A133F383FFFF0B55A5C91C8FC14C080003F7F38003FF813
+076D7E1301B3A2806D7E15F091387FFFF016F8141F8014039138003FF025477BBE30>I<
+127CA212FEB3B3B3AD127CA207476CBE30>I<EA7FE0EAFFFE6D7E8014F07EC66C7E1307
+6D7E1301B3A2806D7E15E091387FFFE06E13F8801407141F5C4A13E09138FFE00092C7FC
+495A5CB3A21303495A137F387FFFF0B5FC14C05C49C8FCEA7FE025477BBE30>I<017C13
+3848B4137C48EB80FE4813C14813C348EBEFFC397FEFFFF0D8FF8713E0010713C0486C13
+80D87C0113003838007C1F0C78B730>I E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Ff cmbx12 20.74 17
+/Ff 17 117 df<EE3FFF0307B512F8033F14FF4AB712E0020716F8021F16FE4AD9F8077F
+91B5D8C00014C04991C7003F7F4901FC020F7F49496E7F49496E7F49496E7F49496E7F4B
+81498590B5C96C7FA24849707FA24886A248864A824886A34886A448864A82A4481B80A8
+B51AC0B3AA6C1B80A86C1B006E5EA46C62A36C62A36C6D4C5BA36C62A26C6D4C5BA26C6E
+4B5B6D616F92B5FC6D96C7FC6D6D4A5B6D6D4A5B6D6D4A5B6D6D4A5B6D01FF023F5B6D02
+C090B55A6ED9F8075C021F90B648C8FC020716F8020116E06E6C1580030702F8C9FCDB00
+3F90CAFC527379F061>48 D<EE01F0EE07F8160F163F167FED01FF150F153F4AB5FC143F
+010FB6FCB8FCA54A7E14C0EBF000C8FCB3B3B3B3AE007FBA12F0A8447171F061>I<9238
+0FFFE04AB67E020F15F0027F15FE49B87E4917E0010F17F8013F8349D9C01F14FF9027FF
+FC0001814801E06D6C80480180021F804890C86C8048486F8048486F8001FF6F804801C0
+6E8002F081486D18806E816E18C0B5821BE06E81A37214F0A56C5BA36C5B6C5B6C5B0003
+13C0C690C9FC90CA15E060A34E14C0A21B80601B0060626295B55A5F624D5C624D5C4D91
+C7FC614D5B4D13F04D5B6194B55A4C49C8FC4C5B4C5B4C13E04C5B604C90C9FCEE7FFC4C
+5A4B5B4B5B4B0180EC0FF04B90C8FC4B5A4B5A4B48ED1FE0EDFFE04A5B4A5B4A90C9FC4A
+48163F4A5ADA3FF017C05D4A48167F4A5A4990CA12FFD903FC160749BAFC5B4919805B5B
+90BBFC5A5A5A5A481A005A5ABCFCA462A44C7176F061>I<923801FFFE033FEBFFF84AB7
+FC020F16E0023F16F84A16FE49B97E49DA003F80010F01F0010714F04901800101804948
+C880D97FF86F7F02E081496C834801FC6F148014FF486E6E14C08181481AE081A96C5C1B
+C06C4A5C6C5C6D90C815806D5AD90FF85D90CA150062606295B55A4D5C624D5C4D5C4D91
+C7FC4D13FC4D5B4CB512E0047F1480037FB548C8FC92B612F818C018F8F0FF806F15F092
+C7003F13FC050713FF050114C071807213F8727F727F867214801BC07214E01BF0A27214
+F81BFCA37214FEA31BFFEBFF80000313E0487F001F13FC487FA2487FA2B67EA31BFEA360
+1BFCA292C8FC6C1AF84A5D4A18F06C494B14E05C6C01C04B14C06C90C915804E14006C6D
+4B5B6C01F092B55A6C01FC4A5C27007FFFC001075C6D01FE013F14C0010F90B85A6D4DC7
+FC010117F8D9003F16E0020F93C8FC020015F0030749C9FC507378F061>I<F10FF04F7E
+193FA2197F19FF60A260606060A2606095B5FCA25F5F5FA25F5F5F5F18BFEFFF3F5EEE03
+FE17FCEE07F8160FEE1FF0EE3FE017C0167FEEFF804B13005E4B5A15074B5A4B5A5E153F
+4B5A4B5A93C7FC4A5A14034A5A5D4A5A141F4A5A4A5A5D4AC8FC5B495A5C495A130F495A
+495A5C137F495A4890C9FC5B485A1207485A485A5B123F485A485A90BC12FCA8CB02F8C7
+FCB3A20307B912FCA856727BF161>I<0170187001FEEF01F86D6C160F02F8167FDAFF80
+EC07FF03FE49B5FC92B85A6262A26297C7FC61616119E061614EC8FC18F86018C095C9FC
+17F817C0020701F8CAFC91CDFCB0923801FFFC031FEBFFE092B612FC020315FF020F16C0
+4A16F0027FD9003F7FDAFFF0010F13FE038001037F4AC76C8002F86E804A6F7F4A6F7F4A
+834A6F7F91C980137E017C707F90CAFC1B80A21BC0A2841BE0A51BF0A313FE3803FF8000
+0F7F4813F0487F5A80B5FCA41BE0A44E14C05C7E4A18805C4A5D6C90C9150001E0606C6C
+5E6D606C6C4C5B7F000794B55A6C6C6C4A5C6C6D4A5C6E4A5C26007FF8021F49C7FC6DB4
+027F5B6DD9F007B55A6D90B712E0010317806D4CC8FC6D6C15F8021F15C002034AC9FCDA
+003F13804C7376F061>I<94381FFF800403B512F8043F14FE4BB77E030782031F16F003
+7F8292B5D8FC017F02039139C0001FFE4A49C7EA07FF021F01F8804A496E13804A01C014
+0F91B548023F13C04991C85A494992B5FC49494A14E0495B495E5D5B495BA290B55A5A5D
+487114C0A24891C91480731300735A48F00FF896C8FC485BA45AA44849903803FFE0041F
+13FE047FEBFFC04BB612F84B81030F15FFB590261FF8038092273FE0007F13E00480011F
+7F4BC76C7F03FE6E7F4B6E7FDAFDF86E7FDAFFF017804B6E14C01BE05D7313F05D1BF8A2
+92C914FC85A21BFE5CA31BFFA26C5BA87EA4807EA21BFE7EA37E1BFC6E5E6C1AF8A27E6F
+17F06C95B512E06D7F1BC06D6D4A14806D4C1400816D6D4A5B6D6D4A5B6D01FF4A13F001
+006E017F5B6ED9F007B55A6E90B7C7FC020F5E020316F86E16E0DA003F1580030702FCC8
+FCDB007F1380507378F061>I<EA03FCA2487E7F14C0ECFFF092BA12C0A45AA31C801C00
+63A2486263636363A26398C7FC48616249CAEA0FF801F0171F494D5A4F5A49604F5A007F
+4D90C8FC60494C5A4E5A614E5A4E5A48CA127F4E5A4D5B96C9FCCA485A4D5A170F4D5A60
+173F4D5A6017FF4C5BA25E4C90CAFCA24C5A161FA24C5AA2167FA24C5AA25DA24B5BA25D
+A25DA25F5DA25DA35DA392B5FCA25FA25CA45CA75CAD6E5CA26E91CBFCA26E5BED3FF8ED
+0FE0527775F461>I<93B57E031F14FC92B77E020316F0020F16FC023F16FF4A8349B5D8
+800314E04901F8C7003F7F4901C0020F7F4990C800037FD91FFC6F7F49486F6C7E137F4A
+7013804948827313C05A4A821BE05AA285487FA38080806E5E8003C017C08103F85D03FE
+17806F6C5C6C6F160004F05C04FC4A5A6C6F5D706C13FFDDE0015B6CDCF8035BDDFC0F13
+C06DDBFF1F5B6D93B5C7FC19FC6D17F06D5F6D17806D17E06D836D6C16FC6E16FF020F83
+6E17E06E83020F83023F8391B97E4984010701F0178049D9C07F16C0013FD9801F16E049
+EB00074948010116F048497F4849023F15F84849140F4A6E15FC48160148496E6C14FE4A
+151F488391C9120348050014FF193F49838500FF84854983A28586A3861BFEA27FA2007F
+1AFC7F1A7F1BF86C7FF2FFF06C7F6E4C13E06C6D4C13C06C6D5E6E4C13806C6D4C13006C
+6D6CED7FFE6C02E04A485A013F01FC020F13F06D9026FFC001B55A010791B712806D95C7
+FC010017FC021F16F002071680DA007F02FCC8FC030191C9FC507378F061>I<93B5FC03
+1F14F092B612FE02076F7E021F16E04A16F891B87E49DAF00713FF0107DA0001804901FC
+6D6C7F49496E7F49496E7F49496E7F90B5486E7F484A8048854891C86C7FA2487114805C
+481AC0A2487213E0A2484918F0A31BF8A2B5FCA27313FCA51BFEA71BFF61A27EA396B6FC
+7EA2806C5FA27E606C7F607E6C6E5C6CEF1FBF6D6DEC3F3F6D6D147F6D6D14FE6D6DEB01
+FC6D01FE130701019039FFC01FF86D91B500F014FE023F15C06E15800203ECFE00DA007F
+13F8030713C092C9FC4F13FCA41BF8A31BF0D91FF093B5FCEB7FFC496C18E0487F486E17
+C06048801B804E1400A26260624E5B4B5C626C91C8485B4A4B5B4A92B55A6C01F04A91C7
+FC02804A5B6C01E0020F5B6D6C023F13F002FE91B55A90273FFFE00F5C6D90B7C8FC0107
+16FC6D16F0010016C0023F92C9FC020714F09126007FFECAFC507378F061>I<96267FFF
+E01670063FB6ED01F80503B700F01403053F04FC14074CB96C130F040706E0131F043F72
+133F93BA00FC137F0303DC00076D13FF030F03C09039003FFF814B02FCC8000713C3037F
+02E0030113F792B600806F6CB5FC02034ACA121F4A02F8834A02E0834A4A1701027F4A83
+91B548CC7E494A85495C4C854988494A85494A85495C8A4991CDFC90B54886A2484A1B7F
+A2481E3F5D481E1F5D5A1F0FA2485CA3481E075DA2F703F0489BC7FCA45DA2B6FCB27EA2
+81A47EA2F703F06FF307F87EA36C80A21F0F7E6F1CF07E6F1B1F7E20E06C6E1B3F816DF5
+7FC06D80F7FF806D806D6E4F13006D6E616D525A826D6E4F5A6D6E4F5A6E6D6C4E5A021F
+6EF0FFE06E6E4D5B6E02F84D5B6E02FE050F90C7FC02006E6CEE3FFE6F02F0EEFFFC031F
+02FE03035B6FDAFFC0021F13E0030303FF0103B55A030093B7C8FC043F18FC040718F004
+0118C0DC003F94C9FC050316F8DD003F1580DE007F01F0CAFC757A75F78C>67
+D<92383FFFF80207B612E0027F15FC49B87E010717E0011F83499026F0007F13FC4948C7
+000F7F90B502036D7E486E6D806F6D80727F486E6E7F8486727FA28684A26C5C72806C5C
+6D90C8FC6D5AEB0FF8EB03E090CAFCA70507B6FC041FB7FC0303B8FC157F0203B9FC021F
+ECFE0391B612800103ECF800010F14C04991C7FC017F13FC90B512F04814C0485C4891C8
+FC485B5A485B5C5A5CA2B5FC5CA360A36E5DA26C5F6E5D187E6C6D846E4A48806C6D4A48
+14FC6C6ED90FF0ECFFFC6C02E090263FE07F14FE00019139FC03FFC06C91B6487E013F4B
+487E010F4B1307010303F01301D9003F0280D9003F13FC020101F8CBFC57507ACE5E>97
+D<93387FFF80030FB512FC037FECFF804AB712E0020716F8021F16FE027FD9F8077F49B5
+D8C000804991C7003F13E04901FC020F7F49496E7F49498049496E7F49496E7F90B55A48
+727E92C914804884485B1BC048841BE0485BA27313F05AA25C5AA21BF885A2B5FCA391BA
+FCA41BF002F8CCFCA67EA3807EA47E806CF103F0F207F86C7F1A0F6C6E17F06C191F6F17
+E06C6E163F6D6DEE7FC06D6D16FF6D6D4B13806D6D4B13006D6D6CEC0FFE6D02E0EC3FFC
+6D02F8ECFFF86D9126FFC00F5B023F91B65A020F178002034CC7FC020016F8031F15E003
+0392C8FCDB000F13E04D507BCE58>101 D<903801FFFCB6FCA8C67E131F7FB3AD95380F
+FFE095B512FE05036E7E050F15E0053F15F84D81932701FFF01F7F4CD900077FDC07FC6D
+80DC0FF06D80DC1FC07F4C48824CC8FC047E6F7F5EEDFDF85E03FF707F5EA25EA25EA293
+C9FCA45DB3B3A6B8D8E003B81280A8617879F76C>104 D<902601FFFCEC7FFEB6020FB5
+12F0057F14FE4CB712C0040716F0041F82047F16FE93B5C66C7F92B500F0010F14C0C66C
+0380010380011F4AC76C806D4A6E8004F06F7F4C6F7F4C6F7F4C8193C915804B7014C086
+1DE0A27414F0A27414F8A47513FCA57513FEAF5113FCA598B512F8A31DF0621DE0621DC0
+621D806F5E701800704B5B505B704B5B7092B55A04FC4A5C704A5C706C010F5C05E0013F
+49C7FC9227FE7FFC01B55A70B712F0040F16C0040393C8FC040015F8053F14C0050301F0
+C9FC94CCFCB3A6B812E0A85F6F7ACD6C>112 D<902601FFF8EB07FEB691383FFFC094B5
+12F00403804C14FE4C8093261FFC3F138093263FE07F13C0DC7F80B5FCC66C5D011FDAFE
+0114E06DEBF9FC16F815FB16F016E015FF16C07114C05E72138095381FFE0093C76C5AF0
+01E095C8FCA25DA65DB3B3A2B812F8A8434E7ACD4F>114 D<15FFA75CA55CA45CA25CA2
+5CA25CA25C91B5FCA25B5B5B131F5B90B9FC120FBAFCA6D8000791C9FCB3B3A3F01FE0AE
+183F7014C07F187F7014806D16FF826D4B13006E6D485AEEFE0F6E90B55A020F5D6E5D02
+0115C06E6C5C031F49C7FC030113F03B6E7CEC4B>116 D E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fg cmsl10 10.95 38
+/Fg 38 91 df<007FB5FCA2B512FEA418067C961E>45 D<121EEA3F80EA7FC012FFA413
+80EA7F00123C0A0A788919>I<1703EF0780170FA2EF1F00A2173EA25FA25FA24C5AA24C
+5AA24C5AA24C5AA24CC7FCA2163E167E167C5EA24B5AA24B5AA24B5AA24B5AA24BC8FCA2
+153EA25DA25DA24A5AA24A5AA24A5AA24A5AA24AC9FCA2143EA25CA25CA2495AA2495AA2
+495AA2495A131F91CAFC133EA25BA25BA2485AA2485AA2485AA2485AA248CBFCA2123EA2
+5AA25AA21270315B7FC32D>I<EC07F8EC3FFF9138FC0FC0903903F003E0903907C001F0
+D90F8013F849C7FC013E14FC017E147C017C147E13FC485AA20003157F5B1207A2120F5B
+A2121F16FF5BA2123FA44848EB01FEA648C7EA03FCA5ED07F8A25A16F0A2150F16E0A3ED
+1FC0A21680007E143F1600157E123E003F5C4A5AD81F805B000FEB07E06C6C485A2603F0
+3FC7FC3800FFFCEB1FE0283F79BC2D>I<157015F014011407143F903803FFE0137FEBFF
+CFEBF80F1300141F15C0A5143F1580A5147F1500A55C5CA513015CA513035CA513075CA5
+130F5CA3131F497EB612F8A31D3D78BC2D>I<EC01FE91380FFFE0023F13F89138FC07FC
+903901E001FE903907C000FF49C7EA7F80011E15C0163F4915E05B0170141F13FF80A35A
+163FA26C90C7FC137E0118EC7FC090C8FCEEFF80A24B1300A24B5A5E4B5A4B5A4B5A5E4B
+5A4BC7FC15FEEC01F84A5A4A5A4A5A4AC8FC143E5C5CEB01E04948130E49485B49C7FC13
+1E495C13705B48485C484814F0000FB6FC5A485D5AB7FC5EA22B3D7CBC2D>I<EC07FC91
+383FFF809138F80FE0903903C007F09039078003FC90380F0001011C14FE013C14FF137F
+1480EBFFC0A31480A291380003FE137E90C7FCED07FC16F8150F16F0ED1FE016C0ED3F80
+ED7E005DEC07F0903803FF8015F090380001FC6E7EED7F80ED3FC0A2ED1FE016F0A316F8
+A4120EEA3F80486C133F16F012FFA216E0157F5B48C7EAFFC000F0158000704913001278
+6C495A003EEB07F86C495A390FE03FE00003B51280C649C7FCEB1FE0283F7ABC2D>I<16
+1C163C167CA216FCED01F815031507150FA2151DED3BF0157315E315C31401EC03839138
+0707E0140E141CA2143814709138E00FC0EB01C014801303EB0700130E49EB1F805B1330
+13705B485A4848EB3F0090C7FC5A120E5A5A48147E1260B8FCA3C73801FE00A25DA41403
+A25DA314074A7E0107B512F8A3283E7BBD2D>I<01061403D90780131F90390FF801FE91
+B512FC16F816F016E0168049EBFE0015F890381C7FC091C8FCA3133C1338A513781370A2
+EC1FE0ECFFF8903873E03E9038FF001F01FCEB0F804914C049EB07E04914F049130390C7
+FC16F8A61507A21206EA3F80487EA2150F00FF15F0A24914E090C7121F00FC15C000F014
+3F00701580ED7F0012786C14FE4A5A6C495A390F800FE03907E03FC06CB5C7FCC613FCEB
+1FE0283F7ABC2D>I<ED7F80913803FFE091380FC0F091383E003802FC131C495A494813
+FE903807E003EB0FC090381F8007133FD97F0013FC01FE1303ED01F0484890C7FC1203A2
+485AA2120F5BA2001FEB3F809038E0FFE0393FE3C0F89038E7007C01EE7F01FC133F4848
+EB1F80A24914C05B16E0A2485AA216F05BA2ED3FE0A290C7FCA4157F16C0A316804814FF
+007E1500007F5C14016C5C4A5A6C6C485A4A5A6C6C485A2607E07FC7FC3803FFFEC613F8
+EB3FC0273F78BC2D>I<EA0380120713E090B712805AA217005E485D5E001EC85A484A5A
+00385D150300784A5A00704AC7FC151E5D485CC8127015F04A5A4A5A4A5A4AC8FC140E14
+1E5C147C14785C1301495AA213075C130F495AA2133F91C9FC5BA25B5B1201A312035BA2
+1207A3485AA5121F5BA26C5AEA0780294074BD2D>I<EC03FC91381FFF8091387C07E090
+3901F001F0903903C000F84948137C49C7123E131E013E141F133C137C137813F8A3163F
+486C143E167E6D147C6C6C14FC6E13F89138C001F09138F003E090397FF807C09138FC0F
+0090383FFF3E6D13F86D13E06D7F01017F8101077F90391F1FFF80D93E0F13C0EBF80726
+01F00113E048486C13F04848137F4848131F001FEC0FF890C71207003E1403A2481401A3
+00FC15F05AA3ED03E0A26CEC07C0007C1580007E140F003EEC1F00003F143E6C6C5B6C6C
+485A3907F00FE00001B512806C6C48C7FCEB0FF0283F7ABC2D>I<EC07F8EC3FFE9138FC
+0F80903901F007C0903907E003E0D90FC013F090381F8001013F14F8EB7F004914FC4848
+1300A24848EB01FEA21207A3485AA41503121F5BA31507A2000F15FC150FA2151F120715
+3F000315F86C6C137F000014EF90387C01CF90393E078FF090380FFE1FEB03F890C713E0
+A2ED3FC0A3ED7F8016005D003F5C487E4A5A00FF495A5D4A5A49485A48495A007049C7FC
+0078137E383E03FC381FFFF06C13C0D801FEC8FC273F79BC2D>I<13F0EA01FC1203EA07
+FEA313FCA2EA03F8EA01E0C7FCB3121EEA3F80EA7FC012FFA41380EA7F00123C0F2778A6
+19>I<17E016011603831607A2160FA2161F83163FA2167F167716F7EEE7FCED01E316C3
+150316831507EE03FEED0F01150E151E151C153C03387FED7800157015F05D4A4880177F
+4A5AA24AC7FCA2020E81173F5C021FB6FC5CA20270C7EA3FE0171F5CA2495AA249488117
+0F49C8FCA2130EA24982013C1507A2137CD801FE4B7E2607FF80EC3FFEB500F00107B512
+FC19F85E3E417DC044>65 D<013FB7FC18E018FC903B007FE00007FE6E48903801FF8094
+38007FC05DF03FE0F01FF0A3027F16F892C8FCA54A16F04A153F19E0187F19C0F0FF8001
+014B13004A4A5A4D5AEF1FF04D5ADC03FFC7FC49B612F8EFFF8002F8C7EA3FE0EF0FF0EF
+07FC717E010715014A81711380A319C0130F5CA5011F4B13805C19005F601707013F4B5A
+4A4A5A4D5A4D5A017F913801FF8001FF020F90C7FCB812FC17F094C8FC3D3E7DBD40>I<
+DCFFC01338030F01F01378037F01FC13F0913A01FF803F01913A07FC000781DA1FE0EB03
+C3DA7FC0EB01E74AC812FF4948ED7FE0D907FC153F495A4948151F495A4948150F494816
+C018074890C9FC485AA2485A000F1880491603121FA248481607A295C7FC485AA412FF5B
+A75BA2181C183C1838A27F007F1778187018F0003F5F6D150160001F16036C6C4B5A95C7
+FC6C6C5D6C6C151E6C6C5D6C6C15F86D6C495A6D6CEB07C0D91FF0EB1F80D907FE01FEC8
+FC0101B512F86D6C13E0DA07FEC9FC3D4276BF42>I<013FB7FC18E018F8903B007FF000
+0FFE6E48EB01FF9438007FC04B6E7E180F85727E727E147F4B6E7EA2727EA302FF178092
+C9FCA54918C05CA41A8013034A5DA41A0013074A5DA261A24E5A130F4A5E180F61181F61
+011F4C5A5C4E5A4EC7FC4D5A4D5A013F4B5A4A4A5AEF3FE0EF7F80017F4A48C8FC01FFEC
+1FFCB812F0178004FCC9FC423E7DBD45>I<013FB812F8A39026007FF0C7127F6E48140F
+18034B14011800A31978147F4B1570A502FF147092C7FCA3190017F0495D4A1301A21607
+161F91B6FC495DA29138FC003F160F1607160301075D5CA219E0180119C0010FEC07004A
+90C712031980A218071900011F5E5C181EA2183E183C013F167C4A15FC4D5A1707017F15
+1F01FF4AB45AB9FCA2603D3E7DBD3E>I<013FB812E0A3903A007FF000016E48EB003F18
+0F4B14071803A31801147F4B15C0A514FF92C71270A395C7FC17F0495D5C160116031607
+161F49B65AA39138FC003F160F160701075D4A1303A5010F4AC8FC5C93C9FCA4131F5CA5
+133F5CA3137FEBFFF0B612F8A33B3E7DBD3B>I<4BB46C1370031F01F013F0037F9038FC
+01E0913A03FF807E03913A0FF8000F83DA1FE0EB07C7DA7F80EB01EF4AC812FFD903FE16
+C04948157F4948153F495A4948151F495A4948168091C9120F5A485AA2485A000F180049
+82121FA248485EA295C7FC485AA412FF5BA6043FB512E05BA29339001FFC00715AA2607F
+127FA2171F123F6D5EA2121F7F000F163F6C7E6C6C4B5A7F6C6C15FF6C6DEB01EFD93FC0
+EB07C7D91FF0EB1F87D907FE9038FE03800101B5EAF8016D6C01E0C8FCDA07FEC9FC3C42
+76BF47>I<013FB5D8F807B6FC04F015FEA29026007FF0C7380FFE006E486E5AA24B5DA4
+180F147F4B5DA4181F14FF92C85BA4183F5B4A5EA491B8FC5B6102FCC8127FA318FF1307
+4A93C7FCA45F130F4A5DA41703131F4A5DA41707133F4A5DA3017F150F496C4A7EB6D8E0
+1FB512FC6115C0483E7DBD44>I<011FB512FC5BA29039003FF8006E5AA25DA5143F5DA5
+147F5DA514FF92C7FCA55B5CA513035CA513075CA5130F5CA5131F5CA3133F497E007FB5
+12F0A2B6FC263E7EBD21>I<013FB500F8010FB5FC4C5BA29026007FF0C7000313E06E48
+6E130019FC4B15F04E5A4E5A4E5A061EC7FC027F5D4B5C4D5A4D5AEF07804DC8FC02FF14
+1E92C7127C5FEE01E04C5A4C5A49021FC9FC4A5B5E4C7E5D03077F01035B9139FC1F3FE0
+153C4B6C7E15F09139FFE00FF84913C092380007FC5C4A6D7E5C707E130F4A6D7F84177F
+717EA2011F6F7E5C717EA2717EA2013F6F7E5C84A2017F83496C4A13E0B600E0017F13FF
+A24B90B6FC483E7DBD47>75 D<013FB512FEA25E9026007FF8C8FCEC3FE0A25DA5147F5D
+A514FF92C9FCA55B5CA513035CA513075CA21838A21870130F5CA218E0A3011F15014A15
+C01703A21707EF0F80013F151F4A143F177FEFFF00017F140301FF143FB9FC5FA2353E7D
+BD39>I<90263FFFF093381FFFF85013F0629026007FF8EFF000023F4D5AA2023B933801
+DFC0A2DA39FCED039FA2F1073F14790271040E5BEC70FE191C19381A7F02F01670DAE07F
+94C7FC19E0A2F001C06201016D6C495A02C05FF00700A2180E6F6C14010103161C028003
+385BA218706F7EF0E00313070200DA01C05BA2923907F00380A294380700075B010E9026
+03F80E5C5FA25F190F011E6D6C5A011C605FA2EEFDC0DB00FF141F013C5D013860013C92
+C7FC017C5C01FE027E143F2607FF80017C4A7EB500FC037FB512E004785E4A1338553E7C
+BD53>I<90263FFFE0023FB5FC6F16FEA29026003FF8020313C0021F030013004A6C157C
+023B163C6F15381439810238167802787FDA707F157082153F82031F15F002F07FDAE00F
+5D8215078203031401010180DAC0015D82811780047F1303010315C04A013F5C17E0161F
+17F0040F1307010715F891C7000791C7FC17FC160317FE04015B4915FF010E6E130E188E
+177F18CEEF3FDE011E16FE011C6F5AA2170FA21707133C01386F5A133C017C150113FE26
+07FF801400B512FC18705C483E7DBD44>I<923803FF80031F13F09238FE01FE913903F0
+003FDA0FC0EB1FC0DA3F80EB07E0027EC76C7E49486E7E49488149486E7E4948157F495A
+013F17804948ED3FC049C9FCA24848EE1FE012035B000718F05B120FA2485A19F8123F5B
+A2127FA219F04848163FA5F07FE0A35BF0FFC0A219805F19007F4D5A127F4D5A60003F16
+0F6D5E001F4C5A4D5A6C6C4B5A95C7FC6C6C15FE00034B5A6C6C4A5A6C6C4A5A017FEC1F
+C06D6C495AD90FE001FEC8FC903903F807F80100B512C0DA0FFCC9FC3D4276BF47>I<01
+3FB612FEEFFFE018F8903B007FF0000FFC6E48EB01FF7113804BEC7FC0183F19E0F01FF0
+A2147F5D19F8A402FFED3FF092C8FCA219E0A2F07FC05B4AEDFF8019004D5A4D5AEF0FF8
+0103ED3FE04A903801FF8091B648C7FC17F002FCCAFCA213075CA5130F5CA5131F5CA513
+3F5CA3137F497EB612E0A25D3D3E7DBD3E>I<013FB612F017FF18E0903B007FF0003FF8
+6E48EB07FCEF01FE4B6D7EF07F8019C0183F19E0147F4B15F0A502FFED7FE092C8FCA219
+C0F0FF80A2494B13004A5D4D5AEF0FF04D5AEF7F800103DA07FEC7FC91B612F017809139
+FC0007E0EE03F8EE00FC0107814A147F717EA284A2130F5CA484011F157F5CA41902013F
+17075CA2F0F00F017F170E496C143FB600E0011F131C94380FF83C4B01071378CA3801FF
+E09438003F8040407DBD43>82 D<9238FF80070207EBE00F021FEBF81E91387F00FE02FC
+EB1F3ED903F0EB0FFE49481307494813034AEB01FC49C7FC491400133E137E177C491578
+A57F1770A26D1500808080EB7FFEECFFE06D13FEEDFFC06D14F06D14FC01038001008014
+3F02031480DA003F13C015031500EE7FE0163F161FA2160F121CA31607160F003C16C0A3
+1780003E151F1700007E5D007F153E6D5C16FC01E0495AD87DF0495AD8FCFCEB0FC03AF8
+7F803F8027F01FFFFEC7FCD8E00713F839C0007FC030427BBF33>I<0007B912F0A33C0F
+FE000FF8003F01F0160F01C04A13034848160190C7FC121EF000E048141F5E1238A21278
+1270153F5E5AA3C81600157F5EA515FF93C9FCA55C5DA514035DA514075DA5140F5DA314
+1FEC7FFC0003B7FCA33C3D76BC42>I<B600E090B512FC4B15F8A2000101C0C7000F1300
+6C49EC03FCEF01F091C9FC60A317015A495EA417031203495EA4170712074993C7FCA45F
+120F49150EA4171E121F49151CA4173C123F491538A31778177017F05F001F15015F1603
+6D4A5A000F93C8FC5E6C6C141E6C6C5C000115F86C6C495A017FEB07C090393FC03F8090
+260FFFFEC9FC010313F89038007FC03E4073BD44>I<B6020FB5FC19FEA2000301E00201
+13E06C01809138007F8091C9EA7E006C173C18386E15781870017F16F0604D5A804D5A13
+3F4DC7FCA26E140E171E011F151C173C17386E1478010F15705FA24C5A8001074A5AA24C
+C8FC5E6E130E0103141E161C163C16386E5B13015EA24B5A14FF6D495AA24BC9FC5D158E
+EC7F9E159C15B8A215F0143F5DA25DA26E5AA292CAFCA2140E404074BD44>I<B6017FB5
+D88007B512804A1A00A2000701C0010101E0C713F06C90C80180EC3FC06C48735A99C7FC
+057F150E1B1E6D191C6C1A3C1B3805FF15787214705E636EEB03BF017F4E5AEE073F505A
+040E7F051F4AC8FC161C6E170E013F143862167804706D5BEEF00F04E05D90381FE00104
+C015F003035E0480140106F85B9226070007130302F05F010F010E150797C9FC5D190E4B
+EB03FC616E5A01075F5D61DAF9C014FE05015BECFB8002FF6F5A7F92C75CA24A93CAFC83
+5C606D5A605C604A15781870594074BD5D>I<010FB500F090B512F85B5FD9003F902680
+003F1300DA0FFEC7EA1FF84BEC0FE00207168096C7FC6E6C141E181C6E6C143C606E6D5B
+4D5ADB7FC05B4D5A92383FE0074DC8FC92381FF01E171C6F6C5A5F923807FCF0EEFDE06F
+B45A5F6F90C9FCA26F7FA2707EA216FF4B7FED03DF9238079FF0ED0F1F92380E0FF8151C
+92383C07FC15784B6C7EEC01E04B6C7EEC038002076D7F4AC7FC021E6E7E5C02386E7E5C
+02F06E7E495A49486E7E130749486E7E497E017F4B7E2603FFF091383FFF80007F01FC49
+B512FEB55CA2453E7EBD44>I<B66C0103B51280A3000101F0C8EBF0006C49ED7FC06D48
+6FC7FC6E153E013F163C606D6C5D606D6C4A5A17036D6C4A5A95C8FC6E140E0103151E5F
+6D6C14385F6D6D13F04C5ADA7FC05B4C5AEDE007023F49C9FC161E91381FF01C5E91380F
+F8785E6E6C5AEDFDC015FF6E5B93CAFC6E5AA35DA21403A45DA21407A45DA2140FA4141F
+4A7E013FB512F0A3413E75BD44>I<010FB712FEA39239C00007FCD91FFCC7EA0FF814F0
+4AEC1FF00280EC3FE091C8EA7FC0013EEDFF80A2013C4A13004C5A494A5A4C5A13704C5A
+4C5A494A5A4C5AA290C74890C7FC4B5A4B5A4B5AA24B5A4B5A4B5A4B5AA24A90C8FC4A5A
+4A5A4A5AA24A5A4A5A4A48EB01C04A5AEF03804990C7FC495A495A494814071800495A49
+485C495A495A171E4890C8123E485A4848157E484815FE4C5A484814074848141F4848EB
+01FFB8FC5FA2373E7BBD38>I E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fh cmbx10 10.95 49
+/Fh 49 122 df<EDFFF8020F13FF027F8049B612E001079038C01FF090390FFE0007D91F
+F8497ED93FE0131F4948497E13FF5C5A91C7FCA2705A705AEE03C093C8FCA6EE03FCB8FC
+A50001903880001F160FB3AB007FD9FE03B512F0A534407EBF3A>12
+D<B612E0A91B097F9823>45 D<161C163E167EA216FE16FC150116F8A2150316F0A21507
+16E0150F16C0A2151F1680153F1600A25D157E15FE5DA214015DA214035D14075DA2140F
+5D141F5DA2143F92C7FC5C147EA214FE5CA213015C13035CA213075C130F5CA2131F5C13
+3F91C8FCA25B137EA213FE5B12015BA212035B12075BA2120F5B121F5BA2123F90C9FCA2
+5A127E12FE5AA25A1278275B7AC334>47 D<ECFFE0010713FC011F13FF017F14C0D9FFE0
+7F489038803FF03A03FE000FF848486D7EA248486D7E001F81A348486D1380A3007F16C0
+A500FF16E0B3A2007F16C0A5003F16806D5BA2001F1600A2000F5D6D13076C6C495A6C6C
+495A6C6D485A6C9038E0FFE06DB55A011F91C7FC010713FC010013E02B3D7CBB34>I<14
+0F143F5C495A130F48B5FCB6FCA313F7EAFE071200B3B3A8007FB612F0A5243C78BB34>
+I<903803FF80013F13F890B512FE00036E7E4881260FF80F7F261FC0037F4848C67F486C
+6D7E6D6D7E487E6D6D7EA26F1380A46C5A6C5A6C5A0007C7FCC8FC4B1300A25E153F5E4B
+5AA24B5A5E4A5B4A5B4A48C7FC5D4A5AEC1FE04A5A4A5A9139FF000F80EB01FC495A4948
+EB1F00495AEB1F8049C7FC017E5C5B48B7FC485D5A5A5A5A5AB7FC5EA4293C7BBB34>I<
+903801FFE0010F13FE013F6D7E90B612E04801817F3A03FC007FF8D807F06D7E82D80FFC
+131F6D80121F7FA56C5A5E6C48133FD801F05CC8FC4B5A5E4B5A4A5B020F5B902607FFFE
+C7FC15F815FEEDFFC0D9000113F06E6C7E6F7E6F7E6F7E1780A26F13C0A217E0EA0FC048
+7E487E487E487EA317C0A25D491580127F49491300D83FC0495A6C6C495A3A0FFE01FFF8
+6CB65A6C5DC61580013F49C7FC010313E02B3D7CBB34>I<ED01F815031507A2150F151F
+153FA2157F15FF5C5CA25C5CEC1FBFEC3F3F143E147C14FCEB01F814F0EB03E01307EB0F
+C0EB1F801400133E137E5B485A5B485A1207485A5B48C7FC5A127E5AB812F8A5C8387FF8
+00AA49B612F8A52D3C7DBB34>I<00071538D80FE0EB01F801FE133F90B6FC5E5E5E5E93
+C7FC5D15F85D15C04AC8FC0180C9FCA9ECFFC0018713FC019F13FF90B67E020113E09039
+F8007FF0496D7E01C06D7E5B6CC77FC8120F82A31780A21207EA1FC0487E487E12FF7FA2
+1700A25B4B5A6C5A01805C6CC7123F6D495AD81FE0495A260FFC075B6CB65A6C92C7FCC6
+14FC013F13F0010790C8FC293D7BBB34>I<EC07FF023F13C049B512F001078049EB03FC
+90383FF80090397FE001FE9038FFC0034849487E48495AA2485A120FA2485A6F5A003F6E
+5A6F5A92C8FC485AA21402EC3FFE00FF496C7E01F9B512E001FB809138E03FF89039FF80
+0FFC4A6C7E825B6F13804915C0A317E05BA4127FA5123FA26D15C0121FA2000F4A13806D
+150012076C6C495A6C6D485A6C9038E07FF86DB55A6D5C6D1480010749C7FC010013F02B
+3D7CBB34>I<121F7F13F890B712F0A45A17E017C0178017005E5E5A007EC7EA01F84B5A
+007C4A5A4B5A4B5A93C7FC485C157E5DC7485A4A5AA24A5A140F5D141F143F5D147FA214
+FF92C8FC5BA25BA3495AA3130FA5131FAA6D5A6D5A6D5A2C3F7ABD34>I<ECFFF0010713
+FE011F6D7E017F14E09039FFC07FF03A01FE001FF848486D7E48486D7E1503485A828112
+1FA27F7F7F6D5B02C05B14F06C6D485A9138FE0FF89138FF9FF06CECFFE06C5D5E6C92C7
+FC6C816D14E0011F80498090B67E48812607FE3F7F48486C1480381FF807D9F00114C048
+486C7E007F8049010F13E0150348487F81167FA2163FA36D15C0127FEE7F807F6C6CECFF
+006C6C5B01FEEB07FE3A0FFFC03FFC6C90B55A000115E06C6C5C011F49C7FC010113F02B
+3D7CBB34>I<903801FFE0010F13FC013F13FF90B612C04801E07F489038003FF048486D
+7E000F6E7E485A6F7E123F48488081178012FFA217C0A517E0A4007F5CA4003F5C6C7E5D
+6C7E00075C3903FF80FB6C13FF6C6C13F36D13C3010F018313C090380008031400A24B13
+80EA03F0487E486C1500487E4B5AA25E151F4B5A495C6C48EBFFE049485B2607FC0F5B6C
+B6C7FC6C14FC6C14F06D13C0D90FFEC8FC2B3D7CBB34>I<16FCA24B7EA24B7EA34B7FA2
+4B7FA34B7FA24B7FA34B7F157C03FC7FEDF87FA2020180EDF03F0203804B7E02078115C0
+82020F814B7E021F811500824A81023E7F027E81027C7FA202FC814A147F49B77EA34982
+A2D907E0C7001F7F4A80010F835C83011F8391C87E4983133E83017E83017C81B500FC91
+B612FCA5463F7CBE4F>65 D<B812F8EFFF8018F018FC8426003FFCC7EA3FFF050F138071
+13C07113E08319F0A27113F8A719F05FA24D13E019C04D13804D1300EF3FFE933801FFF8
+91B712E0188018F818FE02FCC7380FFF80050313C07113E07113F019F8F07FFCA2F03FFE
+A219FFA38460A419FE187FA2F0FFFC4D13F85F4D13F0053F13E0BA12C0190018FC18F095
+C7FC403E7DBD4A>I<922607FFC0130E92B500FC131E020702FF133E023FEDC07E91B7EA
+E1FE01039138803FFB499039F80003FF4901C01300013F90C8127F4948151FD9FFF8150F
+48491507485B4A1503481701485B18004890CAFC197E5A5B193E127FA349170012FFAC12
+7F7F193EA2123FA27F6C187E197C6C7F19FC6C6D16F86C6D150119F06C6D15036C6DED07
+E0D97FFEED0FC06D6CED3F80010F01C0ECFF006D01F8EB03FE6D9039FF801FFC010091B5
+5A023F15E002071580020002FCC7FC030713C03F407ABE4C>I<B812F8EFFF8018F018FC
+18FF26003FFCC76C13C005077F05017F716C7E727E727E727E721380A27213C0A27213E0
+A21AF084A21AF8A41AFCA5197FA319FFA51AF8A41AF0A2601AE0A24E13C0A24E13804E13
+00604E5A4E5A4D485A050713E0057F5BBA5A4EC7FC18F818C005F8C8FC463E7DBD50>I<
+BAFCA4198026003FFEC7123F1707170183183FA2181FF00FC0A31807EE07C0A3F003E0A3
+160F95C7FC161F163F16FF91B6FCA54AC6FC163F161F040F147CA2160719F8A593C71201
+A219F01803A21807A2180FF01FE0183F18FF1703173FBAFCA219C0A33E3D7DBC45>I<B9
+12FEA48426003FFEC77E170F1703170084A284F01F80A3180FA2EE07C0A2F007C0A4040F
+90C7FCA2161F163F16FF91B6FCA54AC6FC163F161F160FA21607A693C9FCACB712E0A53A
+3D7DBC42>I<922607FFC0130E92B500FC131E020702FF133E023FEDC07E91B7EAE1FE01
+039138803FFB499039F80003FF4901C01300013F90C8127F4948151FD9FFF8150F484915
+07485B4A1503481701485B18004890CAFC197E5A5B193E127FA34994C7FC12FFAB0407B6
+12FC127F7FA3003F92C7383FFE00A27F7EA26C7FA26C7F6C7FA26C7F6C7FD97FFE157F6D
+6C7E010F01E014FF6D01F813036D9038FF801F010091B512F3023F15C00207ED803E0200
+9138FE000E030701E090C7FC46407ABE52>I<B71280A526003FFEC7FCB3B3B0B71280A5
+213E7DBD28>73 D<B6037FB512E0A2818181D8003F6D9139001F800081A281816E7E6E7F
+6E7F80826E7F6E7F6E7F6E7F157F826F7F6F7F6F7F6F7F81836F7F6F7F707E701380A270
+13C07013E07013F07013F87013FCA27013FEEF7FFF71139F7113DF8319FF8383838384A2
+8484848484A284B600C080197F193F191FA24B3E7DBD52>78 D<ED3FFF0203B512F0021F
+14FE027F6E7E902701FFF80713E00107D9C00013F84990C7EA3FFCD93FFCEC0FFF49486E
+7F49486E7F48496E7F4A80488448496F7EA24890C96C7E4884A249161F003F84A3484870
+1380A400FF19C0AD007F19806D5EA3003F1900A26D5E6C60A26C6D4B5AA26C6D4B5A6C6D
+4A5BA26C6D4A5B6C6D4A5B6D6C4A5B6DB4023F90C7FC6D01C0EBFFFE0107D9F80713F801
+0190B612E06D5E021F4AC8FC020314F0DA003F90C9FC42407ABE4F>I<B812F017FF18C0
+18F018FC26003FFCC77FEF1FFF7113807113C07113E0A27113F0A319F8A819F0A34D13E0
+19C05F4D1380053F1300EFFFFE91B712F860188005FCC7FC4ACAFCB3A4B77EA53D3E7DBD
+47>I<B87E17FCEFFF8018F08428003FFC000113FE9338003FFF050F7F717F717FA28583
+85A761A25F61614D5B4D90C8FCEF3FFE4CB45A91B712F018C04DC9FC717E9126FC000F7F
+040113F0707F717EA2717EA2717EA685A6F207C019C0A271140F07E01380B76DEBF01F71
+9038FC3F007190B5FC716C5B061F13F8CB000113E04A3F7DBD4E>82
+D<903A03FFC001C0011FEBF803017FEBFE0748B6128F4815DF48010013FFD80FF8130F48
+481303497F4848EB007F127F49143F161F12FF160FA27F1607A27F7F01FC91C7FCEBFF80
+6C13F8ECFFC06C14FCEDFF806C15E016F86C816C816C816C16806C6C15C07F010715E0EB
+007F020714F0EC003F1503030013F8167F163F127800F8151FA2160FA27EA217F07E161F
+6C16E06D143F01E015C001F8EC7F8001FEEB01FF9026FFE00713004890B55A486C14F8D8
+F81F5CD8F00314C027E0003FFEC7FC2D407ABE3A>I<003FB912FCA5903BFE003FFE003F
+D87FF0EE0FFE01C0160349160190C71500197E127EA2007C183EA400FC183F48181FA5C8
+1600B3AF010FB712F8A5403D7CBC49>I<B76C90B61280A526003FFEC9003EC7FCB3B3A4
+197E011F177C80A26D17FC616D6D14014E5A6D6D4A5A6D6D140F6D01F8EC3FC0DA7FFEEC
+FF8091273FFFC00F90C8FC020F90B512FC02035D020015E0031F1480030101F8C9FC493F
+7DBD50>I<903807FFC0013F13F848B6FC48812607FE037F260FF8007F6DEB3FF0486C80
+6F7EA36F7EA26C5A6C5AEA01E0C8FC153F91B5FC130F137F3901FFFE0F4813E0000F1380
+381FFE00485A5B485A12FF5BA4151F7F007F143F6D90387BFF806C6C01FB13FE391FFF07
+F36CEBFFE100031480C6EC003FD91FF890C7FC2F2B7DA933>97 D<13FFB5FCA512077EAF
+EDFFE0020713FC021FEBFF80027F80DAFF8113F09139FC003FF802F06D7E4A6D7E4A1307
+4A80701380A218C082A318E0AA18C0A25E1880A218005E6E5C6E495A6E495A02FCEB7FF0
+903AFCFF01FFE0496CB55AD9F01F91C7FCD9E00713FCC7000113C033407DBE3A>I<EC7F
+F00107B5FC011F14C0017F14E09039FFF01FF0489038800FF848EB001F4848EB3FFC120F
+485AA2485AA2007FEC1FF849EB0FF0ED03C000FF91C7FCAB127F7FA3003F153E7F001F15
+7E6C6C147C6C6C14FC91388001F86C9038C003F0C69038F81FE06DB512C0011F14800107
+EBFE009038007FF0272B7DA92E>I<EE07F8ED07FFA5ED003F161FAFEC7FF0903807FFFE
+011FEBFF9F017F14DF9039FFF01FFF48EBC00348EB00014848EB007F485A001F153F5B12
+3FA2127F5BA212FFAA127FA37F123FA26C6C147F120F6D14FF6C6C01037F6C6D48EBFFE0
+6CEBF03F6C6CB512BF6D143F010713FC010001E0EBE00033407DBE3A>I<ECFFF0010713
+FE011F6D7E017F809039FFE07FE0489038801FF048496C7E48486D7E48486D7E121F4913
+01003F81A2485A6F1380A212FFA290B7FCA401F0C9FCA5127FA27F123FEE0F806C7E161F
+6C6C15006C6C5C6C6D137E6C9038E001FC6C9038F80FF8013FB55A6D14C0010391C7FC90
+38007FF8292B7DA930>I<EC07FE91387FFF8049B512C0010714E090390FFE3FF0EB1FF0
+90393FE07FF8EB7FC013FF1480A2489038003FF0ED1FE0ED0FC092C7FCAAB612E0A50001
+0180C7FCB3AC007FEBFF80A525407DBF20>I<903A03FF8007F0013F9038F83FF8499038
+FCFFFC48B712FE48018313F93A07FC007FC34848EB3FE1001FEDF1FC4990381FF0F81700
+003F81A7001F5DA26D133F000F5D6C6C495A3A03FF83FF8091B5C7FC4814FC01BF5BD80F
+03138090CAFCA2487EA27F13F06CB6FC16F016FC6C15FF17806C16C06C16E01207001F16
+F0393FE000034848EB003F49EC1FF800FF150F90C81207A56C6CEC0FF06D141F003F16E0
+01F0147FD81FFC903801FFC02707FF800F13006C90B55AC615F8013F14E0010101FCC7FC
+2F3D7DA834>I<13FFB5FCA512077EAFED1FF8EDFFFE02036D7E4A80DA0FE07F91381F00
+7F023C805C4A6D7E5CA25CA35CB3A4B5D8FE0FB512E0A5333F7CBE3A>I<EA01F8487E48
+7E487E481380A66C13006C5A6C5A6C5AC8FCA913FFB5FCA512077EB3ABB512F8A515407C
+BF1D>I<13FFB5FCA512077EB3B3AFB512FCA5163F7CBE1D>108 D<01FFD91FF8ECFFC0B5
+90B5010713F80203DAC01F13FE4A6E487FDA0FE09026F07F077F91261F003FEBF8010007
+013EDAF9F0806C0178ECFBC04A6DB4486C7FA24A92C7FC4A5CA34A5CB3A4B5D8FE07B5D8
+F03FEBFF80A551297CA858>I<01FFEB1FF8B5EBFFFE02036D7E4A80DA0FE07F91381F00
+7F0007013C806C5B4A6D7E5CA25CA35CB3A4B5D8FE0FB512E0A533297CA83A>I<EC7FF0
+903803FFFE011FEBFFC0017F14F09039FFE03FF8489038800FFC3A03FE0003FE48486D7E
+000F168048486D13C0A2003F16E049147F007F16F0A400FF16F8AA007F16F0A46C6CECFF
+E0A2001F16C06C6C491380A26C6C4913003A03FF800FFE6C9038E03FFC6C6CB512F0011F
+14C0010791C7FC9038007FF02D2B7DA934>I<01FFEBFFE0B5000713FC021FEBFF80027F
+80DAFF8113F09139FC007FF8000701F06D7E6C496D7E4A130F4A6D7E1880A27013C0A382
+18E0AA4C13C0A318805E18005E6E5C6E495A6E495A02FCEBFFF0DAFF035B92B55A029F91
+C7FC028713FC028113C00280C9FCACB512FEA5333B7DA83A>I<3901FE01FE00FF903807
+FF804A13E04A13F0EC3F1F91387C3FF8000713F8000313F0EBFFE0A29138C01FF0ED0FE0
+91388007C092C7FCA391C8FCB3A2B6FCA525297DA82B>114 D<90383FFC1E48B512BE00
+0714FE5A381FF00F383F800148C7FC007E147EA200FE143EA27E7F6D90C7FC13F8EBFFE0
+6C13FF15C06C14F06C806C806C806C80C61580131F1300020713C014000078147F00F814
+3F151F7EA27E16806C143F6D140001E013FF9038F803FE90B55A15F0D8F87F13C026E00F
+FEC7FC222B7DA929>I<EB07C0A5130FA4131FA3133F137FA213FF5A1207001FEBFFFEB6
+FCA40001EBC000B3151FA96CEBE03EA2017F137EECF8FC90383FFFF86D13F0010713E001
+001380203B7EB929>I<D9FF80EB0FF8B5EB0FFFA50007EC007F6C153FB3A5167FA316FF
+6C5C4B7F6C903AC007DFFFE09138F01F9F6DB5121F6D13FE010F13F8010101E0EBE00033
+2A7CA83A>I<B500FC90383FFFC0A5000101C0903803E0006E1307A26C5E6E130F017F5D
+6E131F013F92C7FC6E5B011F143E6E137E010F147C6E13FCA26D5C15816D5C15C36D5C15
+E76D5C15FF6E5BA36E90C8FCA26E5AA26E5AA26E5AA26E5AA232287EA737>I<B5D8FC03
+B51280A5C69026E0007FC7FC6E13FE6D6C5B6D6C485A6D6C485A010F13076D6C485AED9F
+C06DEBFF806D91C8FC6D5B6E5AA2143F6E7E140F814A7F4A7F4A7F02FE7F903801FC7F49
+486C7E02F07F49486C7E49486C7E011F7F49486C7FD97F008001FE6D7FB5D8C007EBFFC0
+A532287EA737>120 D<B500FC90383FFFC0A5000101C0903803E0006E1307A26C5E6E13
+0F017F5D6E131F013F92C7FC6E5B011F143E6E137E010F147C6E13FCA26D5C15816D5C15
+C36D5C15E76D5C15FF6E5BA36E90C8FCA26E5AA26E5AA26E5AA26E5AA35D14075D000E13
+0FD83F805B387FC01FD8FFE090C9FC5C143E147E5CEBC1F8387FC3F0387E0FE06CB45A6C
+5B6C48CAFCEA03F8323B7EA737>I E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fi cmr10 10.95 93
+/Fi 93 124 df<4AB4EB0FE0021F9038E03FFC913A7F00F8FC1ED901FC90383FF03FD907
+F090397FE07F80494801FF13FF4948485BD93F805C137F0200ED7F00EF003E01FE6D91C7
+FC82ADB97EA3C648C76CC8FCB3AE486C4A7E007FD9FC3FEBFF80A339407FBF35>11
+D<EC03FE91383FFF809138FE03E0903903F800F0D90FE013384948137C90393F8001FE90
+387F00035B5BA2485A6F5AED007093C7FCAA16FEB7FCA33901FC000315011500B3AC486C
+497EB5D8F87F13FCA32E407EBF33>I<EC03FF023F13EE9138FE01FEEB03F090380FE003
+EB1FC0EB3F80EB7F005B5B150148481300AEB7FCA3D801FCC7FCB3AE486C497EB5D8F87F
+13FCA32E407EBF33>I<DA03FE49B4FC91273FFF801F13C0913BFE03E07F01F0903C03F0
+00F1FC0078D90FE0D97FF0131C49484948133E4948484913FF494848495A5B491500A248
+485C03016E5A0300153896C7FCAA197FBBFCA3D801FCC738FE00018485B3AC486C496CEC
+FF80B5D8F87FD9FC3F13FEA347407EBF4C>I<121EEA7F80EAFFC0A9EA7F80ACEA3F00AC
+121EAB120CC7FCA8121EEA7F80A2EAFFC0A4EA7F80A2EA1E000A4179C019>33
+D<001E130F397F803FC000FF137F01C013E0A201E013F0A3007F133F391E600F30000013
+00A401E01370491360A3000114E04913C00003130101001380481303000EEB070048130E
+0018130C0038131C003013181C1C7DBE2D>I<4B6C130C4B6C131EA20307143EA24C133C
+A2030F147CA293C71278A24B14F8A2031E5CA2033E1301A2033C5CA3037C1303A203785C
+A203F81307A24B5CA20201140F007FBAFCBB1280A26C1900C72707C0003EC8FC4B133CA3
+020F147CA292C71278A24A14F8A2021E5CA3023E1301007FBAFCBB1280A26C1900C727F8
+0007C0C8FC4A5CA20101140FA24A91C9FCA301035CA24A131EA20107143EA24A133CA201
+0F147CA291C71278A34914F8A2011E5CA2013E1301A2013C5CA201186D5A41517BBE4C>
+I<14E0A4EB07FC90383FFF8090B512E03901F8E3F03903E0E0FCD807C0133CD80F807FD8
+1F007F003E80003C1580007C140316C00078141F00F8143F157FA47EED3F806CEC0E0092
+C7FC127F138013C0EA3FF013FEEA1FFF6C13FC6C13FF6C14C06C806C6C13F8011F7F1303
+01007FECE7FF14E102E01380157F153FED1FC0A2003E140F127FD8FF801307A5130000FC
+158000F0140F1270007815005D6C141E153E6C5C6C5C3907C0E1F03903F8EFE0C6B51280
+D93FFEC7FCEB0FF8EB00E0A422497BC32D>I<013F1603D9FFC04B7E2601E0E0150F2607
+C070151F48486C4BC7FC023E157E48486C15FE48D90FC0EB03FC003ED90EF0EB0FF8DA0F
+3F13FD007E903A070FFFF1F0007C0200EB03E0160000FC6D6C495A170F604DC8FC5F173E
+5F17FC5F4C5A1603007CD907005B4C5A007E150F003E495C020E49C9FC003F5D6C49133E
+260F803C5B023813FC6C6C485B3A01E0E001F03800FFC090273F0003E0133F90C70007EC
+FFC09339C001E0E0923A0F8007C070031F49487E0400143C033E90381F001C037E497F03
+7C133E4B150F0201027E7F4B137C4A5A020702FCEB03805D4A5A141F92C7FC143E147E14
+7C5CA2495A0103037CEB07005C4948147E010F033E5B4A160E49C8123F496F5B013E9238
+0F803C49173801FC6F6C5A49923801E0E0496FB45A0160043FC7FC41497BC34C>I<EC0F
+80EC7FE0ECF870903803E0380107133CECC01CEB0F80011F131E150EA2EB3F00A55D1480
+A25D157815705D6D6C5A14C1ECC38002C7CAFC02EE91387FFFFCEB0FEC14FC4A020713C0
+6D48913801FE006E5DEF00F06D7E01074B5A496C5D011D1503D939FF4A5A017093C7FC49
+6D5B0001017F140E496C6C131E00036E131C2607801F143C000F6E5B001F6D6C1370263F
+000714F0486E485ADA03FE5B913801FF03486D495A0487C8FCED7FCFED3FFE6F4814386D
+5C150F007F6E6C14786D6D6C1470003F4A6C14F06D496C6C13E0001F91393E3FC0016C6C
+903AFC1FF003C03D07FC07F007FC1F800001B5D8C001B512006C6C90C7EA7FFCD90FF8EC
+0FF03E437CC047>I<121EEA7F8012FF13C0A213E0A3127FEA1E601200A413E013C0A312
+011380120313005A120E5A1218123812300B1C79BE19>I<1430147014E0EB01C0EB0380
+1307EB0F00131E133E133C5B13F85B12015B1203A2485AA2120F5BA2121F90C7FCA25AA3
+123E127EA6127C12FCB2127C127EA6123E123FA37EA27F120FA27F1207A26C7EA212017F
+12007F13787F133E131E7FEB07801303EB01C0EB00E014701430145A77C323>I<12C07E
+12707E7E121E7E6C7E7F12036C7E7F12007F1378137CA27FA2133F7FA21480130FA214C0
+A3130714E0A6130314F0B214E01307A614C0130FA31480A2131F1400A25B133EA25BA213
+7813F85B12015B485A12075B48C7FC121E121C5A5A5A5A145A7BC323>I<EB03C0A2805C
+A600F0140F00FC143F00FE147F00FF14FF393FC3C3FC390FE187F03903F18FC03900FDBF
+00EB3FFCEB0FF0EB03C0EB0FF0EB3FFCEBFDBF3903F18FC0390FE187F0393FC3C3FC39FF
+03C0FF00FE147F00FC143F00F0140F00001400A6805CA220277AC32D>I<1506150FB3A9
+007FB912E0BA12F0A26C18E0C8000FC9FCB3A915063C3C7BB447>I<121EEA7F8012FF13
+C0A213E0A3127FEA1E601200A413E013C0A312011380120313005A120E5A121812381230
+0B1C798919>I<B512FEA617067F961E>I<121EEA7F80A2EAFFC0A4EA7F80A2EA1E000A0A
+798919>I<ED0180ED03C01507A21680150FA216005DA2151E153EA2153C157CA2157815
+F8A25D1401A25D1403A25D1407A25D140FA24AC7FCA2141E143EA2143C147CA2147814F8
+A25C1301A25C1303A25C1307A25C130FA291C8FC5BA2131E133EA25BA2137813F8A25B12
+01A25B1203A25B1207A25B120FA290C9FC5AA2121E123EA2123C127CA2127812F8A25A12
+60225B7BC32D>I<EB01FE90380FFFC090383F03F090387C00F849137C48487F48487F48
+48EB0F80A2000F15C04848EB07E0A3003F15F0A290C712034815F8A64815FCB3A26C15F8
+A56C6CEB07F0A3001F15E0A36C6CEB0FC0A26C6CEB1F80000315006C6C133E6C6C5B017C
+5B90383F03F090380FFFC0D901FEC7FC263F7DBC2D>I<EB01C013031307131F137FEA07
+FFB5FC139FEAF81F1200B3B3ACEB7FF0B612F8A31D3D78BC2D>I<EB07FC90383FFF8090
+B512E03903F01FF83907C007FC390F0001FE001E6D7E001C1580003CEC7FC05AED3FE012
+70B4FC6DEB1FF07FA56C5A6CC7FC120CC813E0153FA216C0157F168015FF16004A5A5D4A
+5A4A5A5D4A5A4A5A4AC7FC147E147C5C495A495A495A495A49C71270133E133C5B4914E0
+485A485A485A48C7120148B6FCA25A4815C0B7FCA3243D7CBC2D>I<EB07FC90383FFF80
+9038F80FE03901E003F839078001FCD80F007F000E6D7E001E1580D81F80137F486C14C0
+7FA27F5BA2121F6C5AC8138015FF1600A24A5AA24A5A5DEC07E04A5A023FC7FCEB1FFCEC
+FF809038000FE0EC07F86E7E6E7E6E7E1680ED7FC0A216E0153FA216F0A2120C123F487E
+487EA316E0A249137F6CC713C01278EDFF807E6C4913006C495A3907C007FC3903F80FF0
+C6B55A013F1380D907F8C7FC243F7CBC2D>I<150E151E153EA2157EA215FE1401A21403
+EC077E1406140E141CA214381470A214E0EB01C0A2EB0380EB0700A2130E5BA25B5BA25B
+5B1201485A90C7FC5A120E120C121C5AA25A5AB8FCA3C8EAFE00AC4A7E49B6FCA3283E7E
+BD2D>I<00061403D80780131F01F813FE90B5FC5D5D5D15C092C7FC14FCEB3FE090C9FC
+ACEB01FE90380FFF8090383E03E090387001F8496C7E49137E497F90C713800006141FC8
+13C0A216E0150FA316F0A3120C127F7F12FFA416E090C7121F12FC007015C012780038EC
+3F80123C6CEC7F00001F14FE6C6C485A6C6C485A3903F80FE0C6B55A013F90C7FCEB07F8
+243F7CBC2D>I<EC1FE0ECFFF8903803F03E90380FC00F90391F000780133E017EEB1FC0
+49133F4848137F12035B12074848EB3F80ED1F00001F91C7FC5BA2123FA3485AA214FE90
+3887FF8039FF8F07E090389C01F09038B800FC01B0137E13F0497F16804914C0A2ED1FE0
+A34914F0A5127FA6123F6D14E0A2121FED3FC0A26C6C1480A20007EC7F006C6C137E6C6C
+5B6C6C485A90387E07F06DB45A010F1380D903FCC7FC243F7CBC2D>I<1238123C123F90
+B612FCA316F85A16F016E00078C712010070EC03C0ED078016005D48141E151C153C5DC8
+127015F04A5A5D14034A5A92C7FC5C141EA25CA2147C147814F8A213015C1303A31307A3
+130F5CA2131FA6133FAA6D5A0107C8FC26407BBD2D>I<EB03FC90381FFF8090387C07E0
+9038F001F83901E0007C48487F48487F48C7FCED0F80121E16C0003E1407A4123FA26DEB
+0F807F6C6C131F6D140001FC133E6C6C5B9038FF80786C6D5A6CEBF3E06CEBFF806C91C7
+FC133F6D13C06D7F013F13F801787F48486C7E3903E01FFF48486C1380260F800313C048
+487E489038007FE0003E143F007E141F007CEC0FF01507481403A31501A46C15E0007C14
+03A2007E15C06C14076CEC0F806DEB1F006C6C133ED807F05B3901FC03F86CB512E0011F
+1380D903FCC7FC243F7CBC2D>I<EB03FCEB1FFF90387E07C09038FC03F048486C7E4848
+6C7E4848137C000F147E4848137F81003F15805B007F15C0A2151F12FF16E0A516F0A512
+7F153FA36C7EA2001F147F120F6C6C13FF6D13DF000313013900F8039F90387E0F1FD91F
+FE13E0EB07F090C7FCA2ED3FC0A41680157FD80F801400487E486C13FEA24A5A5D49485A
+EB8007391E000FE0001F495A260FC07FC7FC3803FFFE6C13F838003FC0243F7CBC2D>I<
+121EEA7F80A2EAFFC0A4EA7F80A2EA1E00C7FCB3121EEA7F80A2EAFFC0A4EA7F80A2EA1E
+000A2779A619>I<121EEA7F80A2EAFFC0A4EA7F80A2EA1E00C7FCB3121E127FEAFF80A2
+13C0A4127F121E1200A412011380A3120313005A1206120E120C121C5A1230A20A3979A6
+19>I<121EEA7F80A2EAFFC0A4EA7F80A2EA1E00C7FCA8120C121EAB123FACEA7F80ACEA
+FFC0A9EA7F80EA1E000A4179AC19>I<007FB912E0BA12F0A26C18E0CDFCAE007FB912E0
+BA12F0A26C18E03C167BA147>I<EB0780EB1FE0A2497EA46D5AA2EB078090C8FCA81303
+80A4130791C7FCA65BA3131EA2133E133C137CA25B1201485A485A120F485A485A127FA2
+48C7127C15FEEC01FFA480157F6C141EA26C6C133C1578390FC001E03907F00FC03901FF
+FE0038003FF020407BAC2B>I<EB1FF890B5FC3903E01FC0390F0007F0001EEB03F848EB
+01FC4814FE140000FE14FF7E7FA46CC7FC123EC7EA01FEA2EC03FCEC07F815F0EC0FC0EC
+1F80EC3F00143E5C147814F85C13015CA2495AA25CAB91C7FC90C8FCA8EB0780EB1FE0A2
+497EA46D5AA2EB078020407BBF2B>I<ED7FE0913807FFFE91391F801F809139780001E0
+D901E0EB0078D90780141E49C87E011E6F7E0138ED01C0496F7E49167000011778484882
+49D93F80131C28070001FFF07F48902607E07C130F000E90260FC01E7F001E90263F0007
+1480001C499038038003003C01FED901C013C0003849ECFE010101EC00FF267803F8027F
+13E000701700495AA200F018F000E01870495AA96D7E12F01270A26D7E007818E0263801
+FC5C01005C003C7F001C017F49EB01C0001E6DEB077F000E903B0FC01E3F8380000F903B
+07E07C1F87006C903A01FFF007FE3C0380003F8001F86D90CAFC6C7E120013707F011EEE
+03F06D160F6D6CED3FC0D901E0913801FE00D90078EC1FF0913A1F8003FF800207B500F8
+C7FC9126007FFEC8FC3C417BBF47>I<15074B7EA34B7EA34B7EA34B7EA34B7E15E7A291
+3801C7FC15C3A291380381FEA34AC67EA3020E6D7EA34A6D7EA34A6D7EA34A6D7EA34A6D
+7EA349486D7E91B6FCA249819138800001A249C87EA24982010E157FA2011E82011C153F
+A2013C820138151FA2017882170F13FC00034C7ED80FFF4B7EB500F0010FB512F8A33D41
+7DC044>I<B712FCEEFF8017F00001903980000FF86C6CC7EA03FE707E701380EF7FC0EF
+3FE0A2EF1FF0A218F8A3170F171FA318F0A2EF3FE0177F18C0EFFF804C1300EE03FCEE0F
+F8EE7FE091B6C7FC17E091C7EA07FCEE01FE933800FF80EF7FC0EF3FE0EF1FF018F8170F
+18FC1707A218FEA718FC170FA2EF1FF818F0173FEF7FE0EFFFC00403138048486C90380F
+FE00B85A17E094C7FC373E7DBD40>I<DB3FF01306912603FFFE130E020F9038FF801E91
+3A3FF007E03E9139FF8000F8D903FEC7EA7C7ED907F8EC1EFE4948140FD93FE014074948
+1403495A91C812014848150012034848167E5B000F173EA24848161EA2123F5B180E127F
+A349160012FFAC127F7F180EA2123FA27F001F171E181C6C7EA20007173C6D16386C6C16
+78000117706C6C16F06EEC01E06D6C15C06D6C1403D90FF0EC07806D6CEC1F00D903FE14
+3E902600FF8013F891393FF007F0020FB512C0020391C7FC9138003FF037427BBF42>I<
+B712FCEEFF8017E000019039C0001FF86C6C48EB03FEEE00FF717E717EEF0FE084717E71
+7E170184717EA21980187F19C0A3F03FE0A519F0AB19E0A5F07FC0A21980A218FF19004D
+5AA24D5A6017074D5A4D5AEF7FC04DC7FCEE03FE48486CEB1FF8B85A178004FCC8FC3C3E
+7DBD45>I<B912E0A300019038C000016C6C48EB001FEF0FF01703A217011700A31870A4
+18381638A41800A21678A216F81501150791B5FCA3EC8007150115001678A21638A2180E
+A3181C93C7FCA4183C1838A21878A318F8EF01F0A21707170F173F48486CEB03FFB912E0
+A3373E7DBD3E>I<B91280A300019038C000036C6C48EB007FEF1FC0170F1707A21703A3
+1701A4EF00E0A21638A31800A31678A216F81501150791B5FCA3EC8007150115001678A2
+1638A693C8FCAF3801FFE0B612F0A3333E7DBD3B>I<DB3FE0130C912603FFFE131C021F
+9038FF803C913A7FF00FC07C9139FF0001F0D903FC90380078FC4948143DD91FE0141F49
+48140F4948140701FF15034890C8FC491501485A000716005B000F177C5B001F173CA248
+5AA2181C127FA25B95C7FC12FFAB041FB512F0127FA26D9139000FFE00EF03FC123FA27F
+121FA26C7EA212077F12036C7E7F6C7F6D6C14076D7E6D6C140FD907F8141ED903FEEC3C
+7C902600FF80EBF83C913A7FF007F01C021FB5EAC00C020391C8FC9138003FF03C427BBF
+47>I<B6D8C01FB512F8A3000101E0C7383FFC0026007F80EC0FF0B3A691B7FCA30280C7
+120FB3A92601FFE0EC3FFCB6D8C01FB512F8A33D3E7DBD44>I<B612F0A3C6EBF000EB3F
+C0B3B3B2EBFFF0B612F0A31C3E7EBD21>I<011FB512FCA3D9000713006E5A1401B3B3A6
+123FEA7F80EAFFC0A44A5A1380D87F005B007C130700385C003C495A6C495A6C495A2603
+E07EC7FC3800FFF8EB3FC026407CBD2F>I<B600C090387FFFFCA3000101E0C7000F1380
+26007F80913807FE0018F818E0604D5A4DC7FC173E5F5F4C5A4C5A4C5A4C5A4CC8FC163E
+5E5E4B5A4B5AED07804B7E151F4B7E4B7E15FF913881EFF8913883C7FCEC878791388F03
+FE91389E01FF14BCDAF8007F4A6D7E5C4A6D7E4A6D7EA2707E707EA2707E707EA2707F71
+7E84173F717E717EA2717E848419802601FFE04A13C0B600C090B6FCA3403E7DBD47>I<
+B612F8A3000101E0C9FC38007F80B3B0EF0380A517071800A45FA35FA25F5F5F4C5A1607
+48486C133FB8FCA3313E7DBD39>I<B500C093B512C0A300016D4BEBE000D8007F1880D9
+77F0ED03BFA3D973F8ED073FA3D971FC150EA2D970FE151CA3027F1538A36E6C1470A36E
+6C14E0A26E6CEB01C0A36E6CEB0380A36E6CEB0700A26E6C130EA36E6C5BA3037F5BA26F
+6C5AA36F6C5AA392380FE1C0A3923807F380A26FB4C7FCA36F5AA213F8486C6D5AD807FF
+EFFFE0B500F80178017FEBFFC0A34A3E7CBD53>I<B56C91B512F88080D8007F03071300
+6EEC01FC6E6E5A1870EB77FCEB73FEA2EB71FF01707FA26E7E6E7EA26E7E6E7EA26E7E6E
+7EA26E7E6E7FA26F7E6F7EA26F7E6F7EA26F7E6F7EA26F7E6F1380A2EE7FC0EE3FE0A2EE
+1FF0EE0FF8A2EE07FCEE03FEA2EE01FF7013F0A2177F173FA2171F170FA2170701F81503
+487ED807FF1501B500F81400A218703D3E7DBD44>I<ED7FE0913807FFFE91391FC03F80
+91397E0007E04948EB03F8D907F0EB00FE4948147F49486E7E49486E7E49C86C7E01FE6F
+7E00018349150300038348486F7EA248486F7EA2001F188049167F003F18C0A3007F18E0
+49163FA300FF18F0AC007F18E06D167FA4003F18C0A26C6CEEFF80A36C6C4B1300A26C6C
+4B5A00035F6D150700015F6C6C4B5A6D5E6D6C4A5A6D6C4A5A6D6C4AC7FC6D6C14FED901
+FCEB03F8D9007FEB0FE091391FC03F80912607FFFEC8FC9138007FE03C427BBF47>I<B7
+12F8EEFF8017E000019039C0003FF86C6C48EB07FCEE01FE707EEF7F80EF3FC018E0A2EF
+1FF0A218F8A818F0A2EF3FE0A218C0EF7F80EFFF004C5AEE07FCEE3FF091B612C04CC7FC
+0280C9FCB3A73801FFE0B612C0A3353E7DBD3E>I<ED7FE0913807FFFE91391FC03F8091
+397F000FE0D901FCEB03F8D907F0EB00FE4948147F49486E7E49486E7E49C86C7E498248
+486F7E49150300038348486F7EA2000F834981001F1880A24848EE7FC0A3007F18E0A249
+163FA200FF18F0AC007F18E0A26D167FA3003F18C0A26C6CEEFF80A3000F18006D5D0007
+DA0F805B6C6C90393FE003FCED70706C6C496C485A6C6C48486C485A017FD9800E5BD93F
+819038061FC0D91FC19038073F80D90FE14AC7FCD907F1EB03FE902601FDC013F8903A00
+7EE007E091271FF03FC013180207B5FC9139007FE1E0DB0001143883711378A2706C13F0
+EFFF0318FFA27113E0A37113C0711380711300715AEF01F83D527BBF47>I<B712C016FC
+EEFF800001D9C00013E06C6C48EB1FF0EE07FCEE01FE707E84717EA2717EA284A760177F
+606017FF95C7FCEE01FCEE07F8EE1FE0EEFF8091B500FCC8FC16F091388001FCED003FEE
+1FC0707E707E83160383160183A383A484A4F0C004190EA28218E0057F131E2601FFE016
+1CB600C0EB3FF094381FF83805071370CA3801FFE09438003F803F407DBD43>I<D907FC
+131890391FFF8038017FEBE0783901FC03F83A03F0007CF8D807C0133F4848130F001F14
+0748C7FC003E1403007E1401A2007C140012FC1678A46C1538A27EA26C6C14007F7FEA3F
+F8EBFF806C13F86CEBFF806C14F06C14FC6C14FF6C15C0013F14E0010714F0EB007F0207
+13F89138007FFC150FED07FE15031501ED00FFA200E0157FA3163FA27EA3163E7E167E6C
+157C6C15FC6C15F86D13016DEB03F06DEB07E0D8F9FCEB0FC03AF07F803F8090391FFFFE
+00D8E00713F839C0007FC028427BBF33>I<003FB91280A3903AF0007FE001018090393F
+C0003F48C7ED1FC0007E1707127C00781703A300701701A548EF00E0A5C81600B3B14B7E
+4B7E0107B612FEA33B3D7DBC42>I<B600C090B512F8A3000101E0C70007130026007F80
+EC01FC715A1870B3B3A4013F16F06E5DA21701011F5E80010F15036E4A5A010793C7FC6D
+6C5C6D6C141E6D6C5C027F14F86E6C485A91390FF00FE00203B51280020049C8FCED1FF0
+3D407DBD44>I<B691380FFFFEA3000301E0020113E06C01809138007F806CEF3F00017F
+163E181C6E153C013F1638A26E1578011F1670A26D6C5DA26E140101075EA26E14030103
+5EA26D6C4AC7FCA2806D150EA26F131E027F141CA26F133C023F1438A26E6C5BA26F13F0
+020F5CA2EDF80102075CA26E6C485AA2EDFE07020191C8FCA26F5A6E130EA2ED7F9CA216
+DCED3FF8A36F5AA36F5AA26F5AA36F5A3F407EBD44>I<B500FE017FB5D88007B5FCA300
+0301C0010101E0C713F86C90C849EC3FE07148EC0F807E7215006E143F017F190E84A26D
+6C60A24D7E6D6C60A2EFE7F86D6C60A2933801C3FC6E18F001076104037F6E0281140101
+036104077F17006D6C4D5AA2040EEB7F806D6C4DC7FCA24CEB3FC0DA7F80160EA24CEB1F
+E003C0161E023F171C047814F0DBE070010F133C021F173804F014F84C1307DA0FF05EA2
+DBF1C0EB03FCDA07F95EA2DBFB80EB01FEDA03FF6F5AA293C8FCA26E5FA24B157F020094
+C8FCA24B81037C153EA20378151E0338151C58407EBD5D>I<007FB5D8C003B512E0A3C6
+49C7EBFC00D93FF8EC3FE06D48EC1F806D6C92C7FC171E6D6C141C6D6C143C5F6D6C1470
+6D6D13F04C5ADA7FC05B023F13036F485ADA1FF090C8FC020F5BEDF81E913807FC1C163C
+6E6C5A913801FF7016F06E5B6F5AA26F7E6F7EA28282153FED3BFEED71FF15F103E07F91
+3801C07F0203804B6C7EEC07004A6D7E020E6D7E5C023C6D7E02386D7E14784A6D7E4A6D
+7F130149486E7E4A6E7E130749C86C7E496F7E497ED9FFC04A7E00076DEC7FFFB500FC01
+03B512FEA33F3E7EBD44>I<B66C0103B51280A3000101F0C8EBF8006C6C48ED3FC0725A
+013F041EC7FC6D7E606D6C15386D6C1578606D6C5D6E14016D5E6D6D1303606E6C49C8FC
+6E6C5B170E6E6C131E171C6E6C5B6E6C137817706E6C13F06F5B6E13016EEB83C05FED7F
+C7DB3FE7C9FC16EFED1FFE5E150F6F5AB3A4ED1FFC020FB512FCA3413E7FBD44>I<003F
+B712F8A391C7EA1FF013F801E0EC3FE00180EC7FC090C8FC003EEDFF80A2003C4A130000
+7C4A5A12784B5A4B5AA200704A5AA24B5A4B5AA2C8485A4A90C7FCA24A5A4A5AA24A5AA2
+4A5A4A5AA24A5A4A5AA24990C8FCA2495A4948141CA2495A495AA2495A495A173C495AA2
+4890C8FC485A1778485A484815F8A24848140116034848140F4848143FED01FFB8FCA32E
+3E7BBD38>I<EAFFFCA4EAF000B3B3B3B3ABEAFFFCA40E5B77C319>I<486C13C000031301
+01001380481303000EEB070048130E0018130C0038131C003013180070133800601330A3
+00E01370481360A400CFEB678039FFC07FE001E013F0A3007F133FA2003F131F01C013E0
+390F0007801C1C73BE2D>I<EAFFFCA4EA003CB3B3B3B3ABEAFFFCA40E5B7FC319>I<EA01
+80120313005A120E5A12181238123012701260A312E05AA412CFEAFFC013E0A3127FA212
+3F13C0EA0F000B1C7ABE19>96 D<EB0FF8EBFFFE3903F01F8039078007E0000F6D7E9038
+E001F8D81FF07F6E7EA3157F6C5AEA0380C8FCA4EC1FFF0103B5FC90381FF87FEB7F8038
+01FC00EA07F8EA0FE0485A485AA248C7FCEE038012FEA315FFA3007F5BEC03BF3B3F8007
+1F8700261FC00E13CF3A07F03C0FFE3A01FFF807FC3A003FC001F0292A7DA82D>I<EA01
+FC12FFA3120712031201B1EC03FC91381FFF8091387C07E09039FDE001F09039FFC000FC
+4A137E91C77E49158049141F17C0EE0FE0A217F0A2160717F8AA17F0A2160FA217E0161F
+17C06D1580EE3F006D5C6E13FE9039F3C001F89039F1E003F09039E0780FC09026C03FFF
+C7FCC7EA07F82D407EBE33>I<49B4FC010F13E090383F00F8017C131E4848131F484813
+7F0007ECFF80485A5B121FA24848EB7F00151C007F91C7FCA290C9FC5AAB6C7EA3003FEC
+01C07F001F140316806C6C13076C6C14000003140E6C6C131E6C6C137890383F01F09038
+0FFFC0D901FEC7FC222A7DA828>I<ED01FC15FFA3150715031501B114FF010713E19038
+1F80F990387E003D49131FD803F81307485A49130348481301121F123F5B127FA290C7FC
+A25AAA7E7FA2123FA26C7E000F14037F000714076C6C497E6C6C497ED8007C017913F890
+383F01F190380FFFC1903A01FE01FC002D407DBE33>I<EB01FE90380FFFC090383F03F0
+9038FC01F848486C7E4848137E48487F000F158049131F001F15C04848130FA2127F16E0
+90C7FCA25AA290B6FCA290C9FCA67EA27F123F16E06C7E1501000F15C06C6C13036DEB07
+806C6C1400C66C131E017E5B90381F80F8903807FFE0010090C7FC232A7EA828>I<EC1F
+C0EC7FF8903801F83C903807E07E90380FC0FFEB1FC1EB3F811401137FEC00FE01FE137C
+1500AEB6FCA3C648C7FCB3AE487E007F13FFA320407EBF1C>I<167C903903F801FF903A
+1FFF078F8090397E0FDE1F9038F803F83803F001A23B07E000FC0600000F6EC7FC49137E
+001F147FA8000F147E6D13FE00075C6C6C485AA23901F803E03903FE0FC026071FFFC8FC
+EB03F80006CAFC120EA3120FA27F7F6CB512E015FE6C6E7E6C15E06C810003813A0FC000
+1FFC48C7EA01FE003E140048157E825A82A46C5D007C153E007E157E6C5D6C6C495A6C6C
+495AD803F0EB0FC0D800FE017FC7FC90383FFFFC010313C0293D7EA82D>I<EA01FC12FF
+A3120712031201B1EC01FE913807FFC091381E07E091387803F09138E001F8D9FDC07F14
+8001FF6D7E91C7FCA25BA25BB3A6486C497EB5D8F87F13FCA32E3F7DBE33>I<EA01E0EA
+07F8A2487EA46C5AA2EA01E0C8FCACEA01FC127FA3120712031201B3AC487EB512F0A314
+3E7DBD1A>I<1478EB01FEA2EB03FFA4EB01FEA2EB00781400AC147FEB7FFFA313017F14
+7FB3B3A5123E127F38FF807E14FEA214FCEB81F8EA7F01387C03F0381E07C0380FFF8038
+01FC00185185BD1C>I<EA01FC12FFA3120712031201B292B51280A392383FFC0016E016
+8093C7FC153C5D5D4A5AEC07C04A5A4AC8FC143E147F4A7E13FD9038FFDFC0EC9FE0140F
+496C7E01FC7F496C7E1401816E7E81826F7E151F826F7EA282486C14FEB539F07FFFE0A3
+2B3F7EBE30>I<EA01FC12FFA3120712031201B3B3B1487EB512F8A3153F7DBE1A>I<2701
+F801FE14FF00FF902707FFC00313E0913B1E07E00F03F0913B7803F03C01F80007903BE0
+01F87000FC2603F9C06D487F000101805C01FBD900FF147F91C75B13FF4992C7FCA2495C
+B3A6486C496CECFF80B5D8F87FD9FC3F13FEA347287DA74C>I<3901F801FE00FF903807
+FFC091381E07E091387803F000079038E001F82603F9C07F0001138001FB6D7E91C7FC13
+FF5BA25BB3A6486C497EB5D8F87F13FCA32E287DA733>I<14FF010713E090381F81F890
+387E007E01F8131F4848EB0F804848EB07C04848EB03E0000F15F04848EB01F8A2003F15
+FCA248C812FEA44815FFA96C15FEA36C6CEB01FCA3001F15F86C6CEB03F0A26C6CEB07E0
+6C6CEB0FC06C6CEB1F80D8007EEB7E0090383F81FC90380FFFF0010090C7FC282A7EA82D
+>I<3901FC03FC00FF90381FFF8091387C0FE09039FDE003F03A07FFC001FC6C496C7E6C
+90C7127F49EC3F805BEE1FC017E0A2EE0FF0A3EE07F8AAEE0FF0A4EE1FE0A2EE3FC06D15
+80EE7F007F6E13FE9138C001F89039FDE007F09039FC780FC0DA3FFFC7FCEC07F891C9FC
+AD487EB512F8A32D3A7EA733>I<02FF131C0107EBC03C90381F80F090397F00387C01FC
+131CD803F8130E4848EB0FFC150748481303121F485A1501485AA448C7FCAA6C7EA36C7E
+A2001F14036C7E15076C6C130F6C7E6C6C133DD8007E137990383F81F190380FFFC19038
+01FE0190C7FCAD4B7E92B512F8A32D3A7DA730>I<3901F807E000FFEB1FF8EC787CECE1
+FE3807F9C100031381EA01FB1401EC00FC01FF1330491300A35BB3A5487EB512FEA31F28
+7EA724>I<90383FC0603901FFF8E03807C03F381F000F003E1307003C1303127C007813
+0112F81400A27E7E7E6D1300EA7FF8EBFFC06C13F86C13FE6C7F6C1480000114C0D8003F
+13E0010313F0EB001FEC0FF800E01303A214017E1400A27E15F07E14016C14E06CEB03C0
+903880078039F3E01F0038E0FFFC38C01FE01D2A7DA824>I<131CA6133CA4137CA213FC
+A2120112031207001FB512C0B6FCA2D801FCC7FCB3A215E0A912009038FE01C0A2EB7F03
+013F138090381F8700EB07FEEB01F81B397EB723>I<D801FC14FE00FF147FA300071403
+0003140100011400B3A51501A31503120015076DEB06FF017E010E13806D4913FC90381F
+C078903807FFE00100903880FE002E297DA733>I<B539E00FFFE0A32707FE000313006C
+48EB00FC5E00015D7F00005DA26D13016D5CA26D6C485AA2ECC007011F91C7FCA290380F
+E00EA2ECF01E0107131CA26D6C5AA2ECFC7801011370A2ECFEF001005BA2EC7FC0A36E5A
+A26EC8FCA3140E2B287EA630>I<B53BC3FFFE03FFF8A3290FFE003FE00013C06C486D48
+EB3F806C4817006D010F141E00016F131C15076D163C00004A6C1338A2017F5E4B7E151D
+D93F805DED3DFC1538D91FC04A5AED78FE9238707E03D90FE0017F5BEDE03F02F0140701
+070387C7FC9138F1C01F02F9148F010315CE9138FB800F02FF14DE6D15FCED00076D5DA2
+4A1303027E5CA2027C1301023C5C023813003D287EA642>I<B539F01FFFE0A30003D9C0
+0F1300C690388007F8D97F0013E002805BD93FC05B011F49C7FC90380FE00EECF01E6D6C
+5A01035B6D6C5A6E5AEB00FF6E5A6E5A81141F814A7E81147BECF1FC903801E1FEECC0FF
+01037F49486C7ED90F007F011E6D7E013E130F496D7E01FC80486C80000F4A7EB539803F
+FFF8A32D277FA630>I<B539E00FFFE0A32707FE000313006C48EB01FC6F5A00015D7F00
+005DA2017F495AA2EC8003013F5CA26D6C48C7FCA26E5A010F130EA26D6C5AA2ECF83C01
+031338A26D6C5AA2ECFEF001005BA2EC7FC0A36E5AA36EC8FCA2140EA2141E141C143C14
+38A2147800181370127EB45BA2495AA248485AD87E07C9FCEA780EEA3C3CEA1FF8EA07E0
+2B3A7EA630>I<001FB61280A2EBE0000180140049485A001E495A121C4A5A003C495A14
+1F00385C4A5A147F5D4AC7FCC6485AA2495A495A130F5C495A90393FC00380A2EB7F80EB
+FF005A5B484813071207491400485A48485BA248485B4848137F00FF495A90B6FCA22127
+7EA628>I<B812F0A22C0280982D>I E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fj cmr12 14.4 16
+/Fj 16 122 df<120FEA3FC0EA7FE0EAFFF0A6EA7FE0EA3FC0EA0F000C0C768B21>46
+D<EC1FF891B5FC010314C090390FF81FF090391FC003F849486C7E017EC7127E49800001
+168049141F4848EC0FC0000716E0491407000F16F0A34848EC03F8A2003F16FCA44848EC
+01FEA700FF16FFB3A5007F16FEA56D1403A2003F16FCA4001F16F8A26D1407000F16F0A2
+6C6CEC0FE0A26C6CEC1FC0A26C6CEC3F806C6CEC7F00017F14FE6D6C485A6D6C485A9039
+0FF81FF00103B512C0010091C7FCEC1FF830517BCE3B>48 D<EC7FE0903803FFFE010F6D
+7E013F14E0D9FF0013F8D801F8EB1FFCD803E06D7E4848EB03FF48486D138090C813C000
+1E16E0001C157F003CED3FF012380078ED1FF81270A2B4ED0FFC13C07FA66C5A6C5A000E
+C8FCC9EA1FF8A317F0163FA2EE7FE017C016FF17804B1300A24B5A4B5A5E4B5A4B5A4B5A
+5E4BC7FC15FE4A5A4A5A4A5A4A5A5D4A5A4AC8FC147E5C4948141CEB03E0495A49481438
+91C8FC131E5B5B491578485A48481570484815F048B7FCA25A5A5AB812E0A42E4F7ACE3B
+>50 D<160F5EA25E5EA25E5DA25D5DA25D151E151C153C5D157015F04A5A5D14035D4A5A
+5C140E5C143C14385C14F05C495A13035C130749C7FC130E131E5B133813785B5B120148
+5A5B120748C8FC120E121E5A123812785AB912F0A4C8000190C7FCAF4B7F4B7F020FB612
+E0A434507DCF3B>52 D<000316C001C0140301F8141F903AFFC003FF8091B612005E5E5E
+16E016804BC7FC019F13F8018113800180C9FCB0EC0FF0ECFFFE01836D7E903987F01FE0
+90399F0007F801BE6D7E01F86D7E496D7E49EC7F805BEE3FC04915E0C9121F17F0A317F8
+160FA317FCA5120EEA3F80487E12FF7FA217F85B161F5B48C813F012700078ED3FE0A26C
+16C0167F6CEDFF80001F16006C6C495A6C6C13036C6CEB07F8D801F8EB1FF06CB4EB7FE0
+6DB51280011F49C7FC010713F8010013C02E517ACE3B>I<49B612FEA490C7003F138092
+380FFE001507B3B3B3A21206EA3FC0487E487EA44B5AA25B007F5D0180131F0078C75B6C
+143F003E4A5A6C5D6C6C495A2707E003FEC7FC3901FC07FC6CB512F0013F13C0D907FCC8
+FC2F547BD13C>74 D<B600FC030FB512E0A4C691CAEBFC00D97FFCEF3FF06D48EF1FC001
+1F616E71C7FC130F1A0E6E171E0107181CA26E173C6D1838816D60A26F16F06D6081027F
+4C5AA281023F4C5AA26F1507021F94C8FC81020F160EA26F151E0207161CA26F153C6E16
+38826E5EA27014F06E5E821801037F5D82033F4A5AA2701307031F92C9FC82030F140EA2
+70131E0307141CA270133C6F143817806F5CA2EFC0F06F5C17E017E1047F5B17F193383F
+F380A217FF7090CAFCA2705AA3705AA3705AA2705AA3705A53547ED158>86
+D<EC0FF891B5FC010314C090390FF80FF090391FC003FC90397F8001FE49C77E4848EC7F
+804848143F49EC1FC0485A000FED0FE05B001F16F01607485AA2007F16F8A25B160312FF
+90B7FCA30180C9FCA8127F7FA2123FA26D1538121F17786C6C1570000716F06D15E06C6C
+14016C6CEC03C06C6C15806D6C130F6D6CEB1F00D90FF0133C903907FE01F80101B512E0
+6D6C1380DA07FCC7FC2D367DB434>101 D<1378EA01FE487E487FA66C90C7FC6C5AEA00
+7890C8FCB0EB7F80B5FCA41203C6FC137FB3B3A43801FFE0B61280A419507CCF21>105
+D<EB7F80B5FCA41203C6FC137FB3B3B3B13801FFE0B612C0A41A537CD221>108
+D<01FFEB07FCB590383FFF8092B512E0913901F00FF8913903C007FC000349C66C7EC601
+0E13016D486D7E5C143002706E7E146014E05CA35CB3AD2601FFE0903801FFE0B600C0B6
+12C0A43A347CB341>110 D<EC0FFC91387FFF8049B512E0903907F807F890391FE001FE
+90393F80007F017EC7EA1F80496E7E48486E7E00038248486E7EA248486E7EA248486E7E
+A2003F82A24848ED7F80A400FF17C0AB007F1780A26D15FFA2003F1700A2001F5E6D1401
+000F5E6D140300075E6C6C4A5A6C6C4A5AA2D8007FEC3F806D6C49C7FC90391FE001FE90
+3907F807F86DB55AD9007F1380DA0FFCC8FC32367CB43B>I<01FFEB1F80B5EB7FF09138
+01FFF8913803E1FC91380783FE0003EB0F07C6131EEB7F1C1438143091387003FC913860
+00F0160014E05CA45CB3AA8048487EB612F0A427347DB32E>114
+D<D907FE13C090387FFF8148B512E33907F803FF390FC0007F4848133F48C7121F003E14
+0F007E1407127C00FC1403A315017EA27E7F6C6C90C7FC13F013FF6C13F86CEBFF806C14
+E06C14F86C14FEC680013F1480010714C0D9003F13E014039138007FF0151F00E0140FED
+07F8A26C1403A215017EA36C15F0A26C14036C15E015076DEB0FC06DEB1F80D8FDF0EB3F
+0039F8FC01FE39F07FFFF8D8E01F13E0D8C00390C7FC25367CB42E>I<D97F80EC7F80B5
+91B5FCA400031503C61500017F157FB3AC17FFA35EA3013F5C6EEB077FA2011F020E7F6D
+6C011C13F06E0178EBFFC0903903FC01F06DB512E06D6C1380912607FC00EB80003A357C
+B341>117 D<B60103B51280A4000301F09039007FF800C601C0EC3FE0017FED1F8095C7
+FC133F6E141E131F171C6E143C010F15388001075DA26E14F001035D8001014A5AA26E13
+036D5D1580027F49C8FCA26F5A023F130E15E0021F5BA2EDF03C020F133815F802075BA2
+EDFCF002035B15FE6E6C5AA36E5BA26FC9FCA3153EA2151CA2153C153815781570A215F0
+5D14015DA2003E495A127F486C48CAFCA2140E141E495A6C5B007C5B383F03E06CB45A00
+075BD801FCCBFC394B7EB23E>121 D E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fk cmbx12 17.28 21
+/Fk 21 118 df<F00FE04E7EA24E7EA34E7EA24E7EA34D7FA24D80A24D80A34D80A24D80
+A34D80A2DD7FBF7FA2181F05FF8017FE04016D7FA24D7E04038217F804076D80A24D7E04
+0F8217E0041F6D80A24D7F043F825F047F6E7FA294C77E4C825E03016F7FA24C80030384
+5E03076F80A24C80030F845E031F6F80A24C81033F845E037F707F93B9FCA292BA7EA24A
+85A203FCC912070203865D020771805D86020F864B82021F865D87023F864B83027F8692
+CBFC874A864A840101875C496C728090381FFFC0B700E092B812FEA66F647BE37A>65
+D<BD12E0A41CF0A2D8000102C0C71207F1003F1A0F1A031A001B7F1B3FF31FF81B0FA21B
+07A21B03A21B011CFCA31B00A419FCA21C7EA41C00A21801A31803A21807180F183FEF01
+FF93B6FCA6EEC001EF003F180F18071803A21801A31800A896C9FCB3A5B912F8A657617A
+E065>70 D<B912E0A6C702E0C7FCB3B3B3B3AEB912E0A633627CE13C>73
+D<BB7E1AFCF2FFC01BF81BFE757ED800010280C7001F80070114F0736C7F081F7F747F74
+7F7414807414C0A27414E0A21DF0A27513F8A41DFCA91DF8A498B512F0A21DE0A25014C0
+1D8062501400505B505B087F5B4FB512E0071F5C93B9C7FC1BFC1BF01B8008F0C8FC04C0
+CCFCB3B3A2B97EA65E627AE16E>80 D<DBFFFCEC01E0020FD9FFE01303027F02FC130749
+B7130F0107EEC01F011F16F049D9C007EBF83F4948C7383FFE7FD9FFF8020FB5FC4801E0
+14014849804849153F91C97E484882001F834982003F83845B007F187FA2193FA200FF18
+1FA27F190FA27FA26D17078080806C01F893C7FC80ECFF8015F86CECFFC016FC6CEDFFE0
+17FE6CEEFFE018F86C17FE6C717E6C846C846D17F86D836D836D8313036D18806D6C17C0
+020F17E01401DA000F16F01500040715F8EE007F1703050014FC183F84060713FE84A200
+7C8300FC83A2197FA3193F7EA31AFC7EA27F1AF86D177F7F1AF06D17FF6D18E06D5E01FF
+18C06E4B138002E04B130002F84B5A02FFED3FFC01CF01E0ECFFF8018301FF010F5B0101
+91B65A6D6C5E48011F93C7FC48010315FC48D9003F14E048020149C8FC476677E35A>83
+D<001FBEFCA64849C79126E0000F148002E0180091C8171F498601F81A0349864986A249
+1B7FA2491B3F007F1DC090C9181FA4007E1C0FA600FE1DE0481C07A5CA95C7FCB3B3B3A3
+021FBAFCA663617AE070>I<913803FFFE027FEBFFF00103B612FE010F6F7E4916E09027
+3FFE001F7FD97FE001077FD9FFF801017F486D6D7F717E486D6E7F85717FA2717FA36C49
+6E7FA26C5B6D5AEB1FC090C9FCA74BB6FC157F0207B7FC147F49B61207010F14C0013FEB
+FE004913F048B512C04891C7FC485B4813F85A5C485B5A5CA2B55AA45FA25F806C5E806C
+047D7F6EEB01F96C6DD903F1EBFF806C01FED90FE114FF6C9027FFC07FC01580000191B5
+487E6C6C4B7E011F02FC130F010302F001011400D9001F90CBFC49437CC14E>97
+D<903807FF80B6FCA6C6FC7F7FB3A8EFFFF8040FEBFF80047F14F00381B612FC038715FF
+038F010014C0DBBFF0011F7FDBFFC001077F93C76C7F4B02007F03F8824B6F7E4B6F1380
+4B17C0851BE0A27313F0A21BF8A37313FCA41BFEAE1BFCA44F13F8A31BF0A24F13E0A24F
+13C06F17804F1300816F4B5A6F4A5B4AB402075B4A6C6C495B9126F83FE0013F13C09127
+F00FFC03B55A4A6CB648C7FCDAC00115F84A6C15E091C7001F91C8FC90C8000313E04F65
+7BE35A>I<92380FFFF04AB67E020F15F0023F15FC91B77E01039039FE001FFF4901F801
+0113804901E0010713C04901804913E0017F90C7FC49484A13F0A2485B485B5A5C5A7113
+E0485B7113C048701380943800FE0095C7FC485BA4B5FCAE7EA280A27EA2806C18FCA26C
+6D150119F87E6C6D15036EED07F06C18E06C6D150F6D6DEC1FC06D01E0EC7F806D6DECFF
+00010701FCEB03FE6D9039FFC03FFC010091B512F0023F5D020F1580020102FCC7FCDA00
+0F13C03E437BC148>I<92380FFFC04AB512FC020FECFF80023F15E091B712F80103D9FE
+037F499039F0007FFF011F01C0011F7F49496D7F4990C76C7F49486E7F48498048844A80
+4884485B727E5A5C48717EA35A5C721380A2B5FCA391B9FCA41A0002C0CBFCA67EA380A2
+7EA27E6E160FF11F806C183F6C7FF17F006C7F6C6D16FE6C17016D6C4B5A6D6D4A5A6D01
+E04A5A6D6DEC3FE0010301FC49B45A6D9026FFC01F90C7FC6D6C90B55A021F15F8020715
+E0020092C8FC030713F041437CC14A>101 D<EE3FFC0307B51280033F14C04AB612F002
+0715F84A9038F03FFC4AEB807F913A7FFE00FFFE4A5A4B4813FF4913F05B4913E0A24913
+C0A27013FE4949EB7FFCEF3FF8EF1FF0EF07C094C7FCB0B812C0A6D8001F01C0C8FCB3B3
+B0007FB612FCA638657CE431>I<F107F8DB7FFEEC3FFE020FB5D8F001B5FC027FDAFE03
+148049B7128F49DCDFFD13C0010FD9F00FEBFFC149D9800114014990C7EBFC0349486E6C
+7E4948EC3FFF48496E018113800780130048F0C03E97C7FC48496E7FA34884A96C60A36C
+6D4A5BA26C60A26C6D4A90C8FC6D6C4A5A6D6C4A5A6D6D485BDBF00F5B4990B612C060D9
+7C7F4AC9FCD9FC0F14F09126007FFECAFC92CCFC1201A47FA27F8014F091B77E18FE6CEF
+FFC019F06D17FC19FF6D846D846D846D84013F8490BAFC0003854801E0C712014890C900
+0F7F484816014848EE007F4848717E8512FF5B85A56D5F007F616D173F003F616D177F6C
+6C4D5A6C01C003035B6C6D4B5B6C01F8031F5BC601FF92B5C7FC6D01F8011F5B011F90B7
+12F8010717E0010094C8FC020F15F0DA003F01FCC9FC4A607CC151>I<EB0FE0EB3FF849
+7E48B5FCA24880A24880A76C5CA26C91C7FCA238007FFC6D5AEB0FE090C9FCAF903807FF
+80007FB5FCA6C6FC7F7FB3B3AEB712C0A622657BE42C>105 D<903807FF80B6FCA6C6FC
+7F7FB3B3B3B3ADB712E0A623647BE32C>108 D<902607FF80D91FFFEEFFF8B691B500F0
+0207EBFF80040702FC023F14E0041F02FF91B612F84C6F488193267FE07F6D4801037F92
+2781FE001F9027E00FF0007FC6DA83F86D9026F01FC06D7F6DD987F06D4A487F6DD98FC0
+DBF87EC7804C6D027C80039FC76E488203BEEEFDF003BC6E4A8003FC04FF834B5FA24B5F
+A24B94C8FCA44B5EB3B2B7D8F007B7D8803FB612FCA67E417BC087>I<902607FF80EB1F
+FFB691B512F0040714FC041F14FF4C8193267FE07F7F922781FE001F7FC6DA83F86D7F6D
+D987F07F6DD98FC0814C7F039FC78015BE03BC8003FC825DA25DA25DA45DB3B2B7D8F007
+B71280A651417BC05A>I<923807FFE092B6FC020715E0021F15F8027F15FE494848C66C
+6C7E010701F0010F13E04901C001037F49496D7F4990C87F49486F7E49486F7E48496F13
+804819C04A814819E048496F13F0A24819F8A348496F13FCA34819FEA4B518FFAD6C19FE
+A46C6D4B13FCA36C19F8A26C6D4B13F0A26C19E06C6D4B13C0A26C6D4B13806C6D4B1300
+6D6C4B5A6D6D495B6D6D495B010701F0010F13E06D01FE017F5B010090B7C7FC023F15FC
+020715E0020092C8FC030713E048437CC151>I<D90FFFEB0FFCB690383FFF8093B512E0
+4B14F04B14F8923907FC7FFC92390FE0FFFEC6EC1F806DD93F0113FF6D133E157E157C15
+F8A215F07013FEA24BEB7FFCEF3FF8EF0FE04B90C7FCA55DB3B0B712F8A638417BC042>
+114 D<913A3FFF8007800107B5EAF81F011FECFE7F017F91B5FC48B8FC48EBE0014890C7
+121FD80FFC1407D81FF0801600485A007F167F49153FA212FF171FA27F7F7F6D92C7FC13
+FF14E014FF6C14F8EDFFC06C15FC16FF6C16C06C16F06C826C826C826C82013F1680010F
+16C01303D9007F15E0020315F0EC001F1500041F13F81607007C150100FC81177F6C163F
+A2171F7EA26D16F0A27F173F6D16E06D157F6D16C001FEEDFF806D0203130002C0EB0FFE
+02FCEB7FFC01DFB65A010F5DD8FE0315C026F8007F49C7FC48010F13E035437BC140>I<
+EC07E0A6140FA5141FA3143FA2147FA214FF5BA25B5B5B5B137F48B5FC000F91B512FEB8
+FCA5D8001F01E0C8FCB3AFEF0FC0AC171F6D6D1480A2173F6D16006F5B6D6D137E6D6D5B
+6DEBFF836EEBFFF86E5C020F14C002035C9126003FFCC7FC325C7DDA3F>I<902607FFC0
+ED3FFEB60207B5FCA6C6EE00076D826D82B3B3A260A360A2607F60183E6D6D147E4E7F6D
+6D4948806D6DD907F0ECFF806D01FFEB3FE06D91B55A6E1500021F5C020314F8DA003F01
+8002F0C7FC51427BC05A>I E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fl cmbx12 24.88 40
+/Fl 40 122 df[<96380FFFFE060FB612E04DB712FC051F16FF94B912C0040784041F18
+F8047F9126FC001F7F4BB6008001017F030702F8C8EA3FFF4B02E0030F7F033F02804B7F
+4B49C9127F92B54893B57E4A02F05D4A4A4B804A4A5D4A4A84634A91C9FC4A5BA24A5B51
+80755C91B5FC5EA3755CA2755C755C755CE23FFEC8FCF40FF899CAFCAF083FB612FCBFFC
+A9C702FCC912038787B3B3B3B2003FB800F0013FB812F0A9>116
+144 123 271 129 12 D[<EB1FE0EBFFFC00037F486D7E488048804880A24880A281B6FC
+81A281A416807EA37EA27E7E6C14BF6C143FC613FCEB1FE090C7FC157F1600A55D5DA214
+015DA214035D1407A24A5AA24A5AA24A5A147F5D4AC7FC5B495A5C1307495A495A495AEB
+FFC0485B4890C8FC485A5B6C5A6C5A6C5A>33 70 111 270 65 39
+D<BA12F0B33C137DB74D>45 D[<1CFC517E517E1D8063A263A3511300A2515AA3515AA2
+515AA3505BA2505BA3505BA2505BA35090C7FCA2505AA3505AA2505AA34F5BA24F5BA34F
+5BA26361A24F90C8FCA34F5AA24F5AA34F5AA24E5BA34E5BA24E5BA34E5BA24E90C9FCA3
+4E5AA24E5AA34E5AA24D5BA34D5BA2615FA24D5BA34D90CAFCA24D5AA34D5AA24D5AA34C
+5BA24C5BA34C5BA24C5BA34C90CBFCA24C5AA34C5AA24C5AA34B5BA25F5DA24B5BA34B5B
+A24B90CCFCA34B5AA24B5AA34B5AA24A5BA34A5BA24A5BA34A5BA24A90CDFCA34A5AA24A
+5AA34A5AA25D5BA2495BA3495BA2495BA34990CEFCA2495AA3495AA2495AA3485BA2485B
+A3485BA2485BA34890CFFCA2485AA3485AA2485AA35BA25B127F6C5A6C5A>89
+207 115 282 116 47 D[<F31FE0F37FF8A2517EA2507FA3507FA25080A35080A25080A3
+5080A25080A397B67EA24F81A34F81A24F82A34F82A24F82A21AFBDF3FF981A2DF7FF181
+1AF06207FF6D80A24E01C081871A804E6E80A24E0100828761060F6E81A24E4883876106
+3F6E81A24E4883876106FF6F80A24D498388614D7080A24D90C8FC768160050F7081A260
+051F708160053F7081A260057F70816005FF7180A2604C7280604C7280A295CAFC4C7281
+5F040F7281A294BDFC4C88A24C88A34C88A293BE7E05E0CB7E5F4B7480A24B497280A294
+CCFC4B7481A24B487381A25E031F7481A24B487381A25E037F7481A24B487480A25E4A76
+80A24A497480A293CEFC4A7681A24A4875814A7E0107B512FCB96C043FBA12FCA9>158
+145 120 272 175 65 D[<BFFC1EFEF6FFE01FFCF7FF8020F020FC20FF8DC7000392CA00
+1F15E00B0181776C800C1F807814FF0C03818A78818E79808B8E8B8E8B8EA27980A47915
+80AB551500A4555CA26A676A676A555C9CB65AA2545D5492C7FC545C5414F80C3F5C545C
+53B612800B0F4AC8FC0B7F14F80A1FB612E095BBC9FC1FF81F801FF8F7FF8020F820FE95
+CBECFFC00C1F14F00C07807814FE0C006E7E7980798079807980798079808E79158023C0
+8B23E08C23F0A223F88CA223FCA38C23FEAB5614FCA55614F8A39DB612F0A25515E06723
+C055158067551500555C555C9CB6FC545D0C075D0C1F15C09BB75A0B0F93C7FCC212FC69
+21E021800EFCC8FC20F020800DF0C9FC0CFCCAFC>143 142 120
+269 165 I[<0803B500C0EE01F00703B600FEEE03F8077FDBFFE015070607B800FC150F
+063F05FF151F4DBA00E0143F050F07F8147F053F07FE14FF94BC5B04039326F8000FECC0
+03040F4BC86CEBF007043F03C0030F6D5A93B648C900036D5A4B03F09339007FFF3F0307
+03C0051F90B5FC4B92CB7E033F02FC18034B02F08492B648844A0380193F4A92CD7E4A4A
+864A4A864A02F0864A4A864A8991B65A494B874992CF7E4C885B494A885E498B494A88A2
+495C8D90B65A8D5A5E48217FA24892D1FC223FA25A5DA248211FA3485CFA0FF09FC7FCA2
+5AA45DA3B6FCB27EA381A47EA46C80FA07F0FA0FF87EA2817EA36C6F1D1F23F07E827E22
+3F6D6E1EE0A26D6E1D7F23C06D6E1DFF7F705213806D806D55130070646D6F646D6F515A
+6E6E1B1F6E6E515A6E6E515A6E6E1BFF6E6E505B6E6E505B6E6F4F5B6E03E04F90C7FC6F
+6EF13FFE6F02FC4F5A030F02FF4E485A6F03C005075B030103F0051F5B6F03FE057F1380
+043FDAFFE00303B5C8FC040F03FE033F13FC0403DBFFF80107B55A040093B812E0053F1A
+80050F4FC9FC050119F8DD003F18C0060795CAFCDE007F16F0070393CBFCDF000314C0>
+141 146 115 271 168 I[<BE12FEF5FFFCF6FFC01FFCF7FF8020E020FC20FF21C0C700
+030380C8000116F0E2000F810B0015FE0C1F800C0315C00C00810D3F8079800D0714FE79
+807981796C808C7A807A808F7A807A808C8F7A818DA17E8DA17E8DA17EA27B80A2A17E8D
+A17EA28DA17EA3A113808DA3A113C0A57B15E0A6A113F0B3A2A113E0A569A113C0A5A113
+80A269A2A11300A3575CA2A15AA269A15A69A15AA2575CA15A69A15A9EB6FC5692C7FC6B
+565C68565C565C565C565C9DB65A5592C8FC0D075C555C0D3F5C9CB65A0C0315C00C0F5D
+0C7F92C9FC0B07B612FC52B712F0C212C09ECAFC20FC20F020800DFCCBFC1FE00CFCCCFC
+53CDFC>156 142 120 269 178 I[<C212F8A48DA5C7000303C0C9123FF5007F1E0F0C01
+80787E1F1F8B8B1F018BA27A7E8C8CA28CA28CA28C8EA28CA38CA38EA2E21FF0157FA67B
+7EA40A3F93C8FCA41C7FA21CFFA26363631B1F1B7F0807B5FC95B8FCA99538C00007F200
+7F1B1F1B07878787A21C7FA21C3FA3FA7FC01C1FA2FAFF80A6571300A299CAFCA369A26A
+A22107A3210F6AA2211FA2213FA2575AA221FFA26868565BA26868207F9DB5FC555C1F07
+1F1F1F7F0C03B6FC1E3F0B1FB7FCC35AA66AA3>138 141 120 268
+153 I[<C21280A421C0A5C7000303C0C81201F40007F5007F0C1F14E01E071E01787E8B
+8B8B8B7913F0A28B8BA2207FA3203F21F8201FA4200FA321FC2007A4F47FC0A3F803FEA4
+9DC7FCA31CFFA463A263A26363631B7F50B5FC1A1F95B8FCA99538C0001F1A01747E1B1F
+878787A287A287A41C7FAA99CBFCB3AFBC12F8A9>127 141 120
+268 146 I[<0803B500C0EE01F00703B600FE4C7E077FDBFFE015070607B800FC150F06
+3F05FF151F4DBA00E0143F050F07F8147F053F07FE14FF94BC5B04039326F8000FECC003
+040F4BC86CEBF007043F03C0030F6D5A93B648C900036D5A4B03F09339007FFF3F030703
+C0051F90B5FC4B92CB7E033F02FC18034B02F08492B648844A0380193F4A92CD7E4A4A86
+4A4A864A02F0864A4A864A8991B65A494B874992CF7E4C885B494A885E498B494A88A249
+5C8D90B65A8D5A5E48217FA24892D1FC223FA25A5DA248211FA3485C7C5A9FC9FCA25AA4
+5DA3B6FCB27EA381A20A0FBB12F8A27EA46C80A36C98C96C02F8C7FCA2817EA36C81A27E
+827E827FA26D80A26D806D80A26D806D80A26D816D816E806E806E806E6E97B6FC6E806E
+806E03C0606E816F02F8606F02FE60030F6E606F03E0173F030103F85F6F03FF933801FF
+FC043F03E00307497E040F03FF033F497E040304FC0107B5EAE00F040093B8487E053FF2
+0001050F07FCEB007F050107F0141FDD003F06C01407060795C81201DE007F04F8ED0070
+0703048093C8FCDF000302E0CDFC>157 146 115 271 183 I[<BC12C0A9C7000103E0C8
+FCB3B3B3B3B3B3B0BC12C0A9>74 142 122 269 87 73 D[<B900E04EB912F884848484
+A2848585C700037094C7000302FCC7FC73DF000F90C8FC7C5A85858585A2708170817081
+7081868270817081708187837181718171817181A2718171817181728188847281728172
+817281A272817281738173818985738173817381898573817481748174818A8674817481
+74818A8675817581758175818B877581758175818C887681768176817681A27681768176
+8177158021C0897715E07715F07715F87715FCA27715FE7715FF7815877815C722E78A78
+15F77815FF8AA28A8A8B8B8BA28B8B8B8BA28B8C8C8C8CA28C8C8C8CA28D8D8D8D8DA24A
+6D8849B500FE88B900FC86227FA2223F221F220F2207A27C5A>165
+142 120 269 182 78 D[<97B512F0077FECFFE00607B712FE067FEEFFE00503B912FC05
+1FF0FF80057F19E00403BB12FC040F9226E0007F14FF043F02FCC7000315C04C02E0DA00
+7F804BB60080031F14F8030702FCC9000314FE4B4A70804B02E0706C80037F0280051F14
+E092B6CB6C804A4A72804A4A72804A02F00600804A4A737F4A4A73804A8B4A4A738091B6
+CD6C80494A7480A2494A7480494A7480498C4C86498D4C87498D494A7580A290B68B4C87
+488EA24892CF6C80A3488E4B88A2488EA3484A761580A34823C0A5484A7615E0A7B621F0
+B36C23E0A26F64A56C23C0A46F646C2380A36C23006F64A26C6AA270636C6AA26C6A7063
+6C6A70636D69A26D6E98B65AA26D6E505DA26D6E5092C7FC6D6870626D6E505C6D686D6F
+4F5C6E6E4F5C6E6E4F5CA26E6E96B65A6E6E4E92C8FC6E6E4E5C020102FF060F14F86E6F
+4D5C6F6E4D5C6F02F094B65A030F6E4C92C9FC6F02FE04075C03016E6C031F14F86F03F0
+92B65A043F02FE020715C0040FDAFFF090B7CAFC040392B812FC04001AF0051F19800507
+4ECBFCDD007F17E0060F94CCFCDE007F15E0070002F0CDFC>148
+146 115 271 175 I[<BE12F8F5FFF01EFF1FE01FFCF7FF8020E020F820FEC700030380
+C8000781E2003F15C00B03810B00810C3F8078800C07807880788178818E8B8E8B8E8B8E
+A28EA28B8EA42380AC2300A46A67A26AA26A676A676A9CB65A6A665492C7FC545C0C1F5C
+545C9BB612E00B075D0B3F5D0A07B648C8FC95BB12F820E0208055C9FC1FF09CCAFC1EF0
+0BF8CBFC06C0D0FCB3B3B2BCFCA9>137 142 120 269 159 I[<BD12FCF4FFFCF5FFE01E
+FCF6FFC01FF01FFE797E20E0C700030380C86C15F80A0181E2003F14FF0B07810B0115E0
+776C8078807880788078808A78818E7881A28E8B8EA37980A48EAA6AA3676AA26AA29CB6
+5AA26A545D9FCAFC66545C545C545C545C9BB612C0535D0B074ACBFC0B3F5C52B612F00A
+7F15C095BBCCFC1FF81FC054CDFC66F6FF801FE00680C7000315F8E1003F14FE0A0F800A
+0315C07681766C807780778077808C7781898D898D898DA38A8DAD8DACA1EB1FC0A1EB3F
+E08D8AA37880A1137FA114C078817818FF7C1580785F786F1500BB00FE6F6F5B796E495A
+7902FEEB1FFC799139FFC07FF80D0792B55A0D015F796C5E0E1F5E0E034BC7FCD4001F14
+F8E7003F13C0>163 144 120 269 173 82 D[<93260FFFF8163E4BB600E0153F031F03
+FE5D037FDBFFC05C0203B800F05B020F05FC5B4A05FF5B027FF0C00F91B526FE000FECF0
+1F010302C0D9007F6D5A4991C800076D5A4901FC030090B6FC4901F0163F4949160F4901
+808290B5170192CBFC4849844849181F87484984A2484984874886A248498588A24887A3
+88A2B58680A36E85A280A26E8580A2818103F0725A6C6E96C7FC15FE8116E06C15FEEEFF
+E017FF6C17F0F0FF806C18F8F1FFC06C19FCF2FF806C1AE01BF86C1AFE6C747E6D1AE088
+6D866D866D1AFF6D876D87010087806E86020F86020386020086153F030F851501DB001F
+19801601DC000F18C0EF007F060717E0F0003F070316F0F1003F1A0F080315F81A00871B
+1F877514FCA287007F86486C85A288A388A36D86A31EF87FA37F1EF0A26D626D1CE0A27F
+6D5013C0A26E1B806E96B5FC6E1B0002F8606E4E5B6E626E6C5F03E04D5B03F84D5B03FE
+057F5BDBFFC093B55A04F803035C496CD9FF80021F91C7FCD9FC1F02FF49B55AD9F80792
+B75A496C19F049C66149011F18804901074DC8FC90C817F848031F16C048030003FCC9FC
+007C04011480>102 146 115 271 129 I[<000FC312F8A6488EA304C0C7001F4AC71201
+03F8C8F0000F03C01C0192C9737E02FC1E1F4A1E0702E08A4A8A4A8A4890CA757EA24920
+3F49201FA349200FA2492007A4492003007F8EA4498CA848487A1380A6CC99C7FCB3B3B3
+B3AA030FBD12FCA9>145 140 120 267 162 I[<BC040FB912C0A9C7000303C0CD001F02
+E0C7FC9E26007FF8C8FC7C5AB3B3B3B3B36E555AA3848022FF6BA26F65726481696F9CC9
+FC72626F66210F6F6E505AA26F6E505A6F535A6F6E1AFF734E5B706E4E5B70637002F04E
+5B706E063F90CAFC706E4E5A7002FF4D485A04006F04075B7102E0043F5B7102FC4BB55A
+050FDAFF80020F14807103FC0103B6CBFC050192B812FC716C61061F19E0060319800600
+06FCCCFC071F17F007011780DF001F03F8CDFCE0001F49CEFC>162
+144 120 269 179 I<93B512FC037FECFFF00207B8FC023F17E091B912F84918FE010772
+7E499126C0007F14E04901E0C7000F80496D020380496D020014FE6F6F7F90B570806F6F
+8085486E6F807380A27380A28885886C5CA26D4982886D5B6D5B010713C0010190CAFC90
+CCFCA90603B7FC050FB8FC0403B9FC167F0307BAFC153F4AB7EA807F020FEDE000023F02
+FCC7FC91B612E0010392C8FC4914FC011F14F04914C0495C90B548C9FC485C485C485C48
+5C5A5D485CA24891CAFCA3B6FC5CA397B6FCA461806C60F107EF6C6E150F6F16CF6C183F
+6FDB7F8F806C6EDBFF0F14E06C02FCDA03FE15FE6C6E91260FFC0791B5FC6C6E6CD93FF8
+17806C923AF803FFF003013F91B6487E010FEF8000010394C77E010004FC141F021F03F0
+140702010380DA007F1400DA000701F8CDFC695F79DD71>97 D[<ED1FF0017FB5FCB7FC
+A9EA003F1307A27FB3B296383FFFC00607B512FE063FECFFE04DB712F8050716FF051F17
+C0057F17F094B5D8C00F8004F301FCC714FE04F701E0023F7F93B50080020F804DC86C14
+E005F80301804D6F804D707F05808294CA804C717F4C7180A24C71808BA27680A28B88A2
+8BA28BA3888BA52080B02000A56764A267A3676467A2525CA267647062704D91C7FC704D
+5BA2714C5B7193B55A05F04B5CDCBFF84B5CDC1FFC030F5C4B6CB44B91C8FC7001C0027F
+5B4B6C01F00103B55A4BC601FF013F14F04B6D90B712C04B011F94C9FC4B6D16FC4B0103
+16F092C86C15804A030F02F8CAFC90CB49CBFC>113 144 121 270
+129 I<94387FFFF0041FB612E093B712FE0307707E031F17F092B97E4A18FE020784021F
+9126F8000F14804A0280010014C04A49C74814E049B500F85C494A17F0494A5C495C494A
+4A14F84991C8FC5D495B90B5FC5D5A485C7314F05A4B6F14E05A7314C0487214804B9338
+3FFE00F20FF84896C8FCA4485CA5B6FCB07EA281A37EA36C80A37E6F18FE6CF201FFA26C
+6E5F1CFE6C801B076C6EEF0FFC6D7F70EE1FF86DF13FF06D6E167F6D6EEEFFE06D02F84B
+13C06D6E5D6D02FF030F13806D03C0023F1300023F02F0903801FFFC6E9126FF801F5B02
+0792B65A6E18C0020060033F4CC7FC030716F8030016C0041F4AC8FCDC007F13C0585F78
+DD67>I[<F53FE098B6FC4FB7FCA996C77E1B0FA287B3B294383FFF80040FB512FC93B712
+80030716E0031F16F8037F16FE4AB9128702074AC66C13C7021F02E0010713F74A91C890
+B6FC4A01FC153F49B548150F4902E081494A81494A814991CA7E495B8749498390B54883
+5A5D5AA2485CA25A5D5AA35AA25D5AA5B6FCB07EA57E81A37EA27EA2817EA26C80A26C62
+6C6E5F636D7F6D6D94B6FC6D606D6D1607705D6D6E4B81010102F0157F6D6E92B712FE6E
+01FE020301EF91B512806E6D6C011F13CF020FDAF801B5120F020391B612FE6E17F86E6C
+16E0030F16800301EDFC00DB003F14E0040049C74AC8FC>113 144
+120 270 129 I<94387FFFC0040FB6FC93B712E0030716FC031F16FF037F17C04AB912F0
+0207DAF80380021F912680003F13FE4A49C7000F7F4A01F802038049B5486E804902C06E
+6C7F494A6F7F4991C9FC49727F4949707F4B84498490B548707F5A4B198048855D481CC0
+86481CE05D5A871DF05AA25D5AA21DF887A2B6FCA392BBFCA51DF00380CDFCA77EA4817E
+A37EA2817EA26CF307F06FF00FF87E816C1B1F6F19F06C1B3F6D6DF07FE06D7FF4FFC06D
+6E4C13806D6E5E6D02F04C13006D6EEE1FFE6D6E4C5A6D6C01FFEEFFF86E02E002035B6E
+02FC021F5B02079126FFC003B55A6E92B7C7FC020060033F17F8030F17E003011780DB00
+3F03FCC8FC040315C0DC000F01F8C9FC5D5F7ADD6A>I[<95383FFF80050FB512F094B612
+FE040781041F16C0047F824BB87E0307DAF8077F031FDAC00F7F4B49C6487F4B495B92B5
+00F0814A4A5B4A5C4A93B612805F4A91C7FC5C5E5C5E5C731400A24C6E5B91B56F5BA273
+5B070313E00700138097C8FCB3A4BA12F8A9C702FCCBFCB3B3B3B3A2003FB9FCA9>81
+144 121 271 71 I<F5FFC093260FFFFC030F13F04BB600E0027F7F031F03FE49B512FE
+037F9226FF8007800203B8EAF01F020FDDFC3F15804A7148133F027FDA003F90B500F014
+C091B500F80107ED807F4902E00101ECFC00010702806D6C5B93C87E49496F7F49496F7F
+49496F6D6D1380491A8077130090B5486F6E6C5AF503F84875C8FCA2484A6F80A44887AB
+6C63A46C6E4B5CA26C63A26D6D4B5CA26D97C9FC6D6D4B5B6D6D4B5B6D6D4B5B705C0101
+02E049B512E06D02F801075C4902FF013F5C4992B648CAFC496002F317F090260FE07F16
+80031F4BCBFC90261FC00115E0DB000F01FCCCFC013F91CFFCA3137FA280A380A2808080
+6E7E15F092B812F06DF0FFE01BFEF3FFC06D1AF81CFE767E6D1BE06D87896D1BFE6D877F
+6E878A0103BD7E130F013F8890BEFC4802E0C9003F814891CBFC4801FC180F4849060180
+4849727E484985884849737F88A2B55A88A66E616C65A26E616C6D4F5B6C656E616C6D4F
+5B6C6D96B55A6C6D6C05035C6F5FC602F0051F49C7FC6D01FC057F5B6DD9FF800303B55A
+010F02F8033F14E06DDAFFE0010FB65A010192B9C8FCD9003F19F8020F19E0020196C9FC
+DA001F17F0030194CAFCDB000192CBFC6A887ADD74>I[<ED1FF0017FB5FCB7FCA9EA003F
+1307A27FB3B2963803FFFC073FEBFFE096B612F8060715FE061F6F7E4E16E095B87E4DD9
+FC03804DD9C000804D48C76C7FDD0FF880DD1FE0824D486E804D5A05FEC881DCF1FC815F
+04F385EEF7F04D81EEFFC0A24D84A294C9FCA25EA35EA45EB3B3AFB9D8E001B912C0A9>
+114 143 119 270 129 I[<EC3FC0ECFFF0010313FC497F497F498049804980A290B67E
+A24881A86C5DA26D5CA26D5C6D5C6D91C8FC6D5B6D5B010013F0EC3FC091CAFCB3A3ED1F
+F0017FB5FCB7FCA9EA003F1307A27FB3B3B3B0B91280A9>49 144
+119 271 65 I[<ED1FF0017FB5FCB7FCA9EA003F1307A27FB3B3B3B3B3B3ACB912C0A9>
+50 143 119 270 65 108 D<DB3FE0912601FFFC943801FFFC017FB5031FD9FFE0041FEB
+FFE0B792B600FC93B612FC060303FF030315FF060F04C0020F16C0063F04F0023F16F095
+B86C91B87E4DD9FC036E49D9FC03804DD9C0006E49D9C000804D48C7003F6D4948C7003F
+7FDD0FF86EDB0FF880D8003F4B48714848830107DB3FC06E9126C03FC06E804D484E5A6D
+4BC86F48C881DCE1FE6FDAE1FE814D61DCE3F8DEF3F884DCE7F0F0F7F04D6F4B81DCEFC0
+F0FFC0A2DCFF804F84A294C993C9FCA24C61A34C61A44C61B3B3AFB900E090B900E090B9
+12E0A9B35D77DCC2>I<DB3FE0913803FFFC017FB5033FEBFFE0B792B612F8060715FE06
+1F6F7E4E16E095B87E4DD9FC03804DD9C000804D48C76C7FDD0FF880D8003FDB1FE08201
+074B486E804D5A6D03FEC881DCE1FC815F04E385EEE7F04D81EEEFC0A2DCFF8084A294C9
+FCA25EA35EA45EB3B3AFB9D8E001B912C0A9725D77DC81>I<94381FFFF00407B612C004
+7F15FC0303B87E030F17E0037F17FC4ABAFC4A9126FC007F80020F02C0010714E04A49C8
+80027F01F8033F13FC91B5486F7F4902C003077F494A6F804991C96C8049497080494971
+7F49874949717FA290B548717F48884B83481D80A2481DC04B83481DE0A2481DF0A3484A
+7114F8A4481DFCA5B61BFEAF6C1DFCA56C6E4D14F8A36C1DF0A36C1DE06F5F6C1DC0A26C
+6E4D1480A26C1D006F5F6C646D6D4D5B6F94B5FC6D636D6D4C5C6D6E4B5C6D6E4B5C6D02
+F0031F5C6D6E4B91C7FC6D6C01FE92B512FC6ED9FFC001075C6E02FC017F5C020791B812
+C0020196C8FC6E6C17FC031F17F003031780DB007F03FCC9FC040715C0DC001F01F0CAFC
+675F7ADD74>I<DB1FF091381FFFC0017FB50203B6FCB7021F15E095B712FC050316FF05
+0F17C0053F17F094B912FC04F1DAC01F8004F79026FC00018093B500E06D6C14C0D8003F
+93C86C8001074B030F8005F86F806D03E06F804D6F804D8194CA6C7F4C864C71805E7680
+A27680A27680A28B88A28BA288A28BA4882080B0200064A467A26467A3525CA267646764
+67647062704D91C7FC7094B55AA2714B5C714B5C714B5C05F84B5C71033F5C05FF4B91C8
+FC06C049B55A04FB01F001075C04F801FF017F14F07190B712C0051F94C9FC7116FC0503
+16F0DD007F1580060F02F8CAFC060049CBFC96CDFCB3ACB912E0A9718579DC81>I<DB7F
+C049B47E90B6021F13F8B7027F13FE4DB67E4D15E04D814D814D01077F94263FF00F7F94
+387FC01F4D48487FD8003F16000107DAC1FE491480EEC3FC6D5DEEC7F05F16CF5F16DF4D
+6D1400A204FFC76C5BA2735B4C6E5B735B070013C04C92C8FCA45EA65EB3B3AAB912FCA9
+515D79DC5F>114 D<92261FFFF814F80203B638C001FC023FEDFC0791B8121F010317FF
+130F013F9038F8001F4990C8FCD9FFF8153F4801E0150F484915034849814890CAFC197F
+4848173F191F485AA2007F180FA31907487EA27FA28002E0705A6E93C8FC14FC14FF15F0
+6CECFF8016FCEEFFF06CEEFF8018F06C17FE727E6C18E0856C18FC6C846C727E6C856D84
+011F846D841303010084023F83140F020183EC001FDB007F16801603DC000F15C0170018
+3F060F14E0007F1703486C82727E857F85857FA2857F1BC07FA27F1B806D5F7F1B006E5E
+6E5F6E163F6E4C5A02FC4C5A6E03035B6E6C4A5B03F0023F5B03FF0107B55A01F991B7C7
+FCD9F07F16FCD9E01F16F0D9800716C0D9000193C8FC48D9003F14F8007C020349C9FC4B
+5F78DD5C>I[<ED03FEA81507A5150FA4151FA3153FA2157FA215FFA25CA25C5CA25C5C5C
+5C91B5FC13035B131F017F91B712F00007BAFCBBFCA7C74AC9FCB3B3AAF101FFB1616E17
+FE82A219076E17FC836EEE0FF871131F6E6EEB3FF071137F6E6EEBFFE06EDAFF0313C06E
+92B512806E1700033F5D6F5D03075D030015E0041F1480040001FCC7FC>72
+132 124 258 90 I<DB0FF8F01FF0017FB594B6FCB74BB7FCA9D8003F94C77E0107190F
+A26D85B3B3B063A463A263A27F6398B6FCA26DF001FB7015036EEF07F3E00FE3806E6D15
+1FE07FC314FF6E6D6CDAFF83EDFFC06E6E010313036E02FCEB3FFE6E91B612FC020017F8
+6F16E0031F16800303EDFE00DB007F14F8040102C093C8FC725E77DC81>I<B90303B7FC
+A9D8000702F8CA000FEBFE006D6E050013E0666D6E6164826D5090C7FC836E4F5AA26E6E
+4C5AA26E6E4C5AA26E6E5F1C3F836E4F5A836E4F5AA26E6E4B5BA26E6E4B90C8FCA26F6E
+5D1B07846F4D5A846F4D5AA26F6E4A5AA26F6E4A5AA26F6E5D1BFF846F4C5B846F4C90C9
+FCA2706E485AA27002C05B1A0F7002E05B1A1F19F0704B5A19F8704B5AA2706E485AA270
+6E5B96B5FC7093CAFCA3715CA2715CA2715CA2715CA3715CA2715CA2715CA27191CBFCA2
+725AA3725A725A725A705D7BDB7B>I<007FB86C49B712FEA9C792C9000F02C0C7FC6E6E
+030101F0C8FC715F6E6E4B5B6E6E4B5B6E4E90C9FC6E6E5E71151F6E6E4B5A6E6E4B5A6E
+4E5A6F6E495B72495B6F6E495B6F806F6E4990CAFC6F4C5A72495A6F6E495A6F6E495A6F
+03815B705E7014C307E75B7091B5CBFC705D705D705D6282705D715C8386718071807180
+837180864D814D815F4D81874D814D81DDFFF3804C13E14C01C1804C0180814E6C804C6E
+804C487F4C48824C486D804C486D804B496D804B497F73804B49834B90C86C804B486F80
+4B48814B486F804B48844C6F804A71804A496F804A49814A90CA814A487180023F728001
+0FB500E07080B8031FB812E0A9735C7CDB7B>120 D<007FB800C04AB71280A9D800034A
+CA000791C7FC6D080013F0775A6D6E4E5AA26E6E6064836E4F90C8FC836E4F5A836E4F5A
+A26E6E4C5AA26E6E5F1C3F6E6E5F1C7F836E4F5A846F4D5B846F4D90C9FCA26F6E4A5AA2
+6F6E5D1B0F846F4D5A846F4D5A846F4D5AA26F6E4A5AA2706E5C627002C091CAFC6219E0
+704B5A19F0704B5AA2706E485AA2706E485AA27002FE5B1A7F19FF704B5AA2715DA27192
+CBFCA2715CA2715CA3715CA2715CA2715CA2715CA2725BA27290CCFCA3725AA2725AA24E
+5AA24E5AA261187FA24E5AA24D5B13FE2603FF804A90CDFC000F13E0486D4A5A487F486D
+4A5AA260B56C141F4D5AA24D5A17FF604C5B4A4990CEFC6C5D4C5A6C49EB3FFC4A495A6C
+4948485A9026FE80075B270FFFC03F5B6C90B6CFFC6C5D6C15F86C6C5C011F14C0010749
+D0FC9038007FE071857CDB7B>I E
+%EndDVIPSBitmapFont
+end
+%%EndProlog
+%%BeginSetup
+%%Feature: *Resolution 600dpi
+TeXDict begin
+
+%%EndSetup
+%%Page: 1 1
+1 0 bop 861 1940 a Fl(FITSIO)76 b(User's)g(Guide)356
+2399 y Fk(A)54 b(Subroutine)e(In)l(terface)h(to)g(FITS)h(F)-13
+b(ormat)53 b(Files)1055 2659 y(for)h(F)-13 b(ortran)53
+b(Programmers)1667 3155 y Fj(V)-10 b(ersion)38 b(2.5)1727
+4058 y Fi(HEASAR)m(C)1764 4170 y(Co)s(de)30 b(662)1363
+4283 y(Go)s(ddard)f(Space)i(Fligh)m(t)f(Cen)m(ter)1522
+4396 y(Green)m(b)s(elt,)g(MD)i(20771)1857 4509 y(USA)1704
+5298 y Fj(July)38 b(2004)p eop
+%%Page: 2 2
+2 1 bop 0 299 a Fi(ii)p eop
+%%Page: 3 3
+3 2 bop 0 1267 a Fl(Con)-6 b(ten)g(ts)0 1858 y Fh(1)84
+b(In)m(tro)s(duction)3136 b(1)0 2118 y(2)119 b(Creating)34
+b(FITSIO/CFITSIO)2405 b(3)136 2280 y Fi(2.1)94 b(Building)28
+b(the)i(Library)57 b(.)45 b(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)h
+(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)
+h(.)g(.)f(.)h(.)g(.)f(.)131 b(3)136 2442 y(2.2)94 b(T)-8
+b(esting)31 b(the)f(Library)i(.)46 b(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)
+h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h
+(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)131 b(6)136 2604
+y(2.3)94 b(Linking)29 b(Programs)h(with)f(FITSIO)40 b(.)46
+b(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g
+(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)131 b(7)136
+2766 y(2.4)94 b(Getting)31 b(Started)g(with)e(FITSIO)55
+b(.)46 b(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)
+f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)131
+b(8)136 2928 y(2.5)94 b(Example)30 b(Program)86 b(.)46
+b(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g
+(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)
+f(.)131 b(8)136 3090 y(2.6)94 b(Legal)31 b(Stu\013)92
+b(.)46 b(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)
+h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f
+(.)h(.)g(.)f(.)h(.)g(.)f(.)131 b(9)136 3252 y(2.7)94
+b(Ac)m(kno)m(wledgemen)m(ts)60 b(.)46 b(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f
+(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)
+h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85 b(10)0 3511
+y Fh(3)119 b(A)35 b(FITS)f(Primer)2917 b(13)0 3771 y(4)119
+b(Extended)35 b(File)f(Name)g(Syn)m(tax)2330 b(15)136
+3933 y Fi(4.1)94 b(Ov)m(erview)83 b(.)46 b(.)g(.)g(.)f(.)h(.)g(.)f(.)h
+(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)
+g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85
+b(15)136 4095 y(4.2)94 b(Filet)m(yp)s(e)60 b(.)45 b(.)h(.)g(.)g(.)f(.)h
+(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)
+g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g
+(.)f(.)85 b(18)345 4257 y(4.2.1)106 b(Notes)32 b(ab)s(out)e(HTTP)g(pro)
+m(xy)g(serv)m(ers)k(.)46 b(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h
+(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85
+b(18)345 4419 y(4.2.2)106 b(Notes)32 b(ab)s(out)e(the)h(ro)s(ot)f
+(\014let)m(yp)s(e)67 b(.)46 b(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g
+(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85
+b(18)345 4581 y(4.2.3)106 b(Notes)32 b(ab)s(out)e(the)h(shmem)e
+(\014let)m(yp)s(e:)69 b(.)46 b(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f
+(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85
+b(20)136 4742 y(4.3)94 b(Base)32 b(Filename)88 b(.)45
+b(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f
+(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)
+h(.)g(.)f(.)85 b(21)136 4904 y(4.4)94 b(Output)30 b(File)f(Name)i(when)
+f(Op)s(ening)e(an)i(Existing)f(File)79 b(.)45 b(.)h(.)g(.)g(.)f(.)h(.)g
+(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85 b(23)136
+5066 y(4.5)94 b(T)-8 b(emplate)31 b(File)f(Name)h(when)e(Creating)h(a)h
+(New)f(File)55 b(.)46 b(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g
+(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85 b(24)136 5228 y(4.6)94
+b(HDU)32 b(Lo)s(cation)e(Sp)s(eci\014cation)45 b(.)g(.)h(.)g(.)f(.)h(.)
+g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g
+(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85 b(24)136 5390 y(4.7)94
+b(Image)32 b(Section)38 b(.)46 b(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)
+g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g
+(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85 b(25)136
+5552 y(4.8)94 b(Column)29 b(and)h(Keyw)m(ord)g(Filtering)e(Sp)s
+(eci\014cation)89 b(.)45 b(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h
+(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85 b(26)136 5714
+y(4.9)94 b(Ro)m(w)31 b(Filtering)e(Sp)s(eci\014cation)80
+b(.)45 b(.)h(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)
+g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85
+b(28)1912 5942 y(iii)p eop
+%%Page: 4 4
+4 3 bop 0 299 a Fi(iv)3310 b Fg(CONTENTS)345 555 y Fi(4.9.1)106
+b(General)31 b(Syn)m(tax)44 b(.)i(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f
+(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)
+f(.)h(.)g(.)f(.)h(.)g(.)f(.)85 b(28)345 716 y(4.9.2)106
+b(Bit)31 b(Masks)43 b(.)j(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g
+(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)
+g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85 b(30)345 876 y(4.9.3)106
+b(V)-8 b(ector)32 b(Columns)91 b(.)46 b(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f
+(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)
+f(.)h(.)g(.)f(.)h(.)g(.)f(.)85 b(31)345 1037 y(4.9.4)106
+b(Go)s(o)s(d)30 b(Time)g(In)m(terv)-5 b(al)30 b(Filtering)59
+b(.)46 b(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)
+h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85 b(33)345 1197
+y(4.9.5)106 b(Spatial)29 b(Region)i(Filtering)56 b(.)46
+b(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g
+(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85 b(33)345
+1358 y(4.9.6)106 b(Example)30 b(Ro)m(w)h(Filters)f(.)45
+b(.)h(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f
+(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85
+b(36)136 1518 y(4.10)80 b(Binning)28 b(or)i(Histogramming)g(Sp)s
+(eci\014cation)f(.)46 b(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g
+(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85 b(37)0
+1771 y Fh(5)f(T)-9 b(emplate)34 b(Files)2985 b(41)136
+1931 y Fi(5.1)94 b(Detailed)31 b(T)-8 b(emplate)30 b(Line)g(F)-8
+b(ormat)48 b(.)e(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)
+g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85
+b(41)136 2092 y(5.2)94 b(Auto-indexing)29 b(of)i(Keyw)m(ords)73
+b(.)45 b(.)h(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)
+g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85
+b(42)136 2252 y(5.3)94 b(T)-8 b(emplate)31 b(P)m(arser)g(Directiv)m(es)
+85 b(.)45 b(.)h(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g
+(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85
+b(43)136 2412 y(5.4)94 b(F)-8 b(ormal)31 b(T)-8 b(emplate)31
+b(Syn)m(tax)j(.)46 b(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)
+h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h
+(.)g(.)f(.)85 b(43)136 2573 y(5.5)94 b(Errors)63 b(.)46
+b(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g
+(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)
+g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85 b(44)136 2733 y(5.6)94
+b(Examples)71 b(.)46 b(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g
+(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)
+f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85 b(44)0
+2986 y Fh(6)f(FITSIO)34 b(Con)m(v)m(en)m(tions)h(and)g(Guidelines)1993
+b(47)136 3146 y Fi(6.1)94 b(CFITSIO)29 b(Size)h(Limitations)39
+b(.)46 b(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)
+g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85
+b(47)136 3307 y(6.2)94 b(Multiple)29 b(Access)i(to)g(the)g(Same)f(FITS)
+g(File)f(.)45 b(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f
+(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85 b(48)136
+3467 y(6.3)94 b(Curren)m(t)30 b(Header)h(Data)h(Unit)d(\(CHDU\))87
+b(.)46 b(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)
+h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85 b(48)136 3628
+y(6.4)94 b(Subroutine)28 b(Names)79 b(.)46 b(.)f(.)h(.)g(.)g(.)f(.)h(.)
+g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g
+(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85 b(48)136
+3788 y(6.5)94 b(Subroutine)28 b(F)-8 b(amilies)30 b(and)f(Datat)m(yp)s
+(es)44 b(.)i(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)
+g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85 b(49)136
+3949 y(6.6)94 b(Implicit)28 b(Data)k(T)m(yp)s(e)e(Con)m(v)m(ersion)64
+b(.)46 b(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)
+h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85
+b(50)136 4109 y(6.7)94 b(Data)32 b(Scaling)87 b(.)46
+b(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g
+(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)
+f(.)h(.)g(.)f(.)85 b(50)136 4270 y(6.8)94 b(Error)30
+b(Status)g(V)-8 b(alues)31 b(and)e(the)i(Error)e(Message)j(Stac)m(k)44
+b(.)i(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h
+(.)g(.)f(.)85 b(51)136 4430 y(6.9)94 b(V)-8 b(ariable-Length)31
+b(Arra)m(y)f(F)-8 b(acilit)m(y)31 b(in)e(Binary)g(T)-8
+b(ables)25 b(.)46 b(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f
+(.)h(.)g(.)f(.)h(.)g(.)f(.)85 b(51)136 4591 y(6.10)49
+b(Supp)s(ort)29 b(for)h(IEEE)g(Sp)s(ecial)e(V)-8 b(alues)67
+b(.)45 b(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)
+g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85 b(52)136
+4751 y(6.11)49 b(When)31 b(the)f(Final)f(Size)h(of)h(the)f(FITS)g(HDU)h
+(is)e(Unkno)m(wn)34 b(.)45 b(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)
+f(.)h(.)g(.)f(.)h(.)g(.)f(.)85 b(53)136 4912 y(6.12)49
+b(Lo)s(cal)31 b(FITS)e(Con)m(v)m(en)m(tions)i(supp)s(orted)d(b)m(y)j
+(FITSIO)72 b(.)46 b(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f
+(.)h(.)g(.)f(.)h(.)g(.)f(.)85 b(53)345 5072 y(6.12.1)61
+b(Supp)s(ort)29 b(for)h(Long)g(String)f(Keyw)m(ord)h(V)-8
+b(alues.)61 b(.)46 b(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)
+h(.)g(.)f(.)h(.)g(.)f(.)85 b(54)345 5232 y(6.12.2)61
+b(Arra)m(ys)31 b(of)f(Fixed-Length)g(Strings)f(in)g(Binary)h(T)-8
+b(ables)69 b(.)46 b(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g
+(.)f(.)85 b(54)345 5393 y(6.12.3)61 b(Keyw)m(ord)30 b(Units)g(Strings)i
+(.)46 b(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f
+(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85
+b(55)345 5553 y(6.12.4)61 b(HIERAR)m(CH)31 b(Con)m(v)m(en)m(tion)g(for)
+f(Extended)g(Keyw)m(ord)g(Names)83 b(.)45 b(.)h(.)g(.)g(.)f(.)h(.)g(.)f
+(.)h(.)g(.)f(.)85 b(55)136 5714 y(6.13)49 b(Optimizing)28
+b(Co)s(de)i(for)g(Maxim)m(um)g(Pro)s(cessing)g(Sp)s(eed)44
+b(.)i(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h
+(.)g(.)f(.)85 b(56)p eop
+%%Page: 5 5
+5 4 bop 0 299 a Fg(CONTENTS)3334 b Fi(v)345 555 y(6.13.1)61
+b(Bac)m(kground)31 b(Information:)40 b(Ho)m(w)31 b(CFITSIO)e(Manages)j
+(Data)g(I/O)91 b(.)46 b(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85
+b(57)0 816 y Fh(7)119 b(The)35 b(CFITSIO)e(Iterator)g(F)-9
+b(unction)2154 b(61)0 1077 y(8)119 b(Basic)36 b(In)m(terface)e
+(Routines)2504 b(63)136 1239 y Fi(8.1)94 b(FITSIO)30
+b(Error)f(Status)h(Routines)83 b(.)46 b(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f
+(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)
+h(.)g(.)f(.)85 b(63)136 1401 y(8.2)94 b(File)30 b(I/O)g(Routines)d(.)46
+b(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h
+(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)
+g(.)f(.)85 b(64)136 1563 y(8.3)94 b(Keyw)m(ord)31 b(I/O)f(Routines)35
+b(.)46 b(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)
+f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f
+(.)85 b(66)136 1725 y(8.4)94 b(Data)32 b(I/O)f(Routines)52
+b(.)46 b(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)
+h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h
+(.)g(.)f(.)85 b(66)0 1986 y Fh(9)119 b(Adv)-6 b(anced)36
+b(In)m(terface)e(Subroutines)2159 b(69)136 2148 y Fi(9.1)94
+b(FITS)30 b(File)g(Op)s(en)f(and)g(Close)h(Subroutines:)75
+b(.)46 b(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)
+g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85 b(69)136 2310 y(9.2)94
+b(HDU-Lev)m(el)32 b(Op)s(erations)107 b(.)46 b(.)g(.)f(.)h(.)g(.)f(.)h
+(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)
+g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85 b(72)136 2472
+y(9.3)94 b(De\014ne)31 b(or)f(Rede\014ne)g(the)h(structure)f(of)g(the)h
+(CHDU)99 b(.)46 b(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f
+(.)h(.)g(.)f(.)h(.)g(.)f(.)85 b(75)136 2634 y(9.4)94
+b(FITS)30 b(Header)h(I/O)f(Subroutines)h(.)46 b(.)g(.)f(.)h(.)g(.)f(.)h
+(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)
+h(.)g(.)f(.)h(.)g(.)f(.)85 b(76)345 2796 y(9.4.1)106
+b(Header)31 b(Space)g(and)f(P)m(osition)f(Routines)59
+b(.)46 b(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)
+h(.)g(.)f(.)h(.)g(.)f(.)85 b(76)345 2958 y(9.4.2)106
+b(Read)31 b(or)f(W)-8 b(rite)31 b(Standard)e(Header)i(Routines)66
+b(.)46 b(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)
+h(.)g(.)f(.)85 b(77)345 3120 y(9.4.3)106 b(W)-8 b(rite)31
+b(Keyw)m(ord)f(Subroutines)115 b(.)46 b(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f
+(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)
+85 b(78)345 3283 y(9.4.4)106 b(Insert)30 b(Keyw)m(ord)g(Subroutines)107
+b(.)46 b(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)
+h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85 b(80)345 3445
+y(9.4.5)106 b(Read)31 b(Keyw)m(ord)f(Subroutines)63 b(.)46
+b(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h
+(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85 b(81)345 3607
+y(9.4.6)106 b(Mo)s(dify)29 b(Keyw)m(ord)i(Subroutines)54
+b(.)46 b(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)
+h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85 b(82)345 3769
+y(9.4.7)106 b(Up)s(date)31 b(Keyw)m(ord)f(Subroutines)115
+b(.)45 b(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)
+g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85 b(83)345 3931
+y(9.4.8)106 b(Delete)32 b(Keyw)m(ord)e(Subroutines)86
+b(.)46 b(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)
+h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85 b(84)136 4093
+y(9.5)94 b(Data)32 b(Scaling)e(and)f(Unde\014ned)g(Pixel)g(P)m
+(arameters)113 b(.)46 b(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g
+(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85 b(84)136 4255 y(9.6)94
+b(FITS)30 b(Primary)f(Arra)m(y)i(or)f(IMA)m(GE)h(Extension)f(I/O)g
+(Subroutines)116 b(.)46 b(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f
+(.)85 b(85)136 4417 y(9.7)94 b(FITS)30 b(ASCI)s(I)f(and)h(Binary)f(T)-8
+b(able)30 b(Data)i(I/O)e(Subroutines)c(.)46 b(.)g(.)g(.)f(.)h(.)g(.)f
+(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85 b(88)345
+4579 y(9.7.1)106 b(Column)29 b(Information)g(Subroutines)120
+b(.)46 b(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)
+f(.)h(.)g(.)f(.)h(.)g(.)f(.)85 b(88)345 4741 y(9.7.2)106
+b(Lo)m(w-Lev)m(el)32 b(T)-8 b(able)30 b(Access)h(Subroutines)59
+b(.)46 b(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)
+h(.)g(.)f(.)h(.)g(.)f(.)85 b(91)345 4903 y(9.7.3)106
+b(Edit)30 b(Ro)m(ws)g(or)h(Columns)105 b(.)46 b(.)f(.)h(.)g(.)f(.)h(.)g
+(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)
+g(.)f(.)h(.)g(.)f(.)85 b(92)345 5066 y(9.7.4)106 b(Read)31
+b(and)f(W)-8 b(rite)30 b(Column)f(Data)j(Routines)65
+b(.)46 b(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)
+f(.)h(.)g(.)f(.)85 b(93)136 5228 y(9.8)94 b(Ro)m(w)31
+b(Selection)f(and)g(Calculator)g(Routines)94 b(.)46 b(.)g(.)g(.)f(.)h
+(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)
+g(.)f(.)85 b(96)136 5390 y(9.9)94 b(Celestial)30 b(Co)s(ordinate)f
+(System)h(Subroutines)97 b(.)46 b(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f
+(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85
+b(98)136 5552 y(9.10)49 b(File)30 b(Chec)m(ksum)g(Subroutines)74
+b(.)45 b(.)h(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)
+g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85
+b(99)136 5714 y(9.11)80 b(Date)32 b(and)d(Time)h(Utilit)m(y)f(Routines)
+68 b(.)45 b(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h
+(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)40
+b(101)p eop
+%%Page: 6 6
+6 5 bop 0 299 a Fi(vi)3310 b Fg(CONTENTS)136 555 y Fi(9.12)49
+b(General)31 b(Utilit)m(y)e(Subroutines)60 b(.)45 b(.)h(.)g(.)f(.)h(.)g
+(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)
+g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)40 b(102)0 806 y Fh(10)67
+b(Summary)34 b(of)h(all)f(FITSIO)g(User-In)m(terface)h(Subroutines)1215
+b(109)0 1057 y(11)67 b(P)m(arameter)34 b(De\014nitions)2563
+b(117)0 1308 y(12)67 b(FITSIO)33 b(Error)i(Status)g(Co)s(des)2295
+b(123)p eop
+%%Page: 1 7
+1 6 bop 0 1225 a Ff(Chapter)65 b(1)0 1687 y Fl(In)-6
+b(tro)6 b(duction)0 2180 y Fi(This)32 b(do)s(cumen)m(t)j(describ)s(es)d
+(the)i(F)-8 b(ortran-callable)35 b(subroutine)d(in)m(terface)j(that)g
+(is)e(pro)m(vided)g(as)h(part)g(of)h(the)0 2293 y(CFITSIO)f(library)f
+(\(whic)m(h)i(is)g(written)g(in)f(ANSI)h(C\).)h(This)e(is)h(a)h
+(companion)f(do)s(cumen)m(t)g(to)i(the)e(CFITSIO)0 2406
+y(User's)k(Guide)e(whic)m(h)h(should)e(b)s(e)i(consulted)g(for)g
+(further)g(information)f(ab)s(out)h(the)h(underlying)c(CFITSIO)0
+2518 y(library)-8 b(.)48 b(In)32 b(the)i(remainder)e(of)h(this)g(do)s
+(cumen)m(t,)h(the)g(terms)f(FITSIO)f(and)h(CFITSIO)f(are)i(in)m(terc)m
+(hangeable)0 2631 y(and)c(refer)g(to)h(the)g(same)f(library)-8
+b(.)0 2791 y(FITSIO/CFITSIO)31 b(is)i(a)g(mac)m(hine-indep)s(enden)m(t)
+e(library)g(of)j(routines)e(for)h(reading)g(and)g(writing)e(data)j
+(\014les)0 2904 y(in)29 b(the)h(FITS)g(\(Flexible)f(Image)i(T)-8
+b(ransp)s(ort)29 b(System\))h(data)h(format.)41 b(It)31
+b(can)f(also)g(read)h(IRAF)f(format)h(image)0 3017 y(\014les)39
+b(and)f(ra)m(w)i(binary)e(data)i(arra)m(ys)g(b)m(y)g(con)m(v)m(erting)g
+(them)f(on)h(the)g(\015y)f(in)m(to)g(a)h(virtual)e(FITS)h(format)h
+(\014le.)0 3130 y(This)31 b(library)g(w)m(as)i(written)f(to)i(pro)m
+(vide)e(a)i(p)s(o)m(w)m(erful)e(y)m(et)i(simple)d(in)m(terface)i(for)g
+(accessing)h(FITS)e(\014les)g(whic)m(h)0 3243 y(will)h(run)h(on)h(most)
+h(commonly)f(used)f(computers)h(and)g(w)m(orkstations.)56
+b(FITSIO)34 b(supp)s(orts)g(all)g(the)i(features)0 3356
+y(describ)s(ed)20 b(in)i(the)g(o\016cial)g(NOST)g(de\014nition)e(of)j
+(the)f(FITS)g(format)h(and)f(can)h(read)f(and)g(write)g(all)f(the)i
+(curren)m(tly)0 3469 y(de\014ned)40 b(t)m(yp)s(es)h(of)g(extensions,)i
+(including)38 b(ASCI)s(I)h(tables)i(\(T)-8 b(ABLE\),)42
+b(Binary)e(tables)h(\(BINT)-8 b(ABLE\))43 b(and)0 3582
+y(IMA)m(GE)36 b(extensions.)55 b(The)34 b(FITSIO)g(subroutines)f
+(insulate)h(the)h(programmer)g(from)g(ha)m(ving)g(to)h(deal)e(with)0
+3695 y(the)25 b(complicated)f(formatting)h(details)e(in)g(the)i(FITS)f
+(\014le,)h(ho)m(w)m(ev)m(er,)j(it)c(is)f(assumed)h(that)h(users)f(ha)m
+(v)m(e)i(a)f(general)0 3808 y(kno)m(wledge)30 b(ab)s(out)g(the)h
+(structure)f(and)g(usage)h(of)f(FITS)g(\014les.)0 3968
+y(The)20 b(CFITSIO)f(pac)m(k)-5 b(age)23 b(w)m(as)e(initially)d(dev)m
+(elop)s(ed)i(b)m(y)g(the)h(HEASAR)m(C)g(\(High)g(Energy)f(Astroph)m
+(ysics)g(Science)0 4081 y(Arc)m(hiv)m(e)34 b(Researc)m(h)h(Cen)m(ter\))
+f(at)h(the)f(NASA)g(Go)s(ddard)e(Space)j(Fligh)m(t)e(Cen)m(ter)h(to)h
+(con)m(v)m(ert)g(v)-5 b(arious)33 b(existing)0 4194 y(and)25
+b(newly)g(acquired)g(astronomical)h(data)g(sets)h(in)m(to)f(FITS)f
+(format)h(and)f(to)i(further)e(analyze)h(data)h(already)e(in)0
+4307 y(FITS)i(format.)41 b(New)28 b(features)g(con)m(tin)m(ue)g(to)h(b)
+s(e)e(added)h(to)g(CFITSIO)f(in)f(large)i(part)g(due)g(to)g(con)m
+(tributions)f(of)0 4419 y(ideas)32 b(or)h(actual)g(co)s(de)g(from)f
+(users)g(of)h(the)g(pac)m(k)-5 b(age.)49 b(The)33 b(In)m(tegral)g
+(Science)f(Data)i(Cen)m(ter)f(in)f(Switzerland,)0 4532
+y(and)h(the)g(XMM/ESTEC)h(pro)5 b(ject)34 b(in)e(The)h(Netherlands)f
+(made)h(esp)s(ecially)f(signi\014can)m(t)g(con)m(tributions)g(that)0
+4645 y(resulted)d(in)g(man)m(y)i(of)f(the)h(new)f(features)g(that)h
+(app)s(eared)f(in)f(v2.0)j(of)e(CFITSIO.)0 4805 y(The)22
+b(latest)h(v)m(ersion)f(of)h(the)f(CFITSIO)f(source)i(co)s(de,)h(do)s
+(cumen)m(tation,)h(and)c(example)i(programs)f(are)h(a)m(v)-5
+b(ailable)0 4918 y(on)30 b(the)h(W)-8 b(orld-Wide)30
+b(W)-8 b(eb)31 b(or)f(via)g(anon)m(ymous)g(ftp)g(from:)382
+5178 y Fe(http://heasarc.gsfc.nasa)o(.go)o(v/fi)o(tsio)382
+5291 y(ftp://legacy.gsfc.nasa.g)o(ov/)o(soft)o(ware)o(/fi)o(tsio)o(/c)
+1927 5942 y Fi(1)p eop
+%%Page: 2 8
+2 7 bop 0 299 a Fi(2)2452 b Fg(CHAPTER)30 b(1.)71 b(INTR)m(ODUCTION)0
+555 y Fi(An)m(y)28 b(questions,)f(bug)g(rep)s(orts,)h(or)f(suggested)i
+(enhancemen)m(ts)f(related)f(to)i(the)e(CFITSIO)f(pac)m(k)-5
+b(age)30 b(should)c(b)s(e)0 668 y(sen)m(t)31 b(to)g(the)g(primary)d
+(author:)382 928 y Fe(Dr.)47 b(William)f(Pence)810 b(Telephone:)92
+b(\(301\))47 b(286-4599)382 1041 y(HEASARC,)e(Code)i(662)811
+b(E-mail:)45 b(pence@tetra.gsfc.nasa.gov)382 1154 y(NASA/Goddard)f
+(Space)j(Flight)f(Center)382 1267 y(Greenbelt,)f(MD)i(20771,)f(USA)0
+1526 y Fi(This)39 b(User's)j(Guide)e(assumes)h(that)h(readers)f
+(already)f(ha)m(v)m(e)j(a)f(general)f(understanding)d(of)k(the)f
+(de\014nition)0 1639 y(and)31 b(structure)g(of)h(FITS)e(format)i
+(\014les.)43 b(F)-8 b(urther)32 b(information)d(ab)s(out)j(FITS)f
+(formats)g(is)g(a)m(v)-5 b(ailable)31 b(from)g(the)0
+1752 y(FITS)h(Supp)s(ort)f(O\016ce)i(at)g Fe(http://fits.gsfc.nasa.gov)
+o Fi(.)42 b(In)32 b(particular,)g(the)h('NOST)f(FITS)g(Standard')0
+1865 y(giv)m(es)i(the)h(authoritativ)m(e)f(de\014nition)e(of)i(the)g
+(FITS)g(data)h(format,)g(and)f(the)g(`FITS)g(User's)g(Guide')f(pro)m
+(vides)0 1978 y(additional)28 b(historical)h(bac)m(kground)h(and)g
+(practical)g(advice)g(on)g(using)f(FITS)h(\014les.)0
+2138 y(CFITSIO)j(users)g(ma)m(y)h(also)g(b)s(e)g(in)m(terested)g(in)f
+(the)h(FTOOLS)f(pac)m(k)-5 b(age)36 b(of)e(programs)g(that)g(can)h(b)s
+(e)e(used)g(to)0 2251 y(manipulate)i(and)g(analyze)i(FITS)f(format)g
+(\014les.)58 b(Information)35 b(ab)s(out)h(FTOOLS)f(can)i(b)s(e)f
+(obtained)f(on)i(the)0 2364 y(W)-8 b(eb)31 b(or)f(via)g(anon)m(ymous)h
+(ftp)f(at:)382 2624 y Fe(http://heasarc.gsfc.nasa)o(.go)o(v/ft)o(ools)
+382 2737 y(ftp://legacy.gsfc.nasa.g)o(ov/)o(soft)o(ware)o(/ft)o(ools)o
+(/rel)o(eas)o(e)p eop
+%%Page: 3 9
+3 8 bop 0 1225 a Ff(Chapter)65 b(2)0 1687 y Fl(Creating)77
+b(FITSIO/CFITSIO)0 2216 y Fd(2.1)135 b(Building)45 b(the)h(Library)0
+2467 y Fi(T)-8 b(o)43 b(use)g(the)g(FITSIO)f(subroutines)e(one)k(m)m
+(ust)e(\014rst)g(build)e(the)j(CFITSIO)f(library)-8 b(,)44
+b(whic)m(h)e(requires)f(a)i(C)0 2580 y(compiler.)71 b(gcc)43
+b(is)d(ideal,)i(or)f(most)h(other)f(ANSI-C)g(compilers)e(will)g(also)i
+(w)m(ork.)73 b(The)40 b(CFITSIO)g(co)s(de)h(is)0 2692
+y(con)m(tained)24 b(in)f(ab)s(out)g(40)i(C)f(source)g(\014les)e
+(\(*.c\))k(and)d(header)h(\014les)f(\(*.h\).)39 b(On)23
+b(V)-10 b(AX/VMS)25 b(systems)f(2)g(assem)m(bly-)0 2805
+y(co)s(de)31 b(\014les)e(\(vmsieeed.mar)h(and)g(vmsieeer.mar\))g(are)h
+(also)f(needed.)0 2965 y(The)45 b(F)-8 b(ortran)46 b(in)m(terface)f
+(subroutines)e(to)j(the)f(C)g(CFITSIO)f(routines)g(are)h(lo)s(cated)h
+(in)e(the)h(f77)p 3538 2965 28 4 v 33 w(wrap1.c,)0 3078
+y(through)22 b(f77)p 459 3078 V 33 w(wrap4.c)h(\014les.)37
+b(These)22 b(are)h(relativ)m(ely)f(simple)e('wrapp)s(ers')h(that)i
+(translate)g(the)g(argumen)m(ts)g(in)e(the)0 3191 y(F)-8
+b(ortran)26 b(subroutine)d(in)m(to)j(the)f(appropriate)g(format)h(for)f
+(the)g(corresp)s(onding)f(C)h(routine.)38 b(This)23 b(translation)i(is)
+0 3304 y(p)s(erformed)19 b(transparen)m(tly)h(to)h(the)g(user)f(b)m(y)g
+(a)h(set)h(of)e(C)h(macros)g(lo)s(cated)g(in)e(the)i(cfortran.h)f
+(\014le.)37 b(Unfortunately)0 3417 y(cfortran.h)28 b(do)s(es)g(not)g
+(supp)s(ort)f(ev)m(ery)h(com)m(bination)g(of)g(C)g(and)f(F)-8
+b(ortran)29 b(compilers)e(so)h(the)h(F)-8 b(ortran)28
+b(in)m(terface)0 3530 y(is)h(not)i(supp)s(orted)e(on)h(all)f
+(platforms.)40 b(\(see)31 b(further)e(notes)i(b)s(elo)m(w\).)0
+3690 y(A)f(standard)f(com)m(bination)h(of)g(C)f(and)h(F)-8
+b(ortran)30 b(compilers)f(will)e(b)s(e)i(assumed)h(b)m(y)f(default,)h
+(but)f(one)h(ma)m(y)h(also)0 3803 y(sp)s(ecify)e(a)i(particular)d(F)-8
+b(ortran)32 b(compiler)c(b)m(y)j(doing:)48 4064 y Fe(>)95
+b(setenv)46 b(CFLAGS)g(-DcompilerName=1)0 4324 y Fi(\(where)33
+b('compilerName')f(is)g(the)h(name)f(of)h(the)g(compiler\))f(b)s(efore)
+g(running)e(the)j(con\014gure)f(command.)47 b(The)0 4437
+y(curren)m(tly)29 b(recognized)i(compiler)e(names)h(are:)48
+4698 y Fe(g77Fortran)48 4811 y(IBMR2Fortran)48 4924 y(CLIPPERFortran)48
+5036 y(pgiFortran)48 5149 y(NAGf90Fortran)48 5262 y(f2cFortran)48
+5375 y(hpuxFortran)48 5488 y(apolloFortran)48 5601 y(sunFortran)48
+5714 y(CRAYFortran)1927 5942 y Fi(3)p eop
+%%Page: 4 10
+4 9 bop 0 299 a Fi(4)1896 b Fg(CHAPTER)30 b(2.)111 b(CREA)-8
+b(TING)31 b(FITSIO/CFITSIO)48 555 y Fe(mipsFortran)48
+668 y(DECFortran)48 781 y(vmsFortran)48 894 y(CONVEXFortran)48
+1007 y(PowerStationFortran)48 1120 y(AbsoftUNIXFortran)48
+1233 y(AbsoftProFortran)48 1346 y(SXFortran)0 1580 y
+Fi(Alternativ)m(ely)-8 b(,)39 b(one)f(ma)m(y)g(edit)f(the)g(CFLA)m(GS)h
+(line)d(in)i(the)g(Mak)m(e\014le)h(to)g(add)f(the)h('-DcompilerName')g
+(\015ag)0 1692 y(after)31 b(running)d(the)i('./con\014gure')h(command.)
+0 1853 y(The)f(CFITSIO)f(library)f(is)h(built)f(on)j(Unix)e(systems)h
+(b)m(y)g(t)m(yping:)48 2087 y Fe(>)95 b(./configure)45
+b([--prefix=/target/insta)o(llat)o(ion)o(/pat)o(h])48
+2199 y(>)95 b(make)476 b(\(or)95 b('make)46 b(shared'\))48
+2312 y(>)95 b(make)47 b(install)93 b(\(this)46 b(step)h(is)g
+(optional\))0 2546 y Fi(at)24 b(the)g(op)s(erating)f(system)h(prompt.)
+38 b(The)23 b(con\014gure)g(command)g(customizes)h(the)g(Mak)m(e\014le)
+g(for)g(the)g(particular)0 2659 y(system,)g(then)d(the)g(`mak)m(e')i
+(command)e(compiles)f(the)h(source)h(\014les)e(and)h(builds)d(the)j
+(library)-8 b(.)36 b(T)m(yp)s(e)21 b(`./con\014gure')0
+2772 y(and)34 b(not)h(simply)d(`con\014gure')j(to)h(ensure)e(that)h
+(the)g(con\014gure)g(script)e(in)h(the)h(curren)m(t)f(directory)g(is)g
+(run)g(and)0 2885 y(not)29 b(some)g(other)g(system-wide)f(con\014gure)g
+(script.)39 b(The)29 b(optional)f('pre\014x')g(argumen)m(t)h(to)g
+(con\014gure)g(giv)m(es)g(the)0 2998 y(path)f(to)i(the)f(directory)f
+(where)g(the)h(CFITSIO)f(library)e(and)i(include)f(\014les)g(should)g
+(b)s(e)h(installed)f(via)h(the)h(later)0 3111 y('mak)m(e)j(install')c
+(command.)41 b(F)-8 b(or)31 b(example,)143 3345 y Fe(>)48
+b(./configure)c(--prefix=/usr1/local)0 3579 y Fi(will)22
+b(cause)k(the)f('mak)m(e)h(install')d(command)i(to)h(cop)m(y)g(the)f
+(CFITSIO)e(lib)s(c\014tsio)f(\014le)j(to)g(/usr1/lo)s(cal/lib)e(and)i
+(the)0 3692 y(necessary)36 b(include)c(\014le)j(to)h(/usr1/lo)s
+(cal/include)d(\(assuming)h(of)h(course)g(that)h(the)f(pro)s(cess)g
+(has)g(p)s(ermission)0 3805 y(to)c(write)f(to)h(these)g(directories\).)
+0 3965 y(By)d(default)g(this)f(also)h(builds)c(the)29
+b(set)f(of)h(F)-8 b(ortran-callable)28 b(wrapp)s(er)e(routines)h(whose)
+h(calling)e(sequences)j(are)0 4078 y(describ)s(ed)f(later)j(in)e(this)g
+(do)s(cumen)m(t.)0 4238 y(The)f('mak)m(e)h(shared')f(option)g(builds)d
+(a)k(shared)e(or)i(dynamic)e(v)m(ersion)h(of)g(the)h(CFITSIO)d(library)
+-8 b(.)38 b(When)28 b(using)0 4351 y(the)f(shared)f(library)f(the)i
+(executable)g(co)s(de)g(is)f(not)h(copied)f(in)m(to)h(y)m(our)g
+(program)g(at)g(link)e(time)h(and)h(instead)f(the)0 4464
+y(program)h(lo)s(cates)h(the)g(necessary)g(library)d(co)s(de)j(at)g
+(run)e(time,)i(normally)e(through)g(LD)p 3065 4464 28
+4 v 33 w(LIBRAR)-8 b(Y)p 3514 4464 V 34 w(P)g(A)g(TH)28
+b(or)0 4577 y(some)j(other)f(metho)s(d.)41 b(The)29 b(adv)-5
+b(an)m(tages)33 b(of)d(using)f(a)i(shared)e(library)f(are:)143
+4811 y Fe(1.)95 b(Less)47 b(disk)f(space)h(if)g(you)g(build)f(more)h
+(than)f(1)i(program)143 4924 y(2.)95 b(Less)47 b(memory)f(if)h(more)g
+(than)f(one)h(copy)g(of)g(a)g(program)f(using)h(the)g(shared)334
+5036 y(library)f(is)h(running)f(at)h(the)g(same)g(time)f(since)h(the)g
+(system)f(is)h(smart)334 5149 y(enough)f(to)h(share)g(copies)f(of)h
+(the)g(shared)f(library)g(at)h(run)g(time.)143 5262 y(3.)95
+b(Possibly)46 b(easier)g(maintenance)e(since)j(a)g(new)g(version)f(of)h
+(the)g(shared)334 5375 y(library)f(can)h(be)g(installed)e(without)h
+(relinking)f(all)i(the)g(software)334 5488 y(that)g(uses)f(it)i(\(as)e
+(long)h(as)g(the)g(subroutine)e(names)i(and)f(calling)334
+5601 y(sequences)f(remain)h(unchanged\).)143 5714 y(4.)95
+b(No)47 b(run-time)f(penalty.)p eop
+%%Page: 5 11
+5 10 bop 0 299 a Fg(2.1.)72 b(BUILDING)31 b(THE)f(LIBRAR)-8
+b(Y)2507 b Fi(5)0 555 y(The)30 b(disadv)-5 b(an)m(tages)31
+b(are:)143 819 y Fe(1.)47 b(More)g(hassle)f(at)h(runtime.)94
+b(You)46 b(have)h(to)g(either)f(build)h(the)g(programs)286
+932 y(specially)f(or)h(have)f(LD_LIBRARY_PATH)e(set)j(right.)143
+1045 y(2.)g(There)g(may)g(be)g(a)g(slight)f(start)h(up)g(penalty,)e
+(depending)h(on)h(where)f(you)h(are)286 1158 y(reading)f(the)h(shared)f
+(library)g(and)h(the)g(program)f(from)g(and)h(if)g(your)g(CPU)g(is)286
+1271 y(either)f(really)h(slow)f(or)h(really)f(heavily)g(loaded.)0
+1535 y Fi(On)30 b(HP/UX)i(systems,)g(the)f(en)m(vironmen)m(t)g(v)-5
+b(ariable)30 b(CFLA)m(GS)h(should)e(b)s(e)i(set)g(to)h(-Ae)g(b)s(efore)
+f(running)d(con-)0 1648 y(\014gure)i(to)h(enable)f("extended)h(ANSI")f
+(features.)0 1808 y(It)f(ma)m(y)h(not)f(b)s(e)f(p)s(ossible)f(to)i
+(staticly)g(link)e(programs)i(that)g(use)g(CFITSIO)e(on)i(some)h
+(platforms)d(\(namely)-8 b(,)30 b(on)0 1921 y(Solaris)k(2.6\))j(due)e
+(to)i(the)e(net)m(w)m(ork)i(driv)m(ers)d(\(whic)m(h)h(pro)m(vide)g(FTP)
+g(and)g(HTTP)g(access)i(to)g(FITS)e(\014les\).)56 b(It)0
+2034 y(is)32 b(p)s(ossible)e(to)k(mak)m(e)f(b)s(oth)g(a)g(dynamic)e
+(and)h(a)i(static)f(v)m(ersion)f(of)h(the)g(CFITSIO)e(library)-8
+b(,)32 b(but)g(net)m(w)m(ork)i(\014le)0 2147 y(access)e(will)27
+b(not)k(b)s(e)f(p)s(ossible)e(using)h(the)h(static)h(v)m(ersion.)0
+2307 y(On)d(V)-10 b(AX/VMS)31 b(and)d(ALPHA/VMS)i(systems)f(the)h(mak)m
+(e)p 2100 2307 28 4 v 34 w(g\015oat.com)h(command)e(\014le)f(ma)m(y)i
+(b)s(e)f(executed)h(to)0 2420 y(build)j(the)k(c\014tsio.olb)e(ob)5
+b(ject)37 b(library)d(using)h(the)h(default)g(G-\015oating)g(p)s(oin)m
+(t)g(option)f(for)h(double)f(v)-5 b(ariables.)0 2533
+y(The)37 b(mak)m(e)p 405 2533 V 33 w(d\015oat.com)i(and)d(mak)m(e)p
+1279 2533 V 34 w(ieee.com)i(\014les)f(ma)m(y)g(b)s(e)g(used)f(instead)h
+(to)h(build)c(the)j(library)e(with)h(the)0 2646 y(other)26
+b(\015oating)h(p)s(oin)m(t)e(options.)38 b(Note)28 b(that)f(the)f
+(getcwd)h(function)e(that)i(is)e(used)g(in)g(the)i(group.c)f(mo)s(dule)
+e(ma)m(y)0 2758 y(require)43 b(that)j(programs)e(using)f(CFITSIO)g(b)s
+(e)h(link)m(ed)g(with)f(the)i(ALPHA$LIBRAR)-8 b(Y:V)e(AX)m(CR)i(TL.OLB)
+0 2871 y(library)g(.)39 b(See)30 b(the)h(example)f(link)e(line)h(in)g
+(the)i(next)f(section)h(of)f(this)g(do)s(cumen)m(t.)0
+3032 y(On)25 b(Windo)m(ws)g(IBM-PC)h(t)m(yp)s(e)g(platforms)e(the)i
+(situation)f(is)f(more)i(complicated)g(b)s(ecause)f(of)h(the)g(wide)f
+(v)-5 b(ariet)m(y)0 3144 y(of)43 b(F)-8 b(ortran)43 b(compilers)f(that)
+h(are)g(a)m(v)-5 b(ailable)42 b(and)g(b)s(ecause)h(of)g(the)g(inheren)m
+(t)f(complexities)g(of)g(calling)g(the)0 3257 y(CFITSIO)25
+b(C)g(routines)g(from)h(F)-8 b(ortran.)40 b(Tw)m(o)26
+b(di\013eren)m(t)g(v)m(ersions)f(of)h(the)h(CFITSIO)d(dll)g(library)g
+(are)i(a)m(v)-5 b(ailable,)0 3370 y(compiled)26 b(with)f(the)j(Borland)
+e(C++)g(compiler)g(and)g(the)i(Microsoft)f(Visual)f(C++)g(compiler,)g
+(resp)s(ectiv)m(ely)-8 b(,)28 b(in)0 3483 y(the)i(\014les)f(c\014tsio)s
+(dll)p 682 3483 V 30 w(2xxx)p 901 3483 V 34 w(b)s(orland.zip)e(and)i
+(c\014tsio)s(dll)p 1927 3483 V 30 w(2xxx)p 2146 3483
+V 33 w(v)m(cc.zip,)i(where)f('2xxx')h(represen)m(ts)f(the)g(curren)m(t)
+0 3596 y(release)43 b(n)m(um)m(b)s(er.)76 b(Both)43 b(these)g(dll)e
+(libraries)f(con)m(tain)j(a)g(set)g(of)f(F)-8 b(ortran)44
+b(wrapp)s(er)d(routines)g(whic)m(h)g(ma)m(y)0 3709 y(b)s(e)c
+(compatible)g(with)f(some,)k(but)d(probably)f(not)h(all,)i(a)m(v)-5
+b(ailable)37 b(F)-8 b(ortran)38 b(compilers.)61 b(T)-8
+b(o)38 b(test)g(if)f(they)h(are)0 3822 y(compatible,)27
+b(compile)f(the)h(program)g(testf77.f)h(and)f(try)f(linking)f(to)i
+(these)h(dll)c(libraries.)37 b(If)27 b(these)g(libraries)d(do)0
+3935 y(not)29 b(w)m(ork)g(with)e(a)i(particular)e(F)-8
+b(ortran)30 b(compiler,)e(then)g(there)h(are)g(2)g(p)s(ossible)e
+(solutions.)38 b(The)28 b(\014rst)g(solution)0 4048 y(w)m(ould)g(b)s(e)
+i(to)g(mo)s(dify)e(the)i(\014le)e(cfortran.h)i(for)f(that)i(particular)
+d(com)m(bination)h(of)h(C)f(and)g(F)-8 b(ortran)30 b(compilers,)0
+4161 y(and)k(then)g(rebuild)d(the)k(CFITSIO)d(dll)h(library)-8
+b(.)50 b(This)33 b(will)f(require,)i(ho)m(w)m(ev)m(er,)j(a)e(some)f
+(exp)s(ertise)g(in)f(mixed)0 4274 y(language)e(programming.)39
+b(The)30 b(other)h(solution)d(is)i(to)h(use)f(the)g(older)g(v5.03)i(F)
+-8 b(ortran-77)32 b(implemen)m(tation)d(of)0 4386 y(FITSIO)c(that)h(is)
+f(still)f(a)m(v)-5 b(ailable)25 b(from)g(the)h(FITSIO)f(w)m(eb-site.)39
+b(This)24 b(v)m(ersion)h(is)g(no)h(longer)f(supp)s(orted,)g(but)g(it)0
+4499 y(do)s(es)k(pro)m(vide)g(the)h(basic)g(functions)e(for)h(reading)g
+(and)g(writing)f(FITS)h(\014les)g(and)g(should)f(b)s(e)h(compatible)g
+(with)0 4612 y(most)i(F)-8 b(ortran)31 b(compilers.)0
+4772 y(CFITSIO)e(has)h(curren)m(tly)f(b)s(een)h(tested)h(on)f(the)h
+(follo)m(wing)e(platforms:)95 5036 y Fe(OPERATING)46
+b(SYSTEM)523 b(COMPILER)143 5149 y(Sun)47 b(OS)1002 b(gcc)47
+b(and)g(cc)g(\(3.0.1\))143 5262 y(Sun)g(Solaris)762 b(gcc)47
+b(and)g(cc)143 5375 y(Silicon)f(Graphics)g(IRIX)285 b(gcc)47
+b(and)g(cc)143 5488 y(Silicon)f(Graphics)g(IRIX64)189
+b(MIPS)143 5601 y(Dec)47 b(Alpha)f(OSF/1)572 b(gcc)47
+b(and)g(cc)143 5714 y(DECstation)93 b(Ultrix)428 b(gcc)p
+eop
+%%Page: 6 12
+6 11 bop 0 299 a Fi(6)1896 b Fg(CHAPTER)30 b(2.)111 b(CREA)-8
+b(TING)31 b(FITSIO/CFITSIO)143 555 y Fe(Dec)47 b(Alpha)f(OpenVMS)476
+b(cc)143 668 y(DEC)47 b(VAX/VMS)762 b(gcc)47 b(and)g(cc)143
+781 y(HP-UX)1049 b(gcc)143 894 y(IBM)47 b(AIX)954 b(gcc)143
+1007 y(Linux)1049 b(gcc)143 1120 y(MkLinux)953 b(DR3)143
+1233 y(Windows)46 b(95/98/NT)523 b(Borland)46 b(C++)h(V4.5)143
+1346 y(Windows)f(95/98/NT/ME/XP)235 b(Microsoft/Compaq)43
+b(Visual)j(C++)h(v5.0,)g(v6.0)143 1458 y(Windows)f(95/98/NT)523
+b(Cygwin)46 b(gcc)143 1571 y(OS/2)1097 b(gcc)47 b(+)g(EMX)143
+1684 y(MacOS)g(7.1)f(or)i(greater)332 b(Metrowerks)45
+b(10.+)0 1949 y Fi(CFITSIO)26 b(will)g(probably)g(run)g(on)i(most)g
+(other)h(Unix)d(platforms.)39 b(Cra)m(y)28 b(sup)s(ercomputers)e(are)j
+(curren)m(tly)e(not)0 2061 y(supp)s(orted.)0 2400 y Fd(2.2)135
+b(T)-11 b(esting)46 b(the)f(Library)0 2652 y Fi(The)40
+b(CFITSIO)e(library)g(should)g(b)s(e)h(tested)i(b)m(y)f(building)c(and)
+j(running)f(the)i(testprog.c)h(program)f(that)h(is)0
+2765 y(included)28 b(with)h(the)h(release.)41 b(On)30
+b(Unix)f(systems)h(t)m(yp)s(e:)191 3029 y Fe(\045)47
+b(make)g(testprog)191 3142 y(\045)g(testprog)f(>)h(testprog.lis)191
+3255 y(\045)g(diff)g(testprog.lis)d(testprog.out)191
+3368 y(\045)j(cmp)g(testprog.fit)e(testprog.std)0 3632
+y Fi(On)30 b(VMS)g(systems,)g(\(assuming)g(cc)h(is)e(the)i(name)f(of)h
+(the)f(C)g(compiler)f(command\),)i(t)m(yp)s(e:)191 3896
+y Fe($)47 b(cc)h(testprog.c)191 4009 y($)f(link)g(testprog,)e
+(cfitsio/lib,)g(alpha$library:vaxcrtl/l)o(ib)191 4122
+y($)i(run)g(testprog)0 4386 y Fi(The)30 b(testprog)h(program)g(should)d
+(pro)s(duce)h(a)i(FITS)f(\014le)f(called)h(`testprog.\014t')i(that)f
+(is)e(iden)m(tical)h(to)h(the)f(`test-)0 4499 y(prog.std')25
+b(FITS)f(\014le)f(included)f(with)h(this)h(release.)39
+b(The)24 b(diagnostic)g(messages)i(\(whic)m(h)d(w)m(ere)i(pip)s(ed)e
+(to)i(the)g(\014le)0 4612 y(testprog.lis)f(in)f(the)i(Unix)e(example\))
+i(should)d(b)s(e)i(iden)m(tical)g(to)h(the)g(listing)d(con)m(tained)j
+(in)e(the)i(\014le)e(testprog.out.)0 4725 y(The)30 b('di\013)7
+b(')30 b(and)f('cmp')i(commands)f(sho)m(wn)g(ab)s(o)m(v)m(e)h(should)e
+(not)h(rep)s(ort)g(an)m(y)h(di\013erences)f(in)f(the)h(\014les.)40
+b(\(There)0 4838 y(ma)m(y)35 b(b)s(e)e(some)h(minor)f(formatting)g
+(di\013erences,)i(suc)m(h)e(as)i(the)f(presence)g(or)g(absence)g(of)g
+(leading)f(zeros,)j(or)e(3)0 4951 y(digit)29 b(exp)s(onen)m(ts)h(in)f
+(n)m(um)m(b)s(ers,)h(whic)m(h)f(can)h(b)s(e)g(ignored\).)0
+5111 y(The)f(F)-8 b(ortran)31 b(wrapp)s(ers)d(in)g(CFITSIO)g(ma)m(y)j
+(b)s(e)e(tested)h(with)f(the)h(testf77)h(program.)40
+b(On)29 b(Unix)g(systems)h(the)0 5224 y(fortran)g(compilation)f(and)h
+(link)e(command)i(ma)m(y)h(b)s(e)f(called)f('f77')j(or)e('g77',)j(dep)s
+(ending)28 b(on)i(the)g(system.)143 5488 y Fe(\045)48
+b(f77)f(-o)g(testf77)f(testf77.f)f(-L.)i(-lcfitsio)e(-lnsl)h(-lsocket)
+48 5601 y(or)143 5714 y(\045)i(f77)f(-f)g(-o)g(testf77)f(testf77.f)f
+(-L.)i(-lcfitsio)188 b(\(under)46 b(SUN)h(O/S\))p eop
+%%Page: 7 13
+7 12 bop 0 299 a Fg(2.3.)72 b(LINKING)30 b(PR)m(OGRAMS)h(WITH)f(FITSIO)
+2041 b Fi(7)48 555 y Fe(or)143 668 y(\045)48 b(f77)f(-o)g(testf77)f
+(testf77.f)f(-Wl,-L.)h(-lcfitsio)f(-lm)i(-lnsl)f(-lsocket)g(\(HP/UX\))
+48 781 y(or)143 894 y(\045)i(g77)f(-o)g(testf77)f(-s)h(testf77.f)e
+(-lcfitsio)g(-lcc_dynamic)g(-lncurses)g(\(Mac)i(OS-X\))143
+1120 y(\045)h(testf77)d(>)j(testf77.lis)143 1233 y(\045)g(diff)e
+(testf77.lis)f(testf77.out)143 1346 y(\045)j(cmp)f(testf77.fit)d
+(testf77.std)0 1591 y Fi(On)31 b(mac)m(hines)g(running)f(SUN)h(O/S,)h
+(F)-8 b(ortran)33 b(programs)e(m)m(ust)h(b)s(e)f(compiled)f(with)h(the)
+h('-f)7 b(')32 b(option)g(to)g(force)0 1704 y(double)24
+b(precision)g(v)-5 b(ariables)24 b(to)i(b)s(e)f(aligned)f(on)i(8-b)m
+(yte)h(b)s(oundarys)c(to)j(mak)m(e)h(the)e(fortran-declared)g(v)-5
+b(ariables)0 1817 y(compatible)32 b(with)f(C.)h(A)h(similar)d(compiler)
+h(option)h(ma)m(y)h(b)s(e)f(required)f(on)h(other)h(platforms.)47
+b(F)-8 b(ailing)31 b(to)i(use)0 1930 y(this)25 b(option)g(ma)m(y)h
+(cause)h(the)f(program)f(to)i(crash)e(on)h(FITSIO)f(routines)f(that)j
+(read)f(or)f(write)g(double)g(precision)0 2043 y(v)-5
+b(ariables.)0 2203 y(Also)30 b(note)h(that)f(on)g(some)h(systems,)f
+(the)h(output)e(listing)f(of)j(the)f(testf77)i(program)d(ma)m(y)i
+(di\013er)e(sligh)m(tly)f(from)0 2316 y(the)j(testf77.std)h(template,)f
+(if)f(leading)f(zeros)i(are)g(not)g(prin)m(ted)e(b)m(y)i(default)f(b)s
+(efore)g(the)h(decimal)e(p)s(oin)m(t)h(when)0 2429 y(using)f(F)i
+(format.)0 2589 y(A)f(few)h(other)f(utilit)m(y)f(programs)h(are)h
+(included)c(with)i(CFITSIO:)191 2835 y Fe(speed)46 b(-)i(measures)d
+(the)i(maximum)f(throughput)f(\(in)i(MB)g(per)g(second\))668
+2947 y(for)g(writing)f(and)h(reading)f(FITS)g(files)h(with)f(CFITSIO)
+191 3173 y(listhead)f(-)j(lists)e(all)h(the)g(header)f(keywords)g(in)h
+(any)g(FITS)f(file)191 3399 y(fitscopy)f(-)j(copies)e(any)h(FITS)g
+(file)f(\(especially)f(useful)h(in)h(conjunction)811
+3512 y(with)g(the)g(CFITSIO's)e(extended)h(input)g(filename)g(syntax\))
+191 3738 y(cookbook)f(-)j(a)f(sample)f(program)g(that)h(peforms)f
+(common)g(read)g(and)811 3851 y(write)h(operations)e(on)i(a)g(FITS)g
+(file.)191 4077 y(iter_a,)f(iter_b,)g(iter_c)g(-)h(examples)f(of)h(the)
+g(CFITSIO)f(iterator)f(routine)0 4322 y Fi(The)30 b(\014rst)f(4)i(of)g
+(these)g(utilit)m(y)d(programs)i(can)h(b)s(e)f(compiled)f(and)g(link)m
+(ed)g(b)m(y)h(t)m(yping)143 4568 y Fe(\045)95 b(make)47
+b(program_name)0 4899 y Fd(2.3)135 b(Linking)45 b(Programs)h(with)f
+(FITSIO)0 5149 y Fi(When)31 b(linking)d(applications)i(soft)m(w)m(are)i
+(with)e(the)h(FITSIO)f(library)-8 b(,)30 b(sev)m(eral)i(system)f
+(libraries)d(usually)h(need)0 5262 y(to)d(b)s(e)f(sp)s(eci\014ed)f(on)h
+(the)h(link)e(comman)h(Unix)g(systems,)i(the)e(most)h(reliable)e(w)m(a)
+m(y)i(to)h(determine)d(what)i(libraries)0 5375 y(are)32
+b(required)e(is)g(to)j(t)m(yp)s(e)e('mak)m(e)i(testprog')g(and)e(see)h
+(what)f(libraries)e(the)j(con\014gure)f(script)g(has)g(added.)43
+b(The)0 5488 y(t)m(ypical)23 b(libraries)e(that)j(ma)m(y)g(need)f(to)h
+(b)s(e)f(added)g(are)g(-lm)g(\(the)h(math)f(library\))f(and)h(-lnsl)e
+(and)i(-lso)s(c)m(k)m(et)i(\(needed)0 5601 y(only)h(for)g(FTP)g(and)g
+(HTTP)g(\014le)g(access\).)41 b(These)26 b(latter)h(2)g(libraries)d
+(are)j(not)g(needed)f(on)g(VMS)h(and)f(Windo)m(ws)0 5714
+y(platforms,)k(b)s(ecause)g(FTP)g(\014le)g(access)h(is)f(not)g(curren)m
+(tly)g(supp)s(orted)e(on)i(those)h(platforms.)p eop
+%%Page: 8 14
+8 13 bop 0 299 a Fi(8)1896 b Fg(CHAPTER)30 b(2.)111 b(CREA)-8
+b(TING)31 b(FITSIO/CFITSIO)0 555 y Fi(Note)36 b(that)f(when)e
+(upgrading)f(to)j(a)g(new)m(er)f(v)m(ersion)g(of)h(CFITSIO)d(it)i(is)g
+(usually)e(necessa)m(y)j(to)g(recompile,)g(as)0 668 y(w)m(ell)29
+b(as)i(relink,)e(the)h(programs)g(that)h(use)f(CFITSIO,)f(b)s(ecause)i
+(the)f(de\014nitions)e(in)h(\014tsio.h)h(often)g(c)m(hange.)0
+1001 y Fd(2.4)135 b(Getting)46 b(Started)g(with)f(FITSIO)0
+1251 y Fi(In)32 b(order)h(to)h(e\013ectiv)m(ely)g(use)f(the)g(FITSIO)f
+(library)f(as)j(quic)m(kly)e(as)h(p)s(ossible,)f(it)h(is)f(recommended)
+h(that)g(new)0 1364 y(users)d(follo)m(w)f(these)i(steps:)0
+1524 y(1.)62 b(Read)38 b(the)f(follo)m(wing)f(`FITS)h(Primer')f(c)m
+(hapter)i(for)g(a)f(brief)f(o)m(v)m(erview)i(of)g(the)g(structure)e(of)
+i(FITS)f(\014les.)0 1637 y(This)24 b(is)h(esp)s(ecially)f(imp)s(ortan)m
+(t)i(for)f(users)h(who)f(ha)m(v)m(e)i(not)g(previously)c(dealt)j(with)f
+(the)h(FITS)f(table)h(and)g(image)0 1750 y(extensions.)0
+1910 y(2.)41 b(W)-8 b(rite)31 b(a)g(simple)d(program)i(to)h(read)g(or)f
+(write)f(a)i(FITS)f(\014le)f(using)g(the)i(Basic)f(In)m(terface)i
+(routines.)0 2071 y(3.)41 b(Refer)28 b(to)i(the)f(co)s(okb)s(o)s(ok.f)g
+(program)f(that)i(is)e(included)e(with)h(this)h(release)h(for)f
+(examples)h(of)g(routines)e(that)0 2183 y(p)s(erform)i(v)-5
+b(arious)29 b(common)i(FITS)f(\014le)f(op)s(erations.)0
+2344 y(4.)52 b(Read)34 b(Chapters)g(4)g(and)f(5)i(to)g(b)s(ecome)f
+(familiar)e(with)g(the)j(con)m(v)m(en)m(tions)g(and)e(adv)-5
+b(anced)34 b(features)h(of)f(the)0 2457 y(FITSIO)29 b(in)m(terface.)0
+2617 y(5.)47 b(Scan)32 b(through)f(the)h(more)h(extensiv)m(e)f(set)h
+(of)g(routines)e(that)h(are)h(pro)m(vided)e(in)g(the)h(`Adv)-5
+b(anced)32 b(In)m(terface'.)0 2730 y(These)22 b(routines)e(p)s(erform)h
+(more)h(sp)s(ecialized)e(functions)g(than)h(are)i(pro)m(vided)d(b)m(y)i
+(the)g(Basic)g(In)m(terface)h(routines.)0 3063 y Fd(2.5)135
+b(Example)46 b(Program)0 3313 y Fi(The)32 b(follo)m(wing)f(listing)f
+(sho)m(ws)i(an)g(example)h(of)f(ho)m(w)h(to)g(use)f(the)g(FITSIO)g
+(routines)f(in)g(a)i(F)-8 b(ortran)33 b(program.)0 3426
+y(Refer)38 b(to)h(the)g(co)s(okb)s(o)s(ok.f)f(program)g(that)h(is)e
+(included)e(with)i(the)i(FITSIO)e(distribution)d(for)k(examples)g(of)0
+3539 y(other)31 b(FITS)e(programs.)286 3794 y Fe(program)46
+b(writeimage)0 4020 y(C)238 b(Create)46 b(a)i(FITS)f(primary)e(array)i
+(containing)e(a)i(2-D)g(image)286 4246 y(integer)f
+(status,unit,blocksize,bit)o(pix,)o(nax)o(is,n)o(axes)o(\(2\))286
+4359 y(integer)g(i,j,group,fpixel,nelement)o(s,ar)o(ray)o(\(300)o(,200)
+o(\))286 4472 y(character)g(filename*80)286 4585 y(logical)g
+(simple,extend)286 4811 y(status=0)0 4924 y(C)238 b(Name)47
+b(of)g(the)g(FITS)g(file)f(to)i(be)f(created:)286 5036
+y(filename='ATESTFILE.FITS')0 5262 y(C)238 b(Get)47 b(an)g(unused)g
+(Logical)e(Unit)i(Number)f(to)h(use)g(to)g(create)f(the)h(FITS)g(file)
+286 5375 y(call)g(ftgiou\(unit,status\))0 5601 y(C)238
+b(create)46 b(the)h(new)g(empty)g(FITS)f(file)286 5714
+y(blocksize=1)p eop
+%%Page: 9 15
+9 14 bop 0 299 a Fg(2.6.)72 b(LEGAL)30 b(STUFF)2995 b
+Fi(9)286 555 y Fe(call)47 b(ftinit\(unit,filename,blo)o(cksi)o(ze,s)o
+(tat)o(us\))0 781 y(C)238 b(initialize)45 b(parameters)g(about)i(the)g
+(FITS)f(image)h(\(300)f(x)i(200)f(16-bit)f(integers\))286
+894 y(simple=.true.)286 1007 y(bitpix=16)286 1120 y(naxis=2)286
+1233 y(naxes\(1\)=300)286 1346 y(naxes\(2\)=200)286 1458
+y(extend=.true.)0 1684 y(C)238 b(write)47 b(the)g(required)e(header)h
+(keywords)286 1797 y(call)h(ftphpr\(unit,simple,bitpi)o(x,na)o(xis,)o
+(nax)o(es,0)o(,1,e)o(xte)o(nd,s)o(tatu)o(s\))0 2023 y(C)238
+b(initialize)45 b(the)i(values)f(in)i(the)e(image)h(with)f(a)i(linear)e
+(ramp)h(function)286 2136 y(do)h(j=1,naxes\(2\))477 2249
+y(do)f(i=1,naxes\(1\))668 2362 y(array\(i,j\)=i+j)477
+2475 y(end)g(do)286 2588 y(end)g(do)0 2813 y(C)238 b(write)47
+b(the)g(array)f(to)h(the)g(FITS)g(file)286 2926 y(group=1)286
+3039 y(fpixel=1)286 3152 y(nelements=naxes\(1\)*naxes\(2)o(\))286
+3265 y(call)g(ftpprj\(unit,group,fpixel)o(,nel)o(emen)o(ts,)o(arra)o
+(y,st)o(atu)o(s\))0 3491 y(C)238 b(write)47 b(another)f(optional)f
+(keyword)h(to)h(the)g(header)286 3604 y(call)g
+(ftpkyj\(unit,'EXPOSURE',1)o(500,)o('Tot)o(al)41 b(Exposure)46
+b(Time',status\))0 3830 y(C)238 b(close)47 b(the)g(file)f(and)h(free)g
+(the)g(unit)f(number)286 3942 y(call)h(ftclos\(unit,)d(status\))286
+4055 y(call)j(ftfiou\(unit,)d(status\))286 4168 y(end)0
+4527 y Fd(2.6)135 b(Legal)46 b(Stu\013)0 4782 y Fi(Cop)m(yrigh)m(t)36
+b(\(Unpublished{all)d(righ)m(ts)j(reserv)m(ed)h(under)e(the)i(cop)m
+(yrigh)m(t)g(la)m(ws)f(of)h(the)g(United)f(States\),)k(U.S.)0
+4895 y(Go)m(v)m(ernmen)m(t)30 b(as)g(represen)m(ted)e(b)m(y)h(the)g
+(Administrator)e(of)i(the)g(National)f(Aeronautics)h(and)f(Space)h
+(Adminis-)0 5008 y(tration.)41 b(No)31 b(cop)m(yrigh)m(t)f(is)g
+(claimed)f(in)g(the)i(United)e(States)i(under)e(Title)h(17,)h(U.S.)f
+(Co)s(de.)0 5168 y(P)m(ermission)e(to)i(freely)e(use,)i(cop)m(y)-8
+b(,)31 b(mo)s(dify)-8 b(,)28 b(and)h(distribute)e(this)h(soft)m(w)m
+(are)j(and)e(its)g(do)s(cumen)m(tation)g(without)0 5281
+y(fee)g(is)e(hereb)m(y)h(gran)m(ted,)i(pro)m(vided)d(that)i(this)e(cop)
+m(yrigh)m(t)i(notice)f(and)g(disclaimer)e(of)i(w)m(arran)m(t)m(y)i(app)
+s(ears)d(in)g(all)0 5394 y(copies.)41 b(\(Ho)m(w)m(ev)m(er,)33
+b(see)e(the)f(restriction)f(on)i(the)f(use)g(of)h(the)f(gzip)g
+(compression)g(co)s(de,)h(b)s(elo)m(w\).)0 5554 y(DISCLAIMER:)0
+5714 y(THE)i(SOFTW)-10 b(ARE)32 b(IS)g(PR)m(O)m(VIDED)i('AS)f(IS')g
+(WITHOUT)f(ANY)i(W)-10 b(ARRANTY)33 b(OF)g(ANY)h(KIND,)f(EI-)p
+eop
+%%Page: 10 16
+10 15 bop 0 299 a Fi(10)1851 b Fg(CHAPTER)30 b(2.)111
+b(CREA)-8 b(TING)31 b(FITSIO/CFITSIO)0 555 y Fi(THER)42
+b(EXPRESSED,)f(IMPLIED,)i(OR)e(ST)-8 b(A)g(TUTOR)g(Y,)43
+b(INCLUDING,)f(BUT)h(NOT)e(LIMITED)h(TO,)0 668 y(ANY)33
+b(W)-10 b(ARRANTY)33 b(THA)-8 b(T)32 b(THE)g(SOFTW)-10
+b(ARE)32 b(WILL)g(CONF)m(ORM)g(TO)g(SPECIFICA)-8 b(TIONS,)30
+b(ANY)0 781 y(IMPLIED)38 b(W)-10 b(ARRANTIES)37 b(OF)h(MER)m(CHANT)-8
+b(ABILITY,)38 b(FITNESS)f(F)m(OR)h(A)g(P)-8 b(AR)g(TICULAR)38
+b(PUR-)0 894 y(POSE,)24 b(AND)i(FREEDOM)f(FR)m(OM)h(INFRINGEMENT,)g
+(AND)f(ANY)h(W)-10 b(ARRANTY)25 b(THA)-8 b(T)25 b(THE)g(DOC-)0
+1007 y(UMENT)-8 b(A)g(TION)31 b(WILL)f(CONF)m(ORM)h(TO)e(THE)h(SOFTW)
+-10 b(ARE,)30 b(OR)g(ANY)h(W)-10 b(ARRANTY)31 b(THA)-8
+b(T)30 b(THE)0 1120 y(SOFTW)-10 b(ARE)31 b(WILL)h(BE)g(ERR)m(OR)g
+(FREE.)g(IN)g(NO)f(EVENT)h(SHALL)f(NASA)h(BE)g(LIABLE)g(F)m(OR)g(ANY)0
+1233 y(D)m(AMA)m(GES,)26 b(INCLUDING,)e(BUT)f(NOT)g(LIMITED)h(TO,)f
+(DIRECT,)g(INDIRECT,)g(SPECIAL)f(OR)h(CON-)0 1346 y(SEQUENTIAL)28
+b(D)m(AMA)m(GES,)k(ARISING)d(OUT)g(OF,)h(RESUL)-8 b(TING)29
+b(FR)m(OM,)h(OR)f(IN)h(ANY)g(W)-10 b(A)i(Y)30 b(CON-)0
+1458 y(NECTED)25 b(WITH)g(THIS)f(SOFTW)-10 b(ARE,)25
+b(WHETHER)g(OR)g(NOT)g(BASED)g(UPON)g(W)-10 b(ARRANTY,)26
+b(CON-)0 1571 y(TRA)m(CT,)d(TOR)-8 b(T)23 b(,)g(OR)g(OTHER)-10
+b(WISE,)22 b(WHETHER)i(OR)f(NOT)f(INJUR)-8 b(Y)24 b(W)-10
+b(AS)23 b(SUST)-8 b(AINED)23 b(BY)h(PER-)0 1684 y(SONS)h(OR)i(PR)m
+(OPER)-8 b(TY)26 b(OR)g(OTHER)-10 b(WISE,)26 b(AND)h(WHETHER)g(OR)f
+(NOT)g(LOSS)f(W)-10 b(AS)26 b(SUST)-8 b(AINED)0 1797
+y(FR)m(OM,)37 b(OR)e(AR)m(OSE)h(OUT)f(OF)h(THE)g(RESUL)-8
+b(TS)35 b(OF,)h(OR)f(USE)h(OF,)g(THE)g(SOFTW)-10 b(ARE)35
+b(OR)g(SER-)0 1910 y(VICES)29 b(PR)m(O)m(VIDED)j(HEREUNDER.")0
+2070 y(The)i(\014le)h(compress.c)g(con)m(tains)g(\(sligh)m(tly)f(mo)s
+(di\014ed\))f(source)i(co)s(de)g(that)h(originally)c(came)k(from)f
+(gzip-1.2.4,)0 2183 y(cop)m(yrigh)m(t)26 b(\(C\))g(1992-1993)k(b)m(y)c
+(Jean-loup)f(Gailly)-8 b(.)38 b(This)24 b(gzip)h(co)s(de)h(is)f
+(distributed)e(under)i(the)h(GNU)g(General)0 2296 y(Public)k(License)i
+(and)f(th)m(us)h(requires)f(that)i(an)m(y)f(soft)m(w)m(are)i(that)f
+(uses)f(the)g(CFITSIO)f(library)f(\(whic)m(h)h(in)g(turn)0
+2409 y(uses)e(the)g(gzip)g(co)s(de\))h(m)m(ust)f(conform)g(to)h(the)f
+(pro)m(visions)e(in)h(the)i(GNU)g(General)f(Public)e(License.)40
+b(A)29 b(cop)m(y)h(of)0 2522 y(the)h(GNU)g(license)e(is)g(included)f
+(at)j(the)g(b)s(eginning)c(of)k(compress.c)g(\014le.)0
+2682 y(An)h(alternate)i(v)m(ersion)e(of)h(the)g(compress.c)g(\014le)f
+(\(called)g(compress)p 2381 2682 28 4 v 33 w(alternate.c\))i(is)e(pro)m
+(vided)f(for)i(users)e(who)0 2795 y(w)m(an)m(t)24 b(to)g(use)e(the)i
+(CFITSIO)d(library)g(but)h(are)h(un)m(willing)d(or)j(unable)e(to)j
+(publicly)c(release)j(their)f(soft)m(w)m(are)i(under)0
+2908 y(the)i(terms)g(of)g(the)g(GNU)h(General)e(Public)f(License.)39
+b(This)24 b(alternate)i(v)m(ersion)g(con)m(tains)g(non-functional)e
+(stubs)0 3021 y(for)g(the)h(\014le)e(compression)h(and)f(uncompression)
+g(routines)g(used)h(b)m(y)g(CFITSIO.)f(Replace)i(the)f(\014le)g
+(`compress.c')0 3134 y(with)32 b(`compress)p 600 3134
+V 33 w(alternate.c')j(b)s(efore)e(compiling)e(the)i(CFITSIO)f(library)
+-8 b(.)48 b(This)31 b(will)g(pro)s(duce)h(a)i(v)m(ersion)f(of)0
+3247 y(CFITSIO)20 b(whic)m(h)h(do)s(es)g(not)h(supp)s(ort)e(reading)h
+(or)h(writing)e(compressed)h(FITS)g(\014les)g(but)g(is)g(otherwise)g
+(iden)m(tical)0 3360 y(to)31 b(the)g(standard)e(v)m(ersion.)0
+3733 y Fd(2.7)135 b(Ac)l(kno)l(wledgemen)l(ts)0 3991
+y Fi(The)29 b(dev)m(elopmen)m(t)g(of)h(man)m(y)f(of)h(the)f(p)s(o)m(w)m
+(erful)f(features)h(in)f(CFITSIO)g(w)m(as)i(made)f(p)s(ossible)e
+(through)h(collab-)0 4104 y(orations)34 b(with)f(man)m(y)i(p)s(eople)e
+(or)i(organizations)f(from)g(around)f(the)i(w)m(orld.)51
+b(The)34 b(follo)m(wing,)g(in)f(particular,)0 4217 y(ha)m(v)m(e)f(made)
+e(esp)s(ecially)f(signi\014can)m(t)g(con)m(tributions:)0
+4377 y(Programmers)c(from)h(the)f(In)m(tegral)h(Science)g(Data)h(Cen)m
+(ter,)g(Switzerland)d(\(namely)-8 b(,)27 b(Jurek)d(Bork)m(o)m(wski,)k
+(Bruce)0 4490 y(O'Neel,)33 b(and)f(Don)h(Jennings\),)e(designed)g(the)i
+(concept)g(for)f(the)h(plug-in)d(I/O)i(driv)m(ers)f(that)i(w)m(as)g(in)
+m(tro)s(duced)0 4603 y(with)h(CFITSIO)f(2.0.)56 b(The)34
+b(use)h(of)g(`driv)m(ers')f(greatly)h(simpli\014ed)d(the)j(lo)m(w-lev)m
+(el)g(I/O,)g(whic)m(h)e(in)h(turn)g(made)0 4716 y(other)40
+b(new)f(features)i(in)d(CFITSIO)g(\(e.g.,)45 b(supp)s(ort)38
+b(for)h(compressed)h(FITS)f(\014les)g(and)g(supp)s(ort)f(for)i(IRAF)0
+4829 y(format)32 b(image)f(\014les\))g(m)m(uc)m(h)g(easier)h(to)g
+(implemen)m(t.)42 b(Jurek)31 b(Bork)m(o)m(wski)g(wrote)h(the)g(Shared)e
+(Memory)i(driv)m(er,)0 4942 y(and)23 b(Bruce)i(O'Neel)f(wrote)g(the)g
+(driv)m(ers)f(for)g(accessing)i(FITS)e(\014les)g(o)m(v)m(er)i(the)f
+(net)m(w)m(ork)h(using)d(the)j(FTP)-8 b(,)24 b(HTTP)-8
+b(,)0 5055 y(and)30 b(R)m(OOT)g(proto)s(cols.)0 5215
+y(The)45 b(ISDC)g(also)g(pro)m(vided)f(the)i(template)g(parsing)e
+(routines)g(\(written)h(b)m(y)g(Jurek)g(Bork)m(o)m(wski\))h(and)f(the)0
+5328 y(hierarc)m(hical)36 b(grouping)f(routines)h(\(written)h(b)m(y)g
+(Don)h(Jennings\).)59 b(The)37 b(ISDC)f(D)m(AL)i(\(Data)h(Access)f(La)m
+(y)m(er\))0 5441 y(routines)29 b(are)i(la)m(y)m(ered)g(on)f(top)h(of)f
+(CFITSIO)f(and)h(mak)m(e)h(extensiv)m(e)g(use)f(of)h(these)g(features.)
+0 5601 y(Uw)m(e)25 b(Lammers)e(\(XMM/ESA/ESTEC,)h(The)g(Netherlands\))f
+(designed)g(the)h(high-p)s(erformance)e(lexical)h(pars-)0
+5714 y(ing)41 b(algorithm)g(that)h(is)f(used)g(to)i(do)e(on-the-\015y)h
+(\014ltering)e(of)i(FITS)f(tables.)75 b(This)40 b(algorithm)h(essen)m
+(tially)p eop
+%%Page: 11 17
+11 16 bop 0 299 a Fg(2.7.)72 b(A)m(CKNO)m(WLEDGEMENTS)2515
+b Fi(11)0 555 y(pre-compiles)34 b(the)i(user-supplied)c(selection)k
+(expression)e(in)m(to)i(a)g(form)g(that)g(can)g(b)s(e)f(rapidly)e(ev)-5
+b(aluated)36 b(for)0 668 y(eac)m(h)31 b(ro)m(w.)40 b(P)m(eter)31
+b(Wilson)d(\(RSTX,)h(NASA/GSF)m(C\))i(then)e(wrote)h(the)g(parsing)e
+(routines)g(used)h(b)m(y)g(CFITSIO)0 781 y(based)i(on)f(Lammers')h
+(design,)f(com)m(bined)g(with)g(other)h(tec)m(hniques)f(suc)m(h)h(as)g
+(the)g(CFITSIO)f(iterator)h(routine)0 894 y(to)h(further)e(enhance)h
+(the)h(data)g(pro)s(cessing)e(throughput.)42 b(This)30
+b(e\013ort)i(also)f(b)s(ene\014ted)f(from)h(a)h(m)m(uc)m(h)f(earlier)0
+1007 y(lexical)22 b(parsing)h(routine)f(that)i(w)m(as)g(dev)m(elop)s
+(ed)f(b)m(y)h(Ken)m(t)g(Blac)m(kburn)e(\(NASA/GSF)m(C\).)j(More)g
+(recen)m(tly)-8 b(,)26 b(Craig)0 1120 y(Markw)m(ardt)j(\(NASA/GSF)m
+(C\))g(implemen)m(ted)e(additional)f(functions)h(\(median,)h(a)m(v)m
+(erage,)k(stddev\))c(and)g(other)0 1233 y(enhancemen)m(ts)j(to)g(the)g
+(lexical)e(parser.)0 1393 y(The)40 b(CFITSIO)g(iterator)h(function)e
+(is)h(lo)s(osely)g(based)h(on)f(similar)f(ideas)h(dev)m(elop)s(ed)g
+(for)h(the)g(XMM)g(Data)0 1506 y(Access)31 b(La)m(y)m(er.)0
+1666 y(P)m(eter)25 b(Wilson)e(\(RSTX,)h(NASA/GSF)m(C\))h(wrote)g(the)f
+(complete)h(set)f(of)h(F)-8 b(ortran-callable)24 b(wrapp)s(ers)e(for)i
+(all)f(the)0 1779 y(CFITSIO)29 b(routines,)g(whic)m(h)g(in)g(turn)h
+(rely)f(on)i(the)f(CF)m(OR)-8 b(TRAN)31 b(macro)g(dev)m(elop)s(ed)f(b)m
+(y)g(Burkhard)f(Buro)m(w.)0 1939 y(The)h(syn)m(tax)i(used)e(b)m(y)h
+(CFITSIO)f(for)g(\014ltering)g(or)h(binning)c(input)i(FITS)i(\014les)f
+(is)g(based)g(on)h(ideas)g(dev)m(elop)s(ed)0 2052 y(for)41
+b(the)g(AXAF)h(Science)f(Cen)m(ter)h(Data)h(Mo)s(del)d(b)m(y)h
+(Jonathan)g(McDo)m(w)m(ell,)k(An)m(tonella)c(F)-8 b(ruscione,)44
+b(Aneta)0 2165 y(Siemigino)m(wsk)-5 b(a)24 b(and)h(Bill)f(Jo)m(y)m(e.)
+41 b(See)26 b(h)m(ttp://heasarc.gsfc.nasa.go)m(v/do)s
+(cs/journal/axaf7.h)m(t)q(ml)31 b(for)25 b(further)0
+2278 y(description)j(of)j(the)g(AXAF)g(Data)h(Mo)s(del.)0
+2438 y(The)j(\014le)f(decompression)g(co)s(de)h(w)m(ere)h(tak)m(en)g
+(directly)e(from)g(the)i(gzip)e(\(GNU)i(zip\))f(program)g(dev)m(elop)s
+(ed)f(b)m(y)0 2551 y(Jean-loup)29 b(Gailly)g(and)h(others.)0
+2711 y(Doug)h(Mink,)f(SA)m(O,)g(pro)m(vided)f(the)i(routines)e(for)h
+(con)m(v)m(erting)h(IRAF)g(format)g(images)f(in)m(to)g(FITS)g(format.)0
+2871 y(In)d(addition,)g(man)m(y)h(other)g(p)s(eople)f(ha)m(v)m(e)i
+(made)f(v)-5 b(aluable)27 b(con)m(tributions)f(to)j(the)f(dev)m
+(elopmen)m(t)g(of)g(CFITSIO.)0 2984 y(These)i(include)e(\(with)i(ap)s
+(ologies)g(to)h(others)f(that)h(ma)m(y)g(ha)m(v)m(e)h(inadv)m(erten)m
+(tly)e(b)s(een)f(omitted\):)0 3144 y(Stev)m(e)g(Allen,)e(Carl)g(Ak)m
+(erlof,)h(Keith)f(Arnaud,)h(Morten)g(Krabb)s(e)e(Barfo)s(ed,)j(Ken)m(t)
+f(Blac)m(kburn,)g(G)g(Bo)s(dammer,)0 3257 y(Romk)m(e)h(Bon)m(tek)m(o)s
+(e,)i(Lucio)c(Chiapp)s(etti,)f(Keith)h(Costorf,)h(Robin)f(Corb)s(et,)h
+(John)e(Da)m(vis,)j(Ric)m(hard)e(Fink,)h(Ning)0 3370
+y(Gan,)h(Emily)c(Greene,)k(Jo)s(e)f(Harrington,)g(Cheng)f(Ho,)i(Phil)c
+(Ho)s(dge,)k(Jim)e(Ingham,)h(Y)-8 b(oshitak)j(a)28 b(Ishisaki,)e(Diab)0
+3483 y(Jerius,)k(Mark)i(Levine,)f(T)-8 b(o)s(dd)30 b(Karak)-5
+b(askian,)31 b(Edw)m(ard)g(King,)f(Scott)j(Ko)s(c)m(h,)e(Claire)f
+(Larkin,)g(Rob)i(Managan,)0 3596 y(Eric)37 b(Mandel,)i(John)e(Matto)m
+(x,)43 b(Carsten)37 b(Mey)m(er,)42 b(Emi)36 b(Miy)m(ata,)42
+b(Stefan)c(Mo)s(c)m(hnac)m(ki,)i(Mik)m(e)f(Noble,)g(Oliv)m(er)0
+3709 y(Ob)s(erdorf,)d(Cliv)m(e)g(P)m(age,)k(Arvind)34
+b(P)m(armar,)k(Je\013)f(P)m(edelt)m(y)-8 b(,)39 b(Tim)c(P)m(earson,)k
+(Maren)e(Purv)m(es,)h(Scott)f(Randall,)0 3822 y(Chris)c(Rogers,)k
+(Arnold)d(Rots,)j(Barry)f(Sc)m(hlesinger,)f(Robin)f(Stebbins,)g(Andrew)
+g(Szymk)m(o)m(wiak,)j(Allyn)d(T)-8 b(en-)0 3934 y(nan)m(t,)31
+b(P)m(eter)g(T)-8 b(eub)s(en,)30 b(James)g(Theiler,)f(Doug)i(T)-8
+b(o)s(dy)g(,)31 b(Shiro)d(Ueno,)k(Stev)m(e)f(W)-8 b(alton,)32
+b(Arc)m(hie)e(W)-8 b(arno)s(c)m(k,)32 b(Alan)0 4047 y(W)-8
+b(atson,)32 b(Dan)f(Whipple,)d(Wim)i(Wimmers,)g(P)m(eter)h(Y)-8
+b(oung,)31 b(Jianjun)d(Xu,)i(and)g(Nelson)g(Zarate.)p
+eop
+%%Page: 12 18
+12 17 bop 0 299 a Fi(12)1851 b Fg(CHAPTER)30 b(2.)111
+b(CREA)-8 b(TING)31 b(FITSIO/CFITSIO)p eop
+%%Page: 13 19
+13 18 bop 0 1225 a Ff(Chapter)65 b(3)0 1687 y Fl(A)78
+b(FITS)f(Primer)0 2180 y Fi(This)22 b(section)j(giv)m(es)f(a)h(brief)d
+(o)m(v)m(erview)j(of)f(the)h(structure)e(of)i(FITS)e(\014les.)37
+b(Users)24 b(should)f(refer)g(to)i(the)g(do)s(cumen-)0
+2293 y(tation)i(a)m(v)-5 b(ailable)27 b(from)g(the)g(NOST,)f(as)i
+(describ)s(ed)d(in)h(the)h(in)m(tro)s(duction,)f(for)h(more)g(detailed)
+g(information)e(on)0 2406 y(FITS)30 b(formats.)0 2566
+y(FITS)37 b(w)m(as)g(\014rst)g(dev)m(elop)s(ed)g(in)f(the)h(late)h
+(1970's)h(as)f(a)f(standard)g(data)h(in)m(terc)m(hange)g(format)g(b)s
+(et)m(w)m(een)g(v)-5 b(ar-)0 2679 y(ious)37 b(astronomical)g(observ)-5
+b(atories.)63 b(Since)36 b(then)h(FITS)g(has)h(b)s(ecome)g(the)g
+(defacto)g(standard)f(data)i(format)0 2791 y(supp)s(orted)29
+b(b)m(y)h(most)h(astronomical)f(data)h(analysis)e(soft)m(w)m(are)i(pac)
+m(k)-5 b(ages.)0 2952 y(A)34 b(FITS)f(\014le)f(consists)h(of)h(one)g
+(or)g(more)g(Header)g(+)f(Data)i(Units)e(\(HDUs\),)j(where)d(the)h
+(\014rst)f(HDU)h(is)f(called)0 3065 y(the)k(`Primary)e(HDU',)j(or)f
+(`Primary)e(Arra)m(y'.)60 b(The)36 b(primary)f(arra)m(y)i(con)m(tains)g
+(an)f(N-dimensional)f(arra)m(y)i(of)0 3177 y(pixels,)28
+b(suc)m(h)g(as)h(a)h(1-D)g(sp)s(ectrum,)e(a)h(2-D)h(image,)g(or)f(a)g
+(3-D)h(data)g(cub)s(e.)39 b(Fiv)m(e)30 b(di\013eren)m(t)e(primary)f
+(datat)m(yp)s(es)0 3290 y(are)f(supp)s(orted:)37 b(Unsigned)24
+b(8-bit)i(b)m(ytes,)h(16)g(and)e(32-bit)h(signed)e(in)m(tegers,)j(and)f
+(32)g(and)f(64-bit)h(\015oating)g(p)s(oin)m(t)0 3403
+y(reals.)40 b(FITS)29 b(also)h(has)g(a)g(con)m(v)m(en)m(tion)i(for)d
+(storing)h(16)h(and)e(32-bit)h(unsigned)e(in)m(tegers)j(\(see)g(the)f
+(later)g(section)0 3516 y(en)m(titled)d(`Unsigned)g(In)m(tegers')i(for)
+e(more)h(details\).)39 b(The)27 b(primary)f(HDU)j(ma)m(y)f(also)g
+(consist)f(of)h(only)f(a)h(header)0 3629 y(with)h(a)i(n)m(ull)d(arra)m
+(y)j(con)m(taining)f(no)g(data)h(pixels.)0 3789 y(An)m(y)i(n)m(um)m(b)s
+(er)e(of)h(additional)f(HDUs)i(ma)m(y)g(follo)m(w)f(the)g(primary)f
+(arra)m(y;)j(these)f(additional)e(HDUs)i(are)g(called)0
+3902 y(FITS)d(`extensions'.)40 b(There)30 b(are)h(curren)m(tly)e(3)i(t)
+m(yp)s(es)g(of)f(extensions)g(de\014ned)f(b)m(y)h(the)h(FITS)f
+(standard:)136 4171 y Fc(\017)46 b Fi(Image)31 b(Extension)f(-)h(a)f
+(N-dimensional)e(arra)m(y)j(of)g(pixels,)e(lik)m(e)g(in)g(a)i(primary)d
+(arra)m(y)136 4368 y Fc(\017)46 b Fi(ASCI)s(I)29 b(T)-8
+b(able)30 b(Extension)g(-)g(ro)m(ws)h(and)e(columns)g(of)i(data)g(in)e
+(ASCI)s(I)g(c)m(haracter)j(format)136 4564 y Fc(\017)46
+b Fi(Binary)30 b(T)-8 b(able)30 b(Extension)f(-)i(ro)m(ws)f(and)g
+(columns)f(of)i(data)g(in)e(binary)f(represen)m(tation)0
+4833 y(In)33 b(eac)m(h)i(case)g(the)f(HDU)h(consists)f(of)g(an)g(ASCI)s
+(I)e(Header)i(Unit)g(follo)m(w)m(ed)f(b)m(y)h(an)g(optional)f(Data)i
+(Unit.)51 b(F)-8 b(or)0 4946 y(historical)34 b(reasons,)j(eac)m(h)f
+(Header)g(or)g(Data)h(unit)d(m)m(ust)h(b)s(e)g(an)g(exact)i(m)m
+(ultiple)c(of)j(2880)h(8-bit)e(b)m(ytes)h(long.)0 5059
+y(An)m(y)30 b(un)m(used)g(space)g(is)g(padded)f(with)g(\014ll)f(c)m
+(haracters)k(\(ASCI)s(I)d(blanks)g(or)i(zeros\).)0 5219
+y(Eac)m(h)i(Header)f(Unit)g(consists)g(of)g(an)m(y)g(n)m(um)m(b)s(er)f
+(of)i(80-c)m(haracter)i(k)m(eyw)m(ord)d(records)g(or)g(`card)h(images')
+f(whic)m(h)0 5332 y(ha)m(v)m(e)g(the)e(general)h(form:)95
+5601 y Fe(KEYNAME)46 b(=)i(value)e(/)i(comment)d(string)95
+5714 y(NULLKEY)h(=)334 b(/)48 b(comment:)d(This)i(keyword)f(has)g(no)i
+(value)1905 5942 y Fi(13)p eop
+%%Page: 14 20
+14 19 bop 0 299 a Fi(14)2398 b Fg(CHAPTER)30 b(3.)112
+b(A)30 b(FITS)g(PRIMER)0 555 y Fi(The)35 b(k)m(eyw)m(ord)i(names)f(ma)m
+(y)g(b)s(e)g(up)f(to)h(8)h(c)m(haracters)g(long)f(and)f(can)h(only)g
+(con)m(tain)g(upp)s(ercase)f(letters,)j(the)0 668 y(digits)23
+b(0-9,)k(the)e(h)m(yphen,)g(and)f(the)h(underscore)e(c)m(haracter.)41
+b(The)24 b(k)m(eyw)m(ord)h(name)g(is)e(\(usually\))g(follo)m(w)m(ed)i
+(b)m(y)f(an)0 781 y(equals)k(sign)g(and)g(a)g(space)i(c)m(haracter)g
+(\(=)e(\))h(in)e(columns)h(9)h(-)f(10)i(of)f(the)f(record,)h(follo)m(w)
+m(ed)g(b)m(y)f(the)h(v)-5 b(alue)28 b(of)h(the)0 894
+y(k)m(eyw)m(ord)34 b(whic)m(h)f(ma)m(y)h(b)s(e)f(either)g(an)h(in)m
+(teger,)h(a)f(\015oating)f(p)s(oin)m(t)g(n)m(um)m(b)s(er,)h(a)g(c)m
+(haracter)h(string)d(\(enclosed)i(in)0 1007 y(single)26
+b(quotes\),)k(or)e(a)g(b)s(o)s(olean)f(v)-5 b(alue)27
+b(\(the)h(letter)g(T)g(or)f(F\).)i(A)f(k)m(eyw)m(ord)g(ma)m(y)h(also)e
+(ha)m(v)m(e)i(a)g(n)m(ull)c(or)j(unde\014ned)0 1120 y(v)-5
+b(alue)30 b(if)f(there)i(is)e(no)h(sp)s(eci\014ed)f(v)-5
+b(alue)30 b(string,)g(as)g(in)f(the)i(second)f(example.)0
+1280 y(The)42 b(last)g(k)m(eyw)m(ord)h(in)e(the)i(header)f(is)f(alw)m
+(a)m(ys)i(the)g(`END')g(k)m(eyw)m(ord)g(whic)m(h)e(has)h(no)h(v)-5
+b(alue)41 b(or)i(commen)m(t)0 1393 y(\014elds.)c(There)30
+b(are)h(man)m(y)f(rules)f(go)m(v)m(erning)i(the)f(exact)i(format)f(of)f
+(a)h(k)m(eyw)m(ord)f(record)h(\(see)g(the)f(NOST)g(FITS)0
+1506 y(Standard\))h(so)h(it)f(is)f(b)s(etter)i(to)g(rely)f(on)g
+(standard)g(in)m(terface)h(soft)m(w)m(are)h(lik)m(e)e(FITSIO)f(to)j
+(correctly)f(construct)0 1619 y(or)e(to)h(parse)g(the)f(k)m(eyw)m(ord)h
+(records)f(rather)g(than)h(try)f(to)h(deal)f(directly)f(with)g(the)h
+(ra)m(w)h(FITS)f(formats.)0 1779 y(Eac)m(h)37 b(Header)g(Unit)e(b)s
+(egins)g(with)g(a)h(series)g(of)g(required)f(k)m(eyw)m(ords)h(whic)m(h)
+f(dep)s(end)g(on)h(the)g(t)m(yp)s(e)h(of)f(HDU.)0 1892
+y(These)31 b(required)f(k)m(eyw)m(ords)i(sp)s(ecify)f(the)g(size)h(and)
+f(format)h(of)g(the)g(follo)m(wing)e(Data)j(Unit.)44
+b(The)31 b(header)g(ma)m(y)0 2005 y(con)m(tain)g(other)g(optional)e(k)m
+(eyw)m(ords)i(to)h(describ)s(e)d(other)h(asp)s(ects)h(of)g(the)g(data,)
+g(suc)m(h)g(as)g(the)f(units)f(or)i(scaling)0 2118 y(v)-5
+b(alues.)43 b(Other)31 b(COMMENT)g(or)g(HISTOR)-8 b(Y)30
+b(k)m(eyw)m(ords)i(are)g(also)f(frequen)m(tly)g(added)f(to)i(further)e
+(do)s(cumen)m(t)0 2230 y(the)h(data)g(\014le.)0 2391
+y(The)36 b(optional)f(Data)j(Unit)e(immediately)e(follo)m(ws)i(the)g
+(last)g(2880-b)m(yte)j(blo)s(c)m(k)d(in)f(the)h(Header)h(Unit.)58
+b(Some)0 2503 y(HDUs)31 b(do)f(not)h(ha)m(v)m(e)g(a)g(Data)h(Unit)e
+(and)g(only)f(consist)h(of)h(the)f(Header)h(Unit.)0 2664
+y(If)24 b(there)i(is)e(more)h(than)f(one)h(HDU)h(in)e(the)h(FITS)f
+(\014le,)h(then)g(the)g(Header)h(Unit)e(of)h(the)g(next)g(HDU)h
+(immediately)0 2777 y(follo)m(ws)e(the)g(last)h(2880-b)m(yte)i(blo)s(c)
+m(k)d(of)h(the)f(previous)f(Data)k(Unit)c(\(or)i(Header)g(Unit)f(if)f
+(there)i(is)f(no)g(Data)i(Unit\).)0 2937 y(The)k(main)f(required)g(k)m
+(eyw)m(ords)h(in)f(FITS)h(primary)f(arra)m(ys)h(or)h(image)f
+(extensions)g(are:)136 3172 y Fc(\017)46 b Fi(BITPIX)25
+b({)h(de\014nes)f(the)g(datat)m(yp)s(e)i(of)e(the)h(arra)m(y:)39
+b(8,)27 b(16,)g(32,)h(-32,)g(-64)e(for)f(unsigned)f(8{bit)h(b)m(yte,)j
+(16{bit)227 3284 y(signed)38 b(in)m(teger,)j(32{bit)e(signed)e(in)m
+(teger,)k(32{bit)e(IEEE)f(\015oating)g(p)s(oin)m(t,)i(and)e(64{bit)h
+(IEEE)e(double)227 3397 y(precision)29 b(\015oating)h(p)s(oin)m(t,)g
+(resp)s(ectiv)m(ely)-8 b(.)136 3585 y Fc(\017)46 b Fi(NAXIS)30
+b({)h(the)g(n)m(um)m(b)s(er)e(of)h(dimensions)e(in)h(the)i(arra)m(y)-8
+b(,)31 b(usually)d(0,)j(1,)g(2,)g(3,)g(or)g(4.)136 3773
+y Fc(\017)46 b Fi(NAXISn)30 b({)h(\(n)f(ranges)g(from)g(1)h(to)g
+(NAXIS\))g(de\014nes)e(the)i(size)f(of)h(eac)m(h)g(dimension.)0
+4008 y(FITS)e(tables)h(start)h(with)e(the)h(k)m(eyw)m(ord)g(XTENSION)g
+(=)f(`T)-8 b(ABLE')31 b(\(for)f(ASCI)s(I)f(tables\))h(or)g(XTENSION)f
+(=)0 4120 y(`BINT)-8 b(ABLE')32 b(\(for)e(binary)f(tables\))h(and)g(ha)
+m(v)m(e)i(the)e(follo)m(wing)f(main)g(k)m(eyw)m(ords:)136
+4355 y Fc(\017)46 b Fi(TFIELDS)30 b({)h(n)m(um)m(b)s(er)e(of)h
+(\014elds)f(or)i(columns)e(in)g(the)h(table)136 4543
+y Fc(\017)46 b Fi(NAXIS2)31 b({)g(n)m(um)m(b)s(er)e(of)h(ro)m(ws)h(in)e
+(the)h(table)136 4731 y Fc(\017)46 b Fi(TTYPEn)29 b({)i(for)f(eac)m(h)i
+(column)d(\(n)h(ranges)h(from)f(1)g(to)h(TFIELDS\))g(giv)m(es)f(the)h
+(name)f(of)h(the)f(column)136 4918 y Fc(\017)46 b Fi(TF)m(ORMn)31
+b({)f(the)h(datat)m(yp)s(e)g(of)g(the)f(column)136 5106
+y Fc(\017)46 b Fi(TUNITn)30 b({)g(the)h(ph)m(ysical)e(units)g(of)h(the)
+h(column)e(\(optional\))0 5341 y(Users)e(should)e(refer)i(to)g(the)h
+(FITS)e(Supp)s(ort)f(O\016ce)i(at)h Fe(http://fits.gsfc.nasa.go)o(v)21
+b Fi(for)27 b(futher)f(informa-)0 5454 y(tion)k(ab)s(out)g(the)h(FITS)e
+(format)i(and)f(related)g(soft)m(w)m(are)i(pac)m(k)-5
+b(ages.)p eop
+%%Page: 15 21
+15 20 bop 0 1225 a Ff(Chapter)65 b(4)0 1687 y Fl(Extended)77
+b(File)g(Name)g(Syn)-6 b(tax)0 2216 y Fd(4.1)135 b(Ov)l(erview)0
+2466 y Fi(CFITSIO)30 b(supp)s(orts)f(an)j(extended)f(syn)m(tax)h(when)f
+(sp)s(ecifying)e(the)j(name)f(of)h(the)g(data)g(\014le)e(to)i(b)s(e)f
+(op)s(ened)g(or)0 2579 y(created)g(that)g(includes)d(the)j(follo)m
+(wing)e(features:)136 2813 y Fc(\017)46 b Fi(CFITSIO)40
+b(can)i(read)f(IRAF)h(format)g(images)f(whic)m(h)f(ha)m(v)m(e)j(header)
+e(\014le)g(names)g(that)h(end)f(with)f(the)227 2926 y('.imh')d
+(extension,)i(as)f(w)m(ell)e(as)i(reading)e(and)h(writing)e(FITS)i
+(\014les,)h(This)e(feature)i(is)e(implemen)m(ted)g(in)227
+3039 y(CFITSIO)29 b(b)m(y)i(\014rst)e(con)m(v)m(erting)j(the)e(IRAF)h
+(image)g(in)m(to)f(a)h(temp)s(orary)f(FITS)g(format)h(\014le)e(in)g
+(memory)-8 b(,)227 3152 y(then)35 b(op)s(ening)e(the)i(FITS)f(\014le.)
+53 b(An)m(y)35 b(of)g(the)g(usual)e(CFITSIO)h(routines)f(then)i(ma)m(y)
+g(b)s(e)f(used)g(to)i(read)227 3265 y(the)31 b(image)f(header)g(or)h
+(data.)41 b(Similarly)-8 b(,)27 b(ra)m(w)j(binary)f(data)i(arra)m(ys)f
+(can)h(b)s(e)f(read)g(b)m(y)g(con)m(v)m(erting)h(them)227
+3378 y(on)g(the)f(\015y)g(in)m(to)g(virtual)f(FITS)h(images.)136
+3557 y Fc(\017)46 b Fi(FITS)37 b(\014les)g(on)g(the)h(in)m(ternet)g
+(can)g(b)s(e)f(read)g(\(and)g(sometimes)h(written\))f(using)f(the)i
+(FTP)-8 b(,)38 b(HTTP)-8 b(,)38 b(or)227 3670 y(R)m(OOT)30
+b(proto)s(cols.)136 3849 y Fc(\017)46 b Fi(FITS)30 b(\014les)f(can)i(b)
+s(e)f(pip)s(ed)e(b)s(et)m(w)m(een)j(tasks)f(on)h(the)f(stdin)f(and)h
+(stdout)g(streams.)136 4028 y Fc(\017)46 b Fi(FITS)20
+b(\014les)g(can)h(b)s(e)f(read)g(and)g(written)g(in)f(shared)h(memory)
+-8 b(.)38 b(This)19 b(can)i(p)s(oten)m(tially)e(ac)m(hiev)m(e)j(m)m(uc)
+m(h)f(b)s(etter)227 4141 y(data)26 b(I/O)e(p)s(erformance)g(compared)h
+(to)h(reading)e(and)g(writing)e(the)j(same)h(FITS)e(\014les)f(on)i
+(magnetic)g(disk.)136 4320 y Fc(\017)46 b Fi(Compressed)30
+b(FITS)f(\014les)h(in)f(gzip)h(or)g(Unix)f(COMPRESS)g(format)h(can)h(b)
+s(e)f(directly)f(read.)136 4499 y Fc(\017)46 b Fi(Output)28
+b(FITS)h(\014les)f(can)h(b)s(e)g(written)f(directly)g(in)f(compressed)i
+(gzip)g(format,)h(th)m(us)e(sa)m(ving)h(disk)f(space.)136
+4678 y Fc(\017)46 b Fi(FITS)26 b(table)g(columns)f(can)i(b)s(e)f
+(created,)i(mo)s(di\014ed,)e(or)g(deleted)g('on-the-\015y')h(as)g(the)g
+(table)f(is)f(op)s(ened)h(b)m(y)227 4791 y(CFITSIO.)32
+b(This)g(creates)j(a)e(virtual)f(FITS)h(\014le)f(con)m(taining)h(the)h
+(mo)s(di\014cations)d(that)j(is)f(then)g(op)s(ened)227
+4904 y(b)m(y)e(the)f(application)f(program.)136 5083
+y Fc(\017)46 b Fi(T)-8 b(able)28 b(ro)m(ws)f(ma)m(y)i(b)s(e)e
+(selected,)i(or)f(\014ltered)f(out,)h(on)g(the)g(\015y)f(when)g(the)h
+(table)g(is)f(op)s(ened)g(b)m(y)g(CFITSIO,)227 5196 y(based)f(on)h(an)f
+(arbitrary)g(user-sp)s(eci\014ed)e(expression.)38 b(Only)25
+b(ro)m(ws)i(for)f(whic)m(h)f(the)i(expression)e(ev)-5
+b(aluates)227 5309 y(to)31 b('TR)m(UE')g(are)g(retained)f(in)f(the)h
+(cop)m(y)i(of)e(the)h(table)f(that)h(is)e(op)s(ened)h(b)m(y)g(the)h
+(application)d(program.)136 5488 y Fc(\017)46 b Fi(Histogram)27
+b(images)g(ma)m(y)g(b)s(e)f(created)h(on)f(the)h(\015y)f(b)m(y)g
+(binning)e(the)i(v)-5 b(alues)26 b(in)f(table)i(columns,)f(resulting)
+227 5601 y(in)35 b(a)h(virtual)f(N-dimensional)e(FITS)j(image.)58
+b(The)35 b(application)f(program)i(then)g(only)f(sees)h(the)h(FITS)227
+5714 y(image)31 b(\(in)e(the)i(primary)d(arra)m(y\))k(instead)d(of)i
+(the)f(original)f(FITS)g(table.)1905 5942 y(15)p eop
+%%Page: 16 22
+16 21 bop 0 299 a Fi(16)1618 b Fg(CHAPTER)30 b(4.)112
+b(EXTENDED)30 b(FILE)h(NAME)f(SYNT)-8 b(AX)0 555 y Fi(The)43
+b(latter)h(3)g(features)g(in)e(particular)g(add)h(v)m(ery)h(p)s(o)m(w)m
+(erful)e(data)i(pro)s(cessing)e(capabilities)g(directly)g(in)m(to)0
+668 y(CFITSIO,)29 b(and)g(hence)h(in)m(to)g(ev)m(ery)g(task)h(that)f
+(uses)g(CFITSIO)e(to)j(read)f(or)g(write)f(FITS)g(\014les.)39
+b(F)-8 b(or)31 b(example,)0 781 y(these)d(features)f(transform)f(a)i(v)
+m(ery)f(simple)e(program)i(that)h(just)f(copies)g(an)g(input)e(FITS)h
+(\014le)g(to)i(a)g(new)e(output)0 894 y(\014le)35 b(\(lik)m(e)g(the)h
+(`\014tscop)m(y')h(program)f(that)g(is)f(distributed)e(with)h
+(CFITSIO\))h(in)m(to)h(a)g(m)m(ultipurp)s(ose)d(FITS)i(\014le)0
+1007 y(pro)s(cessing)23 b(to)s(ol.)39 b(By)25 b(app)s(ending)e(fairly)f
+(simple)h(quali\014ers)g(on)m(to)i(the)g(name)g(of)g(the)g(input)e
+(FITS)h(\014le,)h(the)g(user)0 1120 y(can)37 b(p)s(erform)f(quite)h
+(complex)g(table)g(editing)f(op)s(erations)g(\(e.g.,)41
+b(create)e(new)d(columns,)i(or)f(\014lter)g(out)g(ro)m(ws)0
+1233 y(in)f(a)h(table\))g(or)g(create)h(FITS)f(images)g(b)m(y)g
+(binning)c(or)k(histogramming)f(the)h(v)-5 b(alues)36
+b(in)g(table)h(columns.)59 b(In)0 1346 y(addition,)31
+b(these)i(functions)d(ha)m(v)m(e)k(b)s(een)d(co)s(ded)h(using)e(new)i
+(state-of-the)i(art)f(algorithms)e(that)i(are,)g(in)e(some)0
+1458 y(cases,)h(10)f(-)f(100)i(times)e(faster)h(than)f(previous)f
+(widely)f(used)i(implemen)m(tations.)0 1619 y(Before)k(describing)d
+(the)j(complete)g(syn)m(tax)g(for)f(the)h(extended)f(FITS)g(\014le)f
+(names)h(in)f(the)i(next)g(section,)g(here)0 1732 y(are)d(a)g(few)f
+(examples)g(of)g(FITS)g(\014le)f(names)i(that)f(giv)m(e)h(a)g(quic)m(k)
+f(o)m(v)m(erview)h(of)g(the)f(allo)m(w)m(ed)g(syn)m(tax:)136
+1960 y Fc(\017)46 b Fe('myfile.fits')p Fi(:)37 b(the)31
+b(simplest)d(case)k(of)e(a)h(FITS)f(\014le)f(on)i(disk)d(in)i(the)g
+(curren)m(t)g(directory)-8 b(.)136 2137 y Fc(\017)46
+b Fe('myfile.imh')p Fi(:)37 b(op)s(ens)28 b(an)h(IRAF)g(format)g(image)
+h(\014le)e(and)g(con)m(v)m(erts)i(it)f(on)g(the)g(\015y)f(in)m(to)h(a)g
+(temp)s(orary)227 2250 y(FITS)h(format)h(image)f(in)f(memory)i(whic)m
+(h)e(can)h(then)g(b)s(e)g(read)g(with)f(an)m(y)i(other)g(CFITSIO)e
+(routine.)136 2427 y Fc(\017)46 b Fe(rawfile.dat[i512,512])p
+Fi(:)35 b(op)s(ens)30 b(a)g(ra)m(w)h(binary)d(data)j(arra)m(y)g(\(a)g
+(512)g(x)f(512)i(short)e(in)m(teger)g(arra)m(y)h(in)227
+2540 y(this)h(case\))j(and)d(con)m(v)m(erts)j(it)d(on)h(the)g(\015y)g
+(in)m(to)g(a)g(temp)s(orary)g(FITS)f(format)h(image)h(in)d(memory)i
+(whic)m(h)227 2652 y(can)e(then)f(b)s(e)g(read)g(with)f(an)m(y)i(other)
+f(CFITSIO)f(routine.)136 2830 y Fc(\017)46 b Fe(myfile.fits.gz)p
+Fi(:)d(if)32 b(this)g(is)g(the)h(name)g(of)h(a)f(new)g(output)g
+(\014le,)g(the)g('.gz')i(su\016x)d(will)e(cause)k(it)f(to)h(b)s(e)227
+2942 y(compressed)c(in)f(gzip)h(format)h(when)e(it)h(is)g(written)f(to)
+i(disk.)136 3120 y Fc(\017)46 b Fe('myfile.fits.gz[events,)c(2]')p
+Fi(:)59 b(op)s(ens)40 b(and)f(uncompresses)g(the)i(gzipp)s(ed)d(\014le)
+i(m)m(y\014le.\014ts)f(then)227 3232 y(mo)m(v)m(es)34
+b(to)f(the)f(extension)g(whic)m(h)f(has)g(the)i(k)m(eyw)m(ords)f
+(EXTNAME)g(=)g('EVENTS')g(and)g(EXTVER)f(=)227 3345 y(2.)136
+3522 y Fc(\017)46 b Fe('-')p Fi(:)40 b(a)31 b(dash)f(\(min)m(us)f
+(sign\))h(signi\014es)e(that)j(the)g(input)e(\014le)g(is)h(to)h(b)s(e)f
+(read)g(from)g(the)h(stdin)e(\014le)g(stream,)227 3635
+y(or)i(that)g(the)f(output)g(\014le)g(is)f(to)i(b)s(e)f(written)f(to)i
+(the)g(stdout)f(stream.)136 3812 y Fc(\017)46 b Fe
+('ftp://legacy.gsfc.nasa.g)o(ov/t)o(est/)o(vel)o(a.fi)o(ts')p
+Fi(:)33 b(FITS)28 b(\014les)f(in)g(an)m(y)h(ftp)g(arc)m(hiv)m(e)h(site)
+f(on)g(the)227 3925 y(in)m(ternet)i(ma)m(y)h(b)s(e)f(directly)f(op)s
+(ened)h(with)f(read-only)h(access.)136 4102 y Fc(\017)46
+b Fe('http://legacy.gsfc.nasa.)o(gov/)o(soft)o(war)o(e/te)o(st.f)o(its)
+o(')p Fi(:)d(an)m(y)34 b(v)-5 b(alid)33 b(URL)h(to)h(a)f(FITS)g(\014le)
+f(on)227 4215 y(the)e(W)-8 b(eb)31 b(ma)m(y)g(b)s(e)f(op)s(ened)f(with)
+g(read-only)h(access.)136 4392 y Fc(\017)46 b Fe
+('root://legacy.gsfc.nasa.)o(gov/)o(test)o(/ve)o(la.f)o(its')o
+Fi(:)32 b(similar)21 b(to)j(ftp)f(access)i(except)g(that)f(it)f(pro-)
+227 4505 y(vides)29 b(write)h(as)g(w)m(ell)f(as)i(read)f(access)h(to)g
+(the)f(\014les)g(across)g(the)h(net)m(w)m(ork.)41 b(This)28
+b(uses)i(the)h(ro)s(ot)f(proto)s(col)227 4618 y(dev)m(elop)s(ed)g(at)h
+(CERN.)136 4795 y Fc(\017)46 b Fe('shmem://h2[events]')p
+Fi(:)35 b(op)s(ens)30 b(the)g(FITS)f(\014le)h(in)f(a)h(shared)f(memory)
+i(segmen)m(t)g(and)e(mo)m(v)m(es)j(to)f(the)227 4908
+y(EVENTS)f(extension.)136 5085 y Fc(\017)46 b Fe('mem://')p
+Fi(:)52 b(creates)39 b(a)e(scratc)m(h)i(output)d(\014le)h(in)e(core)j
+(computer)f(memory)-8 b(.)62 b(The)37 b(resulting)e('\014le')i(will)227
+5198 y(disapp)s(ear)24 b(when)g(the)i(program)f(exits,)h(so)g(this)e
+(is)h(mainly)e(useful)h(for)h(testing)h(purp)s(oses)d(when)i(one)g(do)s
+(es)227 5311 y(not)31 b(w)m(an)m(t)g(a)g(p)s(ermanen)m(t)f(cop)m(y)h
+(of)f(the)h(output)f(\014le.)136 5488 y Fc(\017)46 b
+Fe('myfile.fits[3;)e(Images\(10\)]')p Fi(:)49 b(op)s(ens)35
+b(a)i(cop)m(y)g(of)f(the)g(image)h(con)m(tained)f(in)f(the)i(10th)f(ro)
+m(w)h(of)227 5601 y(the)26 b('Images')i(column)c(in)h(the)h(binary)f
+(table)g(in)g(the)h(3th)h(extension)e(of)h(the)h(FITS)e(\014le.)38
+b(The)26 b(application)227 5714 y(just)k(sees)h(this)e(single)g(image)i
+(as)f(the)h(primary)d(arra)m(y)-8 b(.)p eop
+%%Page: 17 23
+17 22 bop 0 299 a Fg(4.1.)72 b(O)m(VER)-10 b(VIEW)3086
+b Fi(17)136 555 y Fc(\017)46 b Fe('myfile.fits[1:512:2,)c(1:512:2]')p
+Fi(:)49 b(op)s(ens)35 b(a)h(section)g(of)f(the)h(input)e(image)i
+(ranging)f(from)g(the)227 668 y(1st)26 b(to)g(the)f(512th)h(pixel)e(in)
+f(X)j(and)e(Y,)i(and)e(selects)i(ev)m(ery)f(second)h(pixel)d(in)h(b)s
+(oth)g(dimensions,)g(resulting)227 781 y(in)29 b(a)i(256)h(x)e(256)i
+(pixel)c(image)j(in)e(this)g(case.)136 981 y Fc(\017)46
+b Fe('myfile.fits[EVENTS][col)41 b(Rad)47 b(=)h(sqrt\(X**2)d(+)j
+(Y**2\)]')p Fi(:)38 b(creates)30 b(and)f(op)s(ens)f(a)h(temp)s(orary)
+227 1094 y(\014le)e(on)g(the)g(\015y)g(\(in)f(memory)h(or)g(on)h
+(disk\))e(that)h(is)g(iden)m(tical)f(to)i(m)m(y\014le.\014ts)e(except)i
+(that)g(it)f(will)e(con)m(tain)227 1207 y(a)41 b(new)f(column)f(in)h
+(the)g(EVENTS)g(extension)g(called)g('Rad')h(whose)f(v)-5
+b(alue)40 b(is)f(computed)i(using)e(the)227 1320 y(indicated)29
+b(expresson)h(whic)m(h)f(is)h(a)g(function)f(of)i(the)g(v)-5
+b(alues)29 b(in)g(the)i(X)f(and)g(Y)h(columns.)136 1520
+y Fc(\017)46 b Fe('myfile.fits[EVENTS][PHA)41 b(>)48
+b(5]')p Fi(:)37 b(creates)27 b(and)e(op)s(ens)g(a)h(temp)s(orary)f
+(FITS)g(\014les)f(that)i(is)f(iden)m(ti-)227 1633 y(cal)k(to)h('m)m
+(y\014le.\014ts')e(except)i(that)f(the)g(EVENTS)f(table)h(will)d(only)i
+(con)m(tain)h(the)g(ro)m(ws)g(that)h(ha)m(v)m(e)g(v)-5
+b(alues)227 1746 y(of)28 b(the)g(PHA)f(column)f(greater)j(than)e(5.)40
+b(In)27 b(general,)h(an)m(y)g(arbitrary)e(b)s(o)s(olean)h(expression)f
+(using)g(a)i(C)f(or)227 1859 y(F)-8 b(ortran-lik)m(e)29
+b(syn)m(tax,)g(whic)m(h)e(ma)m(y)i(com)m(bine)f(AND)h(and)f(OR)f(op)s
+(erators,)i(ma)m(y)g(b)s(e)f(used)f(to)i(select)g(ro)m(ws)227
+1972 y(from)h(a)h(table.)136 2172 y Fc(\017)46 b Fe
+('myfile.fits[EVENTS][bin)41 b(\(X,Y\)=1,2048,4]')p Fi(:)46
+b(creates)37 b(a)e(temp)s(orary)g(FITS)f(primary)f(arra)m(y)227
+2285 y(image)c(whic)m(h)f(is)g(computed)g(on)h(the)g(\015y)f(b)m(y)g
+(binning)e(\(i.e,)k(computing)d(the)i(2-dimensional)e(histogram\))227
+2398 y(of)34 b(the)f(v)-5 b(alues)33 b(in)f(the)i(X)g(and)e(Y)i
+(columns)e(of)i(the)f(EVENTS)g(extension.)49 b(In)33
+b(this)f(case)j(the)e(X)h(and)f(Y)227 2511 y(co)s(ordinates)g(range)h
+(from)f(1)h(to)g(2048)h(and)e(the)h(image)f(pixel)f(size)h(is)g(4)g
+(units)f(in)g(b)s(oth)h(dimensions,)f(so)227 2624 y(the)f(resulting)d
+(image)j(is)e(512)j(x)e(512)i(pixels)d(in)g(size.)136
+2824 y Fc(\017)46 b Fi(The)31 b(\014nal)f(example)i(com)m(bines)f(man)m
+(y)g(of)h(these)g(feature)g(in)m(to)f(one)h(complex)f(expression)f
+(\(it)i(is)e(brok)m(en)227 2937 y(in)m(to)h(sev)m(eral)f(lines)f(for)h
+(clarit)m(y\):)323 3206 y Fe('ftp://legacy.gsfc.nasa)o(.gov)o(/dat)o
+(a/s)o(ampl)o(e.fi)o(ts.)o(gz[E)o(VENT)o(S])370 3319
+y([col)47 b(phacorr)f(=)h(pha)g(*)h(1.1)f(-)g(0.3][phacorr)e(>=)i(5.0)g
+(&&)g(phacorr)f(<=)h(14.0])370 3432 y([bin)g(\(X,Y\)=32]')227
+3701 y Fi(In)37 b(this)g(case,)k(CFITSIO)36 b(\(1\))j(copies)f(and)f
+(uncompresses)g(the)h(FITS)f(\014le)g(from)g(the)h(ftp)f(site)h(on)g
+(the)227 3814 y(legacy)f(mac)m(hine,)h(\(2\))f(mo)m(v)m(es)g(to)g(the)g
+('EVENTS')f(extension,)h(\(3\))g(calculates)g(a)f(new)g(column)f
+(called)227 3927 y('phacorr',)30 b(\(4\))f(selects)g(the)g(ro)m(ws)g
+(in)e(the)i(table)g(that)g(ha)m(v)m(e)h(phacorr)e(in)f(the)i(range)g(5)
+g(to)h(14,)g(and)e(\014nally)227 4040 y(\(5\))35 b(bins)c(the)i
+(remaining)e(ro)m(ws)i(on)h(the)f(X)g(and)g(Y)g(column)f(co)s
+(ordinates,)i(using)d(a)j(pixel)d(size)i(=)g(32)h(to)227
+4153 y(create)d(a)f(2D)g(image.)41 b(All)28 b(this)g(pro)s(cessing)g
+(is)h(completely)g(transparen)m(t)g(to)i(the)e(application)f(program,)
+227 4266 y(whic)m(h)h(simply)f(sees)j(the)g(\014nal)e(2-D)i(image)g(in)
+e(the)h(primary)f(arra)m(y)i(of)f(the)h(op)s(ened)f(\014le.)0
+4538 y(The)c(full)f(extended)i(CFITSIO)e(FITS)h(\014le)g(name)h(can)g
+(con)m(tain)g(sev)m(eral)g(di\013eren)m(t)g(comp)s(onen)m(ts)g(dep)s
+(ending)d(on)0 4651 y(the)31 b(con)m(text.)42 b(These)30
+b(comp)s(onen)m(ts)h(are)g(describ)s(ed)d(in)h(the)h(follo)m(wing)f
+(sections:)0 4924 y Fe(When)47 b(creating)e(a)j(new)f(file:)143
+5036 y(filetype://BaseFilename\(t)o(empl)o(ate)o(Name)o(\))0
+5262 y(When)g(opening)e(an)j(existing)d(primary)h(array)g(or)i(image)e
+(HDU:)143 5375 y(filetype://BaseFilename\(o)o(utNa)o(me\))o([HDU)o
+(loca)o(tio)o(n][I)o(mage)o(Sec)o(tion)o(])0 5601 y(When)h(opening)e
+(an)j(existing)d(table)i(HDU:)143 5714 y(filetype://BaseFilename\(o)o
+(utNa)o(me\))o([HDU)o(loca)o(tio)o(n][c)o(olFi)o(lte)o(r][r)o(owFi)o
+(lte)o(r][b)o(inSp)o(ec])p eop
+%%Page: 18 24
+18 23 bop 0 299 a Fi(18)1618 b Fg(CHAPTER)30 b(4.)112
+b(EXTENDED)30 b(FILE)h(NAME)f(SYNT)-8 b(AX)0 555 y Fi(The)41
+b(\014let)m(yp)s(e,)j(BaseFilename,)h(outName,)g(HDUlo)s(cation,)g(and)
+c(ImageSection)h(comp)s(onen)m(ts,)j(if)c(presen)m(t,)0
+668 y(m)m(ust)30 b(b)s(e)g(giv)m(en)h(in)e(that)i(order,)g(but)f(the)g
+(colFilter,)g(ro)m(wFilter,)h(and)e(binSp)s(ec)g(sp)s(eci\014ers)f(ma)m
+(y)k(follo)m(w)d(in)h(an)m(y)0 781 y(order.)39 b(Regardless)28
+b(of)h(the)f(order,)g(ho)m(w)m(ev)m(er,)i(the)f(colFilter)e(sp)s
+(eci\014er,)g(if)g(presen)m(t,)i(will)d(b)s(e)h(pro)s(cessed)h(\014rst)
+f(b)m(y)0 894 y(CFITSIO,)i(follo)m(w)m(ed)h(b)m(y)g(the)h(ro)m(wFilter)
+f(sp)s(eci\014er,)f(and)g(\014nally)g(b)m(y)h(the)g(binSp)s(ec)e(sp)s
+(eci\014er.)0 1221 y Fd(4.2)135 b(Filet)l(yp)t(e)0 1471
+y Fi(The)37 b(t)m(yp)s(e)g(of)g(\014le)f(determines)g(the)h(medium)e
+(on)i(whic)m(h)f(the)h(\014le)f(is)h(lo)s(cated)g(\(e.g.,)j(disk)c(or)h
+(net)m(w)m(ork\))h(and,)0 1584 y(hence,)f(whic)m(h)d(in)m(ternal)g
+(device)h(driv)m(er)f(is)g(used)g(b)m(y)h(CFITSIO)f(to)i(read)f(and/or)
+g(write)f(the)h(\014le.)55 b(Curren)m(tly)0 1697 y(supp)s(orted)29
+b(t)m(yp)s(es)h(are)382 1913 y Fe(file://)93 b(-)48 b(file)e(on)i
+(local)e(magnetic)g(disk)g(\(default\))382 2026 y(ftp://)141
+b(-)48 b(a)f(readonly)f(file)g(accessed)g(with)h(the)g(anonymous)e(FTP)
+i(protocol.)907 2139 y(It)g(also)g(supports)93 b
+(ftp://username:password@)o(host)o(nam)o(e/..)o(.)907
+2252 y(for)47 b(accessing)e(password-protected)e(ftp)k(sites.)382
+2365 y(http://)93 b(-)48 b(a)f(readonly)f(file)g(accessed)g(with)h(the)
+g(HTTP)f(protocol.)93 b(It)907 2478 y(does)46 b(not)95
+b(support)46 b(username:password)d(like)k(the)g(ftp)f(driver.)907
+2591 y(Proxy)g(HTTP)h(servers)f(are)h(supported)e(using)h(the)h
+(http_proxy)907 2704 y(environment)e(variable.)382 2817
+y(root://)93 b(-)48 b(uses)e(the)h(CERN)g(root)g(protocol)e(for)i
+(writing)f(as)h(well)g(as)907 2930 y(reading)f(files)g(over)h(the)g
+(network.)382 3042 y(shmem://)e(-)j(opens)e(or)h(creates)f(a)i(file)e
+(which)h(persists)e(in)i(the)g(computer's)907 3155 y(shared)f(memory.)
+382 3268 y(mem://)141 b(-)48 b(opens)e(a)i(temporary)d(file)i(in)g
+(core)f(memory.)94 b(The)47 b(file)907 3381 y(disappears)e(when)h(the)h
+(program)f(exits)h(so)g(this)f(is)i(mainly)907 3494 y(useful)e(for)h
+(test)f(purposes)g(when)h(a)g(permanent)e(output)h(file)907
+3607 y(is)h(not)g(desired.)0 3824 y Fi(If)35 b(the)h(\014let)m(yp)s(e)f
+(is)f(not)i(sp)s(eci\014ed,)g(then)f(t)m(yp)s(e)h(\014le://)g(is)e
+(assumed.)56 b(The)35 b(double)f(slashes)h('//')i(are)f(optional)0
+3937 y(and)30 b(ma)m(y)h(b)s(e)e(omitted)i(in)e(most)i(cases.)0
+4220 y Fb(4.2.1)112 b(Notes)37 b(ab)s(out)i(HTTP)d(pro)m(xy)i(serv)m
+(ers)0 4439 y Fi(A)32 b(pro)m(xy)g(HTTP)f(serv)m(er)h(ma)m(y)h(b)s(e)e
+(used)g(b)m(y)h(de\014ning)e(the)i(address)f(\(URL\))i(and)e(p)s(ort)g
+(n)m(um)m(b)s(er)g(of)h(the)g(pro)m(xy)0 4552 y(serv)m(er)f(with)e(the)
+h(h)m(ttp)p 801 4552 28 4 v 33 w(pro)m(xy)g(en)m(vironmen)m(t)g(v)-5
+b(ariable.)40 b(F)-8 b(or)31 b(example)191 4769 y Fe(setenv)46
+b(http_proxy)f(http://heasarc.gsfc.nasa)o(.gov)o(:312)o(8)0
+4985 y Fi(will)35 b(cause)j(CFITSIO)f(to)h(use)g(p)s(ort)f(3128)i(on)f
+(the)g(heasarc)g(pro)m(xy)g(serv)m(er)g(whenev)m(er)g(reading)f(a)h
+(FITS)f(\014le)0 5098 y(with)29 b(HTTP)-8 b(.)0 5382
+y Fb(4.2.2)112 b(Notes)37 b(ab)s(out)i(the)e(ro)s(ot)g(\014let)m(yp)s
+(e)0 5601 y Fi(The)20 b(original)g(ro)s(otd)g(serv)m(er)h(can)h(b)s(e)e
+(obtained)g(from:)36 b Fe(ftp://root.cern.ch/root)o(/roo)o(td.t)o(ar.)o
+(gz)15 b Fi(but,)22 b(for)0 5714 y(it)32 b(to)i(w)m(ork)f(correctly)g
+(with)e(CFITSIO)h(one)h(has)f(to)i(use)e(a)i(mo)s(di\014ed)c(v)m
+(ersion)j(whic)m(h)e(supp)s(orts)g(a)i(command)p eop
+%%Page: 19 25
+19 24 bop 0 299 a Fg(4.2.)72 b(FILETYPE)3128 b Fi(19)0
+555 y(to)41 b(return)d(the)j(length)e(of)h(the)g(\014le.)69
+b(This)38 b(mo)s(di\014ed)f(v)m(ersion)j(is)f(a)m(v)-5
+b(ailable)39 b(in)g(ro)s(otd)g(sub)s(directory)f(in)h(the)0
+668 y(CFITSIO)29 b(ftp)h(area)h(at)286 928 y Fe
+(ftp://legacy.gsfc.nasa.gov)o(/so)o(ftwa)o(re/f)o(its)o(io/c)o(/roo)o
+(t/r)o(ootd)o(.tar)o(.gz)o(.)0 1187 y Fi(This)i(small)f(serv)m(er)j(is)
+f(started)g(either)g(b)m(y)h(inetd)e(when)g(a)i(clien)m(t)f(requests)g
+(a)h(connection)g(to)g(a)f(ro)s(otd)h(serv)m(er)0 1300
+y(or)30 b(b)m(y)g(hand)f(\(i.e.)41 b(from)30 b(the)g(command)g(line\).)
+40 b(The)29 b(ro)s(otd)h(serv)m(er)h(w)m(orks)f(with)f(the)h(R)m(OOT)g
+(TNetFile)g(class.)0 1413 y(It)g(allo)m(ws)e(remote)j(access)f(to)h(R)m
+(OOT)e(database)h(\014les)e(in)g(either)h(read)h(or)f(write)g(mo)s(de.)
+40 b(By)30 b(default)e(TNetFile)0 1526 y(assumes)38 b(p)s(ort)g(432)h
+(\(whic)m(h)e(requires)g(ro)s(otd)h(to)h(b)s(e)f(started)h(as)f(ro)s
+(ot\).)65 b(T)-8 b(o)39 b(run)e(ro)s(otd)h(via)g(inetd)f(add)h(the)0
+1639 y(follo)m(wing)29 b(line)g(to)i(/etc/services:)95
+1898 y Fe(rootd)238 b(432/tcp)0 2158 y Fi(and)30 b(to)h
+(/etc/inetd.conf,)h(add)e(the)g(follo)m(wing)f(line:)95
+2417 y Fe(rootd)47 b(stream)f(tcp)h(nowait)f(root)h
+(/user/rdm/root/bin/root)o(d)42 b(rootd)k(-i)0 2677 y
+Fi(F)-8 b(orce)34 b(inetd)d(to)j(reread)e(its)g(conf)g(\014le)g(with)f
+("kill)f(-HUP)j(<pid)e(inetd>".)46 b(Y)-8 b(ou)33 b(can)g(also)f(start)
+h(ro)s(otd)g(b)m(y)f(hand)0 2790 y(running)i(directly)h(under)f(y)m
+(our)j(priv)-5 b(ate)36 b(accoun)m(t)h(\(no)g(ro)s(ot)g(system)f
+(privileges)e(needed\).)59 b(F)-8 b(or)37 b(example)f(to)0
+2903 y(start)f(ro)s(otd)e(listening)f(on)i(p)s(ort)f(5151)j(just)d(t)m
+(yp)s(e:)49 b Fe(rootd)d(-p)h(5151)33 b Fi(Notice:)49
+b(no)34 b(&)f(is)g(needed.)51 b(Ro)s(otd)35 b(will)0
+3016 y(go)c(in)m(to)g(bac)m(kground)f(b)m(y)g(itself.)95
+3275 y Fe(Rootd)47 b(arguments:)191 3388 y(-i)763 b(says)47
+b(we)g(were)f(started)g(by)h(inetd)191 3501 y(-p)g(port#)476
+b(specifies)45 b(a)j(different)d(port)i(to)g(listen)f(on)191
+3614 y(-d)h(level)476 b(level)46 b(of)i(debug)e(info)h(written)e(to)j
+(syslog)1050 3727 y(0)f(=)h(no)f(debug)f(\(default\))1050
+3840 y(1)h(=)h(minimum)1050 3953 y(2)f(=)h(medium)1050
+4066 y(3)f(=)h(maximum)0 4325 y Fi(Ro)s(otd)29 b(can)f(also)g(b)s(e)g
+(con\014gured)g(for)g(anon)m(ymous)g(usage)h(\(lik)m(e)f(anon)m(ymous)g
+(ftp\).)40 b(T)-8 b(o)29 b(setup)f(ro)s(otd)g(to)h(accept)0
+4438 y(anon)m(ymous)h(logins)f(do)i(the)f(follo)m(wing)f(\(while)g(b)s
+(eing)g(logged)i(in)e(as)h(ro)s(ot\):)143 4698 y Fe(-)48
+b(Add)f(the)f(following)g(line)g(to)i(/etc/passwd:)239
+4924 y(rootd:*:71:72:Anonymous)41 b(rootd:/var/spool/rootd:/b)o(in/)o
+(fals)o(e)239 5149 y(where)46 b(you)h(may)g(modify)f(the)h(uid,)f(gid)h
+(\(71,)g(72\))g(and)g(the)g(home)f(directory)239 5262
+y(to)h(suite)f(your)h(system.)143 5488 y(-)h(Add)f(the)f(following)g
+(line)g(to)i(/etc/group:)239 5714 y(rootd:*:72:rootd)p
+eop
+%%Page: 20 26
+20 25 bop 0 299 a Fi(20)1618 b Fg(CHAPTER)30 b(4.)112
+b(EXTENDED)30 b(FILE)h(NAME)f(SYNT)-8 b(AX)239 668 y
+Fe(where)46 b(the)h(gid)g(must)f(match)h(the)g(gid)g(in)g(/etc/passwd.)
+143 894 y(-)h(Create)e(the)h(directories:)239 1120 y(mkdir)f
+(/var/spool/rootd)239 1233 y(mkdir)g(/var/spool/rootd/tmp)239
+1346 y(chmod)g(777)h(/var/spool/rootd/tmp)239 1571 y(Where)f
+(/var/spool/rootd)d(must)k(match)f(the)h(rootd)g(home)f(directory)g(as)
+239 1684 y(specified)f(in)i(the)g(rootd)f(/etc/passwd)f(entry.)143
+1910 y(-)j(To)f(make)f(writeable)g(directories)e(for)j(anonymous)f(do,)
+h(for)f(example:)239 2136 y(mkdir)g(/var/spool/rootd/pub)239
+2249 y(chown)g(rootd:rootd)f(/var/spool/rootd/pub)0 2492
+y Fi(That's)d(all.)74 b(Sev)m(eral)42 b(additional)e(remarks:)64
+b(y)m(ou)42 b(can)g(login)f(to)i(an)f(anon)m(ymous)f(serv)m(er)i
+(either)e(with)g(the)0 2605 y(names)31 b("anon)m(ymous")h(or)f("ro)s
+(otd".)43 b(The)31 b(passw)m(ord)f(should)f(b)s(e)i(of)g(t)m(yp)s(e)g
+(user@host.do.main.)42 b(Only)29 b(the)i(@)0 2718 y(is)d(enforced)g
+(for)h(the)f(time)h(b)s(eing.)38 b(In)28 b(anon)m(ymous)h(mo)s(de)f
+(the)g(top)h(of)g(the)g(\014le)e(tree)j(is)d(set)i(to)h(the)e(ro)s(otd)
+h(home)0 2831 y(directory)-8 b(,)38 b(therefore)f(only)e(\014les)h(b)s
+(elo)m(w)f(the)i(home)f(directory)g(can)g(b)s(e)g(accessed.)60
+b(Anon)m(ymous)36 b(mo)s(de)g(only)0 2944 y(w)m(orks)30
+b(when)g(the)g(serv)m(er)h(is)e(started)i(via)f(inetd.)0
+3232 y Fb(4.2.3)112 b(Notes)37 b(ab)s(out)i(the)e(shmem)g(\014let)m(yp)
+s(e:)0 3451 y Fi(Shared)d(memory)h(\014les)f(are)h(curren)m(tly)f(supp)
+s(orted)f(on)i(most)h(Unix)e(platforms,)h(where)g(the)g(shared)f
+(memory)0 3564 y(segmen)m(ts)d(are)g(managed)g(b)m(y)f(the)g(op)s
+(erating)g(system)h(k)m(ernel)e(and)h(`liv)m(e')g(indep)s(enden)m(tly)d
+(of)k(pro)s(cesses.)40 b(They)0 3677 y(are)34 b(not)g(deleted)g(\(b)m
+(y)g(default\))f(when)g(the)h(pro)s(cess)f(whic)m(h)g(created)i(them)f
+(terminates,)g(although)g(they)g(will)0 3790 y(disapp)s(ear)d(if)h(the)
+i(system)f(is)f(reb)s(o)s(oted.)49 b(Applications)31
+b(can)j(create)h(shared)d(memory)h(\014les)f(in)g(CFITSIO)g(b)m(y)0
+3903 y(calling:)143 4146 y Fe(fit_create_file\(&fitsfile)o(ptr,)41
+b("shmem://h2",)j(&status\);)0 4389 y Fi(where)22 b(the)g(ro)s(ot)h
+(`\014le')f(names)g(are)g(curren)m(tly)g(restricted)g(to)h(b)s(e)e
+('h0',)k('h1',)f('h2',)h('h3',)f(etc.,)i(up)21 b(to)i(a)g(maxim)m(umn)0
+4502 y(n)m(um)m(b)s(er)d(de\014ned)f(b)m(y)i(the)g(the)g(v)-5
+b(alue)21 b(of)g(SHARED)p 1746 4502 28 4 v 33 w(MAXSEG)g(\(equal)g(to)g
+(16)h(b)m(y)f(default\).)37 b(This)19 b(is)h(a)h(protot)m(yp)s(e)0
+4615 y(implemen)m(tation)27 b(of)i(the)g(shared)f(memory)g(in)m
+(terface)h(and)f(a)h(more)g(robust)f(in)m(terface,)i(whic)m(h)d(will)f
+(ha)m(v)m(e)k(few)m(er)0 4728 y(restrictions)f(on)h(the)h(n)m(um)m(b)s
+(er)e(of)i(\014les)e(and)h(on)g(their)f(names,)i(ma)m(y)g(b)s(e)f(dev)m
+(elop)s(ed)f(in)g(the)i(future.)0 4888 y(When)23 b(op)s(ening)g(an)g
+(already)g(existing)g(FITS)g(\014le)g(in)f(shared)h(memory)h(one)g
+(calls)e(the)i(usual)f(CFITSIO)f(routine:)143 5132 y
+Fe(fits_open_file\(&fitsfilep)o(tr,)41 b("shmem://h7",)j(mode,)j
+(&status\))0 5375 y Fi(The)26 b(\014le)g(mo)s(de)h(can)g(b)s(e)f(READ)m
+(WRITE)h(or)g(READONL)-8 b(Y)28 b(just)e(as)h(with)e(disk)h(\014les.)38
+b(More)28 b(than)e(one)h(pro)s(cess)0 5488 y(can)35 b(op)s(erate)g(on)f
+(READONL)-8 b(Y)35 b(mo)s(de)f(\014les)g(at)h(the)f(same)h(time.)53
+b(CFITSIO)33 b(supp)s(orts)f(prop)s(er)h(\014le)h(lo)s(c)m(king)0
+5601 y(\(b)s(oth)27 b(in)g(READONL)-8 b(Y)29 b(and)e(READ)m(WRITE)h(mo)
+s(des\),)h(so)f(calls)f(to)h(\014ts)p 2572 5601 V 33
+w(op)s(en)p 2795 5601 V 32 w(\014le)f(ma)m(y)h(b)s(e)f(lo)s(c)m(k)m(ed)
+i(out)f(un)m(til)0 5714 y(another)j(other)f(pro)s(cess)g(closes)h(the)f
+(\014le.)p eop
+%%Page: 21 27
+21 26 bop 0 299 a Fg(4.3.)72 b(BASE)30 b(FILENAME)2830
+b Fi(21)0 555 y(When)30 b(an)g(application)f(is)g(\014nished)f
+(accessing)j(a)f(FITS)g(\014le)f(in)g(a)i(shared)e(memory)h(segmen)m
+(t,)i(it)e(ma)m(y)h(close)f(it)0 668 y(\(and)k(the)g(\014le)f(will)e
+(remain)h(in)h(the)h(system\))g(with)f(\014ts)p 1955
+668 28 4 v 32 w(close)p 2174 668 V 33 w(\014le,)h(or)g(delete)g(it)g
+(with)e(\014ts)p 3191 668 V 33 w(delete)p 3456 668 V
+33 w(\014le.)50 b(Ph)m(ys-)0 781 y(ical)34 b(deletion)g(is)g(p)s(ostp)s
+(oned)f(un)m(til)h(the)h(last)f(pro)s(cess)h(calls)f
+(\013clos/\013delt.)54 b(\014ts)p 2801 781 V 32 w(delete)p
+3065 781 V 33 w(\014le)34 b(tries)h(to)g(obtain)g(a)0
+894 y(READ)m(WRITE)f(lo)s(c)m(k)f(on)g(the)g(\014le)g(to)h(b)s(e)e
+(deleted,)i(th)m(us)f(it)g(can)g(b)s(e)g(blo)s(c)m(k)m(ed)g(if)f(the)i
+(ob)5 b(ject)34 b(w)m(as)f(not)h(op)s(ened)0 1007 y(in)29
+b(READ)m(WRITE)i(mo)s(de.)0 1167 y(A)i(shared)f(memory)h(managemen)m(t)
+h(utilit)m(y)d(program)i(called)f(`smem',)h(is)f(included)e(with)i(the)
+h(CFITSIO)e(dis-)0 1280 y(tribution.)37 b(It)27 b(can)g(b)s(e)f(built)f
+(b)m(y)i(t)m(yping)f(`mak)m(e)i(smem';)g(then)f(t)m(yp)s(e)g(`smem)f
+(-h')h(to)h(get)g(a)f(list)e(of)i(v)-5 b(alid)25 b(options.)0
+1393 y(Executing)36 b(smem)g(without)f(an)m(y)i(options)f(causes)g(it)g
+(to)h(list)e(all)g(the)i(shared)e(memory)i(segmen)m(ts)g(curren)m(tly)0
+1506 y(residing)31 b(in)h(the)h(system)h(and)e(managed)i(b)m(y)f(the)h
+(shared)e(memory)h(driv)m(er.)48 b(T)-8 b(o)34 b(get)g(a)g(list)e(of)h
+(all)f(the)i(shared)0 1619 y(memory)c(ob)5 b(jects,)32
+b(run)d(the)h(system)h(utilit)m(y)d(program)i(`ip)s(cs)g([-a]'.)0
+1978 y Fd(4.3)135 b(Base)46 b(Filename)0 2233 y Fi(The)31
+b(base)g(\014lename)g(is)f(the)i(name)f(of)h(the)f(\014le)g(optionally)
+e(including)f(the)k(director/sub)s(directory)d(path,)j(and)0
+2346 y(in)d(the)i(case)g(of)g(`ftp',)f(`h)m(ttp',)i(and)d(`ro)s(ot')j
+(\014let)m(yp)s(es,)d(the)i(mac)m(hine)f(iden)m(ti\014er.)39
+b(Examples:)191 2628 y Fe(myfile.fits)191 2741 y(!data.fits)191
+2854 y(/data/myfile.fits)191 2967 y(fits.gsfc.nasa.gov/ftp/s)o(ampl)o
+(eda)o(ta/m)o(yfil)o(e.f)o(its.)o(gz)0 3248 y Fi(When)29
+b(creating)g(a)g(new)f(output)h(\014le)f(on)h(magnetic)g(disk)e(\(of)j
+(t)m(yp)s(e)f(\014le://\))g(if)f(the)h(base)g(\014lename)f(b)s(egins)f
+(with)0 3361 y(an)34 b(exclamation)h(p)s(oin)m(t)e(\(!\))54
+b(then)34 b(an)m(y)g(existing)g(\014le)f(with)g(that)i(same)g(basename)
+g(will)d(b)s(e)h(deleted)h(prior)f(to)0 3474 y(creating)h(the)g(new)g
+(FITS)f(\014le.)50 b(Otherwise)33 b(if)g(the)h(\014le)f(to)h(b)s(e)g
+(created)h(already)e(exists,)i(then)e(CFITSIO)g(will)0
+3587 y(return)g(an)h(error)f(and)g(will)f(not)i(o)m(v)m(erwrite)g(the)g
+(existing)f(\014le.)51 b(Note)35 b(that)g(the)f(exclamation)g(p)s(oin)m
+(t,)g(')10 b(!',)36 b(is)d(a)0 3700 y(sp)s(ecial)26 b(UNIX)i(c)m
+(haracter,)j(so)d(if)e(it)i(is)f(used)g(on)g(the)h(command)g(line)e
+(rather)i(than)f(en)m(tered)h(at)h(a)f(task)h(prompt,)0
+3813 y(it)i(m)m(ust)g(b)s(e)g(preceded)g(b)m(y)h(a)g(bac)m(kslash)f(to)
+h(force)g(the)g(UNIX)g(shell)d(to)j(pass)f(it)h(v)m(erbatim)f(to)h(the)
+g(application)0 3926 y(program.)0 4086 y(If)24 b(the)i(output)e(disk)g
+(\014le)g(name)h(ends)f(with)f(the)i(su\016x)f('.gz',)k(then)d(CFITSIO)
+e(will)f(compress)j(the)g(\014le)f(using)g(the)0 4199
+y(gzip)g(compression)f(algorithm)g(b)s(efore)h(writing)e(it)i(to)h
+(disk.)37 b(This)22 b(can)j(reduce)f(the)g(amoun)m(t)h(of)f(disk)f
+(space)i(used)0 4312 y(b)m(y)34 b(the)h(\014le.)52 b(Note)36
+b(that)f(this)f(feature)h(requires)e(that)i(the)f(uncompressed)g
+(\014le)f(b)s(e)h(constructed)h(in)e(memory)0 4425 y(b)s(efore)d(it)g
+(is)f(compressed)h(and)g(written)g(to)h(disk,)e(so)h(it)g(can)h(fail)e
+(if)g(there)i(is)e(insu\016cien)m(t)g(a)m(v)-5 b(ailable)30
+b(memory)-8 b(.)0 4585 y(An)45 b(input)f(FITS)g(\014le)h(ma)m(y)h(b)s
+(e)f(compressed)g(with)g(the)g(gzip)g(or)h(Unix)e(compress)i
+(algorithms,)i(in)c(whic)m(h)0 4698 y(case)38 b(CFITSIO)e(will)f
+(uncompress)h(the)i(\014le)f(on)g(the)h(\015y)e(in)m(to)i(a)g(temp)s
+(orary)f(\014le)f(\(in)h(memory)g(or)g(on)h(disk\).)0
+4811 y(Compressed)32 b(\014les)h(ma)m(y)h(only)e(b)s(e)h(op)s(ened)f
+(with)g(read-only)h(p)s(ermission.)47 b(When)33 b(sp)s(ecifying)e(the)j
+(name)f(of)h(a)0 4924 y(compressed)h(FITS)g(\014le)g(it)g(is)g(not)h
+(necessary)g(to)g(app)s(end)e(the)i(\014le)f(su\016x)f(\(e.g.,)39
+b(`.gz')e(or)f(`.Z'\).)g(If)f(CFITSIO)0 5036 y(cannot)24
+b(\014nd)e(the)h(input)e(\014le)i(name)g(without)f(the)h(su\016x,)h
+(then)f(it)g(will)e(automatically)i(searc)m(h)h(for)f(a)g(compressed)0
+5149 y(\014le)35 b(with)f(the)i(same)g(ro)s(ot)g(name.)57
+b(In)35 b(the)h(case)h(of)f(reading)f(ftp)g(and)g(h)m(ttp)h(t)m(yp)s(e)
+g(\014les,)g(CFITSIO)f(generally)0 5262 y(lo)s(oks)i(for)h(a)g
+(compressed)g(v)m(ersion)f(of)h(the)g(\014le)f(\014rst,)i(b)s(efore)e
+(trying)g(to)i(op)s(en)e(the)h(uncompressed)e(\014le.)63
+b(By)0 5375 y(default,)36 b(CFITSIO)f(copies)g(\(and)h(uncompressed)e
+(if)h(necessary\))h(the)g(ftp)f(or)h(h)m(ttp)g(FITS)f(\014le)f(in)m(to)
+i(memory)0 5488 y(on)g(the)g(lo)s(cal)f(mac)m(hine)g(b)s(efore)h(op)s
+(ening)e(it.)57 b(This)34 b(will)f(fail)h(if)h(the)h(lo)s(cal)f(mac)m
+(hine)h(do)s(es)f(not)h(ha)m(v)m(e)h(enough)0 5601 y(memory)g(to)h
+(hold)e(the)h(whole)g(FITS)f(\014le,)j(so)e(in)f(this)g(case,)41
+b(the)c(output)g(\014lename)f(sp)s(eci\014er)g(\(see)i(the)g(next)0
+5714 y(section\))31 b(can)g(b)s(e)e(used)h(to)h(further)e(con)m(trol)i
+(ho)m(w)f(CFITSIO)f(reads)h(ftp)g(and)g(h)m(ttp)g(\014les.)p
+eop
+%%Page: 22 28
+22 27 bop 0 299 a Fi(22)1618 b Fg(CHAPTER)30 b(4.)112
+b(EXTENDED)30 b(FILE)h(NAME)f(SYNT)-8 b(AX)0 555 y Fi(If)32
+b(the)h(input)e(\014le)h(is)g(an)h(IRAF)g(image)g(\014le)f(\(*.imh)g
+(\014le\))h(then)f(CFITSIO)f(will)g(automatically)h(con)m(v)m(ert)j(it)
+d(on)0 668 y(the)27 b(\015y)g(in)m(to)g(a)h(virtual)d(FITS)h(image)i(b)
+s(efore)f(it)f(is)g(op)s(ened)h(b)m(y)g(the)g(application)f(program.)39
+b(IRAF)27 b(images)h(can)0 781 y(only)h(b)s(e)h(op)s(ened)g(with)f
+(READONL)-8 b(Y)31 b(\014le)e(access.)0 941 y(Similarly)-8
+b(,)28 b(if)i(the)h(input)e(\014le)i(is)f(a)h(ra)m(w)g(binary)e(data)j
+(arra)m(y)-8 b(,)33 b(then)d(CFITSIO)g(will)e(con)m(v)m(ert)33
+b(it)d(on)h(the)h(\015y)e(in)m(to)0 1054 y(a)38 b(virtual)e(FITS)i
+(image)g(with)e(the)i(basic)g(set)g(of)g(required)e(header)i(k)m(eyw)m
+(ords)g(b)s(efore)g(it)f(is)g(op)s(ened)g(b)m(y)h(the)0
+1167 y(application)29 b(program)i(\(with)f(READONL)-8
+b(Y)31 b(access\).)44 b(In)30 b(this)g(case)i(the)f(data)g(t)m(yp)s(e)g
+(and)g(dimensions)d(of)j(the)0 1280 y(image)c(m)m(ust)g(b)s(e)f(sp)s
+(eci\014ed)f(in)h(square)h(brac)m(k)m(ets)h(follo)m(wing)d(the)i
+(\014lename)f(\(e.g.)41 b(ra)m(w\014le.dat[ib512,512]\).)h(The)0
+1393 y(\014rst)30 b(c)m(haracter)i(\(case)f(insensitiv)m(e\))e
+(de\014nes)h(the)g(datat)m(yp)s(e)h(of)g(the)g(arra)m(y:)239
+1671 y Fe(b)429 b(8-bit)46 b(unsigned)g(byte)239 1784
+y(i)381 b(16-bit)46 b(signed)g(integer)239 1897 y(u)381
+b(16-bit)46 b(unsigned)g(integer)239 2010 y(j)381 b(32-bit)46
+b(signed)g(integer)239 2123 y(r)h(or)g(f)143 b(32-bit)46
+b(floating)g(point)239 2235 y(d)381 b(64-bit)46 b(floating)g(point)0
+2514 y Fi(An)40 b(optional)f(second)h(c)m(haracter)i(sp)s(eci\014es)d
+(the)i(b)m(yte)f(order)g(of)g(the)h(arra)m(y)g(v)-5 b(alues:)59
+b(b)40 b(or)g(B)h(indicates)e(big)0 2626 y(endian)g(\(as)i(in)e(FITS)g
+(\014les)h(and)g(the)g(nativ)m(e)h(format)f(of)h(SUN)f(UNIX)h(w)m
+(orkstations)f(and)g(Mac)i(PCs\))e(and)0 2739 y(l)g(or)h(L)g(indicates)
+e(little)h(endian)g(\(nativ)m(e)h(format)h(of)f(DEC)f(OSF)h(w)m
+(orkstations)g(and)f(IBM)i(PCs\).)72 b(If)40 b(this)0
+2852 y(c)m(haracter)32 b(is)d(omitted)i(then)f(the)g(arra)m(y)h(is)f
+(assumed)f(to)i(ha)m(v)m(e)h(the)f(nativ)m(e)f(b)m(yte)h(order)f(of)h
+(the)f(lo)s(cal)g(mac)m(hine.)0 2965 y(These)f(datat)m(yp)s(e)h(c)m
+(haracters)h(are)e(then)g(follo)m(w)m(ed)g(b)m(y)g(a)h(series)e(of)h
+(one)h(or)f(more)g(in)m(teger)h(v)-5 b(alues)28 b(separated)i(b)m(y)0
+3078 y(commas)h(whic)m(h)f(de\014ne)f(the)i(size)g(of)f(eac)m(h)i
+(dimension)c(of)j(the)g(ra)m(w)f(arra)m(y)-8 b(.)43 b(Arra)m(ys)30
+b(with)g(up)f(to)j(5)f(dimensions)0 3191 y(are)f(curren)m(tly)f(supp)s
+(orted.)38 b(Finally)-8 b(,)29 b(a)h(b)m(yte)g(o\013set)g(to)h(the)e(p)
+s(osition)f(of)i(the)g(\014rst)e(pixel)g(in)h(the)g(data)i(\014le)d(ma)
+m(y)0 3304 y(b)s(e)e(sp)s(eci\014ed)f(b)m(y)i(separating)g(it)f(with)g
+(a)h(':')39 b(from)27 b(the)g(last)f(dimension)f(v)-5
+b(alue.)39 b(If)26 b(omitted,)i(it)e(is)g(assumed)g(that)0
+3417 y(the)35 b(o\013set)h(=)f(0.)54 b(This)34 b(parameter)h(ma)m(y)h
+(b)s(e)e(used)g(to)i(skip)d(o)m(v)m(er)j(an)m(y)g(header)e(information)
+g(in)f(the)i(\014le)f(that)0 3530 y(precedes)c(the)h(binary)e(data.)41
+b(F)-8 b(urther)30 b(examples:)95 3808 y Fe(raw.dat[b10000])521
+b(1-dimensional)45 b(10000)h(pixel)g(byte)h(array)95
+3921 y(raw.dat[rb400,400,12])233 b(3-dimensional)45 b(floating)g(point)
+h(big-endian)f(array)95 4034 y(img.fits[ib512,512:2880])89
+b(reads)47 b(the)g(512)g(x)g(512)g(short)f(integer)g(array)g(in)1336
+4147 y(a)i(FITS)e(file,)h(skipping)e(over)i(the)g(2880)g(byte)f(header)
+0 4425 y Fi(One)25 b(sp)s(ecial)e(case)j(of)f(input)e(\014le)h(is)g
+(where)h(the)g(\014lename)f(=)h(`-')h(\(a)f(dash)g(or)g(min)m(us)e
+(sign\))h(or)h('stdin')f(or)h('stdout',)0 4538 y(whic)m(h)c
+(signi\014es)g(that)j(the)f(input)d(\014le)i(is)g(to)i(b)s(e)e(read)g
+(from)h(the)g(stdin)e(stream,)k(or)e(written)e(to)j(the)f(stdout)g
+(stream)0 4650 y(if)33 b(a)h(new)g(output)f(\014le)g(is)g(b)s(eing)g
+(created.)52 b(In)33 b(the)h(case)h(of)f(reading)g(from)f(stdin,)g
+(CFITSIO)g(\014rst)g(copies)h(the)0 4763 y(whole)g(stream)i(in)m(to)f
+(a)g(temp)s(orary)g(FITS)f(\014le)h(\(in)f(memory)h(or)g(on)g(disk\),)g
+(and)g(subsequen)m(t)f(reading)g(of)i(the)0 4876 y(FITS)c(\014le)g(o)s
+(ccurs)h(in)e(this)h(cop)m(y)-8 b(.)49 b(When)33 b(writing)e(to)i
+(stdout,)h(CFITSIO)d(\014rst)h(constructs)h(the)g(whole)f(\014le)g(in)0
+4989 y(memory)i(\(since)h(random)e(access)j(is)d(required\),)i(then)f
+(\015ushes)f(it)h(out)h(to)g(the)f(stdout)h(stream)g(when)e(the)i
+(\014le)0 5102 y(is)29 b(closed.)41 b(In)29 b(addition,)g(if)g(the)h
+(output)g(\014lename)f(=)h('-.gz')i(or)e('stdout.gz')h(then)f(it)g
+(will)d(b)s(e)j(gzip)f(compressed)0 5215 y(b)s(efore)h(b)s(eing)f
+(written)g(to)i(stdout.)0 5375 y(This)24 b(abilit)m(y)h(to)h(read)g
+(and)f(write)g(on)h(the)g(stdin)f(and)g(stdout)h(steams)g(allo)m(ws)g
+(FITS)f(\014les)g(to)h(b)s(e)g(pip)s(ed)d(b)s(et)m(w)m(een)0
+5488 y(tasks)42 b(in)e(memory)h(rather)g(than)h(ha)m(ving)f(to)h
+(create)h(temp)s(orary)e(in)m(termediate)g(FITS)f(\014les)h(on)g(disk.)
+72 b(F)-8 b(or)0 5601 y(example)27 b(if)e(task1)j(creates)h(an)e
+(output)f(FITS)g(\014le,)h(and)g(task2)g(reads)g(an)g(input)e(FITS)h
+(\014le,)h(the)g(FITS)f(\014le)g(ma)m(y)0 5714 y(b)s(e)k(pip)s(ed)e(b)s
+(et)m(w)m(een)j(the)f(2)h(tasks)g(b)m(y)f(sp)s(ecifying)p
+eop
+%%Page: 23 29
+23 28 bop 0 299 a Fg(4.4.)72 b(OUTPUT)30 b(FILE)g(NAME)h(WHEN)g
+(OPENING)f(AN)h(EXISTING)e(FILE)967 b Fi(23)143 555 y
+Fe(task1)47 b(-)g(|)g(task2)g(-)0 793 y Fi(where)30 b(the)h(v)m
+(ertical)g(bar)g(is)e(the)i(Unix)f(piping)e(sym)m(b)s(ol.)41
+b(This)29 b(assumes)h(that)i(the)f(2)g(tasks)g(read)g(the)g(name)g(of)0
+906 y(the)g(FITS)e(\014le)h(o\013)g(of)h(the)g(command)f(line.)0
+1236 y Fd(4.4)135 b(Output)45 b(File)g(Name)h(when)f(Op)t(ening)g(an)g
+(Existing)h(File)0 1486 y Fi(An)36 b(optional)g(output)g(\014lename)g
+(ma)m(y)i(b)s(e)e(sp)s(eci\014ed)f(in)g(paren)m(theses)i(immediately)e
+(follo)m(wing)g(the)i(base)g(\014le)0 1599 y(name)28
+b(to)h(b)s(e)f(op)s(ened.)39 b(This)27 b(is)g(mainly)f(useful)h(in)g
+(those)h(cases)i(where)d(CFITSIO)g(creates)j(a)e(temp)s(orary)g(cop)m
+(y)0 1712 y(of)i(the)f(input)f(FITS)g(\014le)h(b)s(efore)g(it)g(is)f
+(op)s(ened)h(and)f(passed)h(to)h(the)g(application)e(program.)40
+b(This)27 b(happ)s(ens)h(b)m(y)0 1825 y(default)h(when)h(op)s(ening)f
+(a)h(net)m(w)m(ork)h(FTP)g(or)f(HTTP-t)m(yp)s(e)g(\014le,)g(when)f
+(reading)g(a)i(compressed)f(FITS)g(\014le)f(on)0 1938
+y(a)36 b(lo)s(cal)f(disk,)h(when)f(reading)g(from)h(the)g(stdin)e
+(stream,)k(or)d(when)g(a)i(column)d(\014lter,)j(ro)m(w)f(\014lter,)g
+(or)g(binning)0 2051 y(sp)s(eci\014er)28 b(is)g(included)f(as)j(part)f
+(of)g(the)h(input)e(\014le)g(sp)s(eci\014cation.)39 b(By)30
+b(default)f(this)f(temp)s(orary)h(\014le)f(is)h(created)0
+2164 y(in)g(memory)-8 b(.)41 b(If)29 b(there)h(is)f(not)h(enough)g
+(memory)g(to)h(create)g(the)g(\014le)e(cop)m(y)-8 b(,)31
+b(then)f(CFITSIO)e(will)f(exit)j(with)f(an)0 2277 y(error.)45
+b(In)32 b(these)g(cases)h(one)g(can)f(force)h(a)f(p)s(ermanen)m(t)g
+(\014le)f(to)i(b)s(e)e(created)i(on)f(disk,)f(instead)h(of)g(a)g(temp)s
+(orary)0 2390 y(\014le)37 b(in)f(memory)-8 b(,)40 b(b)m(y)d(supplying)d
+(the)k(name)g(in)e(paren)m(theses)i(immediately)e(follo)m(wing)g(the)h
+(base)h(\014le)f(name.)0 2503 y(The)30 b(output)g(\014lename)f(can)i
+(include)d(the)j(')10 b(!')41 b(clobb)s(er)29 b(\015ag.)0
+2663 y(Th)m(us,)48 b(if)c(the)h(input)e(\014lename)h(to)h(CFITSIO)f
+(is:)69 b Fe(file1.fits.gz\(file2.fit)o(s\))39 b Fi(then)44
+b(CFITSIO)g(will)0 2776 y(uncompress)39 b(`\014le1.\014ts.gz')i(in)m
+(to)f(the)g(lo)s(cal)f(disk)f(\014le)h(`\014le2.\014ts')h(b)s(efore)g
+(op)s(ening)e(it.)69 b(CFITSIO)38 b(do)s(es)i(not)0 2889
+y(automatically)30 b(delete)h(the)f(output)g(\014le,)g(so)h(it)f(will)d
+(still)i(exist)h(after)h(the)f(application)f(program)h(exits.)0
+3049 y(In)35 b(some)i(cases,)h(sev)m(eral)e(di\013eren)m(t)g(temp)s
+(orary)f(FITS)h(\014les)f(will)e(b)s(e)i(created)i(in)e(sequence,)j
+(for)e(instance,)h(if)0 3162 y(one)g(op)s(ens)g(a)g(remote)h(\014le)e
+(using)g(FTP)-8 b(,)37 b(then)g(\014lters)f(ro)m(ws)h(in)f(a)i(binary)d
+(table)i(extension,)i(then)d(create)j(an)0 3275 y(image)e(b)m(y)g
+(binning)d(a)j(pair)f(of)h(columns.)59 b(In)36 b(this)g(case,)k(the)d
+(remote)h(\014le)e(will)e(b)s(e)i(copied)g(to)i(a)f(temp)s(orary)0
+3388 y(lo)s(cal)h(\014le,)i(then)e(a)h(second)f(temp)s(orary)h(\014le)e
+(will)f(b)s(e)i(created)i(con)m(taining)e(the)g(\014ltered)g(ro)m(ws)g
+(of)h(the)g(table,)0 3500 y(and)c(\014nally)e(a)j(third)d(temp)s(orary)
+i(\014le)g(con)m(taining)f(the)i(binned)d(image)i(will)e(b)s(e)i
+(created.)57 b(In)34 b(cases)i(lik)m(e)f(this)0 3613
+y(where)28 b(m)m(ultiple)e(\014les)h(are)i(created,)h(the)e(out\014le)g
+(sp)s(eci\014er)f(will)e(b)s(e)j(in)m(terpreted)g(the)g(name)g(of)h
+(the)f(\014nal)f(\014le)h(as)0 3726 y(describ)s(ed)g(b)s(elo)m(w,)i(in)
+f(descending)g(priorit)m(y:)136 3964 y Fc(\017)46 b Fi(as)29
+b(the)g(name)g(of)g(the)g(\014nal)e(image)i(\014le)f(if)f(an)i(image)g
+(within)d(a)j(single)e(binary)g(table)i(cell)f(is)f(op)s(ened)h(or)h
+(if)227 4077 y(an)i(image)f(is)g(created)h(b)m(y)f(binning)e(a)i(table)
+h(column.)136 4257 y Fc(\017)46 b Fi(as)33 b(the)f(name)h(of)f(the)h
+(\014le)e(con)m(taining)h(the)g(\014ltered)f(table)i(if)e(a)i(column)e
+(\014lter)g(and/or)h(a)h(ro)m(w)f(\014lter)g(are)227
+4370 y(sp)s(eci\014ed.)136 4551 y Fc(\017)46 b Fi(as)31
+b(the)f(name)h(of)f(the)h(lo)s(cal)f(cop)m(y)h(of)f(the)h(remote)g(FTP)
+f(or)h(HTTP)e(\014le.)136 4731 y Fc(\017)46 b Fi(as)31
+b(the)g(name)g(of)g(the)f(uncompressed)g(v)m(ersion)g(of)h(the)f(FITS)g
+(\014le,)g(if)g(a)h(compressed)f(FITS)g(\014le)g(on)h(lo)s(cal)227
+4844 y(disk)e(has)h(b)s(een)g(op)s(ened.)136 5024 y Fc(\017)46
+b Fi(otherwise,)30 b(the)h(output)f(\014lename)f(is)h(ignored.)0
+5262 y(The)f(output)f(\014le)g(sp)s(eci\014er)g(is)g(useful)f(when)h
+(reading)g(FTP)h(or)g(HTTP-t)m(yp)s(e)g(FITS)f(\014les)g(since)g(it)h
+(can)g(b)s(e)g(used)0 5375 y(to)34 b(create)i(a)e(lo)s(cal)f(disk)f
+(cop)m(y)j(of)f(the)g(\014le)e(that)j(can)f(b)s(e)f(reused)g(in)f(the)i
+(future.)50 b(If)33 b(the)h(output)g(\014le)e(name)i(=)0
+5488 y(`*')i(then)f(a)g(lo)s(cal)f(\014le)g(with)g(the)h(same)g(name)g
+(as)g(the)h(net)m(w)m(ork)f(\014le)f(will)f(b)s(e)h(created.)56
+b(Note)36 b(that)f(CFITSIO)0 5601 y(will)27 b(b)s(eha)m(v)m(e)j
+(di\013eren)m(tly)f(dep)s(ending)e(on)j(whether)f(the)h(remote)g
+(\014le)f(is)g(compressed)g(or)h(not)g(as)g(sho)m(wn)f(b)m(y)h(the)0
+5714 y(follo)m(wing)f(examples:)p eop
+%%Page: 24 30
+24 29 bop 0 299 a Fi(24)1618 b Fg(CHAPTER)30 b(4.)112
+b(EXTENDED)30 b(FILE)h(NAME)f(SYNT)-8 b(AX)136 555 y
+Fc(\017)46 b Fi(`ftp://remote.mac)m(hine/tmp/m)m
+(y\014le.\014ts.gz\(*\)')i(-)43 b(the)g(remote)h(compressed)f(\014le)f
+(is)g(copied)h(to)h(the)227 668 y(lo)s(cal)24 b(compressed)g(\014le)f
+(`m)m(y\014le.\014ts.gz',)k(whic)m(h)c(is)g(then)i(uncompressed)e(in)g
+(lo)s(cal)g(memory)h(b)s(efore)g(b)s(eing)227 781 y(op)s(ened)30
+b(and)g(passed)g(to)h(the)f(application)f(program.)136
+979 y Fc(\017)46 b Fi(`ftp://remote.mac)m(hine/tmp/m)m
+(y\014le.\014ts.gz\(m)m(y\014le.\014ts\)')40 b(-)d(the)g(remote)g
+(compressed)f(\014le)g(is)f(copied)227 1092 y(and)i(uncompressed)g(in)m
+(to)g(the)h(lo)s(cal)f(\014le)g(`m)m(y\014le.\014ts'.)63
+b(This)35 b(example)j(requires)e(less)h(lo)s(cal)g(memory)227
+1205 y(than)30 b(the)h(previous)e(example)h(since)g(the)g(\014le)g(is)f
+(uncompressed)g(on)h(disk)f(instead)h(of)g(in)g(memory)-8
+b(.)136 1403 y Fc(\017)46 b Fi(`ftp://remote.mac)m(hine/tmp/m)m
+(y\014le.\014ts\(m)m(y\014le.\014ts.gz\)')25 b(-)c(this)f(will)f
+(usually)g(pro)s(duce)h(an)h(error)g(since)227 1516 y(CFITSIO)29
+b(itself)g(cannot)i(compress)f(\014les.)0 1759 y(The)36
+b(exact)i(b)s(eha)m(vior)d(of)i(CFITSIO)e(in)g(the)i(latter)f(case)i
+(dep)s(ends)c(on)j(the)f(t)m(yp)s(e)h(of)g(ftp)f(serv)m(er)g(running)e
+(on)0 1872 y(the)d(remote)g(mac)m(hine)f(and)g(ho)m(w)g(it)g(is)f
+(con\014gured.)40 b(In)30 b(some)h(cases,)g(if)e(the)i(\014le)e(`m)m
+(y\014le.\014ts.gz')j(exists)e(on)g(the)0 1985 y(remote)38
+b(mac)m(hine,)g(then)f(the)g(serv)m(er)g(will)e(cop)m(y)i(it)g(to)g
+(the)h(lo)s(cal)e(mac)m(hine.)60 b(In)36 b(other)h(cases)h(the)f(ftp)g
+(serv)m(er)0 2098 y(will)c(automatically)j(create)h(and)f(transmit)f(a)
+h(compressed)g(v)m(ersion)f(of)h(the)g(\014le)f(if)g(only)g(the)h
+(uncompressed)0 2211 y(v)m(ersion)26 b(exists.)40 b(This)25
+b(can)i(get)h(rather)f(confusing,)g(so)g(users)f(should)f(use)i(a)g
+(certain)g(amoun)m(t)h(of)f(caution)g(when)0 2324 y(using)33
+b(the)i(output)f(\014le)g(sp)s(eci\014er)f(with)h(FTP)g(or)h(HTTP)f
+(\014le)g(t)m(yp)s(es,)i(to)f(mak)m(e)h(sure)e(they)h(get)h(the)f(b)s
+(eha)m(vior)0 2437 y(that)c(they)g(exp)s(ect.)0 2783
+y Fd(4.5)135 b(T)-11 b(emplate)46 b(File)g(Name)f(when)g(Creating)h(a)g
+(New)f(File)0 3035 y Fi(When)38 b(a)h(new)f(FITS)g(\014le)g(is)g
+(created)h(with)f(a)g(call)g(to)i(\014ts)p 2101 3035
+28 4 v 32 w(create)p 2369 3035 V 35 w(\014le,)f(the)g(name)g(of)g(a)g
+(template)g(\014le)e(ma)m(y)0 3148 y(b)s(e)i(supplied)e(in)i(paren)m
+(theses)h(immediately)e(follo)m(wing)g(the)j(name)f(of)g(the)g(new)f
+(\014le)g(to)i(b)s(e)e(created.)71 b(This)0 3261 y(template)26
+b(is)e(used)h(to)h(de\014ne)f(the)h(structure)f(of)h(one)f(or)h(more)g
+(HDUs)g(in)e(the)i(new)f(\014le.)38 b(The)25 b(template)h(\014le)e(ma)m
+(y)0 3374 y(b)s(e)32 b(another)h(FITS)f(\014le,)h(in)f(whic)m(h)f(case)
+j(the)f(newly)f(created)i(\014le)e(will)e(ha)m(v)m(e)k(exactly)g(the)f
+(same)g(k)m(eyw)m(ords)g(in)0 3487 y(eac)m(h)25 b(HDU)g(as)g(in)e(the)h
+(template)h(FITS)e(\014le,)i(but)e(all)h(the)g(data)h(units)d(will)g(b)
+s(e)i(\014lled)e(with)g(zeros.)40 b(The)24 b(template)0
+3600 y(\014le)h(ma)m(y)i(also)f(b)s(e)f(an)h(ASCI)s(I)e(text)j(\014le,)
+f(where)g(eac)m(h)h(line)d(\(in)h(general\))i(describ)s(es)d(one)i
+(FITS)f(k)m(eyw)m(ord)i(record.)0 3713 y(The)j(format)h(of)f(the)h
+(ASCI)s(I)e(template)h(\014le)g(is)f(describ)s(ed)f(b)s(elo)m(w.)0
+4059 y Fd(4.6)135 b(HDU)46 b(Lo)t(cation)f(Sp)t(eci\014cation)0
+4312 y Fi(The)c(optional)f(HDU)j(lo)s(cation)e(sp)s(eci\014er)e
+(de\014nes)i(whic)m(h)f(HDU)i(\(Header-Data)i(Unit,)g(also)d(kno)m(wn)g
+(as)h(an)0 4425 y(`extension'\))35 b(within)c(the)k(FITS)e(\014le)g(to)
+i(initially)c(op)s(en.)51 b(It)34 b(m)m(ust)g(immediately)f(follo)m(w)g
+(the)h(base)h(\014le)e(name)0 4538 y(\(or)h(the)g(output)g(\014le)f
+(name)g(if)g(presen)m(t\).)52 b(If)33 b(it)g(is)g(not)h(sp)s(eci\014ed)
+f(then)g(the)h(\014rst)f(HDU)i(\(the)f(primary)e(arra)m(y\))0
+4650 y(is)g(op)s(ened.)46 b(The)32 b(HDU)h(lo)s(cation)f(sp)s
+(eci\014er)f(is)h(required)f(if)g(the)i(colFilter,)f(ro)m(wFilter,)h
+(or)g(binSp)s(ec)d(sp)s(eci\014ers)0 4763 y(are)g(presen)m(t,)f(b)s
+(ecause)h(the)f(primary)e(arra)m(y)j(is)e(not)i(a)f(v)-5
+b(alid)28 b(HDU)i(for)f(these)g(op)s(erations.)40 b(The)29
+b(HDU)h(ma)m(y)g(b)s(e)0 4876 y(sp)s(eci\014ed)d(either)i(b)m(y)f
+(absolute)h(p)s(osition)e(n)m(um)m(b)s(er,)h(starting)h(with)e(0)j(for)
+e(the)h(primary)e(arra)m(y)-8 b(,)31 b(or)e(b)m(y)f(reference)0
+4989 y(to)h(the)g(HDU)g(name,)g(and)f(optionally)-8 b(,)28
+b(the)h(v)m(ersion)f(n)m(um)m(b)s(er)f(and)h(the)h(HDU)g(t)m(yp)s(e)g
+(of)f(the)h(desired)e(extension.)0 5102 y(The)32 b(lo)s(cation)f(of)h
+(an)g(image)h(within)c(a)k(single)d(cell)i(of)g(a)g(binary)f(table)h
+(ma)m(y)g(also)g(b)s(e)g(sp)s(eci\014ed,)f(as)h(describ)s(ed)0
+5215 y(b)s(elo)m(w.)0 5375 y(The)26 b(absolute)g(p)s(osition)e(of)i
+(the)h(extension)f(is)f(sp)s(eci\014ed)f(either)i(b)m(y)g(enclosed)g
+(the)h(n)m(um)m(b)s(er)e(in)g(square)g(brac)m(k)m(ets)0
+5488 y(\(e.g.,)k(`[1]')g(=)d(the)h(\014rst)f(extension)g(follo)m(wing)g
+(the)h(primary)d(arra)m(y\))k(or)f(b)m(y)f(preceded)h(the)g(n)m(um)m(b)
+s(er)e(with)h(a)h(plus)0 5601 y(sign)36 b(\(`+1'\).)63
+b(T)-8 b(o)38 b(sp)s(ecify)e(the)h(HDU)h(b)m(y)g(name,)h(giv)m(e)f(the)
+f(name)h(of)f(the)h(desired)e(HDU)i(\(the)f(v)-5 b(alue)37
+b(of)h(the)0 5714 y(EXTNAME)e(or)g(HDUNAME)h(k)m(eyw)m(ord\))g(and)f
+(optionally)e(the)i(extension)g(v)m(ersion)f(n)m(um)m(b)s(er)g(\(v)-5
+b(alue)36 b(of)g(the)p eop
+%%Page: 25 31
+25 30 bop 0 299 a Fg(4.7.)72 b(IMA)m(GE)31 b(SECTION)2835
+b Fi(25)0 555 y(EXTVER)27 b(k)m(eyw)m(ord\))i(and)e(the)h(extension)g
+(t)m(yp)s(e)f(\(v)-5 b(alue)28 b(of)g(the)g(XTENSION)f(k)m(eyw)m(ord:)
+40 b(IMA)m(GE,)29 b(ASCI)s(I)d(or)0 668 y(T)-8 b(ABLE,)36
+b(or)f(BINT)-8 b(ABLE\),)36 b(separated)f(b)m(y)g(commas)h(and)e(all)g
+(enclosed)h(in)f(square)h(brac)m(k)m(ets.)56 b(If)34
+b(the)h(v)-5 b(alue)0 781 y(of)34 b(EXTVER)f(and)f(XTENSION)h(are)h
+(not)f(sp)s(eci\014ed,)g(then)g(the)h(\014rst)e(extension)i(with)e(the)
+h(correct)i(v)-5 b(alue)33 b(of)0 894 y(EXTNAME)39 b(is)f(op)s(ened.)67
+b(The)38 b(extension)h(name)g(and)f(t)m(yp)s(e)i(are)f(not)h(case)g
+(sensitiv)m(e,)h(and)d(the)h(extension)0 1007 y(t)m(yp)s(e)29
+b(ma)m(y)g(b)s(e)f(abbreviated)g(to)h(a)g(single)e(letter)i(\(e.g.,)i
+(I)d(=)g(IMA)m(GE)i(extension)e(or)g(primary)f(arra)m(y)-8
+b(,)30 b(A)f(or)f(T)g(=)0 1120 y(ASCI)s(I)d(table)h(extension,)h(and)f
+(B)h(=)f(binary)f(table)h(BINT)-8 b(ABLE)27 b(extension\).)40
+b(If)26 b(the)g(HDU)h(lo)s(cation)g(sp)s(eci\014er)0
+1233 y(is)i(equal)h(to)h(`[PRIMAR)-8 b(Y]')32 b(or)f(`[P]',)g(then)f
+(the)h(primary)d(arra)m(y)j(\(the)g(\014rst)f(HDU\))h(will)d(b)s(e)i
+(op)s(ened.)0 1393 y(FITS)k(images)h(are)g(most)h(commonly)e(stored)h
+(in)f(the)h(primary)e(arra)m(y)i(or)g(an)g(image)g(extension,)h(but)e
+(images)0 1506 y(can)d(also)g(b)s(e)f(stored)h(as)h(a)f(v)m(ector)h(in)
+e(a)h(single)f(cell)g(of)h(a)h(binary)d(table)i(\(i.e.)42
+b(eac)m(h)32 b(ro)m(w)f(of)g(the)h(v)m(ector)g(column)0
+1619 y(con)m(tains)c(a)h(di\013eren)m(t)e(image\).)41
+b(Suc)m(h)27 b(an)h(image)h(can)f(b)s(e)g(op)s(ened)f(with)g(CFITSIO)f
+(b)m(y)i(sp)s(ecifying)e(the)i(desired)0 1732 y(column)j(name)h(and)f
+(the)h(ro)m(w)g(n)m(um)m(b)s(er)f(after)h(the)g(binary)e(table)i(HDU)h
+(sp)s(eci\014er)d(as)i(sho)m(wn)g(in)e(the)i(follo)m(wing)0
+1844 y(examples.)70 b(The)40 b(column)f(name)i(is)e(separated)i(from)f
+(the)h(HDU)g(sp)s(eci\014er)e(b)m(y)h(a)h(semicolon)e(and)h(the)h(ro)m
+(w)0 1957 y(n)m(um)m(b)s(er)29 b(is)g(enclosed)h(in)e(paren)m(theses.)
+41 b(In)30 b(this)f(case)i(CFITSIO)d(copies)i(the)g(image)h(from)e(the)
+i(table)f(cell)f(in)m(to)0 2070 y(a)j(temp)s(orary)e(primary)g(arra)m
+(y)h(b)s(efore)g(it)g(is)f(op)s(ened.)43 b(The)30 b(application)g
+(program)h(then)g(just)g(sees)g(the)h(image)0 2183 y(in)h(the)i
+(primary)d(arra)m(y)-8 b(,)37 b(without)c(an)m(y)i(extensions.)52
+b(The)34 b(particular)e(ro)m(w)j(to)g(b)s(e)e(op)s(ened)h(ma)m(y)h(b)s
+(e)f(sp)s(eci\014ed)0 2296 y(either)27 b(b)m(y)g(giving)f(an)h
+(absolute)g(in)m(teger)h(ro)m(w)g(n)m(um)m(b)s(er)e(\(starting)h(with)f
+(1)i(for)f(the)g(\014rst)g(ro)m(w\),)i(or)e(b)m(y)g(sp)s(ecifying)0
+2409 y(a)33 b(b)s(o)s(olean)e(expression)g(that)i(ev)-5
+b(aluates)33 b(to)g(TR)m(UE)g(for)f(the)g(desired)f(ro)m(w.)47
+b(The)32 b(\014rst)f(ro)m(w)i(that)g(satis\014es)f(the)0
+2522 y(expression)27 b(will)e(b)s(e)j(used.)39 b(The)28
+b(ro)m(w)g(selection)g(expression)f(has)h(the)g(same)g(syn)m(tax)h(as)f
+(describ)s(ed)e(in)h(the)h(Ro)m(w)0 2635 y(Filter)i(Sp)s(eci\014er)e
+(section,)j(b)s(elo)m(w.)0 2795 y(Examples:)143 3051
+y Fe(myfile.fits[3])44 b(-)k(open)e(the)h(3rd)g(HDU)g(following)e(the)i
+(primary)f(array)143 3164 y(myfile.fits+3)92 b(-)48 b(same)e(as)h
+(above,)f(but)h(using)g(the)g(FTOOLS-style)d(notation)143
+3277 y(myfile.fits[EVENTS])f(-)k(open)g(the)g(extension)e(that)i(has)g
+(EXTNAME)e(=)j('EVENTS')143 3390 y(myfile.fits[EVENTS,)43
+b(2])95 b(-)47 b(same)g(as)g(above,)f(but)h(also)g(requires)e(EXTVER)h
+(=)i(2)143 3503 y(myfile.fits[events,2,b])42 b(-)47 b(same,)f(but)h
+(also)g(requires)f(XTENSION)f(=)j('BINTABLE')143 3616
+y(myfile.fits[3;)c(images\(17\)])h(-)i(opens)g(the)g(image)f(in)h(row)g
+(17)g(of)g(the)g('images')1527 3728 y(column)f(in)i(the)e(3rd)h
+(extension)f(of)h(the)g(file.)143 3841 y(myfile.fits[3;)d
+(images\(exposure)g(>)j(100\)])g(-)g(as)g(above,)f(but)h(opens)g(the)f
+(image)907 3954 y(in)h(the)g(first)f(row)h(that)g(has)g(an)g
+('exposure')e(column)h(value)907 4067 y(greater)g(than)g(100.)0
+4400 y Fd(4.7)135 b(Image)46 b(Section)0 4650 y Fi(A)41
+b(virtual)e(\014le)g(con)m(taining)h(a)h(rectangular)g(subsection)e(of)
+i(an)g(image)f(can)h(b)s(e)f(extracted)i(and)e(op)s(ened)g(b)m(y)0
+4763 y(sp)s(ecifying)30 b(the)j(range)g(of)g(pixels)e(\(start:end\))i
+(along)g(eac)m(h)h(axis)e(to)h(b)s(e)f(extracted)i(from)e(the)h
+(original)d(image.)0 4876 y(One)g(can)h(also)g(sp)s(ecify)e(an)i
+(optional)f(pixel)f(incremen)m(t)h(\(start:end:step\))i(for)f(eac)m(h)h
+(axis)e(of)h(the)g(input)d(image.)0 4989 y(A)g(pixel)d(step)j(=)f(1)h
+(will)d(b)s(e)i(assumed)f(if)h(it)g(is)f(not)i(sp)s(eci\014ed.)38
+b(If)27 b(the)h(start)g(pixel)e(is)g(larger)i(then)f(the)h(end)e
+(pixel,)0 5102 y(then)32 b(the)g(image)g(will)d(b)s(e)i(\015ipp)s(ed)e
+(\(pro)s(ducing)h(a)i(mirror)f(image\))h(along)g(that)g(dimension.)43
+b(An)32 b(asterisk,)g('*',)0 5215 y(ma)m(y)39 b(b)s(e)e(used)h(to)h(sp)
+s(ecify)e(the)h(en)m(tire)g(range)h(of)f(an)h(axis,)h(and)d('-*')j
+(will)35 b(\015ip)i(the)h(en)m(tire)g(axis.)64 b(The)38
+b(input)0 5328 y(image)30 b(can)g(b)s(e)f(in)f(the)i(primary)e(arra)m
+(y)-8 b(,)31 b(in)d(an)h(image)h(extension,)g(or)g(con)m(tained)f(in)g
+(a)h(v)m(ector)h(cell)e(of)h(a)g(binary)0 5441 y(table.)39
+b(In)25 b(the)h(later)g(2)g(cases)h(the)f(extension)g(name)g(or)f(n)m
+(um)m(b)s(er)g(m)m(ust)h(b)s(e)f(sp)s(eci\014ed)f(b)s(efore)i(the)g
+(image)g(section)0 5554 y(sp)s(eci\014er.)0 5714 y(Examples:)p
+eop
+%%Page: 26 32
+26 31 bop 0 299 a Fi(26)1618 b Fg(CHAPTER)30 b(4.)112
+b(EXTENDED)30 b(FILE)h(NAME)f(SYNT)-8 b(AX)95 555 y Fe
+(myfile.fits[1:512:2,)43 b(2:512:2])i(-)95 b(open)47
+b(a)h(256x256)d(pixel)i(image)668 668 y(consisting)e(of)i(the)g(odd)g
+(numbered)f(columns)g(\(1st)g(axis\))h(and)668 781 y(the)g(even)g
+(numbered)e(rows)i(\(2nd)g(axis\))f(of)h(the)g(image)f(in)i(the)668
+894 y(primary)e(array)g(of)i(the)e(file.)95 1120 y(myfile.fits[*,)e
+(512:256])i(-)h(open)g(an)g(image)g(consisting)e(of)i(all)g(the)g
+(columns)668 1233 y(in)g(the)g(input)g(image,)f(but)h(only)f(rows)h
+(256)g(through)f(512.)668 1346 y(The)h(image)f(will)h(be)g(flipped)f
+(along)g(the)h(2nd)g(axis)g(since)668 1458 y(the)g(starting)f(pixel)g
+(is)h(greater)f(than)h(the)g(ending)f(pixel.)95 1684
+y(myfile.fits[*:2,)e(512:256:2])h(-)i(same)g(as)g(above)f(but)h
+(keeping)f(only)668 1797 y(every)h(other)f(row)h(and)g(column)f(in)h
+(the)g(input)f(image.)95 2023 y(myfile.fits[-*,)e(*])j(-)h(copy)e(the)h
+(entire)f(image,)g(flipping)g(it)h(along)668 2136 y(the)g(first)f
+(axis.)95 2362 y(myfile.fits[3][1:256,1:256)o(])c(-)47
+b(opens)g(a)g(subsection)e(of)i(the)g(image)g(that)668
+2475 y(is)g(in)h(the)e(3rd)h(extension)f(of)h(the)g(file.)95
+2700 y(myfile.fits[4;)d(images\(12\)][1:10,1:10])e(-)48
+b(open)e(an)h(image)g(consisting)286 2813 y(of)h(the)e(first)h(10)g
+(pixels)f(in)h(both)g(dimensions.)e(The)i(original)286
+2926 y(image)g(resides)f(in)h(the)g(12th)f(row)h(of)g(the)g('images')f
+(vector)286 3039 y(column)g(in)i(the)f(table)f(in)h(the)g(4th)g
+(extension)e(of)i(the)g(file.)0 3336 y Fi(When)23 b(CFITSIO)f(op)s(ens)
+h(an)g(image)g(section)h(it)f(\014rst)g(creates)h(a)g(temp)s(orary)f
+(\014le)g(con)m(taining)g(the)g(image)h(section)0 3449
+y(plus)31 b(a)j(cop)m(y)g(of)g(an)m(y)g(other)f(HDUs)h(in)e(the)i
+(\014le.)49 b(This)31 b(temp)s(orary)i(\014le)g(is)f(then)h(op)s(ened)g
+(b)m(y)g(the)h(application)0 3562 y(program,)28 b(so)g(it)f(is)f(not)i
+(p)s(ossible)d(to)j(write)f(to)h(or)g(mo)s(dify)e(the)h(input)f(\014le)
+g(when)h(sp)s(ecifying)e(an)j(image)g(section.)0 3675
+y(Note)39 b(that)f(CFITSIO)e(automatically)h(up)s(dates)g(the)g(w)m
+(orld)g(co)s(ordinate)g(system)h(k)m(eyw)m(ords)f(in)f(the)i(header)0
+3788 y(of)33 b(the)h(image)f(section,)h(if)e(they)i(exist,)g(so)f(that)
+h(the)f(co)s(ordinate)g(asso)s(ciated)h(with)e(eac)m(h)i(pixel)d(in)h
+(the)i(image)0 3901 y(section)d(will)c(b)s(e)j(computed)g(correctly)-8
+b(.)0 4279 y Fd(4.8)135 b(Column)45 b(and)g(Keyw)l(ord)h(Filtering)g
+(Sp)t(eci\014cation)0 4538 y Fi(The)27 b(optional)g(column/k)m(eyw)m
+(ord)h(\014ltering)e(sp)s(eci\014er)g(is)h(used)g(to)i(mo)s(dify)d(the)
+i(column)f(structure)g(and/or)h(the)0 4650 y(header)38
+b(k)m(eyw)m(ords)h(in)e(the)i(HDU)g(that)h(w)m(as)f(selected)g(with)e
+(the)i(previous)e(HDU)i(lo)s(cation)f(sp)s(eci\014er.)64
+b(This)0 4763 y(\014ltering)40 b(sp)s(eci\014er)g(m)m(ust)i(b)s(e)f
+(enclosed)h(in)e(square)i(brac)m(k)m(ets)h(and)e(can)h(b)s(e)f
+(distinguished)d(from)k(a)g(general)0 4876 y(ro)m(w)d(\014lter)f(sp)s
+(eci\014er)f(\(describ)s(ed)g(b)s(elo)m(w\))h(b)m(y)h(the)g(fact)h
+(that)f(it)f(b)s(egins)f(with)h(the)h(string)f('col)h(')g(and)f(is)g
+(not)0 4989 y(immediately)27 b(follo)m(w)m(ed)h(b)m(y)g(an)g(equals)g
+(sign.)39 b(The)28 b(original)e(\014le)h(is)h(not)g(c)m(hanged)h(b)m(y)
+f(this)g(\014ltering)e(op)s(eration,)0 5102 y(and)40
+b(instead)g(the)h(mo)s(di\014cations)e(are)i(made)f(on)h(a)g(cop)m(y)g
+(of)g(the)g(input)e(FITS)h(\014le)f(\(usually)g(in)g(memory\),)0
+5215 y(whic)m(h)32 b(also)h(con)m(tains)g(a)g(cop)m(y)h(of)f(all)f(the)
+i(other)f(HDUs)h(in)d(the)i(\014le.)48 b(This)32 b(temp)s(orary)g
+(\014le)g(is)g(passed)h(to)h(the)0 5328 y(application)c(program)i(and)f
+(will)e(p)s(ersist)h(only)h(un)m(til)f(the)i(\014le)f(is)g(closed)h(or)
+g(un)m(til)e(the)i(program)f(exits,)i(unless)0 5441 y(the)e(out\014le)e
+(sp)s(eci\014er)g(\(see)i(ab)s(o)m(v)m(e\))h(is)e(also)g(supplied.)0
+5601 y(The)h(column/k)m(eyw)m(ord)g(\014lter)f(can)h(b)s(e)g(used)f(to)
+i(p)s(erform)e(the)i(follo)m(wing)d(op)s(erations.)43
+b(More)32 b(than)f(one)g(op)s(er-)0 5714 y(ation)f(ma)m(y)h(b)s(e)f(sp)
+s(eci\014ed)f(b)m(y)h(separating)g(them)g(with)g(semi-colons.)p
+eop
+%%Page: 27 33
+27 32 bop 0 299 a Fg(4.8.)72 b(COLUMN)30 b(AND)h(KEYW)m(ORD)g(FIL)-8
+b(TERING)31 b(SPECIFICA)-8 b(TION)1120 b Fi(27)136 555
+y Fc(\017)46 b Fi(Cop)m(y)36 b(only)f(a)h(sp)s(eci\014ed)f(list)f(of)i
+(columns)f(columns)f(to)j(the)f(\014ltered)f(input)f(\014le.)56
+b(The)36 b(list)e(of)i(column)227 668 y(name)c(should)e(b)s(e)i
+(separated)g(b)m(y)g(semi-colons.)46 b(Wild)30 b(card)i(c)m(haracters)i
+(ma)m(y)e(b)s(e)g(used)f(in)g(the)h(column)227 781 y(names)37
+b(to)h(matc)m(h)g(m)m(ultiple)d(columns.)60 b(If)37 b(the)g(expression)
+f(con)m(tains)i(b)s(oth)e(a)i(list)d(of)j(columns)e(to)i(b)s(e)227
+894 y(included)f(and)h(columns)g(to)h(b)s(e)g(deleted,)i(then)d(all)g
+(the)h(columns)f(in)g(the)h(original)e(table)i(except)h(the)227
+1007 y(explicitly)28 b(deleted)i(columns)f(will)e(app)s(ear)j(in)f(the)
+h(\014ltered)f(table)h(\(i.e.,)h(there)f(is)g(no)g(need)f(to)i
+(explicitly)227 1120 y(list)e(the)i(columns)e(to)i(b)s(e)f(included)d
+(if)j(an)m(y)g(columns)f(are)i(b)s(eing)e(deleted\).)136
+1295 y Fc(\017)46 b Fi(Delete)31 b(a)e(column)f(or)h(k)m(eyw)m(ord)h(b)
+m(y)f(listing)e(the)i(name)g(preceded)g(b)m(y)g(a)g(min)m(us)f(sign)g
+(or)h(an)g(exclamation)227 1408 y(mark)c(\(!\),)h(e.g.,)i('-TIME')d
+(will)d(delete)j(the)f(TIME)h(column)e(if)g(it)i(exists,)g(otherwise)f
+(the)h(TIME)f(k)m(eyw)m(ord.)227 1520 y(An)35 b(error)f(is)g(returned)f
+(if)h(neither)f(a)j(column)d(nor)h(k)m(eyw)m(ord)h(with)f(this)f(name)i
+(exists.)53 b(Note)36 b(that)g(the)227 1633 y(exclamation)25
+b(p)s(oin)m(t,)h(')10 b(!',)27 b(is)d(a)h(sp)s(ecial)f(UNIX)h(c)m
+(haracter,)j(so)d(if)f(it)h(is)f(used)g(on)h(the)g(command)g(line)e
+(rather)227 1746 y(than)33 b(en)m(tered)h(at)g(a)g(task)g(prompt,)f(it)
+g(m)m(ust)g(b)s(e)g(preceded)g(b)m(y)g(a)h(bac)m(kslash)f(to)h(force)g
+(the)f(UNIX)h(shell)227 1859 y(to)d(ignore)f(it.)136
+2034 y Fc(\017)46 b Fi(Rename)29 b(an)g(existing)e(column)g(or)i(k)m
+(eyw)m(ord)g(with)e(the)i(syn)m(tax)g('NewName)h(==)e(OldName'.)39
+b(An)28 b(error)227 2147 y(is)i(returned)f(if)g(neither)h(a)g(column)f
+(nor)h(k)m(eyw)m(ord)h(with)e(this)h(name)g(exists.)136
+2322 y Fc(\017)46 b Fi(App)s(end)37 b(a)j(new)f(column)e(or)j(k)m(eyw)m
+(ord)f(to)h(the)f(table.)67 b(T)-8 b(o)40 b(create)g(a)g(column,)g(giv)
+m(e)g(the)f(new)g(name,)227 2435 y(optionally)34 b(follo)m(w)m(ed)h(b)m
+(y)g(the)g(datat)m(yp)s(e)h(in)e(paren)m(theses,)j(follo)m(w)m(ed)e(b)m
+(y)g(a)h(single)e(equals)g(sign)g(and)h(an)227 2548 y(expression)f(to)i
+(b)s(e)e(used)g(to)i(compute)f(the)g(v)-5 b(alue)34 b(\(e.g.,)k('new)m
+(col\(1J\))e(=)f(0')g(will)e(create)j(a)f(new)g(32-bit)227
+2661 y(in)m(teger)j(column)e(called)h('new)m(col')g(\014lled)f(with)g
+(zeros\).)62 b(The)37 b(datat)m(yp)s(e)h(is)f(sp)s(eci\014ed)e(using)h
+(the)i(same)227 2774 y(syn)m(tax)28 b(that)h(is)d(allo)m(w)m(ed)i(for)f
+(the)h(v)-5 b(alue)27 b(of)h(the)g(FITS)f(TF)m(ORMn)g(k)m(eyw)m(ord)h
+(\(e.g.,)i('I',)f('J',)f('E',)g('D',)h(etc.)227 2886
+y(for)37 b(binary)e(tables,)k(and)d('I8',)k(F12.3',)h('E20.12',)g(etc.)
+62 b(for)37 b(ASCI)s(I)e(tables\).)61 b(If)37 b(the)g(datat)m(yp)s(e)h
+(is)e(not)227 2999 y(sp)s(eci\014ed)23 b(then)g(an)h(appropriate)g
+(datat)m(yp)s(e)h(will)c(b)s(e)j(c)m(hosen)g(dep)s(ending)e(on)i(the)g
+(form)g(of)g(the)g(expression)227 3112 y(\(ma)m(y)f(b)s(e)d(a)i(c)m
+(haracter)h(string,)g(logical,)f(bit,)h(long)e(in)m(teger,)j(or)d
+(double)f(column\).)37 b(An)21 b(appropriate)f(v)m(ector)227
+3225 y(coun)m(t)31 b(\(in)f(the)g(case)i(of)e(binary)f(tables\))h(will)
+e(also)i(b)s(e)g(added)g(if)f(not)i(explicitly)d(sp)s(eci\014ed.)227
+3369 y(When)e(creating)g(a)g(new)f(k)m(eyw)m(ord,)j(the)e(k)m(eyw)m
+(ord)g(name)g(m)m(ust)g(b)s(e)f(preceded)g(b)m(y)h(a)g(p)s(ound)e(sign)
+g('#',)k(and)227 3482 y(the)h(expression)e(m)m(ust)h(ev)-5
+b(aluate)29 b(to)g(a)g(scalar)f(\(i.e.,)h(cannot)g(ha)m(v)m(e)h(a)f
+(column)e(name)h(in)f(the)i(expression\).)227 3595 y(The)j(commen)m(t)i
+(string)e(for)g(the)h(k)m(eyw)m(ord)h(ma)m(y)f(b)s(e)f(sp)s(eci\014ed)f
+(in)g(paren)m(theses)i(immediately)e(follo)m(wing)227
+3708 y(the)e(k)m(eyw)m(ord)f(name)g(\(instead)g(of)g(supplying)d(a)j
+(datat)m(yp)s(e)h(as)g(in)d(the)j(case)g(of)f(creating)g(a)h(new)f
+(column\).)136 3883 y Fc(\017)46 b Fi(Recompute)f(\(o)m(v)m(erwrite\))h
+(the)e(v)-5 b(alues)43 b(in)g(an)h(existing)g(column)f(or)h(k)m(eyw)m
+(ord)g(b)m(y)g(giving)g(the)g(name)227 3996 y(follo)m(w)m(ed)30
+b(b)m(y)h(an)f(equals)g(sign)f(and)h(an)g(arithmetic)g(expression.)0
+4217 y(The)23 b(expression)f(that)j(is)d(used)h(when)g(app)s(ending)e
+(or)i(recomputing)g(columns)f(or)i(k)m(eyw)m(ords)g(can)g(b)s(e)f
+(arbitrarily)0 4330 y(complex)35 b(and)h(ma)m(y)g(b)s(e)f(a)h(function)
+f(of)h(other)g(header)g(k)m(eyw)m(ord)g(v)-5 b(alues)35
+b(and)g(other)h(columns)f(\(in)g(the)h(same)0 4443 y(ro)m(w\).)63
+b(The)37 b(full)e(syn)m(tax)k(and)e(a)m(v)-5 b(ailable)37
+b(functions)f(for)h(the)h(expression)e(are)i(describ)s(ed)e(b)s(elo)m
+(w)h(in)f(the)i(ro)m(w)0 4556 y(\014lter)29 b(sp)s(eci\014cation)h
+(section.)0 4716 y(If)d(the)h(expression)f(con)m(tains)g(b)s(oth)g(a)h
+(list)f(of)h(columns)e(to)i(b)s(e)g(included)c(and)k(columns)e(to)i(b)s
+(e)f(deleted,)i(then)e(all)0 4829 y(the)34 b(columns)f(in)g(the)h
+(original)e(table)i(except)h(the)f(explicitly)e(deleted)i(columns)e
+(will)g(app)s(ear)h(in)g(the)h(\014ltered)0 4942 y(table.)0
+5102 y(F)-8 b(or)30 b(complex)g(or)f(commonly)g(used)g(op)s(erations,)h
+(one)f(can)h(also)g(place)g(the)f(op)s(erations)g(in)m(to)h(an)f
+(external)h(text)0 5215 y(\014le)g(and)g(imp)s(ort)f(it)h(in)m(to)h
+(the)g(column)f(\014lter)f(using)h(the)h(syn)m(tax)g('[col)g
+(@\014lename.txt]'.)42 b(The)31 b(op)s(erations)f(can)0
+5328 y(extend)c(o)m(v)m(er)i(m)m(ultiple)c(lines)h(of)h(the)h(\014le,)g
+(but)e(m)m(ultiple)f(op)s(erations)i(m)m(ust)g(still)f(b)s(e)g
+(separated)i(b)m(y)g(semicolons.)0 5441 y(An)m(y)h(lines)f(in)g(the)h
+(external)h(text)g(\014le)e(that)i(b)s(egin)e(with)g(2)i(slash)e(c)m
+(haracters)j(\('//'\))g(will)c(b)s(e)h(ignored)h(and)f(ma)m(y)0
+5554 y(b)s(e)j(used)f(to)i(add)f(commen)m(ts)h(in)m(to)g(the)f(\014le.)
+0 5714 y(Examples:)p eop
+%%Page: 28 34
+28 33 bop 0 299 a Fi(28)1618 b Fg(CHAPTER)30 b(4.)112
+b(EXTENDED)30 b(FILE)h(NAME)f(SYNT)-8 b(AX)143 555 y
+Fe([col)47 b(Time;rate])713 b(-)47 b(only)g(the)g(Time)g(and)g(rate)f
+(columns)g(will)1670 668 y(appear)h(in)g(the)g(filtered)e(input)i
+(file.)143 894 y([col)g(Time;*raw])713 b(-)47 b(include)f(the)h(Time)g
+(column)f(and)h(any)g(other)1670 1007 y(columns)f(whose)h(name)f(ends)h
+(with)g('raw'.)143 1233 y([col)g(-TIME;)f(Good)h(==)g(STATUS])141
+b(-)47 b(deletes)f(the)h(TIME)g(column)f(and)1670 1346
+y(renames)g(the)h(status)f(column)g(to)i('Good')143 1571
+y([col)f(PI=PHA)f(*)h(1.1)g(+)h(0.2])285 b(-)47 b(creates)f(new)h(PI)g
+(column)f(from)h(PHA)g(values)143 1797 y([col)g(rate)f(=)i
+(rate/exposure])139 b(-)48 b(recomputes)d(the)i(rate)f(column)g(by)i
+(dividing)1670 1910 y(it)g(by)f(the)g(EXPOSURE)e(keyword)h(value.)0
+2252 y Fd(4.9)135 b(Ro)l(w)46 b(Filtering)g(Sp)t(eci\014cation)0
+2503 y Fi(When)29 b(en)m(tering)g(the)g(name)g(of)g(a)g(FITS)f(table)h
+(that)h(is)d(to)j(b)s(e)e(op)s(ened)h(b)m(y)f(a)i(program,)f(an)g
+(optional)f(ro)m(w)h(\014lter)0 2616 y(ma)m(y)i(b)s(e)g(sp)s(eci\014ed)
+e(to)i(select)g(a)h(subset)e(of)h(the)g(ro)m(ws)f(in)g(the)h(table.)42
+b(A)31 b(temp)s(orary)f(new)g(FITS)g(\014le)g(is)g(created)0
+2729 y(on)25 b(the)h(\015y)e(whic)m(h)g(con)m(tains)h(only)g(those)h
+(ro)m(ws)f(for)g(whic)m(h)f(the)h(ro)m(w)g(\014lter)g(expression)f(ev)
+-5 b(aluates)25 b(to)h(true.)39 b(\(The)0 2842 y(primary)25
+b(arra)m(y)i(and)f(an)m(y)g(other)h(extensions)f(in)f(the)i(input)e
+(\014le)g(are)i(also)g(copied)f(to)h(the)f(temp)s(orary)h(\014le\).)38
+b(The)0 2955 y(original)27 b(FITS)i(\014le)f(is)g(closed)h(and)f(the)i
+(new)e(virtual)g(\014le)g(is)g(op)s(ened)g(b)m(y)h(the)h(application)d
+(program.)40 b(The)29 b(ro)m(w)0 3068 y(\014lter)36 b(expression)g(is)h
+(enclosed)g(in)f(square)h(brac)m(k)m(ets)i(follo)m(wing)d(the)h(\014le)
+g(name)g(and)g(extension)g(name)g(\(e.g.,)0 3181 y('\014le.\014ts[ev)m
+(en)m(ts][GRADE==50]')28 b(selects)d(only)f(those)i(ro)m(ws)f(where)f
+(the)h(GRADE)h(column)e(v)-5 b(alue)24 b(equals)g(50\).)0
+3294 y(When)33 b(dealing)f(with)g(tables)g(where)h(eac)m(h)h(ro)m(w)f
+(has)g(an)g(asso)s(ciated)h(time)f(and/or)g(2D)g(spatial)g(p)s
+(osition,)f(the)0 3407 y(ro)m(w)g(\014lter)g(expression)e(can)j(also)f
+(b)s(e)g(used)f(to)i(select)g(ro)m(ws)f(based)g(on)g(the)g(times)g(in)f
+(a)h(Go)s(o)s(d)g(Time)f(In)m(terv)-5 b(als)0 3520 y(\(GTI\))31
+b(extension,)f(or)g(on)h(spatial)e(p)s(osition)g(as)h(giv)m(en)h(in)e
+(a)h(SA)m(O-st)m(yle)h(region)f(\014le.)0 3818 y Fb(4.9.1)112
+b(General)38 b(Syn)m(tax)0 4039 y Fi(The)32 b(ro)m(w)h(\014ltering)e
+(expression)h(can)h(b)s(e)f(an)h(arbitrarily)d(complex)i(series)g(of)h
+(op)s(erations)f(p)s(erformed)g(on)g(con-)0 4152 y(stan)m(ts,)39
+b(k)m(eyw)m(ord)e(v)-5 b(alues,)37 b(and)f(column)f(data)j(tak)m(en)f
+(from)f(the)h(sp)s(eci\014ed)d(FITS)i(T)-8 b(ABLE)37
+b(extension.)58 b(The)0 4264 y(expression)36 b(m)m(ust)i(ev)-5
+b(aluate)38 b(to)h(a)f(b)s(o)s(olean)f(v)-5 b(alue)37
+b(for)g(eac)m(h)i(ro)m(w)f(of)g(the)f(table,)j(where)d(a)h(v)-5
+b(alue)38 b(of)f(F)-10 b(ALSE)0 4377 y(means)30 b(that)h(the)g(ro)m(w)f
+(will)e(b)s(e)i(excluded.)0 4538 y(F)-8 b(or)34 b(complex)f(or)h
+(commonly)e(used)h(\014lters,)g(one)h(can)g(place)f(the)h(expression)e
+(in)m(to)h(a)h(text)g(\014le)f(and)g(imp)s(ort)e(it)0
+4650 y(in)m(to)37 b(the)f(ro)m(w)h(\014lter)f(using)f(the)i(syn)m(tax)g
+('[@\014lename.txt]'.)60 b(The)36 b(expression)g(can)g(b)s(e)g
+(arbitrarily)e(complex)0 4763 y(and)27 b(extend)i(o)m(v)m(er)g(m)m
+(ultiple)d(lines)g(of)i(the)h(\014le.)39 b(An)m(y)28
+b(lines)e(in)h(the)h(external)g(text)h(\014le)e(that)i(b)s(egin)e(with)
+g(2)h(slash)0 4876 y(c)m(haracters)k(\('//'\))g(will)c(b)s(e)i(ignored)
+f(and)h(ma)m(y)h(b)s(e)f(used)f(to)i(add)f(commen)m(ts)h(in)m(to)g(the)
+f(\014le.)0 5036 y(Keyw)m(ord)37 b(and)f(column)f(data)j(are)f
+(referenced)g(b)m(y)g(name.)60 b(An)m(y)37 b(string)e(of)i(c)m
+(haracters)i(not)e(surrounded)d(b)m(y)0 5149 y(quotes)41
+b(\(ie,)i(a)e(constan)m(t)h(string\))e(or)g(follo)m(w)m(ed)g(b)m(y)h
+(an)f(op)s(en)g(paren)m(theses)h(\(ie,)i(a)e(function)e(name\))i(will)d
+(b)s(e)0 5262 y(initially)33 b(in)m(terpreted)i(as)i(a)g(column)e(name)
+h(and)g(its)g(con)m(ten)m(ts)i(for)e(the)h(curren)m(t)f(ro)m(w)g
+(inserted)f(in)m(to)i(the)f(ex-)0 5375 y(pression.)j(If)28
+b(no)h(suc)m(h)g(column)f(exists,)h(a)h(k)m(eyw)m(ord)f(of)h(that)f
+(name)g(will)e(b)s(e)h(searc)m(hed)i(for)f(and)f(its)h(v)-5
+b(alue)28 b(used,)0 5488 y(if)35 b(found.)55 b(T)-8 b(o)36
+b(force)g(the)g(name)g(to)h(b)s(e)e(in)m(terpreted)g(as)h(a)g(k)m(eyw)m
+(ord)g(\(in)f(case)h(there)g(is)f(b)s(oth)g(a)h(column)f(and)0
+5601 y(k)m(eyw)m(ord)41 b(with)d(the)j(same)f(name\),)j(precede)d(the)h
+(k)m(eyw)m(ord)f(name)g(with)f(a)i(single)d(p)s(ound)g(sign,)k('#',)h
+(as)d(in)0 5714 y('#NAXIS2'.)g(Due)27 b(to)g(the)f(generalities)g(of)g
+(FITS)g(column)f(and)h(k)m(eyw)m(ord)h(names,)g(if)e(the)i(column)e(or)
+h(k)m(eyw)m(ord)p eop
+%%Page: 29 35
+29 34 bop 0 299 a Fg(4.9.)72 b(R)m(O)m(W)31 b(FIL)-8
+b(TERING)31 b(SPECIFICA)-8 b(TION)2072 b Fi(29)0 555
+y(name)34 b(con)m(tains)g(a)g(space)h(or)e(a)i(c)m(haracter)g(whic)m(h)
+e(migh)m(t)g(app)s(ear)g(as)i(an)e(arithmetic)g(term)h(then)g(inclose)f
+(the)0 668 y(name)d(in)f('$')j(c)m(haracters)g(as)e(in)f($MAX)j(PHA$)f
+(or)f(#$MAX-PHA$.)43 b(Names)31 b(are)f(case)i(insensitiv)m(e.)0
+828 y(T)-8 b(o)32 b(access)g(a)g(table)f(en)m(try)h(in)e(a)i(ro)m(w)f
+(other)h(than)f(the)g(curren)m(t)g(one,)h(follo)m(w)f(the)g(column's)g
+(name)g(with)f(a)i(ro)m(w)0 941 y(o\013set)37 b(within)c(curly)h
+(braces.)57 b(F)-8 b(or)36 b(example,)h('PHA)p Fc(f)p
+Fi(-3)p Fc(g)p Fi(')h(will)33 b(ev)-5 b(aluate)37 b(to)f(the)g(v)-5
+b(alue)35 b(of)h(column)e(PHA,)j(3)0 1054 y(ro)m(ws)28
+b(ab)s(o)m(v)m(e)i(the)e(ro)m(w)h(curren)m(tly)e(b)s(eing)g(pro)s
+(cessed.)40 b(One)28 b(cannot)h(sp)s(ecify)e(an)h(absolute)g(ro)m(w)g
+(n)m(um)m(b)s(er,)g(only)g(a)0 1167 y(relativ)m(e)i(o\013set.)42
+b(Ro)m(ws)31 b(that)g(fall)e(outside)h(the)g(table)g(will)e(b)s(e)i
+(treated)h(as)g(unde\014ned,)d(or)j(NULLs.)0 1327 y(Bo)s(olean)g(op)s
+(erators)g(can)g(b)s(e)f(used)f(in)h(the)g(expression)g(in)f(either)h
+(their)g(F)-8 b(ortran)31 b(or)f(C)h(forms.)40 b(The)30
+b(follo)m(wing)0 1440 y(b)s(o)s(olean)f(op)s(erators)i(are)g(a)m(v)-5
+b(ailable:)191 1666 y Fe("equal")428 b(.eq.)46 b(.EQ.)h(==)95
+b("not)46 b(equal")476 b(.ne.)94 b(.NE.)h(!=)191 1779
+y("less)46 b(than")238 b(.lt.)46 b(.LT.)h(<)143 b("less)46
+b(than/equal")188 b(.le.)94 b(.LE.)h(<=)47 b(=<)191 1892
+y("greater)e(than")95 b(.gt.)46 b(.GT.)h(>)143 b("greater)45
+b(than/equal")g(.ge.)94 b(.GE.)h(>=)47 b(=>)191 2005
+y("or")572 b(.or.)46 b(.OR.)h(||)95 b("and")762 b(.and.)46
+b(.AND.)h(&&)191 2118 y("negation")236 b(.not.)46 b(.NOT.)h(!)95
+b("approx.)45 b(equal\(1e-7\)")92 b(~)0 2344 y Fi(Note)32
+b(that)g(the)f(exclamation)g(p)s(oin)m(t,)f(')10 b(!',)33
+b(is)d(a)h(sp)s(ecial)e(UNIX)j(c)m(haracter,)h(so)e(if)f(it)g(is)g
+(used)g(on)h(the)g(command)0 2457 y(line)g(rather)h(than)h(en)m(tered)g
+(at)g(a)g(task)g(prompt,)g(it)f(m)m(ust)g(b)s(e)g(preceded)h(b)m(y)f(a)
+h(bac)m(kslash)f(to)i(force)f(the)g(UNIX)0 2570 y(shell)c(to)i(ignore)f
+(it.)0 2730 y(The)i(expression)f(ma)m(y)j(also)e(include)e(arithmetic)i
+(op)s(erators)h(and)f(functions.)46 b(T)-8 b(rigonometric)32
+b(functions)f(use)0 2843 y(radians,)22 b(not)h(degrees.)38
+b(The)22 b(follo)m(wing)e(arithmetic)h(op)s(erators)i(and)e(functions)f
+(can)j(b)s(e)e(used)g(in)g(the)h(expression)0 2956 y(\(function)37
+b(names)g(are)h(case)g(insensitiv)m(e\).)61 b(A)37 b(n)m(ull)f(v)-5
+b(alue)37 b(will)d(b)s(e)j(returned)g(in)f(case)i(of)g(illegal)e(op)s
+(erations)0 3069 y(suc)m(h)30 b(as)h(divide)d(b)m(y)i(zero,)i
+(sqrt\(negativ)m(e\))g(log\(negativ)m(e\),)g(log10\(negativ)m(e\),)i
+(arccos\(.gt.)43 b(1\),)32 b(arcsin\(.gt.)41 b(1\).)191
+3295 y Fe("addition")522 b(+)477 b("subtraction")d(-)191
+3408 y("multiplication")234 b(*)477 b("division")618
+b(/)191 3521 y("negation")522 b(-)477 b("exponentiation")330
+b(**)143 b(^)191 3634 y("absolute)45 b(value")237 b(abs\(x\))g
+("cosine")714 b(cos\(x\))191 3747 y("sine")g(sin\(x\))237
+b("tangent")666 b(tan\(x\))191 3860 y("arc)47 b(cosine")427
+b(arccos\(x\))93 b("arc)47 b(sine")619 b(arcsin\(x\))191
+3973 y("arc)47 b(tangent")379 b(arctan\(x\))93 b("arc)47
+b(tangent")475 b(arctan2\(x,y\))191 4085 y("hyperbolic)45
+b(cos")237 b(cosh\(x\))189 b("hyperbolic)45 b(sin")333
+b(sinh\(x\))191 4198 y("hyperbolic)45 b(tan")237 b(tanh\(x\))189
+b("round)46 b(to)h(nearest)f(int")h(round\(x\))191 4311
+y("round)f(down)h(to)g(int")94 b(floor\(x\))141 b("round)46
+b(up)h(to)h(int")285 b(ceil\(x\))191 4424 y("exponential")378
+b(exp\(x\))237 b("square)46 b(root")476 b(sqrt\(x\))191
+4537 y("natural)45 b(log")381 b(log\(x\))237 b("common)46
+b(log")524 b(log10\(x\))191 4650 y("modulus")570 b(i)48
+b(\045)f(j)286 b("random)46 b(#)h([0.0,1.0\)")141 b(random\(\))191
+4763 y("minimum")570 b(min\(x,y\))141 b("maximum")666
+b(max\(x,y\))191 4876 y("cumulative)45 b(sum")189 b(accum\(x\))141
+b("sequential)45 b(difference")g(seqdiff\(x\))191 4989
+y("if-then-else")330 b(b?x:y)0 5215 y Fi(An)31 b(alternate)h(syn)m(tax)
+g(for)f(the)g(min)f(and)h(max)g(functions)f(has)h(only)f(a)i(single)e
+(argumen)m(t)i(whic)m(h)e(should)f(b)s(e)i(a)0 5328 y(v)m(ector)g(v)-5
+b(alue)29 b(\(see)h(b)s(elo)m(w\).)40 b(The)29 b(result)f(will)f(b)s(e)
+h(the)i(minim)m(um/maxim)m(um)c(elemen)m(t)j(con)m(tained)h(within)d
+(the)0 5441 y(v)m(ector.)0 5601 y(The)35 b(accum\(x\))i(function)e
+(forms)g(the)h(cum)m(ulativ)m(e)g(sum)f(of)h(x,)h(elemen)m(t)g(b)m(y)f
+(elemen)m(t.)57 b(V)-8 b(ector)38 b(columns)d(are)0 5714
+y(supp)s(orted)i(simply)f(b)m(y)i(p)s(erforming)e(the)j(summation)f
+(pro)s(cess)g(through)f(all)h(the)h(v)-5 b(alues.)64
+b(Null)37 b(v)-5 b(alues)38 b(are)p eop
+%%Page: 30 36
+30 35 bop 0 299 a Fi(30)1618 b Fg(CHAPTER)30 b(4.)112
+b(EXTENDED)30 b(FILE)h(NAME)f(SYNT)-8 b(AX)0 555 y Fi(treated)30
+b(as)f(0.)41 b(The)29 b(seqdi\013\(x\))g(function)e(forms)i(the)g
+(sequen)m(tial)g(di\013erence)f(of)i(x,)f(elemen)m(t)h(b)m(y)f(elemen)m
+(t.)40 b(The)0 668 y(\014rst)c(v)-5 b(alue)37 b(of)g(seqdi\013)f(is)g
+(the)h(\014rst)g(v)-5 b(alue)36 b(of)h(x.)61 b(A)37 b(single)f(n)m(ull)
+f(v)-5 b(alue)37 b(in)e(x)i(causes)h(a)f(pair)f(of)h(n)m(ulls)e(in)h
+(the)0 781 y(output.)55 b(The)35 b(seqdi\013)f(and)h(accum)g(functions)
+f(are)i(functional)d(in)m(v)m(erses,)k(i.e.,)g(seqdi\013\(accum\(x\)\))
+f(==)f(x)g(as)0 894 y(long)30 b(as)h(no)f(n)m(ull)e(v)-5
+b(alues)30 b(are)h(presen)m(t.)0 1054 y(The)38 b(follo)m(wing)f(t)m(yp)
+s(e)i(casting)g(op)s(erators)g(are)g(a)m(v)-5 b(ailable,)41
+b(where)d(the)h(inclosing)e(paren)m(theses)i(are)g(required)0
+1167 y(and)30 b(tak)m(en)h(from)f(the)h(C)f(language)g(usage.)42
+b(Also,)30 b(the)h(in)m(teger)f(to)i(real)e(casts)h(v)-5
+b(alues)29 b(to)j(double)d(precision:)764 1398 y Fe("real)46
+b(to)h(integer")189 b(\(int\))46 b(x)239 b(\(INT\))46
+b(x)764 1510 y("integer)f(to)i(real")190 b(\(float\))46
+b(i)143 b(\(FLOAT\))45 b(i)0 1741 y Fi(In)30 b(addition,)e(sev)m(eral)j
+(constan)m(ts)h(are)f(built)d(in)h(for)h(use)g(in)f(n)m(umerical)g
+(expressions:)382 1972 y Fe(#pi)667 b(3.1415...)284 b(#e)620
+b(2.7182...)382 2085 y(#deg)f(#pi/180)380 b(#row)524
+b(current)46 b(row)h(number)382 2197 y(#null)428 b(undefined)45
+b(value)142 b(#snull)428 b(undefined)45 b(string)0 2428
+y Fi(A)40 b(string)e(constan)m(t)j(m)m(ust)e(b)s(e)g(enclosed)g(in)g
+(quotes)h(as)f(in)g('Crab'.)67 b(The)39 b("n)m(ull")g(constan)m(ts)h
+(are)g(useful)e(for)0 2541 y(conditionally)d(setting)j(table)g(v)-5
+b(alues)37 b(to)h(a)g(NULL,)g(or)g(unde\014ned,)f(v)-5
+b(alue)38 b(\(eg.,)j("col1==-99)e(?)62 b(#NULL)38 b(:)0
+2654 y(col1"\).)0 2814 y(There)27 b(is)f(also)i(a)f(function)f(for)i
+(testing)f(if)f(t)m(w)m(o)j(v)-5 b(alues)27 b(are)h(close)f(to)i(eac)m
+(h)f(other,)h(i.e.,)f(if)e(they)i(are)g("near")g(eac)m(h)0
+2927 y(other)c(to)h(within)c(a)j(user)g(sp)s(eci\014ed)e(tolerance.)39
+b(The)24 b(argumen)m(ts,)h(v)-5 b(alue)p 2503 2927 28
+4 v 33 w(1)24 b(and)f(v)-5 b(alue)p 2980 2927 V 32 w(2)25
+b(can)f(b)s(e)f(in)m(teger)h(or)g(real)0 3040 y(and)32
+b(represen)m(t)h(the)g(t)m(w)m(o)h(v)-5 b(alues)32 b(who's)g(pro)m
+(ximit)m(y)g(is)g(b)s(eing)f(tested)i(to)h(b)s(e)e(within)e(the)j(sp)s
+(eci\014ed)e(tolerance,)0 3153 y(also)f(an)h(in)m(teger)f(or)h(real:)
+955 3383 y Fe(near\(value_1,)44 b(value_2,)h(tolerance\))0
+3614 y Fi(When)24 b(a)i(NULL,)e(or)h(unde\014ned,)f(v)-5
+b(alue)24 b(is)g(encoun)m(tered)h(in)f(the)g(FITS)g(table,)i(the)f
+(expression)f(will)e(ev)-5 b(aluate)25 b(to)0 3727 y(NULL)31
+b(unless)e(the)i(unde\014ned)e(v)-5 b(alue)30 b(is)g(not)h(actually)f
+(required)f(for)i(ev)-5 b(aluation,)31 b(e.g.)43 b("TR)m(UE)31
+b(.or.)43 b(NULL")0 3840 y(ev)-5 b(aluates)31 b(to)g(TR)m(UE.)g(The)f
+(follo)m(wing)e(t)m(w)m(o)k(functions)d(allo)m(w)h(some)h(NULL)f
+(detection)h(and)f(handling:)430 4070 y Fe("a)47 b(null)f(value?")667
+b(ISNULL\(x\))430 4183 y("define)45 b(a)j(value)e(for)h(null")190
+b(DEFNULL\(x,y\))0 4414 y Fi(The)36 b(former)h(returns)e(a)i(b)s(o)s
+(olean)f(v)-5 b(alue)36 b(of)h(TR)m(UE)g(if)f(the)h(argumen)m(t)g(x)g
+(is)f(NULL.)h(The)f(later)h("de\014nes")g(a)0 4527 y(v)-5
+b(alue)34 b(to)h(b)s(e)e(substituted)g(for)h(NULL)g(v)-5
+b(alues;)36 b(it)e(returns)f(the)h(v)-5 b(alue)34 b(of)g(x)g(if)f(x)i
+(is)e(not)h(NULL,)h(otherwise)e(it)0 4640 y(returns)c(the)i(v)-5
+b(alue)30 b(of)g(y)-8 b(.)0 4926 y Fb(4.9.2)112 b(Bit)36
+b(Masks)0 5145 y Fi(Bit)f(masks)g(can)h(b)s(e)f(used)f(to)i(select)g
+(out)f(ro)m(ws)h(from)e(bit)h(columns)f(\(TF)m(ORMn)h(=)g(#X\))h(in)e
+(FITS)g(\014les.)54 b(T)-8 b(o)0 5257 y(represen)m(t)30
+b(the)h(mask,)g(binary)-8 b(,)29 b(o)s(ctal,)i(and)f(hex)g(formats)g
+(are)h(allo)m(w)m(ed:)811 5488 y Fe(binary:)142 b
+(b0110xx1010000101xxxx00)o(01)811 5601 y(octal:)190 b(o720x1)46
+b(->)h(\(b111010000xxx001\))811 5714 y(hex:)286 b(h0FxD)94
+b(->)47 b(\(b00001111xxxx1101\))p eop
+%%Page: 31 37
+31 36 bop 0 299 a Fg(4.9.)72 b(R)m(O)m(W)31 b(FIL)-8
+b(TERING)31 b(SPECIFICA)-8 b(TION)2072 b Fi(31)0 555
+y(In)22 b(all)g(the)h(represen)m(tations,)i(an)d(x)h(or)g(X)g(is)f
+(allo)m(w)m(ed)h(in)e(the)i(mask)g(as)g(a)h(wild)c(card.)38
+b(Note)25 b(that)e(the)g(x)g(represen)m(ts)0 668 y(a)k(di\013eren)m(t)g
+(n)m(um)m(b)s(er)f(of)h(wild)d(card)j(bits)f(in)g(eac)m(h)i(represen)m
+(tation.)40 b(All)25 b(represen)m(tations)i(are)h(case)g(insensitiv)m
+(e.)0 828 y(T)-8 b(o)28 b(construct)g(the)g(b)s(o)s(olean)e(expression)
+h(using)f(the)i(mask)f(as)h(the)g(b)s(o)s(olean)e(equal)h(op)s(erator)h
+(describ)s(ed)e(ab)s(o)m(v)m(e)0 941 y(on)34 b(a)h(bit)f(table)h
+(column.)52 b(F)-8 b(or)35 b(example,)h(if)d(y)m(ou)i(had)f(a)h(7)g
+(bit)f(column)f(named)h(\015ags)h(in)e(a)i(FITS)f(table)h(and)0
+1054 y(w)m(an)m(ted)c(all)e(ro)m(ws)i(ha)m(ving)f(the)g(bit)g(pattern)g
+(0010011,)k(the)c(selection)h(expression)e(w)m(ould)g(b)s(e:)1336
+1301 y Fe(flags)47 b(==)g(b0010011)191 1414 y(or)1336
+1526 y(flags)g(.eq.)f(b10011)0 1773 y Fi(It)35 b(is)f(also)h(p)s
+(ossible)d(to)k(test)g(if)e(a)h(range)g(of)g(bits)f(is)g(less)g(than,)i
+(less)e(than)h(equal,)h(greater)g(than)e(and)h(greater)0
+1886 y(than)30 b(equal)g(to)h(a)g(particular)e(b)s(o)s(olean)g(v)-5
+b(alue:)1336 2132 y Fe(flags)47 b(<=)g(bxxx010xx)1336
+2245 y(flags)g(.gt.)f(bxxx100xx)1336 2358 y(flags)h(.le.)f(b1xxxxxxx)0
+2605 y Fi(Notice)31 b(the)g(use)f(of)h(the)f(x)g(bit)g(v)-5
+b(alue)30 b(to)h(limit)d(the)i(range)h(of)g(bits)e(b)s(eing)g
+(compared.)0 2765 y(It)j(is)g(not)g(necessary)h(to)g(sp)s(ecify)e(the)i
+(leading)e(\(most)i(signi\014can)m(t\))f(zero)h(\(0\))g(bits)e(in)g
+(the)i(mask,)g(as)g(sho)m(wn)e(in)0 2878 y(the)g(second)f(expression)f
+(ab)s(o)m(v)m(e.)0 3038 y(Bit)43 b(wise)f(AND,)i(OR)e(and)g(NOT)h(op)s
+(erations)f(are)h(also)g(p)s(ossible)d(on)j(t)m(w)m(o)h(or)f(more)g
+(bit)f(\014elds)f(using)h(the)0 3151 y('&'\(AND\),)35
+b(')p Fc(j)p Fi('\(OR\),)g(and)e(the)h(')10 b(!'\(NOT\))34
+b(op)s(erators.)51 b(All)32 b(of)h(these)h(op)s(erators)g(result)e(in)h
+(a)h(bit)e(\014eld)g(whic)m(h)0 3264 y(can)f(then)f(b)s(e)f(used)h
+(with)f(the)i(equal)f(op)s(erator.)41 b(F)-8 b(or)31
+b(example:)1241 3510 y Fe(\(!flags\))45 b(==)j(b1101100)1241
+3623 y(\(flags)e(&)h(b1000001\))f(==)h(bx000001)0 3870
+y Fi(Bit)34 b(\014elds)f(can)h(b)s(e)f(app)s(ended)g(as)h(w)m(ell)f
+(using)g(the)h('+')g(op)s(erator.)53 b(Strings)32 b(can)j(b)s(e)e
+(concatenated)j(this)d(w)m(a)m(y)-8 b(,)0 3983 y(to)s(o.)0
+4271 y Fb(4.9.3)112 b(V)-9 b(ector)36 b(Columns)0 4490
+y Fi(V)-8 b(ector)37 b(columns)d(can)i(also)f(b)s(e)g(used)f(in)g
+(building)e(the)j(expression.)55 b(No)36 b(sp)s(ecial)e(syn)m(tax)h(is)
+g(required)e(if)i(one)0 4603 y(w)m(an)m(ts)46 b(to)f(op)s(erate)h(on)f
+(all)f(elemen)m(ts)h(of)g(the)h(v)m(ector.)86 b(Simply)42
+b(use)j(the)g(column)f(name)h(as)g(for)g(a)g(scalar)0
+4716 y(column.)c(V)-8 b(ector)32 b(columns)e(can)h(b)s(e)f(freely)g(in)
+m(termixed)g(with)f(scalar)i(columns)e(or)i(constan)m(ts)h(in)e
+(virtually)e(all)0 4829 y(expressions.)39 b(The)29 b(result)f(will)e(b)
+s(e)j(of)g(the)g(same)h(dimension)c(as)k(the)f(v)m(ector.)42
+b(Tw)m(o)29 b(v)m(ectors)i(in)d(an)h(expression,)0 4942
+y(though,)f(need)e(to)i(ha)m(v)m(e)g(the)f(same)g(n)m(um)m(b)s(er)f(of)
+h(elemen)m(ts)g(and)f(ha)m(v)m(e)j(the)e(same)g(dimensions.)37
+b(The)26 b(only)g(places)0 5055 y(a)35 b(v)m(ector)h(column)d(cannot)i
+(b)s(e)f(used)f(\(for)i(no)m(w,)g(an)m(yw)m(a)m(y\))h(are)f(the)g(SA)m
+(O)f(region)g(functions)f(and)g(the)i(NEAR)0 5168 y(b)s(o)s(olean)29
+b(function.)0 5328 y(Arithmetic)22 b(and)g(logical)h(op)s(erations)f
+(are)i(all)e(p)s(erformed)f(on)i(an)g(elemen)m(t)g(b)m(y)g(elemen)m(t)h
+(basis.)37 b(Comparing)22 b(t)m(w)m(o)0 5441 y(v)m(ector)32
+b(columns,)d(eg)i("COL1)f(==)g(COL2",)g(th)m(us)g(results)f(in)g
+(another)h(v)m(ector)i(of)e(b)s(o)s(olean)g(v)-5 b(alues)29
+b(indicating)0 5554 y(whic)m(h)g(elemen)m(ts)i(of)f(the)h(t)m(w)m(o)h
+(v)m(ectors)f(are)g(equal.)0 5714 y(Eigh)m(t)f(functions)f(are)i(a)m(v)
+-5 b(ailable)30 b(that)h(op)s(erate)g(on)f(a)h(v)m(ector)h(and)d
+(return)h(a)g(scalar)h(result:)p eop
+%%Page: 32 38
+32 37 bop 0 299 a Fi(32)1618 b Fg(CHAPTER)30 b(4.)112
+b(EXTENDED)30 b(FILE)h(NAME)f(SYNT)-8 b(AX)191 555 y
+Fe("minimum")284 b(MIN\(V\))475 b("maximum")714 b(MAX\(V\))191
+668 y("average")284 b(AVERAGE\(V\))f("median")762 b(MEDIAN\(V\))191
+781 y("sumation")236 b(SUM\(V\))475 b("standard)46 b(deviation")188
+b(STDDEV\(V\))191 894 y("#)47 b(of)g(values")94 b(NELEM\(V\))379
+b("#)48 b(of)f(non-null)e(values")94 b(NVALID\(V\))0
+1217 y Fi(where)40 b(V)h(represen)m(ts)g(the)g(name)g(of)h(a)f(v)m
+(ector)h(column)e(or)h(a)h(man)m(ually)d(constructed)i(v)m(ector)i
+(using)c(curly)0 1330 y(brac)m(k)m(ets)27 b(as)f(describ)s(ed)d(b)s
+(elo)m(w.)38 b(The)25 b(\014rst)g(6)h(of)g(these)g(functions)e(ignore)h
+(an)m(y)h(n)m(ull)d(v)-5 b(alues)25 b(in)f(the)i(v)m(ector)h(when)0
+1443 y(computing)i(the)i(result.)0 1603 y(The)h(SUM)h(function)e
+(literally)g(sums)g(all)h(the)h(elemen)m(ts)g(in)f(x,)h(returning)e(a)i
+(scalar)g(v)-5 b(alue.)47 b(If)32 b(x)h(is)f(a)h(b)s(o)s(olean)0
+1716 y(v)m(ector,)40 b(SUM)c(returns)f(the)h(n)m(um)m(b)s(er)f(of)i(TR)
+m(UE)f(elemen)m(ts.)59 b(The)36 b(NELEM)g(function)f(returns)g(the)h(n)
+m(um)m(b)s(er)0 1829 y(of)i(elemen)m(ts)g(in)f(v)m(ector)i(x)f(whereas)
+f(NV)-10 b(ALID)39 b(return)d(the)i(n)m(um)m(b)s(er)f(of)h(non-n)m(ull)
+d(elemen)m(ts)k(in)d(the)i(v)m(ector.)0 1942 y(\(NELEM)28
+b(also)g(op)s(erates)g(on)g(bit)e(and)h(string)g(columns,)g(returning)f
+(their)h(column)f(widths.\))39 b(As)27 b(an)h(example,)0
+2055 y(to)42 b(test)g(whether)f(all)f(elemen)m(ts)i(of)g(t)m(w)m(o)g(v)
+m(ectors)h(satisfy)e(a)h(giv)m(en)f(logical)g(comparison,)i(one)f(can)g
+(use)f(the)0 2168 y(expression)668 2492 y Fe(SUM\()47
+b(COL1)f(>)i(COL2)f(\))g(==)g(NELEM\()f(COL1)h(\))0 2815
+y Fi(whic)m(h)31 b(will)e(return)i(TR)m(UE)h(if)f(all)g(elemen)m(ts)h
+(of)g(COL1)g(are)g(greater)h(than)f(their)f(corresp)s(onding)f(elemen)m
+(ts)i(in)0 2928 y(COL2.)0 3088 y(T)-8 b(o)32 b(sp)s(ecify)e(a)j(single)
+d(elemen)m(t)i(of)g(a)g(v)m(ector,)i(giv)m(e)e(the)g(column)e(name)i
+(follo)m(w)m(ed)f(b)m(y)h(a)g(comma-separated)h(list)0
+3201 y(of)c(co)s(ordinates)f(enclosed)h(in)e(square)i(brac)m(k)m(ets.)
+41 b(F)-8 b(or)30 b(example,)f(if)e(a)i(v)m(ector)i(column)c(named)i
+(PHAS)f(exists)g(in)0 3314 y(the)f(table)f(as)h(a)g(one)g(dimensional,)
+e(256)j(comp)s(onen)m(t)f(list)e(of)i(n)m(um)m(b)s(ers)e(from)h(whic)m
+(h)g(y)m(ou)h(w)m(an)m(ted)g(to)g(select)h(the)0 3427
+y(57th)k(comp)s(onen)m(t)g(for)f(use)g(in)f(the)i(expression,)e(then)i
+(PHAS[57])g(w)m(ould)e(do)i(the)f(tric)m(k.)44 b(Higher)31
+b(dimensional)0 3540 y(arra)m(ys)41 b(of)h(data)f(ma)m(y)h(app)s(ear)f
+(in)e(a)j(column.)72 b(But)41 b(in)f(order)g(to)i(in)m(terpret)e(them,)
+k(the)e(TDIMn)e(k)m(eyw)m(ord)0 3653 y(m)m(ust)34 b(app)s(ear)g(in)f
+(the)h(header.)52 b(Assuming)33 b(that)i(a)f(\(4,4,4,4\))k(arra)m(y)c
+(is)g(pac)m(k)m(ed)h(in)m(to)f(eac)m(h)i(ro)m(w)e(of)g(a)h(column)0
+3766 y(named)26 b(ARRA)-8 b(Y4D,)28 b(the)f(\(1,2,3,4\))i(comp)s(onen)m
+(t)e(elemen)m(t)f(of)h(eac)m(h)g(ro)m(w)g(is)e(accessed)j(b)m(y)e(ARRA)
+-8 b(Y4D[1,2,3,4].)0 3878 y(Arra)m(ys)33 b(up)e(to)j(dimension)c(5)j
+(are)f(curren)m(tly)g(supp)s(orted.)46 b(Eac)m(h)33 b(v)m(ector)h
+(index)d(can)i(itself)e(b)s(e)h(an)h(expression,)0 3991
+y(although)38 b(it)g(m)m(ust)h(ev)-5 b(aluate)39 b(to)g(an)g(in)m
+(teger)g(v)-5 b(alue)38 b(within)e(the)j(b)s(ounds)d(of)j(the)g(v)m
+(ector.)67 b(V)-8 b(ector)40 b(columns)0 4104 y(whic)m(h)30
+b(con)m(tain)h(spaces)h(or)f(arithmetic)f(op)s(erators)i(m)m(ust)f(ha)m
+(v)m(e)h(their)e(names)h(enclosed)g(in)f("$")i(c)m(haracters)h(as)0
+4217 y(with)c($ARRA)-8 b(Y-4D$[1,2,3,4].)0 4377 y(A)45
+b(more)f(C-lik)m(e)g(syn)m(tax)i(for)e(sp)s(ecifying)e(v)m(ector)47
+b(indices)42 b(is)i(also)h(a)m(v)-5 b(ailable.)82 b(The)45
+b(elemen)m(t)g(used)e(in)h(the)0 4490 y(preceding)27
+b(example)h(alternativ)m(ely)g(could)f(b)s(e)h(sp)s(eci\014ed)f(with)f
+(the)j(syn)m(tax)g(ARRA)-8 b(Y4D[4][3][2][1].)45 b(Note)30
+b(the)0 4603 y(rev)m(erse)40 b(order)f(of)h(indices)d(\(as)j(in)e(C\),)
+i(as)f(w)m(ell)g(as)g(the)h(fact)g(that)g(the)g(v)-5
+b(alues)39 b(are)g(still)f(ones-based)h(\(as)h(in)0 4716
+y(F)-8 b(ortran)39 b({)g(adopted)g(to)g(a)m(v)m(oid)g(am)m(biguit)m(y)f
+(for)h(1D)g(v)m(ectors\).)67 b(With)38 b(this)g(syn)m(tax,)j(one)e(do)s
+(es)f(not)h(need)f(to)0 4829 y(sp)s(ecify)29 b(all)g(of)i(the)f
+(indices.)39 b(T)-8 b(o)31 b(extract)h(a)f(3D)g(slice)e(of)i(this)e(4D)
+i(arra)m(y)-8 b(,)32 b(use)e(ARRA)-8 b(Y4D[4].)0 4989
+y(V)g(ariable-length)30 b(v)m(ector)i(columns)d(are)h(not)h(supp)s
+(orted.)0 5149 y(V)-8 b(ectors)24 b(can)e(b)s(e)f(man)m(ually)f
+(constructed)j(within)c(the)j(expression)f(using)f(a)i(comma-separated)
+i(list)d(of)h(elemen)m(ts)0 5262 y(surrounded)35 b(b)m(y)j(curly)f
+(braces)i(\(')p Fc(fg)p Fi('\).)66 b(F)-8 b(or)38 b(example,)i(')p
+Fc(f)p Fi(1,3,6,1)p Fc(g)p Fi(')i(is)c(a)g(4-elemen)m(t)h(v)m(ector)h
+(con)m(taining)e(the)0 5375 y(v)-5 b(alues)25 b(1,)i(3,)g(6,)g(and)e
+(1.)40 b(The)25 b(v)m(ector)i(can)f(con)m(tain)g(only)f(b)s(o)s(olean,)
+g(in)m(teger,)j(and)d(real)g(v)-5 b(alues)25 b(\(or)h(expressions\).)0
+5488 y(The)e(elemen)m(ts)g(will)e(b)s(e)i(promoted)g(to)h(the)g
+(highest)e(datat)m(yp)s(e)i(presen)m(t.)39 b(An)m(y)24
+b(elemen)m(ts)h(whic)m(h)e(are)i(themselv)m(es)0 5601
+y(v)m(ectors,)40 b(will)34 b(b)s(e)i(expanded)g(out)h(with)f(eac)m(h)h
+(of)g(its)f(elemen)m(ts)i(b)s(ecoming)d(an)i(elemen)m(t)g(in)f(the)h
+(constructed)0 5714 y(v)m(ector.)p eop
+%%Page: 33 39
+33 38 bop 0 299 a Fg(4.9.)72 b(R)m(O)m(W)31 b(FIL)-8
+b(TERING)31 b(SPECIFICA)-8 b(TION)2072 b Fi(33)0 555
+y Fb(4.9.4)112 b(Go)s(o)s(d)38 b(Time)e(In)m(terv)-6
+b(al)37 b(Filtering)0 774 y Fi(A)44 b(common)g(\014ltering)f(metho)s(d)
+g(in)m(v)m(olv)m(es)h(selecting)g(ro)m(ws)g(whic)m(h)e(ha)m(v)m(e)k(a)e
+(time)g(v)-5 b(alue)43 b(whic)m(h)g(lies)f(within)0 887
+y(what)37 b(is)f(called)h(a)h(Go)s(o)s(d)f(Time)f(In)m(terv)-5
+b(al)37 b(or)g(GTI.)g(The)g(time)g(in)m(terv)-5 b(als)36
+b(are)i(de\014ned)e(in)g(a)h(separate)i(FITS)0 1000 y(table)h
+(extension)g(whic)m(h)e(con)m(tains)i(2)h(columns)e(giving)f(the)j
+(start)f(and)g(stop)g(time)f(of)h(eac)m(h)i(go)s(o)s(d)e(in)m(terv)-5
+b(al.)0 1113 y(The)34 b(\014ltering)f(op)s(eration)i(accepts)h(only)d
+(those)j(ro)m(ws)e(of)h(the)g(input)e(table)i(whic)m(h)e(ha)m(v)m(e)j
+(an)f(asso)s(ciated)g(time)0 1226 y(whic)m(h)f(falls)h(within)e(one)j
+(of)g(the)g(time)f(in)m(terv)-5 b(als)35 b(de\014ned)g(in)f(the)i(GTI)g
+(extension.)56 b(A)36 b(high)f(lev)m(el)g(function,)0
+1339 y(gti\014lter\(a,b,c,d\),)42 b(is)d(a)m(v)-5 b(ailable)39
+b(whic)m(h)f(ev)-5 b(aluates)40 b(eac)m(h)h(ro)m(w)e(of)h(the)f(input)f
+(table)h(and)g(returns)f(TR)m(UE)i(or)0 1452 y(F)-10
+b(ALSE)30 b(dep)s(ending)e(whether)i(the)g(ro)m(w)h(is)e(inside)f(or)i
+(outside)g(the)h(go)s(o)s(d)f(time)g(in)m(terv)-5 b(al.)40
+b(The)30 b(syn)m(tax)h(is)286 1696 y Fe(gtifilter\()45
+b([)j("gtifile")d([,)i(expr)g([,)g("STARTCOL",)e("STOPCOL")g(])j(])f(])
+g(\))0 1941 y Fi(where)20 b(eac)m(h)h("[]")h(demarks)e(optional)f
+(parameters.)38 b(Note)21 b(that)g(the)g(quotes)f(around)g(the)g
+(gti\014le)g(and)f(ST)-8 b(AR)g(T/STOP)0 2054 y(column)32
+b(are)i(required.)49 b(Either)33 b(single)f(or)i(double)e(quotes)i(ma)m
+(y)g(b)s(e)f(used.)50 b(In)33 b(cases)h(where)g(this)e(expression)0
+2167 y(is)d(en)m(tered)h(on)g(the)g(Unix)f(command)h(line,)e(enclose)i
+(the)g(en)m(tire)g(expression)f(in)f(double)h(quotes,)h(and)g(then)f
+(use)0 2280 y(single)23 b(quotes)i(within)c(the)k(expression)e(to)i
+(enclose)f(the)h('gti\014le')f(and)f(other)i(terms.)38
+b(It)25 b(is)e(also)h(usually)e(p)s(ossible)0 2393 y(to)38
+b(do)e(the)h(rev)m(erse,)j(and)c(enclose)h(the)g(whole)f(expression)g
+(in)f(single)h(quotes)h(and)f(then)h(use)f(double)f(quotes)0
+2506 y(within)c(the)i(expression.)49 b(The)33 b(gti\014le,)g(if)g(sp)s
+(eci\014ed,)f(can)i(b)s(e)f(blank)f(\(""\))j(whic)m(h)d(will)e(mean)k
+(to)g(use)f(the)h(\014rst)0 2619 y(extension)f(with)g(the)g(name)h
+("*GTI*")h(in)e(the)g(curren)m(t)h(\014le,)g(a)g(plain)d(extension)i
+(sp)s(eci\014er)f(\(eg,)k("+2",)g("[2]",)0 2731 y(or)30
+b("[STDGTI]"\))i(whic)m(h)d(will)f(b)s(e)i(used)f(to)j(select)f(an)f
+(extension)g(in)f(the)i(curren)m(t)f(\014le,)g(or)g(a)h(regular)f
+(\014lename)0 2844 y(with)f(or)i(without)e(an)i(extension)f(sp)s
+(eci\014er)f(whic)m(h)g(in)g(the)i(latter)g(case)g(will)d(mean)i(to)i
+(use)e(the)h(\014rst)e(extension)0 2957 y(with)36 b(an)h(extension)f
+(name)i("*GTI*".)62 b(Expr)36 b(can)h(b)s(e)g(an)m(y)g(arithmetic)g
+(expression,)g(including)d(simply)h(the)0 3070 y(time)g(column)g(name.)
+57 b(A)36 b(v)m(ector)h(time)f(expression)e(will)f(pro)s(duce)i(a)h(v)m
+(ector)h(b)s(o)s(olean)e(result.)56 b(ST)-8 b(AR)g(TCOL)0
+3183 y(and)27 b(STOPCOL)f(are)i(the)g(names)g(of)g(the)g(ST)-8
+b(AR)g(T/STOP)26 b(columns)h(in)f(the)i(GTI)g(extension.)40
+b(If)27 b(one)h(of)g(them)0 3296 y(is)h(sp)s(eci\014ed,)g(they)i(b)s
+(oth)f(m)m(ust)g(b)s(e.)0 3456 y(In)21 b(its)g(simplest)f(form,)k(no)d
+(parameters)h(need)g(to)h(b)s(e)e(pro)m(vided)f({)i(default)f(v)-5
+b(alues)21 b(will)f(b)s(e)h(used.)37 b(The)21 b(expression)0
+3569 y("gti\014lter\(\)")31 b(is)f(equiv)-5 b(alen)m(t)29
+b(to)334 3814 y Fe(gtifilter\()45 b("",)i(TIME,)f("*START*",)f
+("*STOP*")h(\))0 4059 y Fi(This)30 b(will)e(searc)m(h)k(the)g(curren)m
+(t)f(\014le)f(for)h(a)h(GTI)f(extension,)g(\014lter)g(the)g(TIME)g
+(column)f(in)g(the)i(curren)m(t)f(table,)0 4172 y(using)i(ST)-8
+b(AR)g(T/STOP)34 b(times)h(tak)m(en)g(from)g(columns)e(in)h(the)h(GTI)g
+(extension)f(with)g(names)g(con)m(taining)h(the)0 4284
+y(strings)c("ST)-8 b(AR)g(T")33 b(and)e("STOP".)46 b(The)32
+b(wildcards)d(\('*'\))34 b(allo)m(w)e(sligh)m(t)f(v)-5
+b(ariations)31 b(in)g(naming)g(con)m(v)m(en)m(tions)0
+4397 y(suc)m(h)38 b(as)g("TST)-8 b(AR)g(T")39 b(or)f("ST)-8
+b(AR)g(TTIME".)65 b(The)37 b(same)i(default)f(v)-5 b(alues)37
+b(apply)g(for)h(unsp)s(eci\014ed)e(parame-)0 4510 y(ters)g(when)f(the)h
+(\014rst)f(one)i(or)f(t)m(w)m(o)h(parameters)f(are)h(sp)s(eci\014ed.)55
+b(The)36 b(function)e(automatically)i(searc)m(hes)h(for)0
+4623 y(TIMEZER)m(O/I/F)g(k)m(eyw)m(ords)f(in)f(the)i(curren)m(t)f(and)g
+(GTI)g(extensions,)h(applying)e(a)h(relativ)m(e)h(time)f(o\013set,)j
+(if)0 4736 y(necessary)-8 b(.)0 5024 y Fb(4.9.5)112 b(Spatial)37
+b(Region)g(Filtering)0 5243 y Fi(Another)h(common)g(\014ltering)e
+(metho)s(d)h(selects)h(ro)m(ws)g(based)g(on)f(whether)h(the)g(spatial)f
+(p)s(osition)e(asso)s(ciated)0 5356 y(with)c(eac)m(h)j(ro)m(w)e(is)g
+(lo)s(cated)h(within)d(a)j(giv)m(en)f(2-dimensional)e(region.)47
+b(The)32 b(syn)m(tax)h(for)f(this)g(high-lev)m(el)f(\014lter)0
+5469 y(is)334 5714 y Fe(regfilter\()45 b("regfilename")f([)k(,)f
+(Xexpr,)f(Yexpr)h([)g(,)h("wcs)e(cols")h(])g(])g(\))p
+eop
+%%Page: 34 40
+34 39 bop 0 299 a Fi(34)1618 b Fg(CHAPTER)30 b(4.)112
+b(EXTENDED)30 b(FILE)h(NAME)f(SYNT)-8 b(AX)0 555 y Fi(where)22
+b(eac)m(h)i("[]")g(demarks)e(optional)g(parameters.)38
+b(The)22 b(region)g(\014le)g(name)g(is)g(required)f(and)h(m)m(ust)g(b)s
+(e)g(enclosed)0 668 y(in)38 b(quotes.)70 b(The)39 b(remaining)f
+(parameters)i(are)g(optional.)68 b(The)39 b(region)g(\014le)g(is)g(an)g
+(ASCI)s(I)g(text)h(\014le)f(whic)m(h)0 781 y(con)m(tains)30
+b(a)f(list)f(of)i(one)f(or)h(more)f(geometric)i(shap)s(es)d(\(circle,)i
+(ellipse,)d(b)s(o)m(x,)j(etc.\))42 b(whic)m(h)28 b(de\014nes)g(a)i
+(region)f(on)0 894 y(the)i(celestial)f(sphere)g(or)h(an)g(area)g
+(within)d(a)j(particular)f(2D)h(image.)42 b(The)30 b(region)h(\014le)f
+(is)f(t)m(ypically)h(generated)0 1007 y(using)21 b(an)i(image)g(displa)
+m(y)e(program)i(suc)m(h)f(as)h(fv/PO)m(W)h(\(distribute)c(b)m(y)j(the)g
+(HEASAR)m(C\),)g(or)g(ds9)g(\(distributed)0 1120 y(b)m(y)k(the)g
+(Smithsonian)d(Astroph)m(ysical)i(Observ)-5 b(atory\).)39
+b(Users)27 b(should)e(refer)h(to)i(the)f(do)s(cumen)m(tation)f(pro)m
+(vided)0 1233 y(with)j(these)i(programs)f(for)g(more)h(details)e(on)h
+(the)h(syn)m(tax)g(used)e(in)g(the)i(region)f(\014les.)0
+1393 y(In)44 b(its)g(simpliest)e(form,)47 b(\(e.g.,)j
+(reg\014lter\("region.reg"\))c(\))f(the)g(co)s(ordinates)f(in)f(the)i
+(default)e('X')i(and)f('Y')0 1506 y(columns)32 b(will)e(b)s(e)i(used)g
+(to)i(determine)e(if)f(eac)m(h)j(ro)m(w)f(is)f(inside)f(or)i(outside)f
+(the)h(area)h(sp)s(eci\014ed)d(in)g(the)i(region)0 1619
+y(\014le.)40 b(Alternate)31 b(p)s(osition)d(column)h(names,)i(or)f
+(expressions,)f(ma)m(y)i(b)s(e)f(en)m(tered)h(if)e(needed,)i(as)f(in)
+382 1867 y Fe(regfilter\("region.reg",)41 b(XPOS,)47
+b(YPOS\))0 2116 y Fi(Region)36 b(\014ltering)e(can)i(b)s(e)f(applied)e
+(most)j(unam)m(biguously)d(if)i(the)h(p)s(ositions)e(in)g(the)i(region)
+f(\014le)g(and)g(in)g(the)0 2229 y(table)g(to)h(b)s(e)e(\014ltered)g
+(are)i(b)s(oth)e(giv)m(e)i(in)e(terms)h(of)g(absolute)g(celestial)g(co)
+s(ordinate)g(units.)53 b(In)35 b(this)f(case)i(the)0
+2342 y(lo)s(cations)24 b(and)f(sizes)h(of)h(the)f(geometric)h(shap)s
+(es)f(in)f(the)h(region)g(\014le)f(are)i(sp)s(eci\014ed)e(in)g(angular)
+g(units)g(on)h(the)g(sky)0 2455 y(\(e.g.,)32 b(p)s(ositions)c(giv)m(en)
+j(in)e(R.A.)h(and)g(Dec.)42 b(and)30 b(sizes)g(in)f(arcseconds)h(or)h
+(arcmin)m(utes\).)40 b(Similarly)-8 b(,)27 b(eac)m(h)32
+b(ro)m(w)0 2568 y(of)h(the)h(\014ltered)e(table)h(will)d(ha)m(v)m(e)35
+b(a)e(celestial)g(co)s(ordinate)g(asso)s(ciated)g(with)f(it.)49
+b(This)31 b(asso)s(ciation)i(is)f(usually)0 2681 y(implemen)m(ted)37
+b(using)f(a)j(set)g(of)f(so-called)g('W)-8 b(orld)38
+b(Co)s(ordinate)g(System')g(\(or)h(W)m(CS\))f(FITS)g(k)m(eyw)m(ords)g
+(that)0 2794 y(de\014ne)27 b(the)g(co)s(ordinate)g(transformation)g
+(that)h(m)m(ust)f(b)s(e)f(applied)f(to)j(the)g(v)-5 b(alues)26
+b(in)g(the)i('X')g(and)e('Y')i(columns)0 2906 y(to)j(calculate)g(the)f
+(co)s(ordinate.)0 3067 y(Alternativ)m(ely)-8 b(,)27 b(one)g(can)g(p)s
+(erform)e(spatial)h(\014ltering)e(using)h(unitless)g('pixel')g(co)s
+(ordinates)i(for)f(the)h(regions)f(and)0 3180 y(ro)m(w)33
+b(p)s(ositions.)47 b(In)33 b(this)f(case)i(the)f(user)g(m)m(ust)g(b)s
+(e)f(careful)g(to)i(ensure)f(that)g(the)h(p)s(ositions)d(in)h(the)h(2)g
+(\014les)g(are)0 3292 y(self-consisten)m(t.)52 b(A)34
+b(t)m(ypical)g(problem)e(is)h(that)i(the)f(region)g(\014le)f(ma)m(y)i
+(b)s(e)e(generated)j(using)c(a)j(binned)c(image,)0 3405
+y(but)h(the)h(un)m(binned)d(co)s(ordinates)i(are)h(giv)m(en)g(in)e(the)
+i(ev)m(en)m(t)i(table.)47 b(The)32 b(R)m(OSA)-8 b(T)33
+b(ev)m(en)m(ts)h(\014les,)f(for)f(example,)0 3518 y(ha)m(v)m(e)f(X)f
+(and)f(Y)g(pixel)f(co)s(ordinates)h(that)i(range)f(from)f(1)h(-)g
+(15360.)42 b(These)30 b(co)s(ordinates)f(are)h(t)m(ypically)e(binned)0
+3631 y(b)m(y)33 b(a)h(factor)g(of)f(32)h(to)g(pro)s(duce)e(a)i(480x480)
+i(pixel)31 b(image.)50 b(If)32 b(one)i(then)f(uses)g(a)g(region)g
+(\014le)f(generated)i(from)0 3744 y(this)29 b(image)i(\(in)f(image)g
+(pixel)f(units\))h(to)h(\014lter)e(the)i(R)m(OSA)-8 b(T)30
+b(ev)m(en)m(ts)i(\014le,)e(then)g(the)h(X)g(and)f(Y)g(column)g(v)-5
+b(alues)0 3857 y(m)m(ust)30 b(b)s(e)g(con)m(v)m(erted)i(to)f(corresp)s
+(onding)d(pixel)h(units)g(as)h(in:)382 4106 y Fe
+(regfilter\("rosat.reg",)42 b(X/32.+.5,)j(Y/32.+.5\))0
+4354 y Fi(Note)h(that)f(this)e(binning)e(con)m(v)m(ersion)k(is)e(not)i
+(necessary)g(if)e(the)i(region)f(\014le)f(is)h(sp)s(eci\014ed)e(using)h
+(celestial)0 4467 y(co)s(ordinate)h(units)f(instead)g(of)h(pixel)f
+(units)g(b)s(ecause)h(CFITSIO)e(is)i(then)f(able)h(to)h(directly)e
+(compare)i(the)0 4580 y(celestial)27 b(co)s(ordinate)h(of)f(eac)m(h)i
+(ro)m(w)f(in)e(the)i(table)f(with)g(the)g(celestial)h(co)s(ordinates)f
+(in)f(the)i(region)f(\014le)g(without)0 4693 y(ha)m(ving)j(to)h(kno)m
+(w)f(an)m(ything)g(ab)s(out)g(ho)m(w)h(the)f(image)h(ma)m(y)g(ha)m(v)m
+(e)g(b)s(een)f(binned.)0 4853 y(The)f(last)g("w)m(cs)h(cols")g
+(parameter)g(should)d(rarely)h(b)s(e)h(needed.)40 b(If)29
+b(supplied,)d(this)j(string)f(con)m(tains)i(the)f(names)0
+4966 y(of)37 b(the)g(2)h(columns)e(\(space)i(or)f(comma)g(separated\))h
+(whic)m(h)e(ha)m(v)m(e)i(the)g(asso)s(ciated)f(W)m(CS)g(k)m(eyw)m
+(ords.)61 b(If)37 b(not)0 5079 y(supplied,)d(the)i(\014lter)f(will)f
+(scan)i(the)g(X)g(and)f(Y)h(expressions)f(for)h(column)e(names.)58
+b(If)35 b(only)g(one)i(is)e(found)f(in)0 5192 y(eac)m(h)e(expression,)d
+(those)i(columns)e(will)f(b)s(e)h(used,)h(otherwise)g(an)g(error)g
+(will)e(b)s(e)i(returned.)0 5352 y(These)g(region)g(shap)s(es)g(are)g
+(supp)s(orted)f(\(names)h(are)h(case)h(insensitiv)m(e\):)334
+5601 y Fe(Point)428 b(\()48 b(X1,)f(Y1)g(\))715 b(<-)48
+b(One)f(pixel)f(square)g(region)334 5714 y(Line)476 b(\()48
+b(X1,)f(Y1,)g(X2,)f(Y2)i(\))333 b(<-)48 b(One)f(pixel)f(wide)h(region)p
+eop
+%%Page: 35 41
+35 40 bop 0 299 a Fg(4.9.)72 b(R)m(O)m(W)31 b(FIL)-8
+b(TERING)31 b(SPECIFICA)-8 b(TION)2072 b Fi(35)334 555
+y Fe(Polygon)332 b(\()48 b(X1,)f(Y1,)g(X2,)f(Y2,)h(...)g(\))95
+b(<-)48 b(Rest)e(are)h(interiors)e(with)334 668 y(Rectangle)236
+b(\()48 b(X1,)f(Y1,)g(X2,)f(Y2,)h(A)h(\))334 b(|)47 b(boundaries)e
+(considered)334 781 y(Box)524 b(\()48 b(Xc,)f(Yc,)g(Wdth,)f(Hght,)g(A)i
+(\))143 b(V)47 b(within)f(the)h(region)334 894 y(Diamond)332
+b(\()48 b(Xc,)f(Yc,)g(Wdth,)f(Hght,)g(A)i(\))334 1007
+y(Circle)380 b(\()48 b(Xc,)f(Yc,)g(R)g(\))334 1120 y(Annulus)332
+b(\()48 b(Xc,)f(Yc,)g(Rin,)f(Rout)h(\))334 1233 y(Ellipse)332
+b(\()48 b(Xc,)f(Yc,)g(Rx,)f(Ry,)h(A)h(\))334 1346 y(Elliptannulus)c(\()
+k(Xc,)f(Yc,)g(Rinx,)f(Riny,)g(Routx,)g(Routy,)g(Ain,)h(Aout)g(\))334
+1458 y(Sector)380 b(\()48 b(Xc,)f(Yc,)g(Amin,)f(Amax)h(\))0
+1732 y Fi(where)28 b(\(Xc,Yc\))j(is)c(the)i(co)s(ordinate)g(of)f(the)h
+(shap)s(e's)f(cen)m(ter;)j(\(X#,Y#\))e(are)g(the)g(co)s(ordinates)f(of)
+h(the)g(shap)s(e's)0 1845 y(edges;)39 b(Rxxx)c(are)g(the)h(shap)s(es')f
+(v)-5 b(arious)34 b(Radii)g(or)h(semima)5 b(jor/minor)34
+b(axes;)k(and)d(Axxx)g(are)h(the)g(angles)f(of)0 1958
+y(rotation)d(\(or)f(b)s(ounding)e(angles)i(for)g(Sector\))h(in)e
+(degrees.)44 b(F)-8 b(or)32 b(rotated)h(shap)s(es,)e(the)g(rotation)h
+(angle)f(can)h(b)s(e)0 2071 y(left)f(o\013,)i(indicating)c(no)i
+(rotation.)45 b(Common)31 b(alternate)h(names)f(for)h(the)f(regions)g
+(can)h(also)g(b)s(e)e(used:)43 b(rotb)s(o)m(x)0 2184
+y(=)29 b(b)s(o)m(x;)g(rotrectangle)h(=)f(rectangle;)h(\(rot\)rhom)m
+(bus)f(=)f(\(rot\)diamond;)i(and)e(pie)g(=)g(sector.)42
+b(When)28 b(a)i(shap)s(e's)0 2297 y(name)e(is)f(preceded)g(b)m(y)h(a)g
+(min)m(us)f(sign,)g('-',)j(the)e(de\014ned)e(region)i(is)f(instead)g
+(the)h(area)h(*outside*)f(its)f(b)s(oundary)0 2410 y(\(ie,)35
+b(the)f(region)g(is)f(in)m(v)m(erted\).)52 b(All)32 b(the)i(shap)s(es)f
+(within)f(a)i(single)f(region)g(\014le)h(are)g(OR'd)f(together)j(to)e
+(create)0 2523 y(the)29 b(region,)h(and)e(the)i(order)f(is)f
+(signi\014can)m(t.)39 b(The)29 b(o)m(v)m(erall)g(w)m(a)m(y)i(of)e(lo)s
+(oking)f(at)i(region)f(\014les)f(is)g(that)i(if)e(the)i(\014rst)0
+2636 y(region)e(is)g(an)h(excluded)f(region)g(then)g(a)i(dumm)m(y)d
+(included)f(region)j(of)g(the)g(whole)f(detector)i(is)e(inserted)f(in)h
+(the)0 2749 y(fron)m(t.)40 b(Then)25 b(eac)m(h)j(region)e(sp)s
+(eci\014cation)g(as)h(it)f(is)g(pro)s(cessed)g(o)m(v)m(errides)g(an)m
+(y)h(selections)g(inside)d(of)j(that)g(region)0 2861
+y(sp)s(eci\014ed)35 b(b)m(y)h(previous)f(regions.)58
+b(Another)37 b(w)m(a)m(y)g(of)g(thinking)d(ab)s(out)i(this)f(is)h(that)
+h(if)e(a)i(previous)e(excluded)0 2974 y(region)30 b(is)f(completely)h
+(inside)f(of)h(a)h(subsequen)m(t)e(included)f(region)i(the)h(excluded)e
+(region)h(is)f(ignored.)0 3135 y(The)44 b(p)s(ositional)f(co)s
+(ordinates)i(ma)m(y)g(b)s(e)g(giv)m(en)g(either)f(in)g(pixel)f(units,)k
+(decimal)d(degrees)i(or)f(hh:mm:ss.s,)0 3247 y(dd:mm:ss.s)25
+b(units.)37 b(The)26 b(shap)s(e)f(sizes)h(ma)m(y)g(b)s(e)g(giv)m(en)g
+(in)e(pixels,)i(degrees,)h(arcmin)m(utes,)g(or)f(arcseconds.)40
+b(Lo)s(ok)0 3360 y(at)31 b(examples)f(of)g(region)g(\014le)g(pro)s
+(duced)e(b)m(y)i(fv/PO)m(W)h(or)g(ds9)f(for)g(further)f(details)g(of)i
+(the)f(region)g(\014le)f(format.)0 3521 y(There)37 b(are)g(three)g
+(functions)f(that)h(are)h(primarily)c(for)i(use)h(with)f(SA)m(O)h
+(region)f(\014les)g(and)h(the)g(FSA)m(OI)g(task,)0 3633
+y(but)e(they)h(can)h(b)s(e)e(used)g(directly)-8 b(.)57
+b(They)36 b(return)f(a)h(b)s(o)s(olean)f(true)h(or)g(false)f(dep)s
+(ending)f(on)i(whether)f(a)i(t)m(w)m(o)0 3746 y(dimensional)28
+b(p)s(oin)m(t)h(is)g(in)g(the)i(region)f(or)g(not:)191
+4020 y Fe("point)46 b(in)h(a)h(circular)d(region")477
+4133 y(circle\(xcntr,ycntr,radius)o(,Xco)o(lumn)o(,Yc)o(olum)o(n\))191
+4359 y("point)h(in)h(an)g(elliptical)e(region")430 4472
+y(ellipse\(xcntr,ycntr,xhl)o(f_w)o(dth,)o(yhlf)o(_wd)o(th,r)o(otat)o
+(ion)o(,Xco)o(lumn)o(,Yc)o(olum)o(n\))191 4698 y("point)h(in)h(a)h
+(rectangular)c(region")620 4811 y(box\(xcntr,ycntr,xfll_wdth,)o(yfll)o
+(_wd)o(th,r)o(otat)o(ion)o(,Xco)o(lumn)o(,Yc)o(olum)o(n\))191
+5036 y(where)334 5149 y(\(xcntr,ycntr\))g(are)j(the)g(\(x,y\))f
+(position)g(of)h(the)g(center)f(of)h(the)g(region)334
+5262 y(\(xhlf_wdth,yhlf_wdth\))42 b(are)47 b(the)g(\(x,y\))f(half)h
+(widths)f(of)h(the)g(region)334 5375 y(\(xfll_wdth,yfll_wdth\))42
+b(are)47 b(the)g(\(x,y\))f(full)h(widths)f(of)h(the)g(region)334
+5488 y(\(radius\))f(is)h(half)f(the)h(diameter)f(of)h(the)g(circle)334
+5601 y(\(rotation\))e(is)i(the)g(angle\(degrees\))d(that)j(the)g
+(region)f(is)h(rotated)f(with)620 5714 y(respect)g(to)h
+(\(xcntr,ycntr\))p eop
+%%Page: 36 42
+36 41 bop 0 299 a Fi(36)1618 b Fg(CHAPTER)30 b(4.)112
+b(EXTENDED)30 b(FILE)h(NAME)f(SYNT)-8 b(AX)334 555 y
+Fe(\(Xcoord,Ycoord\))44 b(are)j(the)g(\(x,y\))f(coordinates)f(to)i
+(test,)f(usually)g(column)620 668 y(names)334 781 y(NOTE:)g(each)h
+(parameter)e(can)i(itself)f(be)i(an)f(expression,)d(not)j(merely)f(a)
+620 894 y(column)h(name)f(or)h(constant.)0 1201 y Fb(4.9.6)112
+b(Example)37 b(Ro)m(w)g(Filters)191 1423 y Fe([)47 b(binary)f(&&)i(mag)
+f(<=)g(5.0])380 b(-)48 b(Extract)e(all)h(binary)f(stars)g(brighter)1766
+1536 y(than)94 b(fifth)47 b(magnitude)e(\(note)h(that)1766
+1649 y(the)h(initial)f(space)g(is)h(necessary)e(to)1766
+1762 y(prevent)h(it)h(from)g(being)f(treated)g(as)h(a)1766
+1875 y(binning)f(specification\))191 2101 y([#row)g(>=)h(125)g(&&)h
+(#row)e(<=)h(175])142 b(-)48 b(Extract)e(row)h(numbers)e(125)i(through)
+f(175)191 2327 y([IMAGE[4,5])f(.gt.)h(100])476 b(-)48
+b(Extract)e(all)h(rows)f(that)h(have)g(the)1766 2439
+y(\(4,5\))f(component)g(of)h(the)g(IMAGE)f(column)1766
+2552 y(greater)g(than)g(100)191 2778 y([abs\(sin\(theta)e(*)j(#deg\)\))
+f(<)i(0.5])e(-)i(Extract)e(all)h(rows)f(having)g(the)1766
+2891 y(absolute)f(value)i(of)g(the)g(sine)g(of)g(theta)1766
+3004 y(less)94 b(than)47 b(a)g(half)g(where)f(the)h(angles)1766
+3117 y(are)g(tabulated)e(in)i(degrees)191 3343 y([SUM\()f(SPEC)h(>)g
+(3*BACKGRND)e(\)>=1])94 b(-)48 b(Extract)e(all)h(rows)f(containing)f(a)
+1766 3456 y(spectrum,)g(held)i(in)g(vector)f(column)1766
+3569 y(SPEC,)g(with)h(at)g(least)f(one)h(value)g(3)1766
+3681 y(times)f(greater)g(than)h(the)g(background)1766
+3794 y(level)f(held)h(in)g(a)h(keyword,)d(BACKGRND)191
+4020 y([VCOL=={1,4,2}])759 b(-)48 b(Extract)e(all)h(rows)f(whose)h
+(vector)f(column)1766 4133 y(VCOL)h(contains)e(the)i(3-elements)e(1,)i
+(4,)g(and)1766 4246 y(2.)191 4472 y([@rowFilter.txt])711
+b(-)48 b(Extract)e(rows)g(using)h(the)g(expression)1766
+4585 y(contained)e(within)h(the)h(text)g(file)1766 4698
+y(rowFilter.txt)191 4924 y([gtifilter\(\)])855 b(-)48
+b(Search)e(the)h(current)f(file)g(for)h(a)h(GTI)239 5036
+y(extension,)92 b(filter)i(the)47 b(TIME)239 5149 y(column)f(in)h(the)g
+(current)f(table,)g(using)239 5262 y(START/STOP)f(times)h(taken)g(from)
+239 5375 y(columns)f(in)j(the)f(GTI)94 b(extension)191
+5601 y([regfilter\("pow.reg"\)])423 b(-)48 b(Extract)e(rows)g(which)h
+(have)f(a)i(coordinate)1766 5714 y(\(as)f(given)f(in)h(the)g(X)h(and)f
+(Y)g(columns\))p eop
+%%Page: 37 43
+37 42 bop 0 299 a Fg(4.10.)113 b(BINNING)31 b(OR)f(HISTOGRAMMING)h
+(SPECIFICA)-8 b(TION)1313 b Fi(37)1766 555 y Fe(within)46
+b(the)h(spatial)f(region)g(specified)1766 668 y(in)h(the)g(pow.reg)f
+(region)g(file.)191 894 y([regfilter\("pow.reg",)c(Xs,)47
+b(Ys\)])f(-)i(Same)f(as)g(above,)f(except)g(that)h(the)1766
+1007 y(Xs)g(and)g(Ys)g(columns)f(will)h(be)g(used)f(to)1766
+1120 y(determine)f(the)i(coordinate)e(of)i(each)1766
+1233 y(row)g(in)g(the)g(table.)0 1560 y Fd(4.10)180 b(Binning)45
+b(or)g(Histogramming)i(Sp)t(eci\014cation)0 1810 y Fi(The)22
+b(optional)g(binning)e(sp)s(eci\014er)h(is)h(enclosed)h(in)f(square)g
+(brac)m(k)m(ets)j(and)d(can)h(b)s(e)f(distinguished)d(from)k(a)g
+(general)0 1923 y(ro)m(w)32 b(\014lter)g(sp)s(eci\014cation)f(b)m(y)h
+(the)h(fact)g(that)g(it)f(b)s(egins)f(with)g(the)h(k)m(eyw)m(ord)h
+('bin')e(not)i(immediately)d(follo)m(w)m(ed)0 2036 y(b)m(y)41
+b(an)f(equals)h(sign.)71 b(When)41 b(binning)c(is)j(sp)s(eci\014ed,)i
+(a)f(temp)s(orary)g(N-dimensional)d(FITS)i(primary)f(arra)m(y)0
+2149 y(is)j(created)i(b)m(y)f(computing)g(the)g(histogram)g(of)g(the)g
+(v)-5 b(alues)43 b(in)e(the)j(sp)s(eci\014ed)d(columns)h(of)h(a)h(FITS)
+e(table)0 2262 y(extension.)e(After)30 b(the)f(histogram)g(is)g
+(computed)g(the)h(input)d(FITS)i(\014le)g(con)m(taining)g(the)g(table)h
+(is)e(then)h(closed)0 2375 y(and)34 b(the)h(temp)s(orary)f(FITS)g
+(primary)f(arra)m(y)i(is)f(op)s(ened)g(and)g(passed)g(to)h(the)g
+(application)e(program.)54 b(Th)m(us,)0 2488 y(the)39
+b(application)e(program)i(nev)m(er)g(sees)g(the)g(original)e(FITS)h
+(table)h(and)f(only)g(sees)i(the)f(image)g(in)e(the)i(new)0
+2601 y(temp)s(orary)32 b(\014le)g(\(whic)m(h)g(has)g(no)h(additional)d
+(extensions\).)48 b(Ob)m(viously)-8 b(,)32 b(the)h(application)e
+(program)h(m)m(ust)h(b)s(e)0 2714 y(exp)s(ecting)d(to)h(op)s(en)f(a)h
+(FITS)e(image)i(and)f(not)g(a)h(FITS)f(table)g(in)f(this)g(case.)0
+2874 y(The)h(data)h(t)m(yp)s(e)f(of)h(the)f(FITS)g(histogram)f(image)i
+(ma)m(y)g(b)s(e)f(sp)s(eci\014ed)e(b)m(y)i(app)s(ending)e('b')i(\(for)h
+(8-bit)f(b)m(yte\),)h('i')0 2987 y(\(for)g(16-bit)f(in)m(tegers\),)h
+('j')g(\(for)g(32-bit)f(in)m(teger\),)i('r')e(\(for)h(32-bit)f
+(\015oating)h(p)s(oin)m(ts\),)e(or)i('d')f(\(for)h(64-bit)f(double)0
+3100 y(precision)c(\015oating)i(p)s(oin)m(t\))g(to)g(the)h('bin')d(k)m
+(eyw)m(ord)j(\(e.g.)41 b('[binr)27 b(X]')h(creates)i(a)e(real)g
+(\015oating)g(p)s(oin)m(t)f(image\).)40 b(If)0 3212 y(the)26
+b(datat)m(yp)s(e)h(is)e(not)h(explicitly)e(sp)s(eci\014ed)g(then)i(a)g
+(32-bit)g(in)m(teger)h(image)f(will)d(b)s(e)i(created)i(b)m(y)f
+(default,)h(unless)0 3325 y(the)i(w)m(eigh)m(ting)f(option)g(is)g(also)
+h(sp)s(eci\014ed)e(in)g(whic)m(h)h(case)h(the)g(image)g(will)d(ha)m(v)m
+(e)k(a)f(32-bit)g(\015oating)g(p)s(oin)m(t)e(data)0 3438
+y(t)m(yp)s(e)k(b)m(y)f(default.)0 3598 y(The)24 b(histogram)f(image)i
+(ma)m(y)g(ha)m(v)m(e)g(from)f(1)g(to)h(4)g(dimensions)c(\(axes\),)27
+b(dep)s(ending)22 b(on)i(the)g(n)m(um)m(b)s(er)f(of)h(columns)0
+3711 y(that)31 b(are)g(sp)s(eci\014ed.)39 b(The)30 b(general)g(form)g
+(of)g(the)h(binning)c(sp)s(eci\014cation)i(is:)48 3931
+y Fe([bin{bijrd})92 b(Xcol=min:max:binsize,)42 b(Ycol=)47
+b(...,)f(Zcol=...,)f(Tcol=...;)h(weight])0 4152 y Fi(in)38
+b(whic)m(h)g(up)g(to)i(4)g(columns,)g(eac)m(h)g(corresp)s(onding)d(to)j
+(an)g(axis)e(of)i(the)f(image,)j(are)e(listed.)65 b(The)39
+b(column)0 4264 y(names)27 b(are)h(case)h(insensitiv)m(e,)d(and)h(the)h
+(column)e(n)m(um)m(b)s(er)g(ma)m(y)i(b)s(e)f(giv)m(en)g(instead)g(of)h
+(the)g(name,)g(preceded)f(b)m(y)0 4377 y(a)32 b(p)s(ound)e(sign)h
+(\(e.g.,)j([bin)c(#4=1:512]\).)47 b(If)31 b(the)h(column)f(name)h(is)e
+(not)i(sp)s(eci\014ed,)f(then)g(CFITSIO)g(will)e(\014rst)0
+4490 y(try)37 b(to)h(use)f(the)g('preferred)f(column')h(as)g(sp)s
+(eci\014ed)f(b)m(y)h(the)g(CPREF)g(k)m(eyw)m(ord)h(if)e(it)g(exists)h
+(\(e.g.,)k('CPREF)0 4603 y(=)i('DETX,DETY'\),)h(otherwise)f(column)f
+(names)h('X',)h('Y',)g('Z',)f(and)f('T')i(will)c(b)s(e)i(assumed)h(for)
+g(eac)m(h)h(of)0 4716 y(the)37 b(4)h(axes,)i(resp)s(ectiv)m(ely)-8
+b(.)60 b(In)37 b(cases)h(where)e(the)i(column)e(name)h(could)f(b)s(e)g
+(confused)h(with)f(an)h(arithmetic)0 4829 y(expression,)29
+b(enclose)i(the)g(column)e(name)h(in)f(paren)m(theses)i(to)g(force)g
+(the)f(name)h(to)g(b)s(e)f(in)m(terpreted)f(literally)-8
+b(.)0 4989 y(Eac)m(h)33 b(column)e(name)h(ma)m(y)h(b)s(e)f(follo)m(w)m
+(ed)f(b)m(y)i(an)f(equals)f(sign)h(and)f(then)h(the)g(lo)m(w)m(er)h
+(and)f(upp)s(er)e(range)i(of)h(the)0 5102 y(histogram,)e(and)f(the)h
+(size)g(of)g(the)g(histogram)g(bins,)e(separated)i(b)m(y)g(colons.)42
+b(Spaces)31 b(are)g(allo)m(w)m(ed)g(b)s(efore)g(and)0
+5215 y(after)e(the)g(equals)f(sign)f(but)h(not)h(within)d(the)j
+('min:max:binsize')d(string.)39 b(The)29 b(min,)e(max)i(and)f(binsize)f
+(v)-5 b(alues)0 5328 y(ma)m(y)32 b(b)s(e)e(in)m(teger)h(or)g
+(\015oating)g(p)s(oin)m(t)f(n)m(um)m(b)s(ers,)g(or)h(they)g(ma)m(y)g(b)
+s(e)g(the)g(names)g(of)g(k)m(eyw)m(ords)g(in)f(the)h(header)g(of)0
+5441 y(the)g(table.)40 b(If)30 b(the)h(latter,)g(then)f(the)g(v)-5
+b(alue)30 b(of)h(that)g(k)m(eyw)m(ord)f(is)g(substituted)f(in)m(to)h
+(the)h(expression.)0 5601 y(Default)36 b(v)-5 b(alues)35
+b(for)h(the)g(min,)g(max)g(and)g(binsize)e(quan)m(tities)h(will)e(b)s
+(e)i(used)h(if)e(not)j(explicitly)c(giv)m(en)j(in)f(the)0
+5714 y(binning)27 b(expression)i(as)i(sho)m(wn)f(in)f(these)i
+(examples:)p eop
+%%Page: 38 44
+38 43 bop 0 299 a Fi(38)1618 b Fg(CHAPTER)30 b(4.)112
+b(EXTENDED)30 b(FILE)h(NAME)f(SYNT)-8 b(AX)191 555 y
+Fe([bin)47 b(x)g(=)g(:512:2])94 b(-)47 b(use)g(default)f(minimum)g
+(value)191 668 y([bin)h(x)g(=)g(1::2])190 b(-)47 b(use)g(default)f
+(maximum)g(value)191 781 y([bin)h(x)g(=)g(1:512])142
+b(-)47 b(use)g(default)f(bin)h(size)191 894 y([bin)g(x)g(=)g(1:])286
+b(-)47 b(use)g(default)f(maximum)g(value)g(and)h(bin)g(size)191
+1007 y([bin)g(x)g(=)g(:512])190 b(-)47 b(use)g(default)f(minimum)g
+(value)g(and)h(bin)g(size)191 1120 y([bin)g(x)g(=)g(2])334
+b(-)47 b(use)g(default)f(minimum)g(and)h(maximum)f(values)191
+1233 y([bin)h(x])524 b(-)47 b(use)g(default)f(minimum,)g(maximum)g(and)
+g(bin)h(size)191 1346 y([bin)g(4])524 b(-)47 b(default)f(2-D)h(image,)f
+(bin)h(size)g(=)g(4)h(in)f(both)g(axes)191 1458 y([bin])619
+b(-)47 b(default)f(2-D)h(image)0 1713 y Fi(CFITSIO)31
+b(will)f(use)i(the)h(v)-5 b(alue)32 b(of)h(the)g(TLMINn,)f(TLMAXn,)h
+(and)f(TDBINn)h(k)m(eyw)m(ords,)h(if)d(they)i(exist,)g(for)0
+1826 y(the)k(default)e(min,)i(max,)h(and)e(binsize,)g(resp)s(ectiv)m
+(ely)-8 b(.)59 b(If)36 b(they)h(do)f(not)h(exist)f(then)g(CFITSIO)f
+(will)f(use)i(the)0 1939 y(actual)c(minim)m(um)d(and)j(maxim)m(um)f(v)
+-5 b(alues)31 b(in)g(the)h(column)e(for)i(the)g(histogram)g(min)e(and)i
+(max)g(v)-5 b(alues.)44 b(The)0 2052 y(default)33 b(binsize)e(will)g(b)
+s(e)i(set)h(to)h(1,)g(or)e(\(max)h(-)g(min\))e(/)i(10.,)i(whic)m(hev)m
+(er)d(is)g(smaller,)g(so)g(that)i(the)e(histogram)0 2165
+y(will)28 b(ha)m(v)m(e)j(at)g(least)g(10)g(bins)e(along)h(eac)m(h)i
+(axis.)0 2325 y(A)41 b(shortcut)g(notation)g(is)f(allo)m(w)m(ed)h(if)f
+(all)g(the)h(columns/axes)g(ha)m(v)m(e)h(the)f(same)g(binning)d(sp)s
+(eci\014cation.)72 b(In)0 2438 y(this)32 b(case)h(all)f(the)h(column)e
+(names)i(ma)m(y)g(b)s(e)f(listed)f(within)f(paren)m(theses,)k(follo)m
+(w)m(ed)f(b)m(y)f(the)h(\(single\))f(binning)0 2551 y(sp)s
+(eci\014cation,)d(as)i(in:)191 2805 y Fe([bin)47 b(\(X,Y\)=1:512:2])191
+2918 y([bin)g(\(X,Y\))f(=)h(5])0 3172 y Fi(The)31 b(optional)g(w)m
+(eigh)m(ting)h(factor)g(is)f(the)h(last)f(item)h(in)e(the)i(binning)d
+(sp)s(eci\014er)h(and,)i(if)e(presen)m(t,)j(is)d(separated)0
+3285 y(from)38 b(the)g(list)f(of)h(columns)f(b)m(y)h(a)h(semi-colon.)63
+b(As)39 b(the)f(histogram)g(is)f(accum)m(ulated,)k(this)c(w)m(eigh)m(t)
+i(is)e(used)0 3398 y(to)e(incremen)m(ted)e(the)h(v)-5
+b(alue)34 b(of)g(the)g(appropriated)e(bin)h(in)f(the)i(histogram.)51
+b(If)34 b(the)g(w)m(eigh)m(ting)g(factor)h(is)e(not)0
+3511 y(sp)s(eci\014ed,)23 b(then)g(the)g(default)f(w)m(eigh)m(t)i(=)e
+(1)i(is)e(assumed.)37 b(The)23 b(w)m(eigh)m(ting)g(factor)h(ma)m(y)f(b)
+s(e)g(a)g(constan)m(t)i(in)m(teger)e(or)0 3624 y(\015oating)29
+b(p)s(oin)m(t)f(n)m(um)m(b)s(er,)g(or)h(the)g(name)g(of)g(a)g(k)m(eyw)m
+(ord)h(con)m(taining)e(the)i(w)m(eigh)m(ting)e(v)-5 b(alue.)40
+b(Or)28 b(the)h(w)m(eigh)m(ting)0 3737 y(factor)g(ma)m(y)g(b)s(e)e(the)
+h(name)g(of)h(a)f(table)g(column)f(in)g(whic)m(h)f(case)k(the)e(v)-5
+b(alue)27 b(in)g(that)i(column,)e(on)h(a)h(ro)m(w)f(b)m(y)g(ro)m(w)0
+3850 y(basis,)h(will)f(b)s(e)i(used.)0 4010 y(In)35 b(some)h(cases,)i
+(the)d(column)g(or)g(k)m(eyw)m(ord)h(ma)m(y)g(giv)m(e)g(the)g(recipro)s
+(cal)e(of)i(the)g(actual)g(w)m(eigh)m(t)g(v)-5 b(alue)35
+b(that)h(is)0 4123 y(needed.)49 b(In)32 b(this)g(case,)j(precede)e(the)
+h(w)m(eigh)m(t)f(k)m(eyw)m(ord)h(or)f(column)f(name)h(b)m(y)g(a)g
+(slash)f('/')i(to)g(tell)e(CFITSIO)0 4236 y(to)f(use)f(the)h(recipro)s
+(cal)e(of)h(the)h(v)-5 b(alue)30 b(when)f(constructing)h(the)h
+(histogram.)0 4396 y(F)-8 b(or)35 b(complex)e(or)h(commonly)f(used)g
+(histograms,)i(one)f(can)g(also)g(place)g(its)f(description)f(in)m(to)i
+(a)g(text)h(\014le)e(and)0 4509 y(imp)s(ort)43 b(it)g(in)m(to)i(the)f
+(binning)d(sp)s(eci\014cation)i(using)g(the)i(syn)m(tax)f('[bin)f
+(@\014lename.txt]'.)83 b(The)44 b(\014le's)f(con-)0 4622
+y(ten)m(ts)37 b(can)e(extend)h(o)m(v)m(er)h(m)m(ultiple)c(lines,)j
+(although)f(it)g(m)m(ust)g(still)f(conform)i(to)g(the)g(no-spaces)g
+(rule)e(for)i(the)0 4735 y(min:max:binsize)e(syn)m(tax)k(and)e(eac)m(h)
+i(axis)f(sp)s(eci\014cation)f(m)m(ust)h(still)d(b)s(e)j
+(comma-separated.)62 b(An)m(y)37 b(lines)e(in)0 4848
+y(the)d(external)g(text)h(\014le)e(that)i(b)s(egin)d(with)h(2)h(slash)f
+(c)m(haracters)i(\('//'\))h(will)29 b(b)s(e)j(ignored)f(and)g(ma)m(y)i
+(b)s(e)e(used)g(to)0 4961 y(add)f(commen)m(ts)h(in)m(to)f(the)h
+(\014le.)0 5121 y(Examples:)191 5375 y Fe([bini)46 b(detx,)h(dety])762
+b(-)47 b(2-D,)g(16-bit)f(integer)g(histogram)1861 5488
+y(of)i(DETX)e(and)h(DETY)g(columns,)e(using)1861 5601
+y(default)h(values)g(for)h(the)g(histogram)1861 5714
+y(range)g(and)g(binsize)p eop
+%%Page: 39 45
+39 44 bop 0 299 a Fg(4.10.)113 b(BINNING)31 b(OR)f(HISTOGRAMMING)h
+(SPECIFICA)-8 b(TION)1313 b Fi(39)191 668 y Fe([bin)47
+b(\(detx,)f(dety\)=16;)f(/exposure])g(-)i(2-D,)g(32-bit)f(real)h
+(histogram)e(of)i(DETX)1861 781 y(and)g(DETY)g(columns)f(with)g(a)i
+(bin)f(size)f(=)i(16)1861 894 y(in)g(both)e(axes.)h(The)f(histogram)g
+(values)1861 1007 y(are)h(divided)f(by)h(the)g(EXPOSURE)f(keyword)1861
+1120 y(value.)191 1346 y([bin)h(time=TSTART:TSTOP:0.1])280
+b(-)47 b(1-D)g(lightcurve,)e(range)h(determined)f(by)1861
+1458 y(the)i(TSTART)f(and)h(TSTOP)g(keywords,)1861 1571
+y(with)g(0.1)g(unit)g(size)f(bins.)191 1797 y([bin)h(pha,)f
+(time=8000.:8100.:0.1])90 b(-)47 b(2-D)g(image)g(using)f(default)g
+(binning)1861 1910 y(of)i(the)e(PHA)h(column)f(for)h(the)g(X)h(axis,)
+1861 2023 y(and)f(1000)g(bins)g(in)g(the)g(range)1861
+2136 y(8000.)g(to)g(8100.)f(for)h(the)g(Y)h(axis.)191
+2362 y([bin)f(@binFilter.txt])616 b(-)47 b(Use)g(the)g(contents)f(of)h
+(the)g(text)f(file)1861 2475 y(binFilter.txt)f(for)h(the)h(binning)1861
+2588 y(specifications.)p eop
+%%Page: 40 46
+40 45 bop 0 299 a Fi(40)1618 b Fg(CHAPTER)30 b(4.)112
+b(EXTENDED)30 b(FILE)h(NAME)f(SYNT)-8 b(AX)p eop
+%%Page: 41 47
+41 46 bop 0 1225 a Ff(Chapter)65 b(5)0 1687 y Fl(T)-19
+b(emplate)76 b(Files)0 2180 y Fi(When)38 b(a)h(new)f(FITS)g(\014le)g
+(is)g(created)h(with)f(a)g(call)g(to)i(\014ts)p 2101
+2180 28 4 v 32 w(create)p 2369 2180 V 35 w(\014le,)f(the)g(name)g(of)g
+(a)g(template)g(\014le)e(ma)m(y)0 2293 y(b)s(e)i(supplied)e(in)i(paren)
+m(theses)h(immediately)e(follo)m(wing)g(the)j(name)f(of)g(the)g(new)f
+(\014le)g(to)i(b)s(e)e(created.)71 b(This)0 2406 y(template)26
+b(is)e(used)h(to)h(de\014ne)f(the)h(structure)f(of)h(one)f(or)h(more)g
+(HDUs)g(in)e(the)i(new)f(\014le.)38 b(The)25 b(template)h(\014le)e(ma)m
+(y)0 2518 y(b)s(e)32 b(another)h(FITS)f(\014le,)h(in)f(whic)m(h)f(case)
+j(the)f(newly)f(created)i(\014le)e(will)e(ha)m(v)m(e)k(exactly)g(the)f
+(same)g(k)m(eyw)m(ords)g(in)0 2631 y(eac)m(h)25 b(HDU)g(as)g(in)e(the)h
+(template)h(FITS)e(\014le,)i(but)e(all)h(the)g(data)h(units)d(will)g(b)
+s(e)i(\014lled)e(with)g(zeros.)40 b(The)24 b(template)0
+2744 y(\014le)h(ma)m(y)i(also)f(b)s(e)f(an)h(ASCI)s(I)e(text)j(\014le,)
+f(where)g(eac)m(h)h(line)d(\(in)h(general\))i(describ)s(es)d(one)i
+(FITS)f(k)m(eyw)m(ord)i(record.)0 2857 y(The)j(format)h(of)f(the)h
+(ASCI)s(I)e(template)h(\014le)g(is)f(describ)s(ed)f(in)i(the)g(follo)m
+(wing)f(sections.)0 3188 y Fd(5.1)135 b(Detailed)47 b(T)-11
+b(emplate)46 b(Line)f(F)-11 b(ormat)0 3438 y Fi(The)30
+b(format)h(of)f(eac)m(h)i(ASCI)s(I)c(template)j(line)e(closely)h(follo)
+m(ws)f(the)i(format)g(of)f(a)h(FITS)f(k)m(eyw)m(ord)g(record:)95
+3682 y Fe(KEYWORD)46 b(=)i(KEYVALUE)d(/)j(COMMENT)0 3926
+y Fi(except)22 b(that)g(free)g(format)f(ma)m(y)h(b)s(e)f(used)f
+(\(e.g.,)25 b(the)d(equals)e(sign)h(ma)m(y)g(app)s(ear)g(at)h(an)m(y)g
+(p)s(osition)d(in)h(the)i(line\))e(and)0 4039 y(T)-8
+b(AB)34 b(c)m(haracters)g(are)g(allo)m(w)m(ed)f(and)g(are)g(treated)h
+(the)g(same)f(as)h(space)f(c)m(haracters.)51 b(The)33
+b(KEYV)-10 b(ALUE)33 b(and)0 4152 y(COMMENT)d(\014elds)f(are)i
+(optional.)41 b(The)30 b(equals)g(sign)f(c)m(haracter)k(is)c(also)i
+(optional,)f(but)g(it)g(is)f(recommended)0 4264 y(that)42
+b(it)e(b)s(e)h(included)d(for)j(clarit)m(y)-8 b(.)73
+b(An)m(y)41 b(template)h(line)d(that)j(b)s(egins)e(with)f(the)j(p)s
+(ound)d('#')i(c)m(haracter)i(is)0 4377 y(ignored)29 b(b)m(y)i(the)f
+(template)h(parser)f(and)g(ma)m(y)h(b)s(e)e(use)h(to)h(insert)f(commen)
+m(ts)h(in)m(to)f(the)h(template)g(\014le)e(itself.)0
+4538 y(The)d(KEYW)m(ORD)g(name)g(\014eld)f(is)g(limited)f(to)j(8)f(c)m
+(haracters)h(in)e(length)h(and)f(only)g(the)h(letters)h(A-Z,)f(digits)f
+(0-9,)0 4650 y(and)j(the)g(h)m(yphen)f(and)h(underscore)g(c)m
+(haracters)h(ma)m(y)g(b)s(e)f(used,)g(without)g(an)m(y)g(em)m(b)s
+(edded)g(spaces.)40 b(Lo)m(w)m(ercase)0 4763 y(letters)21
+b(in)f(the)i(template)f(k)m(eyw)m(ord)h(name)f(will)d(b)s(e)j(con)m(v)m
+(erted)i(to)f(upp)s(ercase.)36 b(Leading)21 b(spaces)g(in)f(the)i
+(template)0 4876 y(line)i(preceding)h(the)g(k)m(eyw)m(ord)h(name)g(are)
+g(generally)f(ignored,)h(except)g(if)f(the)h(\014rst)f(8)h(c)m
+(haracters)h(of)f(a)g(template)0 4989 y(line)d(are)j(all)e(blank,)h
+(then)g(the)g(en)m(tire)g(line)f(is)g(treated)i(as)f(a)h(FITS)e(commen)
+m(t)i(k)m(eyw)m(ord)g(\(with)e(a)i(blank)d(k)m(eyw)m(ord)0
+5102 y(name\))31 b(and)f(is)f(copied)h(v)m(erbatim)g(in)m(to)g(the)h
+(FITS)e(header.)0 5262 y(The)37 b(KEYV)-10 b(ALUE)37
+b(\014eld)f(ma)m(y)i(ha)m(v)m(e)g(an)m(y)g(allo)m(w)m(ed)f(FITS)g(data)
+h(t)m(yp)s(e:)54 b(c)m(haracter)39 b(string,)g(logical,)f(in)m(teger,)0
+5375 y(real,)33 b(complex)f(in)m(teger,)i(or)e(complex)h(real.)46
+b(The)32 b(c)m(haracter)j(string)c(v)-5 b(alues)32 b(need)g(not)h(b)s
+(e)f(enclosed)g(in)f(single)0 5488 y(quote)e(c)m(haracters)h(unless)d
+(they)h(are)h(necessary)g(to)g(distinguish)24 b(the)29
+b(string)e(from)h(a)h(di\013eren)m(t)f(data)h(t)m(yp)s(e)f(\(e.g.)0
+5601 y(2.0)h(is)d(a)i(real)g(but)f('2.0')i(is)e(a)h(string\).)39
+b(The)27 b(k)m(eyw)m(ord)h(has)f(an)h(unde\014ned)d(\(n)m(ull\))h(v)-5
+b(alue)28 b(if)e(the)i(template)g(record)0 5714 y(only)h(con)m(tains)i
+(blanks)e(follo)m(wing)g(the)h("=")h(or)g(b)s(et)m(w)m(een)g(the)f("=")
+h(and)f(the)g("/")i(commen)m(t)g(\014eld)c(delimiter.)1905
+5942 y(41)p eop
+%%Page: 42 48
+42 47 bop 0 299 a Fi(42)2340 b Fg(CHAPTER)30 b(5.)71
+b(TEMPLA)-8 b(TE)30 b(FILES)0 555 y Fi(String)25 b(k)m(eyw)m(ord)i(v)-5
+b(alues)26 b(longer)g(than)g(68)h(c)m(haracters)h(\(the)f(maxim)m(um)e
+(length)h(that)h(will)d(\014t)i(in)f(a)i(single)e(FITS)0
+668 y(k)m(eyw)m(ord)41 b(record\))g(are)g(p)s(ermitted)e(using)g(the)i
+(CFITSIO)e(long)h(string)g(con)m(v)m(en)m(tion.)73 b(They)40
+b(can)h(either)f(b)s(e)0 781 y(sp)s(eci\014ed)27 b(as)j(a)f(single)f
+(long)g(line)g(in)f(the)j(template,)g(or)f(b)m(y)f(using)g(m)m(ultiple)
+f(lines)g(where)h(the)i(con)m(tin)m(uing)e(lines)0 894
+y(con)m(tain)j(the)f('CONTINUE')g(k)m(eyw)m(ord,)h(as)g(in)e(this)g
+(example:)95 1139 y Fe(LONGKEY)46 b(=)i('This)e(is)h(a)h(long)e(string)
+g(value)h(that)f(is)i(contin&')95 1252 y(CONTINUE)94
+b('ued)46 b(over)h(2)g(records')f(/)h(comment)f(field)h(goes)f(here)0
+1497 y Fi(The)29 b(format)h(of)g(template)g(lines)d(with)i(CONTINUE)f
+(k)m(eyw)m(ord)i(is)f(v)m(ery)h(strict:)40 b(3)30 b(spaces)g(m)m(ust)f
+(follo)m(w)g(CON-)0 1610 y(TINUE)h(and)g(the)g(rest)h(of)f(the)h(line)e
+(is)g(copied)h(v)m(erbatim)g(to)h(the)g(FITS)e(\014le.)0
+1771 y(The)i(start)h(of)g(the)f(optional)g(COMMENT)g(\014eld)f(m)m(ust)
+i(b)s(e)e(preceded)i(b)m(y)f("/",)i(whic)m(h)d(is)h(used)g(to)h
+(separate)g(it)0 1883 y(from)e(the)g(k)m(eyw)m(ord)h(v)-5
+b(alue)29 b(\014eld.)40 b(Exceptions)29 b(are)i(if)e(the)i(KEYW)m(ORD)g
+(name)f(\014eld)f(con)m(tains)h(COMMENT,)0 1996 y(HISTOR)-8
+b(Y,)30 b(CONTINUE,)g(or)g(if)f(the)i(\014rst)f(8)g(c)m(haracters)i(of)
+f(the)f(template)h(line)e(are)i(blanks.)0 2157 y(More)c(than)f(one)h
+(Header-Data)i(Unit)d(\(HDU\))h(ma)m(y)g(b)s(e)f(de\014ned)f(in)g(the)i
+(template)g(\014le.)38 b(The)26 b(start)h(of)g(an)f(HDU)0
+2269 y(de\014nition)i(is)h(denoted)i(with)e(a)i(SIMPLE)e(or)i(XTENSION)
+e(template)i(line:)0 2430 y(1\))j(SIMPLE)f(b)s(egins)f(a)i(Primary)f
+(HDU)h(de\014nition.)48 b(SIMPLE)33 b(ma)m(y)h(only)f(app)s(ear)g(as)h
+(the)g(\014rst)f(k)m(eyw)m(ord)h(in)0 2543 y(the)e(template)h(\014le.)
+44 b(If)32 b(the)g(template)h(\014le)e(b)s(egins)f(with)h(XTENSION)g
+(instead)g(of)h(SIMPLE,)g(then)f(a)i(default)0 2655 y(empt)m(y)d
+(Primary)d(HDU)j(is)f(created,)i(and)d(the)i(template)g(is)e(then)h
+(assumed)f(to)i(de\014ne)f(the)h(k)m(eyw)m(ords)f(starting)0
+2768 y(with)g(the)i(\014rst)e(extension)h(follo)m(wing)f(the)i(Primary)
+e(HDU.)0 2928 y(2\))35 b(XTENSION)e(marks)g(the)i(b)s(eginning)c(of)j
+(a)h(new)e(extension)h(HDU)g(de\014nition.)50 b(The)33
+b(previous)g(HDU)i(will)0 3041 y(b)s(e)30 b(closed)g(at)h(this)e(p)s
+(oin)m(t)h(and)f(pro)s(cessing)h(of)g(the)h(next)f(extension)g(b)s
+(egins.)0 3373 y Fd(5.2)135 b(Auto-indexing)45 b(of)h(Keyw)l(ords)0
+3623 y Fi(If)31 b(a)h(template)f(k)m(eyw)m(ord)h(name)f(ends)g(with)f
+(a)h("#")h(c)m(haracter,)i(it)d(is)f(said)g(to)i(b)s(e)f
+('auto-indexed'.)43 b(Eac)m(h)32 b("#")0 3736 y(c)m(haracter)i(will)c
+(b)s(e)i(replaced)h(b)m(y)f(the)h(curren)m(t)g(in)m(teger)g(index)e(v)
+-5 b(alue,)33 b(whic)m(h)f(gets)h(reset)h(=)e(1)h(at)h(the)e(start)i
+(of)0 3849 y(eac)m(h)h(new)f(HDU)g(in)f(the)h(\014le)f(\(or)h(7)h(in)d
+(the)i(sp)s(ecial)f(case)i(of)f(a)g(GR)m(OUP)h(de\014nition\).)49
+b(The)33 b(FIRST)g(indexed)0 3962 y(k)m(eyw)m(ord)c(in)e(eac)m(h)i
+(template)g(HDU)g(de\014nition)d(is)h(used)g(as)i(the)f('incremen)m
+(tor';)i(eac)m(h)f(subsequen)m(t)f(o)s(ccurrence)0 4075
+y(of)k(this)e(SAME)h(k)m(eyw)m(ord)h(will)d(cause)j(the)g(index)e(v)-5
+b(alue)31 b(to)h(b)s(e)f(incremen)m(ted.)43 b(This)30
+b(b)s(eha)m(vior)g(can)i(b)s(e)f(rather)0 4188 y(subtle,)c(as)h
+(illustrated)e(in)g(the)i(follo)m(wing)e(examples)h(in)f(whic)m(h)h
+(the)h(TTYPE)e(k)m(eyw)m(ord)i(is)f(the)h(incremen)m(tor)f(in)0
+4300 y(b)s(oth)j(cases:)95 4546 y Fe(TTYPE#)47 b(=)g(TIME)95
+4659 y(TFORM#)g(=)g(1D)95 4772 y(TTYPE#)g(=)g(RATE)95
+4884 y(TFORM#)g(=)g(1E)0 5130 y Fi(will)23 b(create)28
+b(TTYPE1,)e(TF)m(ORM1,)i(TTYPE2,)f(and)e(TF)m(ORM2)i(k)m(eyw)m(ords.)40
+b(But)26 b(if)f(the)h(template)g(lo)s(oks)f(lik)m(e,)95
+5375 y Fe(TTYPE#)47 b(=)g(TIME)95 5488 y(TTYPE#)g(=)g(RATE)95
+5601 y(TFORM#)g(=)g(1D)95 5714 y(TFORM#)g(=)g(1E)p eop
+%%Page: 43 49
+43 48 bop 0 299 a Fg(5.3.)72 b(TEMPLA)-8 b(TE)30 b(P)-8
+b(ARSER)30 b(DIRECTIVES)2073 b Fi(43)0 555 y(this)30
+b(results)f(in)h(a)h(FITS)f(\014les)g(with)f(TTYPE1,)i(TTYPE2,)g(TF)m
+(ORM2,)h(and)e(TF)m(ORM2,)i(whic)m(h)e(is)g(probably)0
+668 y(not)h(what)f(w)m(as)h(in)m(tended!)0 1000 y Fd(5.3)135
+b(T)-11 b(emplate)46 b(P)l(arser)g(Directiv)l(es)0 1251
+y Fi(In)29 b(addition)g(to)h(the)g(template)h(lines)d(whic)m(h)h
+(de\014ne)g(individual)d(k)m(eyw)m(ords,)k(the)g(template)h(parser)e
+(recognizes)0 1363 y(3)h(sp)s(ecial)f(directiv)m(es)g(whic)m(h)g(are)h
+(eac)m(h)h(preceded)f(b)m(y)f(the)h(bac)m(kslash)g(c)m(haracter:)90
+b Fe(\\include,)45 b(\\group)p Fi(,)29 b(and)48 1476
+y Fe(\\end)p Fi(.)0 1637 y(The)37 b('include')f(directiv)m(e)i(m)m(ust)
+f(b)s(e)h(follo)m(w)m(ed)f(b)m(y)h(a)g(\014lename.)62
+b(It)38 b(forces)g(the)g(parser)f(to)i(temp)s(orarily)d(stop)0
+1749 y(reading)e(the)h(curren)m(t)g(template)g(\014le)f(and)g(b)s(egin)
+g(reading)g(the)h(include)d(\014le.)54 b(Once)35 b(the)g(parser)f(reac)
+m(hes)i(the)0 1862 y(end)f(of)h(the)g(include)d(\014le)i(it)g(con)m
+(tin)m(ues)g(parsing)g(the)g(curren)m(t)h(template)g(\014le.)55
+b(Include)34 b(\014les)h(can)h(b)s(e)f(nested,)0 1975
+y(and)30 b(HDU)h(de\014nitions)d(can)i(span)g(m)m(ultiple)e(template)j
+(\014les.)0 2135 y(The)g(start)h(of)g(a)g(GR)m(OUP)h(de\014nition)c(is)
+i(denoted)h(with)e(the)i('group')g(directiv)m(e,)f(and)h(the)f(end)h
+(of)f(a)i(GR)m(OUP)0 2248 y(de\014nition)i(is)i(denoted)g(with)f(the)i
+('end')f(directiv)m(e.)61 b(Eac)m(h)39 b(GR)m(OUP)e(con)m(tains)h(0)g
+(or)f(more)h(mem)m(b)s(er)f(blo)s(c)m(ks)0 2361 y(\(HDUs)44
+b(or)f(GR)m(OUPs\).)79 b(Mem)m(b)s(er)42 b(blo)s(c)m(ks)h(of)g(t)m(yp)s
+(e)g(GR)m(OUP)g(can)g(con)m(tain)g(their)f(o)m(wn)h(mem)m(b)s(er)f(blo)
+s(c)m(ks.)0 2474 y(The)32 b(GR)m(OUP)g(de\014nition)e(itself)h(o)s
+(ccupies)h(one)g(FITS)g(\014le)f(HDU)i(of)f(sp)s(ecial)f(t)m(yp)s(e)h
+(\(GR)m(OUP)h(HDU\),)h(so)e(if)g(a)0 2587 y(template)f(sp)s(eci\014es)e
+(1)i(group)e(with)g(1)i(mem)m(b)s(er)f(HDU)h(lik)m(e:)0
+2838 y Fe(\\group)0 2951 y(grpdescr)46 b(=)h('demo')0
+3064 y(xtension)f(bintable)0 3177 y(#)h(this)g(bintable)f(has)h(0)g
+(cols,)f(0)i(rows)0 3290 y(\\end)0 3541 y Fi(then)30
+b(the)h(parser)e(creates)j(a)f(FITS)f(\014le)f(with)g(3)i(HDUs)g(:)0
+3792 y Fe(1\))47 b(dummy)g(PHDU)0 3905 y(2\))g(GROUP)g(HDU)f(\(has)h(1)
+h(member,)d(which)i(is)g(bintable)e(in)j(HDU)f(number)f(3\))0
+4018 y(3\))h(bintable)f(\(member)g(of)h(GROUP)f(in)h(HDU)g(number)f
+(2\))0 4269 y Fi(T)-8 b(ec)m(hnically)29 b(sp)s(eaking,)g(the)g(GR)m
+(OUP)i(HDU)f(is)f(a)h(BINT)-8 b(ABLE)30 b(with)f(6)h(columns.)39
+b(Applications)28 b(can)i(de\014ne)0 4382 y(additional)20
+b(columns)h(in)f(a)j(GR)m(OUP)f(HDU)h(using)e(TF)m(ORMn)g(and)h(TTYPEn)
+f(\(where)g(n)h(is)f(7,)j(8,)h(....\))39 b(k)m(eyw)m(ords)0
+4494 y(or)30 b(their)g(auto-indexing)f(equiv)-5 b(alen)m(ts.)0
+4655 y(F)d(or)26 b(a)f(more)g(complicated)f(example)g(of)h(a)h
+(template)f(\014le)f(using)f(the)i(group)f(directiv)m(es,)i(lo)s(ok)e
+(at)h(the)g(sample.tpl)0 4767 y(\014le)k(that)i(is)f(included)d(in)j
+(the)g(CFITSIO)f(distribution.)0 5100 y Fd(5.4)135 b(F)-11
+b(ormal)46 b(T)-11 b(emplate)45 b(Syn)l(tax)0 5350 y
+Fi(The)30 b(template)h(syn)m(tax)g(can)f(formally)f(b)s(e)h(de\014ned)f
+(as)i(follo)m(ws:)191 5601 y Fe(TEMPLATE)45 b(=)j(BLOCK)e([)i(BLOCK)e
+(...)h(])p eop
+%%Page: 44 50
+44 49 bop 0 299 a Fi(44)2340 b Fg(CHAPTER)30 b(5.)71
+b(TEMPLA)-8 b(TE)30 b(FILES)334 555 y Fe(BLOCK)46 b(=)i({)f(HDU)g(|)h
+(GROUP)e(})334 781 y(GROUP)g(=)i(\\GROUP)e([)h(BLOCK)g(...)g(])g(\\END)
+430 1007 y(HDU)f(=)i(XTENSION)d([)j(LINE)f(...)f(])i({)f(XTENSION)f(|)h
+(\\GROUP)f(|)i(\\END)f(|)g(EOF)g(})382 1233 y(LINE)f(=)i([)f(KEYWORD)f
+([)i(=)f(])h(])f([)g(VALUE)g(])g([)h(/)f(COMMENT)f(])191
+1458 y(X)h(...)238 b(-)48 b(X)f(can)g(be)g(present)f(1)h(or)h(more)e
+(times)191 1571 y({)h(X)h(|)f(Y)h(})f(-)h(X)f(or)g(Y)191
+1684 y([)g(X)h(])238 b(-)48 b(X)f(is)g(optional)0 1937
+y Fi(A)m(t)34 b(the)f(topmost)g(lev)m(el,)g(the)g(template)h(de\014nes)
+d(1)j(or)e(more)h(template)g(blo)s(c)m(ks.)48 b(Blo)s(c)m(ks)33
+b(can)g(b)s(e)f(either)g(HDU)0 2050 y(\(Header)27 b(Data)h(Unit\))f(or)
+f(a)h(GR)m(OUP)-8 b(.)28 b(F)-8 b(or)27 b(eac)m(h)g(blo)s(c)m(k)f(the)h
+(parser)f(creates)i(1)f(\(or)g(more)f(for)h(GR)m(OUPs\))g(FITS)0
+2163 y(\014le)i(HDUs.)0 2495 y Fd(5.5)135 b(Errors)0
+2745 y Fi(In)24 b(general)g(the)g(\014ts)p 692 2745 28
+4 v 33 w(execute)p 1019 2745 V 34 w(template\(\))h(function)e(tries)h
+(to)h(b)s(e)f(as)g(atomic)h(as)g(p)s(ossible,)e(so)h(either)g(ev)m
+(erything)0 2858 y(is)f(done)h(or)g(nothing)e(is)h(done.)39
+b(If)23 b(an)h(error)f(o)s(ccurs)h(during)e(parsing)g(of)i(the)g
+(template,)i(\014ts)p 3125 2858 V 33 w(execute)p 3452
+2858 V 34 w(template\(\))0 2971 y(will)i(\(try)j(to\))h(delete)f(the)g
+(top)g(lev)m(el)f(BLOCK)g(\(with)g(all)f(its)i(c)m(hildren)d(if)i(an)m
+(y\))h(in)f(whic)m(h)f(the)i(error)f(o)s(ccurred,)0 3084
+y(then)g(it)g(will)e(stop)i(reading)g(the)g(template)h(\014le)e(and)h
+(it)g(will)e(return)h(with)g(an)h(error.)0 3417 y Fd(5.6)135
+b(Examples)0 3667 y Fi(1.)54 b(This)33 b(template)i(\014le)f(will)e
+(create)k(a)f(200)h(x)e(300)i(pixel)d(image,)k(with)c(4-b)m(yte)j(in)m
+(teger)f(pixel)e(v)-5 b(alues,)35 b(in)f(the)0 3780 y(primary)28
+b(HDU:)95 4032 y Fe(SIMPLE)47 b(=)g(T)95 4145 y(BITPIX)g(=)g(32)95
+4258 y(NAXIS)g(=)g(2)239 b(/)47 b(number)f(of)h(dimensions)95
+4371 y(NAXIS1)g(=)g(100)95 b(/)47 b(length)f(of)h(first)g(axis)95
+4484 y(NAXIS2)g(=)g(200)95 b(/)47 b(length)f(of)h(second)f(axis)95
+4597 y(OBJECT)h(=)g(NGC)g(253)g(/)g(name)g(of)g(observed)f(object)0
+4850 y Fi(The)35 b(allo)m(w)m(ed)g(v)-5 b(alues)35 b(of)g(BITPIX)g(are)
+h(8,)h(16,)h(32,)g(-32,)g(or)d(-64,)j(represen)m(ting,)e(resp)s(ectiv)m
+(ely)-8 b(,)37 b(8-bit)e(in)m(teger,)0 4962 y(16-bit)c(in)m(teger,)g
+(32-bit)f(in)m(teger,)h(32-bit)g(\015oating)f(p)s(oin)m(t,)g(or)g(64)h
+(bit)f(\015oating)g(p)s(oin)m(t)f(pixels.)0 5123 y(2.)39
+b(T)-8 b(o)23 b(create)h(a)f(FITS)e(table,)k(the)d(template)h(\014rst)f
+(needs)g(to)i(include)c(XTENSION)i(=)g(T)-8 b(ABLE)23
+b(or)f(BINT)-8 b(ABLE)0 5235 y(to)31 b(de\014ne)e(whether)g(it)g(is)g
+(an)g(ASCI)s(I)g(or)g(binary)f(table,)i(and)g(NAXIS2)g(to)g(de\014ne)f
+(the)h(n)m(um)m(b)s(er)f(of)h(ro)m(ws)f(in)g(the)0 5348
+y(table.)49 b(Tw)m(o)34 b(template)f(lines)f(are)i(then)f(needed)f(to)i
+(de\014ne)f(the)g(name)h(\(TTYPEn\))e(and)h(FITS)g(data)h(format)0
+5461 y(\(TF)m(ORMn\))d(of)f(the)h(columns,)e(as)i(in)e(this)g(example:)
+95 5714 y Fe(xtension)46 b(=)h(bintable)p eop
+%%Page: 45 51
+45 50 bop 0 299 a Fg(5.6.)72 b(EXAMPLES)3084 b Fi(45)95
+555 y Fe(naxis2)47 b(=)g(40)95 668 y(ttype#)g(=)g(Name)95
+781 y(tform#)g(=)g(10a)95 894 y(ttype#)g(=)g(Npoints)95
+1007 y(tform#)g(=)g(j)95 1120 y(ttype#)g(=)g(Rate)95
+1233 y(tunit#)g(=)g(counts/s)95 1346 y(tform#)g(=)g(e)0
+1605 y Fi(The)26 b(ab)s(o)m(v)m(e)j(example)d(de\014nes)g(a)i(n)m(ull)d
+(primary)g(arra)m(y)i(follo)m(w)m(ed)g(b)m(y)g(a)g(40-ro)m(w)h(binary)d
+(table)i(extension)g(with)f(3)0 1718 y(columns)h(called)g('Name',)j
+('Np)s(oin)m(ts',)e(and)g('Rate',)i(with)d(data)i(formats)f(of)g('10A')
+i(\(ASCI)s(I)d(c)m(haracter)i(string\),)0 1831 y('1J')k(\(in)m(teger\))
+h(and)e('1E')i(\(\015oating)e(p)s(oin)m(t\),)h(resp)s(ectiv)m(ely)-8
+b(.)48 b(Note)34 b(that)f(the)g(other)g(required)e(FITS)h(k)m(eyw)m
+(ords)0 1944 y(\(BITPIX,)37 b(NAXIS,)g(NAXIS1,)h(PCOUNT,)e(GCOUNT,)h
+(TFIELDS,)f(and)g(END\))h(do)g(not)g(need)f(to)h(b)s(e)f(ex-)0
+2057 y(plicitly)f(de\014ned)h(in)h(the)g(template)h(b)s(ecause)g(their)
+f(v)-5 b(alues)37 b(can)h(b)s(e)f(inferred)e(from)j(the)f(other)h(k)m
+(eyw)m(ords)g(in)0 2170 y(the)d(template.)54 b(This)33
+b(example)i(also)g(illustrates)d(that)k(the)f(templates)g(are)g
+(generally)f(case-insensitiv)m(e)g(\(the)0 2283 y(k)m(eyw)m(ord)29
+b(names)g(and)g(TF)m(ORMn)f(v)-5 b(alues)29 b(are)g(con)m(v)m(erted)i
+(to)e(upp)s(er-case)g(in)e(the)i(FITS)g(\014le\))f(and)g(that)i(string)
+0 2396 y(k)m(eyw)m(ord)h(v)-5 b(alues)30 b(generally)f(do)h(not)h(need)
+f(to)h(b)s(e)f(enclosed)g(in)f(quotes.)p eop
+%%Page: 46 52
+46 51 bop 0 299 a Fi(46)2340 b Fg(CHAPTER)30 b(5.)71
+b(TEMPLA)-8 b(TE)30 b(FILES)p eop
+%%Page: 47 53
+47 52 bop 0 1225 a Ff(Chapter)65 b(6)0 1687 y Fl(FITSIO)76
+b(Con)-6 b(v)g(en)g(tions)76 b(and)h(Guidelines)0 2216
+y Fd(6.1)135 b(CFITSIO)44 b(Size)h(Limitations)0 2476
+y Fi(CFITSIO)31 b(places)h(few)h(restrictions)e(on)i(the)f(size)h(of)f
+(FITS)g(\014les)g(that)h(it)f(reads)g(or)h(writes.)46
+b(There)32 b(are)h(a)g(few)0 2589 y(limits,)28 b(ho)m(w)m(ev)m(er,)k
+(whic)m(h)d(ma)m(y)i(a\013ect)h(some)f(extreme)g(cases:)0
+2749 y(1.)43 b(The)31 b(maxim)m(um)f(n)m(um)m(b)s(er)g(of)h(FITS)f
+(\014les)g(that)i(ma)m(y)g(b)s(e)e(sim)m(ultaneously)f(op)s(ened)i(b)m
+(y)g(CFITSIO)e(is)h(set)i(b)m(y)0 2862 y(NMAXFILES)i(as)g(de\014ned)f
+(in)g(\014tsio2.h.)51 b(It)34 b(is)f(curren)m(tly)g(set)i(=)f(300)h(b)m
+(y)f(default.)51 b(CFITSIO)32 b(will)f(allo)s(cate)0
+2975 y(ab)s(out)i(80)g(*)h(NMAXFILES)f(b)m(ytes)g(of)g(memory)g(for)g
+(in)m(ternal)e(use.)48 b(Note)34 b(that)g(the)f(underlying)d(C)i
+(compiler)0 3088 y(or)39 b(op)s(erating)g(system,)k(ma)m(y)d(ha)m(v)m
+(e)g(a)g(smaller)e(limit)g(on)h(the)h(n)m(um)m(b)s(er)e(of)i(op)s(ened)
+e(\014les.)67 b(The)39 b(C)h(sym)m(b)s(olic)0 3201 y(constan)m(t)31
+b(F)m(OPEN)p 690 3201 28 4 v 34 w(MAX)f(is)f(in)m(tended)g(to)i
+(de\014ne)e(the)i(maxim)m(um)e(n)m(um)m(b)s(er)f(of)j(\014les)e(that)h
+(ma)m(y)h(op)s(en)e(at)i(once)0 3314 y(\(including)d(an)m(y)j(other)g
+(text)h(or)f(binary)e(\014les)h(that)i(ma)m(y)f(b)s(e)g(op)s(en,)f(not)
+h(just)g(FITS)f(\014les\).)42 b(On)30 b(some)h(systems)0
+3427 y(it)f(has)g(b)s(een)g(found)f(that)i(gcc)g(supp)s(orts)e(a)h
+(maxim)m(um)g(of)g(255)i(op)s(ened)e(\014les.)0 3587
+y(Note)d(that)e(op)s(ening)f(and)h(op)s(erating)g(on)g(man)m(y)g(FITS)g
+(\014les)f(sim)m(ultaneously)f(in)h(parallel)f(ma)m(y)j(b)s(e)f(less)f
+(e\016cien)m(t)0 3700 y(than)k(op)s(erating)g(on)g(smaller)f(groups)h
+(of)h(\014les)e(in)g(series.)40 b(CFITSIO)27 b(only)g(has)h(NIOBUF)h(n)
+m(um)m(b)s(er)f(of)g(in)m(ternal)0 3813 y(bu\013ers)j(\(set)j(=)e(40)i
+(b)m(y)e(default\))h(that)g(are)g(used)f(for)g(temp)s(orary)g(storage)i
+(of)f(the)g(most)g(recen)m(t)h(data)f(records)0 3926
+y(that)40 b(ha)m(v)m(e)g(b)s(een)e(read)h(or)g(written)f(in)f(the)i
+(FITS)f(\014les.)66 b(If)38 b(the)h(n)m(um)m(b)s(er)f(of)h(op)s(ened)f
+(\014les)g(is)g(greater)i(than)0 4039 y(NIOBUF,)j(then)f(CFITSIO)e(ma)m
+(y)j(w)m(aste)h(more)e(time)g(\015ushing)d(and)j(re-reading)g(or)g
+(re-writing)e(the)j(same)0 4152 y(records)30 b(in)f(the)i(FITS)e
+(\014les.)0 4312 y(2.)54 b(By)35 b(default,)g(CFITSIO)e(can)i(handle)f
+(FITS)g(\014les)f(up)h(to)h(2.1)h(GB)g(in)d(size)i(\(2**31)i(b)m
+(ytes\).)54 b(This)33 b(\014le)h(size)0 4425 y(limit)k(is)i(often)g
+(imp)s(osed)f(b)m(y)h(32-bit)h(op)s(erating)e(systems.)71
+b(More)41 b(recen)m(tly)-8 b(,)44 b(as)d(64-bit)f(op)s(erating)g
+(systems)0 4538 y(b)s(ecome)33 b(more)g(common,)g(an)g(industry-wide)c
+(standard)j(\(at)i(least)e(on)h(Unix)e(systems\))i(has)g(b)s(een)f(dev)
+m(elop)s(ed)0 4650 y(to)39 b(supp)s(ort)d(larger)h(sized)h(\014les)f
+(\(see)h(h)m(ttp://ftp.sas.com/standards/large.\014le/\).)66
+b(Starting)38 b(with)e(v)m(ersion)0 4763 y(2.1)45 b(of)e(CFITSIO,)f
+(larger)h(FITS)g(\014les)f(up)h(to)h(6)g(terab)m(ytes)h(in)d(size)h(ma)
+m(y)h(b)s(e)f(read)g(and)g(written)g(on)g(sup-)0 4876
+y(p)s(orted)f(platforms.)75 b(In)42 b(order)g(to)h(supp)s(ort)e(these)h
+(larger)g(\014les,)j(CFITSIO)c(m)m(ust)h(b)s(e)g(compiled)f(with)g(the)
+0 4989 y('-D)p 129 4989 V 34 w(LAR)m(GEFILE)p 696 4989
+V 33 w(SOUR)m(CE')h(and)g(`-D)p 1491 4989 V 34 w(FILE)p
+1736 4989 V 33 w(OFFSET)p 2137 4989 V 32 w(BITS=64')h(compiler)e
+(\015ags.)78 b(Some)43 b(platforms)0 5102 y(ma)m(y)c(also)f(require)f
+(the)h(`-D)p 1002 5102 V 34 w(LAR)m(GE)p 1358 5102 V
+33 w(FILES')g(compiler)f(\015ag.)64 b(This)37 b(causes)h(the)h
+(compiler)e(to)i(allo)s(cate)f(8-)0 5215 y(b)m(ytes)44
+b(instead)f(of)h(4-b)m(ytes)h(for)f(the)g(`o\013)p 1473
+5215 V 33 w(t')g(datat)m(yp)s(e)h(whic)m(h)e(is)f(used)h(to)i(store)f
+(\014le)f(o\013set)i(p)s(ositions.)79 b(It)0 5328 y(app)s(ears)31
+b(that)i(in)d(most)j(cases)g(it)e(is)g(not)h(necessary)h(to)f(also)g
+(include)e(these)i(compiler)f(\015ags)h(when)f(compiling)0
+5441 y(programs)f(that)h(link)d(to)j(the)g(CFITSIO)e(library)-8
+b(.)0 5601 y(If)21 b(CFITSIO)e(is)h(compiled)g(with)g(the)h(-D)p
+1386 5601 V 33 w(LAR)m(GEFILE)p 1952 5601 V 34 w(SOUR)m(CE)f(and)g(-D)p
+2654 5601 V 34 w(FILE)p 2899 5601 V 33 w(OFFSET)p 3300
+5601 V 32 w(BITS=64)h(\015ags)0 5714 y(on)36 b(a)g(platform)f(that)h
+(supp)s(orts)e(large)i(\014les,)h(then)e(it)h(can)g(read)g(and)f(write)
+g(FITS)g(\014les)g(that)h(con)m(tain)g(up)f(to)1905 5942
+y(47)p eop
+%%Page: 48 54
+48 53 bop 0 299 a Fi(48)1277 b Fg(CHAPTER)29 b(6.)72
+b(FITSIO)29 b(CONVENTIONS)g(AND)i(GUIDELINES)0 555 y
+Fi(2**31)39 b(2880-b)m(yte)g(FITS)d(records,)j(or)d(appro)m(ximately)g
+(6)h(terab)m(ytes)h(in)e(size.)59 b(It)37 b(is)f(still)f(required)f
+(that)k(the)0 668 y(v)-5 b(alue)29 b(of)g(the)g(NAXISn)f(and)h(PCOUNT)f
+(k)m(eyw)m(ords)h(in)f(eac)m(h)i(extension)f(b)s(e)f(within)f(the)i
+(range)h(of)f(a)g(signed)f(4-)0 781 y(b)m(yte)d(in)m(teger)g(\(max)g(v)
+-5 b(alue)25 b(=)f(2,147,483,648\).)44 b(Th)m(us,)25
+b(eac)m(h)h(dimension)c(of)j(an)f(image)h(\(giv)m(en)g(b)m(y)g(the)g
+(NAXISn)0 894 y(k)m(eyw)m(ords\),)32 b(the)f(total)h(width)d(of)i(a)g
+(table)g(\(NAXIS1)h(k)m(eyw)m(ord\),)g(the)f(n)m(um)m(b)s(er)f(of)h(ro)
+m(ws)g(in)e(a)i(table)g(\(NAXIS2)0 1007 y(k)m(eyw)m(ord\),)d(and)d(the)
+h(total)h(size)f(of)g(the)g(v)-5 b(ariable-length)25
+b(arra)m(y)h(heap)g(in)f(binary)f(tables)i(\(PCOUNT)f(k)m(eyw)m(ord\))0
+1120 y(m)m(ust)30 b(b)s(e)g(less)g(than)g(this)f(limit.)0
+1280 y(Curren)m(tly)-8 b(,)30 b(supp)s(ort)f(for)i(large)g(\014les)f
+(within)e(CFITSIO)h(has)i(b)s(een)f(tested)i(on)f(the)g(Lin)m(ux,)f
+(Solaris,)f(and)h(IBM)0 1393 y(AIX)g(op)s(erating)g(systems.)0
+1750 y Fd(6.2)135 b(Multiple)46 b(Access)e(to)i(the)f(Same)g(FITS)f
+(File)0 2005 y Fi(CFITSIO)35 b(supp)s(orts)g(sim)m(ultaneous)g(read)h
+(and)g(write)g(access)h(to)h(m)m(ultiple)c(HDUs)j(in)e(the)i(same)g
+(FITS)f(\014le.)0 2118 y(Th)m(us,)43 b(one)e(can)h(op)s(en)e(the)h
+(same)h(FITS)e(\014le)g(t)m(wice)i(within)c(a)k(single)d(program)i(and)
+g(mo)m(v)m(e)h(to)g(2)f(di\013eren)m(t)0 2231 y(HDUs)30
+b(in)e(the)i(\014le,)f(and)g(then)g(read)h(and)e(write)h(data)h(or)g(k)
+m(eyw)m(ords)g(to)g(the)g(2)f(extensions)h(just)e(as)i(if)f(one)g(w)m
+(ere)0 2344 y(accessing)e(2)g(completely)f(separate)h(FITS)f(\014les.)
+38 b(Since)26 b(in)f(general)h(it)g(is)g(not)h(p)s(ossible)d(to)j(ph)m
+(ysically)d(op)s(en)i(the)0 2457 y(same)36 b(\014le)f(t)m(wice)h(and)f
+(then)g(exp)s(ect)h(to)g(b)s(e)f(able)g(to)i(sim)m(ultaneously)c(\(or)j
+(in)e(alternating)h(succession\))h(write)0 2570 y(to)f(2)f(di\013eren)m
+(t)g(lo)s(cations)g(in)e(the)j(\014le,)f(CFITSIO)f(recognizes)i(when)e
+(the)h(\014le)f(to)i(b)s(e)f(op)s(ened)f(\(in)g(the)i(call)e(to)0
+2683 y(\014ts)p 127 2683 28 4 v 32 w(op)s(en)p 349 2683
+V 33 w(\014le\))28 b(has)g(already)g(b)s(een)g(op)s(ened)g(and)g
+(instead)g(of)h(actually)f(op)s(ening)f(the)i(\014le)f(again,)h(just)f
+(logically)0 2796 y(links)g(the)j(new)f(\014le)g(to)h(the)g(old)e
+(\014le.)41 b(\(This)29 b(only)h(applies)e(if)i(the)h(\014le)e(is)h(op)
+s(ened)g(more)g(than)g(once)i(within)c(the)0 2908 y(same)g(program,)g
+(and)f(do)s(es)h(not)f(prev)m(en)m(t)i(the)f(same)g(\014le)e(from)h(b)s
+(eing)g(sim)m(ultaneously)e(op)s(ened)i(b)m(y)g(more)h(than)0
+3021 y(one)h(program\).)40 b(Then)28 b(b)s(efore)g(CFITSIO)f(reads)h
+(or)h(writes)f(to)h(either)f(\(logical\))h(\014le,)f(it)g(mak)m(es)i
+(sure)d(that)j(an)m(y)0 3134 y(mo)s(di\014cations)g(made)h(to)h(the)g
+(other)g(\014le)e(ha)m(v)m(e)j(b)s(een)e(completely)g(\015ushed)e(from)
+i(the)h(in)m(ternal)e(bu\013ers)h(to)h(the)0 3247 y(\014le.)43
+b(Th)m(us,)30 b(in)g(principle,)f(one)i(could)f(op)s(en)h(a)h(\014le)e
+(t)m(wice,)i(in)e(one)i(case)g(p)s(oin)m(ting)e(to)i(the)f(\014rst)g
+(extension)g(and)0 3360 y(in)i(the)i(other)g(p)s(oin)m(ting)d(to)k(the)
+e(2nd)g(extension)h(and)e(then)i(write)e(data)j(to)f(b)s(oth)f
+(extensions,)h(in)e(an)m(y)i(order,)0 3473 y(without)24
+b(danger)i(of)f(corrupting)g(the)g(\014le,)h(There)f(ma)m(y)h(b)s(e)f
+(some)h(e\016ciency)f(p)s(enalties)f(in)g(doing)h(this)f(ho)m(w)m(ev)m
+(er,)0 3586 y(since)j(CFITSIO)g(has)h(to)h(\015ush)d(all)h(the)h(in)m
+(ternal)f(bu\013ers)g(related)h(to)h(one)f(\014le)f(b)s(efore)h(switc)m
+(hing)e(to)j(the)f(other,)0 3699 y(so)i(it)g(w)m(ould)f(still)f(b)s(e)i
+(pruden)m(t)f(to)i(minimize)d(the)i(n)m(um)m(b)s(er)f(of)i(times)e(one)
+i(switc)m(hes)f(bac)m(k)h(and)e(forth)h(b)s(et)m(w)m(een)0
+3812 y(doing)f(I/O)i(to)g(di\013eren)m(t)f(HDUs)h(in)e(the)h(same)h
+(\014le.)0 4169 y Fd(6.3)135 b(Curren)l(t)46 b(Header)f(Data)h(Unit)g
+(\(CHDU\))0 4424 y Fi(In)32 b(general,)i(a)g(FITS)e(\014le)h(can)g(con)
+m(tain)g(m)m(ultiple)e(Header)j(Data)h(Units,)e(also)g(called)f
+(extensions.)48 b(CFITSIO)0 4537 y(only)37 b(op)s(erates)i(within)d
+(one)i(HDU)h(at)g(an)m(y)g(giv)m(en)f(time,)i(and)e(the)g(curren)m(tly)
+f(selected)i(HDU)g(is)e(called)h(the)0 4650 y(Curren)m(t)h(Header)h
+(Data)h(Unit)e(\(CHDU\).)i(When)f(a)g(FITS)f(\014le)g(is)f(\014rst)h
+(created)i(or)f(op)s(ened)f(the)h(CHDU)g(is)0 4763 y(automatically)25
+b(de\014ned)e(to)j(b)s(e)e(the)h(\014rst)f(HDU)i(\(i.e.,)g(the)f
+(primary)e(arra)m(y\).)40 b(CFITSIO)23 b(routines)h(are)h(pro)m(vided)0
+4876 y(to)36 b(mo)m(v)m(e)h(to)g(and)e(op)s(en)g(an)m(y)h(other)g
+(existing)e(HDU)j(within)c(the)j(FITS)f(\014le)f(or)i(to)g(app)s(end)e
+(or)i(insert)e(a)i(new)0 4989 y(HDU)31 b(in)e(the)i(FITS)e(\014le)h
+(whic)m(h)f(then)h(b)s(ecomes)h(the)f(CHDU.)0 5346 y
+Fd(6.4)135 b(Subroutine)45 b(Names)0 5601 y Fi(All)24
+b(FITSIO)h(subroutine)f(names)i(b)s(egin)e(with)h(the)h(letters)g('ft')
+g(to)h(distinguish)22 b(them)k(from)f(other)h(subroutines)0
+5714 y(and)34 b(are)h(5)g(or)f(6)h(c)m(haracters)h(long.)53
+b(Users)34 b(should)f(not)h(name)h(their)f(o)m(wn)g(subroutines)e(b)s
+(eginning)g(with)h('ft')p eop
+%%Page: 49 55
+49 54 bop 0 299 a Fg(6.5.)72 b(SUBR)m(OUTINE)30 b(F)-10
+b(AMILIES)30 b(AND)h(D)m(A)-8 b(T)g(A)g(TYPES)1697 b
+Fi(49)0 555 y(to)32 b(a)m(v)m(oid)h(con\015icts.)44 b(\(The)32
+b(SPP)f(in)m(terface)h(routines)e(all)h(b)s(egin)f(with)h('fs'\).)45
+b(Subroutines)29 b(whic)m(h)h(read)i(or)g(get)0 668 y(information)c
+(from)i(the)h(FITS)e(\014le)g(ha)m(v)m(e)j(names)e(b)s(eginning)d(with)
+i('ftg...'.)43 b(Subroutines)27 b(whic)m(h)i(write)g(or)i(put)0
+781 y(information)e(in)m(to)h(the)h(FITS)e(\014le)h(ha)m(v)m(e)h(names)
+g(b)s(eginning)c(with)i('ftp...'.)0 1274 y Fd(6.5)135
+b(Subroutine)45 b(F)-11 b(amilies)46 b(and)f(Datat)l(yp)t(es)0
+1556 y Fi(Man)m(y)h(of)g(the)g(subroutines)d(come)k(in)d(families)f
+(whic)m(h)i(di\013er)f(only)h(in)f(the)i(datat)m(yp)s(e)g(of)g(the)f
+(asso)s(ciated)0 1669 y(parameter\(s\))34 b(.)47 b(The)32
+b(datat)m(yp)s(e)i(of)f(these)g(subroutines)d(is)i(indicated)f(b)m(y)i
+(the)g(last)f(letter)h(of)g(the)g(subroutine)0 1781 y(name)d(\(e.g.,)j
+('j')d(in)f('ftpkyj'\))i(as)f(follo)m(ws:)382 2176 y
+Fe(x)47 b(-)h(bit)382 2289 y(b)f(-)h(character*1)c(\(unsigned)i(byte\))
+382 2402 y(i)h(-)h(short)e(integer)g(\(I*2\))382 2515
+y(j)h(-)h(integer)e(\(I*4\))382 2628 y(e)h(-)h(real)e(exponential)f
+(floating)h(point)g(\(R*4\))382 2741 y(f)h(-)h(real)e(fixed-format)f
+(floating)g(point)i(\(R*4\))382 2854 y(d)g(-)h(double)e(precision)f
+(real)i(floating-point)d(\(R*8\))382 2967 y(g)j(-)h(double)e(precision)
+f(fixed-format)g(floating)g(point)h(\(R*8\))382 3079
+y(c)h(-)h(complex)e(reals)g(\(pairs)g(of)h(R*4)g(values\))382
+3192 y(m)g(-)h(double)e(precision)f(complex)h(\(pairs)g(of)h(R*8)g
+(values\))382 3305 y(l)g(-)h(logical)e(\(L*4\))382 3418
+y(s)h(-)h(character)d(string)0 3813 y Fi(When)23 b(dealing)f(with)g
+(the)h(FITS)g(b)m(yte)g(datat)m(yp)s(e,)j(it)d(is)f(imp)s(ortan)m(t)h
+(to)g(remem)m(b)s(er)g(that)h(the)f(ra)m(w)g(v)-5 b(alues)23
+b(\(b)s(efore)0 3926 y(an)m(y)i(scaling)e(b)m(y)h(the)h(BSCALE)e(and)h
+(BZER)m(O,)g(or)h(TSCALn)d(and)i(TZER)m(On)f(k)m(eyw)m(ord)i(v)-5
+b(alues\))24 b(in)f(b)m(yte)i(arra)m(ys)0 4039 y(\(BITPIX)37
+b(=)f(8\))h(or)f(b)m(yte)i(columns)d(\(TF)m(ORMn)i(=)f('B'\))h(are)g
+(in)m(terpreted)f(as)h(unsigned)d(b)m(ytes)j(with)f(v)-5
+b(alues)0 4152 y(ranging)39 b(from)g(0)i(to)f(255.)71
+b(Some)40 b(F)-8 b(ortran)40 b(compilers)f(supp)s(ort)f(a)i
+(non-standard)f(b)m(yte)h(datat)m(yp)s(e)h(suc)m(h)f(as)0
+4264 y(INTEGER*1,)34 b(LOGICAL*1,)g(or)f(BYTE,)g(whic)m(h)e(can)i
+(sometimes)g(b)s(e)f(used)g(instead)g(of)h(CHARA)m(CTER*1)0
+4377 y(v)-5 b(ariables.)37 b(Man)m(y)23 b(mac)m(hines)f(p)s(ermit)g
+(passing)f(a)i(n)m(umeric)f(datat)m(yp)s(e)h(\(suc)m(h)g(as)g
+(INTEGER*1\))h(to)f(the)g(FITSIO)0 4490 y(subroutines)40
+b(whic)m(h)i(are)h(exp)s(ecting)f(a)h(CHARA)m(CTER*1)h(datat)m(yp)s(e,)
+j(but)42 b(this)f(tec)m(hnically)h(violates)h(the)0 4603
+y(F)-8 b(ortran-77)29 b(standard)d(and)g(is)g(not)h(supp)s(orted)e(on)i
+(all)f(mac)m(hines)g(\(e.g.,)k(on)c(a)i(V)-10 b(AX/VMS)27
+b(mac)m(hine)g(one)g(m)m(ust)0 4716 y(use)j(the)h(V)-10
+b(AX-sp)s(eci\014c)30 b(\045DESCR)f(function\).)0 4876
+y(One)22 b(feature)h(of)g(the)g(CFITSIO)e(routines)h(is)f(that)j(they)f
+(can)g(op)s(erate)g(on)f(a)h(`X')h(\(bit\))e(column)g(in)f(a)i(binary)e
+(table)0 4989 y(as)35 b(though)e(it)h(w)m(ere)h(a)g(`B')g(\(b)m(yte\))g
+(column.)52 b(F)-8 b(or)35 b(example)f(a)g(`11X')i(datat)m(yp)s(e)f
+(column)e(can)i(b)s(e)f(in)m(terpreted)0 5102 y(the)28
+b(same)h(as)f(a)g(`2B')i(column)d(\(i.e.,)i(2)f(unsigned)e(8-bit)i(b)m
+(ytes\).)41 b(In)27 b(some)i(instances,)f(it)f(can)i(b)s(e)e(more)h
+(e\016cien)m(t)0 5215 y(to)j(read)f(and)g(write)g(whole)f(b)m(ytes)i
+(at)g(a)g(time,)f(rather)h(than)f(reading)f(or)i(writing)d(eac)m(h)k
+(individual)25 b(bit.)0 5375 y(The)41 b(double)g(precision)f(complex)h
+(datat)m(yp)s(e)i(is)e(not)h(a)g(standard)f(F)-8 b(ortran-77)43
+b(datat)m(yp)s(e.)76 b(If)41 b(a)i(particular)0 5488
+y(F)-8 b(ortran)35 b(compiler)e(do)s(es)h(not)h(directly)e(supp)s(ort)g
+(this)h(datat)m(yp)s(e,)i(then)f(one)f(ma)m(y)h(instead)f(pass)g(an)h
+(arra)m(y)g(of)0 5601 y(pairs)c(of)i(double)e(precision)g(v)-5
+b(alues)31 b(to)j(these)f(subroutines.)44 b(The)33 b(\014rst)e(v)-5
+b(alue)32 b(in)f(eac)m(h)j(pair)d(is)h(the)h(real)f(part,)0
+5714 y(and)e(the)g(second)h(is)e(the)i(imaginary)e(part.)p
+eop
+%%Page: 50 56
+50 55 bop 0 299 a Fi(50)1277 b Fg(CHAPTER)29 b(6.)72
+b(FITSIO)29 b(CONVENTIONS)g(AND)i(GUIDELINES)0 555 y
+Fd(6.6)135 b(Implicit)46 b(Data)g(T)l(yp)t(e)f(Con)l(v)l(ersion)0
+816 y Fi(The)22 b(FITSIO)g(routines)g(that)i(read)e(and)h(write)f(n)m
+(umerical)f(data)j(can)f(p)s(erform)f(implicit)e(data)j(t)m(yp)s(e)g
+(con)m(v)m(ersion.)0 929 y(This)h(means)h(that)h(the)g(data)g(t)m(yp)s
+(e)g(of)g(the)g(v)-5 b(ariable)24 b(or)i(arra)m(y)g(in)e(the)i(program)
+f(do)s(es)g(not)h(need)g(to)g(b)s(e)f(the)h(same)0 1042
+y(as)i(the)f(data)h(t)m(yp)s(e)g(of)f(the)h(v)-5 b(alue)27
+b(in)f(the)h(FITS)g(\014le.)39 b(Data)28 b(t)m(yp)s(e)g(con)m(v)m
+(ersion)g(is)e(supp)s(orted)g(for)h(n)m(umerical)f(and)0
+1155 y(string)32 b(data)i(t)m(yp)s(es)f(\(if)g(the)h(string)e(con)m
+(tains)h(a)h(v)-5 b(alid)31 b(n)m(um)m(b)s(er)h(enclosed)h(in)f
+(quotes\))i(when)f(reading)f(a)i(FITS)0 1268 y(header)d(k)m(eyw)m(ord)g
+(v)-5 b(alue)30 b(and)h(for)f(n)m(umeric)g(v)-5 b(alues)30
+b(when)g(reading)g(or)h(writing)e(v)-5 b(alues)30 b(in)f(the)i(primary)
+e(arra)m(y)0 1381 y(or)40 b(a)h(table)g(column.)69 b(CFITSIO)39
+b(returns)h(status)g(=)h(NUM)p 2185 1381 28 4 v 33 w(O)m(VERFLO)m(W)g
+(if)f(the)g(con)m(v)m(erted)i(data)f(v)-5 b(alue)0 1493
+y(exceeds)33 b(the)g(range)g(of)g(the)f(output)g(data)i(t)m(yp)s(e.)47
+b(Implicit)30 b(data)j(t)m(yp)s(e)g(con)m(v)m(ersion)g(is)e(not)i(supp)
+s(orted)d(within)0 1606 y(binary)f(tables)h(for)g(string,)f(logical,)i
+(complex,)f(or)g(double)f(complex)h(data)h(t)m(yp)s(es.)0
+1767 y(In)g(addition,)f(an)m(y)h(table)g(column)f(ma)m(y)i(b)s(e)f
+(read)g(as)h(if)e(it)h(con)m(tained)g(string)f(v)-5 b(alues.)43
+b(In)31 b(the)g(case)i(of)e(n)m(umeric)0 1879 y(columns)e(the)i
+(returned)e(string)g(will)f(b)s(e)i(formatted)h(using)d(the)j(TDISPn)e
+(displa)m(y)g(format)h(if)g(it)g(exists.)0 2266 y Fd(6.7)135
+b(Data)46 b(Scaling)0 2527 y Fi(When)38 b(reading)e(n)m(umerical)h
+(data)h(v)-5 b(alues)37 b(in)f(the)i(primary)e(arra)m(y)i(or)g(a)g
+(table)g(column,)h(the)e(v)-5 b(alues)37 b(will)f(b)s(e)0
+2640 y(scaled)h(automatically)h(b)m(y)f(the)h(BSCALE)f(and)g(BZER)m(O)h
+(\(or)g(TSCALn)d(and)i(TZER)m(On\))g(header)g(k)m(eyw)m(ord)0
+2753 y(v)-5 b(alues)32 b(if)f(they)h(are)h(presen)m(t)g(in)e(the)h
+(header.)47 b(The)31 b(scaled)i(data)g(that)g(is)e(returned)g(to)i(the)
+g(reading)e(program)0 2866 y(will)d(ha)m(v)m(e)382 3171
+y Fe(output)46 b(value)g(=)i(\(FITS)e(value\))g(*)i(BSCALE)e(+)h(BZERO)
+0 3476 y Fi(\(a)30 b(corresp)s(onding)d(form)m(ula)h(using)g(TSCALn)f
+(and)i(TZER)m(On)e(is)h(used)h(when)f(reading)g(from)h(table)g
+(columns\).)0 3589 y(In)i(the)i(case)g(of)f(in)m(teger)g(output)g(v)-5
+b(alues)31 b(the)i(\015oating)f(p)s(oin)m(t)f(scaled)g(v)-5
+b(alue)32 b(is)f(truncated)h(to)h(an)f(in)m(teger)g(\(not)0
+3702 y(rounded)38 b(to)i(the)g(nearest)g(in)m(teger\).)69
+b(The)39 b(ftpscl)f(and)h(fttscl)h(subroutines)d(ma)m(y)j(b)s(e)f(used)
+g(to)h(o)m(v)m(erride)g(the)0 3815 y(scaling)28 b(parameters)h
+(de\014ned)e(in)g(the)i(header)f(\(e.g.,)j(to)e(turn)f(o\013)h(the)f
+(scaling)g(so)h(that)g(the)g(program)f(can)h(read)0 3928
+y(the)i(ra)m(w)f(unscaled)f(v)-5 b(alues)30 b(from)g(the)g(FITS)g
+(\014le\).)0 4088 y(When)44 b(writing)f(n)m(umerical)g(data)i(to)g(the)
+g(primary)e(arra)m(y)i(or)f(to)h(a)g(table)g(column)e(the)i(data)g(v)-5
+b(alues)44 b(will)0 4201 y(generally)27 b(b)s(e)h(automatically)g(in)m
+(v)m(ersely)g(scaled)g(b)m(y)g(the)g(v)-5 b(alue)28 b(of)g(the)h
+(BSCALE)e(and)h(BZER)m(O)g(\(or)h(TSCALn)0 4314 y(and)h(TZER)m(On\))g
+(header)g(k)m(eyw)m(ord)h(v)-5 b(alues)30 b(if)g(they)h(they)g(exist)f
+(in)f(the)i(header.)42 b(These)30 b(k)m(eyw)m(ords)h(m)m(ust)g(ha)m(v)m
+(e)0 4426 y(b)s(een)f(written)g(to)i(the)g(header)e(b)s(efore)h(an)m(y)
+h(data)f(is)f(written)h(for)f(them)i(to)f(ha)m(v)m(e)i(an)m(y)e
+(e\013ect.)44 b(Otherwise,)31 b(one)0 4539 y(ma)m(y)j(use)f(the)g
+(ftpscl)f(and)h(fttscl)g(subroutines)d(to)k(de\014ne)f(or)g(o)m(v)m
+(erride)g(the)g(scaling)g(k)m(eyw)m(ords)g(in)f(the)h(header)0
+4652 y(\(e.g.,)h(to)f(turn)d(o\013)j(the)f(scaling)f(so)h(that)g(the)g
+(program)g(can)g(write)f(the)h(ra)m(w)g(unscaled)f(v)-5
+b(alues)31 b(in)m(to)h(the)g(FITS)0 4765 y(\014le\).)42
+b(If)30 b(scaling)g(is)g(p)s(erformed,)f(the)i(in)m(v)m(erse)g(scaled)g
+(output)f(v)-5 b(alue)31 b(that)g(is)f(written)g(in)m(to)h(the)g(FITS)f
+(\014le)g(will)0 4878 y(ha)m(v)m(e)430 5183 y Fe(FITS)46
+b(value)h(=)g(\(\(input)f(value\))g(-)h(BZERO\))f(/)i(BSCALE)0
+5488 y Fi(\(a)39 b(corresp)s(onding)c(form)m(ula)i(using)g(TSCALn)f
+(and)h(TZER)m(On)g(is)g(used)g(when)f(writing)g(to)j(table)f
+(columns\).)0 5601 y(Rounding)18 b(to)j(the)g(nearest)g(in)m(teger,)h
+(rather)f(than)f(truncation,)i(is)d(p)s(erformed)g(when)g(writing)f(in)
+m(teger)j(datat)m(yp)s(es)0 5714 y(to)31 b(the)g(FITS)e(\014le.)p
+eop
+%%Page: 51 57
+51 56 bop 0 299 a Fg(6.8.)72 b(ERR)m(OR)30 b(ST)-8 b(A)g(TUS)30
+b(V)-10 b(ALUES)30 b(AND)h(THE)f(ERR)m(OR)g(MESSA)m(GE)h(ST)-8
+b(A)m(CK)848 b Fi(51)0 555 y Fd(6.8)135 b(Error)46 b(Status)f(V)-11
+b(alues)45 b(and)g(the)g(Error)g(Message)h(Stac)l(k)0
+809 y Fi(The)33 b(last)h(parameter)g(in)f(nearly)g(ev)m(ery)h(FITSIO)f
+(subroutine)f(is)h(the)h(error)f(status)h(v)-5 b(alue)34
+b(whic)m(h)e(is)h(b)s(oth)g(an)0 922 y(input)i(and)g(an)i(output)f
+(parameter.)60 b(A)36 b(returned)f(p)s(ositiv)m(e)h(v)-5
+b(alue)36 b(for)g(this)g(parameter)h(indicates)e(an)h(error)0
+1035 y(w)m(as)31 b(detected.)42 b(A)30 b(listing)e(of)j(all)e(the)i
+(FITSIO)e(status)i(co)s(de)f(v)-5 b(alues)30 b(is)f(giv)m(en)i(at)g
+(the)f(end)g(of)h(this)e(do)s(cumen)m(t.)0 1195 y(The)22
+b(FITSIO)g(library)e(uses)j(an)f(`inherited)f(status')i(con)m(v)m(en)m
+(tion)h(for)f(the)g(status)g(parameter)g(whic)m(h)f(means)g(that)0
+1308 y(if)h(a)i(subroutine)e(is)g(called)h(with)f(a)i(p)s(ositiv)m(e)e
+(input)g(v)-5 b(alue)24 b(of)h(the)f(status)h(parameter,)h(then)f(the)f
+(subroutine)f(will)0 1421 y(exit)i(immediately)d(without)i(c)m(hanging)
+h(the)f(v)-5 b(alue)24 b(of)h(the)g(status)g(parameter.)39
+b(Th)m(us,)25 b(if)f(one)g(passes)h(the)g(status)0 1533
+y(v)-5 b(alue)30 b(returned)f(from)h(eac)m(h)i(FITSIO)d(routine)g(as)i
+(input)e(to)i(the)f(next)h(FITSIO)e(subroutine,)g(then)h(whenev)m(er)0
+1646 y(an)39 b(error)g(is)g(detected)h(all)f(further)f(FITSIO)g(pro)s
+(cessing)g(will)f(cease.)69 b(This)38 b(con)m(v)m(en)m(tion)i(can)g
+(simplify)c(the)0 1759 y(error)30 b(c)m(hec)m(king)i(in)d(application)g
+(programs)i(b)s(ecause)g(it)f(is)g(not)h(necessary)g(to)g(c)m(hec)m(k)i
+(the)e(v)-5 b(alue)30 b(of)h(the)g(status)0 1872 y(parameter)j(after)g
+(ev)m(ery)g(single)f(FITSIO)f(subroutine)f(call.)50 b(If)33
+b(a)h(program)f(con)m(tains)h(a)g(sequence)g(of)g(sev)m(eral)0
+1985 y(FITSIO)23 b(calls,)h(one)g(can)g(just)g(c)m(hec)m(k)h(the)f
+(status)g(v)-5 b(alue)23 b(after)i(the)f(last)f(call.)38
+b(Since)23 b(the)h(returned)e(status)j(v)-5 b(alues)0
+2098 y(are)36 b(generally)f(distinctiv)m(e,)h(it)f(should)f(b)s(e)h(p)s
+(ossible)e(to)j(determine)f(whic)m(h)f(subroutine)g(originally)f
+(returned)0 2211 y(the)e(error)f(status.)0 2371 y(FITSIO)i(also)h(main)
+m(tains)e(an)i(in)m(ternal)f(stac)m(k)i(of)f(error)g(messages)h(\(80-c)
+m(haracter)i(maxim)m(um)c(length\))g(whic)m(h)0 2484
+y(in)j(man)m(y)h(cases)h(pro)m(vide)e(a)h(more)g(detailed)g
+(explanation)f(of)h(the)g(cause)h(of)f(the)g(error)g(than)f(is)g(pro)m
+(vided)g(b)m(y)0 2597 y(the)40 b(error)e(status)i(n)m(um)m(b)s(er)e
+(alone.)68 b(It)39 b(is)g(recommended)g(that)g(the)h(error)f(message)h
+(stac)m(k)h(b)s(e)e(prin)m(ted)f(out)0 2710 y(whenev)m(er)31
+b(a)h(program)g(detects)g(a)g(FITSIO)e(error.)44 b(T)-8
+b(o)32 b(do)f(this,)g(call)g(the)h(FTGMSG)g(routine)e(rep)s(eatedly)h
+(to)0 2823 y(get)i(the)g(successiv)m(e)f(messages)i(on)e(the)g(stac)m
+(k.)48 b(When)32 b(the)h(stac)m(k)g(is)f(empt)m(y)g(FTGMSG)h(will)d
+(return)h(a)h(blank)0 2936 y(string.)40 b(Note)31 b(that)g(this)e(is)g
+(a)h(`First)g(In)f({)i(First)e(Out')h(stac)m(k,)i(so)e(the)h(oldest)f
+(error)f(message)j(is)d(returned)g(\014rst)0 3049 y(b)m(y)h(ftgmsg.)0
+3399 y Fd(6.9)135 b(V)-11 b(ariable-Length)46 b(Arra)l(y)f(F)-11
+b(acilit)l(y)46 b(in)f(Binary)g(T)-11 b(ables)0 3653
+y Fi(FITSIO)38 b(pro)m(vides)h(easy-to-use)i(supp)s(ort)d(for)h
+(reading)f(and)h(writing)f(data)i(in)e(v)-5 b(ariable)38
+b(length)h(\014elds)f(of)i(a)0 3766 y(binary)34 b(table.)55
+b(The)35 b(v)-5 b(ariable)34 b(length)g(columns)g(ha)m(v)m(e)j(TF)m
+(ORMn)e(k)m(eyw)m(ord)h(v)-5 b(alues)34 b(of)i(the)f(form)g
+(`1Pt\(len\)')0 3878 y(where)27 b(`t')g(is)f(the)i(datat)m(yp)s(e)g(co)
+s(de)f(\(e.g.,)j(I,)d(J,)g(E,)g(D,)g(etc.\))41 b(and)27
+b(`len')f(is)h(an)f(in)m(teger)i(sp)s(ecifying)d(the)i(maxim)m(um)0
+3991 y(length)f(of)h(the)h(v)m(ector)g(in)e(the)h(table.)39
+b(If)27 b(the)g(v)-5 b(alue)26 b(of)h(`len')g(is)f(not)h(sp)s
+(eci\014ed)e(when)h(the)h(table)g(is)f(created)i(\(e.g.,)0
+4104 y(if)e(the)i(TF)m(ORM)f(k)m(eyw)m(ord)h(v)-5 b(alue)27
+b(is)f(simply)f(sp)s(eci\014ed)h(as)h('1PE')h(instead)f(of)g
+('1PE\(400\))j(\),)e(then)f(FITSIO)g(will)0 4217 y(automatically)i
+(scan)g(the)g(table)g(when)f(it)h(is)f(closed)h(to)h(determine)e(the)h
+(maxim)m(um)f(length)g(of)i(the)f(v)m(ector)i(and)0 4330
+y(will)d(app)s(end)g(this)i(v)-5 b(alue)30 b(to)h(the)f(TF)m(ORMn)g(v)
+-5 b(alue.)0 4490 y(The)25 b(same)h(routines)f(whic)m(h)f(read)i(and)f
+(write)g(data)h(in)e(an)i(ordinary)e(\014xed)h(length)g(binary)f(table)
+h(extension)h(are)0 4603 y(also)k(used)f(for)h(v)-5 b(ariable)29
+b(length)h(\014elds,)e(ho)m(w)m(ev)m(er,)k(the)e(subroutine)e
+(parameters)j(tak)m(e)h(on)e(a)g(sligh)m(tly)e(di\013eren)m(t)0
+4716 y(in)m(terpretation)i(as)g(describ)s(ed)f(b)s(elo)m(w.)0
+4876 y(All)35 b(the)h(data)h(in)e(a)i(v)-5 b(ariable)35
+b(length)g(\014eld)g(is)g(written)h(in)m(to)g(an)g(area)h(called)f(the)
+g(`heap')g(whic)m(h)f(follo)m(ws)h(the)0 4989 y(main)25
+b(\014xed-length)g(FITS)g(binary)g(table.)39 b(The)25
+b(size)h(of)h(the)f(heap,)h(in)e(b)m(ytes,)i(is)e(sp)s(eci\014ed)g
+(with)f(the)j(PCOUNT)0 5102 y(k)m(eyw)m(ord)21 b(in)e(the)i(FITS)f
+(header.)37 b(When)20 b(creating)h(a)g(new)f(binary)f(table,)j(the)f
+(initial)d(v)-5 b(alue)20 b(of)g(PCOUNT)g(should)0 5215
+y(usually)29 b(b)s(e)h(set)i(to)g(zero.)44 b(FITSIO)30
+b(will)e(recompute)k(the)f(size)g(of)h(the)f(heap)g(as)g(the)h(data)g
+(is)e(written)g(and)h(will)0 5328 y(automatically)25
+b(up)s(date)f(the)i(PCOUNT)e(k)m(eyw)m(ord)h(v)-5 b(alue)25
+b(when)f(the)h(table)g(is)f(closed.)39 b(When)25 b(writing)e(v)-5
+b(ariable)0 5441 y(length)33 b(data)h(to)g(a)g(table,)h(CFITSIO)d(will)
+e(automatically)k(extend)f(the)h(size)f(of)h(the)g(heap)f(area)h(if)f
+(necessary)-8 b(,)0 5554 y(so)31 b(that)g(an)m(y)f(follo)m(wing)f(HDUs)
+i(do)f(not)h(get)h(o)m(v)m(erwritten.)0 5714 y(By)e(default)e(the)i
+(heap)f(data)i(area)f(starts)g(immediately)e(after)i(the)f(last)h(ro)m
+(w)f(of)h(the)g(\014xed-length)e(table.)41 b(This)p eop
+%%Page: 52 58
+52 57 bop 0 299 a Fi(52)1277 b Fg(CHAPTER)29 b(6.)72
+b(FITSIO)29 b(CONVENTIONS)g(AND)i(GUIDELINES)0 555 y
+Fi(default)26 b(starting)g(lo)s(cation)h(ma)m(y)g(b)s(e)f(o)m(v)m
+(erridden)g(b)m(y)h(the)g(THEAP)f(k)m(eyw)m(ord,)i(but)f(this)e(is)h
+(not)h(recommended.)0 668 y(If)34 b(additional)e(ro)m(ws)i(of)g(data)h
+(are)g(added)e(to)i(the)f(table,)i(CFITSIO)c(will)g(automatically)i
+(shift)e(the)j(the)f(heap)0 781 y(do)m(wn)g(to)i(mak)m(e)f(ro)s(om)g
+(for)f(the)h(new)f(ro)m(ws,)i(but)e(it)h(is)e(ob)m(viously)h(b)s(e)g
+(more)h(e\016cien)m(t)g(to)g(initially)c(create)37 b(the)0
+894 y(table)30 b(with)e(the)i(necessary)g(n)m(um)m(b)s(er)f(of)h(blank)
+e(ro)m(ws,)i(so)g(that)g(the)g(heap)g(do)s(es)f(not)h(needed)g(to)g(b)s
+(e)f(constan)m(tly)0 1007 y(mo)m(v)m(ed.)0 1167 y(When)40
+b(writing)f(to)i(a)g(v)-5 b(ariable)39 b(length)h(\014eld,)i(the)f(en)m
+(tire)g(arra)m(y)g(of)f(v)-5 b(alues)40 b(for)g(a)h(giv)m(en)g(ro)m(w)g
+(of)f(the)h(table)0 1280 y(m)m(ust)36 b(b)s(e)g(written)f(with)g(a)h
+(single)f(call)h(to)h(FTPCLx.)57 b(The)36 b(total)h(length)f(of)g(the)g
+(arra)m(y)h(is)e(calculated)h(from)0 1393 y(\(NELEM+FELEM-1\).)44
+b(One)30 b(cannot)i(app)s(end)d(more)i(elemen)m(ts)g(to)h(an)e
+(existing)g(\014eld)g(at)h(a)h(later)f(time;)g(an)m(y)0
+1506 y(attempt)k(to)f(do)g(so)g(will)d(simply)g(o)m(v)m(erwrite)k(all)d
+(the)i(data)h(whic)m(h)d(w)m(as)i(previously)e(written.)50
+b(Note)35 b(also)e(that)0 1619 y(the)h(new)g(data)g(will)e(b)s(e)h
+(written)g(to)i(a)f(new)g(area)g(of)g(the)h(heap)e(and)h(the)g(heap)g
+(space)g(used)f(b)m(y)h(the)g(previous)0 1732 y(write)i(cannot)i(b)s(e)
+e(reclaimed.)60 b(F)-8 b(or)38 b(this)e(reason)h(it)g(is)f(advised)g
+(that)i(eac)m(h)g(ro)m(w)f(of)h(a)f(v)-5 b(ariable)36
+b(length)g(\014eld)0 1844 y(only)c(b)s(e)h(written)f(once.)50
+b(An)33 b(exception)g(to)h(this)e(general)h(rule)f(o)s(ccurs)h(when)f
+(setting)h(elemen)m(ts)h(of)f(an)g(arra)m(y)0 1957 y(as)38
+b(unde\014ned.)63 b(One)37 b(m)m(ust)i(\014rst)e(write)g(a)i(dumm)m(y)e
+(v)-5 b(alue)38 b(in)m(to)g(the)h(arra)m(y)f(with)f(FTPCLx,)j(and)e
+(then)g(call)0 2070 y(FTPCLU)33 b(to)i(\015ag)f(the)f(desired)g(elemen)
+m(ts)h(as)f(unde\014ned.)49 b(\(Do)35 b(not)f(use)f(the)h(FTPCNx)f
+(family)f(of)i(routines)0 2183 y(with)27 b(v)-5 b(ariable)28
+b(length)g(\014elds\).)39 b(Note)30 b(that)f(the)g(ro)m(ws)g(of)g(a)g
+(table,)g(whether)f(\014xed)g(or)h(v)-5 b(ariable)27
+b(length,)i(do)g(not)0 2296 y(ha)m(v)m(e)j(to)f(b)s(e)e(written)h
+(consecutiv)m(ely)g(and)g(ma)m(y)h(b)s(e)f(written)f(in)g(an)m(y)i
+(order.)0 2456 y(When)40 b(writing)f(to)i(a)g(v)-5 b(ariable)39
+b(length)h(ASCI)s(I)f(c)m(haracter)j(\014eld)d(\(e.g.,)45
+b(TF)m(ORM)c(=)f('1P)-8 b(A'\))43 b(only)c(a)i(single)0
+2569 y(c)m(haracter)33 b(string)e(written.)43 b(FTPCLS)30
+b(writes)h(the)h(whole)e(length)h(of)h(the)g(input)d(string)i(\(min)m
+(us)f(an)m(y)i(trailing)0 2682 y(blank)k(c)m(haracters\),)42
+b(th)m(us)37 b(the)h(NELEM)f(and)g(FELEM)h(parameters)g(are)g(ignored.)
+61 b(If)37 b(the)h(input)d(string)i(is)0 2795 y(completely)26
+b(blank)g(then)g(FITSIO)g(will)e(write)i(one)h(blank)e(c)m(haracter)k
+(to)e(the)g(FITS)f(\014le.)39 b(Similarly)-8 b(,)24 b(FTGCVS)0
+2908 y(and)35 b(FTGCFS)g(read)g(the)h(en)m(tire)f(string)g(\(truncated)
+g(to)i(the)e(width)f(of)h(the)h(c)m(haracter)h(string)d(argumen)m(t)i
+(in)0 3021 y(the)31 b(subroutine)d(call\))i(and)g(also)g(ignore)g(the)g
+(NELEM)h(and)f(FELEM)g(parameters.)0 3181 y(The)35 b(FTPDES)h
+(subroutine)d(is)i(useful)f(in)g(situations)h(where)g(m)m(ultiple)f(ro)
+m(ws)h(of)h(a)g(v)-5 b(ariable)35 b(length)g(column)0
+3294 y(ha)m(v)m(e)d(the)e(iden)m(tical)f(arra)m(y)i(of)g(v)-5
+b(alues.)40 b(One)30 b(can)g(simply)e(write)i(the)g(arra)m(y)h(once)g
+(for)g(the)f(\014rst)g(ro)m(w,)g(and)g(then)0 3407 y(use)36
+b(FTPDES)g(to)h(write)f(the)g(same)h(descriptor)f(v)-5
+b(alues)35 b(in)m(to)i(the)f(other)h(ro)m(ws)f(\(use)h(the)f(FTGDES)h
+(routine)0 3520 y(to)f(read)f(the)h(\014rst)f(descriptor)f(v)-5
+b(alue\);)38 b(all)c(the)i(ro)m(ws)f(will)e(then)i(p)s(oin)m(t)f(to)i
+(the)g(same)f(storage)i(lo)s(cation)e(th)m(us)0 3633
+y(sa)m(ving)30 b(disk)f(space.)0 3793 y(When)35 b(reading)f(from)g(a)i
+(v)-5 b(ariable)33 b(length)i(arra)m(y)g(\014eld)f(one)h(can)g(only)g
+(read)f(as)i(man)m(y)f(elemen)m(ts)g(as)g(actually)0
+3906 y(exist)h(in)e(that)j(ro)m(w)e(of)h(the)g(table;)j(reading)c(do)s
+(es)h(not)g(automatically)f(con)m(tin)m(ue)h(with)f(the)h(next)g(ro)m
+(w)g(of)g(the)0 4019 y(table)28 b(as)g(o)s(ccurs)g(when)f(reading)g(an)
+h(ordinary)f(\014xed)g(length)g(table)h(\014eld.)39 b(A)m(ttempts)29
+b(to)g(read)f(more)g(than)g(this)0 4131 y(will)h(cause)k(an)e(error)h
+(status)g(to)g(b)s(e)f(returned.)44 b(One)32 b(can)g(determine)f(the)h
+(n)m(um)m(b)s(er)e(of)i(elemen)m(ts)g(in)f(eac)m(h)i(ro)m(w)0
+4244 y(of)e(a)f(v)-5 b(ariable)29 b(column)h(with)f(the)h(FTGDES)h
+(subroutine.)0 4657 y Fd(6.10)136 b(Supp)t(ort)44 b(for)h(IEEE)g(Sp)t
+(ecial)h(V)-11 b(alues)0 4924 y Fi(The)26 b(ANSI/IEEE-754)h
+(\015oating-p)s(oin)m(t)f(n)m(um)m(b)s(er)f(standard)g(de\014nes)h
+(certain)g(sp)s(ecial)f(v)-5 b(alues)25 b(that)i(are)g(used)e(to)0
+5036 y(represen)m(t)j(suc)m(h)g(quan)m(tities)f(as)h(Not-a-Num)m(b)s
+(er)h(\(NaN\),)h(denormalized,)d(under\015o)m(w,)g(o)m(v)m(er\015o)m
+(w,)j(and)d(in\014nit)m(y)-8 b(.)0 5149 y(\(See)29 b(the)f(App)s(endix)
+d(in)i(the)h(NOST)g(FITS)f(standard)g(or)h(the)g(NOST)g(FITS)f(User's)h
+(Guide)f(for)h(a)g(list)f(of)h(these)0 5262 y(v)-5 b(alues\).)40
+b(The)30 b(FITSIO)f(subroutines)f(that)j(read)f(\015oating)h(p)s(oin)m
+(t)e(data)i(in)e(FITS)g(\014les)h(recognize)h(these)g(IEEE)0
+5375 y(sp)s(ecial)38 b(v)-5 b(alues)38 b(and)h(b)m(y)g(default)f(in)m
+(terpret)h(the)g(o)m(v)m(er\015o)m(w)i(and)d(in\014nit)m(y)f(v)-5
+b(alues)39 b(as)g(b)s(eing)f(equiv)-5 b(alen)m(t)39 b(to)h(a)0
+5488 y(NaN,)35 b(and)e(con)m(v)m(ert)i(the)f(under\015o)m(w)e(and)h
+(denormalized)f(v)-5 b(alues)33 b(in)m(to)h(zeros.)51
+b(In)33 b(some)h(cases)h(programmers)0 5601 y(ma)m(y)d(w)m(an)m(t)g
+(access)g(to)g(the)g(ra)m(w)f(IEEE)g(v)-5 b(alues,)31
+b(without)f(an)m(y)i(mo)s(di\014cation)d(b)m(y)i(FITSIO.)g(This)e(can)j
+(b)s(e)e(done)0 5714 y(b)m(y)k(calling)g(the)g(FTGPVx)h(or)g(FTGCVx)g
+(routines)e(while)g(sp)s(ecifying)f(0.0)k(as)f(the)f(v)-5
+b(alue)34 b(of)h(the)g(NULL)-10 b(V)g(AL)p eop
+%%Page: 53 59
+53 58 bop 0 299 a Fg(6.11.)73 b(WHEN)31 b(THE)f(FINAL)g(SIZE)f(OF)i
+(THE)f(FITS)f(HDU)i(IS)f(UNKNO)m(WN)978 b Fi(53)0 555
+y(parameter.)72 b(This)38 b(will)g(force)j(FITSIO)e(to)j(simply)c(pass)
+i(the)g(IEEE)g(v)-5 b(alues)40 b(through)g(to)h(the)g(application)0
+668 y(program,)30 b(without)f(an)m(y)h(mo)s(di\014cation.)39
+b(This)29 b(do)s(es)g(not)h(w)m(ork)g(for)g(double)f(precision)f(v)-5
+b(alues)29 b(on)h(V)-10 b(AX/VMS)0 781 y(mac)m(hines,)37
+b(ho)m(w)m(ev)m(er,)i(where)d(there)g(is)f(no)h(easy)g(w)m(a)m(y)h(to)g
+(b)m(ypass)f(the)g(default)f(in)m(terpretation)g(of)h(the)h(IEEE)0
+894 y(sp)s(ecial)29 b(v)-5 b(alues.)0 1393 y Fd(6.11)136
+b(When)44 b(the)h(Final)h(Size)f(of)g(the)g(FITS)f(HDU)h(is)g(Unkno)l
+(wn)0 1676 y Fi(It)27 b(is)g(not)g(required)e(to)j(kno)m(w)f(the)h
+(total)g(size)f(of)g(a)h(FITS)e(data)i(arra)m(y)g(or)f(table)g(b)s
+(efore)g(b)s(eginning)d(to)k(write)f(the)0 1789 y(data)32
+b(to)f(the)g(FITS)f(\014le.)42 b(In)30 b(the)h(case)h(of)f(the)g
+(primary)e(arra)m(y)i(or)g(an)f(image)i(extension,)e(one)i(should)c
+(initially)0 1902 y(create)j(the)e(arra)m(y)h(with)d(the)j(size)f(of)g
+(the)g(highest)f(dimension)f(\(largest)j(NAXISn)e(k)m(eyw)m(ord\))i
+(set)g(to)g(a)f(dumm)m(y)0 2015 y(v)-5 b(alue,)25 b(suc)m(h)f(as)g(1.)
+39 b(Then)23 b(after)i(all)e(the)i(data)f(ha)m(v)m(e)i(b)s(een)d
+(written)g(and)h(the)g(true)g(dimensions)e(are)i(kno)m(wn,)h(then)0
+2128 y(the)31 b(NAXISn)e(v)-5 b(alue)30 b(should)f(b)s(e)h(up)s(dated)f
+(using)g(the)i(\014ts)p 2051 2128 28 4 v 62 w(up)s(date)p
+2389 2128 V 32 w(k)m(ey)h(routine)d(b)s(efore)h(mo)m(ving)h(to)g
+(another)0 2240 y(extension)f(or)g(closing)g(the)g(FITS)g(\014le.)0
+2401 y(When)f(writing)e(to)i(FITS)g(tables,)g(CFITSIO)e(automatically)i
+(k)m(eeps)h(trac)m(k)g(of)f(the)g(highest)g(ro)m(w)g(n)m(um)m(b)s(er)e
+(that)0 2514 y(is)k(written)g(to,)i(and)e(will)e(increase)j(the)g(size)
+g(of)g(the)g(table)f(if)g(necessary)-8 b(.)46 b(CFITSIO)30
+b(will)f(also)j(automatically)0 2626 y(insert)j(space)i(in)e(the)h
+(FITS)f(\014le)h(if)f(necessary)-8 b(,)39 b(to)e(ensure)e(that)i(the)f
+(data)h('heap',)h(if)d(it)h(exists,)h(and/or)g(an)m(y)0
+2739 y(additional)26 b(HDUs)j(that)g(follo)m(w)e(the)i(table)f(do)g
+(not)h(get)g(o)m(v)m(erwritten)g(as)f(new)g(ro)m(ws)g(are)h(written)e
+(to)i(the)g(table.)0 2900 y(As)37 b(a)h(general)f(rule)f(it)h(is)f(b)s
+(est)h(to)h(sp)s(ecify)e(the)i(initial)c(n)m(um)m(b)s(er)i(of)i(ro)m
+(ws)f(=)g(0)g(when)g(the)g(table)g(is)g(created,)0 3012
+y(then)h(let)g(CFITSIO)f(k)m(eep)i(trac)m(k)g(of)g(the)f(n)m(um)m(b)s
+(er)f(of)i(ro)m(ws)f(that)h(are)f(actually)g(written.)64
+b(The)38 b(application)0 3125 y(program)e(should)e(not)j(man)m(ually)e
+(up)s(date)g(the)i(n)m(um)m(b)s(er)e(of)h(ro)m(ws)g(in)f(the)i(table)f
+(\(as)h(giv)m(en)f(b)m(y)g(the)h(NAXIS2)0 3238 y(k)m(eyw)m(ord\))j
+(since)e(CFITSIO)f(do)s(es)i(this)f(automatically)-8
+b(.)66 b(If)38 b(a)i(table)e(is)g(initially)e(created)k(with)d(more)i
+(than)0 3351 y(zero)i(ro)m(ws,)j(then)c(this)g(will)d(usually)i(b)s(e)h
+(considered)f(as)i(the)g(minim)m(um)d(size)i(of)h(the)g(table,)i(ev)m
+(en)e(if)f(few)m(er)0 3464 y(ro)m(ws)30 b(are)g(actually)f(written)g
+(to)i(the)f(table.)40 b(Th)m(us,)30 b(if)e(a)j(table)e(is)g(initially)d
+(created)31 b(with)e(NAXIS2)h(=)f(20,)j(and)0 3577 y(CFITSIO)f(only)h
+(writes)f(10)j(ro)m(ws)e(of)h(data)g(b)s(efore)f(closing)g(the)h
+(table,)g(then)f(NAXIS2)h(will)d(remain)h(equal)h(to)0
+3690 y(20.)50 b(If)33 b(ho)m(w)m(ev)m(er,)i(30)g(ro)m(ws)e(of)g(data)h
+(are)g(written)e(to)i(this)e(table,)i(then)f(NAXIS2)h(will)c(b)s(e)j
+(increased)f(from)h(20)0 3803 y(to)f(30.)44 b(The)31
+b(one)g(exception)h(to)g(this)e(automatic)i(up)s(dating)d(of)i(the)h
+(NAXIS2)f(k)m(eyw)m(ord)h(is)e(if)g(the)i(application)0
+3916 y(program)c(directly)e(mo)s(di\014es)g(the)j(v)-5
+b(alue)27 b(of)h(NAXIS2)g(\(up)f(or)h(do)m(wn\))g(itself)f(just)g(b)s
+(efore)h(closing)f(the)h(table.)40 b(In)0 4029 y(this)27
+b(case,)j(CFITSIO)d(do)s(es)h(not)h(up)s(date)e(NAXIS2)i(again,)g
+(since)f(it)g(assumes)g(that)h(the)f(application)f(program)0
+4142 y(m)m(ust)32 b(ha)m(v)m(e)h(had)f(a)g(go)s(o)s(d)g(reason)h(for)f
+(c)m(hanging)g(the)g(v)-5 b(alue)32 b(directly)-8 b(.)45
+b(This)30 b(is)h(not)i(recommended,)f(ho)m(w)m(ev)m(er,)0
+4254 y(and)j(is)g(only)g(pro)m(vided)g(for)g(bac)m(kw)m(ard)h
+(compatibilit)m(y)e(with)h(soft)m(w)m(are)i(that)g(initially)32
+b(creates)37 b(a)f(table)g(with)0 4367 y(a)e(large)g(n)m(um)m(b)s(er)f
+(of)h(ro)m(ws,)h(than)f(decreases)g(the)h(NAXIS2)f(v)-5
+b(alue)33 b(to)i(the)f(actual)g(smaller)f(v)-5 b(alue)33
+b(just)g(b)s(efore)0 4480 y(closing)c(the)i(table.)0
+4979 y Fd(6.12)136 b(Lo)t(cal)45 b(FITS)e(Con)l(v)l(en)l(tions)k(supp)t
+(orted)d(b)l(y)h(FITSIO)0 5262 y Fi(CFITSIO)25 b(supp)s(orts)g(sev)m
+(eral)i(lo)s(cal)e(FITS)h(con)m(v)m(en)m(tions)i(whic)m(h)d(are)i(not)g
+(de\014ned)e(in)g(the)i(o\016cial)f(NOST)g(FITS)0 5375
+y(standard)k(and)g(whic)m(h)g(are)h(not)g(necessarily)e(recognized)i
+(or)g(supp)s(orted)e(b)m(y)i(other)g(FITS)f(soft)m(w)m(are)i(pac)m(k)-5
+b(ages.)0 5488 y(Programmers)36 b(should)e(b)s(e)h(cautious)h(ab)s(out)
+f(using)g(these)h(features,)i(esp)s(ecially)c(if)h(the)h(FITS)f
+(\014les)g(that)i(are)0 5601 y(pro)s(duced)31 b(are)i(exp)s(ected)g(to)
+g(b)s(e)f(pro)s(cessed)g(b)m(y)h(other)f(soft)m(w)m(are)i(systems)f
+(whic)m(h)e(do)i(not)f(use)h(the)f(CFITSIO)0 5714 y(in)m(terface.)p
+eop
+%%Page: 54 60
+54 59 bop 0 299 a Fi(54)1277 b Fg(CHAPTER)29 b(6.)72
+b(FITSIO)29 b(CONVENTIONS)g(AND)i(GUIDELINES)0 555 y
+Fb(6.12.1)113 b(Supp)s(ort)37 b(for)h(Long)g(String)e(Keyw)m(ord)i(V)-9
+b(alues.)0 774 y Fi(The)23 b(length)h(of)g(a)g(standard)f(FITS)g
+(string)g(k)m(eyw)m(ord)h(is)f(limited)f(to)i(68)h(c)m(haracters)g(b)s
+(ecause)f(it)f(m)m(ust)h(\014t)g(en)m(tirely)0 887 y(within)33
+b(a)j(single)f(FITS)g(header)h(k)m(eyw)m(ord)g(record.)57
+b(In)35 b(some)h(instances)f(it)h(is)e(necessary)j(to)f(enco)s(de)g
+(strings)0 1000 y(longer)26 b(than)g(this)f(limit,)g(so)h(FITSIO)f
+(supp)s(orts)f(a)j(lo)s(cal)e(con)m(v)m(en)m(tion)i(in)e(whic)m(h)g
+(the)h(string)f(v)-5 b(alue)26 b(is)f(con)m(tin)m(ued)0
+1113 y(o)m(v)m(er)34 b(m)m(ultiple)d(k)m(eyw)m(ords.)49
+b(This)31 b(con)m(tin)m(uation)i(con)m(v)m(en)m(tion)i(uses)d(an)h(amp)
+s(ersand)f(c)m(haracter)i(at)g(the)f(end)g(of)0 1226
+y(eac)m(h)c(substring)c(to)j(indicate)f(that)h(it)f(is)g(con)m(tin)m
+(ued)g(on)g(the)h(next)g(k)m(eyw)m(ord,)h(and)d(the)i(con)m(tin)m
+(uation)g(k)m(eyw)m(ords)0 1339 y(all)42 b(ha)m(v)m(e)j(the)f(name)f
+(CONTINUE)g(without)f(an)i(equal)f(sign)f(in)g(column)h(9.)80
+b(The)43 b(string)g(v)-5 b(alue)42 b(ma)m(y)j(b)s(e)0
+1452 y(con)m(tin)m(ued)28 b(in)f(this)h(w)m(a)m(y)h(o)m(v)m(er)h(as)e
+(man)m(y)h(additional)d(CONTINUE)i(k)m(eyw)m(ords)g(as)h(is)e
+(required.)39 b(The)27 b(follo)m(wing)0 1564 y(lines)i(illustrate)f
+(this)h(con)m(tin)m(uation)i(con)m(v)m(en)m(tion)g(whic)m(h)e(is)h
+(used)f(in)g(the)i(v)-5 b(alue)30 b(of)g(the)h(STRKEY)e(k)m(eyw)m(ord:)
+0 1802 y Fe(LONGSTRN=)45 b('OGIP)i(1.0')524 b(/)47 b(The)g(OGIP)g(Long)
+f(String)g(Convention)f(may)i(be)g(used.)0 1915 y(STRKEY)94
+b(=)47 b('This)g(is)g(a)g(very)g(long)g(string)f(keyword&')93
+b(/)47 b(Optional)f(Comment)0 2028 y(CONTINUE)93 b(')48
+b(value)e(that)h(is)g(continued)e(over)i(3)g(keywords)f(in)h(the)g(&)95
+b(')0 2141 y(CONTINUE)e('FITS)47 b(header.')e(/)j(This)e(is)h(another)f
+(optional)g(comment.)0 2379 y Fi(It)29 b(is)f(recommended)g(that)h(the)
+g(LONGSTRN)f(k)m(eyw)m(ord,)i(as)f(sho)m(wn)f(here,)h(alw)m(a)m(ys)h(b)
+s(e)e(included)e(in)h(an)m(y)i(HDU)0 2492 y(that)f(uses)e(this)g
+(longstring)g(con)m(v)m(en)m(tion.)41 b(A)27 b(subroutine)e(called)h
+(FTPLSW)h(has)g(b)s(een)f(pro)m(vided)g(in)f(CFITSIO)0
+2605 y(to)31 b(write)f(this)f(k)m(eyw)m(ord)i(if)e(it)h(do)s(es)g(not)h
+(already)f(exist.)0 2765 y(This)22 b(long)i(string)g(con)m(v)m(en)m
+(tion)h(is)e(supp)s(orted)g(b)m(y)h(the)g(follo)m(wing)f(FITSIO)g
+(subroutines)f(that)j(deal)f(with)f(string-)0 2878 y(v)-5
+b(alued)29 b(k)m(eyw)m(ords:)286 3116 y Fe(ftgkys)46
+b(-)i(read)f(a)g(string)f(keyword)286 3229 y(ftpkls)g(-)i(write)e
+(\(append\))g(a)h(string)f(keyword)286 3342 y(ftikls)g(-)i(insert)e(a)h
+(string)g(keyword)286 3455 y(ftmkls)f(-)i(modify)e(the)h(value)f(of)h
+(an)h(existing)d(string)h(keyword)286 3568 y(ftukls)g(-)i(update)e(an)h
+(existing)f(keyword,)f(or)i(write)g(a)g(new)g(keyword)286
+3681 y(ftdkey)f(-)i(delete)e(a)h(keyword)0 3919 y Fi(These)41
+b(routines)e(will)f(transparen)m(tly)i(read,)k(write,)f(or)e(delete)g
+(a)g(long)f(string)g(v)-5 b(alue)40 b(in)g(the)h(FITS)f(\014le,)j(so)0
+4031 y(programmers)36 b(in)f(general)h(do)g(not)h(ha)m(v)m(e)g(to)g(b)s
+(e)f(concerned)g(ab)s(out)g(the)g(details)g(of)g(the)h(con)m(v)m(en)m
+(tion)g(that)g(is)0 4144 y(used)32 b(to)i(enco)s(de)f(the)g(long)f
+(string)g(in)g(the)h(FITS)f(header.)48 b(When)33 b(reading)f(a)h(long)g
+(string,)g(one)g(m)m(ust)g(ensure)0 4257 y(that)h(the)f(c)m(haracter)i
+(string)e(parameter)h(used)e(in)g(these)i(subroutine)d(calls)i(has)g(b)
+s(een)f(declared)h(long)g(enough)0 4370 y(to)e(hold)e(the)i(en)m(tire)f
+(string,)g(otherwise)f(the)i(returned)e(string)g(v)-5
+b(alue)30 b(will)e(b)s(e)i(truncated.)0 4530 y(Note)d(that)e(the)h
+(more)f(commonly)g(used)f(FITSIO)g(subroutine)g(to)i(write)e(string)g
+(v)-5 b(alued)24 b(k)m(eyw)m(ords)i(\(FTPKYS\))0 4643
+y(do)s(es)38 b(NOT)g(supp)s(ort)f(this)g(long)h(string)g(con)m(v)m(en)m
+(tion)h(and)f(only)g(supp)s(orts)e(strings)h(up)h(to)h(68)g(c)m
+(haracters)h(in)0 4756 y(length.)h(This)29 b(has)h(b)s(een)g(done)h
+(delib)s(erately)d(to)k(prev)m(en)m(t)f(programs)g(from)f(inadv)m
+(erten)m(tly)g(writing)f(k)m(eyw)m(ords)0 4869 y(using)37
+b(this)h(non-standard)f(con)m(v)m(en)m(tion)j(without)e(the)g(explicit)
+f(in)m(ten)m(t)i(of)g(the)g(programmer)f(or)h(user.)64
+b(The)0 4982 y(FTPKLS)28 b(subroutine)f(m)m(ust)i(b)s(e)g(called)f
+(instead)h(to)h(write)e(long)h(strings.)39 b(This)27
+b(routine)i(can)g(also)g(b)s(e)g(used)f(to)0 5095 y(write)i(ordinary)e
+(string)i(v)-5 b(alues)29 b(less)h(than)g(68)h(c)m(haracters)h(in)d
+(length.)0 5382 y Fb(6.12.2)113 b(Arra)m(ys)37 b(of)g(Fixed-Length)i
+(Strings)e(in)f(Binary)h(T)-9 b(ables)0 5601 y Fi(The)29
+b(de\014nition)e(of)j(the)f(FITS)g(binary)e(table)j(extension)f(format)
+g(do)s(es)h(not)f(pro)m(vide)g(a)g(simple)f(w)m(a)m(y)i(to)g(sp)s
+(ecify)0 5714 y(that)f(a)f(c)m(haracter)i(column)d(con)m(tains)h(an)g
+(arra)m(y)h(of)f(\014xed-length)f(strings.)39 b(T)-8
+b(o)29 b(supp)s(ort)d(this)h(feature,)i(FITSIO)p eop
+%%Page: 55 61
+55 60 bop 0 299 a Fg(6.12.)73 b(LOCAL)29 b(FITS)h(CONVENTIONS)f(SUPPOR)
+-8 b(TED)29 b(BY)i(FITSIO)1168 b Fi(55)0 555 y(uses)31
+b(a)h(lo)s(cal)f(con)m(v)m(en)m(tion)h(for)f(the)h(format)g(of)g(the)f
+(TF)m(ORMn)g(k)m(eyw)m(ord)h(v)-5 b(alue)31 b(of)h(the)g(form)f('rAw')g
+(where)g('r')0 668 y(is)c(an)g(in)m(teger)h(sp)s(ecifying)d(the)j
+(total)g(width)e(in)g(c)m(haracters)j(of)f(the)g(column,)f(and)g('w')g
+(is)g(an)g(in)m(teger)h(sp)s(ecifying)0 781 y(the)c(\(\014xed\))g
+(length)g(of)g(an)g(individual)19 b(unit)k(string)g(within)e(the)j(v)m
+(ector.)41 b(F)-8 b(or)24 b(example,)i(TF)m(ORM1)e(=)g('120A10')0
+894 y(w)m(ould)k(indicate)g(that)h(the)h(binary)d(table)i(column)f(is)g
+(120)i(c)m(haracters)g(wide)e(and)h(consists)f(of)h(12)h(10-c)m
+(haracter)0 1007 y(length)e(strings.)39 b(This)27 b(con)m(v)m(en)m
+(tion)j(is)d(recognized)i(b)m(y)g(the)f(FITSIO)g(subroutines)e(that)j
+(read)g(or)f(write)g(strings)0 1120 y(in)37 b(binary)f(tables.)64
+b(The)37 b(Binary)g(T)-8 b(able)38 b(de\014nition)e(do)s(cumen)m(t)i
+(sp)s(eci\014es)e(that)j(other)f(optional)f(c)m(haracters)0
+1233 y(ma)m(y)f(follo)m(w)f(the)g(datat)m(yp)s(e)i(co)s(de)e(in)g(the)g
+(TF)m(ORM)h(k)m(eyw)m(ord,)i(so)d(this)g(lo)s(cal)f(con)m(v)m(en)m
+(tion)j(is)d(in)h(compliance)0 1346 y(with)23 b(the)i(FITS)f(standard,)
+i(although)e(other)h(FITS)f(readers)g(are)h(not)g(required)e(to)i
+(recognize)h(this)e(con)m(v)m(en)m(tion.)0 1506 y(The)h(Binary)g(T)-8
+b(able)26 b(de\014nition)d(do)s(cumen)m(t)j(that)h(w)m(as)f(appro)m(v)m
+(ed)g(b)m(y)g(the)g(IA)m(U)g(in)f(1994)j(con)m(tains)e(an)f(app)s
+(endix)0 1619 y(describing)20 b(an)j(alternate)g(con)m(v)m(en)m(tion)h
+(for)f(sp)s(ecifying)d(arra)m(ys)j(of)g(\014xed)f(or)h(v)-5
+b(ariable)22 b(length)g(strings)f(in)h(a)h(binary)0 1732
+y(table)34 b(c)m(haracter)h(column)e(\(with)g(the)i(form)e
+('rA:SSTRw/nnn\)'.)50 b(This)32 b(app)s(endix)f(w)m(as)k(not)f
+(o\016cially)f(v)m(oted)0 1844 y(on)d(b)m(y)h(the)f(IA)m(U)h(and)f
+(hence)g(is)g(still)e(pro)m(visional.)39 b(FITSIO)29
+b(do)s(es)h(not)h(curren)m(tly)e(supp)s(ort)g(this)g(prop)s(osal.)0
+2147 y Fb(6.12.3)113 b(Keyw)m(ord)37 b(Units)g(Strings)0
+2368 y Fi(One)g(de\014ciency)g(of)h(the)g(curren)m(t)g(FITS)f(Standard)
+f(is)h(that)i(it)e(do)s(es)g(not)h(de\014ne)f(a)i(sp)s(eci\014c)d(con)m
+(v)m(en)m(tion)j(for)0 2481 y(recording)29 b(the)h(ph)m(ysical)f(units)
+g(of)h(a)g(k)m(eyw)m(ord)h(v)-5 b(alue.)40 b(The)30 b(TUNITn)f(k)m(eyw)
+m(ord)h(can)g(b)s(e)g(used)f(to)i(sp)s(ecify)e(the)0
+2594 y(ph)m(ysical)34 b(units)g(of)h(the)h(v)-5 b(alues)35
+b(in)f(a)h(table)h(column,)f(but)g(there)g(is)g(no)g(analogous)h(con)m
+(v)m(en)m(tion)g(for)f(k)m(eyw)m(ord)0 2707 y(v)-5 b(alues.)41
+b(The)30 b(commen)m(t)h(\014eld)f(of)g(the)h(k)m(eyw)m(ord)g(is)f
+(often)h(used)f(for)g(this)f(purp)s(ose,)h(but)f(the)i(units)e(are)i
+(usually)0 2819 y(not)g(sp)s(eci\014ed)d(in)h(a)i(w)m(ell)e(de\014ned)h
+(format)g(that)h(FITS)f(readers)g(can)h(easily)e(recognize)i(and)f
+(extract.)0 2980 y(T)-8 b(o)28 b(solv)m(e)g(this)e(de\014ciency)-8
+b(,)29 b(FITSIO)d(uses)h(a)h(lo)s(cal)f(con)m(v)m(en)m(tion)i(in)d
+(whic)m(h)g(the)i(k)m(eyw)m(ord)g(units)e(are)i(enclosed)f(in)0
+3093 y(square)20 b(brac)m(k)m(ets)j(as)e(the)f(\014rst)g(tok)m(en)i(in)
+e(the)g(k)m(eyw)m(ord)i(commen)m(t)f(\014eld;)i(more)e(sp)s
+(eci\014cally)-8 b(,)21 b(the)g(op)s(ening)e(square)0
+3205 y(brac)m(k)m(et)28 b(immediately)d(follo)m(ws)g(the)i(slash)e('/')
+i(commen)m(t)h(\014eld)d(delimiter)f(and)i(a)g(single)f(space)i(c)m
+(haracter.)41 b(The)0 3318 y(follo)m(wing)29 b(examples)h(illustrate)e
+(k)m(eyw)m(ords)j(that)g(use)f(this)f(con)m(v)m(en)m(tion:)0
+3588 y Fe(EXPOSURE=)713 b(1800.0)47 b(/)g([s])g(elapsed)f(exposure)f
+(time)0 3701 y(V_HELIO)h(=)763 b(16.23)47 b(/)g([km)g(s**\(-1\)])e
+(heliocentric)g(velocity)0 3814 y(LAMBDA)94 b(=)763 b(5400.)47
+b(/)g([angstrom])e(central)h(wavelength)0 3927 y(FLUX)190
+b(=)47 b(4.9033487787637465E-30)42 b(/)47 b([J/cm**2/s])e(average)h
+(flux)0 4196 y Fi(In)28 b(general,)g(the)h(units)d(named)i(in)f(the)i
+(IA)m(U\(1988\))i(St)m(yle)d(Guide)f(are)i(recommended,)f(with)f(the)i
+(main)e(excep-)0 4309 y(tion)j(that)h(the)f(preferred)g(unit)e(for)j
+(angle)f(is)f('deg')j(for)e(degrees.)0 4469 y(The)24
+b(FTPUNT)g(and)g(FTGUNT)h(subroutines)e(in)g(FITSIO)g(write)h(and)g
+(read,)i(resp)s(ectiv)m(ely)-8 b(,)26 b(the)e(k)m(eyw)m(ord)h(unit)0
+4582 y(strings)k(in)g(an)i(existing)e(k)m(eyw)m(ord.)0
+4884 y Fb(6.12.4)113 b(HIERAR)m(CH)34 b(Con)m(v)m(en)m(tion)j(for)g
+(Extended)h(Keyw)m(ord)f(Names)0 5106 y Fi(CFITSIO)k(supp)s(orts)g(the)
+i(HIERAR)m(CH)g(k)m(eyw)m(ord)g(con)m(v)m(en)m(tion)h(whic)m(h)e(allo)m
+(ws)g(k)m(eyw)m(ord)h(names)g(that)h(are)0 5218 y(longer)33
+b(then)f(8)i(c)m(haracters)g(and)f(ma)m(y)h(con)m(tain)f(the)g(full)e
+(range)i(of)h(prin)m(table)d(ASCI)s(I)g(text)j(c)m(haracters.)51
+b(This)0 5331 y(con)m(v)m(en)m(tion)38 b(w)m(as)g(dev)m(elop)s(ed)e(at)
+i(the)f(Europ)s(ean)f(Southern)g(Observ)-5 b(atory)37
+b(\(ESO\))f(to)i(supp)s(ort)d(hierarc)m(hical)0 5444
+y(FITS)30 b(k)m(eyw)m(ord)g(suc)m(h)h(as:)0 5714 y Fe(HIERARCH)46
+b(ESO)g(INS)h(FOCU)g(POS)g(=)g(-0.00002500)e(/)j(Focus)e(position)p
+eop
+%%Page: 56 62
+56 61 bop 0 299 a Fi(56)1277 b Fg(CHAPTER)29 b(6.)72
+b(FITSIO)29 b(CONVENTIONS)g(AND)i(GUIDELINES)0 555 y
+Fi(Basically)-8 b(,)52 b(this)46 b(con)m(v)m(en)m(tion)j(uses)e(the)h
+(FITS)f(k)m(eyw)m(ord)h('HIERAR)m(CH')h(to)f(indicate)f(that)h(this)e
+(con)m(v)m(en-)0 668 y(tion)e(is)f(b)s(eing)g(used,)k(then)d(the)g
+(actual)h(k)m(eyw)m(ord)f(name)h(\()p Fe('ESO)i(INS)f(FOCU)h(POS')c
+Fi(in)g(this)g(example\))h(b)s(e-)0 781 y(gins)39 b(in)f(column)g(10)j
+(and)e(can)h(con)m(tain)f(an)m(y)h(prin)m(table)e(ASCI)s(I)g(text)j(c)m
+(haracters,)i(including)37 b(spaces.)68 b(The)0 894 y(equals)43
+b(sign)h(marks)f(the)h(end)g(of)g(the)g(k)m(eyw)m(ord)h(name)f(and)f
+(is)h(follo)m(w)m(ed)f(b)m(y)h(the)g(usual)f(v)-5 b(alue)44
+b(and)f(com-)0 1007 y(men)m(t)31 b(\014elds)e(just)h(as)h(in)e
+(standard)h(FITS)g(k)m(eyw)m(ords.)41 b(F)-8 b(urther)30
+b(details)g(of)h(this)e(con)m(v)m(en)m(tion)j(are)f(describ)s(ed)d(at)0
+1120 y(h)m(ttp://arcdev.hq.eso.org/dicb/dicd/dic-1-1.4.h)m(tml)33
+b(\(searc)m(h)f(for)e(HIERAR)m(CH\).)0 1280 y(This)42
+b(con)m(v)m(en)m(tion)k(allo)m(ws)e(a)g(m)m(uc)m(h)h(broader)e(range)i
+(of)f(k)m(eyw)m(ord)h(names)f(than)h(is)e(allo)m(w)m(ed)h(b)m(y)g(the)h
+(FITS)0 1393 y(Standard.)40 b(Here)30 b(are)h(more)g(examples)f(of)g
+(suc)m(h)g(k)m(eyw)m(ords:)0 1655 y Fe(HIERARCH)46 b(LongKeyword)e(=)k
+(47.5)e(/)i(Keyword)e(has)h(>)g(8)g(characters,)e(and)i(mixed)f(case)0
+1768 y(HIERARCH)g(XTE$TEMP)f(=)j(98.6)e(/)i(Keyword)d(contains)h(the)h
+('$')g(character)0 1881 y(HIERARCH)f(Earth)g(is)h(a)h(star)e(=)i(F)f(/)
+h(Keyword)d(contains)h(embedded)f(spaces)0 2143 y Fi(CFITSIO)40
+b(will)f(transparen)m(tly)i(read)h(and)f(write)f(these)j(k)m(eyw)m
+(ords,)i(so)d(application)e(programs)h(do)g(not)h(in)0
+2256 y(general)32 b(need)g(to)h(kno)m(w)f(an)m(ything)g(ab)s(out)g(the)
+g(sp)s(eci\014c)f(implemen)m(tation)g(details)g(of)i(the)f(HIERAR)m(CH)
+g(con-)0 2369 y(v)m(en)m(tion.)49 b(In)32 b(particular,)h(application)e
+(programs)h(do)h(not)h(need)e(to)i(sp)s(ecify)e(the)h(`HIERAR)m(CH')h
+(part)f(of)g(the)0 2482 y(k)m(eyw)m(ord)g(name)f(when)g(reading)f(or)h
+(writing)f(k)m(eyw)m(ords)h(\(although)g(it)g(ma)m(y)h(b)s(e)f
+(included)d(if)j(desired\).)45 b(When)0 2595 y(writing)33
+b(a)i(k)m(eyw)m(ord,)h(CFITSIO)d(\014rst)h(c)m(hec)m(ks)i(to)f(see)g
+(if)f(the)h(k)m(eyw)m(ord)g(name)f(is)g(legal)g(as)h(a)g(standard)f
+(FITS)0 2708 y(k)m(eyw)m(ord)k(\(no)g(more)f(than)h(8)g(c)m(haracters)h
+(long)e(and)g(con)m(taining)g(only)f(letters,)k(digits,)e(or)g(a)g(min)
+m(us)d(sign)i(or)0 2821 y(underscore\).)68 b(If)39 b(so)h(it)f(writes)g
+(it)g(as)g(a)h(standard)f(FITS)g(k)m(eyw)m(ord,)k(otherwise)c(it)g
+(uses)g(the)h(hierarc)m(h)e(con-)0 2934 y(v)m(en)m(tion)33
+b(to)g(write)f(the)g(k)m(eyw)m(ord.)48 b(The)32 b(maxim)m(um)f(k)m(eyw)
+m(ord)i(name)f(length)g(is)g(67)h(c)m(haracters,)i(whic)m(h)c(lea)m(v)m
+(es)0 3047 y(only)c(1)i(space)g(for)f(the)h(v)-5 b(alue)28
+b(\014eld.)38 b(A)29 b(more)f(practical)g(limit)e(is)i(ab)s(out)g(40)h
+(c)m(haracters,)i(whic)m(h)c(lea)m(v)m(es)i(enough)0
+3160 y(ro)s(om)f(for)h(most)f(k)m(eyw)m(ord)h(v)-5 b(alues.)40
+b(CFITSIO)27 b(returns)g(an)h(error)h(if)e(there)i(is)e(not)i(enough)f
+(ro)s(om)h(for)f(b)s(oth)g(the)0 3273 y(k)m(eyw)m(ord)k(name)f(and)f
+(the)i(k)m(eyw)m(ord)f(v)-5 b(alue)31 b(on)g(the)h(80-c)m(haracter)h
+(card,)f(except)g(for)f(string-v)-5 b(alued)30 b(k)m(eyw)m(ords)0
+3385 y(whic)m(h)i(are)h(simply)d(truncated)j(so)g(that)h(the)f(closing)
+f(quote)i(c)m(haracter)g(falls)d(in)h(column)g(80.)49
+b(In)32 b(the)h(curren)m(t)0 3498 y(implemen)m(tation,)28
+b(CFITSIO)f(preserv)m(es)i(the)g(case)h(of)f(the)g(letters)g(when)f
+(writing)f(the)i(k)m(eyw)m(ord)g(name,)g(but)f(it)0 3611
+y(is)c(case-insensitiv)m(e)g(when)g(reading)g(or)h(searc)m(hing)g(for)g
+(a)g(k)m(eyw)m(ord.)40 b(The)24 b(curren)m(t)h(implemen)m(tation)e
+(allo)m(ws)i(an)m(y)0 3724 y(ASCI)s(I)k(text)j(c)m(haracter)h(\(ASCI)s
+(I)c(32)j(to)f(ASCI)s(I)f(126\))i(in)e(the)h(k)m(eyw)m(ord)g(name)g
+(except)h(for)e(the)h('=')g(c)m(haracter.)0 3837 y(A)f(space)h(is)f
+(also)g(required)f(on)h(either)g(side)f(of)i(the)f(equal)g(sign.)0
+4174 y Fd(6.13)136 b(Optimizing)45 b(Co)t(de)g(for)h(Maxim)l(um)f(Pro)t
+(cessing)g(Sp)t(eed)0 4425 y Fi(CFITSIO)22 b(has)h(b)s(een)f(carefully)
+g(designed)g(to)i(obtain)f(the)g(highest)g(p)s(ossible)d(sp)s(eed)j
+(when)f(reading)g(and)h(writing)0 4538 y(FITS)33 b(\014les.)50
+b(In)33 b(order)h(to)g(ac)m(hiev)m(e)h(the)f(b)s(est)g(p)s(erformance,)
+g(ho)m(w)m(ev)m(er,)i(application)d(programmers)g(m)m(ust)h(b)s(e)0
+4650 y(careful)23 b(to)i(call)e(the)h(CFITSIO)f(routines)f
+(appropriately)h(and)g(in)g(an)g(e\016cien)m(t)i(sequence;)i
+(inappropriate)21 b(usage)0 4763 y(of)31 b(CFITSIO)d(routines)i(can)g
+(greatly)h(slo)m(w)f(do)m(wn)g(the)h(execution)f(sp)s(eed)g(of)g(a)h
+(program.)0 4924 y(The)f(maxim)m(um)g(p)s(ossible)e(I/O)j(sp)s(eed)f
+(of)h(CFITSIO)e(dep)s(ends)g(of)i(course)g(on)f(the)h(t)m(yp)s(e)g(of)g
+(computer)g(system)0 5036 y(that)g(it)e(is)g(running)e(on.)41
+b(As)30 b(a)g(rough)g(guide,)f(the)h(curren)m(t)g(generation)g(of)g(w)m
+(orkstations)g(can)h(ac)m(hiev)m(e)g(sp)s(eeds)0 5149
+y(of)k(2)g({)g(10)g(MB/s)h(when)e(reading)g(or)g(writing)f(FITS)h
+(images)h(and)f(similar,)f(or)i(sligh)m(tly)e(slo)m(w)m(er)i(sp)s(eeds)
+e(with)0 5262 y(FITS)c(binary)g(tables.)40 b(Reading)30
+b(of)g(FITS)g(\014les)f(can)i(o)s(ccur)f(at)h(ev)m(en)f(higher)f(rates)
+i(\(30MB/s)i(or)d(more\))h(if)e(the)0 5375 y(FITS)d(\014le)g(is)f
+(still)g(cac)m(hed)j(in)d(system)i(memory)f(follo)m(wing)g(a)h
+(previous)e(read)h(or)h(write)f(op)s(eration)g(on)h(the)g(same)0
+5488 y(\014le.)43 b(T)-8 b(o)32 b(more)g(accurately)g(predict)e(the)i
+(b)s(est)f(p)s(erformance)g(that)h(is)e(p)s(ossible)f(on)j(an)m(y)g
+(particular)d(system,)k(a)0 5601 y(diagnostic)f(program)h(called)f
+(\\sp)s(eed.c")h(is)f(included)e(with)i(the)h(CFITSIO)e(distribution)e
+(whic)m(h)j(can)h(b)s(e)f(run)0 5714 y(to)f(appro)m(ximately)f(measure)
+g(the)h(maxim)m(um)e(p)s(ossible)f(sp)s(eed)h(of)i(writing)d(and)i
+(reading)g(a)g(test)i(FITS)d(\014le.)p eop
+%%Page: 57 63
+57 62 bop 0 299 a Fg(6.13.)73 b(OPTIMIZING)29 b(CODE)h(F)m(OR)h
+(MAXIMUM)g(PR)m(OCESSING)f(SPEED)971 b Fi(57)0 555 y(The)33
+b(follo)m(wing)e(2)j(sections)f(pro)m(vide)g(some)g(bac)m(kground)g(on)
+h(ho)m(w)f(CFITSIO)f(in)m(ternally)f(manages)j(the)f(data)0
+668 y(I/O)g(and)g(describ)s(es)e(some)j(strategies)g(that)g(ma)m(y)g(b)
+s(e)e(used)h(to)h(optimize)e(the)i(pro)s(cessing)e(sp)s(eed)g(of)h
+(soft)m(w)m(are)0 781 y(that)e(uses)f(CFITSIO.)0 1080
+y Fb(6.13.1)113 b(Bac)m(kground)38 b(Information:)48
+b(Ho)m(w)37 b(CFITSIO)h(Manages)h(Data)f(I/O)0 1300 y
+Fi(Man)m(y)22 b(CFITSIO)e(op)s(erations)h(in)m(v)m(olv)m(e)h
+(transferring)e(only)h(a)h(small)e(n)m(um)m(b)s(er)h(of)h(b)m(ytes)g
+(to)g(or)g(from)f(the)h(FITS)f(\014le)0 1413 y(\(e.g,)31
+b(reading)d(a)h(k)m(eyw)m(ord,)h(or)f(writing)e(a)i(ro)m(w)g(in)e(a)i
+(table\);)h(it)f(w)m(ould)e(b)s(e)h(v)m(ery)i(ine\016cien)m(t)e(to)h
+(ph)m(ysically)e(read)0 1526 y(or)32 b(write)g(suc)m(h)g(small)e(blo)s
+(c)m(ks)i(of)g(data)h(directly)e(in)g(the)h(FITS)g(\014le)f(on)h(disk,)
+g(therefore)g(CFITSIO)f(main)m(tains)0 1639 y(a)38 b(set)g(of)g(in)m
+(ternal)f(Input{Output)e(\(IO\))j(bu\013ers)f(in)f(RAM)i(memory)g(that)
+g(eac)m(h)h(con)m(tain)f(one)g(FITS)f(blo)s(c)m(k)0 1752
+y(\(2880)27 b(b)m(ytes\))f(of)f(data.)40 b(Whenev)m(er)25
+b(CFITSIO)f(needs)g(to)i(access)g(data)g(in)e(the)h(FITS)f(\014le,)i
+(it)e(\014rst)g(transfers)h(the)0 1865 y(FITS)30 b(blo)s(c)m(k)g(con)m
+(taining)g(those)h(b)m(ytes)g(in)m(to)f(one)h(of)f(the)h(IO)f
+(bu\013ers)f(in)g(memory)-8 b(.)42 b(The)30 b(next)g(time)g(CFITSIO)0
+1977 y(needs)36 b(to)g(access)i(b)m(ytes)e(in)f(the)h(same)h(blo)s(c)m
+(k)e(it)h(can)g(then)g(go)h(to)f(the)h(fast)f(IO)f(bu\013er)g(rather)h
+(than)g(using)f(a)0 2090 y(m)m(uc)m(h)d(slo)m(w)m(er)h(system)f(disk)f
+(access)i(routine.)45 b(The)32 b(n)m(um)m(b)s(er)f(of)h(a)m(v)-5
+b(ailable)32 b(IO)g(bu\013ers)f(is)g(determined)g(b)m(y)h(the)0
+2203 y(NIOBUF)f(parameter)g(\(in)e(\014tsio2.h\))h(and)g(is)g(curren)m
+(tly)f(set)i(to)g(40.)0 2363 y(Whenev)m(er)24 b(CFITSIO)f(reads)g(or)h
+(writes)f(data)h(it)g(\014rst)f(c)m(hec)m(ks)i(to)g(see)f(if)f(that)h
+(blo)s(c)m(k)g(of)g(the)g(FITS)f(\014le)f(is)h(already)0
+2476 y(loaded)32 b(in)m(to)g(one)g(of)g(the)g(IO)g(bu\013ers.)44
+b(If)32 b(not,)h(and)e(if)g(there)h(is)f(an)h(empt)m(y)h(IO)e(bu\013er)
+g(a)m(v)-5 b(ailable,)32 b(then)g(it)g(will)0 2589 y(load)g(that)i(blo)
+s(c)m(k)e(in)m(to)g(the)h(IO)g(bu\013er)e(\(when)h(reading)g(a)h(FITS)f
+(\014le\))g(or)h(will)d(initialize)g(a)j(new)f(blo)s(c)m(k)h(\(when)0
+2702 y(writing)i(to)j(a)g(FITS)f(\014le\).)61 b(If)37
+b(all)f(the)i(IO)e(bu\013ers)h(are)g(already)g(full,)g(it)g(m)m(ust)h
+(decide)e(whic)m(h)g(one)i(to)g(reuse)0 2815 y(\(generally)32
+b(the)h(one)g(that)g(has)f(b)s(een)g(accessed)i(least)e(recen)m(tly\),)
+i(and)e(\015ush)f(the)i(con)m(ten)m(ts)h(bac)m(k)g(to)f(disk)e(if)g(it)
+0 2928 y(has)f(b)s(een)g(mo)s(di\014ed)e(b)s(efore)i(loading)f(the)i
+(new)f(blo)s(c)m(k.)0 3088 y(The)g(one)g(ma)5 b(jor)30
+b(exception)h(to)g(the)f(ab)s(o)m(v)m(e)h(pro)s(cess)f(o)s(ccurs)g
+(whenev)m(er)g(a)g(large)h(con)m(tiguous)f(set)h(of)f(b)m(ytes)h(are)0
+3201 y(accessed,)37 b(as)d(migh)m(t)h(o)s(ccur)f(when)f(reading)h(or)g
+(writing)e(a)j(FITS)f(image.)53 b(In)34 b(this)f(case)i(CFITSIO)e(b)m
+(ypasses)0 3314 y(the)i(in)m(ternal)f(IO)h(bu\013ers)f(and)g(simply)f
+(reads)i(or)g(writes)g(the)g(desired)f(b)m(ytes)h(directly)f(in)g(the)h
+(disk)f(\014le)g(with)0 3427 y(a)j(single)e(call)g(to)i(a)g(lo)m(w-lev)
+m(el)f(\014le)f(read)h(or)h(write)e(routine.)57 b(The)36
+b(minim)m(um)e(threshold)g(for)i(the)h(n)m(um)m(b)s(er)e(of)0
+3540 y(b)m(ytes)40 b(to)g(read)f(or)g(write)f(this)h(w)m(a)m(y)h(is)e
+(set)i(b)m(y)f(the)g(MINDIRECT)g(parameter)h(and)e(is)h(curren)m(tly)f
+(set)i(to)g(3)0 3653 y(FITS)28 b(blo)s(c)m(ks)f(=)h(8640)i(b)m(ytes.)41
+b(This)27 b(is)g(the)h(most)h(e\016cien)m(t)g(w)m(a)m(y)g(to)g(read)g
+(or)f(write)g(large)g(c)m(h)m(unks)g(of)g(data)i(and)0
+3766 y(can)37 b(ac)m(hiev)m(e)h(IO)e(transfer)g(rates)h(of)g(5)g({)g
+(10MB/s)i(or)d(greater.)61 b(Note)38 b(that)f(this)f(fast)h(direct)f
+(IO)g(pro)s(cess)g(is)0 3878 y(not)29 b(applicable)d(when)h(accessing)i
+(columns)f(of)g(data)h(in)e(a)i(FITS)f(table)g(b)s(ecause)h(the)f(b)m
+(ytes)h(are)g(generally)f(not)0 3991 y(con)m(tiguous)h(since)f(they)h
+(are)h(in)m(terlea)m(v)m(ed)f(b)m(y)g(the)g(other)g(columns)f(of)h
+(data)g(in)f(the)h(table.)40 b(This)27 b(explains)g(wh)m(y)0
+4104 y(the)k(sp)s(eed)e(for)h(accessing)h(FITS)f(tables)g(is)f
+(generally)h(slo)m(w)m(er)g(than)h(accessing)f(FITS)g(images.)0
+4264 y(Giv)m(en)h(this)g(bac)m(kground)g(information,)f(the)i(general)f
+(strategy)i(for)e(e\016cien)m(tly)g(accessing)h(FITS)f(\014les)f
+(should)0 4377 y(no)m(w)36 b(b)s(e)g(apparen)m(t:)52
+b(when)35 b(dealing)g(with)g(FITS)h(images,)i(read)e(or)g(write)f
+(large)i(c)m(h)m(unks)f(of)g(data)h(at)g(a)f(time)0 4490
+y(so)30 b(that)h(the)f(direct)g(IO)f(mec)m(hanism)g(will)f(b)s(e)h(in)m
+(v)m(ok)m(ed;)i(when)e(accessing)i(FITS)e(headers)h(or)g(FITS)f
+(tables,)h(on)0 4603 y(the)35 b(other)g(hand,)g(once)g(a)g(particular)f
+(FITS)g(blo)s(c)m(k)g(has)g(b)s(een)g(loading)g(in)m(to)h(one)g(of)g
+(the)f(IO)h(bu\013ers,)g(try)f(to)0 4716 y(access)39
+b(all)d(the)h(needed)g(information)f(in)g(that)i(blo)s(c)m(k)f(b)s
+(efore)g(it)g(gets)h(\015ushed)d(out)j(of)g(the)f(IO)g(bu\013er.)60
+b(It)38 b(is)0 4829 y(imp)s(ortan)m(t)30 b(to)i(a)m(v)m(oid)f(the)g
+(situation)f(where)h(the)g(same)g(FITS)f(blo)s(c)m(k)h(is)f(b)s(eing)f
+(read)i(then)g(\015ushed)e(from)h(a)h(IO)0 4942 y(bu\013er)e(m)m
+(ultiple)f(times.)0 5102 y(The)i(follo)m(wing)f(section)h(giv)m(es)h
+(more)f(sp)s(eci\014c)g(suggestions)g(for)g(optimizing)f(the)h(use)g
+(of)h(CFITSIO.)0 5262 y(1.)54 b(When)34 b(dealing)f(with)h(a)h(FITS)e
+(primary)g(arra)m(y)i(or)g(IMA)m(GE)g(extension,)h(it)e(is)f(more)i
+(e\016cien)m(t)g(to)g(read)g(or)0 5375 y(write)30 b(large)g(c)m(h)m
+(unks)g(of)g(the)h(image)f(at)i(a)e(time)g(\(at)i(least)e(3)h(FITS)f
+(blo)s(c)m(ks)f(=)h(8640)i(b)m(ytes\))f(so)g(that)g(the)f(direct)0
+5488 y(IO)j(mec)m(hanism)g(will)d(b)s(e)j(used)g(as)g(describ)s(ed)f
+(in)g(the)h(previous)f(section.)50 b(Smaller)32 b(c)m(h)m(unks)h(of)g
+(data)h(are)g(read)0 5601 y(or)d(written)f(via)h(the)g(IO)f(bu\013ers,)
+g(whic)m(h)g(is)g(somewhat)h(less)f(e\016cien)m(t)i(b)s(ecause)f(of)g
+(the)g(extra)h(cop)m(y)f(op)s(eration)0 5714 y(and)26
+b(additional)e(b)s(o)s(okk)m(eeping)i(steps)h(that)g(are)g(required.)38
+b(In)26 b(principle)d(it)j(is)g(more)g(e\016cien)m(t)h(to)h(read)e(or)h
+(write)p eop
+%%Page: 58 64
+58 63 bop 0 299 a Fi(58)1277 b Fg(CHAPTER)29 b(6.)72
+b(FITSIO)29 b(CONVENTIONS)g(AND)i(GUIDELINES)0 555 y
+Fi(as)e(big)f(an)h(arra)m(y)h(of)f(image)g(pixels)e(at)j(one)f(time)f
+(as)i(p)s(ossible,)d(ho)m(w)m(ev)m(er,)j(if)e(the)i(arra)m(y)f(b)s
+(ecomes)g(so)g(large)g(that)0 668 y(the)j(op)s(erating)f(system)g
+(cannot)h(store)g(it)f(all)g(in)f(RAM,)i(then)f(the)h(p)s(erformance)f
+(ma)m(y)h(b)s(e)f(degraded)g(b)s(ecause)0 781 y(of)g(the)f(increased)g
+(sw)m(apping)f(of)h(virtual)f(memory)h(to)h(disk.)0 941
+y(2.)51 b(When)33 b(dealing)g(with)f(FITS)h(tables,)i(the)f(most)g(imp)
+s(ortan)m(t)f(e\016ciency)g(factor)i(in)d(the)i(soft)m(w)m(are)h
+(design)e(is)0 1054 y(to)k(read)f(or)g(write)f(the)h(data)h(in)e(the)h
+(FITS)g(\014le)f(in)g(a)h(single)f(pass)h(through)f(the)h(\014le.)57
+b(An)36 b(example)g(of)g(p)s(o)s(or)0 1167 y(program)g(design)g(w)m
+(ould)f(b)s(e)h(to)h(read)g(a)f(large,)j(3-column)d(table)g(b)m(y)h
+(sequen)m(tially)e(reading)h(the)g(en)m(tire)h(\014rst)0
+1280 y(column,)24 b(then)g(going)g(bac)m(k)g(to)h(read)e(the)h(2nd)g
+(column,)g(and)f(\014nally)f(the)i(3rd)f(column;)i(this)e(ob)m(viously)
+f(requires)0 1393 y(3)j(passes)f(through)f(the)i(\014le)e(whic)m(h)g
+(could)h(triple)e(the)j(execution)f(time)g(of)h(an)f(I/O)g(limited)e
+(program.)38 b(F)-8 b(or)25 b(small)0 1506 y(tables)30
+b(this)f(is)h(not)g(imp)s(ortan)m(t,)g(but)g(when)f(reading)g(m)m
+(ulti-megab)m(yte)i(sized)f(tables)g(these)h(ine\016ciencies)e(can)0
+1619 y(b)s(ecome)g(signi\014can)m(t.)39 b(The)28 b(more)h(e\016cien)m
+(t)g(pro)s(cedure)e(in)h(this)f(case)j(is)d(to)j(read)e(or)h(write)f
+(only)f(as)i(man)m(y)g(ro)m(ws)0 1732 y(of)g(the)g(table)g(as)g(will)e
+(\014t)h(in)m(to)h(the)h(a)m(v)-5 b(ailable)28 b(in)m(ternal)g(I/O)h
+(bu\013ers,)f(then)h(access)h(all)e(the)h(necessary)g(columns)0
+1844 y(of)i(data)h(within)c(that)k(range)f(of)g(ro)m(ws.)43
+b(Then)29 b(after)j(the)f(program)g(is)f(completely)g(\014nished)f
+(with)g(the)j(data)f(in)0 1957 y(those)i(ro)m(ws)e(it)h(can)g(mo)m(v)m
+(e)i(on)e(to)g(the)h(next)f(range)g(of)g(ro)m(ws)g(that)h(will)c(\014t)
+j(in)f(the)h(bu\013ers,)f(con)m(tin)m(uing)g(in)g(this)0
+2070 y(w)m(a)m(y)d(un)m(til)d(the)h(en)m(tire)h(\014le)f(has)g(b)s(een)
+g(pro)s(cessed.)39 b(By)27 b(using)e(this)h(pro)s(cedure)f(of)i
+(accessing)g(all)f(the)g(columns)g(of)0 2183 y(a)k(table)f(in)f
+(parallel)f(rather)i(than)g(sequen)m(tially)-8 b(,)29
+b(eac)m(h)h(blo)s(c)m(k)f(of)h(the)f(FITS)g(\014le)f(will)e(only)j(b)s
+(e)f(read)i(or)f(written)0 2296 y(once.)0 2456 y(The)g(optimal)f(n)m
+(um)m(b)s(er)g(of)i(ro)m(ws)f(to)i(read)e(or)g(write)g(at)h(one)g(time)
+f(in)f(a)i(giv)m(en)f(table)h(dep)s(ends)d(on)j(the)f(width)f(of)0
+2569 y(the)k(table)g(ro)m(w,)h(on)f(the)g(n)m(um)m(b)s(er)f(of)h(I/O)g
+(bu\013ers)f(that)i(ha)m(v)m(e)g(b)s(een)e(allo)s(cated)h(in)f(FITSIO,)
+g(and)h(also)g(on)g(the)0 2682 y(n)m(um)m(b)s(er)27 b(of)i(other)f
+(FITS)g(\014les)f(that)i(are)g(op)s(en)f(at)h(the)g(same)g(time)f
+(\(since)g(one)h(I/O)f(bu\013er)f(is)h(alw)m(a)m(ys)h(reserv)m(ed)0
+2795 y(for)34 b(eac)m(h)h(op)s(en)f(FITS)f(\014le\).)52
+b(F)-8 b(ortunately)g(,)36 b(a)f(FITSIO)e(routine)g(is)h(a)m(v)-5
+b(ailable)33 b(that)i(will)c(return)j(the)g(optimal)0
+2908 y(n)m(um)m(b)s(er)e(of)i(ro)m(ws)g(for)g(a)g(giv)m(en)f(table:)48
+b(call)33 b(ftgrsz\(unit,)h(nro)m(ws,)g(status\).)52
+b(It)34 b(is)f(not)h(critical)e(to)j(use)e(exactly)0
+3021 y(the)f(v)-5 b(alue)31 b(of)g(nro)m(ws)g(returned)g(b)m(y)g(this)f
+(routine,)h(as)h(long)f(as)h(one)g(do)s(es)f(not)h(exceed)g(it.)44
+b(Using)31 b(a)h(v)m(ery)f(small)0 3134 y(v)-5 b(alue)31
+b(ho)m(w)m(ev)m(er)j(can)e(also)g(lead)f(to)i(p)s(o)s(or)e(p)s
+(erformance)g(b)s(ecause)h(of)g(the)g(o)m(v)m(erhead)h(from)f(the)g
+(larger)f(n)m(um)m(b)s(er)0 3247 y(of)g(subroutine)d(calls.)0
+3407 y(The)36 b(optimal)f(n)m(um)m(b)s(er)h(of)g(ro)m(ws)h(returned)e
+(b)m(y)h(ftgrsz)h(is)f(v)-5 b(alid)35 b(only)g(as)i(long)f(as)h(the)f
+(application)f(program)0 3520 y(is)e(only)h(reading)g(or)g(writing)e
+(data)j(in)f(the)g(sp)s(eci\014ed)f(table.)53 b(An)m(y)34
+b(other)h(calls)e(to)i(access)h(data)f(in)e(the)i(table)0
+3633 y(header)e(or)h(in)e(an)m(y)i(other)g(FITS)f(\014le)g(w)m(ould)f
+(cause)i(additional)e(blo)s(c)m(ks)h(of)h(data)g(to)g(b)s(e)f(loaded)h
+(in)m(to)f(the)h(I/O)0 3745 y(bu\013ers)i(displacing)f(data)j(from)f
+(the)g(original)f(table,)j(and)e(should)e(b)s(e)i(a)m(v)m(oided)g
+(during)e(the)j(critical)e(p)s(erio)s(d)0 3858 y(while)28
+b(the)j(table)f(is)g(b)s(eing)f(read)h(or)g(written.)0
+4019 y(Occasionally)f(it)g(is)f(necessary)i(to)h(sim)m(ultaneously)c
+(access)k(more)f(than)f(one)h(FITS)f(table,)h(for)g(example)f(when)0
+4131 y(transferring)41 b(v)-5 b(alues)42 b(from)g(an)h(input)d(table)j
+(to)g(an)g(output)f(table.)78 b(In)42 b(cases)h(lik)m(e)f(this,)j(one)e
+(should)e(call)0 4244 y(ftgrsz)28 b(to)h(get)g(the)f(optimal)f(n)m(um)m
+(b)s(er)g(of)h(ro)m(ws)g(for)f(eac)m(h)j(table)d(separately)-8
+b(,)30 b(than)d(reduce)h(the)g(n)m(um)m(b)s(er)f(of)h(ro)m(ws)0
+4357 y(prop)s(ortionally)-8 b(.)42 b(F)-8 b(or)33 b(example,)f(if)f
+(the)h(optimal)f(n)m(um)m(b)s(er)f(of)i(ro)m(ws)g(in)e(the)i(input)e
+(table)i(is)f(3600)i(and)e(is)g(1400)0 4470 y(in)h(the)h(output)f
+(table,)i(then)f(these)g(v)-5 b(alues)33 b(should)e(b)s(e)h(cut)h(in)f
+(half)g(to)i(1800)g(and)f(700,)i(resp)s(ectiv)m(ely)-8
+b(,)34 b(if)e(b)s(oth)0 4583 y(tables)e(are)h(going)f(to)h(b)s(e)f
+(accessed)i(at)f(the)f(same)h(time.)0 4743 y(3.)39 b(Use)24
+b(binary)e(table)h(extensions)g(rather)g(than)h(ASCI)s(I)e(table)h
+(extensions)g(for)g(b)s(etter)h(e\016ciency)g(when)e(dealing)0
+4856 y(with)36 b(tabular)h(data.)62 b(The)37 b(I/O)g(to)h(ASCI)s(I)e
+(tables)h(is)g(slo)m(w)m(er)g(b)s(ecause)h(of)f(the)h(o)m(v)m(erhead)h
+(in)d(formatting)h(or)0 4969 y(parsing)29 b(the)i(ASCI)s(I)f(data)h
+(\014elds,)f(and)g(b)s(ecause)h(ASCI)s(I)e(tables)h(are)h(ab)s(out)g(t)
+m(wice)g(as)g(large)g(as)g(binary)e(tables)0 5082 y(with)g(the)i(same)f
+(information)f(con)m(ten)m(t.)0 5242 y(4.)64 b(Design)38
+b(soft)m(w)m(are)h(so)g(that)f(it)g(reads)g(the)g(FITS)f(header)h(k)m
+(eyw)m(ords)g(in)f(the)h(same)h(order)e(in)g(whic)m(h)g(they)0
+5355 y(o)s(ccur)c(in)f(the)h(\014le.)48 b(When)32 b(reading)h(k)m(eyw)m
+(ords,)h(FITSIO)e(searc)m(hes)i(forw)m(ard)e(starting)h(from)f(the)i(p)
+s(osition)d(of)0 5468 y(the)e(last)h(k)m(eyw)m(ord)f(that)h(w)m(as)g
+(read.)40 b(If)29 b(it)f(reac)m(hes)j(the)e(end)g(of)g(the)h(header)f
+(without)f(\014nding)f(the)i(k)m(eyw)m(ord,)h(it)0 5581
+y(then)j(go)s(es)h(bac)m(k)g(to)h(the)e(start)h(of)g(the)g(header)f
+(and)g(con)m(tin)m(ues)g(the)h(searc)m(h)g(do)m(wn)f(to)h(the)g(p)s
+(osition)d(where)i(it)0 5694 y(started.)41 b(In)30 b(practice,)h(as)f
+(long)g(as)h(the)f(en)m(tire)h(FITS)e(header)h(can)h(\014t)f(at)h(one)g
+(time)f(in)f(the)h(a)m(v)-5 b(ailable)30 b(in)m(ternal)p
+eop
+%%Page: 59 65
+59 64 bop 0 299 a Fg(6.13.)73 b(OPTIMIZING)29 b(CODE)h(F)m(OR)h
+(MAXIMUM)g(PR)m(OCESSING)f(SPEED)971 b Fi(59)0 555 y(I/O)33
+b(bu\013ers,)h(then)f(the)h(header)f(k)m(eyw)m(ord)h(access)h(will)30
+b(b)s(e)j(v)m(ery)h(fast)g(and)f(it)g(mak)m(es)h(little)e(di\013erence)
+h(whic)m(h)0 668 y(order)d(they)g(are)h(accessed.)0 828
+y(5.)40 b(Av)m(oid)28 b(the)f(use)h(of)f(scaling)g(\(b)m(y)h(using)e
+(the)i(BSCALE)e(and)h(BZER)m(O)h(or)f(TSCAL)g(and)g(TZER)m(O)f(k)m(eyw)
+m(ords\))0 941 y(in)34 b(FITS)g(\014les)f(since)i(the)g(scaling)f(op)s
+(erations)g(add)g(to)i(the)f(pro)s(cessing)e(time)i(needed)f(to)i(read)
+f(or)g(write)f(the)0 1054 y(data.)60 b(In)36 b(some)i(cases)f(it)f(ma)m
+(y)i(b)s(e)e(more)h(e\016cien)m(t)g(to)g(temp)s(orarily)e(turn)h(o\013)
+h(the)g(scaling)f(\(using)f(ftpscl)h(or)0 1167 y(fttscl\))31
+b(and)e(then)h(read)h(or)f(write)g(the)g(ra)m(w)h(unscaled)e(v)-5
+b(alues)30 b(in)f(the)h(FITS)g(\014le.)0 1327 y(6.)40
+b(Av)m(oid)26 b(using)g(the)h('implicit)d(datat)m(yp)s(e)j(con)m(v)m
+(ersion')g(capabilit)m(y)f(in)f(FITSIO.)h(F)-8 b(or)28
+b(instance,)f(when)f(reading)0 1440 y(a)f(FITS)e(image)i(with)e(BITPIX)
+h(=)g(-32)i(\(32-bit)f(\015oating)f(p)s(oin)m(t)f(pixels\),)i(read)f
+(the)h(data)g(in)m(to)f(a)h(single)e(precision)0 1553
+y(\015oating)f(p)s(oin)m(t)e(data)j(arra)m(y)f(in)f(the)h(program.)37
+b(F)-8 b(orcing)22 b(FITSIO)f(to)h(con)m(v)m(ert)i(the)e(data)g(to)h(a)
+f(di\013eren)m(t)f(datat)m(yp)s(e)0 1666 y(can)31 b(signi\014can)m(tly)
+d(slo)m(w)i(the)h(program.)0 1826 y(7.)57 b(Where)36
+b(feasible,)g(design)f(FITS)g(binary)f(tables)h(using)f(v)m(ector)k
+(column)c(elemen)m(ts)i(so)g(that)g(the)g(data)h(are)0
+1939 y(written)29 b(as)h(a)g(con)m(tiguous)g(set)g(of)g(b)m(ytes,)g
+(rather)g(than)f(as)h(single)e(elemen)m(ts)i(in)f(m)m(ultiple)e(ro)m
+(ws.)41 b(F)-8 b(or)30 b(example,)0 2052 y(it)35 b(is)g(faster)h(to)g
+(access)h(the)f(data)h(in)d(a)i(table)g(that)g(con)m(tains)g(a)g
+(single)e(ro)m(w)i(and)f(2)h(columns)e(with)h(TF)m(ORM)0
+2165 y(k)m(eyw)m(ords)e(equal)g(to)h('10000E')h(and)e('10000J',)j(than)
+d(it)f(is)g(to)i(access)g(the)g(same)f(amoun)m(t)h(of)f(data)h(in)e(a)h
+(table)0 2278 y(with)39 b(10000)k(ro)m(ws)d(whic)m(h)g(has)g(columns)f
+(with)g(the)i(TF)m(ORM)g(k)m(eyw)m(ords)g(equal)f(to)h('1E')h(and)e
+('1J'.)h(In)f(the)0 2391 y(former)27 b(case)i(the)f(10000)i(\015oating)
+e(p)s(oin)m(t)f(v)-5 b(alues)27 b(in)g(the)h(\014rst)f(column)g(are)h
+(all)f(written)g(in)f(a)i(con)m(tiguous)g(blo)s(c)m(k)0
+2503 y(of)e(the)f(\014le)g(whic)m(h)f(can)i(b)s(e)f(read)g(or)g
+(written)g(quic)m(kly)-8 b(,)26 b(whereas)f(in)f(the)i(second)f(case)i
+(eac)m(h)g(\015oating)e(p)s(oin)m(t)f(v)-5 b(alue)0 2616
+y(in)33 b(the)h(\014rst)f(column)f(is)h(in)m(terlea)m(v)m(ed)i(with)d
+(the)i(in)m(teger)h(v)-5 b(alue)33 b(in)g(the)h(second)g(column)e(of)i
+(the)g(same)h(ro)m(w)f(so)0 2729 y(CFITSIO)29 b(has)h(to)h(explicitly)d
+(mo)m(v)m(e)k(to)f(the)g(p)s(osition)d(of)j(eac)m(h)g(elemen)m(t)g(to)g
+(b)s(e)f(read)g(or)g(written.)0 2889 y(8.)52 b(Av)m(oid)34
+b(the)h(use)e(of)i(v)-5 b(ariable)32 b(length)i(v)m(ector)i(columns)c
+(in)h(binary)g(tables,)i(since)e(an)m(y)i(reading)e(or)h(writing)0
+3002 y(of)f(these)g(data)g(requires)e(that)i(CFITSIO)f(\014rst)f(lo)s
+(ok)i(up)e(or)i(compute)g(the)f(starting)h(address)f(of)g(eac)m(h)i(ro)
+m(w)f(of)0 3115 y(data)e(in)e(the)i(heap.)0 3275 y(9.)40
+b(When)26 b(cop)m(ying)g(data)i(from)e(one)g(FITS)g(table)g(to)h
+(another,)h(it)e(is)g(faster)g(to)i(transfer)e(the)g(ra)m(w)h(b)m(ytes)
+g(instead)0 3388 y(of)f(reading)f(then)h(writing)e(eac)m(h)j(column)d
+(of)j(the)f(table.)39 b(The)25 b(FITSIO)g(subroutines)f(FTGTBS)h(and)h
+(FTPTBS)0 3501 y(\(for)i(ASCI)s(I)f(tables\),)i(and)e(FTGTBB)i(and)e
+(FTPTBB)i(\(for)f(binary)e(tables\))i(will)e(p)s(erform)g(lo)m(w-lev)m
+(el)i(reads)g(or)0 3614 y(writes)33 b(of)i(an)m(y)f(con)m(tiguous)h
+(range)g(of)f(b)m(ytes)h(in)e(a)i(table)f(extension.)52
+b(These)34 b(routines)f(can)i(b)s(e)e(used)h(to)h(read)0
+3727 y(or)29 b(write)f(a)h(whole)f(ro)m(w)g(\(or)i(m)m(ultiple)c(ro)m
+(ws\))j(of)g(a)g(table)g(with)e(a)i(single)e(subroutine)g(call.)39
+b(These)29 b(routines)f(are)0 3840 y(fast)38 b(b)s(ecause)f(they)h(b)m
+(ypass)f(all)f(the)i(usual)e(data)i(scaling,)h(error)e(c)m(hec)m(king)h
+(and)f(mac)m(hine)g(dep)s(enden)m(t)f(data)0 3953 y(con)m(v)m(ersion)k
+(that)h(is)d(normally)h(done)g(b)m(y)h(FITSIO,)f(and)g(they)h(allo)m(w)
+f(the)h(program)g(to)h(write)e(the)h(data)g(to)0 4066
+y(the)34 b(output)g(\014le)f(in)g(exactly)i(the)f(same)h(b)m(yte)g
+(order.)51 b(F)-8 b(or)35 b(these)g(same)f(reasons,)i(use)e(of)g(these)
+h(routines)e(can)0 4179 y(b)s(e)g(somewhat)h(risky)e(b)s(ecause)h(no)g
+(v)-5 b(alidation)32 b(or)i(mac)m(hine)f(dep)s(enden)m(t)f(con)m(v)m
+(ersion)i(is)e(p)s(erformed)g(b)m(y)h(these)0 4292 y(routines.)39
+b(In)27 b(general)g(these)i(routines)d(are)i(only)f(recommended)g(for)h
+(optimizing)e(critical)g(pieces)i(of)g(co)s(de)g(and)0
+4405 y(should)d(only)i(b)s(e)g(used)f(b)m(y)i(programmers)e(who)h
+(thoroughly)g(understand)e(the)j(in)m(ternal)e(b)m(yte)i(structure)f
+(of)h(the)0 4517 y(FITS)i(tables)g(they)g(are)h(reading)f(or)g
+(writing.)0 4678 y(10.)41 b(Another)30 b(strategy)g(for)g(impro)m(ving)
+d(the)j(sp)s(eed)e(of)i(writing)e(a)h(FITS)g(table,)h(similar)d(to)j
+(the)f(previous)f(one,)0 4791 y(is)j(to)h(directly)f(construct)h(the)f
+(en)m(tire)h(b)m(yte)g(stream)g(for)g(a)g(whole)f(table)g(ro)m(w)h
+(\(or)g(m)m(ultiple)e(ro)m(ws\))i(within)d(the)0 4903
+y(application)j(program)i(and)g(then)f(write)h(it)f(to)i(the)f(FITS)f
+(\014le)h(with)e(ftptbb.)51 b(This)32 b(a)m(v)m(oids)j(all)e(the)h(o)m
+(v)m(erhead)0 5016 y(normally)e(presen)m(t)i(in)e(the)i(column-orien)m
+(ted)f(CFITSIO)f(write)h(routines.)50 b(This)32 b(tec)m(hnique)h
+(should)f(only)h(b)s(e)0 5129 y(used)26 b(for)h(critical)f
+(applications,)g(b)s(ecause)g(it)h(mak)m(es)h(the)f(co)s(de)g(more)g
+(di\016cult)e(to)i(understand)e(and)i(main)m(tain,)0
+5242 y(and)d(it)g(mak)m(es)i(the)f(co)s(de)g(more)f(system)h(dep)s
+(enden)m(t)f(\(e.g.,)k(do)c(the)h(b)m(ytes)g(need)g(to)g(b)s(e)f(sw)m
+(app)s(ed)g(b)s(efore)g(writing)0 5355 y(to)31 b(the)g(FITS)e
+(\014le?\).)0 5515 y(11.)53 b(Finally)-8 b(,)34 b(external)g(factors)i
+(suc)m(h)e(as)g(the)h(t)m(yp)s(e)f(of)h(magnetic)f(disk)f(con)m
+(troller)h(\(SCSI)f(or)i(IDE\),)g(the)f(size)0 5628 y(of)h(the)g(disk)f
+(cac)m(he,)k(the)d(a)m(v)m(erage)i(seek)f(sp)s(eed)e(of)h(the)g(disk,)g
+(the)g(amoun)m(t)h(of)f(disk)e(fragmen)m(tation,)k(and)e(the)p
+eop
+%%Page: 60 66
+60 65 bop 0 299 a Fi(60)1277 b Fg(CHAPTER)29 b(6.)72
+b(FITSIO)29 b(CONVENTIONS)g(AND)i(GUIDELINES)0 555 y
+Fi(amoun)m(t)e(of)g(RAM)f(a)m(v)-5 b(ailable)28 b(on)h(the)f(system)h
+(can)g(all)e(ha)m(v)m(e)j(a)f(signi\014can)m(t)e(impact)i(on)f(o)m(v)m
+(erall)h(I/O)f(e\016ciency)-8 b(.)0 668 y(F)g(or)36 b(critical)e
+(applications,)g(a)i(system)f(administrator)e(should)g(review)h(the)i
+(prop)s(osed)d(system)j(hardw)m(are)e(to)0 781 y(iden)m(tify)29
+b(an)m(y)i(p)s(oten)m(tial)e(I/O)i(b)s(ottlenec)m(ks.)p
+eop
+%%Page: 61 67
+61 66 bop 0 1225 a Ff(Chapter)65 b(7)0 1687 y Fl(The)77
+b(CFITSIO)f(Iterator)i(F)-19 b(unction)0 2180 y Fi(The)41
+b(\014ts)p 325 2180 28 4 v 33 w(iterate)p 615 2180 V
+33 w(data)i(function)d(in)h(CFITSIO)f(pro)m(vides)h(a)h(unique)d(metho)
+s(d)j(of)g(executing)g(an)f(arbitrary)0 2293 y(user-supplied)33
+b(`w)m(ork')k(function)e(that)i(op)s(erates)g(on)g(ro)m(ws)f(of)h(data)
+g(in)e(FITS)h(tables)g(or)g(on)h(pixels)d(in)i(FITS)0
+2406 y(images.)i(Rather)24 b(than)e(explicitly)f(reading)h(and)h
+(writing)e(the)i(FITS)g(images)g(or)g(columns)f(of)h(data,)i(one)f
+(instead)0 2518 y(calls)34 b(the)i(CFITSIO)d(iterator)j(routine,)g
+(passing)e(to)i(it)f(the)g(name)g(of)h(the)f(user's)g(w)m(ork)g
+(function)f(that)i(is)e(to)0 2631 y(b)s(e)c(executed)h(along)f(with)f
+(a)i(list)e(of)h(all)f(the)i(table)f(columns)f(or)h(image)g(arra)m(ys)h
+(that)g(are)f(to)h(b)s(e)f(passed)g(to)h(the)0 2744 y(w)m(ork)37
+b(function.)60 b(The)37 b(CFITSIO)e(iterator)j(function)e(then)h(do)s
+(es)g(all)f(the)h(w)m(ork)g(of)h(allo)s(cating)e(memory)h(for)0
+2857 y(the)28 b(arra)m(ys,)h(reading)e(the)h(input)d(data)k(from)e(the)
+h(FITS)f(\014le,)g(passing)g(them)h(to)g(the)g(w)m(ork)g(function,)f
+(and)g(then)0 2970 y(writing)34 b(an)m(y)j(output)f(data)h(bac)m(k)h
+(to)f(the)f(FITS)g(\014le)f(after)i(the)g(w)m(ork)g(function)e(exits.)
+58 b(Because)38 b(it)e(is)g(often)0 3083 y(more)h(e\016cien)m(t)h(to)g
+(pro)s(cess)f(only)f(a)i(subset)f(of)g(the)g(total)h(table)g(ro)m(ws)f
+(at)h(one)f(time,)i(the)f(iterator)f(function)0 3196
+y(can)f(determine)f(the)i(optim)m(um)e(amoun)m(t)h(of)g(data)h(to)g
+(pass)e(in)g(eac)m(h)i(iteration)f(and)f(rep)s(eatly)g(call)h(the)g(w)m
+(ork)0 3309 y(function)29 b(un)m(til)g(the)h(en)m(tire)h(table)f(b)s
+(een)f(pro)s(cessed.)0 3469 y(F)-8 b(or)37 b(man)m(y)f(applications)e
+(this)g(single)h(CFITSIO)f(iterator)j(function)d(can)i(e\013ectiv)m
+(ely)h(replace)f(all)f(the)h(other)0 3582 y(CFITSIO)g(routines)h(for)g
+(reading)g(or)g(writing)f(data)i(in)e(FITS)h(images)h(or)f(tables.)63
+b(Using)36 b(the)i(iterator)g(has)0 3695 y(sev)m(eral)31
+b(imp)s(ortan)m(t)e(adv)-5 b(an)m(tages)32 b(o)m(v)m(er)g(the)f
+(traditional)d(metho)s(d)i(of)h(reading)e(and)h(writing)e(FITS)i(data)h
+(\014les:)136 3961 y Fc(\017)46 b Fi(It)33 b(cleanly)f(separates)i(the)
+f(data)h(I/O)f(from)f(the)h(routine)f(that)i(op)s(erates)f(on)g(the)g
+(data.)49 b(This)31 b(leads)h(to)227 4074 y(a)f(more)g(mo)s(dular)d
+(and)i(`ob)5 b(ject)31 b(orien)m(ted')g(programming)e(st)m(yle.)136
+4268 y Fc(\017)46 b Fi(It)27 b(simpli\014es)c(the)k(application)e
+(program)i(b)m(y)f(eliminating)e(the)j(need)g(to)g(allo)s(cate)g
+(memory)g(for)f(the)h(data)227 4381 y(arra)m(ys)e(and)f(eliminates)f
+(most)h(of)h(the)f(calls)g(to)h(the)g(CFITSIO)d(routines)i(that)h
+(explicitly)d(read)i(and)g(write)227 4494 y(the)31 b(data.)136
+4689 y Fc(\017)46 b Fi(It)32 b(ensures)e(that)i(the)g(data)g(are)g(pro)
+s(cessed)f(as)h(e\016cien)m(tly)f(as)g(p)s(ossible.)42
+b(This)30 b(is)g(esp)s(ecially)g(imp)s(ortan)m(t)227
+4801 y(when)44 b(pro)s(cessing)f(tabular)h(data)i(since)e(the)h
+(iterator)g(function)e(will)f(calculate)j(the)g(most)g(e\016cien)m(t)
+227 4914 y(n)m(um)m(b)s(er)36 b(of)i(ro)m(ws)g(in)e(the)i(table)f(to)h
+(b)s(e)f(passed)g(at)i(one)e(time)h(to)g(the)g(user's)e(w)m(ork)i
+(function)e(on)i(eac)m(h)227 5027 y(iteration.)136 5222
+y Fc(\017)46 b Fi(Mak)m(es)39 b(it)d(p)s(ossible)f(for)i(larger)g(pro)5
+b(jects)37 b(to)h(dev)m(elop)f(a)h(library)c(of)k(w)m(ork)f(functions)f
+(that)h(all)f(ha)m(v)m(e)j(a)227 5335 y(uniform)28 b(calling)h
+(sequence)i(and)f(are)h(all)e(indep)s(enden)m(t)f(of)j(the)f(details)g
+(of)g(the)h(FITS)e(\014le)h(format.)0 5601 y(There)g(are)h(basically)e
+(2)j(steps)e(in)g(using)f(the)i(CFITSIO)e(iterator)i(function.)41
+b(The)30 b(\014rst)g(step)h(is)f(to)h(design)f(the)0
+5714 y(w)m(ork)c(function)e(itself)g(whic)m(h)g(m)m(ust)i(ha)m(v)m(e)g
+(a)g(prescrib)s(ed)d(set)j(of)g(input)e(parameters.)39
+b(One)25 b(of)h(these)g(parameters)1905 5942 y(61)p eop
+%%Page: 62 68
+62 67 bop 0 299 a Fi(62)1455 b Fg(CHAPTER)30 b(7.)112
+b(THE)30 b(CFITSIO)e(ITERA)-8 b(TOR)30 b(FUNCTION)0 555
+y Fi(is)e(a)h(structure)g(con)m(taining)g(p)s(oin)m(ters)e(to)j(the)f
+(arra)m(ys)h(of)f(data;)h(the)f(w)m(ork)h(function)d(can)j(p)s(erform)d
+(an)m(y)i(desired)0 668 y(op)s(erations)j(on)i(these)f(arra)m(ys)h(and)
+e(do)s(es)h(not)g(need)g(to)h(w)m(orry)f(ab)s(out)g(ho)m(w)g(the)h
+(input)d(data)j(w)m(ere)f(read)g(from)0 781 y(the)e(\014le)e(or)h(ho)m
+(w)h(the)f(output)g(data)h(get)h(written)d(bac)m(k)i(to)h(the)e
+(\014le.)0 941 y(The)24 b(second)h(step)g(is)e(to)j(design)d(the)i
+(driv)m(er)f(routine)f(that)j(op)s(ens)e(all)f(the)i(necessary)g(FITS)f
+(\014les)g(and)g(initializes)0 1054 y(the)41 b(input)f(parameters)h(to)
+h(the)g(iterator)f(function.)72 b(The)41 b(driv)m(er)f(program)h(calls)
+f(the)i(CFITSIO)e(iterator)0 1167 y(function)29 b(whic)m(h)g(then)h
+(reads)g(the)h(data)g(and)f(passes)g(it)g(to)h(the)g(user's)e(w)m(ork)i
+(function.)0 1327 y(F)-8 b(urther)41 b(details)g(on)h(using)e(the)i
+(iterator)g(function)f(can)h(b)s(e)f(found)f(in)h(the)h(companion)f
+(CFITSIO)f(User's)0 1440 y(Guide,)30 b(and)f(in)g(the)i(iter)p
+875 1440 28 4 v 32 w(a.f,)g(iter)p 1198 1440 V 33 w(b.f)f(and)f(iter)p
+1678 1440 V 33 w(c.f)h(example)g(programs.)p eop
+%%Page: 63 69
+63 68 bop 0 1225 a Ff(Chapter)65 b(8)0 1687 y Fl(Basic)77
+b(In)-6 b(terface)77 b(Routines)0 2180 y Fi(This)26 b(section)h
+(de\014nes)g(a)h(basic)f(set)h(of)g(subroutines)d(that)j(can)g(b)s(e)f
+(used)g(to)h(p)s(erform)e(the)i(most)g(common)g(t)m(yp)s(es)0
+2293 y(of)d(read)g(and)f(write)g(op)s(erations)g(on)h(FITS)f(\014les.)
+38 b(New)25 b(users)f(should)f(start)i(with)f(these)h(subroutines)e
+(and)h(then,)0 2406 y(as)33 b(needed,)h(explore)e(the)i(more)f(adv)-5
+b(ance)33 b(routines)f(describ)s(ed)f(in)h(the)h(follo)m(wing)f(c)m
+(hapter)h(to)h(p)s(erform)e(more)0 2518 y(complex)e(or)g(sp)s
+(ecialized)f(op)s(erations.)0 2679 y(A)h(righ)m(t)f(arro)m(w)h(sym)m(b)
+s(ol)e(\()p Fa(>)p Fi(\))i(is)f(used)g(to)h(separate)h(the)e(input)f
+(parameters)i(from)f(the)h(output)f(parameters)h(in)0
+2791 y(the)i(de\014nition)d(of)i(eac)m(h)i(routine.)43
+b(This)29 b(sym)m(b)s(ol)i(is)f(not)i(actually)f(part)g(of)h(the)f
+(calling)f(sequence.)45 b(Note)32 b(that)0 2904 y(the)f(status)h
+(parameter)g(is)e(b)s(oth)h(an)g(input)e(and)i(an)g(output)g(parameter)
+h(and)e(m)m(ust)h(b)s(e)g(initialized)d(=)j(0)h(prior)0
+3017 y(to)f(calling)e(the)i(FITSIO)e(subroutines.)0 3177
+y(Refer)h(to)i(Chapter)d(9)i(for)f(the)h(de\014nition)d(of)i(all)g(the)
+g(parameters)h(used)e(b)m(y)i(these)g(in)m(terface)f(routines.)0
+3525 y Fd(8.1)135 b(FITSIO)44 b(Error)h(Status)h(Routines)0
+3773 y Fh(1)81 b Fi(Return)24 b(the)i(curren)m(t)f(v)m(ersion)g(n)m(um)
+m(b)s(er)f(of)i(the)f(\014tsio)g(library)-8 b(.)37 b(The)25
+b(v)m(ersion)g(n)m(um)m(b)s(er)f(will)f(b)s(e)h(incremen)m(ted)227
+3886 y(with)29 b(eac)m(h)j(new)e(release)g(of)h(CFITSIO.)382
+4157 y Fe(FTVERS\()46 b(>)h(version\))0 4429 y Fh(2)81
+b Fi(Return)45 b(the)i(descriptiv)m(e)e(text)i(string)f(corresp)s
+(onding)e(to)j(a)g(FITSIO)e(error)h(status)h(co)s(de.)89
+b(The)46 b(30-)227 4541 y(c)m(haracter)32 b(length)e(string)f(con)m
+(tains)i(a)g(brief)e(description)f(of)i(the)h(cause)g(of)f(the)h
+(error.)382 4813 y Fe(FTGERR\(status,)44 b(>)j(errtext\))0
+5084 y Fh(3)81 b Fi(Return)40 b(the)h(top)g(\(oldest\))g(80-c)m
+(haracter)j(error)c(message)i(from)f(the)g(in)m(ternal)e(FITSIO)h(stac)
+m(k)i(of)f(error)227 5197 y(messages)29 b(and)f(shift)f(an)m(y)h
+(remaining)e(messages)j(on)f(the)g(stac)m(k)i(up)d(one)h(lev)m(el.)40
+b(An)m(y)28 b(FITSIO)f(error)h(will)227 5310 y(generate)h(one)e(or)g
+(more)h(messages)g(on)f(the)g(stac)m(k.)41 b(Call)26
+b(this)g(routine)g(rep)s(eatedly)g(to)i(get)h(eac)m(h)f(message)227
+5422 y(in)h(sequence.)41 b(The)30 b(error)g(stac)m(k)i(is)e(empt)m(y)g
+(when)g(a)g(blank)f(string)h(is)f(returned.)382 5694
+y Fe(FTGMSG\()46 b(>)h(errmsg\))1905 5942 y Fi(63)p eop
+%%Page: 64 70
+64 69 bop 0 299 a Fi(64)1747 b Fg(CHAPTER)30 b(8.)111
+b(BASIC)30 b(INTERF)-10 b(A)m(CE)30 b(R)m(OUTINES)0 555
+y Fh(4)81 b Fi(The)33 b(FTPMRK)h(routine)f(puts)h(an)g(in)m(visible)d
+(mark)m(er)j(on)g(the)h(CFITSIO)d(error)i(stac)m(k.)54
+b(The)33 b(FTCMRK)227 668 y(routine)40 b(can)h(then)g(b)s(e)f(used)g
+(to)h(delete)g(an)m(y)g(more)g(recen)m(t)h(error)e(messages)i(on)f(the)
+g(stac)m(k,)k(bac)m(k)c(to)227 781 y(the)32 b(p)s(osition)d(of)i(the)g
+(mark)m(er.)43 b(This)30 b(preserv)m(es)h(an)m(y)g(older)g(error)f
+(messages)i(on)f(the)h(stac)m(k.)44 b(FTCMSG)227 894
+y(simply)21 b(clears)h(the)h(en)m(tire)g(error)f(message)i(stac)m(k.)40
+b(These)23 b(routines)e(are)i(called)f(without)g(an)m(y)h(argumen)m
+(ts.)382 1152 y Fe(FTPMRK)382 1265 y(FTCMRK)382 1378
+y(FTCMSG)0 1637 y Fh(5)81 b Fi(Prin)m(t)29 b(out)i(the)g(error)f
+(message)i(corresp)s(onding)d(to)i(the)g(input)e(status)i(v)-5
+b(alue)30 b(and)g(all)g(the)h(error)f(messages)227 1750
+y(on)g(the)h(FITSIO)e(stac)m(k)i(to)g(the)g(sp)s(eci\014ed)d(\014le)i
+(stream)g(\(stream)h(can)g(b)s(e)e(either)h(the)g(string)f('STDOUT')227
+1863 y(or)i('STDERR'\).)f(If)g(the)h(input)d(status)j(v)-5
+b(alue)30 b(=)g(0)h(then)f(this)f(routine)g(do)s(es)h(nothing.)334
+2121 y Fe(FTRPRT)46 b(\(stream,)g(>)h(status\))0 2380
+y Fh(6)81 b Fi(W)-8 b(rite)38 b(an)g(80-c)m(haracter)j(message)e(to)g
+(the)f(FITSIO)f(error)h(stac)m(k.)65 b(Application)36
+b(programs)i(should)e(not)227 2493 y(normally)29 b(write)g(to)j(the)e
+(stac)m(k,)i(but)e(there)g(ma)m(y)h(b)s(e)f(some)h(situations)e(where)h
+(this)f(is)h(desirable.)382 2751 y Fe(FTPMSG\(errmsg\))0
+3085 y Fd(8.2)135 b(File)46 b(I/O)f(Routines)0 3325 y
+Fh(1)81 b Fi(Op)s(en)34 b(an)h(existing)g(FITS)f(\014le)h(with)f
+(readonly)h(or)g(readwrite)g(access.)58 b(This)33 b(routine)i(alw)m(a)m
+(ys)h(op)s(ens)f(the)227 3438 y(primary)29 b(arra)m(y)j(\(the)f
+(\014rst)f(HDU\))i(of)f(the)h(\014le,)e(and)g(do)s(es)h(not)g(mo)m(v)m
+(e)h(to)g(a)f(follo)m(wing)f(extension,)h(if)f(one)227
+3551 y(w)m(as)d(sp)s(eci\014ed)e(as)h(part)h(of)f(the)h(\014lename.)38
+b(Use)27 b(the)g(FTNOPN)f(routine)f(to)i(automatically)g(mo)m(v)m(e)h
+(to)f(the)227 3664 y(extension.)43 b(This)30 b(routine)g(will)f(also)i
+(op)s(en)g(IRAF)g(images)h(\(.imh)e(format)i(\014les\))f(and)f(ra)m(w)i
+(binary)d(data)227 3776 y(arra)m(ys)f(with)e(READONL)-8
+b(Y)28 b(access)h(b)m(y)e(\014rst)g(con)m(v)m(erting)h(them)f(on)g(the)
+h(\015y)f(in)m(to)g(virtual)f(FITS)h(images.)227 3889
+y(See)36 b(the)g(`Extended)f(File)g(Name)i(Syn)m(tax')f(c)m(hapter)g
+(for)f(more)h(details.)56 b(The)35 b(second)h(routine)e(simply)227
+4002 y(op)s(ens)e(the)g(sp)s(eci\014ed)f(\014le)h(without)f(trying)h
+(to)h(in)m(terpret)f(the)g(\014lename)g(using)f(the)h(extended)h
+(\014lename)227 4115 y(syn)m(tax.)382 4374 y Fe
+(FTOPEN\(unit,filename,rwm)o(ode)o(,)42 b(>)47 b(blocksize,status\))382
+4487 y(FTDKOPEN\(unit,filename,r)o(wmo)o(de,)41 b(>)48
+b(blocksize,status\))0 4745 y Fh(2)81 b Fi(Op)s(en)24
+b(an)i(existing)f(FITS)g(\014le)g(with)f(readonly)h(or)h(readwrite)f
+(access)i(and)f(mo)m(v)m(e)h(to)f(a)h(follo)m(wing)d(extension,)227
+4858 y(if)37 b(one)h(w)m(as)g(sp)s(eci\014ed)f(as)h(part)f(of)h(the)h
+(\014lename.)62 b(\(e.g.,)42 b('\014lename.\014ts+2')37
+b(or)h('\014lename.\014ts[2]')h(will)227 4971 y(mo)m(v)m(e)f(to)g(the)e
+(3rd)g(HDU)i(in)d(the)i(\014le\).)59 b(Note)37 b(that)h(this)d(routine)
+h(di\013ers)f(from)h(FTOPEN)g(in)f(that)i(it)227 5084
+y(do)s(es)30 b(not)h(ha)m(v)m(e)h(the)e(redundan)m(t)f(blo)s(c)m(ksize)
+h(argumen)m(t.)382 5342 y Fe(FTNOPN\(unit,filename,rwm)o(ode)o(,)42
+b(>)47 b(status\))0 5601 y Fh(3)81 b Fi(Op)s(en)31 b(an)h(existing)f
+(FITS)h(\014le)f(with)g(readonly)h(or)g(readwrite)g(access)h(and)f
+(then)g(mo)m(v)m(e)i(to)f(the)g(\014rst)e(HDU)227 5714
+y(con)m(taining)25 b(signi\014can)m(t)g(data,)i(if)d(a\))j(an)e(HDU)h
+(name)g(or)f(n)m(um)m(b)s(er)f(to)i(op)s(en)f(w)m(as)h(not)g
+(explicitly)d(sp)s(eci\014ed)p eop
+%%Page: 65 71
+65 70 bop 0 299 a Fg(8.2.)72 b(FILE)30 b(I/O)h(R)m(OUTINES)2693
+b Fi(65)227 555 y(as)31 b(part)g(of)g(the)g(\014lename,)g(and)f(b\))h
+(if)f(the)h(FITS)f(\014le)g(con)m(tains)h(a)h(n)m(ull)c(primary)h(arra)
+m(y)j(\(i.e.,)g(NAXIS)e(=)227 668 y(0\).)41 b(In)26 b(this)h(case,)i
+(it)e(will)e(lo)s(ok)i(for)g(the)h(\014rst)e(IMA)m(GE)j(HDU)f(with)e
+(NAXIS)h(>)h(0,)g(or)g(the)f(\014rst)g(table)g(that)227
+781 y(do)s(es)h(not)g(con)m(tain)f(the)h(strings)f(`GTI')h(\(Go)s(o)s
+(d)f(Time)g(In)m(terv)-5 b(al\))28 b(or)g(`OBST)-8 b(ABLE')28
+b(in)e(the)i(EXTNAME)227 894 y(k)m(eyw)m(ord)37 b(v)-5
+b(alue.)60 b(FTTOPN)36 b(is)f(similar,)h(except)i(it)e(will)e(mo)m(v)m
+(e)39 b(to)e(the)g(\014rst)f(signi\014can)m(t)g(table)g(HDU)227
+1007 y(\(skipping)24 b(o)m(v)m(er)i(an)m(y)g(image)g(HDUs\))h(in)d(the)
+i(\014le)f(if)f(a)i(sp)s(eci\014c)f(HDU)h(name)g(or)g(n)m(um)m(b)s(er)e
+(is)h(not)g(sp)s(eci\014ed.)227 1120 y(FTIOPN)30 b(will)e(mo)m(v)m(e)k
+(to)f(the)f(\014rst)g(non-n)m(ull)e(image)j(HDU,)g(skipping)d(o)m(v)m
+(er)j(an)m(y)g(tables.)382 1372 y Fe(FTDOPN\(unit,filename,rwm)o(ode)o
+(,)42 b(>)47 b(status\))382 1485 y(FTTOPN\(unit,filename,rwm)o(ode)o(,)
+42 b(>)47 b(status\))382 1598 y(FTIOPN\(unit,filename,rwm)o(ode)o(,)42
+b(>)47 b(status\))0 1851 y Fh(4)81 b Fi(Op)s(en)30 b(and)h(initialize)e
+(a)j(new)f(empt)m(y)h(FITS)e(\014le.)44 b(A)31 b(template)h(\014le)f
+(ma)m(y)h(also)g(b)s(e)f(sp)s(eci\014ed)f(to)i(de\014ne)f(the)227
+1964 y(structure)h(of)h(the)g(new)f(\014le)f(\(see)j(section)e
+(4.2.4\).)50 b(The)32 b(second)g(routine)g(simply)e(creates)k(the)f(sp)
+s(eci\014ed)227 2077 y(\014le)d(without)f(trying)h(to)h(in)m(terpret)e
+(the)i(\014lename)f(using)e(the)j(extended)f(\014lename)g(syn)m(tax.)
+382 2330 y Fe(FTINIT\(unit,filename,blo)o(cks)o(ize,)41
+b(>)48 b(status\))382 2442 y(FTDKINIT\(unit,filename,b)o(loc)o(ksiz)o
+(e,)42 b(>)47 b(status\))0 2695 y Fh(5)81 b Fi(Close)30
+b(a)g(FITS)g(\014le)f(previously)f(op)s(ened)i(with)f(ftop)s(en)h(or)g
+(ftinit)382 2948 y Fe(FTCLOS\(unit,)44 b(>)k(status\))0
+3201 y Fh(6)81 b Fi(Mo)m(v)m(e)32 b(to)f(a)g(sp)s(eci\014ed)e
+(\(absolute\))h(HDU)h(in)f(the)g(FITS)g(\014le)f(\(nhdu)g(=)h(1)h(for)f
+(the)g(FITS)g(primary)e(arra)m(y\))382 3453 y Fe(FTMAHD\(unit,nhdu,)43
+b(>)k(hdutype,status\))0 3706 y Fh(7)81 b Fi(Create)30
+b(a)f(primary)e(arra)m(y)j(\(if)f(none)g(already)f(exists\),)i(or)f
+(insert)f(a)i(new)f(IMA)m(GE)h(extension)f(immediately)227
+3819 y(follo)m(wing)22 b(the)h(CHDU,)g(or)g(insert)f(a)h(new)g(Primary)
+e(Arra)m(y)i(at)h(the)f(b)s(eginning)d(of)j(the)g(\014le.)37
+b(An)m(y)23 b(follo)m(wing)227 3932 y(extensions)28 b(in)g(the)h
+(\014le)e(will)f(b)s(e)i(shifted)g(do)m(wn)g(to)h(mak)m(e)h(ro)s(om)e
+(for)h(the)g(new)f(extension.)39 b(If)29 b(the)g(CHDU)227
+4045 y(is)g(the)h(last)f(HDU)h(in)f(the)g(\014le)g(then)g(the)h(new)f
+(image)h(extension)f(will)e(simply)g(b)s(e)i(app)s(ended)f(to)i(the)g
+(end)227 4158 y(of)k(the)h(\014le.)51 b(One)33 b(can)h(force)h(a)g(new)
+e(primary)f(arra)m(y)j(to)g(b)s(e)e(inserted)g(at)i(the)f(b)s(eginning)
+d(of)j(the)h(FITS)227 4271 y(\014le)29 b(b)m(y)g(setting)g(status)h(=)f
+(-9)h(prior)e(to)i(calling)d(the)j(routine.)39 b(In)29
+b(this)f(case)i(the)g(old)e(primary)g(arra)m(y)i(will)227
+4384 y(b)s(e)c(con)m(v)m(erted)j(to)e(an)g(IMA)m(GE)g(extension.)39
+b(The)27 b(new)f(extension)g(\(or)h(primary)e(arra)m(y\))j(will)c(b)s
+(ecome)j(the)227 4496 y(CHDU.)382 4749 y Fe(FTIIMG\(unit,bitpix,naxis)o
+(,na)o(xes,)41 b(>)48 b(status\))0 5002 y Fh(8)81 b Fi(Insert)30
+b(a)i(new)f(ASCI)s(I)f(T)-8 b(ABLE)31 b(extension)g(immediately)f
+(follo)m(wing)f(the)j(CHDU.)g(An)m(y)f(follo)m(wing)f(exten-)227
+5115 y(sions)25 b(will)e(b)s(e)i(shifted)f(do)m(wn)h(to)h(mak)m(e)h(ro)
+s(om)e(for)h(the)f(new)g(extension.)39 b(If)25 b(there)h(are)g(no)g
+(other)f(follo)m(wing)227 5228 y(extensions)31 b(then)g(the)h(new)f
+(table)g(extension)g(will)e(simply)g(b)s(e)i(app)s(ended)f(to)i(the)f
+(end)g(of)h(the)f(\014le.)43 b(The)227 5341 y(new)30
+b(extension)g(will)e(b)s(ecome)j(the)f(CHDU.)382 5593
+y Fe(FTITAB\(unit,rowlen,nrows)o(,tf)o(ield)o(s,tt)o(ype)o(,tbc)o(ol,t)
+o(for)o(m,tu)o(nit,)o(ext)o(name)o(,)42 b(>)716 5706
+y(status\))p eop
+%%Page: 66 72
+66 71 bop 0 299 a Fi(66)1747 b Fg(CHAPTER)30 b(8.)111
+b(BASIC)30 b(INTERF)-10 b(A)m(CE)30 b(R)m(OUTINES)0 555
+y Fh(9)81 b Fi(Insert)26 b(a)h(new)g(binary)e(table)h(extension)h
+(immediately)e(follo)m(wing)h(the)h(CHDU.)g(An)m(y)g(follo)m(wing)e
+(extensions)227 668 y(will)36 b(b)s(e)i(shifted)f(do)m(wn)h(to)h(mak)m
+(e)g(ro)s(om)g(for)f(the)g(new)g(extension.)65 b(If)38
+b(there)h(are)f(no)h(other)f(follo)m(wing)227 781 y(extensions)e(then)h
+(the)f(new)g(bin)m(table)f(extension)i(will)d(simply)g(b)s(e)i(app)s
+(ended)e(to)k(the)e(end)g(of)h(the)g(\014le.)227 894
+y(The)30 b(new)g(extension)g(will)e(b)s(ecome)j(the)f(CHDU.)382
+1137 y Fe(FTIBIN\(unit,nrows,tfield)o(s,t)o(type)o(,tfo)o(rm,)o(tuni)o
+(t,ex)o(tna)o(me,v)o(arid)o(at)41 b(>)48 b(status\))0
+1468 y Fd(8.3)135 b(Keyw)l(ord)46 b(I/O)f(Routines)0
+1705 y Fh(1)81 b Fi(Put)30 b(\(app)s(end\))f(an)h(80-c)m(haracter)j
+(record)e(in)m(to)f(the)h(CHU.)382 1948 y Fe(FTPREC\(unit,card,)43
+b(>)k(status\))0 2191 y Fh(2)81 b Fi(Put)28 b(\(app)s(end\))g(a)h(new)g
+(k)m(eyw)m(ord)g(of)g(the)g(appropriate)f(datat)m(yp)s(e)i(in)m(to)f
+(the)g(CHU.)g(The)f(E)h(and)f(D)i(v)m(ersions)227 2304
+y(of)24 b(this)e(routine)g(ha)m(v)m(e)i(the)g(added)e(feature)i(that)g
+(if)e(the)h('decimals')g(parameter)h(is)e(negativ)m(e,)k(then)d(the)g
+('G')227 2417 y(displa)m(y)28 b(format)i(rather)f(then)g(the)h('E')f
+(format)h(will)d(b)s(e)i(used)f(when)h(constructing)g(the)g(k)m(eyw)m
+(ord)h(v)-5 b(alue,)227 2530 y(taking)26 b(the)h(absolute)f(v)-5
+b(alue)25 b(of)i('decimals')e(for)h(the)h(precision.)37
+b(This)25 b(will)e(suppress)h(trailing)h(zeros,)j(and)227
+2643 y(will)34 b(use)j(a)g(\014xed)f(format)h(rather)g(than)f(an)h(exp)
+s(onen)m(tial)e(format,)k(dep)s(ending)34 b(on)j(the)g(magnitude)f(of)
+227 2755 y(the)31 b(v)-5 b(alue.)382 2998 y Fe
+(FTPKY[JLS]\(unit,keyword,)o(key)o(val,)o(comm)o(ent)o(,)42
+b(>)47 b(status\))382 3111 y(FTPKY[EDFG]\(unit,keyword)o(,ke)o(yval)o
+(,dec)o(ima)o(ls,c)o(omme)o(nt,)41 b(>)48 b(status\))0
+3354 y Fh(3)81 b Fi(Get)37 b(the)f(n)m(th)f(80-c)m(haracter)k(header)d
+(record)g(from)f(the)h(CHU.)h(The)e(\014rst)g(k)m(eyw)m(ord)i(in)d(the)
+i(header)g(is)f(at)227 3467 y(k)m(ey)p 365 3467 28 4
+v 34 w(no)42 b(=)f(1;)49 b(if)41 b(k)m(ey)p 996 3467
+V 34 w(no)h(=)f(0)i(then)e(this)g(subroutine)f(simple)g(mo)m(v)m(es)k
+(the)e(in)m(ternal)f(p)s(oin)m(ter)g(to)i(the)227 3580
+y(b)s(eginning)33 b(of)j(the)g(header)f(so)h(that)g(subsequen)m(t)f(k)m
+(eyw)m(ord)h(op)s(erations)f(will)e(start)j(at)g(the)g(top)g(of)g(the)
+227 3693 y(header;)31 b(it)f(also)g(returns)f(a)i(blank)e(card)h(v)-5
+b(alue)30 b(in)f(this)g(case.)382 3936 y Fe(FTGREC\(unit,key_no,)42
+b(>)48 b(card,status\))0 4178 y Fh(4)81 b Fi(Get)31 b(a)g(k)m(eyw)m
+(ord)g(v)-5 b(alue)29 b(\(with)h(the)g(appropriate)g(datat)m(yp)s(e\))h
+(and)f(commen)m(t)i(from)e(the)g(CHU)382 4421 y Fe
+(FTGKY[EDJLS]\(unit,keywor)o(d,)41 b(>)48 b(keyval,comment,status\))0
+4664 y Fh(5)81 b Fi(Delete)31 b(an)f(existing)g(k)m(eyw)m(ord)h
+(record.)382 4907 y Fe(FTDKEY\(unit,keyword,)42 b(>)48
+b(status\))0 5238 y Fd(8.4)135 b(Data)46 b(I/O)g(Routines)0
+5488 y Fi(The)32 b(follo)m(wing)f(routines)g(read)i(or)f(write)g(data)h
+(v)-5 b(alues)32 b(in)f(the)i(curren)m(t)f(HDU)i(of)e(the)h(FITS)f
+(\014le.)46 b(Automatic)0 5601 y(datat)m(yp)s(e)28 b(con)m(v)m(ersion)g
+(will)c(b)s(e)j(attempted)h(for)g(n)m(umerical)d(datat)m(yp)s(es)k(if)d
+(the)h(sp)s(eci\014ed)f(datat)m(yp)s(e)i(is)e(di\013eren)m(t)0
+5714 y(from)k(the)g(actual)h(datat)m(yp)s(e)h(of)e(the)h(FITS)e(arra)m
+(y)i(or)f(table)h(column.)p eop
+%%Page: 67 73
+67 72 bop 0 299 a Fg(8.4.)72 b(D)m(A)-8 b(T)g(A)32 b(I/O)f(R)m(OUTINES)
+2650 b Fi(67)0 555 y Fh(1)81 b Fi(W)-8 b(rite)30 b(elemen)m(ts)h(in)m
+(to)f(the)h(primary)d(data)k(arra)m(y)e(or)h(image)f(extension.)382
+771 y Fe(FTPPR[BIJED]\(unit,group,)o(fpi)o(xel,)o(nele)o(men)o(ts,v)o
+(alue)o(s,)41 b(>)48 b(status\))0 987 y Fh(2)81 b Fi(Read)30
+b(elemen)m(ts)i(from)e(the)h(primary)d(data)k(arra)m(y)f(or)g(image)g
+(extension.)41 b(Unde\014ned)29 b(arra)m(y)j(elemen)m(ts)f(will)227
+1100 y(b)s(e)g(returned)f(with)g(a)i(v)-5 b(alue)30 b(=)h(n)m(ullv)-5
+b(al,)30 b(unless)f(n)m(ullv)-5 b(al)29 b(=)i(0)h(in)e(whic)m(h)g(case)
+i(no)f(c)m(hec)m(ks)i(for)e(unde\014ned)227 1213 y(pixels)f(will)e(b)s
+(e)i(p)s(erformed.)42 b(The)30 b(an)m(yf)i(parameter)f(is)f(set)i(to)g
+(true)f(\(=)g(.true.\))43 b(if)30 b(an)m(y)i(of)f(the)g(returned)227
+1326 y(elemen)m(ts)g(w)m(ere)g(unde\014ned.)382 1542
+y Fe(FTGPV[BIJED]\(unit,group,)o(fpi)o(xel,)o(nele)o(men)o(ts,n)o(ullv)
+o(al,)41 b(>)48 b(values,anyf,status\))0 1758 y Fh(3)81
+b Fi(W)-8 b(rite)35 b(elemen)m(ts)h(in)m(to)f(an)g(ASCI)s(I)e(or)i
+(binary)f(table)h(column.)53 b(The)35 b(`felem')g(parameter)h(applies)d
+(only)h(to)227 1871 y(v)m(ector)e(columns)d(in)g(binary)g(tables)h(and)
+g(is)f(ignored)h(when)f(writing)g(to)i(ASCI)s(I)d(tables.)382
+2087 y Fe(FTPCL[SLBIJEDCM]\(unit,co)o(lnu)o(m,fr)o(ow,f)o(ele)o(m,ne)o
+(leme)o(nts)o(,val)o(ues,)41 b(>)47 b(status\))0 2303
+y Fh(4)81 b Fi(Read)22 b(elemen)m(ts)g(from)f(an)g(ASCI)s(I)g(or)g
+(binary)f(table)i(column.)37 b(Unde\014ned)20 b(arra)m(y)i(elemen)m(ts)
+g(will)d(b)s(e)i(returned)227 2416 y(with)31 b(a)i(v)-5
+b(alue)32 b(=)g(n)m(ullv)-5 b(al,)31 b(unless)g(n)m(ullv)-5
+b(al)29 b(=)k(0)f(\(or)h(=)f(')h(')f(for)g(ftgcvs\))i(in)d(whic)m(h)g
+(case)j(no)e(c)m(hec)m(king)h(for)227 2529 y(unde\014ned)23
+b(v)-5 b(alues)24 b(will)e(b)s(e)j(p)s(erformed.)37 b(The)24
+b(ANYF)i(parameter)f(is)f(set)i(to)f(true)g(if)f(an)m(y)h(of)g(the)g
+(returned)227 2642 y(elemen)m(ts)31 b(are)g(unde\014ned.)227
+2785 y(An)m(y)d(column,)g(regardless)f(of)h(it's)g(in)m(trinsic)d
+(datat)m(yp)s(e,)30 b(ma)m(y)e(b)s(e)f(read)h(as)g(a)h(string.)39
+b(It)28 b(should)d(b)s(e)j(noted)227 2898 y(ho)m(w)m(ev)m(er)k(that)f
+(reading)e(a)i(n)m(umeric)e(column)g(as)i(a)g(string)e(is)g(10)j(-)e
+(100)i(times)e(slo)m(w)m(er)g(than)g(reading)g(the)227
+3011 y(same)36 b(column)e(as)i(a)g(n)m(um)m(b)s(er)e(due)g(to)j(the)e
+(large)h(o)m(v)m(erhead)g(in)e(constructing)h(the)h(formatted)g
+(strings.)227 3124 y(The)i(displa)m(y)e(format)i(of)g(the)g(returned)f
+(strings)f(will)f(b)s(e)j(determined)e(b)m(y)i(the)g(TDISPn)f(k)m(eyw)m
+(ord,)j(if)227 3237 y(it)c(exists,)h(otherwise)f(b)m(y)g(the)g(datat)m
+(yp)s(e)h(of)f(the)h(column.)56 b(The)36 b(length)f(of)i(the)f
+(returned)f(strings)g(can)227 3350 y(b)s(e)29 b(determined)e(with)h
+(the)h(ftgcdw)g(routine.)39 b(The)28 b(follo)m(wing)g(TDISPn)f(displa)m
+(y)h(formats)h(are)g(curren)m(tly)227 3463 y(supp)s(orted:)418
+3661 y Fe(Iw.m)142 b(Integer)418 3774 y(Ow.m)g(Octal)47
+b(integer)418 3887 y(Zw.m)142 b(Hexadecimal)45 b(integer)418
+4000 y(Fw.d)142 b(Fixed)47 b(floating)e(point)418 4113
+y(Ew.d)142 b(Exponential)45 b(floating)h(point)418 4226
+y(Dw.d)142 b(Exponential)45 b(floating)h(point)418 4339
+y(Gw.d)142 b(General;)46 b(uses)g(Fw.d)h(if)g(significance)e(not)i
+(lost,)f(else)h(Ew.d)227 4538 y Fi(where)24 b(w)h(is)e(the)i(width)e
+(in)g(c)m(haracters)j(of)f(the)g(displa)m(y)m(ed)e(v)-5
+b(alues,)26 b(m)e(is)g(the)g(minim)m(um)e(n)m(um)m(b)s(er)i(of)g
+(digits)227 4651 y(displa)m(y)m(ed,)29 b(and)g(d)h(is)e(the)j(n)m(um)m
+(b)s(er)d(of)i(digits)e(to)j(the)f(righ)m(t)g(of)g(the)g(decimal.)39
+b(The)29 b(.m)h(\014eld)f(is)g(optional.)382 4867 y Fe
+(FTGCV[SBIJEDCM]\(unit,col)o(num)o(,fro)o(w,fe)o(lem)o(,nel)o(emen)o
+(ts,)o(null)o(val,)41 b(>)1098 4980 y(values,anyf,status\))0
+5196 y Fh(5)81 b Fi(Get)42 b(the)g(table)g(column)e(n)m(um)m(b)s(er)h
+(and)g(full)e(name)j(of)g(the)f(column)g(whose)g(name)h(matc)m(hes)h
+(the)f(input)227 5309 y(template)34 b(string.)47 b(See)33
+b(the)h(`Adv)-5 b(anced)33 b(In)m(terface)h(Routines')e(c)m(hapter)i
+(for)f(a)g(full)e(description)g(of)i(this)227 5422 y(routine.)382
+5638 y Fe(FTGCNN\(unit,casesen,colt)o(emp)o(late)o(,)42
+b(>)47 b(colname,colnum,status\))p eop
+%%Page: 68 74
+68 73 bop 0 299 a Fi(68)1747 b Fg(CHAPTER)30 b(8.)111
+b(BASIC)30 b(INTERF)-10 b(A)m(CE)30 b(R)m(OUTINES)p eop
+%%Page: 69 75
+69 74 bop 0 1225 a Ff(Chapter)65 b(9)0 1687 y Fl(Adv)-13
+b(anced)78 b(In)-6 b(terface)77 b(Subroutines)0 2180
+y Fi(This)30 b(c)m(hapter)i(de\014nes)f(all)f(the)i(a)m(v)-5
+b(ailable)31 b(subroutines)f(in)g(the)i(FITSIO)e(user)h(in)m(terface.)
+45 b(F)-8 b(or)33 b(completeness,)0 2293 y(the)43 b(basic)f
+(subroutines)e(describ)s(ed)g(in)i(the)g(previous)g(c)m(hapter)h(are)g
+(also)f(rep)s(eated)h(here.)77 b(A)43 b(righ)m(t)f(arro)m(w)0
+2406 y(sym)m(b)s(ol)28 b(is)f(used)h(here)h(to)g(separate)h(the)f
+(input)e(parameters)i(from)f(the)h(output)g(parameters)g(in)e(the)i
+(de\014nition)0 2518 y(of)k(eac)m(h)h(subroutine.)46
+b(This)31 b(sym)m(b)s(ol)h(is)g(not)h(actually)g(part)f(of)h(the)h
+(calling)d(sequence.)49 b(An)32 b(alphab)s(etical)f(list)0
+2631 y(and)f(de\014nition)e(of)i(all)g(the)g(parameters)h(is)e(giv)m
+(en)i(at)g(the)f(end)g(of)h(this)e(section.)0 2961 y
+Fd(9.1)135 b(FITS)44 b(File)i(Op)t(en)e(and)h(Close)h(Subroutines:)0
+3197 y Fh(1)81 b Fi(Op)s(en)39 b(an)h(existing)f(FITS)h(\014le)f(with)g
+(readonly)h(or)g(readwrite)g(access.)72 b(FTDOPN)41 b(also)f(mo)m(v)m
+(es)i(to)f(the)227 3310 y(\014rst)30 b(HDU)h(con)m(taining)f
+(signi\014can)m(t)f(data,)j(if)d(no)h(sp)s(eci\014c)f(HDU)i(is)f(sp)s
+(eci\014ed)f(as)h(part)g(of)h(the)f(\014lename.)227 3423
+y(FTTOPN)39 b(and)h(FTIOPN)f(are)h(similar)d(except)k(that)g(they)f
+(will)d(mo)m(v)m(e)k(to)g(the)f(\014rst)f(table)g(HDU)i(or)227
+3536 y(image)31 b(HDU,)g(resp)s(ectiv)m(ely)-8 b(,)31
+b(if)e(a)i(HDU)g(name)f(or)h(n)m(um)m(b)s(er)e(is)g(not)i(sp)s
+(eci\014ed)d(as)j(part)f(of)h(the)f(\014lename.)382 3770
+y Fe(FTOPEN\(unit,filename,rwm)o(ode)o(,)42 b(>)47 b
+(blocksize,status\))382 3883 y(FTDOPN\(unit,filename,rwm)o(ode)o(,)42
+b(>)47 b(status\))382 3996 y(FTTOPN\(unit,filename,rwm)o(ode)o(,)42
+b(>)47 b(status\))382 4108 y(FTIOPN\(unit,filename,rwm)o(ode)o(,)42
+b(>)47 b(status\))0 4343 y Fh(2)81 b Fi(Op)s(en)24 b(an)i(existing)f
+(FITS)g(\014le)g(with)f(readonly)h(or)h(readwrite)f(access)i(and)f(mo)m
+(v)m(e)h(to)f(a)h(follo)m(wing)d(extension,)227 4455
+y(if)37 b(one)h(w)m(as)g(sp)s(eci\014ed)f(as)h(part)f(of)h(the)h
+(\014lename.)62 b(\(e.g.,)42 b('\014lename.\014ts+2')37
+b(or)h('\014lename.\014ts[2]')h(will)227 4568 y(mo)m(v)m(e)f(to)g(the)e
+(3rd)g(HDU)i(in)d(the)i(\014le\).)59 b(Note)37 b(that)h(this)d(routine)
+h(di\013ers)f(from)h(FTOPEN)g(in)f(that)i(it)227 4681
+y(do)s(es)30 b(not)h(ha)m(v)m(e)h(the)e(redundan)m(t)f(blo)s(c)m(ksize)
+h(argumen)m(t.)382 4915 y Fe(FTNOPN\(unit,filename,rwm)o(ode)o(,)42
+b(>)47 b(status\))0 5149 y Fh(3)81 b Fi(Reop)s(en)38
+b(a)i(FITS)e(\014le)h(that)g(w)m(as)h(previously)d(op)s(ened)h(with)g
+(FTOPEN,)h(FTNOPN,)g(or)h(FTINIT.)e(The)227 5262 y(newunit)e(n)m(um)m
+(b)s(er)g(ma)m(y)j(then)e(b)s(e)g(treated)i(as)f(a)g(separate)g
+(\014le,)h(and)e(one)h(ma)m(y)h(sim)m(ultaneously)c(read)227
+5375 y(or)h(write)f(to)h(2)g(\(or)g(more\))g(di\013eren)m(t)f
+(extensions)g(in)f(the)i(same)g(\014le.)55 b(The)35 b(FTOPEN)g(and)g
+(FTNOPN)227 5488 y(routines)e(\(ab)s(o)m(v)m(e\))i(automatically)e
+(detects)i(cases)g(where)e(a)g(previously)f(op)s(ened)g(\014le)h(is)g
+(b)s(eing)f(op)s(ened)227 5601 y(again,)c(and)f(then)g(in)m(ternally)e
+(call)h(FTREOPEN,)h(so)h(programs)e(should)g(rarely)g(need)h(to)h
+(explicitly)d(call)227 5714 y(this)30 b(routine.)1905
+5942 y(69)p eop
+%%Page: 70 76
+70 75 bop 0 299 a Fi(70)1319 b Fg(CHAPTER)29 b(9.)112
+b(AD)m(V)-10 b(ANCED)32 b(INTERF)-10 b(A)m(CE)30 b(SUBR)m(OUTINES)334
+555 y Fe(FTREOPEN\(unit,)44 b(>)j(newunit,)f(status\))0
+804 y Fh(4)81 b Fi(Op)s(en)29 b(and)g(initialize)f(a)j(new)f(empt)m(y)g
+(FITS)g(\014le)334 1054 y Fe(FTINIT\(unit,filename,bloc)o(ksi)o(ze,)41
+b(>)48 b(status\))0 1303 y Fh(5)81 b Fi(Create)24 b(a)g(new)f(FITS)g
+(\014le,)h(using)e(a)i(template)g(\014le)e(to)j(de\014ne)d(its)h
+(initial)e(size)j(and)f(structure.)37 b(The)24 b(template)227
+1416 y(ma)m(y)39 b(b)s(e)f(another)h(FITS)e(HDU)i(or)g(an)f(ASCI)s(I)f
+(template)i(\014le.)63 b(If)38 b(the)h(input)d(template)j(\014le)e
+(name)i(is)227 1529 y(blank,)27 b(then)g(this)f(routine)g(b)s(eha)m(v)m
+(es)i(the)f(same)h(as)f(FTINIT.)g(The)f(curren)m(tly)h(supp)s(orted)e
+(format)i(of)h(the)227 1641 y(ASCI)s(I)c(template)i(\014le)f(is)f
+(describ)s(ed)g(under)g(the)i(\014ts)p 2037 1641 28 4
+v 32 w(parse)p 2277 1641 V 33 w(template)f(routine)g(\(in)g(the)g
+(general)h(Utilities)227 1754 y(section\),)31 b(but)f(this)f(ma)m(y)i
+(c)m(hange)h(sligh)m(tly)d(later)h(releases)g(of)h(CFITSIO.)334
+2004 y Fe(FTTPLT\(unit,)45 b(filename,)g(tplfilename,)f(>)k(status\))0
+2253 y Fh(6)81 b Fi(Flush)32 b(in)m(ternal)g(bu\013ers)h(of)h(data)g
+(to)g(the)g(output)g(FITS)f(\014le)g(previously)e(op)s(ened)i(with)f
+(ftop)s(en)i(or)f(ftinit.)227 2366 y(The)j(routine)g(usually)e(nev)m
+(er)j(needs)f(to)i(b)s(e)e(called,)h(but)f(doing)g(so)h(will)d(ensure)i
+(that)h(if)e(the)i(program)227 2479 y(subsequen)m(tly)29
+b(ab)s(orts,)h(then)h(the)f(FITS)g(\014le)f(will)f(ha)m(v)m(e)k(at)f
+(least)f(b)s(een)g(closed)g(prop)s(erly)-8 b(.)382 2728
+y Fe(FTFLUS\(unit,)44 b(>)k(status\))0 2977 y Fh(7)81
+b Fi(Close)30 b(a)g(FITS)g(\014le)f(previously)f(op)s(ened)i(with)f
+(ftop)s(en)h(or)g(ftinit)382 3226 y Fe(FTCLOS\(unit,)44
+b(>)k(status\))0 3475 y Fh(8)81 b Fi(Close)33 b(and)g(DELETE)g(a)h
+(FITS)f(\014le)g(previously)e(op)s(ened)i(with)f(ftop)s(en)h(or)h
+(ftinit.)49 b(This)32 b(routine)g(ma)m(y)j(b)s(e)227
+3588 y(useful)28 b(in)h(cases)h(where)g(a)g(FITS)f(\014le)f(is)h
+(created,)i(but)e(an)h(error)f(o)s(ccurs)h(whic)m(h)e(prev)m(en)m(ts)j
+(the)e(complete)227 3701 y(\014le)h(from)g(b)s(eing)f(written.)382
+3950 y Fe(FTDELT\(unit,)44 b(>)k(status\))0 4199 y Fh(9)81
+b Fi(Get)31 b(the)g(v)-5 b(alue)30 b(of)g(an)g(un)m(used)g(I/O)g(unit)f
+(n)m(um)m(b)s(er)g(whic)m(h)g(ma)m(y)i(then)f(b)s(e)g(used)g(as)g
+(input)f(to)i(FTOPEN)f(or)227 4312 y(FTINIT.)36 b(This)e(routine)h
+(searc)m(hes)i(for)f(the)g(\014rst)f(un)m(used)g(unit)f(n)m(um)m(b)s
+(er)h(in)f(the)j(range)f(from)f(with)g(99)227 4425 y(do)m(wn)e(to)h
+(50.)50 b(This)31 b(routine)h(just)h(k)m(eeps)h(an)f(in)m(ternal)f
+(list)f(of)j(the)f(allo)s(cated)g(unit)f(n)m(um)m(b)s(ers)g(and)g(do)s
+(es)227 4538 y(not)26 b(ph)m(ysically)d(c)m(hec)m(k)j(that)g(the)g(F)-8
+b(ortran)25 b(unit)f(is)g(a)m(v)-5 b(ailable)25 b(\(to)h(b)s(e)f
+(compatible)f(with)g(the)h(SPP)f(v)m(ersion)227 4651
+y(of)35 b(FITSIO\).)g(Th)m(us)f(users)g(m)m(ust)h(not)g(indep)s(enden)m
+(tly)d(allo)s(cate)j(an)m(y)h(unit)d(n)m(um)m(b)s(ers)h(in)g(the)h
+(range)g(50)227 4764 y(-)42 b(99)g(if)e(this)g(routine)g(is)g(also)h
+(to)h(b)s(e)f(used)f(in)g(the)h(same)h(program.)73 b(This)39
+b(routine)h(is)g(pro)m(vided)g(for)227 4877 y(con)m(v)m(enience)33
+b(only)-8 b(,)31 b(and)f(it)h(is)f(not)i(required)d(that)j(the)f(unit)f
+(n)m(um)m(b)s(ers)g(used)g(b)m(y)h(FITSIO)f(b)s(e)h(allo)s(cated)227
+4990 y(b)m(y)g(this)e(routine.)382 5239 y Fe(FTGIOU\()46
+b(>)h(iounit,)f(status\))0 5488 y Fh(10)g Fi(F)-8 b(ree)34
+b(\(deallo)s(cate\))g(an)f(I/O)g(unit)e(n)m(um)m(b)s(er)h(whic)m(h)f(w)
+m(as)i(previously)e(allo)s(cated)i(with)f(FTGIOU.)h(All)e(pre-)227
+5601 y(viously)26 b(allo)s(cated)i(unit)e(n)m(um)m(b)s(ers)g(ma)m(y)i
+(b)s(e)f(deallo)s(cated)h(at)g(once)h(b)m(y)e(calling)f(FTFIOU)i(with)e
+(iounit)g(=)227 5714 y(-1.)p eop
+%%Page: 71 77
+71 76 bop 0 299 a Fg(9.1.)72 b(FITS)30 b(FILE)g(OPEN)g(AND)h(CLOSE)e
+(SUBR)m(OUTINES:)1561 b Fi(71)382 555 y Fe(FTFIOU\(iounit,)44
+b(>)j(status\))0 788 y Fh(11)f Fi(Return)30 b(the)h(F)-8
+b(ortran)31 b(unit)f(n)m(um)m(b)s(er)f(that)i(corresp)s(onds)f(to)h
+(the)g(C)g(\014ts\014le)e(p)s(oin)m(ter)h(v)-5 b(alue,)31
+b(or)f(vice)h(v)m(ersa.)227 901 y(These)37 b(2)h(C)f(routines)f(ma)m(y)
+h(b)s(e)g(useful)e(in)h(mixed)g(language)i(programs)f(where)f(b)s(oth)h
+(C)g(and)f(F)-8 b(ortran)227 1014 y(subroutines)24 b(need)h(to)i
+(access)g(the)f(same)g(\014le.)39 b(F)-8 b(or)26 b(example,)h(if)e(a)h
+(FITS)f(\014le)g(is)g(op)s(ened)g(with)f(unit)g(12)j(b)m(y)227
+1127 y(a)k(F)-8 b(ortran)31 b(subroutine,)e(then)h(a)h(C)f(routine)g
+(within)e(the)i(same)h(program)g(could)e(get)j(the)e(\014t\014le)g(p)s
+(oin)m(ter)227 1240 y(v)-5 b(alue)38 b(to)g(access)h(the)f(same)h
+(\014le)e(b)m(y)g(calling)g('fptr)g(=)h(CUnit2FITS\(12\)'.)63
+b(These)38 b(routines)f(return)g(a)227 1353 y(v)-5 b(alue)30
+b(of)h(zero)g(if)e(an)h(error)g(o)s(ccurs.)286 1586 y
+Fe(int)334 b(CFITS2Unit\(fitsfile)42 b(*ptr\);)286 1698
+y(fitsfile*)k(CUnit2FITS\(int)e(unit\);)0 1931 y Fh(11)i
+Fi(P)m(arse)32 b(the)g(input)d(\014lename)i(and)g(return)f(the)i(HDU)g
+(n)m(um)m(b)s(er)e(that)i(w)m(ould)e(b)s(e)h(mo)m(v)m(ed)i(to)f(if)e
+(the)i(\014le)e(w)m(ere)227 2044 y(op)s(ened)j(with)f(FTNOPN.)h(The)f
+(returned)g(HDU)i(n)m(um)m(b)s(er)e(b)s(egins)g(with)g(1)h(for)g(the)g
+(primary)f(arra)m(y)-8 b(,)35 b(so)227 2157 y(for)d(example,)f(if)g
+(the)h(input)e(\014lename)g(=)i(`m)m(y\014le.\014ts[2]')g(then)f(hdun)m
+(um)e(=)j(3)g(will)d(b)s(e)i(returned.)43 b(FIT-)227
+2270 y(SIO)35 b(do)s(es)h(not)g(op)s(en)g(the)g(\014le)f(to)i(c)m(hec)m
+(k)h(if)d(the)h(extension)g(actually)g(exists)f(if)h(an)f(extension)h
+(n)m(um)m(b)s(er)227 2383 y(is)42 b(sp)s(eci\014ed.)74
+b(If)42 b(an)g(extension)g(*name*)h(is)e(included)f(in)h(the)h(\014le)f
+(name)i(sp)s(eci\014cation)e(\(e.g.)77 b(`m)m(y-)227
+2496 y(\014le.\014ts[EVENTS]')29 b(then)g(this)g(routine)g(will)e(ha)m
+(v)m(e)k(to)f(op)s(en)f(the)h(FITS)f(\014le)g(and)g(lo)s(ok)g(for)h
+(the)g(p)s(osition)227 2609 y(of)38 b(the)h(named)e(extension,)j(then)e
+(close)g(\014le)f(again.)63 b(This)37 b(is)g(not)h(p)s(ossible)d(if)i
+(the)h(\014le)f(is)g(b)s(eing)g(read)227 2722 y(from)f(the)g(stdin)e
+(stream,)k(and)d(an)h(error)f(will)e(b)s(e)j(returned)e(in)h(this)g
+(case.)58 b(If)35 b(the)h(\014lename)f(do)s(es)h(not)227
+2835 y(sp)s(ecify)28 b(an)h(explicit)e(extension)i(\(e.g.)42
+b('m)m(y\014le.\014ts'\))29 b(then)g(hdun)m(um)e(=)h(-99)j(will)26
+b(b)s(e)j(returned,)f(whic)m(h)g(is)227 2948 y(functionally)j(equiv)-5
+b(alen)m(t)33 b(to)i(hdun)m(um)c(=)i(1.)50 b(This)32
+b(routine)g(is)h(mainly)f(used)g(for)i(bac)m(kw)m(ard)g(compati-)227
+3060 y(bilit)m(y)d(in)g(the)h(fto)s(ols)g(soft)m(w)m(are)i(pac)m(k)-5
+b(age)34 b(and)e(is)f(not)h(recommended)g(for)g(general)h(use.)46
+b(It)32 b(is)g(generally)227 3173 y(b)s(etter)j(and)g(more)g(e\016cien)
+m(t)g(to)h(\014rst)e(op)s(en)g(the)h(FITS)f(\014le)g(with)g(FTNOPN,)h
+(then)g(use)f(FTGHDN)i(to)227 3286 y(determine)29 b(whic)m(h)g(HDU)h
+(in)e(the)i(\014le)f(has)h(b)s(een)f(op)s(ened,)g(rather)g(than)h
+(calling)e(FTEXTN)i(follo)m(w)m(ed)f(b)m(y)227 3399 y(a)i(call)f(to)h
+(FTNOPN.)382 3632 y Fe(FTEXTN\(filename,)43 b(>)48 b(nhdu,)e(status\))0
+3865 y Fh(12)g Fi(Return)30 b(the)g(name)h(of)f(the)h(op)s(ened)e(FITS)
+h(\014le.)382 4098 y Fe(FTFLNM\(unit,)44 b(>)k(filename,)d(status\))0
+4331 y Fh(13)h Fi(Return)30 b(the)g(I/O)g(mo)s(de)g(of)h(the)g(op)s(en)
+e(FITS)h(\014le)f(\(READONL)-8 b(Y)32 b(=)e(0,)h(READ)m(WRITE)g(=)f
+(1\).)382 4564 y Fe(FTFLMD\(unit,)44 b(>)k(iomode,)e(status\))0
+4796 y Fh(14)g Fi(Return)30 b(the)g(\014le)g(t)m(yp)s(e)g(of)h(the)f
+(op)s(ened)g(FITS)g(\014le)f(\(e.g.)42 b('\014le://',)31
+b('ftp://',)h(etc.\).)382 5029 y Fe(FTURLT\(unit,)44
+b(>)k(urltype,)d(status\))0 5262 y Fh(15)h Fi(P)m(arse)27
+b(the)f(input)e(\014lename)i(or)g(URL)g(in)m(to)g(its)g(comp)s(onen)m
+(t)g(parts:)39 b(the)26 b(\014le)f(t)m(yp)s(e)i(\(\014le://,)g(ftp://,)
+h(h)m(ttp://,)227 5375 y(etc\),)34 b(the)e(base)g(input)d(\014le)i
+(name,)h(the)g(name)g(of)g(the)g(output)f(\014le)g(that)h(the)g(input)e
+(\014le)g(is)h(to)h(b)s(e)f(copied)227 5488 y(to)38 b(prior)d(to)i(op)s
+(ening,)g(the)g(HDU)g(or)f(extension)h(sp)s(eci\014cation,)g(the)g
+(\014ltering)d(sp)s(eci\014er,)j(the)g(binning)227 5601
+y(sp)s(eci\014er,)d(and)f(the)i(column)e(sp)s(eci\014er.)50
+b(Blank)33 b(strings)g(will)f(b)s(e)h(returned)g(for)h(an)m(y)g(comp)s
+(onen)m(ts)g(that)227 5714 y(are)d(not)g(presen)m(t)f(in)f(the)i(input)
+d(\014le)i(name.)p eop
+%%Page: 72 78
+72 77 bop 0 299 a Fi(72)1319 b Fg(CHAPTER)29 b(9.)112
+b(AD)m(V)-10 b(ANCED)32 b(INTERF)-10 b(A)m(CE)30 b(SUBR)m(OUTINES)334
+555 y Fe(FTIURL\(filename,)43 b(>)48 b(filetype,)d(infile,)h(outfile,)g
+(extspec,)f(filter,)716 668 y(binspec,)g(colspec,)h(status\))0
+913 y Fh(16)g Fi(P)m(arse)e(the)g(input)e(\014le)h(name)g(and)g(return)
+g(the)h(ro)s(ot)g(\014le)e(name.)81 b(The)43 b(ro)s(ot)h(name)g
+(includes)d(the)j(\014le)227 1025 y(t)m(yp)s(e)35 b(if)f(sp)s
+(eci\014ed,)h(\(e.g.)56 b('ftp://')37 b(or)e('h)m(ttp://'\))i(and)d
+(the)h(full)e(path)i(name,)h(to)g(the)f(exten)m(t)i(that)e(it)g(is)227
+1138 y(sp)s(eci\014ed)25 b(in)f(the)j(input)d(\014lename.)38
+b(It)26 b(do)s(es)g(not)g(include)e(the)i(HDU)h(name)f(or)g(n)m(um)m(b)
+s(er,)g(or)g(an)m(y)h(\014ltering)227 1251 y(sp)s(eci\014cations.)334
+1496 y Fe(FTRTNM\(filename,)43 b(>)48 b(rootname,)d(status\))0
+1740 y Fh(16)h Fi(T)-8 b(est)36 b(if)f(the)h(input)e(\014le)h(or)g(a)i
+(compressed)e(v)m(ersion)g(of)h(the)g(\014le)f(\(with)g(a)h(.gz,)i(.Z,)
+e(.z,)i(or)e(.zip)f(extension\))227 1853 y(exists)j(on)g(disk.)62
+b(The)37 b(returned)g(v)-5 b(alue)37 b(of)h(the)h('exists')f(parameter)
+g(will)d(ha)m(v)m(e)40 b(1)e(of)g(the)g(4)g(follo)m(wing)227
+1966 y(v)-5 b(alues:)370 2198 y Fe(2:)95 b(the)47 b(file)g(does)g(not)f
+(exist,)h(but)f(a)i(compressed)d(version)h(does)g(exist)370
+2311 y(1:)95 b(the)47 b(disk)g(file)g(does)f(exist)370
+2424 y(0:)95 b(neither)46 b(the)h(file)g(nor)g(a)g(compressed)e
+(version)h(of)h(the)g(file)g(exist)323 2537 y(-1:)94
+b(the)47 b(input)g(file)f(name)h(is)g(not)g(a)g(disk)g(file)g(\(could)f
+(be)h(a)g(ftp,)g(http,)561 2650 y(smem,)g(or)g(mem)g(file,)f(or)h(a)h
+(file)e(piped)h(in)g(on)g(the)g(STDIN)f(stream\))286
+2894 y(FTEXIST\(filename,)d(>)48 b(exists,)e(status\);)0
+3225 y Fd(9.2)135 b(HDU-Lev)l(el)47 b(Op)t(erations)0
+3475 y Fi(When)30 b(a)h(FITS)f(\014le)f(is)h(\014rst)f(op)s(ened)h(or)g
+(created,)i(the)f(in)m(ternal)e(bu\013ers)g(in)g(FITSIO)g
+(automatically)i(p)s(oin)m(t)e(to)0 3588 y(the)h(\014rst)g(HDU)h(in)e
+(the)h(\014le.)40 b(The)29 b(follo)m(wing)g(routines)g(ma)m(y)i(b)s(e)e
+(used)h(to)h(mo)m(v)m(e)g(to)g(another)f(HDU)h(in)e(the)i(\014le.)0
+3701 y(Note)j(that)f(the)g(HDU)g(n)m(um)m(b)s(ering)e(con)m(v)m(en)m
+(tion)i(used)f(in)f(FITSIO)h(denotes)h(the)f(primary)f(arra)m(y)i(as)g
+(the)g(\014rst)0 3814 y(HDU,)e(the)g(\014rst)f(extension)g(in)f(a)h
+(FITS)g(\014le)f(is)h(the)g(second)h(HDU,)g(and)f(so)h(on.)0
+4059 y Fh(1)81 b Fi(Mo)m(v)m(e)32 b(to)f(a)g(sp)s(eci\014ed)e
+(\(absolute\))h(HDU)h(in)f(the)g(FITS)g(\014le)f(\(nhdu)g(=)h(1)h(for)f
+(the)g(FITS)g(primary)e(arra)m(y\))382 4303 y Fe(FTMAHD\(unit,nhdu,)43
+b(>)k(hdutype,status\))0 4548 y Fh(2)81 b Fi(Mo)m(v)m(e)32
+b(to)f(a)g(new)f(\(existing\))g(HDU)h(forw)m(ard)f(or)g(bac)m(kw)m
+(ards)h(relativ)m(e)f(to)h(the)g(CHDU)382 4792 y Fe
+(FTMRHD\(unit,nmove,)43 b(>)k(hdutype,status\))0 5036
+y Fh(3)81 b Fi(Mo)m(v)m(e)22 b(to)f(the)f(\(\014rst\))h(HDU)g(whic)m(h)
+e(has)h(the)g(sp)s(eci\014ed)f(extension)h(t)m(yp)s(e)g(and)g(EXTNAME)g
+(\(or)h(HDUNAME\))227 5149 y(and)32 b(EXTVER)g(k)m(eyw)m(ord)h(v)-5
+b(alues.)47 b(The)32 b(hdut)m(yp)s(e)f(parameter)i(ma)m(y)h(ha)m(v)m(e)
+f(a)g(v)-5 b(alue)32 b(of)h(IMA)m(GE)p 3640 5149 28 4
+v 34 w(HDU,)227 5262 y(ASCI)s(I)p 486 5262 V 32 w(TBL,)f(BINAR)-8
+b(Y)p 1122 5262 V 34 w(TBL,)32 b(or)h(ANY)p 1718 5262
+V 33 w(HDU)g(where)f(ANY)p 2458 5262 V 33 w(HDU)i(means)e(that)h(only)f
+(the)g(extname)227 5375 y(and)k(extv)m(er)h(v)-5 b(alues)35
+b(will)e(b)s(e)i(used)g(to)i(lo)s(cate)g(the)f(correct)h(extension.)57
+b(If)35 b(the)h(input)e(v)-5 b(alue)36 b(of)g(extv)m(er)227
+5488 y(is)c(0)h(then)f(the)g(EXTVER)h(k)m(eyw)m(ord)g(is)e(ignored)h
+(and)g(the)g(\014rst)g(HDU)h(with)e(a)i(matc)m(hing)g(EXTNAME)227
+5601 y(\(or)j(HDUNAME\))h(k)m(eyw)m(ord)f(will)c(b)s(e)j(found.)55
+b(If)34 b(no)i(matc)m(hing)f(HDU)h(is)f(found)f(in)g(the)h(\014le)g
+(then)g(the)227 5714 y(curren)m(t)27 b(HDU)g(will)d(remain)h(unc)m
+(hanged)i(and)f(a)h(status)g(=)f(BAD)p 2501 5714 V 34
+w(HDU)p 2740 5714 V 33 w(NUM)h(\(301\))i(will)24 b(b)s(e)i(returned.)p
+eop
+%%Page: 73 79
+73 78 bop 0 299 a Fg(9.2.)72 b(HDU-LEVEL)31 b(OPERA)-8
+b(TIONS)2414 b Fi(73)382 555 y Fe(FTMNHD\(unit,)44 b(hdutype,)i
+(extname,)f(extver,)h(>)i(status\))0 804 y Fh(4)81 b
+Fi(Get)31 b(the)g(n)m(um)m(b)s(er)e(of)h(the)h(curren)m(t)f(HDU)h(in)e
+(the)i(FITS)e(\014le)h(\(primary)f(arra)m(y)h(=)g(1\))382
+1054 y Fe(FTGHDN\(unit,)44 b(>)k(nhdu\))0 1303 y Fh(5)81
+b Fi(Return)39 b(the)i(t)m(yp)s(e)g(of)g(the)g(curren)m(t)f(HDU)i(in)d
+(the)i(FITS)f(\014le.)70 b(The)41 b(p)s(ossible)d(v)-5
+b(alues)40 b(for)g(hdut)m(yp)s(e)g(are)227 1416 y(IMA)m(GE)p
+546 1416 28 4 v 34 w(HDU)31 b(\(0\),)h(ASCI)s(I)p 1242
+1416 V 31 w(TBL)e(\(1\),)i(or)e(BINAR)-8 b(Y)p 2133 1416
+V 34 w(TBL)30 b(\(2\).)382 1665 y Fe(FTGHDT\(unit,)44
+b(>)k(hdutype,)d(status\))0 1914 y Fh(6)81 b Fi(Return)29
+b(the)i(total)g(n)m(um)m(b)s(er)e(of)i(HDUs)f(in)g(the)g(FITS)g
+(\014le.)40 b(The)29 b(CHDU)i(remains)e(unc)m(hanged.)382
+2163 y Fe(FTTHDU\(unit,)44 b(>)k(hdunum,)e(status\))0
+2412 y Fh(7)81 b Fi(Create)36 b(\(app)s(end\))e(a)h(new)g(empt)m(y)g
+(HDU)h(follo)m(wing)e(the)h(last)g(extension)g(that)h(has)f(b)s(een)f
+(previously)f(ac-)227 2525 y(cessed)41 b(b)m(y)f(the)g(program.)70
+b(This)39 b(will)e(o)m(v)m(erwrite)k(an)m(y)g(extensions)f(in)e(an)j
+(existing)e(FITS)g(\014le)h(if)f(the)227 2638 y(program)31
+b(has)g(not)g(already)g(mo)m(v)m(ed)h(to)f(that)h(\(or)f(a)h(later\))f
+(extension)g(using)e(the)i(FTMAHD)h(or)f(FTM-)227 2751
+y(RHD)24 b(routines.)37 b(F)-8 b(or)25 b(example,)f(if)f(an)g(existing)
+f(FITS)h(\014le)f(con)m(tains)i(a)g(primary)d(arra)m(y)j(and)f(5)g
+(extensions)227 2864 y(and)31 b(a)h(program)f(\(1\))h(op)s(ens)f(the)g
+(FITS)g(\014le,)g(\(2\))h(mo)m(v)m(es)h(to)f(extension)f(4,)h(\(3\))g
+(mo)m(v)m(es)h(bac)m(k)f(to)g(the)f(pri-)227 2977 y(mary)36
+b(arra)m(y)-8 b(,)38 b(and)e(\(4\))h(then)e(calls)g(FTCRHD,)h(then)g
+(the)g(new)g(extension)f(will)e(b)s(e)j(written)e(follo)m(wing)227
+3090 y(the)d(4th)f(extension,)h(o)m(v)m(erwriting)f(the)g(existing)f
+(5th)i(extension.)382 3339 y Fe(FTCRHD\(unit,)44 b(>)k(status\))0
+3588 y Fh(8)81 b Fi(Insert)41 b(a)h(new)f(IMA)m(GE)i(extension)f
+(immediately)e(follo)m(wing)g(the)i(CHDU.)g(An)m(y)g(follo)m(wing)e
+(extensions)227 3701 y(will)c(b)s(e)i(shifted)f(do)m(wn)h(to)h(mak)m(e)
+g(ro)s(om)g(for)f(the)g(new)g(extension.)65 b(If)38 b(there)h(are)f(no)
+h(other)f(follo)m(wing)227 3814 y(extensions)29 b(then)g(the)h(new)e
+(image)i(extension)f(will)e(simply)f(b)s(e)j(app)s(ended)f(to)i(the)f
+(end)g(of)g(the)h(\014le.)39 b(The)227 3927 y(new)30
+b(extension)g(will)e(b)s(ecome)j(the)f(CHDU.)382 4176
+y Fe(FTIIMG\(unit,bitpix,naxis)o(,na)o(xes,)41 b(>)48
+b(status\))0 4425 y Fh(9)81 b Fi(Insert)30 b(a)i(new)f(ASCI)s(I)f(T)-8
+b(ABLE)31 b(extension)g(immediately)f(follo)m(wing)f(the)j(CHDU.)g(An)m
+(y)f(follo)m(wing)f(exten-)227 4538 y(sions)25 b(will)e(b)s(e)i
+(shifted)f(do)m(wn)h(to)h(mak)m(e)h(ro)s(om)e(for)h(the)f(new)g
+(extension.)39 b(If)25 b(there)h(are)g(no)g(other)f(follo)m(wing)227
+4651 y(extensions)31 b(then)g(the)h(new)f(table)g(extension)g(will)e
+(simply)g(b)s(e)i(app)s(ended)f(to)i(the)f(end)g(of)h(the)f(\014le.)43
+b(The)227 4764 y(new)30 b(extension)g(will)e(b)s(ecome)j(the)f(CHDU.)
+382 5013 y Fe(FTITAB\(unit,rowlen,nrows)o(,tf)o(ield)o(s,tt)o(ype)o
+(,tbc)o(ol,t)o(for)o(m,tu)o(nit,)o(ext)o(name)o(,)42
+b(>)716 5126 y(status\))0 5375 y Fh(10)k Fi(Insert)25
+b(a)h(new)f(binary)e(table)j(extension)f(immediately)e(follo)m(wing)h
+(the)i(CHDU.)g(An)m(y)g(follo)m(wing)d(extensions)227
+5488 y(will)36 b(b)s(e)i(shifted)f(do)m(wn)h(to)h(mak)m(e)g(ro)s(om)g
+(for)f(the)g(new)g(extension.)65 b(If)38 b(there)h(are)f(no)h(other)f
+(follo)m(wing)227 5601 y(extensions)e(then)h(the)f(new)g(bin)m(table)f
+(extension)i(will)d(simply)g(b)s(e)i(app)s(ended)e(to)k(the)e(end)g(of)
+h(the)g(\014le.)227 5714 y(The)30 b(new)g(extension)g(will)e(b)s(ecome)
+j(the)f(CHDU.)p eop
+%%Page: 74 80
+74 79 bop 0 299 a Fi(74)1319 b Fg(CHAPTER)29 b(9.)112
+b(AD)m(V)-10 b(ANCED)32 b(INTERF)-10 b(A)m(CE)30 b(SUBR)m(OUTINES)382
+555 y Fe(FTIBIN\(unit,nrows,tfield)o(s,t)o(type)o(,tfo)o(rm,)o(tuni)o
+(t,ex)o(tna)o(me,v)o(arid)o(at)41 b(>)48 b(status\))0
+777 y Fh(11)e Fi(Resize)25 b(an)f(image)h(b)m(y)f(mo)s(di\014ng)e(the)j
+(size,)h(dimensions,)d(and/or)h(datat)m(yp)s(e)h(of)g(the)g(curren)m(t)
+f(primary)e(arra)m(y)227 890 y(or)29 b(image)h(extension.)39
+b(If)29 b(the)g(new)g(image,)h(as)f(sp)s(eci\014ed)e(b)m(y)i(the)g
+(input)e(argumen)m(ts,)j(is)e(larger)h(than)g(the)227
+1003 y(curren)m(t)34 b(existing)f(image)h(in)f(the)h(FITS)f(\014le)g
+(then)g(zero)i(\014ll)d(data)j(will)c(b)s(e)i(inserted)g(at)h(the)g
+(end)g(of)g(the)227 1116 y(curren)m(t)25 b(image)g(and)f(an)m(y)i
+(follo)m(wing)d(extensions)i(will)d(b)s(e)i(mo)m(v)m(ed)i(further)e
+(bac)m(k)h(in)f(the)h(\014le.)38 b(Similarly)-8 b(,)23
+b(if)227 1229 y(the)28 b(new)e(image)i(is)e(smaller)g(than)h(the)g
+(curren)m(t)g(image)g(then)g(an)m(y)h(follo)m(wing)e(extensions)g(will)
+f(b)s(e)h(shifted)227 1342 y(up)32 b(to)m(w)m(ards)i(the)g(b)s
+(eginning)c(of)j(the)h(FITS)e(\014le)g(and)h(the)g(image)g(data)h(will)
+d(b)s(e)h(truncated)h(to)h(the)f(new)227 1455 y(size.)40
+b(This)24 b(routine)h(rewrites)h(the)g(BITPIX,)h(NAXIS,)f(and)g(NAXISn)
+g(k)m(eyw)m(ords)g(with)f(the)i(appropriate)227 1567
+y(v)-5 b(alues)30 b(for)g(new)g(image.)382 1789 y Fe
+(FTRSIM\(unit,bitpix,naxis)o(,na)o(xes,)o(stat)o(us\))0
+2011 y Fh(12)46 b Fi(Delete)33 b(the)g(CHDU)g(in)e(the)h(FITS)f
+(\014le.)46 b(An)m(y)32 b(follo)m(wing)f(HDUs)i(will)d(b)s(e)h(shifted)
+g(forw)m(ard)h(in)f(the)h(\014le,)g(to)227 2124 y(\014ll)k(in)g(the)h
+(gap)h(created)g(b)m(y)g(the)f(deleted)g(HDU.)i(In)d(the)i(case)g(of)g
+(deleting)e(the)i(primary)d(arra)m(y)j(\(the)227 2237
+y(\014rst)30 b(HDU)h(in)e(the)i(\014le\))f(then)g(the)h(curren)m(t)f
+(primary)e(arra)m(y)j(will)d(b)s(e)i(replace)g(b)m(y)h(a)g(n)m(ull)d
+(primary)g(arra)m(y)227 2350 y(con)m(taining)j(the)h(minim)m(um)c(set)k
+(of)g(required)d(k)m(eyw)m(ords)j(and)e(no)i(data.)44
+b(If)31 b(there)g(are)h(more)f(extensions)227 2463 y(in)e(the)h(\014le)
+f(follo)m(wing)g(the)h(one)g(that)h(is)e(deleted,)h(then)g(the)g(the)g
+(CHDU)h(will)c(b)s(e)j(rede\014ned)e(to)j(p)s(oin)m(t)e(to)227
+2576 y(the)e(follo)m(wing)e(extension.)40 b(If)26 b(there)h(are)g(no)g
+(follo)m(wing)e(extensions)h(then)h(the)g(CHDU)g(will)d(b)s(e)i
+(rede\014ned)227 2689 y(to)35 b(p)s(oin)m(t)e(to)i(the)f(previous)e
+(HDU.)j(The)e(output)h(HDUTYPE)g(parameter)h(indicates)d(the)j(t)m(yp)s
+(e)f(of)g(the)227 2802 y(new)c(CHDU)h(after)g(the)f(previous)f(CHDU)i
+(has)f(b)s(een)g(deleted.)382 3024 y Fe(FTDHDU\(unit,)44
+b(>)k(hdutype,status\))0 3245 y Fh(13)e Fi(Cop)m(y)36
+b(all)f(or)h(part)g(of)g(the)g(input)e(FITS)h(\014le)g(and)h(app)s(end)
+e(it)h(to)i(the)f(end)g(of)g(the)g(output)g(FITS)f(\014le.)56
+b(If)227 3358 y('previous')27 b(is)g(true)h(\(not)g(0\),)i(then)d(an)m
+(y)h(HDUs)h(preceding)e(the)h(curren)m(t)f(HDU)i(in)d(the)i(input)e
+(\014le)h(will)f(b)s(e)227 3471 y(copied)33 b(to)h(the)g(output)f
+(\014le.)50 b(Similarly)-8 b(,)31 b('curren)m(t')j(and)e('follo)m
+(wing')h(determine)g(whether)f(the)i(curren)m(t)227 3584
+y(HDU,)g(and/or)e(an)m(y)h(follo)m(wing)e(HDUs)i(in)e(the)h(input)f
+(\014le)g(will)f(b)s(e)i(copied)g(to)h(the)f(output)g(\014le.)46
+b(If)32 b(all)g(3)227 3697 y(parameters)j(are)h(true,)g(then)e(the)h
+(en)m(tire)g(input)e(\014le)h(will)e(b)s(e)i(copied.)54
+b(On)33 b(return,)j(the)f(curren)m(t)f(HDU)227 3810 y(in)29
+b(the)g(input)f(\014le)h(will)e(b)s(e)i(unc)m(hanged,)h(and)f(the)h
+(last)f(copied)g(HDU)i(will)c(b)s(e)i(the)h(curren)m(t)f(HDU)h(in)f
+(the)227 3923 y(output)h(\014le.)382 4145 y Fe(FTCPFL\(iunit,)44
+b(ounit,)i(previous,)f(current,)h(following,)f(>)i(status\))0
+4367 y Fh(14)f Fi(Cop)m(y)35 b(the)f(en)m(tire)h(CHDU)g(from)f(the)g
+(FITS)g(\014le)g(asso)s(ciated)h(with)e(IUNIT)h(to)i(the)e(CHDU)h(of)g
+(the)g(FITS)227 4480 y(\014le)f(asso)s(ciated)h(with)e(OUNIT.)h(The)g
+(output)g(HDU)h(m)m(ust)f(b)s(e)g(empt)m(y)h(and)e(not)i(already)f(con)
+m(tain)h(an)m(y)227 4593 y(k)m(eyw)m(ords.)41 b(Space)29
+b(will)d(b)s(e)j(reserv)m(ed)g(for)g(MOREKEYS)f(additional)e(k)m(eyw)m
+(ords)k(in)d(the)j(output)e(header)227 4706 y(if)i(there)g(is)g(not)g
+(already)g(enough)g(space.)382 4927 y Fe(FTCOPY\(iunit,ounit,morek)o
+(eys)o(,)42 b(>)47 b(status\))0 5149 y Fh(15)f Fi(Cop)m(y)27
+b(the)h(header)f(\(and)g(not)g(the)g(data\))i(from)d(the)i(CHDU)g(asso)
+s(ciated)f(with)f(in)m(unit)f(to)j(the)f(CHDU)h(asso-)227
+5262 y(ciated)e(with)e(outunit.)38 b(If)25 b(the)g(curren)m(t)h(output)
+f(HDU)h(is)e(not)i(completely)f(empt)m(y)-8 b(,)27 b(then)e(the)h(CHDU)
+g(will)227 5375 y(b)s(e)e(closed)h(and)f(a)i(new)e(HDU)h(will)e(b)s(e)h
+(app)s(ended)f(to)j(the)f(output)f(\014le.)38 b(This)23
+b(routine)h(will)e(automatically)227 5488 y(transform)31
+b(the)g(necessary)h(k)m(eyw)m(ords)f(when)g(cop)m(ying)g(a)g(primary)f
+(arra)m(y)i(to)f(and)g(image)h(extension,)f(or)227 5601
+y(an)c(image)g(extension)f(to)h(a)h(primary)c(arra)m(y)-8
+b(.)41 b(An)26 b(empt)m(y)h(output)f(data)i(unit)d(will)f(b)s(e)i
+(created)i(\(all)e(v)-5 b(alues)227 5714 y(=)30 b(0\).)p
+eop
+%%Page: 75 81
+75 80 bop 0 299 a Fg(9.3.)72 b(DEFINE)31 b(OR)f(REDEFINE)h(THE)f(STR)m
+(UCTURE)f(OF)h(THE)g(CHDU)1042 b Fi(75)382 555 y Fe(FTCPHD\(inunit,)44
+b(outunit,)h(>)j(status\))0 819 y Fh(16)e Fi(Cop)m(y)d(just)g(the)g
+(data)h(from)f(the)g(CHDU)h(asso)s(ciated)f(with)f(IUNIT)h(to)h(the)f
+(CHDU)h(asso)s(ciated)f(with)227 932 y(OUNIT.)26 b(This)e(will)f(o)m(v)
+m(erwrite)j(an)m(y)g(data)g(previously)e(in)g(the)i(OUNIT)f(CHDU.)h
+(This)e(lo)m(w)i(lev)m(el)f(routine)227 1045 y(is)h(used)f(b)m(y)i
+(FTCOPY,)f(but)g(it)f(ma)m(y)j(also)e(b)s(e)g(useful)e(in)i(certain)g
+(application)f(programs)h(whic)m(h)f(w)m(an)m(t)i(to)227
+1158 y(cop)m(y)j(the)f(data)h(from)f(one)g(FITS)f(\014le)g(to)i
+(another)f(but)g(also)g(w)m(an)m(t)h(to)g(mo)s(dify)d(the)i(header)g(k)
+m(eyw)m(ords)g(in)227 1271 y(the)j(pro)s(cess.)44 b(all)31
+b(the)h(required)e(header)h(k)m(eyw)m(ords)h(m)m(ust)g(b)s(e)f(written)
+g(to)h(the)g(OUNIT)f(CHDU)h(b)s(efore)227 1383 y(calling)d(this)g
+(routine)382 1647 y Fe(FTCPDT\(iunit,ounit,)42 b(>)48
+b(status\))0 1985 y Fd(9.3)135 b(De\014ne)45 b(or)g(Rede\014ne)h(the)f
+(structure)g(of)g(the)g(CHDU)0 2237 y Fi(It)32 b(should)e(rarely)h(b)s
+(e)h(necessary)g(to)h(call)e(the)h(subroutines)e(in)g(this)h(section.)
+46 b(FITSIO)30 b(in)m(ternally)g(calls)h(these)0 2350
+y(routines)i(whenev)m(er)h(necessary)-8 b(,)36 b(so)e(an)m(y)g(calls)f
+(to)i(these)f(routines)f(b)m(y)h(application)e(programs)i(will)d(lik)m
+(ely)i(b)s(e)0 2462 y(redundan)m(t.)0 2726 y Fh(1)81
+b Fi(This)35 b(routine)h(forces)i(FITSIO)e(to)i(scan)f(the)g(curren)m
+(t)g(header)g(k)m(eyw)m(ords)h(that)f(de\014ne)g(the)g(structure)g(of)
+227 2839 y(the)31 b(HDU)f(\(suc)m(h)g(as)h(the)f(NAXISn,)g(PCOUNT)f
+(and)g(GCOUNT)h(k)m(eyw)m(ords\))h(so)f(that)h(it)e(can)i(initialize)
+227 2952 y(the)36 b(in)m(ternal)e(bu\013ers)g(that)i(describ)s(e)e(the)
+i(HDU)g(structure.)55 b(This)34 b(routine)h(ma)m(y)h(b)s(e)e(used)h
+(instead)g(of)227 3065 y(the)k(more)g(complicated)g(calls)f(to)h(ftp)s
+(def,)h(ftadef)f(or)g(ftb)s(def.)65 b(This)37 b(routine)h(is)g(also)h
+(v)m(ery)g(useful)e(for)227 3178 y(reinitializing)30
+b(the)k(structure)g(of)g(an)f(HDU,)i(if)e(the)h(n)m(um)m(b)s(er)e(of)i
+(ro)m(ws)g(in)f(a)h(table,)h(as)f(sp)s(eci\014ed)e(b)m(y)i(the)227
+3291 y(NAXIS2)d(k)m(eyw)m(ord,)g(has)f(b)s(een)g(mo)s(di\014ed)e(from)i
+(its)g(initial)d(v)-5 b(alue.)382 3554 y Fe(FTRDEF\(unit,)44
+b(>)k(status\))141 b(\(DEPRECATED\))0 3818 y Fh(2)81
+b Fi(De\014ne)27 b(the)g(structure)g(of)g(the)g(primary)e(arra)m(y)j
+(or)f(IMA)m(GE)h(extension.)39 b(When)27 b(writing)e(GR)m(OUP)m(ed)j
+(FITS)227 3931 y(\014les)42 b(that)i(b)m(y)e(con)m(v)m(en)m(tion)j(set)
+e(the)g(NAXIS1)g(k)m(eyw)m(ord)h(equal)e(to)i(0,)i(ftp)s(def)c(m)m(ust)
+h(b)s(e)f(called)g(with)227 4044 y(naxes\(1\))27 b(=)e(1,)i(NOT)e(0,)i
+(otherwise)e(FITSIO)f(will)f(rep)s(ort)i(an)g(error)g(status=308)i
+(when)d(trying)h(to)h(write)227 4157 y(data)31 b(to)g(a)g(group.)40
+b(Note:)i(it)30 b(is)g(usually)e(simpler)g(to)j(call)f(FTRDEF)g(rather)
+h(than)f(this)f(routine.)382 4421 y Fe(FTPDEF\(unit,bitpix,naxis)o(,na)
+o(xes,)o(pcou)o(nt,)o(gcou)o(nt,)41 b(>)48 b(status\))93
+b(\(DEPRECATED\))0 4684 y Fh(3)81 b Fi(De\014ne)32 b(the)h(structure)f
+(of)g(an)h(ASCI)s(I)e(table)h(\(T)-8 b(ABLE\))33 b(extension.)47
+b(Note:)f(it)32 b(is)f(usually)f(simpler)g(to)k(call)227
+4797 y(FTRDEF)d(rather)f(than)h(this)e(routine.)382 5061
+y Fe(FTADEF\(unit,rowlen,tfiel)o(ds,)o(tbco)o(l,tf)o(orm)o(,nro)o(ws)42
+b(>)47 b(status\))f(\(DEPRECATED\))0 5325 y Fh(4)81 b
+Fi(De\014ne)35 b(the)h(structure)f(of)g(a)h(binary)e(table)h(\(BINT)-8
+b(ABLE\))37 b(extension.)55 b(Note:)e(it)35 b(is)f(usually)f(simpler)g
+(to)227 5438 y(call)d(FTRDEF)h(rather)f(than)g(this)f(routine.)382
+5701 y Fe(FTBDEF\(unit,tfields,tfor)o(m,v)o(arid)o(at,n)o(row)o(s)42
+b(>)47 b(status\))f(\(DEPRECATED\))p eop
+%%Page: 76 82
+76 81 bop 0 299 a Fi(76)1319 b Fg(CHAPTER)29 b(9.)112
+b(AD)m(V)-10 b(ANCED)32 b(INTERF)-10 b(A)m(CE)30 b(SUBR)m(OUTINES)0
+555 y Fh(5)81 b Fi(De\014ne)34 b(the)g(size)g(of)g(the)g(Curren)m(t)f
+(Data)i(Unit,)g(o)m(v)m(erriding)d(the)i(length)g(of)g(the)g(data)h
+(unit)d(as)i(previously)227 668 y(de\014ned)e(b)m(y)h(ftp)s(def,)g
+(ftadef,)i(or)e(ftb)s(def.)48 b(This)32 b(is)g(useful)f(if)i(one)g(do)s
+(es)g(not)h(kno)m(w)f(the)g(total)h(size)f(of)h(the)227
+781 y(data)f(unit)e(un)m(til)g(after)h(the)h(data)g(ha)m(v)m(e)g(b)s
+(een)f(written.)45 b(The)32 b(size)g(\(in)f(b)m(ytes\))i(of)g(an)f
+(ASCI)s(I)f(or)h(Binary)227 894 y(table)26 b(is)f(giv)m(en)g(b)m(y)h
+(NAXIS1)g(*)g(NAXIS2.)40 b(\(Note)27 b(that)f(to)h(determine)e(the)g(v)
+-5 b(alue)26 b(of)g(NAXIS1)f(it)h(is)f(often)227 1007
+y(more)32 b(con)m(v)m(enien)m(t)g(to)g(read)f(the)g(v)-5
+b(alue)31 b(of)g(the)h(NAXIS1)f(k)m(eyw)m(ord)h(from)e(the)i(output)e
+(\014le,)h(rather)g(than)227 1120 y(computing)e(the)h(ro)m(w)g(length)g
+(directly)e(from)h(all)g(the)h(TF)m(ORM)h(k)m(eyw)m(ord)f(v)-5
+b(alues\).)40 b(Note:)i(it)29 b(is)g(usually)227 1233
+y(simpler)f(to)j(call)f(FTRDEF)h(rather)f(than)g(this)f(routine.)382
+1454 y Fe(FTDDEF\(unit,bytlen,)42 b(>)48 b(status\))e(\(DEPRECATED\))0
+1676 y Fh(6)81 b Fi(De\014ne)22 b(the)g(zero)i(indexed)c(b)m(yte)j
+(o\013set)g(of)g(the)f('heap')h(measured)e(from)h(the)h(start)g(of)f
+(the)g(binary)f(table)h(data.)227 1789 y(By)30 b(default)f(the)g(heap)h
+(is)e(assumed)h(to)h(start)g(immediately)e(follo)m(wing)g(the)i
+(regular)e(table)i(data,)g(i.e.,)g(at)227 1902 y(lo)s(cation)36
+b(NAXIS1)h(x)g(NAXIS2.)59 b(This)35 b(routine)g(is)h(only)f(relev)-5
+b(an)m(t)37 b(for)f(binary)f(tables)h(whic)m(h)g(con)m(tain)227
+2015 y(v)-5 b(ariable)34 b(length)h(arra)m(y)g(columns)f(\(with)h(TF)m
+(ORMn)g(=)f('Pt'\).)57 b(This)33 b(subroutine)g(also)i(automatically)
+227 2128 y(writes)22 b(the)h(v)-5 b(alue)22 b(of)h(theap)g(to)h(a)f(k)m
+(eyw)m(ord)g(in)f(the)h(extension)f(header.)38 b(This)21
+b(subroutine)g(m)m(ust)i(b)s(e)f(called)227 2241 y(after)27
+b(the)f(required)e(k)m(eyw)m(ords)j(ha)m(v)m(e)g(b)s(een)e(written)g
+(\(with)g(ftph)m(bn\))g(and)h(after)g(the)h(table)f(structure)f(has)227
+2354 y(b)s(een)30 b(de\014ned)f(\(with)g(ftb)s(def)7
+b(\))30 b(but)g(b)s(efore)g(an)m(y)g(data)h(is)f(written)f(to)i(the)g
+(table.)382 2575 y Fe(FTPTHP\(unit,theap,)43 b(>)k(status\))0
+2903 y Fd(9.4)135 b(FITS)44 b(Header)i(I/O)f(Subroutines)0
+3156 y Fb(9.4.1)112 b(Header)38 b(Space)h(and)f(P)m(osition)d(Routines)
+0 3359 y Fh(1)81 b Fi(Reserv)m(e)37 b(space)g(in)e(the)i(CHU)f(for)h
+(MOREKEYS)e(more)i(header)f(k)m(eyw)m(ords.)59 b(This)35
+b(subroutine)f(ma)m(y)k(b)s(e)227 3472 y(called)c(to)i(reserv)m(e)g
+(space)f(for)g(k)m(eyw)m(ords)g(whic)m(h)f(are)h(to)h(b)s(e)e(written)g
+(at)h(a)h(later)f(time,)h(after)f(the)g(data)227 3585
+y(unit)g(or)h(subsequen)m(t)f(extensions)g(ha)m(v)m(e)i(b)s(een)e
+(written)g(to)i(the)f(FITS)f(\014le.)57 b(If)35 b(this)g(subroutine)f
+(is)h(not)227 3698 y(explicitly)25 b(called,)i(then)g(the)g(initial)e
+(size)h(of)i(the)f(FITS)f(header)h(will)e(b)s(e)h(limited)f(to)j(the)f
+(space)h(a)m(v)-5 b(ailable)227 3811 y(at)24 b(the)g(time)f(that)h(the)
+g(\014rst)f(data)h(is)f(written)f(to)i(the)g(asso)s(ciated)g(data)g
+(unit.)37 b(FITSIO)22 b(has)i(the)f(abilit)m(y)f(to)227
+3924 y(dynamically)g(add)h(more)h(space)h(to)g(the)f(header)g(if)f
+(needed,)i(ho)m(w)m(ev)m(er)g(it)f(is)f(more)h(e\016cien)m(t)g(to)h
+(preallo)s(cate)227 4037 y(the)31 b(required)d(space)j(if)f(the)g(size)
+g(is)g(kno)m(wn)g(in)f(adv)-5 b(ance.)382 4258 y Fe
+(FTHDEF\(unit,morekeys,)42 b(>)47 b(status\))0 4480 y
+Fh(2)81 b Fi(Return)23 b(the)i(n)m(um)m(b)s(er)e(of)h(existing)g(k)m
+(eyw)m(ords)g(in)g(the)g(CHU)g(\(NOT)h(including)c(the)j(END)h(k)m(eyw)
+m(ord)g(whic)m(h)e(is)227 4593 y(not)h(considered)e(a)h(real)g(k)m(eyw)
+m(ord\))h(and)f(the)g(remaining)f(space)h(a)m(v)-5 b(ailable)23
+b(to)h(write)e(additional)g(k)m(eyw)m(ords)227 4706 y(in)38
+b(the)i(CHU.)f(\(returns)f(KEYSADD)i(=)f(-1)h(if)e(the)h(header)g(has)g
+(not)h(y)m(et)g(b)s(een)e(closed\).)68 b(Note)40 b(that)227
+4819 y(FITSIO)23 b(will)f(attempt)j(to)g(dynamically)d(add)h(space)i
+(for)f(more)g(k)m(eyw)m(ords)h(if)e(required)f(when)h(app)s(ending)227
+4932 y(new)30 b(k)m(eyw)m(ords)h(to)g(a)g(header.)382
+5153 y Fe(FTGHSP\(iunit,)44 b(>)j(keysexist,keysadd,status\))0
+5375 y Fh(3)81 b Fi(Return)38 b(the)i(n)m(um)m(b)s(er)e(of)h(k)m(eyw)m
+(ords)h(in)e(the)h(header)g(and)g(the)g(curren)m(t)h(p)s(osition)d(in)h
+(the)h(header.)68 b(This)227 5488 y(returns)37 b(the)g(n)m(um)m(b)s(er)
+f(of)i(the)g(k)m(eyw)m(ord)g(record)f(that)h(will)d(b)s(e)i(read)g
+(next)h(\(or)g(one)g(greater)g(than)g(the)227 5601 y(p)s(osition)27
+b(of)h(the)h(last)f(k)m(eyw)m(ord)h(that)g(w)m(as)f(read)g(or)h
+(written\).)39 b(A)29 b(v)-5 b(alue)27 b(of)i(1)g(is)e(returned)g(if)g
+(the)i(p)s(oin)m(ter)227 5714 y(is)h(p)s(ositioned)e(at)j(the)g(b)s
+(eginning)c(of)k(the)g(header.)p eop
+%%Page: 77 83
+77 82 bop 0 299 a Fg(9.4.)72 b(FITS)30 b(HEADER)h(I/O)f(SUBR)m(OUTINES)
+2086 b Fi(77)382 555 y Fe(FTGHPS\(iunit,)44 b(>)j
+(keysexist,key_no,status\))0 845 y Fb(9.4.2)112 b(Read)38
+b(or)f(W)-9 b(rite)36 b(Standard)j(Header)e(Routines)0
+1064 y Fi(These)31 b(subroutines)d(pro)m(vide)i(a)h(simple)e(metho)s(d)
+h(of)h(reading)f(or)h(writing)e(most)i(of)g(the)g(k)m(eyw)m(ord)g(v)-5
+b(alues)30 b(that)0 1177 y(are)e(normally)e(required)g(in)h(a)h(FITS)f
+(\014les.)39 b(These)27 b(subroutines)f(are)i(pro)m(vided)e(for)i(con)m
+(v)m(enience)g(only)f(and)h(are)0 1290 y(not)36 b(required)d(to)j(b)s
+(e)f(used.)55 b(If)35 b(preferred,)h(users)e(ma)m(y)i(call)f(the)h(lo)m
+(w)m(er-lev)m(el)f(subroutines)e(describ)s(ed)h(in)g(the)0
+1402 y(previous)29 b(section)i(to)h(individually)26 b(read)k(or)h
+(write)f(the)h(required)e(k)m(eyw)m(ords.)43 b(Note)32
+b(that)g(in)d(most)j(cases,)g(the)0 1515 y(required)25
+b(k)m(eyw)m(ords)i(suc)m(h)g(as)g(NAXIS,)f(TFIELD,)h(TTYPEn,)g(etc,)i
+(whic)m(h)c(de\014ne)h(the)h(structure)f(of)h(the)g(HDU)0
+1628 y(m)m(ust)j(b)s(e)g(written)f(to)j(the)e(header)g(b)s(efore)g(an)m
+(y)h(data)g(can)g(b)s(e)e(written)h(to)h(the)g(image)f(or)h(table.)0
+1881 y Fh(1)81 b Fi(Put)37 b(the)i(primary)d(header)i(or)g(IMA)m(GE)h
+(extension)e(k)m(eyw)m(ords)i(in)m(to)f(the)g(CHU.)g(There)g(are)g(2)h
+(a)m(v)-5 b(ailable)227 1994 y(routines:)38 b(The)27
+b(simpler)d(FTPHPS)j(routine)f(is)g(equiv)-5 b(alen)m(t)27
+b(to)g(calling)f(ftphpr)f(with)h(the)h(default)g(v)-5
+b(alues)227 2107 y(of)35 b(SIMPLE)f(=)g(true,)i(p)s(coun)m(t)e(=)g(0,)i
+(gcoun)m(t)g(=)e(1,)i(and)e(EXTEND)h(=)f(true.)53 b(PCOUNT,)34
+b(GCOUNT)227 2220 y(and)23 b(EXTEND)h(k)m(eyw)m(ords)g(are)h(not)f
+(required)e(in)g(the)i(primary)e(header)h(and)h(are)g(only)f(written)g
+(if)f(p)s(coun)m(t)227 2333 y(is)30 b(not)h(equal)g(to)h(zero,)g(gcoun)
+m(t)g(is)e(not)h(equal)f(to)i(zero)g(or)f(one,)g(and)g(if)f(extend)h
+(is)f(TR)m(UE,)h(resp)s(ectiv)m(ely)-8 b(.)227 2446 y(When)30
+b(writing)f(to)i(an)f(IMA)m(GE)i(extension,)e(the)g(SIMPLE)g(and)g
+(EXTEND)g(parameters)h(are)g(ignored.)382 2699 y Fe
+(FTPHPS\(unit,bitpix,naxis)o(,na)o(xes,)41 b(>)48 b(status\))382
+2925 y(FTPHPR\(unit,simple,bitpi)o(x,n)o(axis)o(,nax)o(es,)o(pcou)o
+(nt,g)o(cou)o(nt,e)o(xten)o(d,)41 b(>)48 b(status\))0
+3178 y Fh(2)81 b Fi(Get)44 b(primary)d(header)i(or)h(IMA)m(GE)g
+(extension)f(k)m(eyw)m(ords)h(from)f(the)g(CHU.)h(When)f(reading)f
+(from)h(an)227 3291 y(IMA)m(GE)32 b(extension)e(the)g(SIMPLE)g(and)f
+(EXTEND)i(parameters)g(are)f(ignored.)382 3544 y Fe
+(FTGHPR\(unit,maxdim,)42 b(>)48 b(simple,bitpix,naxis,naxe)o(s,p)o
+(coun)o(t,gc)o(oun)o(t,ex)o(tend)o(,)716 3657 y(status\))0
+3911 y Fh(3)81 b Fi(Put)34 b(the)h(ASCI)s(I)f(table)h(header)g(k)m(eyw)
+m(ords)g(in)m(to)g(the)g(CHU.)h(The)e(optional)g(TUNITn)g(and)h
+(EXTNAME)227 4024 y(k)m(eyw)m(ords)c(are)g(written)e(only)h(if)f(the)i
+(input)d(string)h(v)-5 b(alues)30 b(are)h(not)f(blank.)382
+4277 y Fe(FTPHTB\(unit,rowlen,nrows)o(,tf)o(ield)o(s,tt)o(ype)o(,tbc)o
+(ol,t)o(for)o(m,tu)o(nit,)o(ext)o(name)o(,)42 b(>)716
+4390 y(status\))0 4643 y Fh(4)81 b Fi(Get)31 b(the)g(ASCI)s(I)d(table)j
+(header)f(k)m(eyw)m(ords)h(from)e(the)i(CHU)382 4896
+y Fe(FTGHTB\(unit,maxdim,)42 b(>)48 b(rowlen,nrows,tfields,tty)o(pe,)o
+(tbco)o(l,tf)o(orm)o(,tun)o(it,)716 5009 y(extname,status\))0
+5262 y Fh(5)81 b Fi(Put)34 b(the)h(binary)e(table)i(header)f(k)m(eyw)m
+(ords)i(in)m(to)e(the)h(CHU.)g(The)g(optional)f(TUNITn)g(and)g(EXTNAME)
+227 5375 y(k)m(eyw)m(ords)i(are)g(written)e(only)g(if)h(the)g(input)e
+(string)i(v)-5 b(alues)34 b(are)i(not)f(blank.)54 b(The)35
+b(p)s(coun)m(t)g(parameter,)227 5488 y(whic)m(h)e(sp)s(eci\014es)g(the)
+i(size)f(of)h(the)f(v)-5 b(ariable)33 b(length)h(arra)m(y)h(heap,)g
+(should)e(initially)d(=)k(0;)j(FITSIO)d(will)227 5601
+y(automatically)24 b(up)s(date)f(the)h(PCOUNT)f(k)m(eyw)m(ord)h(v)-5
+b(alue)23 b(if)g(an)m(y)h(v)-5 b(ariable)23 b(length)g(arra)m(y)i(data)
+f(is)f(written)227 5714 y(to)31 b(the)e(heap.)41 b(The)29
+b(TF)m(ORM)g(k)m(eyw)m(ord)h(v)-5 b(alue)29 b(for)h(v)-5
+b(ariable)28 b(length)h(v)m(ector)i(columns)d(should)g(ha)m(v)m(e)j
+(the)p eop
+%%Page: 78 84
+78 83 bop 0 299 a Fi(78)1319 b Fg(CHAPTER)29 b(9.)112
+b(AD)m(V)-10 b(ANCED)32 b(INTERF)-10 b(A)m(CE)30 b(SUBR)m(OUTINES)227
+555 y Fi(form)d('Pt\(len\)')i(or)e('1Pt\(len\)')i(where)e(`t')h(is)f
+(the)h(data)g(t)m(yp)s(e)g(co)s(de)f(letter)h(\(A,I,J,E,D,)h(etc.\))42
+b(and)27 b(`len')g(is)227 668 y(an)h(in)m(teger)h(sp)s(ecifying)d(the)i
+(maxim)m(um)f(length)g(of)i(the)f(v)m(ectors)h(in)e(that)i(column)e
+(\(len)g(m)m(ust)h(b)s(e)g(greater)227 781 y(than)j(or)h(equal)e(to)j
+(the)e(longest)h(v)m(ector)g(in)e(the)i(column\).)43
+b(If)30 b(`len')h(is)g(not)g(sp)s(eci\014ed)f(when)g(the)i(table)f(is)
+227 894 y(created)c(\(e.g.,)i(the)d(input)e(TF)m(ORMn)i(v)-5
+b(alue)25 b(is)g(just)g('1Pt'\))j(then)d(FITSIO)g(will)e(scan)j(the)g
+(column)f(when)227 1007 y(the)30 b(table)f(is)f(\014rst)h(closed)g(and)
+g(will)d(app)s(end)i(the)h(maxim)m(um)g(length)f(to)i(the)g(TF)m(ORM)f
+(k)m(eyw)m(ord)h(v)-5 b(alue.)227 1120 y(Note)28 b(that)e(if)f(the)h
+(table)g(is)f(subsequen)m(tly)g(mo)s(di\014ed)f(to)j(increase)e(the)i
+(maxim)m(um)e(length)g(of)h(the)g(v)m(ectors)227 1233
+y(then)k(the)h(mo)s(difying)d(program)i(is)f(resp)s(onsible)f(for)i
+(also)g(up)s(dating)e(the)j(TF)m(ORM)g(k)m(eyw)m(ord)g(v)-5
+b(alue.)382 1462 y Fe(FTPHBN\(unit,nrows,tfield)o(s,t)o(type)o(,tfo)o
+(rm,)o(tuni)o(t,ex)o(tna)o(me,v)o(arid)o(at,)41 b(>)48
+b(status\))0 1691 y Fh(6)81 b Fi(Get)31 b(the)g(binary)d(table)i
+(header)h(k)m(eyw)m(ords)f(from)g(the)h(CHU)382 1921
+y Fe(FTGHBN\(unit,maxdim,)42 b(>)48 b(nrows,tfields,ttype,tfor)o(m,t)o
+(unit)o(,ext)o(nam)o(e,va)o(rida)o(t,)716 2034 y(status\))0
+2320 y Fb(9.4.3)112 b(W)-9 b(rite)36 b(Keyw)m(ord)h(Subroutines)0
+2524 y Fh(1)81 b Fi(Put)30 b(\(app)s(end\))f(an)h(80-c)m(haracter)j
+(record)e(in)m(to)f(the)h(CHU.)382 2753 y Fe(FTPREC\(unit,card,)43
+b(>)k(status\))0 2982 y Fh(2)81 b Fi(Put)36 b(\(app)s(end\))g(a)i
+(COMMENT)f(k)m(eyw)m(ord)g(in)m(to)g(the)h(CHU.)f(Multiple)e(COMMENT)i
+(k)m(eyw)m(ords)g(will)e(b)s(e)227 3095 y(written)30
+b(if)f(the)i(input)d(commen)m(t)j(string)f(is)f(longer)h(than)g(72)i(c)
+m(haracters.)382 3325 y Fe(FTPCOM\(unit,comment,)42 b(>)48
+b(status\))0 3554 y Fh(3)81 b Fi(Put)24 b(\(app)s(end\))g(a)h(HISTOR)-8
+b(Y)25 b(k)m(eyw)m(ord)g(in)m(to)g(the)g(CHU.)g(Multiple)e(HISTOR)-8
+b(Y)24 b(k)m(eyw)m(ords)h(will)e(b)s(e)h(written)227
+3667 y(if)30 b(the)g(input)f(history)g(string)g(is)h(longer)g(than)g
+(72)h(c)m(haracters.)382 3897 y Fe(FTPHIS\(unit,history,)42
+b(>)48 b(status\))0 4126 y Fh(4)81 b Fi(Put)36 b(\(app)s(end\))f(the)h
+(D)m(A)-8 b(TE)38 b(k)m(eyw)m(ord)f(in)m(to)f(the)g(CHU.)h(The)f(k)m
+(eyw)m(ord)g(v)-5 b(alue)36 b(will)e(con)m(tain)j(the)f(curren)m(t)227
+4239 y(system)c(date)g(as)g(a)f(c)m(haracter)i(string)e(in)f
+('dd/mm/yy')h(format.)44 b(If)31 b(a)h(D)m(A)-8 b(TE)32
+b(k)m(eyw)m(ord)g(already)f(exists)227 4352 y(in)j(the)h(header,)i
+(then)d(this)g(subroutine)f(will)g(simply)f(up)s(date)j(the)g(k)m(eyw)m
+(ord)g(v)-5 b(alue)35 b(in-place)f(with)g(the)227 4465
+y(curren)m(t)c(date.)382 4694 y Fe(FTPDAT\(unit,)44 b(>)k(status\))0
+4924 y Fh(5)81 b Fi(Put)22 b(\(app)s(end\))f(a)i(new)f(k)m(eyw)m(ord)h
+(of)g(the)f(appropriate)g(datat)m(yp)s(e)h(in)m(to)g(the)f(CHU.)h(Note)
+h(that)f(FTPKYS)f(will)227 5036 y(only)32 b(write)g(string)f(v)-5
+b(alues)32 b(up)f(to)j(68)f(c)m(haracters)h(in)d(length;)i(longer)f
+(strings)g(will)d(b)s(e)j(truncated.)47 b(The)227 5149
+y(FTPKLS)27 b(routine)g(can)i(b)s(e)f(used)f(to)i(write)e(longer)h
+(strings,)g(using)e(a)j(non-standard)e(FITS)h(con)m(v)m(en)m(tion.)227
+5262 y(The)23 b(E)h(and)f(D)h(v)m(ersions)f(of)h(this)e(routine)h(ha)m
+(v)m(e)i(the)f(added)f(feature)h(that)g(if)f(the)h('decimals')f
+(parameter)h(is)227 5375 y(negativ)m(e,)h(then)20 b(the)i('G')g(displa)
+m(y)d(format)i(rather)g(then)g(the)g('E')h(format)f(will)e(b)s(e)h
+(used)g(when)g(constructing)227 5488 y(the)25 b(k)m(eyw)m(ord)f(v)-5
+b(alue,)25 b(taking)f(the)h(absolute)f(v)-5 b(alue)23
+b(of)i('decimals')e(for)h(the)g(precision.)37 b(This)22
+b(will)g(suppress)227 5601 y(trailing)32 b(zeros,)k(and)d(will)f(use)h
+(a)i(\014xed)e(format)h(rather)g(than)f(an)h(exp)s(onen)m(tial)f
+(format,)j(dep)s(ending)31 b(on)227 5714 y(the)g(magnitude)e(of)i(the)f
+(v)-5 b(alue.)p eop
+%%Page: 79 85
+79 84 bop 0 299 a Fg(9.4.)72 b(FITS)30 b(HEADER)h(I/O)f(SUBR)m(OUTINES)
+2086 b Fi(79)382 555 y Fe(FTPKY[JLS]\(unit,keyword,)o(key)o(val,)o
+(comm)o(ent)o(,)42 b(>)47 b(status\))382 668 y
+(FTPKY[EDFG]\(unit,keyword)o(,ke)o(yval)o(,dec)o(ima)o(ls,c)o(omme)o
+(nt,)41 b(>)48 b(status\))0 915 y Fh(6)81 b Fi(Put)33
+b(\(app)s(end\))h(a)g(string)f(v)-5 b(alued)33 b(k)m(eyw)m(ord)i(in)m
+(to)f(the)h(CHU)f(whic)m(h)f(ma)m(y)h(b)s(e)g(longer)g(than)f(68)i(c)m
+(haracters)227 1028 y(in)i(length.)63 b(This)36 b(uses)i(the)g(Long)g
+(String)f(Keyw)m(ord)h(con)m(v)m(en)m(tion)h(that)f(is)f(describ)s(ed)f
+(in)h(the)h("Usage)227 1141 y(Guidelines)30 b(and)h(Suggestions")i
+(section)f(of)h(this)e(do)s(cumen)m(t.)46 b(Since)32
+b(this)f(uses)h(a)g(non-standard)g(FITS)227 1254 y(con)m(v)m(en)m(tion)
+37 b(to)e(enco)s(de)h(the)f(long)g(k)m(eyw)m(ord)g(string,)h(programs)e
+(whic)m(h)g(use)h(this)f(routine)g(should)f(also)227
+1367 y(call)d(the)g(FTPLSW)g(routine)g(to)h(add)e(some)i(COMMENT)f(k)m
+(eyw)m(ords)h(to)g(w)m(arn)f(users)f(of)i(the)f(FITS)g(\014le)227
+1480 y(that)36 b(this)e(con)m(v)m(en)m(tion)j(is)d(b)s(eing)g(used.)55
+b(FTPLSW)35 b(also)g(writes)g(a)g(k)m(eyw)m(ord)h(called)f(LONGSTRN)f
+(to)227 1593 y(record)c(the)h(v)m(ersion)e(of)i(the)f(longstring)f(con)
+m(v)m(en)m(tion)i(that)g(has)f(b)s(een)g(used,)f(in)g(case)i(a)g(new)f
+(con)m(v)m(en)m(tion)227 1705 y(is)e(adopted)h(at)g(some)g(p)s(oin)m(t)
+e(in)h(the)g(future.)40 b(If)28 b(the)g(LONGSTRN)g(k)m(eyw)m(ord)h(is)f
+(already)g(presen)m(t)g(in)g(the)227 1818 y(header,)j(then)f(FTPLSW)g
+(will)d(simply)h(return)i(and)f(will)f(not)j(write)e(duplicate)g(k)m
+(eyw)m(ords.)382 2065 y Fe(FTPKLS\(unit,keyword,keyv)o(al,)o(comm)o
+(ent,)41 b(>)47 b(status\))382 2178 y(FTPLSW\(unit,)d(>)k(status\))0
+2425 y Fh(7)81 b Fi(Put)30 b(\(app)s(end\))g(a)h(new)f(k)m(eyw)m(ord)h
+(with)e(an)i(unde\014ned,)e(or)h(n)m(ull,)f(v)-5 b(alue)30
+b(in)m(to)h(the)g(CHU.)g(The)f(v)-5 b(alue)30 b(string)227
+2538 y(of)h(the)f(k)m(eyw)m(ord)h(is)f(left)g(blank)f(in)g(this)g
+(case.)382 2785 y Fe(FTPKYU\(unit,keyword,comm)o(ent)o(,)42
+b(>)47 b(status\))0 3032 y Fh(8)81 b Fi(Put)41 b(\(app)s(end\))g(a)i(n)
+m(um)m(b)s(ered)d(sequence)j(of)f(k)m(eyw)m(ords)g(in)m(to)g(the)h
+(CHU.)f(One)f(ma)m(y)i(app)s(end)d(the)j(same)227 3145
+y(commen)m(t)37 b(to)g(ev)m(ery)g(k)m(eyw)m(ord)g(\(and)f(eliminate)e
+(the)j(need)f(to)h(ha)m(v)m(e)g(an)f(arra)m(y)h(of)f(iden)m(tical)f
+(commen)m(t)227 3258 y(strings,)i(one)f(for)g(eac)m(h)h(k)m(eyw)m
+(ord\))g(b)m(y)f(including)d(the)j(amp)s(ersand)e(c)m(haracter)k(as)e
+(the)h(last)f(non-blank)227 3371 y(c)m(haracter)h(in)d(the)i
+(\(\014rst\))f(COMMENTS)f(string)g(parameter.)56 b(This)34
+b(same)h(string)g(will)d(then)j(b)s(e)g(used)227 3484
+y(for)30 b(the)g(commen)m(t)h(\014eld)e(in)f(all)h(the)h(k)m(eyw)m
+(ords.)41 b(\(Note)32 b(that)e(the)g(SPP)f(v)m(ersion)h(of)g(these)g
+(routines)f(only)227 3597 y(supp)s(orts)g(a)i(single)e(commen)m(t)i
+(string\).)382 3844 y Fe(FTPKN[JLS]\(unit,keyroot,)o(sta)o(rtno)o(,no_)
+o(key)o(s,ke)o(yval)o(s,c)o(omme)o(nts,)41 b(>)47 b(status\))382
+3957 y(FTPKN[EDFG]\(unit,keyroot)o(,st)o(artn)o(o,no)o(_ke)o(ys,k)o
+(eyva)o(ls,)o(deci)o(mals)o(,co)o(mmen)o(ts,)41 b(>)907
+4070 y(status\))0 4317 y Fh(9)81 b Fi(Cop)m(y)21 b(an)h(indexed)e(k)m
+(eyw)m(ord)j(from)e(one)h(HDU)h(to)f(another,)i(mo)s(difying)c(the)i
+(index)e(n)m(um)m(b)s(er)g(of)i(the)g(k)m(eyw)m(ord)227
+4430 y(name)37 b(in)e(the)h(pro)s(cess.)58 b(F)-8 b(or)37
+b(example,)h(this)d(routine)h(could)f(read)h(the)h(TLMIN3)f(k)m(eyw)m
+(ord)h(from)f(the)227 4542 y(input)27 b(HDU)i(\(b)m(y)f(giving)f(k)m
+(eyro)s(ot)j(=)d("TLMIN")i(and)f(inn)m(um)e(=)i(3\))h(and)f(write)f(it)
+h(to)h(the)f(output)g(HDU)227 4655 y(with)35 b(the)h(k)m(eyw)m(ord)h
+(name)f(TLMIN4)g(\(b)m(y)g(setting)h(outn)m(um)e(=)h(4\).)58
+b(If)36 b(the)g(input)e(k)m(eyw)m(ord)j(do)s(es)f(not)227
+4768 y(exist,)31 b(then)f(this)f(routine)g(simply)f(returns)h(without)h
+(indicating)e(an)i(error.)382 5015 y Fe(FTCPKYinunit,)44
+b(outunit,)i(innum,)g(outnum,)f(keyroot,)h(>)h(status\))0
+5262 y Fh(10)f Fi(Put)33 b(\(app)s(end\))f(a)h('triple)f(precision')g
+(k)m(eyw)m(ord)h(in)m(to)g(the)h(CHU)f(in)f(F28.16)j(format.)49
+b(The)33 b(\015oating)g(p)s(oin)m(t)227 5375 y(k)m(eyw)m(ord)d(v)-5
+b(alue)29 b(is)f(constructed)i(b)m(y)f(concatenating)i(the)e(input)f
+(in)m(teger)i(v)-5 b(alue)28 b(with)g(the)i(input)d(double)227
+5488 y(precision)20 b(fraction)i(v)-5 b(alue)22 b(\(whic)m(h)f(m)m(ust)
+h(ha)m(v)m(e)h(a)f(v)-5 b(alue)22 b(b)s(et)m(w)m(een)h(0.0)g(and)e
+(1.0\).)40 b(The)21 b(FTGKYT)h(routine)227 5601 y(should)34
+b(b)s(e)i(used)f(to)i(read)f(this)e(k)m(eyw)m(ord)j(v)-5
+b(alue,)37 b(b)s(ecause)f(the)g(other)h(k)m(eyw)m(ord)f(reading)f
+(subroutines)227 5714 y(will)28 b(not)j(preserv)m(e)f(the)h(full)d
+(precision)g(of)j(the)f(v)-5 b(alue.)p eop
+%%Page: 80 86
+80 85 bop 0 299 a Fi(80)1319 b Fg(CHAPTER)29 b(9.)112
+b(AD)m(V)-10 b(ANCED)32 b(INTERF)-10 b(A)m(CE)30 b(SUBR)m(OUTINES)382
+555 y Fe(FTPKYT\(unit,keyword,intv)o(al,)o(dblv)o(al,c)o(omm)o(ent,)41
+b(>)48 b(status\))0 850 y Fh(11)e Fi(W)-8 b(rite)35 b(k)m(eyw)m(ords)h
+(to)f(the)h(CHDU)f(that)h(are)f(de\014ned)f(in)f(an)i(ASCI)s(I)f
+(template)h(\014le.)54 b(The)34 b(format)i(of)f(the)227
+963 y(template)c(\014le)f(is)f(describ)s(ed)f(under)h(the)i(ftgthd)f
+(routine)f(b)s(elo)m(w.)382 1258 y Fe(FTPKTP\(unit,)44
+b(filename,)i(>)h(status\))0 1552 y Fh(12)f Fi(App)s(end)28
+b(the)i(ph)m(ysical)e(units)h(string)g(to)h(an)g(existing)f(k)m(eyw)m
+(ord.)41 b(This)28 b(routine)h(uses)g(a)h(lo)s(cal)g(con)m(v)m(en)m
+(tion,)227 1665 y(sho)m(wn)i(in)f(the)i(follo)m(wing)e(example,)i(in)e
+(whic)m(h)g(the)i(k)m(eyw)m(ord)g(units)e(are)i(enclosed)f(in)f(square)
+h(brac)m(k)m(ets)227 1778 y(in)d(the)i(b)s(eginning)d(of)i(the)h(k)m
+(eyw)m(ord)g(commen)m(t)g(\014eld.)239 2073 y Fe(VELOCITY=)809
+b(12.3)46 b(/)i([km/s])e(orbital)g(speed)382 2299 y
+(FTPUNT\(unit,keyword,unit)o(s,)41 b(>)48 b(status\))0
+2630 y Fb(9.4.4)112 b(Insert)38 b(Keyw)m(ord)f(Subroutines)0
+2865 y Fh(1)81 b Fi(Insert)26 b(a)h(new)f(k)m(eyw)m(ord)h(record)g(in)m
+(to)f(the)h(CHU)g(at)g(the)g(sp)s(eci\014ed)e(p)s(osition)g(\(i.e.,)j
+(immediately)d(preceding)227 2978 y(the)34 b(\(k)m(eyno\)th)g(k)m(eyw)m
+(ord)g(in)e(the)i(header.\))49 b(This)32 b('insert)g(record')i
+(subroutine)d(is)h(somewhat)i(less)f(e\016-)227 3091
+y(cien)m(t)27 b(then)g(the)g('app)s(end)e(record')i(subroutine)e
+(\(FTPREC\))h(describ)s(ed)f(ab)s(o)m(v)m(e)j(b)s(ecause)f(the)g
+(remaining)227 3204 y(k)m(eyw)m(ords)k(in)e(the)i(header)f(ha)m(v)m(e)h
+(to)g(b)s(e)f(shifted)f(do)m(wn)h(one)h(slot.)382 3499
+y Fe(FTIREC\(unit,key_no,card,)41 b(>)47 b(status\))0
+3793 y Fh(2)81 b Fi(Insert)36 b(a)h(new)f(k)m(eyw)m(ord)i(in)m(to)f
+(the)g(CHU.)g(The)f(new)g(k)m(eyw)m(ord)i(is)e(inserted)f(immediately)g
+(follo)m(wing)h(the)227 3906 y(last)26 b(k)m(eyw)m(ord)h(that)f(has)g
+(b)s(een)g(read)g(from)f(the)h(header.)40 b(The)25 b(FTIKLS)g
+(subroutine)f(w)m(orks)i(the)g(same)h(as)227 4019 y(the)h(FTIKYS)e
+(subroutine,)g(except)j(it)e(also)g(supp)s(orts)f(long)h(string)f(v)-5
+b(alues)27 b(greater)h(than)f(68)h(c)m(haracters)227
+4132 y(in)35 b(length.)58 b(These)36 b('insert)f(k)m(eyw)m(ord')i
+(subroutines)d(are)j(somewhat)g(less)e(e\016cien)m(t)i(then)f(the)g
+('app)s(end)227 4245 y(k)m(eyw)m(ord')30 b(subroutines)d(describ)s(ed)g
+(ab)s(o)m(v)m(e)j(b)s(ecause)f(the)g(remaining)f(k)m(eyw)m(ords)h(in)f
+(the)h(header)g(ha)m(v)m(e)h(to)227 4358 y(b)s(e)g(shifted)f(do)m(wn)h
+(one)h(slot.)382 4653 y Fe(FTIKEY\(unit,)44 b(card,)j(>)g(status\))382
+4766 y(FTIKY[JLS]\(unit,keyword,)o(key)o(val,)o(comm)o(ent)o(,)42
+b(>)47 b(status\))382 4878 y(FTIKLS\(unit,keyword,keyv)o(al,)o(comm)o
+(ent,)41 b(>)47 b(status\))382 4991 y(FTIKY[EDFG]\(unit,keyword)o(,ke)o
+(yval)o(,dec)o(ima)o(ls,c)o(omme)o(nt,)41 b(>)48 b(status\))0
+5286 y Fh(3)81 b Fi(Insert)32 b(a)i(new)f(k)m(eyw)m(ord)h(with)e(an)h
+(unde\014ned,)g(or)g(n)m(ull,)f(v)-5 b(alue)33 b(in)m(to)h(the)f(CHU.)h
+(The)f(v)-5 b(alue)33 b(string)f(of)i(the)227 5399 y(k)m(eyw)m(ord)d
+(is)f(left)g(blank)f(in)g(this)g(case.)382 5694 y Fe
+(FTIKYU\(unit,keyword,comm)o(ent)o(,)42 b(>)47 b(status\))p
+eop
+%%Page: 81 87
+81 86 bop 0 299 a Fg(9.4.)72 b(FITS)30 b(HEADER)h(I/O)f(SUBR)m(OUTINES)
+2086 b Fi(81)0 555 y Fb(9.4.5)112 b(Read)38 b(Keyw)m(ord)g(Subroutines)
+0 774 y Fi(These)29 b(routines)e(return)h(the)h(v)-5
+b(alue)28 b(of)h(the)g(sp)s(eci\014ed)e(k)m(eyw)m(ord\(s\).)41
+b(Wild)28 b(card)g(c)m(haracters)i(\(*,)h(?,)e(or)g(#\))f(ma)m(y)0
+887 y(b)s(e)f(used)h(when)f(sp)s(ecifying)f(the)i(name)g(of)g(the)g(k)m
+(eyw)m(ord)h(to)g(b)s(e)e(read:)39 b(a)29 b(')10 b(?')40
+b(will)25 b(matc)m(h)k(an)m(y)g(single)d(c)m(haracter)0
+1000 y(at)38 b(that)g(p)s(osition)d(in)h(the)i(k)m(eyw)m(ord)g(name)f
+(and)g(a)g('*')i(will)34 b(matc)m(h)k(an)m(y)g(length)f(\(including)d
+(zero\))k(string)f(of)0 1113 y(c)m(haracters.)65 b(The)37
+b('#')h(c)m(haracter)h(will)c(matc)m(h)k(an)m(y)f(consecutiv)m(e)h
+(string)e(of)h(decimal)f(digits)f(\(0)j(-)f(9\).)64 b(Note)0
+1226 y(that)30 b(when)f(a)g(wild)e(card)j(is)e(used)h(in)f(the)i(input)
+d(k)m(eyw)m(ord)j(name,)g(the)g(routine)e(will)f(only)i(searc)m(h)h
+(for)f(a)h(matc)m(h)0 1339 y(from)h(the)h(curren)m(t)g(header)g(p)s
+(osition)e(to)i(the)h(end)e(of)h(the)g(header.)45 b(It)32
+b(will)d(not)j(resume)g(the)g(searc)m(h)g(from)g(the)0
+1452 y(top)i(of)h(the)f(header)g(bac)m(k)h(to)g(the)f(original)e
+(header)i(p)s(osition)e(as)j(is)e(done)h(when)f(no)h(wildcards)d(are)k
+(included)0 1564 y(in)e(the)h(k)m(eyw)m(ord)h(name.)52
+b(If)33 b(the)h(desired)f(k)m(eyw)m(ord)i(string)e(is)g(8-c)m
+(haracters)j(long)e(\(the)g(maxim)m(um)f(length)h(of)0
+1677 y(a)i(k)m(eyw)m(ord)g(name\))g(then)g(a)g('*')g(ma)m(y)h(b)s(e)e
+(app)s(ended)f(as)h(the)h(nin)m(th)f(c)m(haracter)i(of)f(the)f(input)f
+(name)i(to)g(force)0 1790 y(the)31 b(k)m(eyw)m(ord)g(searc)m(h)h(to)f
+(stop)g(at)g(the)g(end)f(of)h(the)g(header)g(\(e.g.,)i('COMMENT)d(*')i
+(will)c(searc)m(h)j(for)g(the)g(next)0 1903 y(COMMENT)37
+b(k)m(eyw)m(ord\).)64 b(The)37 b(\013grec)i(routine)e(ma)m(y)h(b)s(e)f
+(used)g(to)i(set)f(the)g(starting)f(p)s(osition)f(when)h(doing)0
+2016 y(wild)28 b(card)i(searc)m(hes.)0 2264 y Fh(1)81
+b Fi(Get)37 b(the)f(n)m(th)f(80-c)m(haracter)k(header)d(record)g(from)f
+(the)h(CHU.)h(The)e(\014rst)g(k)m(eyw)m(ord)i(in)d(the)i(header)g(is)f
+(at)227 2377 y(k)m(ey)p 365 2377 28 4 v 34 w(no)42 b(=)f(1;)49
+b(if)41 b(k)m(ey)p 996 2377 V 34 w(no)h(=)f(0)i(then)e(this)g
+(subroutine)f(simple)g(mo)m(v)m(es)k(the)e(in)m(ternal)f(p)s(oin)m(ter)
+g(to)i(the)227 2490 y(b)s(eginning)33 b(of)j(the)g(header)f(so)h(that)g
+(subsequen)m(t)f(k)m(eyw)m(ord)h(op)s(erations)f(will)e(start)j(at)g
+(the)g(top)g(of)g(the)227 2603 y(header;)31 b(it)f(also)g(returns)f(a)i
+(blank)e(card)h(v)-5 b(alue)30 b(in)f(this)g(case.)382
+2850 y Fe(FTGREC\(unit,key_no,)42 b(>)48 b(card,status\))0
+3098 y Fh(2)81 b Fi(Get)31 b(the)g(name,)f(v)-5 b(alue)30
+b(\(as)h(a)g(string\),)f(and)g(commen)m(t)i(of)e(the)h(n)m(th)f(k)m
+(eyw)m(ord)h(in)e(CHU.)i(This)e(routine)g(also)227 3211
+y(c)m(hec)m(ks)i(that)f(the)g(returned)e(k)m(eyw)m(ord)i(name)f(\(KEYW)
+m(ORD\))i(con)m(tains)f(only)e(legal)h(ASCI)s(I)f(c)m(haracters.)227
+3324 y(Call)h(FTGREC)h(and)g(FTPSV)m(C)g(to)h(b)m(ypass)f(this)f(error)
+h(c)m(hec)m(k.)382 3572 y Fe(FTGKYN\(unit,key_no,)42
+b(>)48 b(keyword,value,comment,st)o(atu)o(s\))0 3819
+y Fh(3)81 b Fi(Get)31 b(the)g(80-c)m(haracter)i(header)d(record)g(for)g
+(the)h(named)f(k)m(eyw)m(ord)382 4067 y Fe(FTGCRD\(unit,keyword,)42
+b(>)48 b(card,status\))0 4315 y Fh(4)81 b Fi(Get)26 b(the)f(next)h(k)m
+(eyw)m(ord)f(whose)g(name)h(matc)m(hes)g(one)f(of)h(the)f(strings)f(in)
+g('inclist')g(but)g(do)s(es)h(not)g(matc)m(h)i(an)m(y)227
+4428 y(of)32 b(the)f(strings)f(in)g('exclist'.)43 b(The)30
+b(strings)g(in)g(inclist)f(and)i(exclist)f(ma)m(y)i(con)m(tain)g(wild)c
+(card)j(c)m(haracters)227 4541 y(\(*,)38 b(?,)e(and)e(#\))i(as)f
+(describ)s(ed)e(at)j(the)f(b)s(eginning)d(of)k(this)e(section.)55
+b(This)33 b(routine)h(searc)m(hes)i(from)f(the)227 4654
+y(curren)m(t)28 b(header)f(p)s(osition)f(to)i(the)g(end)f(of)h(the)g
+(header,)g(only)-8 b(,)28 b(and)f(do)s(es)g(not)h(con)m(tin)m(ue)g(the)
+g(searc)m(h)g(from)227 4767 y(the)41 b(top)g(of)g(the)g(header)g(bac)m
+(k)h(to)f(the)g(original)e(p)s(osition.)71 b(The)40 b(curren)m(t)h
+(header)f(p)s(osition)f(ma)m(y)j(b)s(e)227 4880 y(reset)33
+b(with)d(the)i(ftgrec)h(routine.)43 b(Note)33 b(that)g(nexc)f(ma)m(y)g
+(b)s(e)f(set)h(=)g(0)g(if)e(there)i(are)g(no)g(k)m(eyw)m(ords)g(to)h(b)
+s(e)227 4993 y(excluded.)40 b(This)28 b(routine)i(returns)f(status)i(=)
+f(202)h(if)f(a)g(matc)m(hing)h(k)m(eyw)m(ord)g(is)e(not)i(found.)382
+5240 y Fe(FTGNXK\(unit,inclist,ninc)o(,ex)o(clis)o(t,ne)o(xc,)41
+b(>)48 b(card,status\))0 5488 y Fh(5)81 b Fi(Get)30 b(the)g(literal)f
+(k)m(eyw)m(ord)h(v)-5 b(alue)29 b(as)h(a)g(c)m(haracter)i(string.)39
+b(Regardless)30 b(of)g(the)g(datat)m(yp)s(e)g(of)g(the)g(k)m(eyw)m
+(ord,)227 5601 y(this)36 b(routine)g(simply)f(returns)h(the)h(string)f
+(of)h(c)m(haracters)i(in)c(the)j(v)-5 b(alue)36 b(\014eld)g(of)h(the)g
+(k)m(eyw)m(ord)h(along)227 5714 y(with)29 b(the)i(commen)m(t)g
+(\014eld.)p eop
+%%Page: 82 88
+82 87 bop 0 299 a Fi(82)1319 b Fg(CHAPTER)29 b(9.)112
+b(AD)m(V)-10 b(ANCED)32 b(INTERF)-10 b(A)m(CE)30 b(SUBR)m(OUTINES)382
+555 y Fe(FTGKEY\(unit,keyword,)42 b(>)48 b(value,comment,status\))0
+817 y Fh(6)81 b Fi(Get)31 b(a)g(k)m(eyw)m(ord)g(v)-5
+b(alue)29 b(\(with)h(the)g(appropriate)g(datat)m(yp)s(e\))h(and)f
+(commen)m(t)i(from)e(the)g(CHU)382 1079 y Fe(FTGKY[EDJLS]\(unit,keywor)
+o(d,)41 b(>)48 b(keyval,comment,status\))0 1341 y Fh(7)81
+b Fi(Get)24 b(a)g(sequence)g(of)g(n)m(um)m(b)s(ered)e(k)m(eyw)m(ord)i
+(v)-5 b(alues.)37 b(These)24 b(routines)e(do)h(not)h(supp)s(ort)e(wild)
+f(card)i(c)m(haracters)227 1454 y(in)29 b(the)i(ro)s(ot)g(name.)382
+1716 y Fe(FTGKN[EDJLS]\(unit,keyroo)o(t,s)o(tart)o(no,m)o(ax_)o(keys)o
+(,)42 b(>)47 b(keyvals,nfound,status\))0 1977 y Fh(8)81
+b Fi(Get)27 b(the)f(v)-5 b(alue)25 b(of)i(a)f(\015oating)g(p)s(oin)m(t)
+f(k)m(eyw)m(ord,)j(returning)c(the)i(in)m(teger)g(and)g(fractional)f
+(parts)h(of)g(the)g(v)-5 b(alue)227 2090 y(in)31 b(separate)h
+(subroutine)e(argumen)m(ts.)45 b(This)30 b(subroutine)f(ma)m(y)k(b)s(e)
+e(used)g(to)h(read)g(an)m(y)g(k)m(eyw)m(ord)g(but)f(is)227
+2203 y(esp)s(ecially)e(useful)f(for)j(reading)e(the)i('triple)e
+(precision')f(k)m(eyw)m(ords)j(written)f(b)m(y)g(FTPKYT.)382
+2465 y Fe(FTGKYT\(unit,keyword,)42 b(>)48 b(intval,dblval,comment,s)o
+(tat)o(us\))0 2727 y Fh(9)81 b Fi(Get)24 b(the)g(ph)m(ysical)f(units)f
+(string)g(in)h(an)g(existing)g(k)m(eyw)m(ord.)39 b(This)22
+b(routine)h(uses)g(a)h(lo)s(cal)f(con)m(v)m(en)m(tion,)k(sho)m(wn)227
+2840 y(in)32 b(the)i(follo)m(wing)d(example,)j(in)e(whic)m(h)g(the)h(k)
+m(eyw)m(ord)h(units)e(are)h(enclosed)g(in)f(square)h(brac)m(k)m(ets)i
+(in)d(the)227 2953 y(b)s(eginning)g(of)j(the)g(k)m(eyw)m(ord)g(commen)m
+(t)h(\014eld.)52 b(A)35 b(blank)f(string)f(is)h(returned)g(if)f(no)i
+(units)e(are)i(de\014ned)227 3066 y(for)30 b(the)h(k)m(eyw)m(ord.)191
+3328 y Fe(VELOCITY=)809 b(12.3)46 b(/)i([km/s])e(orbital)g(speed)382
+3553 y(FTGUNT\(unit,keyword,)c(>)48 b(units,status\))0
+3846 y Fb(9.4.6)112 b(Mo)s(dify)38 b(Keyw)m(ord)f(Subroutines)0
+4066 y Fi(Wild)30 b(card)h(c)m(haracters,)j(as)e(describ)s(ed)d(in)h
+(the)i(Read)g(Keyw)m(ord)f(section,)h(ab)s(o)m(v)m(e,)h(ma)m(y)g(b)s(e)
+d(used)h(when)g(sp)s(eci-)0 4179 y(fying)e(the)i(name)f(of)h(the)f(k)m
+(eyw)m(ord)h(to)g(b)s(e)f(mo)s(di\014ed.)0 4441 y Fh(1)81
+b Fi(Mo)s(dify)29 b(\(o)m(v)m(erwrite\))i(the)g(n)m(th)f(80-c)m
+(haracter)j(header)d(record)h(in)e(the)h(CHU)382 4702
+y Fe(FTMREC\(unit,key_no,card,)41 b(>)47 b(status\))0
+4964 y Fh(2)81 b Fi(Mo)s(dify)36 b(\(o)m(v)m(erwrite\))j(the)f(80-c)m
+(haracter)j(header)c(record)h(for)f(the)h(named)f(k)m(eyw)m(ord)h(in)f
+(the)h(CHU.)g(This)227 5077 y(can)31 b(b)s(e)f(used)f(to)i(o)m(v)m
+(erwrite)g(the)g(name)f(of)h(the)f(k)m(eyw)m(ord)h(as)g(w)m(ell)e(as)i
+(its)f(v)-5 b(alue)29 b(and)h(commen)m(t)i(\014elds.)382
+5339 y Fe(FTMCRD\(unit,keyword,card)o(,)42 b(>)47 b(status\))0
+5601 y Fh(3)81 b Fi(Mo)s(dify)32 b(\(o)m(v)m(erwrite\))k(the)e(name)g
+(of)h(an)f(existing)f(k)m(eyw)m(ord)h(in)f(the)i(CHU)f(preserving)e
+(the)j(curren)m(t)e(v)-5 b(alue)227 5714 y(and)30 b(commen)m(t)h
+(\014elds.)p eop
+%%Page: 83 89
+83 88 bop 0 299 a Fg(9.4.)72 b(FITS)30 b(HEADER)h(I/O)f(SUBR)m(OUTINES)
+2086 b Fi(83)382 555 y Fe(FTMNAM\(unit,oldkey,keywo)o(rd,)41
+b(>)48 b(status\))0 823 y Fh(4)81 b Fi(Mo)s(dify)29 b(\(o)m(v)m
+(erwrite\))i(the)g(commen)m(t)g(\014eld)e(of)i(an)f(existing)f(k)m(eyw)
+m(ord)i(in)e(the)i(CHU)382 1091 y Fe(FTMCOM\(unit,keyword,comm)o(ent)o
+(,)42 b(>)47 b(status\))0 1358 y Fh(5)81 b Fi(Mo)s(dify)23
+b(the)i(v)-5 b(alue)24 b(and)g(commen)m(t)i(\014elds)d(of)i(an)f
+(existing)g(k)m(eyw)m(ord)h(in)e(the)i(CHU.)g(The)f(FTMKLS)g(subrou-)
+227 1471 y(tine)34 b(w)m(orks)f(the)h(same)h(as)f(the)g(FTMKYS)f
+(subroutine,)g(except)i(it)f(also)f(supp)s(orts)f(long)i(string)f(v)-5
+b(alues)227 1584 y(greater)38 b(than)f(68)h(c)m(haracters)g(in)e
+(length.)59 b(Optionally)-8 b(,)37 b(one)g(ma)m(y)h(mo)s(dify)d(only)h
+(the)h(v)-5 b(alue)36 b(\014eld)g(and)227 1697 y(lea)m(v)m(e)31
+b(the)e(commen)m(t)i(\014eld)d(unc)m(hanged)h(b)m(y)g(setting)g(the)h
+(input)d(COMMENT)i(parameter)h(equal)f(to)h(the)227 1810
+y(amp)s(ersand)f(c)m(haracter)k(\(&\).)42 b(The)30 b(E)g(and)g(D)h(v)m
+(ersions)f(of)h(this)f(routine)f(ha)m(v)m(e)j(the)f(added)f(feature)h
+(that)227 1923 y(if)25 b(the)i('decimals')e(parameter)i(is)e(negativ)m
+(e,)k(then)d(the)g('G')h(displa)m(y)d(format)j(rather)f(then)g(the)g
+('E')h(format)227 2036 y(will)f(b)s(e)i(used)f(when)h(constructing)g
+(the)g(k)m(eyw)m(ord)h(v)-5 b(alue,)29 b(taking)f(the)h(absolute)f(v)-5
+b(alue)28 b(of)g('decimals')g(for)227 2149 y(the)37 b(precision.)58
+b(This)34 b(will)g(suppress)h(trailing)f(zeros,)39 b(and)d(will)e(use)j
+(a)g(\014xed)e(format)i(rather)g(than)f(an)227 2262 y(exp)s(onen)m
+(tial)30 b(format,)h(dep)s(ending)c(on)k(the)f(magnitude)g(of)g(the)h
+(v)-5 b(alue.)382 2530 y Fe(FTMKY[JLS]\(unit,keyword,)o(key)o(val,)o
+(comm)o(ent)o(,)42 b(>)47 b(status\))382 2642 y
+(FTMKLS\(unit,keyword,keyv)o(al,)o(comm)o(ent,)41 b(>)47
+b(status\))382 2755 y(FTMKY[EDFG]\(unit,keyword)o(,ke)o(yval)o(,dec)o
+(ima)o(ls,c)o(omme)o(nt,)41 b(>)48 b(status\))0 3023
+y Fh(6)81 b Fi(Mo)s(dify)21 b(the)h(v)-5 b(alue)22 b(of)g(an)g
+(existing)g(k)m(eyw)m(ord)g(to)h(b)s(e)f(unde\014ned,)g(or)g(n)m(ull.)
+36 b(The)22 b(v)-5 b(alue)21 b(string)h(of)g(the)g(k)m(eyw)m(ord)227
+3136 y(is)29 b(set)i(to)g(blank.)39 b(Optionally)-8 b(,)28
+b(one)i(ma)m(y)h(lea)m(v)m(e)g(the)g(commen)m(t)g(\014eld)d(unc)m
+(hanged)i(b)m(y)g(setting)g(the)g(input)227 3249 y(COMMENT)g(parameter)
+h(equal)f(to)h(the)g(amp)s(ersand)e(c)m(haracter)j(\(&\).)382
+3517 y Fe(FTMKYU\(unit,keyword,comm)o(ent)o(,)42 b(>)47
+b(status\))0 3817 y Fb(9.4.7)112 b(Up)s(date)39 b(Keyw)m(ord)e
+(Subroutines)0 4032 y Fh(1)81 b Fi(Up)s(date)36 b(an)g(80-c)m(haracter)
+j(record)d(in)f(the)i(CHU.)f(If)g(the)g(sp)s(eci\014ed)f(k)m(eyw)m(ord)
+i(already)e(exists)h(then)g(that)227 4144 y(header)j(record)f(will)e(b)
+s(e)i(replaced)h(with)e(the)i(input)e(CARD)h(string.)65
+b(If)38 b(it)h(do)s(es)f(not)h(exist)f(then)h(the)227
+4257 y(new)f(record)g(will)d(b)s(e)i(added)h(to)g(the)g(header.)64
+b(The)37 b(FTUKLS)g(subroutine)f(w)m(orks)i(the)g(same)h(as)f(the)227
+4370 y(FTUKYS)28 b(subroutine,)f(except)j(it)e(also)h(supp)s(orts)d
+(long)i(string)g(v)-5 b(alues)28 b(greater)i(than)e(68)h(c)m(haracters)
+h(in)227 4483 y(length.)382 4751 y Fe(FTUCRD\(unit,keyword,card)o(,)42
+b(>)47 b(status\))0 5019 y Fh(2)81 b Fi(Up)s(date)44
+b(the)i(v)-5 b(alue)44 b(and)h(commen)m(t)h(\014elds)d(of)i(a)h(k)m
+(eyw)m(ord)f(in)f(the)h(CHU.)h(The)e(sp)s(eci\014ed)f(k)m(eyw)m(ord)j
+(is)227 5132 y(mo)s(di\014ed)37 b(if)g(it)h(already)g(exists)g(\(b)m(y)
+h(calling)e(FTMKYx\))i(otherwise)e(a)i(new)f(k)m(eyw)m(ord)h(is)f
+(created)h(b)m(y)227 5245 y(calling)c(FTPKYx.)58 b(The)36
+b(E)g(and)f(D)i(v)m(ersions)e(of)i(this)e(routine)g(ha)m(v)m(e)i(the)g
+(added)e(feature)i(that)g(if)e(the)227 5357 y('decimals')30
+b(parameter)i(is)e(negativ)m(e,)i(then)e(the)h('G')h(displa)m(y)d
+(format)i(rather)g(then)f(the)h('E')g(format)h(will)227
+5470 y(b)s(e)41 b(used)f(when)h(constructing)g(the)g(k)m(eyw)m(ord)h(v)
+-5 b(alue,)44 b(taking)d(the)g(absolute)g(v)-5 b(alue)41
+b(of)h('decimals')e(for)227 5583 y(the)d(precision.)58
+b(This)34 b(will)g(suppress)h(trailing)f(zeros,)39 b(and)d(will)e(use)j
+(a)g(\014xed)e(format)i(rather)g(than)f(an)227 5696 y(exp)s(onen)m
+(tial)30 b(format,)h(dep)s(ending)c(on)k(the)f(magnitude)g(of)g(the)h
+(v)-5 b(alue.)p eop
+%%Page: 84 90
+84 89 bop 0 299 a Fi(84)1319 b Fg(CHAPTER)29 b(9.)112
+b(AD)m(V)-10 b(ANCED)32 b(INTERF)-10 b(A)m(CE)30 b(SUBR)m(OUTINES)382
+555 y Fe(FTUKY[JLS]\(unit,keyword,)o(key)o(val,)o(comm)o(ent)o(,)42
+b(>)47 b(status\))382 668 y(FTUKLS\(unit,keyword,keyv)o(al,)o(comm)o
+(ent,)41 b(>)47 b(status\))382 781 y(FTUKY[EDFG]\(unit,keyword)o(,ke)o
+(yval)o(,dec)o(ima)o(ls,c)o(omme)o(nt,)41 b(>)48 b(status\))0
+1044 y Fh(3)81 b Fi(Up)s(date)23 b(the)g(v)-5 b(alue)23
+b(of)h(an)f(existing)g(k)m(eyw)m(ord)h(to)g(b)s(e)f(unde\014ned,)f(or)i
+(n)m(ull,)f(or)g(insert)g(a)g(new)g(unde\014ned-v)-5
+b(alue)227 1157 y(k)m(eyw)m(ord)30 b(if)e(it)h(do)s(esn't)g(already)g
+(exist.)40 b(The)29 b(v)-5 b(alue)29 b(string)f(of)h(the)h(k)m(eyw)m
+(ord)f(is)g(left)g(blank)f(in)f(this)i(case.)382 1420
+y Fe(FTUKYU\(unit,keyword,comm)o(ent)o(,)42 b(>)47 b(status\))0
+1715 y Fb(9.4.8)112 b(Delete)37 b(Keyw)m(ord)g(Subroutines)0
+1927 y Fh(1)81 b Fi(Delete)31 b(an)f(existing)f(k)m(eyw)m(ord)i
+(record.)40 b(The)30 b(space)h(previously)d(o)s(ccupied)h(b)m(y)h(the)g
+(k)m(eyw)m(ord)h(is)e(reclaimed)227 2040 y(b)m(y)d(mo)m(ving)g(all)f
+(the)h(follo)m(wing)f(header)h(records)g(up)f(one)h(ro)m(w)h(in)d(the)j
+(header.)39 b(The)25 b(\014rst)h(routine)f(deletes)227
+2153 y(a)34 b(k)m(eyw)m(ord)f(at)h(a)g(sp)s(eci\014ed)d(p)s(osition)g
+(in)h(the)h(header)g(\(the)h(\014rst)e(k)m(eyw)m(ord)i(is)e(at)i(p)s
+(osition)d(1\),)k(whereas)227 2266 y(the)d(second)g(routine)f(deletes)h
+(a)g(sp)s(eci\014cally)d(named)i(k)m(eyw)m(ord.)46 b(Wild)30
+b(card)h(c)m(haracters,)j(as)e(describ)s(ed)227 2378
+y(in)e(the)h(Read)g(Keyw)m(ord)f(section,)h(ab)s(o)m(v)m(e,)h(ma)m(y)g
+(b)s(e)e(used)g(when)f(sp)s(ecifying)g(the)i(name)g(of)g(the)f(k)m(eyw)
+m(ord)227 2491 y(to)h(b)s(e)f(deleted)g(\(b)s(e)g(careful!\).)382
+2755 y Fe(FTDREC\(unit,key_no,)42 b(>)48 b(status\))382
+2867 y(FTDKEY\(unit,keyword,)42 b(>)48 b(status\))0 3205
+y Fd(9.5)135 b(Data)46 b(Scaling)g(and)e(Unde\014ned)h(Pixel)h(P)l
+(arameters)0 3456 y Fi(These)24 b(subroutines)e(de\014ne)i(or)h(mo)s
+(dify)d(the)j(in)m(ternal)e(parameters)i(used)f(b)m(y)g(FITSIO)g(to)h
+(either)f(scale)h(the)f(data)0 3569 y(or)33 b(to)i(represen)m(t)e
+(unde\014ned)e(pixels.)48 b(Generally)33 b(FITSIO)f(will)f(scale)i(the)
+h(data)g(according)f(to)h(the)g(v)-5 b(alues)33 b(of)0
+3682 y(the)f(BSCALE)g(and)f(BZER)m(O)h(\(or)h(TSCALn)d(and)i(TZER)m
+(On\))f(k)m(eyw)m(ords,)i(ho)m(w)m(ev)m(er)h(these)e(subroutines)e(ma)m
+(y)0 3795 y(b)s(e)i(used)h(to)h(o)m(v)m(erride)f(the)g(k)m(eyw)m(ord)h
+(v)-5 b(alues.)48 b(This)31 b(ma)m(y)j(b)s(e)f(useful)e(when)h(one)i(w)
+m(an)m(ts)f(to)h(read)f(or)g(write)g(the)0 3908 y(ra)m(w)d(unscaled)e
+(v)-5 b(alues)28 b(in)h(the)g(FITS)g(\014le.)39 b(Similarly)-8
+b(,)27 b(FITSIO)h(generally)h(uses)g(the)g(v)-5 b(alue)29
+b(of)h(the)f(BLANK)h(or)0 4021 y(TNULLn)35 b(k)m(eyw)m(ord)h(to)g
+(signify)d(an)j(unde\014ned)d(pixel,)i(but)g(these)h(routines)f(ma)m(y)
+h(b)s(e)e(used)h(to)h(o)m(v)m(erride)g(this)0 4134 y(v)-5
+b(alue.)40 b(These)30 b(subroutines)e(do)j(not)f(create)i(or)f(mo)s
+(dify)d(the)j(corresp)s(onding)d(header)i(k)m(eyw)m(ord)h(v)-5
+b(alues.)0 4397 y Fh(1)81 b Fi(Reset)26 b(the)g(scaling)e(factors)i(in)
+e(the)i(primary)e(arra)m(y)i(or)f(image)h(extension;)h(do)s(es)e(not)g
+(c)m(hange)i(the)f(BSCALE)227 4510 y(and)i(BZER)m(O)g(k)m(eyw)m(ord)h
+(v)-5 b(alues)27 b(and)h(only)f(a\013ects)j(the)e(automatic)i(scaling)d
+(p)s(erformed)g(when)g(the)h(data)227 4623 y(elemen)m(ts)e(are)g
+(written/read)f(to/from)h(the)g(FITS)f(\014le.)38 b(When)25
+b(reading)g(from)g(a)h(FITS)f(\014le)f(the)i(returned)227
+4736 y(data)i(v)-5 b(alue)27 b(=)g(\(the)h(v)-5 b(alue)27
+b(giv)m(en)h(in)e(the)h(FITS)g(arra)m(y\))h(*)g(BSCALE)f(+)g(BZER)m(O.)
+g(The)g(in)m(v)m(erse)h(form)m(ula)227 4849 y(is)33 b(used)g(when)g
+(writing)f(data)j(v)-5 b(alues)33 b(to)h(the)g(FITS)g(\014le.)50
+b(\(NOTE:)34 b(BSCALE)f(and)g(BZER)m(O)h(m)m(ust)g(b)s(e)227
+4962 y(declared)c(as)h(Double)f(Precision)f(v)-5 b(ariables\).)382
+5225 y Fe(FTPSCL\(unit,bscale,bzero)o(,)42 b(>)47 b(status\))0
+5488 y Fh(2)81 b Fi(Reset)39 b(the)f(scaling)g(parameters)g(for)h(a)f
+(table)g(column;)k(do)s(es)c(not)g(c)m(hange)i(the)e(TSCALn)f(or)h
+(TZER)m(On)227 5601 y(k)m(eyw)m(ord)29 b(v)-5 b(alues)28
+b(and)f(only)h(a\013ects)h(the)g(automatic)g(scaling)e(p)s(erformed)g
+(when)g(the)i(data)g(elemen)m(ts)g(are)227 5714 y(written/read)i
+(to/from)h(the)g(FITS)f(\014le.)43 b(When)31 b(reading)f(from)h(a)h
+(FITS)f(\014le)f(the)i(returned)e(data)i(v)-5 b(alue)p
+eop
+%%Page: 85 91
+85 90 bop 0 299 a Fg(9.6.)72 b(FITS)30 b(PRIMAR)-8 b(Y)31
+b(ARRA)-8 b(Y)31 b(OR)f(IMA)m(GE)h(EXTENSION)e(I/O)i(SUBR)m(OUTINES)589
+b Fi(85)227 555 y(=)40 b(\(the)h(v)-5 b(alue)39 b(giv)m(en)h(in)f(the)h
+(FITS)g(arra)m(y\))g(*)h(TSCAL)e(+)g(TZER)m(O.)h(The)f(in)m(v)m(erse)h
+(form)m(ula)g(is)f(used)227 668 y(when)33 b(writing)f(data)j(v)-5
+b(alues)34 b(to)g(the)h(FITS)e(\014le.)51 b(\(NOTE:)34
+b(TSCAL)f(and)g(TZER)m(O)g(m)m(ust)h(b)s(e)f(declared)227
+781 y(as)e(Double)f(Precision)f(v)-5 b(ariables\).)382
+1041 y Fe(FTTSCL\(unit,colnum,tscal)o(,tz)o(ero,)41 b(>)48
+b(status\))0 1300 y Fh(3)81 b Fi(De\014ne)36 b(the)g(in)m(teger)h(v)-5
+b(alue)35 b(to)i(b)s(e)e(used)h(to)h(signify)d(unde\014ned)g(pixels)g
+(in)h(the)h(primary)e(arra)m(y)j(or)f(image)227 1413
+y(extension.)53 b(This)33 b(is)g(only)h(used)g(if)f(BITPIX)h(=)h(8,)h
+(16,)g(or)f(32.)54 b(This)33 b(do)s(es)h(not)h(create)h(or)e(c)m(hange)
+i(the)227 1526 y(v)-5 b(alue)30 b(of)h(the)f(BLANK)h(k)m(eyw)m(ord)g
+(in)e(the)h(header.)382 1786 y Fe(FTPNUL\(unit,blank,)43
+b(>)k(status\))0 2046 y Fh(4)81 b Fi(De\014ne)36 b(the)g(string)f(to)h
+(b)s(e)f(used)g(to)i(signify)d(unde\014ned)g(pixels)g(in)g(a)i(column)f
+(in)g(an)g(ASCI)s(I)g(table.)57 b(This)227 2158 y(do)s(es)30
+b(not)h(create)h(or)e(c)m(hange)i(the)e(v)-5 b(alue)30
+b(of)h(the)f(TNULLn)g(k)m(eyw)m(ord.)382 2418 y Fe
+(FTSNUL\(unit,colnum,snull)41 b(>)47 b(status\))0 2678
+y Fh(5)81 b Fi(De\014ne)34 b(the)h(v)-5 b(alue)33 b(to)i(b)s(e)f(used)g
+(to)h(signify)d(unde\014ned)g(pixels)h(in)g(an)h(in)m(teger)h(column)e
+(in)g(a)h(binary)f(table)227 2791 y(\(where)c(TF)m(ORMn)f(=)g('B',)i
+('I',)f(or)f('J'\).)i(This)c(do)s(es)j(not)f(create)j(or)d(c)m(hange)i
+(the)e(v)-5 b(alue)28 b(of)h(the)g(TNULLn)227 2904 y(k)m(eyw)m(ord.)382
+3163 y Fe(FTTNUL\(unit,colnum,tnull)41 b(>)47 b(status\))0
+3497 y Fd(9.6)135 b(FITS)44 b(Primary)h(Arra)l(y)g(or)g(IMA)l(GE)g
+(Extension)h(I/O)f(Subroutines)0 3747 y Fi(These)26 b(subroutines)e
+(put)i(or)h(get)g(data)h(v)-5 b(alues)25 b(in)h(the)g(primary)f(data)i
+(arra)m(y)g(\(i.e.,)h(the)f(\014rst)f(HDU)h(in)e(the)i(FITS)0
+3860 y(\014le\))34 b(or)h(an)f(IMA)m(GE)i(extension.)53
+b(The)34 b(data)i(arra)m(y)f(is)e(represen)m(ted)i(as)g(a)g(single)e
+(one-dimensional)g(arra)m(y)i(of)0 3973 y(pixels)f(regardless)i(of)g
+(the)g(actual)g(dimensionalit)m(y)d(of)k(the)f(arra)m(y)-8
+b(,)38 b(and)e(the)g(FPIXEL)g(parameter)g(giv)m(es)h(the)0
+4086 y(p)s(osition)26 b(within)e(this)j(1-D)h(arra)m(y)g(of)g(the)g
+(\014rst)e(pixel)g(to)i(read)g(or)f(write.)39 b(Automatic)28
+b(data)g(t)m(yp)s(e)g(con)m(v)m(ersion)g(is)0 4199 y(p)s(erformed)h
+(for)i(n)m(umeric)f(data)h(\(except)i(for)d(complex)h(data)g(t)m(yp)s
+(es\))h(if)e(the)h(data)g(t)m(yp)s(e)g(of)g(the)g(primary)e(arra)m(y)0
+4312 y(\(de\014ned)f(b)m(y)g(the)h(BITPIX)f(k)m(eyw)m(ord\))h
+(di\013ers)f(from)g(the)g(data)i(t)m(yp)s(e)e(of)h(the)g(arra)m(y)g(in)
+e(the)i(calling)e(subroutine.)0 4425 y(The)41 b(data)i(v)-5
+b(alues)41 b(are)h(also)g(scaled)f(b)m(y)h(the)g(BSCALE)f(and)g(BZER)m
+(O)h(header)f(v)-5 b(alues)41 b(as)h(they)g(are)g(b)s(eing)0
+4538 y(written)31 b(or)h(read)g(from)g(the)g(FITS)g(arra)m(y)-8
+b(.)47 b(The)31 b(ftpscl)h(subroutine)e(MUST)h(b)s(e)h(called)f(to)i
+(de\014ne)e(the)i(scaling)0 4650 y(parameters)h(when)e(writing)g(data)i
+(to)g(the)g(FITS)f(arra)m(y)h(or)f(to)h(o)m(v)m(erride)g(the)g(default)
+e(scaling)h(v)-5 b(alue)33 b(giv)m(en)g(in)0 4763 y(the)e(header)f
+(when)f(reading)h(the)g(FITS)g(arra)m(y)-8 b(.)0 4924
+y(Tw)m(o)41 b(sets)f(of)h(subroutines)d(are)j(pro)m(vided)e(to)i(read)g
+(the)f(data)i(arra)m(y)f(whic)m(h)e(di\013er)g(in)g(the)i(w)m(a)m(y)g
+(unde\014ned)0 5036 y(pixels)33 b(are)j(handled.)54 b(The)35
+b(\014rst)f(set)i(of)g(routines)e(\(FTGPVx\))i(simply)d(return)h(an)h
+(arra)m(y)h(of)g(data)g(elemen)m(ts)0 5149 y(in)31 b(whic)m(h)g
+(unde\014ned)f(pixels)g(are)j(set)f(equal)g(to)h(a)g(v)-5
+b(alue)31 b(sp)s(eci\014ed)g(b)m(y)h(the)g(user)g(in)f(the)h('n)m(ullv)
+-5 b(al')30 b(parameter.)0 5262 y(An)k(additional)f(feature)i(of)f
+(these)h(subroutines)e(is)g(that)j(if)d(the)i(user)f(sets)h(n)m(ullv)-5
+b(al)32 b(=)i(0,)i(then)f(no)f(c)m(hec)m(ks)i(for)0 5375
+y(unde\014ned)d(pixels)h(will)f(b)s(e)h(p)s(erformed,)i(th)m(us)f
+(increasing)f(the)i(sp)s(eed)e(of)i(the)g(program.)55
+b(The)35 b(second)h(set)g(of)0 5488 y(routines)30 b(\(FTGPFx\))j
+(returns)d(the)i(data)g(elemen)m(t)g(arra)m(y)g(and,)f(in)g(addition,)f
+(a)i(logical)f(arra)m(y)h(whic)m(h)e(de\014nes)0 5601
+y(whether)40 b(the)g(corresp)s(onding)e(data)j(pixel)e(is)g
+(unde\014ned.)69 b(The)39 b(latter)i(set)g(of)f(subroutines)e(ma)m(y)j
+(b)s(e)f(more)0 5714 y(con)m(v)m(enien)m(t)32 b(to)h(use)e(in)f(some)h
+(circumstances,)h(ho)m(w)m(ev)m(er,)h(it)e(requires)f(an)h(additional)e
+(arra)m(y)j(of)g(logical)f(v)-5 b(alues)p eop
+%%Page: 86 92
+86 91 bop 0 299 a Fi(86)1319 b Fg(CHAPTER)29 b(9.)112
+b(AD)m(V)-10 b(ANCED)32 b(INTERF)-10 b(A)m(CE)30 b(SUBR)m(OUTINES)0
+555 y Fi(whic)m(h)35 b(can)h(b)s(e)g(un)m(wieldy)d(when)j(w)m(orking)f
+(with)g(large)h(data)h(arra)m(ys.)58 b(Also)36 b(for)g(programmer)g
+(con)m(v)m(enience,)0 668 y(sets)j(of)g(subroutines)e(to)i(directly)f
+(read)g(or)h(write)f(2)h(and)g(3)g(dimensional)d(arra)m(ys)j(ha)m(v)m
+(e)h(b)s(een)e(pro)m(vided,)i(as)0 781 y(w)m(ell)29 b(as)h(a)g(set)g
+(of)g(subroutines)d(to)j(read)g(or)g(write)e(an)m(y)i(con)m(tiguous)g
+(rectangular)g(subset)f(of)h(pixels)e(within)f(the)0
+894 y(n-dimensional)g(arra)m(y)-8 b(.)0 1150 y Fh(1)81
+b Fi(Get)30 b(the)g(data)g(t)m(yp)s(e)f(of)h(the)g(image)f(\(=)h
+(BITPIX)f(v)-5 b(alue\).)40 b(P)m(ossible)28 b(returned)g(v)-5
+b(alues)29 b(are:)41 b(8,)30 b(16,)h(32,)g(-32,)227 1263
+y(or)f(-64)h(corresp)s(onding)d(to)j(unsigned)d(b)m(yte,)j(signed)e
+(2-b)m(yte)i(in)m(teger,)g(signed)e(4-b)m(yte)i(in)m(teger,)g(real,)f
+(and)227 1376 y(double.)227 1525 y(The)c(second)f(subroutine)f(is)h
+(similar)e(to)j(FTGIDT,)h(except)f(that)h(if)e(the)g(image)i(pixel)d(v)
+-5 b(alues)25 b(are)h(scaled,)227 1638 y(with)g(non-default)g(v)-5
+b(alues)26 b(for)h(the)h(BZER)m(O)f(and)f(BSCALE)g(k)m(eyw)m(ords,)j
+(then)e(this)f(routine)g(will)e(return)227 1751 y(the)32
+b('equiv)-5 b(alen)m(t')31 b(data)g(t)m(yp)s(e)h(that)f(is)f(needed)h
+(to)h(store)g(the)f(scaled)g(v)-5 b(alues.)42 b(F)-8
+b(or)32 b(example,)f(if)f(BITPIX)227 1864 y(=)39 b(16)g(and)g(BSCALE)f
+(=)g(0.1)i(then)f(the)g(equiv)-5 b(alen)m(t)38 b(data)h(t)m(yp)s(e)g
+(is)f(\015oating)h(p)s(oin)m(t,)h(and)e(-32)i(will)d(b)s(e)227
+1977 y(returned.)65 b(There)39 b(are)g(2)g(sp)s(ecial)f(cases:)58
+b(if)38 b(the)h(image)g(con)m(tains)g(unsigned)e(2-b)m(yte)j(in)m
+(teger)f(v)-5 b(alues,)227 2090 y(with)39 b(BITPIX)h(=)f(16,)44
+b(BSCALE)39 b(=)h(1,)j(and)c(BZER)m(O)h(=)g(32768,)45
+b(then)39 b(this)g(routine)g(will)f(return)h(a)227 2203
+y(non-standard)26 b(v)-5 b(alue)26 b(of)h(20)h(for)f(the)g(bitpix)e(v)
+-5 b(alue.)39 b(Similarly)23 b(if)i(the)j(image)f(con)m(tains)g
+(unsigned)e(4-b)m(yte)227 2316 y(in)m(tegers,)31 b(then)f(bitpix)e
+(will)g(b)s(e)i(returned)f(with)g(a)i(v)-5 b(alue)30
+b(of)g(40.)382 2571 y Fe(FTGIDT\(unit,)44 b(>)k(bitpix,status\))382
+2684 y(FTGIET\(unit,)c(>)k(bitpix,status\))0 2940 y Fh(2)81
+b Fi(Get)31 b(the)g(dimension)c(\(n)m(um)m(b)s(er)j(of)g(axes)h(=)f
+(NAXIS\))h(of)f(the)h(image)382 3196 y Fe(FTGIDM\(unit,)44
+b(>)k(naxis,status\))0 3452 y Fh(3)81 b Fi(Get)31 b(the)g(size)f(of)g
+(all)g(the)g(dimensions)e(of)i(the)h(image)382 3707 y
+Fe(FTGISZ\(unit,)44 b(maxdim,)i(>)i(naxes,status\))0
+3963 y Fh(4)81 b Fi(Get)35 b(the)f(parameters)g(that)h(de\014ne)e(the)h
+(t)m(yp)s(e)g(and)g(size)f(of)i(the)f(image.)52 b(This)32
+b(routine)h(simply)e(com)m(bines)227 4076 y(calls)f(to)h(the)f(ab)s(o)m
+(v)m(e)i(3)f(routines.)382 4332 y Fe(FTGIPR\(unit,)44
+b(maxdim,)i(>)i(bitpix,)d(naxis,)h(naxes,)h(int)f(*status\))0
+4588 y Fh(5)81 b Fi(Put)30 b(elemen)m(ts)g(in)m(to)h(the)f(data)h(arra)
+m(y)382 4843 y Fe(FTPPR[BIJED]\(unit,group,)o(fpi)o(xel,)o(nele)o(men)o
+(ts,v)o(alue)o(s,)41 b(>)48 b(status\))0 5099 y Fh(6)81
+b Fi(Put)30 b(elemen)m(ts)h(in)m(to)f(the)h(data)g(arra)m(y)-8
+b(,)32 b(substituting)c(the)i(appropriate)g(FITS)g(n)m(ull)e(v)-5
+b(alue)30 b(for)g(all)g(elemen)m(ts)227 5212 y(whic)m(h)d(are)g(equal)h
+(to)g(the)f(v)-5 b(alue)27 b(of)h(NULL)-10 b(V)g(AL.)28
+b(F)-8 b(or)28 b(in)m(teger)g(FITS)f(arra)m(ys,)i(the)e(n)m(ull)f(v)-5
+b(alue)27 b(de\014ned)f(b)m(y)227 5325 y(the)k(previous)e(call)h(to)i
+(FTPNUL)e(will)e(b)s(e)i(substituted;)g(for)g(\015oating)h(p)s(oin)m(t)
+f(FITS)g(arra)m(ys)h(\(BITPIX)f(=)227 5438 y(-32)j(or)e(-64\))i(then)e
+(the)h(sp)s(ecial)e(IEEE)g(NaN)i(\(Not-a-Num)m(b)s(er\))h(v)-5
+b(alue)30 b(will)e(b)s(e)i(substituted.)382 5694 y Fe
+(FTPPN[BIJED]\(unit,group,)o(fpi)o(xel,)o(nele)o(men)o(ts,v)o(alue)o
+(s,n)o(ullv)o(al)42 b(>)47 b(status\))p eop
+%%Page: 87 93
+87 92 bop 0 299 a Fg(9.6.)72 b(FITS)30 b(PRIMAR)-8 b(Y)31
+b(ARRA)-8 b(Y)31 b(OR)f(IMA)m(GE)h(EXTENSION)e(I/O)i(SUBR)m(OUTINES)589
+b Fi(87)0 555 y Fh(7)81 b Fi(Set)30 b(data)h(arra)m(y)g(elemen)m(ts)g
+(as)f(unde\014ned)382 808 y Fe(FTPPRU\(unit,group,fpixel)o(,ne)o(leme)o
+(nts,)41 b(>)47 b(status\))0 1060 y Fh(8)81 b Fi(Get)36
+b(elemen)m(ts)f(from)g(the)g(data)h(arra)m(y)-8 b(.)55
+b(Unde\014ned)34 b(arra)m(y)h(elemen)m(ts)h(will)c(b)s(e)j(returned)f
+(with)f(a)j(v)-5 b(alue)34 b(=)227 1173 y(n)m(ullv)-5
+b(al,)28 b(unless)h(n)m(ullv)-5 b(al)28 b(=)i(0)h(in)e(whic)m(h)g(case)
+i(no)g(c)m(hec)m(ks)g(for)g(unde\014ned)d(pixels)g(will)g(b)s(e)i(p)s
+(erformed.)382 1425 y Fe(FTGPV[BIJED]\(unit,group,)o(fpi)o(xel,)o(nele)
+o(men)o(ts,n)o(ullv)o(al,)41 b(>)48 b(values,anyf,status\))0
+1678 y Fh(9)81 b Fi(Get)32 b(elemen)m(ts)f(and)g(n)m(ull\015ags)e(from)
+i(data)h(arra)m(y)-8 b(.)44 b(An)m(y)32 b(unde\014ned)d(arra)m(y)i
+(elemen)m(ts)h(will)c(ha)m(v)m(e)33 b(the)e(corre-)227
+1791 y(sp)s(onding)d(\015agv)-5 b(als)30 b(elemen)m(t)h(set)g(equal)f
+(to)h(.TR)m(UE.)382 2043 y Fe(FTGPF[BIJED]\(unit,group,)o(fpi)o(xel,)o
+(nele)o(men)o(ts,)41 b(>)48 b(values,flagvals,anyf,sta)o(tus)o(\))0
+2295 y Fh(10)e Fi(Put)30 b(v)-5 b(alues)30 b(in)m(to)g(group)g
+(parameters)382 2548 y Fe(FTPGP[BIJED]\(unit,group,)o(fpa)o(rm,n)o
+(parm)o(,va)o(lues)o(,)42 b(>)47 b(status\))0 2800 y
+Fh(11)f Fi(Get)31 b(v)-5 b(alues)30 b(from)g(group)g(parameters)382
+3053 y Fe(FTGGP[BIJED]\(unit,group,)o(fpa)o(rm,n)o(parm)o(,)42
+b(>)47 b(values,status\))0 3305 y Fi(The)32 b(follo)m(wing)e(4)j
+(subroutines)d(transfer)h(FITS)h(images)g(with)f(2)h(or)g(3)h
+(dimensions)c(to)k(or)f(from)g(a)h(data)f(arra)m(y)0
+3418 y(whic)m(h)g(has)h(b)s(een)g(declared)f(in)g(the)i(calling)e
+(program.)49 b(The)33 b(dimensionalit)m(y)d(of)k(the)f(FITS)g(image)g
+(is)f(passed)0 3531 y(b)m(y)26 b(the)g(naxis1,)g(naxis2,)h(and)e
+(naxis3)h(parameters)g(and)f(the)h(declared)g(dimensions)d(of)j(the)g
+(program)g(arra)m(y)h(are)0 3644 y(passed)k(in)e(the)j(dim1)d(and)i
+(dim2)f(parameters.)43 b(Note)32 b(that)g(the)f(program)g(arra)m(y)g
+(do)s(es)g(not)g(ha)m(v)m(e)i(to)e(ha)m(v)m(e)i(the)0
+3757 y(same)28 b(dimensions)d(as)j(the)g(FITS)e(arra)m(y)-8
+b(,)30 b(but)d(m)m(ust)g(b)s(e)g(at)i(least)e(as)h(big.)39
+b(F)-8 b(or)29 b(example)e(if)f(a)i(FITS)f(image)h(with)0
+3870 y(NAXIS1)j(=)f(NAXIS2)h(=)f(400)i(is)d(read)i(in)m(to)f(a)h
+(program)f(arra)m(y)h(whic)m(h)e(is)h(dimensioned)e(as)i(512)i(x)f(512)
+g(pixels,)0 3983 y(then)d(the)g(image)h(will)c(just)j(\014ll)e(the)j
+(lo)m(w)m(er)f(left)g(corner)g(of)h(the)f(arra)m(y)h(with)e(pixels)f
+(in)h(the)i(range)f(1)h(-)f(400)i(in)d(the)0 4095 y(X)32
+b(an)g(Y)h(directions.)45 b(This)30 b(has)i(the)h(e\013ect)g(of)g
+(taking)f(a)h(con)m(tiguous)f(set)h(of)f(pixel)f(v)-5
+b(alue)32 b(in)e(the)j(FITS)e(arra)m(y)0 4208 y(and)k(writing)e(them)i
+(to)h(a)g(non-con)m(tiguous)f(arra)m(y)g(in)f(program)h(memory)g
+(\(i.e.,)i(there)f(are)f(no)m(w)h(some)f(blank)0 4321
+y(pixels)29 b(around)g(the)h(edge)i(of)e(the)h(image)f(in)f(the)i
+(program)f(arra)m(y\).)0 4574 y Fh(11)46 b Fi(Put)30
+b(2-D)i(image)e(in)m(to)h(the)f(data)h(arra)m(y)382 4826
+y Fe(FTP2D[BIJED]\(unit,group,)o(dim)o(1,na)o(xis1)o(,na)o(xis2)o(,ima)
+o(ge,)41 b(>)48 b(status\))0 5078 y Fh(12)e Fi(Put)30
+b(3-D)i(cub)s(e)d(in)m(to)i(the)f(data)h(arra)m(y)382
+5331 y Fe(FTP3D[BIJED]\(unit,group,)o(dim)o(1,di)o(m2,n)o(axi)o(s1,n)o
+(axis)o(2,n)o(axis)o(3,cu)o(be,)41 b(>)48 b(status\))0
+5583 y Fh(13)e Fi(Get)29 b(2-D)f(image)g(from)g(the)f(data)i(arra)m(y)
+-8 b(.)41 b(Unde\014ned)26 b(pixels)f(in)i(the)h(arra)m(y)g(will)d(b)s
+(e)i(set)h(equal)f(to)i(the)e(v)-5 b(alue)227 5696 y(of)31
+b('n)m(ullv)-5 b(al',)28 b(unless)h(n)m(ullv)-5 b(al=0)28
+b(in)h(whic)m(h)g(case)j(no)e(testing)h(for)f(unde\014ned)e(pixels)g
+(will)g(b)s(e)i(p)s(erformed.)p eop
+%%Page: 88 94
+88 93 bop 0 299 a Fi(88)1319 b Fg(CHAPTER)29 b(9.)112
+b(AD)m(V)-10 b(ANCED)32 b(INTERF)-10 b(A)m(CE)30 b(SUBR)m(OUTINES)382
+555 y Fe(FTG2D[BIJED]\(unit,group,)o(nul)o(lval)o(,dim)o(1,n)o(axis)o
+(1,na)o(xis)o(2,)42 b(>)47 b(image,anyf,status\))0 766
+y Fh(14)f Fi(Get)31 b(3-D)h(cub)s(e)e(from)g(the)g(data)h(arra)m(y)-8
+b(.)42 b(Unde\014ned)29 b(pixels)g(in)g(the)h(arra)m(y)h(will)d(b)s(e)i
+(set)h(equal)f(to)h(the)f(v)-5 b(alue)227 879 y(of)31
+b('n)m(ullv)-5 b(al',)28 b(unless)h(n)m(ullv)-5 b(al=0)28
+b(in)h(whic)m(h)g(case)j(no)e(testing)h(for)f(unde\014ned)e(pixels)g
+(will)g(b)s(e)i(p)s(erformed.)382 1089 y Fe(FTG3D[BIJED]\(unit,group,)o
+(nul)o(lval)o(,dim)o(1,d)o(im2,)o(naxi)o(s1,)o(naxi)o(s2,n)o(axi)o(s3,)
+41 b(>)1002 1202 y(cube,anyf,status\))0 1413 y Fi(The)i(follo)m(wing)e
+(subroutines)g(transfer)i(a)h(rectangular)f(subset)f(of)i(the)f(pixels)
+e(in)h(a)i(FITS)e(N-dimensional)0 1525 y(image)30 b(to)h(or)f(from)f
+(an)h(arra)m(y)g(whic)m(h)f(has)h(b)s(een)f(declared)g(in)g(the)h
+(calling)f(program.)40 b(The)29 b(fpixels)f(and)h(lpixels)0
+1638 y(parameters)e(are)h(in)m(teger)f(arra)m(ys)h(whic)m(h)e(sp)s
+(ecify)f(the)j(starting)f(and)f(ending)g(pixels)f(in)h(eac)m(h)i
+(dimension)c(of)k(the)0 1751 y(FITS)36 b(image)h(that)g(are)g(to)h(b)s
+(e)e(read)g(or)h(written.)59 b(\(Note)38 b(that)g(these)f(are)g(the)g
+(starting)f(and)g(ending)g(pixels)0 1864 y(in)d(the)i(FITS)f(image,)j
+(not)e(in)e(the)i(declared)f(arra)m(y\).)55 b(The)34
+b(arra)m(y)i(parameter)f(is)f(treated)h(simply)e(as)i(a)g(large)0
+1977 y(one-dimensional)28 b(arra)m(y)i(of)h(the)f(appropriate)f(datat)m
+(yp)s(e)i(con)m(taining)f(the)g(pixel)e(v)-5 b(alues;)30
+b(The)f(pixel)g(v)-5 b(alues)29 b(in)0 2090 y(the)d(FITS)f(arra)m(y)i
+(are)f(read/written)f(from/to)i(this)e(program)g(arra)m(y)i(in)d
+(strict)i(sequence)g(without)f(an)m(y)i(gaps;)g(it)0
+2203 y(is)h(up)f(to)j(the)f(calling)e(routine)h(to)h(correctly)g(in)m
+(terpret)f(the)h(dimensionalit)m(y)d(of)j(this)f(arra)m(y)-8
+b(.)41 b(The)28 b(t)m(w)m(o)i(families)0 2316 y(of)d(FITS)g(reading)f
+(routines)g(\(FTGSVx)h(and)g(FTGSFx)g(subroutines\))e(also)j(ha)m(v)m
+(e)g(an)f('incs')g(parameter)g(whic)m(h)0 2429 y(de\014nes)j(the)h
+(data)h(sampling)c(in)m(terv)-5 b(al)30 b(in)g(eac)m(h)i(dimension)c
+(of)j(the)g(FITS)f(arra)m(y)-8 b(.)43 b(F)-8 b(or)32
+b(example,)f(if)f(incs\(1\)=2)0 2542 y(and)j(incs\(2\)=3)g(when)g
+(reading)f(a)i(2-dimensional)d(FITS)i(image,)h(then)f(only)g(ev)m(ery)h
+(other)f(pixel)f(in)g(the)i(\014rst)0 2655 y(dimension)c(and)j(ev)m
+(ery)h(3rd)e(pixel)g(in)g(the)h(second)g(dimension)d(will)h(b)s(e)h
+(returned)g(in)g(the)h('arra)m(y')h(parameter.)0 2767
+y([Note:)39 b(the)25 b(FTGSSx)f(family)g(of)g(routines)g(whic)m(h)g(w)m
+(ere)h(presen)m(t)g(in)e(previous)g(v)m(ersions)h(of)h(FITSIO)f(ha)m(v)
+m(e)i(b)s(een)0 2880 y(sup)s(erseded)i(b)m(y)j(the)f(more)h(general)f
+(FTGSVx)g(family)f(of)i(routines.])0 3091 y Fh(15)46
+b Fi(Put)30 b(an)g(arbitrary)f(data)i(subsection)f(in)m(to)g(the)h
+(data)g(arra)m(y)-8 b(.)382 3301 y Fe(FTPSS[BIJED]\(unit,group,)o(nax)o
+(is,n)o(axes)o(,fp)o(ixel)o(s,lp)o(ixe)o(ls,a)o(rray)o(,)42
+b(>)47 b(status\))0 3512 y Fh(16)f Fi(Get)30 b(an)e(arbitrary)f(data)j
+(subsection)d(from)h(the)h(data)g(arra)m(y)-8 b(.)42
+b(Unde\014ned)27 b(pixels)f(in)i(the)g(arra)m(y)i(will)25
+b(b)s(e)j(set)227 3625 y(equal)j(to)i(the)e(v)-5 b(alue)32
+b(of)f('n)m(ullv)-5 b(al',)30 b(unless)g(n)m(ullv)-5
+b(al=0)30 b(in)g(whic)m(h)g(case)j(no)e(testing)h(for)f(unde\014ned)f
+(pixels)227 3738 y(will)e(b)s(e)i(p)s(erformed.)382 3948
+y Fe(FTGSV[BIJED]\(unit,group,)o(nax)o(is,n)o(axes)o(,fp)o(ixel)o(s,lp)
+o(ixe)o(ls,i)o(ncs,)o(nul)o(lval)o(,)42 b(>)1002 4061
+y(array,anyf,status\))0 4272 y Fh(17)k Fi(Get)34 b(an)f(arbitrary)f
+(data)h(subsection)f(from)h(the)g(data)g(arra)m(y)-8
+b(.)50 b(An)m(y)33 b(Unde\014ned)e(pixels)g(in)h(the)h(arra)m(y)h(will)
+227 4384 y(ha)m(v)m(e)e(the)e(corresp)s(onding)f('\015agv)-5
+b(als')30 b(elemen)m(t)h(set)g(equal)f(to)h(.TR)m(UE.)382
+4595 y Fe(FTGSF[BIJED]\(unit,group,)o(nax)o(is,n)o(axes)o(,fp)o(ixel)o
+(s,lp)o(ixe)o(ls,i)o(ncs,)41 b(>)1002 4708 y(array,flagvals,anyf,statu)
+o(s\))0 5034 y Fd(9.7)135 b(FITS)44 b(ASCI)t(I)g(and)h(Binary)g(T)-11
+b(able)45 b(Data)h(I/O)f(Subroutines)0 5287 y Fb(9.7.1)112
+b(Column)37 b(Information)f(Subroutines)0 5488 y Fh(1)81
+b Fi(Get)30 b(the)g(n)m(um)m(b)s(er)e(of)i(ro)m(ws)g(or)f(columns)f(in)
+h(the)h(curren)m(t)f(FITS)g(table.)40 b(The)29 b(n)m(um)m(b)s(er)f(of)i
+(ro)m(ws)g(is)e(giv)m(en)i(b)m(y)227 5601 y(the)k(NAXIS2)f(k)m(eyw)m
+(ord)h(and)e(the)i(n)m(um)m(b)s(er)e(of)h(columns)f(is)g(giv)m(en)h(b)m
+(y)g(the)h(TFIELDS)e(k)m(eyw)m(ord)i(in)e(the)227 5714
+y(header)e(of)h(the)g(table.)p eop
+%%Page: 89 95
+89 94 bop 0 299 a Fg(9.7.)72 b(FITS)30 b(ASCI)s(I)f(AND)i(BINAR)-8
+b(Y)31 b(T)-8 b(ABLE)31 b(D)m(A)-8 b(T)g(A)32 b(I/O)e(SUBR)m(OUTINES)
+979 b Fi(89)382 555 y Fe(FTGNRW\(unit,)44 b(>)k(nrows,)e(status\))382
+668 y(FTGNCL\(unit,)e(>)k(ncols,)e(status\))0 921 y Fh(2)81
+b Fi(Get)25 b(the)f(table)h(column)e(n)m(um)m(b)s(er)g(\(and)h(name\))h
+(of)f(the)h(column)e(whose)h(name)g(matc)m(hes)i(an)e(input)f(template)
+227 1034 y(name.)38 b(The)21 b(table)h(column)e(names)i(are)g
+(de\014ned)e(b)m(y)i(the)g(TTYPEn)e(k)m(eyw)m(ords)i(in)e(the)i(FITS)f
+(header.)37 b(If)22 b(a)227 1147 y(column)h(do)s(es)h(not)g(ha)m(v)m(e)
+h(a)f(TTYPEn)f(k)m(eyw)m(ord,)j(then)d(these)h(routines)f(assume)h
+(that)g(the)h(name)e(consists)227 1260 y(of)i(all)f(blank)g(c)m
+(haracters.)40 b(These)25 b(2)g(subroutines)d(p)s(erform)i(the)h(same)g
+(function)f(except)i(that)f(FTGCNO)227 1373 y(only)i(returns)f(the)h(n)
+m(um)m(b)s(er)f(of)h(the)g(matc)m(hing)h(column)e(whereas)h(FTGCNN)g
+(also)g(returns)f(the)i(name)f(of)227 1486 y(the)k(column.)39
+b(If)30 b(CASESEN)f(=)h(.true.)41 b(then)30 b(the)h(column)e(name)h
+(matc)m(h)i(will)27 b(b)s(e)j(case-sensitiv)m(e.)227
+1635 y(The)41 b(input)d(column)i(name)h(template)g(\(COL)-8
+b(TEMPLA)g(TE\))41 b(is)f(\(1\))h(either)g(the)g(exact)h(name)f(of)g
+(the)227 1748 y(column)35 b(to)j(b)s(e)d(searc)m(hed)i(for,)h(or)e
+(\(2\))i(it)e(ma)m(y)h(con)m(tain)f(wild)e(cards)i(c)m(haracters)i
+(\(*,)h(?,)f(or)e(#\),)i(or)f(\(3\))227 1861 y(it)c(ma)m(y)h(con)m
+(tain)f(the)g(n)m(um)m(b)s(er)f(of)h(the)g(desired)f(column)g(\(where)h
+(the)g(n)m(um)m(b)s(er)f(is)g(expressed)g(as)h(ASCI)s(I)227
+1974 y(digits\).)39 b(The)28 b(\014rst)g(2)h(wild)d(cards)i(b)s(eha)m
+(v)m(e)h(similarly)c(to)k(UNIX)g(\014lename)f(matc)m(hing:)39
+b(the)29 b('*')g(c)m(haracter)227 2087 y(matc)m(hes)e(an)m(y)g
+(sequence)f(of)h(c)m(haracters)g(\(including)c(zero)k(c)m(haracters\))h
+(and)d(the)i(')10 b(?')39 b(c)m(haracter)28 b(matc)m(hes)227
+2199 y(an)m(y)40 b(single)f(c)m(haracter.)71 b(The)39
+b(#)h(wildcard)d(will)g(matc)m(h)k(an)m(y)f(consecutiv)m(e)h(string)e
+(of)h(decimal)e(digits)227 2312 y(\(0-9\).)45 b(As)31
+b(an)g(example,)g(the)g(template)g(strings)f('AB?DE',)i('AB*E',)h(and)d
+('AB*CDE')j(will)28 b(all)i(matc)m(h)227 2425 y(the)c(string)f
+('ABCDE'.)j(If)d(more)h(than)g(one)g(column)f(name)h(in)f(the)h(table)g
+(matc)m(hes)h(the)f(template)h(string,)227 2538 y(then)33
+b(the)h(\014rst)f(matc)m(h)h(is)e(returned)h(and)f(the)i(status)g(v)-5
+b(alue)33 b(will)d(b)s(e)j(set)h(to)g(237)h(as)f(a)f(w)m(arning)g(that)
+h(a)227 2651 y(unique)f(matc)m(h)j(w)m(as)f(not)g(found.)53
+b(T)-8 b(o)35 b(\014nd)f(the)h(other)g(cases)g(that)h(matc)m(h)g(the)f
+(template,)h(simply)d(call)227 2764 y(the)27 b(subroutine)e(again)i
+(lea)m(ving)g(the)g(input)e(status)i(v)-5 b(alue)27 b(equal)f(to)i(237)
+g(and)f(the)g(next)g(matc)m(hing)g(name)227 2877 y(will)i(then)j(b)s(e)
+f(returned.)43 b(Rep)s(eat)32 b(this)f(pro)s(cess)g(un)m(til)f(a)i
+(status)g(=)g(219)h(\(column)d(name)i(not)g(found\))f(is)227
+2990 y(returned.)40 b(If)30 b(these)h(subroutines)d(fail)h(to)i(matc)m
+(h)g(the)g(template)g(to)g(an)m(y)g(of)f(the)h(columns)e(in)g(the)i
+(table,)227 3103 y(they)i(lastly)e(c)m(hec)m(k)j(if)e(the)g(template)h
+(can)g(b)s(e)e(in)m(terpreted)h(as)h(a)g(simple)d(p)s(ositiv)m(e)h(in)m
+(teger)i(\(e.g.,)i('7',)f(or)227 3216 y('512'\))i(and)d(if)f(so,)j
+(they)f(return)e(that)j(column)d(n)m(um)m(b)s(er.)49
+b(If)33 b(no)g(matc)m(hes)i(are)f(found)e(then)h(a)h(status)g(=)227
+3329 y(219)e(error)e(is)f(returned.)227 3478 y(Note)i(that)e(the)h
+(FITS)e(Standard)g(recommends)g(that)i(only)e(letters,)i(digits,)e(and)
+h(the)g(underscore)f(c)m(har-)227 3591 y(acter)44 b(b)s(e)e(used)g(in)g
+(column)f(names)i(\(with)f(no)g(em)m(b)s(edded)g(spaces)h(in)f(the)h
+(name\).)78 b(T)-8 b(railing)40 b(blank)227 3704 y(c)m(haracters)32
+b(are)f(not)g(signi\014can)m(t.)40 b(It)31 b(is)e(recommended)i(that)g
+(the)g(column)e(names)h(in)g(a)h(giv)m(en)f(table)h(b)s(e)227
+3816 y(unique)e(within)f(the)i(\014rst)g(8)h(c)m(haracters.)382
+4070 y Fe(FTGCNO\(unit,casesen,colt)o(emp)o(late)o(,)42
+b(>)47 b(colnum,status\))382 4182 y(FTGCNN\(unit,casesen,colt)o(emp)o
+(late)o(,)42 b(>)47 b(colname,colnum,status\))0 4436
+y Fh(3)81 b Fi(Get)39 b(the)g(datat)m(yp)s(e)h(of)e(a)h(column)f(in)f
+(an)h(ASCI)s(I)g(or)g(binary)f(table.)65 b(This)37 b(routine)h(returns)
+f(an)i(in)m(teger)227 4549 y(co)s(de)34 b(v)-5 b(alue)32
+b(corresp)s(onding)f(to)j(the)g(datat)m(yp)s(e)g(of)f(the)g(column.)48
+b(\(See)34 b(the)f(FTBNFM)i(and)d(FT)-8 b(ASFM)227 4661
+y(subroutines)26 b(in)h(the)h(Utilities)f(section)h(of)g(this)f(do)s
+(cumen)m(t)h(for)g(a)h(list)e(of)h(the)h(co)s(de)f(v)-5
+b(alues\).)40 b(The)27 b(v)m(ector)227 4774 y(rep)s(eat)38
+b(coun)m(t)g(\(whic)m(h)f(is)g(alw)m(a)m(y)h(1)g(for)g(ASCI)s(I)e
+(table)h(columns\))g(is)g(also)g(returned.)62 b(If)37
+b(the)h(sp)s(eci\014ed)227 4887 y(column)31 b(has)g(an)g(ASCI)s(I)f(c)m
+(haracter)j(datat)m(yp)s(e)g(\(co)s(de)f(=)f(16\))i(then)e(the)h(width)
+d(of)j(a)g(unit)e(string)h(in)f(the)227 5000 y(column)i(is)g(also)h
+(returned.)48 b(Note)34 b(that)g(this)d(routine)h(supp)s(orts)g(the)h
+(lo)s(cal)f(con)m(v)m(en)m(tion)i(for)f(sp)s(ecifying)227
+5113 y(arra)m(ys)f(of)f(strings)f(within)e(a)k(binary)d(table)i(c)m
+(haracter)h(column,)f(using)e(the)i(syn)m(tax)h(TF)m(ORM)f(=)g('rAw')
+227 5226 y(where)f('r')g(is)g(the)g(total)h(n)m(um)m(b)s(er)e(of)i(c)m
+(haracters)g(\(=)g(the)f(width)f(of)h(the)g(column\))g(and)g('w')g(is)f
+(the)i(width)227 5339 y(of)39 b(a)f(unit)f(string)g(within)f(the)i
+(column.)63 b(Th)m(us)37 b(if)g(the)h(column)f(has)h(TF)m(ORM)h(=)f
+('60A12')i(then)e(this)227 5452 y(routine)30 b(will)d(return)j(dataco)s
+(de)h(=)f(16,)h(rep)s(eat)g(=)f(60,)i(and)d(width)g(=)h(12.)227
+5601 y(The)h(second)h(routine,)f(FTEQTY)g(is)f(similar)f(except)k(that)
+f(in)e(the)i(case)g(of)g(scaled)f(in)m(teger)h(columns)e(it)227
+5714 y(returns)23 b(the)h('equiv)-5 b(alen)m(t')23 b(data)h(t)m(yp)s(e)
+g(that)h(is)d(needed)i(to)g(store)g(the)g(scaled)f(v)-5
+b(alues,)25 b(and)e(not)h(necessarily)p eop
+%%Page: 90 96
+90 95 bop 0 299 a Fi(90)1319 b Fg(CHAPTER)29 b(9.)112
+b(AD)m(V)-10 b(ANCED)32 b(INTERF)-10 b(A)m(CE)30 b(SUBR)m(OUTINES)227
+555 y Fi(the)38 b(ph)m(ysical)f(data)h(t)m(yp)s(e)g(of)g(the)g
+(unscaled)f(v)-5 b(alues)37 b(as)h(stored)g(in)f(the)h(FITS)f(table.)63
+b(F)-8 b(or)38 b(example)g(if)227 668 y(a)d('1I')g(column)e(in)g(a)h
+(binary)f(table)h(has)g(TSCALn)f(=)g(1)i(and)f(TZER)m(On)f(=)g(32768,)
+38 b(then)c(this)f(column)227 781 y(e\013ectiv)m(ely)25
+b(con)m(tains)f(unsigned)e(short)h(in)m(teger)i(v)-5
+b(alues,)24 b(and)g(th)m(us)f(the)h(returned)f(v)-5 b(alue)23
+b(of)h(t)m(yp)s(eco)s(de)h(will)227 894 y(b)s(e)32 b(the)h(co)s(de)g
+(for)g(an)f(unsigned)f(short)h(in)m(teger,)i(not)f(a)g(signed)f(short)g
+(in)m(teger.)48 b(Similarly)-8 b(,)30 b(if)i(a)h(column)227
+1007 y(has)d(TTYPEn)g(=)g('1I')h(and)f(TSCALn)e(=)i(0.12,)j(then)d(the)
+g(returned)g(t)m(yp)s(eco)s(de)g(will)e(b)s(e)i(the)h(co)s(de)f(for)h
+(a)227 1120 y('real')g(column.)382 1382 y Fe(FTGTCL\(unit,colnum,)42
+b(>)48 b(datacode,repeat,width,st)o(atu)o(s\))382 1495
+y(FTEQTY\(unit,colnum,)42 b(>)48 b(datacode,repeat,width,st)o(atu)o
+(s\))0 1758 y Fh(4)81 b Fi(Return)22 b(the)i(displa)m(y)e(width)g(of)h
+(a)h(column.)38 b(This)21 b(is)i(the)h(length)f(of)g(the)h(string)f
+(that)h(will)d(b)s(e)i(returned)f(when)227 1871 y(reading)32
+b(the)h(column)f(as)h(a)g(formatted)g(string.)47 b(The)32
+b(displa)m(y)f(width)g(is)h(determined)g(b)m(y)g(the)h(TDISPn)227
+1984 y(k)m(eyw)m(ord,)e(if)f(presen)m(t,)g(otherwise)g(b)m(y)g(the)h
+(data)g(t)m(yp)s(e)g(of)f(the)h(column.)382 2246 y Fe(FTGCDW\(unit,)44
+b(colnum,)i(>)i(dispwidth,)d(status\))0 2509 y Fh(5)81
+b Fi(Get)29 b(information)d(ab)s(out)i(an)g(existing)f(ASCI)s(I)g
+(table)h(column.)39 b(\(NOTE:)28 b(TSCAL)f(and)g(TZER)m(O)h(m)m(ust)g
+(b)s(e)227 2622 y(declared)i(as)h(Double)f(Precision)f(v)-5
+b(ariables\).)39 b(All)29 b(the)i(returned)e(parameters)i(are)f(scalar)
+h(quan)m(tities.)382 2884 y Fe(FTGACL\(unit,colnum,)42
+b(>)716 2997 y(ttype,tbcol,tunit,tform,)o(tsca)o(l,t)o(zero)o(,snu)o
+(ll,)o(tdis)o(p,st)o(atu)o(s\))0 3259 y Fh(6)81 b Fi(Get)29
+b(information)d(ab)s(out)h(an)h(existing)f(binary)f(table)i(column.)39
+b(\(NOTE:)28 b(TSCAL)e(and)i(TZER)m(O)f(m)m(ust)h(b)s(e)227
+3372 y(declared)i(as)g(Double)f(Precision)g(v)-5 b(ariables\).)39
+b(D)m(A)-8 b(T)g(A)g(TYPE)32 b(is)d(a)h(c)m(haracter)i(string)c(whic)m
+(h)h(returns)g(the)227 3485 y(datat)m(yp)s(e)35 b(of)g(the)f(column)f
+(as)h(de\014ned)f(b)m(y)h(the)g(TF)m(ORMn)g(k)m(eyw)m(ord)h(\(e.g.,)i
+('I',)e('J','E',)g('D',)g(etc.\).)54 b(In)227 3598 y(the)27
+b(case)g(of)g(an)f(ASCI)s(I)f(c)m(haracter)j(column,)e(D)m(A)-8
+b(T)g(A)g(TYPE)29 b(will)23 b(ha)m(v)m(e)28 b(a)f(v)-5
+b(alue)26 b(of)g(the)h(form)f('An')g(where)227 3711 y('n')34
+b(is)f(an)h(in)m(teger)h(expressing)e(the)h(width)e(of)i(the)h(\014eld)
+d(in)h(c)m(haracters.)53 b(F)-8 b(or)35 b(example,)g(if)e(TF)m(ORM)h(=)
+227 3824 y('160A8')39 b(then)e(FTGBCL)f(will)e(return)i(D)m(A)-8
+b(T)g(A)g(TYPE='A8')39 b(and)d(REPEA)-8 b(T=20.)60 b(All)35
+b(the)i(returned)227 3937 y(parameters)31 b(are)g(scalar)f(quan)m
+(tities.)382 4199 y Fe(FTGBCL\(unit,colnum,)42 b(>)716
+4312 y(ttype,tunit,datatype,rep)o(eat,)o(tsc)o(al,t)o(zero)o(,tn)o
+(ull,)o(tdis)o(p,s)o(tatu)o(s\))0 4575 y Fh(7)81 b Fi(Put)31
+b(\(app)s(end\))g(a)i(TDIMn)f(k)m(eyw)m(ord)g(whose)g(v)-5
+b(alue)32 b(has)g(the)g(form)g('\(l,m,n...\)')46 b(where)32
+b(l,)g(m,)g(n...)46 b(are)33 b(the)227 4688 y(dimensions)28
+b(of)i(a)h(m)m(ultidimension)c(arra)m(y)j(column)g(in)f(a)h(binary)f
+(table.)382 4950 y Fe(FTPTDM\(unit,colnum,naxis)o(,na)o(xes,)41
+b(>)48 b(status\))0 5213 y Fh(8)81 b Fi(Return)29 b(the)h(n)m(um)m(b)s
+(er)e(of)i(and)g(size)f(of)h(the)g(dimensions)e(of)i(a)g(table)g
+(column.)39 b(Normally)29 b(this)g(information)227 5326
+y(is)h(giv)m(en)h(b)m(y)g(the)g(TDIMn)f(k)m(eyw)m(ord,)i(but)e(if)g
+(this)g(k)m(eyw)m(ord)h(is)f(not)h(presen)m(t)g(then)g(this)e(routine)h
+(returns)227 5439 y(NAXIS)g(=)g(1)h(and)f(NAXES\(1\))h(equal)f(to)h
+(the)g(rep)s(eat)g(coun)m(t)g(in)e(the)h(TF)m(ORM)h(k)m(eyw)m(ord.)382
+5701 y Fe(FTGTDM\(unit,colnum,maxdi)o(m,)41 b(>)48 b
+(naxis,naxes,status\))p eop
+%%Page: 91 97
+91 96 bop 0 299 a Fg(9.7.)72 b(FITS)30 b(ASCI)s(I)f(AND)i(BINAR)-8
+b(Y)31 b(T)-8 b(ABLE)31 b(D)m(A)-8 b(T)g(A)32 b(I/O)e(SUBR)m(OUTINES)
+979 b Fi(91)0 555 y Fh(9)81 b Fi(Deco)s(de)33 b(the)g(input)e(TDIMn)i
+(k)m(eyw)m(ord)g(string)e(\(e.g.)50 b('\(100,200\)'\))37
+b(and)32 b(return)g(the)h(n)m(um)m(b)s(er)e(of)i(and)f(size)227
+668 y(of)c(the)g(dimensions)d(of)j(a)g(binary)e(table)h(column.)39
+b(If)27 b(the)h(input)e(tdimstr)g(c)m(haracter)j(string)e(is)g(n)m
+(ull,)f(then)227 781 y(this)e(routine)f(returns)g(naxis)g(=)i(1)f(and)g
+(naxes[0])i(equal)d(to)j(the)e(rep)s(eat)h(coun)m(t)g(in)e(the)h(TF)m
+(ORM)h(k)m(eyw)m(ord.)227 894 y(This)k(routine)g(is)h(called)f(b)m(y)h
+(FTGTDM.)382 1147 y Fe(FTDTDM\(unit,tdimstr,coln)o(um,)o(maxd)o(im,)41
+b(>)48 b(naxis,naxes,)c(status\))0 1400 y Fh(10)i Fi(Return)32
+b(the)h(optimal)f(n)m(um)m(b)s(er)g(of)h(ro)m(ws)g(to)h(read)f(or)g
+(write)f(at)i(one)f(time)g(for)f(maxim)m(um)g(I/O)h(e\016ciency)-8
+b(.)227 1513 y(Refer)31 b(to)g(the)g(\\Optimizing)d(Co)s(de")i(section)
+h(in)e(Chapter)h(5)g(for)h(more)f(discussion)e(on)i(ho)m(w)h(to)g(use)f
+(this)227 1626 y(routine.)382 1879 y Fe(FFGRSZ\(unit,)44
+b(>)k(nrows,status\))0 2169 y Fb(9.7.2)112 b(Lo)m(w-Lev)m(el)38
+b(T)-9 b(able)37 b(Access)g(Subroutines)0 2388 y Fi(The)d(follo)m(wing)
+e(subroutines)g(pro)m(vide)i(lo)m(w-lev)m(el)g(access)h(to)g(the)g
+(data)g(in)e(ASCI)s(I)f(or)i(binary)f(tables)h(and)g(are)0
+2501 y(mainly)27 b(useful)g(as)j(an)f(e\016cien)m(t)g(w)m(a)m(y)h(to)g
+(cop)m(y)g(all)e(or)h(part)g(of)g(a)g(table)g(from)g(one)g(lo)s(cation)
+g(to)h(another.)40 b(These)0 2614 y(routines)23 b(simply)f(read)i(or)h
+(write)e(the)i(sp)s(eci\014ed)d(n)m(um)m(b)s(er)h(of)i(consecutiv)m(e)g
+(b)m(ytes)g(in)e(an)h(ASCI)s(I)f(or)h(binary)f(table,)0
+2727 y(without)36 b(regard)h(for)f(column)g(b)s(oundaries)e(or)j(the)g
+(ro)m(w)g(length)g(in)e(the)i(table.)60 b(The)37 b(\014rst)f(t)m(w)m(o)
+i(subroutines)0 2840 y(read)29 b(or)h(write)f(consecutiv)m(e)h(b)m
+(ytes)g(in)e(a)i(table)f(to)i(or)e(from)g(a)h(c)m(haracter)h(string)d
+(v)-5 b(ariable,)29 b(while)f(the)h(last)h(t)m(w)m(o)0
+2953 y(subroutines)f(read)j(or)g(write)f(consecutiv)m(e)h(b)m(ytes)h
+(to)f(or)g(from)f(a)h(v)-5 b(ariable)31 b(declared)g(as)h(a)g(n)m
+(umeric)e(data)j(t)m(yp)s(e)0 3065 y(\(e.g.,)40 b(INTEGER,)d
+(INTEGER*2,)i(REAL,)d(DOUBLE)h(PRECISION\).)f(These)g(routines)g(do)g
+(not)h(p)s(erform)0 3178 y(an)m(y)c(mac)m(hine)f(dep)s(enden)m(t)g
+(data)i(con)m(v)m(ersion)f(or)f(b)m(yte)i(sw)m(apping,)e(except)i(that)
+f(con)m(v)m(ersion)g(to/from)g(ASCI)s(I)0 3291 y(format)d(is)f(p)s
+(erformed)f(b)m(y)h(the)h(FTGTBS)f(and)g(FTPTBS)g(routines)g(on)g(mac)m
+(hines)g(whic)m(h)g(do)g(not)h(use)f(ASCI)s(I)0 3404
+y(c)m(haracter)j(co)s(des)e(in)f(the)i(in)m(ternal)e(data)i(represen)m
+(tations)g(\(e.g.,)h(on)e(IBM)h(mainframe)e(computers\).)0
+3657 y Fh(1)81 b Fi(Read)26 b(a)h(consecutiv)m(e)g(string)f(of)g(c)m
+(haracters)i(from)e(an)g(ASCI)s(I)f(table)h(in)m(to)h(a)f(c)m(haracter)
+i(v)-5 b(ariable)26 b(\(spanning)227 3770 y(columns)31
+b(and)h(m)m(ultiple)e(ro)m(ws)i(if)f(necessary\))i(This)e(routine)g
+(should)f(not)j(b)s(e)e(used)h(with)f(binary)f(tables)227
+3883 y(b)s(ecause)h(of)f(complications)f(related)i(to)g(passing)e
+(string)g(v)-5 b(ariables)29 b(b)s(et)m(w)m(een)i(C)f(and)g(F)-8
+b(ortran.)382 4136 y Fe(FTGTBS\(unit,frow,startch)o(ar,)o(ncha)o(rs,)41
+b(>)48 b(string,status\))0 4390 y Fh(2)81 b Fi(W)-8 b(rite)30
+b(a)h(consecutiv)m(e)g(string)e(of)i(c)m(haracters)g(to)g(an)f(ASCI)s
+(I)f(table)h(from)g(a)h(c)m(haracter)h(v)-5 b(ariable)29
+b(\(spanning)227 4503 y(columns)i(and)h(m)m(ultiple)e(ro)m(ws)i(if)f
+(necessary\))i(This)e(routine)g(should)f(not)j(b)s(e)e(used)h(with)f
+(binary)f(tables)227 4615 y(b)s(ecause)h(of)f(complications)f(related)i
+(to)g(passing)e(string)g(v)-5 b(ariables)29 b(b)s(et)m(w)m(een)i(C)f
+(and)g(F)-8 b(ortran.)382 4869 y Fe(FTPTBS\(unit,frow,startch)o(ar,)o
+(ncha)o(rs,s)o(tri)o(ng,)41 b(>)48 b(status\))0 5122
+y Fh(3)81 b Fi(Read)27 b(a)h(consecutiv)m(e)h(arra)m(y)f(of)g(b)m(ytes)
+g(from)f(an)g(ASCI)s(I)f(or)i(binary)d(table)j(in)m(to)f(a)h(n)m
+(umeric)f(v)-5 b(ariable)26 b(\(span-)227 5235 y(ning)31
+b(columns)f(and)i(m)m(ultiple)d(ro)m(ws)j(if)f(necessary\).)46
+b(The)32 b(arra)m(y)g(parameter)g(ma)m(y)h(b)s(e)e(declared)g(as)i(an)m
+(y)227 5348 y(n)m(umerical)g(datat)m(yp)s(e)i(as)g(long)f(as)h(the)f
+(arra)m(y)h(is)e(at)i(least)g('nc)m(hars')g(b)m(ytes)f(long,)i(e.g.,)g
+(if)e(nc)m(hars)g(=)g(17,)227 5461 y(then)c(declare)h(the)f(arra)m(y)h
+(as)g(INTEGER*4)g(ARRA)-8 b(Y\(5\).)382 5714 y Fe
+(FTGTBB\(unit,frow,startch)o(ar,)o(ncha)o(rs,)41 b(>)48
+b(array,status\))p eop
+%%Page: 92 98
+92 97 bop 0 299 a Fi(92)1319 b Fg(CHAPTER)29 b(9.)112
+b(AD)m(V)-10 b(ANCED)32 b(INTERF)-10 b(A)m(CE)30 b(SUBR)m(OUTINES)0
+555 y Fh(4)81 b Fi(W)-8 b(rite)31 b(a)g(consecutiv)m(e)h(arra)m(y)g(of)
+f(b)m(ytes)g(to)h(an)e(ASCI)s(I)g(or)h(binary)e(table)i(from)f(a)i(n)m
+(umeric)d(v)-5 b(ariable)30 b(\(span-)227 668 y(ning)k(columns)f(and)h
+(m)m(ultiple)e(ro)m(ws)j(if)e(necessary\))j(The)e(arra)m(y)h(parameter)
+g(ma)m(y)h(b)s(e)e(declared)g(as)h(an)m(y)227 781 y(n)m(umerical)e
+(datat)m(yp)s(e)i(as)g(long)f(as)h(the)f(arra)m(y)h(is)e(at)i(least)g
+('nc)m(hars')g(b)m(ytes)f(long,)i(e.g.,)g(if)e(nc)m(hars)g(=)g(17,)227
+894 y(then)c(declare)h(the)f(arra)m(y)h(as)g(INTEGER*4)g(ARRA)-8
+b(Y\(5\).)382 1161 y Fe(FTPTBB\(unit,frow,startch)o(ar,)o(ncha)o(rs,a)o
+(rra)o(y,)42 b(>)47 b(status\))0 1461 y Fb(9.7.3)112
+b(Edit)36 b(Ro)m(ws)h(or)h(Columns)0 1676 y Fh(1)81 b
+Fi(Insert)26 b(blank)g(ro)m(ws)i(in)m(to)f(an)g(existing)f(ASCI)s(I)g
+(or)h(binary)f(table)h(\(in)g(the)g(CDU\).)h(All)e(the)i(ro)m(ws)f(F)m
+(OLLO)m(W-)227 1789 y(ING)32 b(ro)m(w)f(FR)m(O)m(W)i(are)e(shifted)f
+(do)m(wn)h(b)m(y)g(NR)m(O)m(WS)h(ro)m(ws.)43 b(If)31
+b(FR)m(O)m(W)i(=)d(0)i(then)f(the)g(blank)f(ro)m(ws)i(are)227
+1902 y(inserted)e(at)i(the)f(b)s(eginning)e(of)i(the)g(table.)43
+b(This)29 b(routine)h(mo)s(di\014es)f(the)j(NAXIS2)f(k)m(eyw)m(ord)h
+(to)f(re\015ect)227 2015 y(the)g(new)f(n)m(um)m(b)s(er)f(of)h(ro)m(ws)h
+(in)e(the)h(table.)382 2282 y Fe(FTIROW\(unit,frow,nrows,)41
+b(>)48 b(status\))0 2550 y Fh(2)81 b Fi(Delete)26 b(ro)m(ws)g(from)f
+(an)g(existing)g(ASCI)s(I)f(or)h(binary)f(table)h(\(in)g(the)h(CDU\).)g
+(The)f(NR)m(O)m(WS)h(n)m(um)m(b)s(er)e(of)i(ro)m(ws)227
+2663 y(are)k(deleted,)g(starting)f(with)g(ro)m(w)g(FR)m(O)m(W,)j(and)d
+(an)m(y)h(remaining)d(ro)m(ws)j(in)e(the)i(table)f(are)h(shifted)f(up)f
+(to)227 2775 y(\014ll)35 b(in)h(the)h(space.)61 b(This)35
+b(routine)h(mo)s(di\014es)f(the)j(NAXIS2)f(k)m(eyw)m(ord)g(to)h
+(re\015ect)f(the)h(new)e(n)m(um)m(b)s(er)g(of)227 2888
+y(ro)m(ws)31 b(in)e(the)h(table.)382 3156 y Fe
+(FTDROW\(unit,frow,nrows,)41 b(>)48 b(status\))0 3423
+y Fh(3)81 b Fi(Delete)25 b(a)g(list)e(of)i(ro)m(ws)f(from)g(an)h(ASCI)s
+(I)e(or)h(binary)f(table)h(\(in)g(the)g(CDU\).)i(In)e(the)g(\014rst)g
+(routine,)h('ro)m(wrange')227 3536 y(is)i(a)h(c)m(haracter)h(string)e
+(listing)f(the)i(ro)m(ws)f(or)h(ro)m(w)g(ranges)g(to)g(delete)g
+(\(e.g.,)j('2-4,)e(5,)g(8-9'\).)42 b(In)27 b(the)h(second)227
+3649 y(routine,)36 b('ro)m(wlist')e(is)g(an)g(in)m(teger)i(arra)m(y)f
+(of)g(ro)m(w)g(n)m(um)m(b)s(ers)e(to)j(b)s(e)e(deleted)h(from)f(the)h
+(table.)55 b(nro)m(ws)34 b(is)227 3762 y(the)e(n)m(um)m(b)s(er)e(of)h
+(ro)m(w)h(n)m(um)m(b)s(ers)e(in)g(the)h(list.)43 b(The)31
+b(\014rst)f(ro)m(w)i(in)e(the)h(table)h(is)e(1)i(not)f(0.)44
+b(The)31 b(list)f(of)i(ro)m(w)227 3875 y(n)m(um)m(b)s(ers)d(m)m(ust)h
+(b)s(e)g(sorted)h(in)e(ascending)g(order.)382 4142 y
+Fe(FTDRRG\(unit,rowrange,)42 b(>)47 b(status\))382 4255
+y(FTDRWS\(unit,rowlist,nrow)o(s,)41 b(>)48 b(status\))0
+4523 y Fh(4)81 b Fi(Insert)43 b(a)i(blank)e(column)h(\(or)g(columns\))g
+(in)m(to)g(an)g(existing)g(ASCI)s(I)f(or)h(binary)f(table)h(\(in)g(the)
+g(CDU\).)227 4636 y(COLNUM)c(sp)s(eci\014es)f(the)i(column)e(n)m(um)m
+(b)s(er)g(that)i(the)f(\(\014rst\))g(new)g(column)f(should)f(o)s(ccup)m
+(y)j(in)e(the)227 4749 y(table.)57 b(NCOLS)34 b(sp)s(eci\014es)g(ho)m
+(w)i(man)m(y)g(columns)e(are)i(to)g(b)s(e)f(inserted.)56
+b(An)m(y)35 b(existing)g(columns)f(from)227 4862 y(this)k(p)s(osition)e
+(and)i(higher)f(are)i(mo)m(v)m(ed)g(o)m(v)m(er)h(to)f(allo)m(w)f(ro)s
+(om)g(for)h(the)f(new)g(column\(s\).)64 b(The)38 b(index)227
+4975 y(n)m(um)m(b)s(er)j(on)h(all)f(the)h(follo)m(wing)e(k)m(eyw)m
+(ords)j(will)c(b)s(e)i(incremen)m(ted)h(if)f(necessary)h(to)h
+(re\015ect)f(the)g(new)227 5087 y(p)s(osition)30 b(of)h(the)g
+(column\(s\))g(in)f(the)h(table:)42 b(TBCOLn,)30 b(TF)m(ORMn,)i
+(TTYPEn,)e(TUNITn,)h(TNULLn,)227 5200 y(TSCALn,)22 b(TZER)m(On,)g
+(TDISPn,)g(TDIMn,)h(TLMINn,)g(TLMAXn,)f(TDMINn,)i(TDMAXn,)f(TCTYPn,)227
+5313 y(TCRPXn,)30 b(TCR)-10 b(VLn,)29 b(TCDL)-8 b(Tn,)30
+b(TCR)m(OTn,)f(and)g(TCUNIn.)382 5581 y Fe(FTICOL\(unit,colnum,ttype)o
+(,tf)o(orm,)41 b(>)48 b(status\))382 5694 y(FTICLS\(unit,colnum,ncols)o
+(,tt)o(ype,)o(tfor)o(m,)41 b(>)48 b(status\))p eop
+%%Page: 93 99
+93 98 bop 0 299 a Fg(9.7.)72 b(FITS)30 b(ASCI)s(I)f(AND)i(BINAR)-8
+b(Y)31 b(T)-8 b(ABLE)31 b(D)m(A)-8 b(T)g(A)32 b(I/O)e(SUBR)m(OUTINES)
+979 b Fi(93)0 555 y Fh(5)81 b Fi(Mo)s(dify)36 b(the)h(v)m(ector)i
+(length)e(of)g(a)h(binary)d(table)i(column)f(\(e.g.,)41
+b(c)m(hange)e(a)e(column)f(from)h(TF)m(ORMn)g(=)227 668
+y('1E')31 b(to)h('20E'\).)g(The)e(v)m(ector)i(length)d(ma)m(y)i(b)s(e)f
+(increased)g(or)g(decreased)h(from)f(the)g(curren)m(t)h(v)-5
+b(alue.)382 924 y Fe(FTMVEC\(unit,colnum,newve)o(cle)o(n,)42
+b(>)47 b(status\))0 1180 y Fh(6)81 b Fi(Delete)28 b(a)g(column)f(from)g
+(an)g(existing)g(ASCI)s(I)f(or)i(binary)d(table)j(\(in)f(the)g(CDU\).)i
+(The)e(index)f(n)m(um)m(b)s(er)g(of)i(all)227 1293 y(the)k(k)m(eyw)m
+(ords)h(listed)d(ab)s(o)m(v)m(e)k(\(for)e(FTICOL\))f(will)e(b)s(e)j
+(decremen)m(ted)g(if)f(necessary)i(to)g(re\015ect)f(the)g(new)227
+1406 y(p)s(osition)24 b(of)i(the)g(column\(s\))f(in)f(the)i(table.)39
+b(Those)26 b(index)e(k)m(eyw)m(ords)i(that)g(refer)f(to)i(the)f
+(deleted)f(column)227 1519 y(will)30 b(also)i(b)s(e)g(deleted.)46
+b(Note)33 b(that)g(the)g(ph)m(ysical)e(size)h(of)g(the)h(FITS)e(\014le)
+h(will)d(not)k(b)s(e)e(reduced)h(b)m(y)g(this)227 1632
+y(op)s(eration,)d(and)f(the)h(empt)m(y)g(FITS)f(blo)s(c)m(ks)g(if)g(an)
+m(y)h(at)g(the)g(end)f(of)h(the)g(\014le)f(will)e(b)s(e)i(padded)g
+(with)f(zeros.)382 1888 y Fe(FTDCOL\(unit,colnum,)42
+b(>)48 b(status\))0 2144 y Fh(7)81 b Fi(Cop)m(y)30 b(a)g(column)f(from)
+h(one)g(HDU)h(to)g(another)f(\(or)h(to)g(the)f(same)h(HDU\).)g(If)f
+(createcol)i(=)d(TR)m(UE,)i(then)f(a)227 2257 y(new)20
+b(column)f(will)f(b)s(e)i(inserted)f(in)g(the)i(output)f(table,)j(at)e
+(p)s(osition)d(`outcolumn',)k(otherwise)e(the)h(existing)227
+2370 y(output)29 b(column)e(will)f(b)s(e)i(o)m(v)m(erwritten)h(\(in)f
+(whic)m(h)f(case)j(it)e(m)m(ust)g(ha)m(v)m(e)i(a)f(compatible)f(datat)m
+(yp)s(e\).)42 b(Note)227 2483 y(that)31 b(the)g(\014rst)e(column)h(in)f
+(a)h(table)h(is)e(at)i(coln)m(um)f(=)g(1.)382 2739 y
+Fe(FTCPCL\(inunit,outunit,in)o(col)o(num,)o(outc)o(oln)o(um,c)o(reat)o
+(eco)o(l,)42 b(>)47 b(status\);)0 3029 y Fb(9.7.4)112
+b(Read)38 b(and)h(W)-9 b(rite)35 b(Column)i(Data)g(Routines)0
+3248 y Fi(These)22 b(subroutines)e(put)i(or)g(get)i(data)f(v)-5
+b(alues)21 b(in)g(the)i(curren)m(t)f(ASCI)s(I)f(or)h(Binary)f(table)i
+(extension.)37 b(Automatic)0 3361 y(data)21 b(t)m(yp)s(e)g(con)m(v)m
+(ersion)f(is)f(p)s(erformed)g(for)h(n)m(umerical)f(data)i(t)m(yp)s(es)g
+(\(B,I,J,E,D\))h(if)d(the)i(data)g(t)m(yp)s(e)f(of)h(the)f(column)0
+3474 y(\(de\014ned)32 b(b)m(y)i(the)f(TF)m(ORM)h(k)m(eyw)m(ord\))g
+(di\013ers)e(from)g(the)i(data)g(t)m(yp)s(e)f(of)h(the)f(calling)f
+(subroutine.)47 b(The)33 b(data)0 3587 y(v)-5 b(alues)29
+b(are)i(also)f(scaled)f(b)m(y)h(the)g(TSCALn)f(and)g(TZER)m(On)g
+(header)h(v)-5 b(alues)29 b(as)h(they)g(are)h(b)s(eing)d(written)h(to)i
+(or)0 3700 y(read)j(from)f(the)h(FITS)f(arra)m(y)-8 b(.)51
+b(The)33 b(fttscl)h(subroutine)d(MUST)j(b)s(e)f(used)g(to)h(de\014ne)f
+(the)h(scaling)f(parameters)0 3813 y(when)f(writing)f(data)j(to)g(the)f
+(table)g(or)g(to)h(o)m(v)m(erride)f(the)h(default)e(scaling)g(v)-5
+b(alues)33 b(giv)m(en)g(in)f(the)h(header)g(when)0 3926
+y(reading)c(from)h(the)h(table.)0 4086 y(In)h(the)i(case)g(of)f(binary)
+f(tables)h(with)f(v)m(ector)i(elemen)m(ts,)h(the)e('felem')g(parameter)
+h(de\014nes)e(the)i(starting)f(pixel)0 4199 y(within)j(the)i(elemen)m
+(t)h(v)m(ector.)65 b(This)37 b(parameter)h(is)f(ignored)h(with)e(ASCI)s
+(I)h(tables.)64 b(Similarly)-8 b(,)37 b(in)g(the)h(case)0
+4312 y(of)45 b(binary)d(tables)i(the)h('nelemen)m(ts')g(parameter)g(sp)
+s(eci\014es)e(the)h(total)h(n)m(um)m(b)s(er)e(of)i(v)m(ector)h(v)-5
+b(alues)44 b(read)g(or)0 4425 y(written)35 b(\(con)m(tin)m(uing)g(on)h
+(subsequen)m(t)f(ro)m(ws)g(if)g(required\))f(and)i(not)g(the)g(n)m(um)m
+(b)s(er)e(of)i(table)g(elemen)m(ts.)57 b(Tw)m(o)0 4538
+y(sets)36 b(of)f(subroutines)f(are)h(pro)m(vided)f(to)j(get)f(the)g
+(column)e(data)i(whic)m(h)e(di\013er)g(in)h(the)g(w)m(a)m(y)i
+(unde\014ned)c(pixels)0 4650 y(are)f(handled.)41 b(The)31
+b(\014rst)g(set)h(of)f(routines)g(\(FTGCV\))h(simply)d(return)h(an)h
+(arra)m(y)h(of)f(data)h(elemen)m(ts)g(in)e(whic)m(h)0
+4763 y(unde\014ned)41 b(pixels)h(are)i(set)g(equal)f(to)i(a)f(v)-5
+b(alue)43 b(sp)s(eci\014ed)f(b)m(y)h(the)h(user)f(in)f(the)i('n)m(ullv)
+-5 b(al')41 b(parameter.)81 b(An)0 4876 y(additional)41
+b(feature)j(of)g(these)g(subroutines)d(is)i(that)h(if)e(the)i(user)e
+(sets)i(n)m(ullv)-5 b(al)41 b(=)i(0,)48 b(then)43 b(no)g(c)m(hec)m(ks)i
+(for)0 4989 y(unde\014ned)33 b(pixels)h(will)f(b)s(e)h(p)s(erformed,)i
+(th)m(us)f(increasing)f(the)i(sp)s(eed)e(of)i(the)g(program.)55
+b(The)35 b(second)h(set)g(of)0 5102 y(routines)g(\(FTGCF\))i(returns)d
+(the)i(data)h(elemen)m(t)f(arra)m(y)h(and)e(in)g(addition)f(a)i
+(logical)g(arra)m(y)g(of)g(\015ags)g(whic)m(h)0 5215
+y(de\014nes)29 b(whether)h(the)h(corresp)s(onding)d(data)j(pixel)e(is)g
+(unde\014ned.)0 5375 y(An)m(y)41 b(column,)h(regardless)e(of)h(it's)f
+(in)m(trinsic)e(datat)m(yp)s(e,)45 b(ma)m(y)c(b)s(e)f(read)h(as)g(a)g
+(string.)70 b(It)41 b(should)e(b)s(e)h(noted)0 5488 y(ho)m(w)m(ev)m(er)
+32 b(that)f(reading)e(a)i(n)m(umeric)e(column)g(as)i(a)f(string)g(is)f
+(10)i(-)g(100)g(times)f(slo)m(w)m(er)h(than)f(reading)f(the)i(same)0
+5601 y(column)f(as)i(a)g(n)m(um)m(b)s(er)e(due)h(to)h(the)g(large)g(o)m
+(v)m(erhead)g(in)f(constructing)g(the)h(formatted)g(strings.)43
+b(The)31 b(displa)m(y)0 5714 y(format)26 b(of)g(the)h(returned)d
+(strings)h(will)e(b)s(e)j(determined)e(b)m(y)i(the)g(TDISPn)f(k)m(eyw)m
+(ord,)j(if)c(it)i(exists,)h(otherwise)e(b)m(y)p eop
+%%Page: 94 100
+94 99 bop 0 299 a Fi(94)1319 b Fg(CHAPTER)29 b(9.)112
+b(AD)m(V)-10 b(ANCED)32 b(INTERF)-10 b(A)m(CE)30 b(SUBR)m(OUTINES)0
+555 y Fi(the)e(datat)m(yp)s(e)h(of)g(the)f(column.)39
+b(The)28 b(length)f(of)i(the)f(returned)f(strings)g(can)h(b)s(e)g
+(determined)f(with)f(the)j(ftgcdw)0 668 y(routine.)40
+b(The)30 b(follo)m(wing)e(TDISPn)i(displa)m(y)e(formats)j(are)f(curren)
+m(tly)g(supp)s(orted:)191 923 y Fe(Iw.m)142 b(Integer)191
+1036 y(Ow.m)g(Octal)46 b(integer)191 1149 y(Zw.m)142
+b(Hexadecimal)45 b(integer)191 1262 y(Fw.d)142 b(Fixed)46
+b(floating)g(point)191 1375 y(Ew.d)142 b(Exponential)45
+b(floating)g(point)191 1488 y(Dw.d)142 b(Exponential)45
+b(floating)g(point)191 1600 y(Gw.d)142 b(General;)46
+b(uses)g(Fw.d)h(if)g(significance)d(not)j(lost,)g(else)f(Ew.d)0
+1855 y Fi(where)37 b(w)h(is)f(the)h(width)e(in)h(c)m(haracters)i(of)f
+(the)h(displa)m(y)m(ed)d(v)-5 b(alues,)40 b(m)d(is)g(the)h(minim)m(um)e
+(n)m(um)m(b)s(er)g(of)i(digits)0 1968 y(displa)m(y)m(ed,)29
+b(and)h(d)g(is)f(the)i(n)m(um)m(b)s(er)e(of)h(digits)f(to)i(the)g(righ)
+m(t)f(of)h(the)f(decimal.)40 b(The)30 b(.m)g(\014eld)f(is)g(optional.)0
+2223 y Fh(1)81 b Fi(Put)30 b(elemen)m(ts)h(in)m(to)g(an)f(ASCI)s(I)f
+(or)i(binary)e(table)i(column)e(\(in)h(the)h(CDU\).)g(\(The)g(SPP)f
+(FSPCLS)f(routine)227 2336 y(has)38 b(an)f(additional)f(in)m(teger)i
+(argumen)m(t)g(after)h(the)f(V)-10 b(ALUES)37 b(c)m(haracter)i(string)e
+(whic)m(h)f(sp)s(eci\014es)h(the)227 2449 y(size)30 b(of)h(the)g(1st)g
+(dimension)c(of)k(this)e(2-D)j(CHAR)e(arra)m(y\).)382
+2704 y Fe(FTPCL[SLBIJEDCM]\(unit,co)o(lnu)o(m,fr)o(ow,f)o(ele)o(m,ne)o
+(leme)o(nts)o(,val)o(ues,)41 b(>)47 b(status\))0 2959
+y Fh(2)81 b Fi(Put)29 b(elemen)m(ts)h(in)m(to)g(an)g(ASCI)s(I)e(or)i
+(binary)e(table)i(column)e(\(in)h(the)h(CDU\))g(substituting)e(the)i
+(appropriate)227 3072 y(FITS)i(n)m(ull)e(v)-5 b(alue)31
+b(for)h(an)m(y)h(elemen)m(ts)f(that)h(are)f(equal)g(to)h(NULL)-10
+b(V)g(AL.)32 b(This)e(family)h(of)h(routines)f(m)m(ust)227
+3185 y(NOT)h(b)s(e)g(used)f(to)i(write)f(to)h(v)-5 b(ariable)31
+b(length)g(arra)m(y)i(columns.)45 b(F)-8 b(or)33 b(ASCI)s(I)e(T)-8
+b(ABLE)32 b(extensions,)h(the)227 3298 y(n)m(ull)39 b(v)-5
+b(alue)41 b(de\014ned)f(b)m(y)h(the)g(previous)f(call)g(to)i(FTSNUL)e
+(will)f(b)s(e)h(substituted;)45 b(F)-8 b(or)42 b(in)m(teger)g(FITS)227
+3410 y(columns,)c(in)e(a)i(binary)e(table)h(the)g(n)m(ull)f(v)-5
+b(alue)36 b(de\014ned)h(b)m(y)g(the)g(previous)f(call)h(to)h(FTTNUL)f
+(will)e(b)s(e)227 3523 y(substituted;)27 b(F)-8 b(or)28
+b(\015oating)g(p)s(oin)m(t)e(FITS)g(columns)g(a)i(sp)s(ecial)e(IEEE)h
+(NaN)h(\(Not-a-Num)m(b)s(er\))h(v)-5 b(alue)27 b(will)227
+3636 y(b)s(e)j(substituted.)382 3891 y Fe(FTPCN[BIJED]\(unit,colnum)o
+(,fr)o(ow,f)o(elem)o(,ne)o(leme)o(nts,)o(val)o(ues,)o(null)o(val)41
+b(>)48 b(status\))0 4146 y Fh(3)81 b Fi(Put)37 b(bit)g(v)-5
+b(alues)37 b(in)m(to)h(a)g(binary)e(b)m(yte)i(\('B'\))i(or)d(bit)g
+(\('X'\))i(table)f(column)f(\(in)f(the)i(CDU\).)h(LRA)-8
+b(Y)38 b(is)f(an)227 4259 y(arra)m(y)d(of)g(logical)e(v)-5
+b(alues)33 b(corresp)s(onding)e(to)j(the)g(sequence)f(of)h(bits)e(to)i
+(b)s(e)f(written.)48 b(If)33 b(LRA)-8 b(Y)34 b(is)e(true)227
+4372 y(then)g(the)g(corresp)s(onding)e(bit)h(is)g(set)h(to)h(1,)g
+(otherwise)e(the)h(bit)f(is)g(set)i(to)g(0.)45 b(Note)34
+b(that)e(in)f(the)h(case)h(of)227 4485 y('X')g(columns,)f(FITSIO)f
+(will)f(write)h(to)i(all)e(8)i(bits)e(of)h(eac)m(h)i(b)m(yte)f(whether)
+e(they)i(are)g(formally)d(v)-5 b(alid)31 b(or)227 4598
+y(not.)46 b(Th)m(us)31 b(if)g(the)h(column)f(is)f(de\014ned)h(as)h
+('4X',)i(and)d(one)h(calls)f(FTPCLX)h(with)e(fbit=1)h(and)g(n)m(bit=8,)
+227 4711 y(then)j(all)f(8)h(bits)f(will)e(b)s(e)i(written)g(in)m(to)h
+(the)g(\014rst)g(b)m(yte)g(\(as)h(opp)s(osed)e(to)i(writing)c(the)k
+(\014rst)e(4)h(bits)f(in)m(to)227 4824 y(the)e(\014rst)f(ro)m(w)g(and)g
+(then)g(the)h(next)f(4)h(bits)e(in)m(to)i(the)f(next)h(ro)m(w\),)g(ev)m
+(en)g(though)f(the)h(last)f(4)h(bits)e(of)i(eac)m(h)227
+4937 y(b)m(yte)g(are)g(formally)e(not)i(de\014ned.)382
+5191 y Fe(FTPCLX\(unit,colnum,frow,)o(fbi)o(t,nb)o(it,l)o(ray)o(,)42
+b(>)47 b(status\))0 5446 y Fh(4)81 b Fi(Set)30 b(table)g(elemen)m(ts)h
+(in)e(a)i(column)e(as)i(unde\014ned)382 5701 y Fe
+(FTPCLU\(unit,colnum,frow,)o(fel)o(em,n)o(elem)o(ent)o(s,)42
+b(>)47 b(status\))p eop
+%%Page: 95 101
+95 100 bop 0 299 a Fg(9.7.)72 b(FITS)30 b(ASCI)s(I)f(AND)i(BINAR)-8
+b(Y)31 b(T)-8 b(ABLE)31 b(D)m(A)-8 b(T)g(A)32 b(I/O)e(SUBR)m(OUTINES)
+979 b Fi(95)0 555 y Fh(5)81 b Fi(Get)34 b(elemen)m(ts)f(from)g(an)g
+(ASCI)s(I)f(or)h(binary)f(table)h(column)f(\(in)g(the)h(CDU\).)i(These)
+e(routines)f(return)g(the)227 668 y(v)-5 b(alues)29 b(of)h(the)g(table)
+g(column)f(arra)m(y)h(elemen)m(ts.)41 b(Unde\014ned)28
+b(arra)m(y)j(elemen)m(ts)f(will)d(b)s(e)i(returned)g(with)g(a)227
+781 y(v)-5 b(alue)25 b(=)h(n)m(ullv)-5 b(al,)24 b(unless)g(n)m(ullv)-5
+b(al)23 b(=)i(0)h(\(or)g(=)f(')h(')g(for)f(ftgcvs\))i(in)d(whic)m(h)g
+(case)j(no)e(c)m(hec)m(king)i(for)e(unde\014ned)227 894
+y(v)-5 b(alues)27 b(will)e(b)s(e)i(p)s(erformed.)39 b(The)27
+b(ANYF)h(parameter)g(is)f(set)h(to)g(true)g(if)f(an)m(y)g(of)h(the)g
+(returned)f(elemen)m(ts)227 1007 y(are)f(unde\014ned.)37
+b(\(Note:)i(the)26 b(ftgcl)f(routine)f(simple)f(gets)j(an)g(arra)m(y)f
+(of)g(logical)g(data)h(v)-5 b(alues)24 b(without)h(an)m(y)227
+1120 y(c)m(hec)m(ks)39 b(for)e(unde\014ned)e(v)-5 b(alues;)40
+b(use)d(the)g(ftgc\015)h(routine)e(to)i(c)m(hec)m(k)g(for)f
+(unde\014ned)e(logical)i(elemen)m(ts\).)227 1233 y(\(The)29
+b(SPP)f(FSGCVS)g(routine)f(has)i(an)f(additional)f(in)m(teger)i
+(argumen)m(t)g(after)g(the)g(V)-10 b(ALUES)28 b(c)m(haracter)227
+1346 y(string)i(whic)m(h)f(sp)s(eci\014es)g(the)h(size)h(of)f(the)h
+(1st)g(dimension)c(of)k(this)e(2-D)j(CHAR)e(arra)m(y\).)382
+1595 y Fe(FTGCL\(unit,colnum,frow,f)o(ele)o(m,ne)o(leme)o(nts)o(,)42
+b(>)47 b(values,status\))382 1708 y(FTGCV[SBIJEDCM]\(unit,col)o(num)o
+(,fro)o(w,fe)o(lem)o(,nel)o(emen)o(ts,)o(null)o(val,)41
+b(>)1098 1821 y(values,anyf,status\))0 2071 y Fh(6)81
+b Fi(Get)44 b(elemen)m(ts)g(and)e(n)m(ull)g(\015ags)h(from)g(an)h(ASCI)
+s(I)d(or)j(binary)d(table)j(column)e(\(in)g(the)i(CHDU\).)g(These)227
+2184 y(routines)28 b(return)f(the)i(v)-5 b(alues)28 b(of)h(the)g(table)
+g(column)e(arra)m(y)j(elemen)m(ts.)40 b(An)m(y)29 b(unde\014ned)d(arra)
+m(y)k(elemen)m(ts)227 2297 y(will)k(ha)m(v)m(e)k(the)f(corresp)s
+(onding)e(\015agv)-5 b(als)36 b(elemen)m(t)i(set)f(equal)f(to)i(.TR)m
+(UE.)f(The)f(ANYF)i(parameter)f(is)227 2409 y(set)30
+b(to)g(true)g(if)e(an)m(y)i(of)f(the)h(returned)e(elemen)m(ts)i(are)g
+(unde\014ned.)38 b(\(The)29 b(SPP)f(FSGCFS)h(routine)g(has)g(an)227
+2522 y(additional)24 b(in)m(teger)j(argumen)m(t)f(after)h(the)f(V)-10
+b(ALUES)26 b(c)m(haracter)i(string)d(whic)m(h)f(sp)s(eci\014es)h(the)i
+(size)e(of)i(the)227 2635 y(1st)k(dimension)d(of)j(this)e(2-D)i(CHAR)g
+(arra)m(y\).)382 2885 y Fe(FTGCF[SLBIJEDCM]\(unit,co)o(lnu)o(m,fr)o
+(ow,f)o(ele)o(m,ne)o(leme)o(nts)o(,)42 b(>)1193 2998
+y(values,flagvals,anyf,stat)o(us\))0 3247 y Fh(7)81 b
+Fi(Get)29 b(an)f(arbitrary)f(data)i(subsection)e(from)h(an)g
+(N-dimensional)e(arra)m(y)j(in)e(a)h(binary)f(table)h(v)m(ector)i
+(column.)227 3360 y(Unde\014ned)k(pixels)f(in)h(the)i(arra)m(y)g(will)c
+(b)s(e)j(set)h(equal)e(to)i(the)g(v)-5 b(alue)35 b(of)g('n)m(ullv)-5
+b(al',)35 b(unless)e(n)m(ullv)-5 b(al=0)33 b(in)227 3473
+y(whic)m(h)f(case)j(no)e(testing)h(for)f(unde\014ned)e(pixels)h(will)e
+(b)s(e)j(p)s(erformed.)49 b(The)32 b(\014rst)h(and)g(last)g(ro)m(ws)h
+(in)e(the)227 3586 y(table)27 b(to)g(b)s(e)f(read)g(are)h(sp)s
+(eci\014ed)d(b)m(y)j(fpixels\(naxis+1\))d(and)i(lpixels\(naxis+1\),)f
+(and)h(hence)g(are)h(treated)227 3699 y(as)f(the)f(next)h(higher)e
+(dimension)f(of)i(the)h(FITS)e(N-dimensional)f(arra)m(y)-8
+b(.)40 b(The)25 b(INCS)f(parameter)i(sp)s(eci\014es)227
+3812 y(the)31 b(sampling)d(in)m(terv)-5 b(al)30 b(in)f(eac)m(h)i
+(dimension)d(b)s(et)m(w)m(een)j(the)g(data)g(elemen)m(ts)f(that)h(will)
+d(b)s(e)i(returned.)382 4062 y Fe(FTGSV[BIJED]\(unit,colnum)o(,na)o
+(xis,)o(naxe)o(s,f)o(pixe)o(ls,l)o(pix)o(els,)o(incs)o(,nu)o(llva)o(l,)
+42 b(>)1002 4175 y(array,anyf,status\))0 4424 y Fh(8)81
+b Fi(Get)29 b(an)f(arbitrary)f(data)i(subsection)e(from)h(an)g
+(N-dimensional)e(arra)m(y)j(in)e(a)h(binary)f(table)h(v)m(ector)i
+(column.)227 4537 y(An)m(y)39 b(Unde\014ned)e(pixels)g(in)h(the)h(arra)
+m(y)g(will)d(ha)m(v)m(e)k(the)f(corresp)s(onding)e('\015agv)-5
+b(als')39 b(elemen)m(t)g(set)g(equal)227 4650 y(to)d(.TR)m(UE.)f(The)f
+(\014rst)g(and)g(last)h(ro)m(ws)g(in)e(the)i(table)g(to)g(b)s(e)g(read)
+f(are)h(sp)s(eci\014ed)e(b)m(y)i(fpixels\(naxis+1\))227
+4763 y(and)k(lpixels\(naxis+1\),)g(and)f(hence)i(are)f(treated)i(as)e
+(the)g(next)h(higher)e(dimension)e(of)k(the)f(FITS)g(N-)227
+4876 y(dimensional)d(arra)m(y)-8 b(.)66 b(The)38 b(INCS)g(parameter)h
+(sp)s(eci\014es)e(the)h(sampling)f(in)m(terv)-5 b(al)38
+b(in)f(eac)m(h)j(dimension)227 4989 y(b)s(et)m(w)m(een)31
+b(the)g(data)g(elemen)m(ts)g(that)g(will)c(b)s(e)j(returned.)382
+5238 y Fe(FTGSF[BIJED]\(unit,colnum)o(,na)o(xis,)o(naxe)o(s,f)o(pixe)o
+(ls,l)o(pix)o(els,)o(incs)o(,)42 b(>)1002 5351 y
+(array,flagvals,anyf,statu)o(s\))0 5601 y Fh(9)81 b Fi(Get)33
+b(bit)f(v)-5 b(alues)33 b(from)f(a)h(b)m(yte)h(\('B'\))g(or)f(bit)f
+(\(`X`\))i(table)f(column)f(\(in)g(the)h(CDU\).)g(LRA)-8
+b(Y)34 b(is)e(an)g(arra)m(y)i(of)227 5714 y(logical)k(v)-5
+b(alues)38 b(corresp)s(onding)f(to)i(the)g(sequence)f(of)h(bits)f(to)h
+(b)s(e)f(read.)65 b(If)38 b(LRA)-8 b(Y)39 b(is)e(true)i(then)f(the)p
+eop
+%%Page: 96 102
+96 101 bop 0 299 a Fi(96)1319 b Fg(CHAPTER)29 b(9.)112
+b(AD)m(V)-10 b(ANCED)32 b(INTERF)-10 b(A)m(CE)30 b(SUBR)m(OUTINES)227
+555 y Fi(corresp)s(onding)j(bit)g(w)m(as)h(set)h(to)g(1,)h(otherwise)e
+(the)g(bit)g(w)m(as)g(set)h(to)g(0.)53 b(Note)35 b(that)g(in)e(the)i
+(case)g(of)f('X')227 668 y(columns,)40 b(FITSIO)e(will)e(read)i(all)g
+(8)h(bits)f(of)h(eac)m(h)h(b)m(yte)f(whether)f(they)h(are)g(formally)f
+(v)-5 b(alid)37 b(or)h(not.)227 781 y(Th)m(us)c(if)f(the)i(column)e(is)
+g(de\014ned)g(as)i('4X',)h(and)d(one)i(calls)f(FTGCX)g(with)f(fbit=1)h
+(and)f(n)m(bit=8,)i(then)227 894 y(all)28 b(8)i(bits)e(will)e(b)s(e)j
+(read)g(from)g(the)g(\014rst)f(b)m(yte)i(\(as)g(opp)s(osed)e(to)i
+(reading)e(the)i(\014rst)e(4)i(bits)e(from)g(the)i(\014rst)227
+1007 y(ro)m(w)g(and)e(then)h(the)h(\014rst)e(4)i(bits)e(from)h(the)g
+(next)g(ro)m(w\),)i(ev)m(en)f(though)f(the)g(last)g(4)h(bits)e(of)h
+(eac)m(h)i(b)m(yte)f(are)227 1120 y(formally)f(not)i(de\014ned.)382
+1385 y Fe(FTGCX\(unit,colnum,frow,f)o(bit)o(,nbi)o(t,)42
+b(>)47 b(lray,status\))0 1650 y Fh(10)f Fi(Read)31 b(an)m(y)g
+(consecutiv)m(e)g(set)g(of)g(bits)f(from)g(an)g('X')i(or)e('B')i
+(column)d(and)h(in)m(terpret)g(them)h(as)g(an)f(unsigned)227
+1763 y(n-bit)j(in)m(teger.)53 b(NBIT)35 b(m)m(ust)f(b)s(e)f(less)h
+(than)g(or)g(equal)g(to)h(16)g(when)f(calling)e(FTGCXI,)j(and)f(less)f
+(than)227 1876 y(or)f(equal)f(to)h(32)g(when)e(calling)g(FTGCXJ;)i
+(there)f(is)g(no)g(limit)e(on)j(the)f(v)-5 b(alue)31
+b(of)h(NBIT)f(for)g(FTGCXD,)227 1989 y(but)38 b(the)h(returned)e
+(double)h(precision)e(v)-5 b(alue)38 b(only)g(has)g(48)i(bits)d(of)i
+(precision)e(on)h(most)h(32-bit)g(w)m(ord)227 2102 y(mac)m(hines.)63
+b(The)37 b(NBITS)g(bits)g(are)h(in)m(terpreted)f(as)h(an)g(unsigned)d
+(in)m(teger)k(unless)d(NBITS)h(=)g(16)i(\(in)227 2215
+y(FTGCXI\))e(or)g(32)g(\(in)f(FTGCXJ\))g(in)f(whic)m(h)h(case)h(the)g
+(string)f(of)g(bits)g(are)h(in)m(terpreted)e(as)i(16-bit)g(or)227
+2328 y(32-bit)j(2's)g(complemen)m(t)g(signed)e(in)m(tegers.)68
+b(If)39 b(NR)m(O)m(WS)i(is)d(greater)j(than)e(1)h(then)f(the)h(same)g
+(set)g(of)227 2441 y(bits)33 b(will)e(b)s(e)i(read)h(from)f(sequen)m
+(tial)g(ro)m(ws)h(in)e(the)i(table)f(starting)h(with)e(ro)m(w)i(FR)m(O)
+m(W.)h(Note)g(that)g(the)227 2554 y(n)m(um)m(b)s(ering)26
+b(con)m(v)m(en)m(tion)j(used)e(here)g(for)h(the)g(FBIT)f(parameter)i
+(adopts)e(1)h(for)g(the)g(\014rst)f(elemen)m(t)h(of)g(the)227
+2667 y(v)m(ector)k(of)f(bits;)e(this)h(is)f(the)i(Most)g(Signi\014can)m
+(t)e(Bit)h(of)h(the)f(in)m(teger)h(v)-5 b(alue.)382 2932
+y Fe(FTGCX[IJD]\(unit,colnum,f)o(row)o(,nro)o(ws,f)o(bit)o(,nbi)o(t,)42
+b(>)47 b(array,status\))0 3197 y Fh(11)f Fi(Get)37 b(the)e(descriptor)g
+(for)g(a)h(v)-5 b(ariable)35 b(length)g(column)f(in)g(a)i(binary)e
+(table.)56 b(The)35 b(descriptor)g(consists)g(of)227
+3310 y(2)d(in)m(teger)f(parameters:)42 b(the)31 b(n)m(um)m(b)s(er)f(of)
+h(elemen)m(ts)h(in)d(the)i(arra)m(y)h(and)e(the)h(starting)g(o\013set)h
+(relativ)m(e)f(to)227 3423 y(the)d(start)f(of)g(the)h(heap.)39
+b(The)27 b(\014rst)f(routine)g(returns)g(a)h(single)f(descriptor)g
+(whereas)h(the)g(second)g(routine)227 3536 y(returns)i(the)i
+(descriptors)e(for)h(a)h(range)g(of)f(ro)m(ws)h(in)e(the)h(table.)382
+3801 y Fe(FTGDES\(unit,colnum,rownu)o(m,)41 b(>)48 b
+(nelements,offset,status\))382 3914 y(FFGDESSunit,colnum,first)o(row)o
+(,nro)o(ws)42 b(>)47 b(nelements,offset,)c(status\))0
+4179 y Fh(12)j Fi(Put)29 b(the)g(descriptor)f(for)h(a)h(v)-5
+b(ariable)28 b(length)h(column)f(in)g(a)h(binary)f(table.)40
+b(This)27 b(subroutine)h(can)h(b)s(e)g(used)227 4292
+y(in)23 b(conjunction)h(with)f(FTGDES)h(to)h(enable)f(2)h(or)f(more)g
+(arra)m(ys)h(to)g(p)s(oin)m(t)e(to)i(the)g(same)g(storage)g(lo)s
+(cation)227 4405 y(to)31 b(sa)m(v)m(e)h(storage)g(space)f(if)e(the)i
+(arra)m(ys)g(are)g(iden)m(tical.)382 4671 y Fe
+(FTPDES\(unit,colnum,rownu)o(m,n)o(elem)o(ents)o(,of)o(fset)o(,)42
+b(>)47 b(status\))0 5011 y Fd(9.8)135 b(Ro)l(w)46 b(Selection)g(and)f
+(Calculator)h(Routines)0 5262 y Fi(These)21 b(routines)e(all)h(parse)h
+(and)f(ev)-5 b(aluate)22 b(an)e(input)f(string)h(con)m(taining)h(a)g
+(user)f(de\014ned)g(arithmetic)g(expression.)0 5375 y(The)29
+b(\014rst)f(3)i(routines)e(select)i(ro)m(ws)f(in)f(a)i(FITS)e(table,)i
+(based)f(on)g(whether)g(the)g(expression)f(ev)-5 b(aluates)30
+b(to)g(true)0 5488 y(\(not)e(equal)e(to)i(zero\))g(or)f(false)g
+(\(zero\).)41 b(The)27 b(other)g(routines)f(ev)-5 b(aluate)28
+b(the)f(expression)f(and)g(calculate)i(a)f(v)-5 b(alue)0
+5601 y(for)35 b(eac)m(h)h(ro)m(w)g(of)f(the)h(table.)55
+b(The)35 b(allo)m(w)m(ed)g(expression)f(syn)m(tax)h(is)g(describ)s(ed)e
+(in)h(the)h(ro)m(w)h(\014lter)e(section)h(in)0 5714 y(the)i(earlier)f
+(`Extended)g(File)g(Name)h(Syn)m(tax')g(c)m(hapter)h(of)f(this)e(do)s
+(cumen)m(t.)60 b(The)36 b(expression)g(ma)m(y)h(also)g(b)s(e)p
+eop
+%%Page: 97 103
+97 102 bop 0 299 a Fg(9.8.)72 b(R)m(O)m(W)31 b(SELECTION)e(AND)i
+(CALCULA)-8 b(TOR)29 b(R)m(OUTINES)1382 b Fi(97)0 555
+y(written)27 b(to)j(a)e(text)i(\014le,)e(and)g(the)h(name)f(of)h(the)f
+(\014le,)g(prep)s(ended)f(with)g(a)i('@')f(c)m(haracter)i(ma)m(y)f(b)s
+(e)f(supplied)d(for)0 668 y(the)34 b('expr')g(parameter)g(\(e.g.)53
+b('@\014lename.txt'\).)e(The)34 b(expression)e(in)h(the)h(\014le)f(can)
+h(b)s(e)f(arbitrarily)e(complex)0 781 y(and)k(extend)h(o)m(v)m(er)h(m)m
+(ultiple)c(lines)h(of)i(the)f(\014le.)56 b(Lines)35 b(that)h(b)s(egin)e
+(with)g(2)i(slash)f(c)m(haracters)i(\('//'\))h(will)33
+b(b)s(e)0 894 y(ignored)c(and)h(ma)m(y)h(b)s(e)f(used)g(to)h(add)e
+(commen)m(ts)j(to)f(the)f(\014le.)0 1171 y Fh(1)81 b
+Fi(Ev)-5 b(aluate)37 b(a)g(b)s(o)s(olean)f(expression)g(o)m(v)m(er)i
+(the)g(indicated)d(ro)m(ws,)k(returning)c(an)i(arra)m(y)h(of)f(\015ags)
+g(indicating)227 1284 y(whic)m(h)29 b(ro)m(ws)i(ev)-5
+b(aluated)30 b(to)h(TR)m(UE/F)-10 b(ALSE)430 1560 y Fe
+(FTFROW\(unit,expr,firstr)o(ow,)41 b(nrows,)46 b(>)i(n_good_rows,)c
+(row_status,)h(status\))0 1837 y Fh(2)81 b Fi(Find)28
+b(the)j(\014rst)f(ro)m(w)g(whic)m(h)f(satis\014es)h(the)h(input)d(b)s
+(o)s(olean)h(expression)430 2114 y Fe(FTFFRW\(unit,)44
+b(expr,)i(>)i(rownum,)e(status\))0 2391 y Fh(3)81 b Fi(Ev)-5
+b(aluate)34 b(an)g(expression)g(on)g(all)f(ro)m(ws)i(of)f(a)h(table.)53
+b(If)34 b(the)g(input)f(and)h(output)g(\014les)f(are)i(not)g(the)f
+(same,)227 2503 y(cop)m(y)39 b(the)f(TR)m(UE)g(ro)m(ws)h(to)f(the)h
+(output)e(\014le.)63 b(If)38 b(the)g(\014les)f(are)i(the)f(same,)j
+(delete)d(the)g(F)-10 b(ALSE)38 b(ro)m(ws)227 2616 y(\(preserv)m(e)31
+b(the)g(TR)m(UE)f(ro)m(ws\).)430 2893 y Fe(FTSROW\(inunit,)43
+b(outunit,)j(expr,)g(>)i(status\))0 3170 y Fh(4)81 b
+Fi(Calculate)26 b(an)h(expression)e(for)i(the)f(indicated)g(ro)m(ws)g
+(of)h(a)g(table,)h(returning)d(the)i(results,)f(cast)i(as)f(datat)m(yp)
+s(e)227 3283 y(\(TSHOR)-8 b(T,)32 b(TDOUBLE,)h(etc\),)h(in)d(arra)m(y)
+-8 b(.)48 b(If)31 b(n)m(ulv)-5 b(al==NULL,)31 b(UNDEFs)i(will)c(b)s(e)j
+(zero)s(ed)g(out.)47 b(F)-8 b(or)227 3396 y(v)m(ector)37
+b(results,)e(the)g(n)m(um)m(b)s(er)e(of)i(elemen)m(ts)h(returned)d(ma)m
+(y)j(b)s(e)e(less)g(than)h(nelemen)m(ts)f(if)g(nelemen)m(ts)h(is)227
+3509 y(not)30 b(an)g(ev)m(en)h(m)m(ultiple)c(of)j(the)g(result)f
+(dimension.)38 b(Call)28 b(FTTEXP)i(to)g(obtain)g(the)g(dimensions)d
+(of)j(the)227 3621 y(results.)430 3898 y Fe(FTCROW\(unit,datatype,ex)o
+(pr,)o(firs)o(trow)o(,ne)o(leme)o(nts,)o(nul)o(val,)41
+b(>)620 4011 y(array,anynul,status\))0 4288 y Fh(5)81
+b Fi(Ev)-5 b(aluate)32 b(an)h(expression)e(and)i(write)e(the)i(result)f
+(either)g(to)i(a)f(column)e(\(if)h(the)h(expression)e(is)h(a)h
+(function)227 4401 y(of)d(other)g(columns)f(in)f(the)i(table\))g(or)g
+(to)g(a)h(k)m(eyw)m(ord)f(\(if)f(the)h(expression)e(ev)-5
+b(aluates)31 b(to)f(a)g(constan)m(t)i(and)227 4514 y(is)e(not)g(a)h
+(function)e(of)i(other)f(columns)g(in)f(the)h(table\).)41
+b(In)30 b(the)h(former)e(case,)j(the)f(parName)f(parameter)227
+4627 y(is)39 b(the)h(name)f(of)h(the)g(column)e(\(whic)m(h)h(ma)m(y)h
+(or)f(ma)m(y)h(not)g(already)f(exist\))h(in)m(to)f(whic)m(h)g(to)h
+(write)f(the)227 4739 y(results,)e(and)g(parInfo)e(con)m(tains)i(an)g
+(optional)e(TF)m(ORM)i(k)m(eyw)m(ord)g(v)-5 b(alue)37
+b(if)e(a)i(new)f(column)g(is)f(b)s(eing)227 4852 y(created.)42
+b(If)28 b(a)h(TF)m(ORM)h(v)-5 b(alue)28 b(is)g(not)h(sp)s(eci\014ed)f
+(then)g(a)i(default)e(format)h(will)e(b)s(e)h(used,)h(dep)s(ending)d
+(on)227 4965 y(the)35 b(expression.)53 b(If)34 b(the)h(expression)e(ev)
+-5 b(aluates)36 b(to)f(a)g(constan)m(t,)i(then)e(the)g(result)e(will)f
+(b)s(e)i(written)g(to)227 5078 y(the)28 b(k)m(eyw)m(ord)g(name)f(giv)m
+(en)g(b)m(y)h(the)f(parName)h(parameter,)h(and)d(the)i(parInfo)e
+(parameter)i(ma)m(y)g(b)s(e)f(used)227 5191 y(to)k(supply)d(an)i
+(optional)g(commen)m(t)h(for)f(the)g(k)m(eyw)m(ord.)42
+b(If)29 b(the)i(k)m(eyw)m(ord)g(do)s(es)f(not)g(already)g(exist,)g
+(then)227 5304 y(the)g(name)f(of)h(the)g(k)m(eyw)m(ord)g(m)m(ust)f(b)s
+(e)g(preceded)g(with)f(a)i('#')f(c)m(haracter,)j(otherwise)d(the)g
+(result)g(will)e(b)s(e)227 5417 y(written)j(to)h(a)g(column)e(with)g
+(that)i(name.)430 5694 y Fe(FTCALC\(inunit,)43 b(expr,)k(outunit,)e
+(parName,)h(parInfo,)f(>)j(status\))p eop
+%%Page: 98 104
+98 103 bop 0 299 a Fi(98)1319 b Fg(CHAPTER)29 b(9.)112
+b(AD)m(V)-10 b(ANCED)32 b(INTERF)-10 b(A)m(CE)30 b(SUBR)m(OUTINES)0
+555 y Fh(6)81 b Fi(This)37 b(calculator)j(routine)f(is)f(similar)f(to)j
+(the)g(previous)e(routine,)j(except)g(that)f(the)g(expression)e(is)h
+(only)227 668 y(ev)-5 b(aluated)41 b(o)m(v)m(er)g(the)f(sp)s(eci\014ed)
+f(ro)m(w)h(ranges.)70 b(nranges)39 b(sp)s(eci\014es)g(the)h(n)m(um)m(b)
+s(er)f(of)h(ro)m(w)h(ranges,)i(and)227 781 y(\014rstro)m(w)30
+b(and)g(lastro)m(w)g(giv)m(e)h(the)g(starting)f(and)g(ending)f(ro)m(w)h
+(n)m(um)m(b)s(er)f(of)i(eac)m(h)g(range.)430 1031 y Fe
+(FTCALC_RNG\(inunit,)42 b(expr,)47 b(outunit,)e(parName,)h(parInfo,)573
+1144 y(nranges,)f(firstrow,)h(lastrow,)f(>)j(status\))0
+1394 y Fh(7)81 b Fi(Ev)-5 b(aluate)30 b(the)h(giv)m(en)f(expression)f
+(and)h(return)f(information)g(on)h(the)h(result.)430
+1643 y Fe(FTTEXP\(unit,)44 b(expr,)i(>)i(datatype,)d(nelem,)h(naxis,)g
+(naxes,)g(status\))0 1976 y Fd(9.9)135 b(Celestial)48
+b(Co)t(ordinate)e(System)f(Subroutines)0 2226 y Fi(The)36
+b(FITS)g(comm)m(unit)m(y)g(has)g(adopted)h(a)g(set)g(of)g(k)m(eyw)m
+(ord)g(con)m(v)m(en)m(tions)g(that)g(de\014ne)f(the)h(transformations)0
+2339 y(needed)30 b(to)i(con)m(v)m(ert)g(b)s(et)m(w)m(een)f(pixel)e(lo)s
+(cations)h(in)f(an)i(image)g(and)f(the)g(corresp)s(onding)f(celestial)h
+(co)s(ordinates)0 2452 y(on)25 b(the)h(sky)-8 b(,)27
+b(or)e(more)g(generally)-8 b(,)27 b(that)f(de\014ne)e(w)m(orld)g(co)s
+(ordinates)i(that)f(are)h(to)g(b)s(e)f(asso)s(ciated)h(with)e(an)m(y)i
+(pixel)0 2564 y(lo)s(cation)34 b(in)f(an)i(n-dimensional)c(FITS)j(arra)
+m(y)-8 b(.)54 b(CFITSIO)33 b(is)g(distributed)f(with)h(a)i(couple)e(of)
+i(self-con)m(tained)0 2677 y(W)-8 b(orld)27 b(Co)s(ordinate)f(System)g
+(\(W)m(CS\))i(routines,)f(ho)m(w)m(ev)m(er,)i(these)f(routines)e(DO)h
+(NOT)f(supp)s(ort)f(all)h(the)h(latest)0 2790 y(W)m(CS)38
+b(con)m(v)m(en)m(tions,)j(so)e(it)f(is)f(STR)m(ONGL)-8
+b(Y)38 b(RECOMMENDED)h(that)f(soft)m(w)m(are)i(dev)m(elop)s(ers)d(use)h
+(a)h(more)0 2903 y(robust)30 b(external)g(W)m(CS)g(library)-8
+b(.)39 b(Sev)m(eral)30 b(recommended)g(libraries)e(are:)95
+3153 y Fe(WCSLIB)47 b(-)95 b(supported)45 b(by)i(Mark)g(Calabretta)95
+3266 y(WCSTools)f(-)h(supported)f(by)h(Doug)g(Mink)95
+3379 y(AST)g(library)f(-)i(developed)d(by)i(the)g(U.K.)g(Starlink)e
+(project)0 3629 y Fi(More)30 b(information)d(ab)s(out)i(the)g(W)m(CS)g
+(k)m(eyw)m(ord)h(con)m(v)m(en)m(tions)g(and)e(links)f(to)j(all)e(of)h
+(these)g(W)m(CS)g(libraries)e(can)0 3742 y(b)s(e)j(found)f(on)h(the)h
+(FITS)e(Supp)s(ort)g(O\016ce)h(w)m(eb)g(site)h(at)g(h)m
+(ttp://\014ts.gsfc.nasa.go)m(v)j(under)29 b(the)h(W)m(CS)h(link.)0
+3902 y(The)i(functions)g(pro)m(vided)g(in)f(these)j(external)e(W)m(CS)h
+(libraries)e(will)f(need)j(access)h(to)g(the)f(W)m(CS)g(information)0
+4015 y(con)m(tained)g(in)e(the)i(FITS)f(\014le)g(headers.)51
+b(One)33 b(con)m(v)m(enien)m(t)i(w)m(a)m(y)g(to)f(pass)g(this)e
+(information)g(to)j(the)f(extermal)0 4128 y(library)j(is)i(to)i(use)e
+(FITSIO)g(to)h(cop)m(y)h(the)f(header)f(k)m(eyw)m(ords)h(in)m(to)g(one)
+g(long)f(c)m(haracter)j(string,)f(and)e(then)0 4240 y(pass)29
+b(this)g(string)g(to)h(an)g(in)m(terface)g(routine)f(in)g(the)h
+(external)f(library)f(that)i(will)d(extract)32 b(the)e(necessary)g(W)m
+(CS)0 4353 y(information)f(\(e.g.,)j(see)f(the)f(astFitsChan)g(and)g
+(astPutCards)g(routines)f(in)g(the)i(Starlink)d(AST)i(library\).)0
+4514 y(The)24 b(follo)m(wing)g(FITSIO)f(routines)h(DO)h(NOT)f(supp)s
+(ort)f(the)i(more)g(recen)m(t)h(W)m(CS)f(con)m(v)m(en)m(tions)h(that)g
+(ha)m(v)m(e)g(b)s(een)0 4626 y(appro)m(v)m(ed)37 b(as)h(part)f(of)g
+(the)h(FITS)e(standard.)61 b(Consequen)m(tly)-8 b(,)38
+b(the)g(follo)m(wing)d(routines)i(ARE)g(NO)m(W)h(DEP-)0
+4739 y(RECA)-8 b(TED.)29 b(It)f(is)g(STR)m(ONGL)-8 b(Y)28
+b(RECOMMENDED)h(that)g(soft)m(w)m(are)h(dev)m(elop)s(ers)e(not)h(use)f
+(these)h(routines,)0 4852 y(and)h(instead)f(use)h(an)h(external)f(W)m
+(CS)g(library)-8 b(,)29 b(as)i(describ)s(ed)d(ab)s(o)m(v)m(e.)0
+5012 y(These)21 b(routines)f(are)h(included)d(mainly)h(for)i(bac)m(kw)m
+(ard)g(compatibilit)m(y)f(with)f(existing)h(soft)m(w)m(are.)39
+b(They)21 b(supp)s(ort)0 5125 y(the)30 b(follo)m(wing)f(standard)g(map)
+g(pro)5 b(jections:)40 b(-SIN,)30 b(-T)-8 b(AN,)31 b(-AR)m(C,)g(-NCP)-8
+b(,)30 b(-GLS,)g(-MER,)h(and)e(-AIT)h(\(these)0 5238
+y(are)f(the)g(legal)f(v)-5 b(alues)28 b(for)g(the)h(co)s(ordt)m(yp)s(e)
+f(parameter\).)41 b(These)28 b(routines)g(are)h(based)f(on)g(similar)e
+(functions)h(in)0 5351 y(Classic)i(AIPS.)h(All)f(the)i(angular)e(quan)m
+(tities)h(are)h(giv)m(en)f(in)f(units)g(of)h(degrees.)0
+5601 y Fh(1)81 b Fi(Get)22 b(the)g(v)-5 b(alues)20 b(of)i(all)e(the)i
+(standard)f(FITS)f(celestial)h(co)s(ordinate)h(system)f(k)m(eyw)m(ords)
+h(from)f(the)h(header)f(of)h(a)227 5714 y(FITS)j(image)h(\(i.e.,)h(the)
+e(primary)f(arra)m(y)i(or)f(an)h(image)f(extension\).)39
+b(These)26 b(v)-5 b(alues)24 b(ma)m(y)i(then)g(b)s(e)e(passed)p
+eop
+%%Page: 99 105
+99 104 bop 0 299 a Fg(9.10.)73 b(FILE)30 b(CHECKSUM)f(SUBR)m(OUTINES)
+2080 b Fi(99)227 555 y(to)39 b(the)e(subroutines)f(that)i(p)s(erform)e
+(the)i(co)s(ordinate)f(transformations.)62 b(If)37 b(an)m(y)h(or)g(all)
+e(of)i(the)g(W)m(CS)227 668 y(k)m(eyw)m(ords)32 b(are)f(not)g(presen)m
+(t,)h(then)f(default)f(v)-5 b(alues)30 b(will)f(b)s(e)h(returned.)41
+b(If)31 b(the)g(\014rst)g(co)s(ordinate)f(axis)h(is)227
+781 y(the)e(declination-lik)m(e)e(co)s(ordinate,)i(then)f(this)f
+(routine)h(will)e(sw)m(ap)i(them)h(so)g(that)g(the)g(longitudinal-lik)m
+(e)227 894 y(co)s(ordinate)h(is)g(returned)f(as)i(the)f(\014rst)g
+(axis.)227 1045 y(If)35 b(the)h(\014le)e(uses)h(the)g(new)m(er)h('CDj)p
+1454 1045 28 4 v 32 w(i')f(W)m(CS)g(transformation)g(matrix)g(k)m(eyw)m
+(ords)g(instead)g(of)g(old)g(st)m(yle)227 1158 y('CDEL)-8
+b(Tn')37 b(and)f('CR)m(OT)-8 b(A2')38 b(k)m(eyw)m(ords,)h(then)e(this)e
+(routine)h(will)e(calculate)k(and)e(return)g(the)h(v)-5
+b(alues)227 1271 y(of)33 b(the)g(equiv)-5 b(alen)m(t)33
+b(old-st)m(yle)f(k)m(eyw)m(ords.)49 b(Note)34 b(that)g(the)f(con)m(v)m
+(ersion)g(from)f(the)i(new-st)m(yle)f(k)m(eyw)m(ords)227
+1383 y(to)f(the)f(old-st)m(yle)f(v)-5 b(alues)30 b(is)g(sometimes)g
+(only)g(an)h(appro)m(ximation,)f(so)g(if)g(the)h(appro)m(ximation)f(is)
+f(larger)227 1496 y(than)37 b(an)h(in)m(ternally)d(de\014ned)h
+(threshold)g(lev)m(el,)j(then)e(CFITSIO)f(will)f(still)g(return)h(the)i
+(appro)m(ximate)227 1609 y(W)m(CS)f(k)m(eyw)m(ord)g(v)-5
+b(alues,)38 b(but)e(will)e(also)j(return)e(with)h(status)h(=)f(506,)k
+(to)e(w)m(arn)e(the)h(calling)e(program)227 1722 y(that)30
+b(appro)m(ximations)d(ha)m(v)m(e)j(b)s(een)e(made.)40
+b(It)29 b(is)f(then)g(up)g(to)h(the)g(calling)f(program)g(to)h(decide)g
+(whether)227 1835 y(the)34 b(appro)m(ximations)e(are)i(su\016cien)m
+(tly)e(accurate)k(for)d(the)h(particular)d(application,)i(or)h(whether)
+f(more)227 1948 y(precise)d(W)m(CS)g(transformations)g(m)m(ust)g(b)s(e)
+g(p)s(erformed)f(using)g(new-st)m(yle)h(W)m(CS)h(k)m(eyw)m(ords)f
+(directly)-8 b(.)382 2209 y Fe(FTGICS\(unit,)44 b(>)k
+(xrval,yrval,xrpix,yrpix)o(,xin)o(c,yi)o(nc,)o(rot,)o(coor)o(dty)o
+(pe,s)o(tatu)o(s\))0 2470 y Fh(2)81 b Fi(Get)34 b(the)f(v)-5
+b(alues)32 b(of)h(all)f(the)h(standard)f(FITS)h(celestial)f(co)s
+(ordinate)h(system)g(k)m(eyw)m(ords)g(from)g(the)g(header)227
+2583 y(of)j(a)h(FITS)e(table)g(where)h(the)g(X)g(and)f(Y)h(\(or)g(RA)g
+(and)g(DEC)f(co)s(ordinates)h(are)g(stored)g(in)f(2)h(separate)227
+2695 y(columns)31 b(of)h(the)g(table.)45 b(These)31 b(v)-5
+b(alues)31 b(ma)m(y)i(then)e(b)s(e)h(passed)f(to)h(the)g(subroutines)e
+(that)i(p)s(erform)f(the)227 2808 y(co)s(ordinate)f(transformations.)
+382 3069 y Fe(FTGTCS\(unit,xcol,ycol,)42 b(>)716 3182
+y(xrval,yrval,xrpix,yrpix,)o(xinc)o(,yi)o(nc,r)o(ot,c)o(oor)o(dtyp)o
+(e,st)o(atu)o(s\))0 3443 y Fh(3)81 b Fi(Calculate)40
+b(the)i(celestial)e(co)s(ordinate)h(corresp)s(onding)e(to)j(the)f
+(input)e(X)i(and)g(Y)g(pixel)e(lo)s(cation)i(in)f(the)227
+3556 y(image.)382 3817 y Fe(FTWLDP\(xpix,ypix,xrval,y)o(rva)o(l,xr)o
+(pix,)o(yrp)o(ix,x)o(inc,)o(yin)o(c,ro)o(t,)1241 3929
+y(coordtype,)45 b(>)i(xpos,ypos,status\))0 4190 y Fh(4)81
+b Fi(Calculate)40 b(the)i(X)f(and)f(Y)h(pixel)f(lo)s(cation)g(corresp)s
+(onding)f(to)j(the)f(input)e(celestial)i(co)s(ordinate)g(in)f(the)227
+4303 y(image.)382 4564 y Fe(FTXYPX\(xpos,ypos,xrval,y)o(rva)o(l,xr)o
+(pix,)o(yrp)o(ix,x)o(inc,)o(yin)o(c,ro)o(t,)1241 4677
+y(coordtype,)45 b(>)i(xpix,ypix,status\))0 5012 y Fd(9.10)136
+b(File)45 b(Chec)l(ksum)g(Subroutines)0 5262 y Fi(The)33
+b(follo)m(wing)e(routines)h(either)h(compute)g(or)h(v)-5
+b(alidate)32 b(the)i(c)m(hec)m(ksums)f(for)g(the)h(CHDU.)g(The)e(D)m(A)
+-8 b(T)g(ASUM)0 5375 y(k)m(eyw)m(ord)33 b(is)e(used)g(to)i(store)f(the)
+h(n)m(umerical)d(v)-5 b(alue)32 b(of)g(the)g(32-bit,)h(1's)g(complemen)
+m(t)f(c)m(hec)m(ksum)h(for)f(the)g(data)0 5488 y(unit)25
+b(alone.)39 b(If)25 b(there)h(is)g(no)f(data)i(unit)e(then)g(the)h(v)-5
+b(alue)26 b(is)f(set)h(to)h(zero.)40 b(The)26 b(n)m(umerical)e(v)-5
+b(alue)26 b(is)f(stored)h(as)g(an)0 5601 y(ASCI)s(I)20
+b(string)h(of)i(digits,)f(enclosed)g(in)e(quotes,)25
+b(b)s(ecause)d(the)g(v)-5 b(alue)22 b(ma)m(y)g(b)s(e)f(to)s(o)i(large)f
+(to)h(represen)m(t)f(as)g(a)h(32-bit)0 5714 y(signed)k(in)m(teger.)40
+b(The)27 b(CHECKSUM)g(k)m(eyw)m(ord)i(is)e(used)g(to)h(store)h(the)f
+(ASCI)s(I)e(enco)s(ded)i(COMPLEMENT)f(of)p eop
+%%Page: 100 106
+100 105 bop 0 299 a Fi(100)1274 b Fg(CHAPTER)29 b(9.)112
+b(AD)m(V)-10 b(ANCED)32 b(INTERF)-10 b(A)m(CE)30 b(SUBR)m(OUTINES)0
+555 y Fi(the)c(c)m(hec)m(ksum)h(for)f(the)h(en)m(tire)f(HDU.)h(Storing)
+e(the)i(complemen)m(t,)g(rather)f(than)g(the)h(actual)f(c)m(hec)m
+(ksum,)i(forces)0 668 y(the)k(c)m(hec)m(ksum)h(for)f(the)h(whole)e(HDU)
+i(to)g(equal)f(zero.)47 b(If)31 b(the)i(\014le)e(has)h(b)s(een)f(mo)s
+(di\014ed)f(since)i(the)g(c)m(hec)m(ksums)0 781 y(w)m(ere)39
+b(computed,)i(then)e(the)g(HDU)g(c)m(hec)m(ksum)h(will)c(usually)g(not)
+j(equal)g(zero.)66 b(These)39 b(c)m(hec)m(ksum)g(k)m(eyw)m(ord)0
+894 y(con)m(v)m(en)m(tions)33 b(are)g(based)f(on)g(a)g(pap)s(er)f(b)m
+(y)h(Rob)g(Seaman)g(published)d(in)i(the)h(pro)s(ceedings)f(of)h(the)h
+(AD)m(ASS)f(IV)0 1007 y(conference)f(in)e(Baltimore)h(in)g(No)m(v)m(em)
+m(b)s(er)h(1994)h(and)e(a)h(later)f(revision)f(in)g(June)g(1995.)0
+1237 y Fh(1)81 b Fi(Compute)33 b(and)g(write)g(the)h(D)m(A)-8
+b(T)g(ASUM)35 b(and)e(CHECKSUM)g(k)m(eyw)m(ord)h(v)-5
+b(alues)33 b(for)g(the)h(CHDU)g(in)m(to)g(the)227 1350
+y(curren)m(t)25 b(header.)38 b(The)24 b(D)m(A)-8 b(T)g(ASUM)27
+b(v)-5 b(alue)24 b(is)f(the)i(32-bit)g(c)m(hec)m(ksum)g(for)f(the)h
+(data)g(unit,)g(expressed)f(as)h(a)227 1463 y(decimal)30
+b(in)m(teger)g(enclosed)g(in)f(single)g(quotes.)41 b(The)30
+b(CHECKSUM)g(k)m(eyw)m(ord)g(v)-5 b(alue)30 b(is)f(a)i(16-c)m(haracter)
+227 1576 y(string)i(whic)m(h)f(is)h(the)g(ASCI)s(I-enco)s(ded)f(v)-5
+b(alue)33 b(for)h(the)f(complemen)m(t)h(of)g(the)f(c)m(hec)m(ksum)i
+(for)e(the)h(whole)227 1689 y(HDU.)h(If)e(these)g(k)m(eyw)m(ords)h
+(already)f(exist,)h(their)e(v)-5 b(alues)33 b(will)e(b)s(e)i(up)s
+(dated)f(only)g(if)g(necessary)i(\(i.e.,)h(if)227 1802
+y(the)c(\014le)e(has)h(b)s(een)g(mo)s(di\014ed)e(since)i(the)h
+(original)d(k)m(eyw)m(ord)j(v)-5 b(alues)30 b(w)m(ere)h(computed\).)382
+2033 y Fe(FTPCKS\(unit,)44 b(>)k(status\))0 2263 y Fh(2)81
+b Fi(Up)s(date)28 b(the)h(CHECKSUM)e(k)m(eyw)m(ord)i(v)-5
+b(alue)28 b(in)f(the)i(CHDU,)g(assuming)e(that)i(the)f(D)m(A)-8
+b(T)g(ASUM)30 b(k)m(eyw)m(ord)227 2376 y(exists)35 b(and)g(already)g
+(has)g(the)h(correct)g(v)-5 b(alue.)55 b(This)34 b(routine)g
+(calculates)i(the)g(new)f(c)m(hec)m(ksum)h(for)f(the)227
+2489 y(curren)m(t)40 b(header)g(unit,)i(adds)d(it)h(to)h(the)f(data)h
+(unit)e(c)m(hec)m(ksum,)44 b(enco)s(des)c(the)g(v)-5
+b(alue)40 b(in)m(to)g(an)g(ASCI)s(I)227 2602 y(string,)30
+b(and)g(writes)f(the)i(string)e(to)i(the)g(CHECKSUM)e(k)m(eyw)m(ord.)
+382 2833 y Fe(FTUCKS\(unit,)44 b(>)k(status\))0 3063
+y Fh(3)81 b Fi(V)-8 b(erify)34 b(the)g(CHDU)h(b)m(y)g(computing)e(the)i
+(c)m(hec)m(ksums)g(and)f(comparing)g(them)g(with)f(the)i(k)m(eyw)m
+(ords.)53 b(The)227 3176 y(data)34 b(unit)e(is)g(v)m(eri\014ed)g
+(correctly)h(if)f(the)i(computed)f(c)m(hec)m(ksum)g(equals)g(the)g(v)-5
+b(alue)33 b(of)g(the)g(D)m(A)-8 b(T)g(ASUM)227 3289 y(k)m(eyw)m(ord.)64
+b(The)37 b(c)m(hec)m(ksum)i(for)f(the)g(en)m(tire)f(HDU)i(\(header)f
+(plus)e(data)j(unit\))d(is)h(correct)i(if)e(it)h(equals)227
+3402 y(zero.)55 b(The)34 b(output)g(D)m(A)-8 b(T)g(A)m(OK)37
+b(and)d(HDUOK)h(parameters)g(in)e(this)h(subroutine)e(are)j(in)m
+(tegers)g(whic)m(h)227 3515 y(will)24 b(ha)m(v)m(e)j(a)f(v)-5
+b(alue)26 b(=)g(1)g(if)f(the)i(data)f(or)g(HDU)h(is)e(v)m(eri\014ed)h
+(correctly)-8 b(,)28 b(a)e(v)-5 b(alue)26 b(=)f(0)i(if)e(the)h(D)m(A)-8
+b(T)g(ASUM)28 b(or)227 3628 y(CHECKSUM)h(k)m(eyw)m(ord)g(is)g(not)g
+(presen)m(t,)h(or)f(v)-5 b(alue)29 b(=)g(-1)h(if)e(the)i(computed)f(c)m
+(hec)m(ksum)h(is)e(not)i(correct.)382 3858 y Fe(FTVCKS\(unit,)44
+b(>)k(dataok,hduok,status\))0 4089 y Fh(4)81 b Fi(Compute)25
+b(and)h(return)f(the)i(c)m(hec)m(ksum)g(v)-5 b(alues)25
+b(for)h(the)h(CHDU)f(\(as)h(double)e(precision)g(v)-5
+b(ariables\))25 b(without)227 4202 y(creating)45 b(or)f(mo)s(difying)e
+(the)j(CHECKSUM)e(and)h(D)m(A)-8 b(T)g(ASUM)46 b(k)m(eyw)m(ords.)83
+b(This)43 b(routine)g(is)h(used)227 4315 y(in)m(ternally)29
+b(b)m(y)h(FTV)m(CKS,)g(but)g(ma)m(y)h(b)s(e)e(useful)g(in)g(other)i
+(situations)e(as)h(w)m(ell.)382 4545 y Fe(FTGCKS\(unit,)44
+b(>)k(datasum,hdusum,status\))0 4776 y Fh(5)81 b Fi(Enco)s(de)33
+b(a)h(c)m(hec)m(ksum)h(v)-5 b(alue)33 b(\(stored)h(in)f(a)h(double)f
+(precision)f(v)-5 b(ariable\))33 b(in)m(to)g(a)i(16-c)m(haracter)h
+(string.)50 b(If)227 4889 y(COMPLEMENT)30 b(=)g(.true.)41
+b(then)30 b(the)g(32-bit)h(sum)e(v)-5 b(alue)30 b(will)e(b)s(e)i
+(complemen)m(ted)g(b)s(efore)g(enco)s(ding.)382 5120
+y Fe(FTESUM\(sum,complement,)42 b(>)47 b(checksum\))0
+5350 y Fh(6)81 b Fi(Deco)s(de)39 b(a)f(16)h(c)m(haracter)h(c)m(hec)m
+(ksum)e(string)f(in)m(to)h(a)h(double)d(precision)g(v)-5
+b(alue.)64 b(If)37 b(COMPLEMENT)g(=)227 5463 y(.true.)k(then)30
+b(the)h(32-bit)f(sum)g(v)-5 b(alue)30 b(will)d(b)s(e)j(complemen)m(ted)
+h(after)f(deco)s(ding.)382 5694 y Fe(FTDSUM\(checksum,compleme)o(nt,)41
+b(>)48 b(sum\))p eop
+%%Page: 101 107
+101 106 bop 0 299 a Fg(9.11.)113 b(D)m(A)-8 b(TE)31 b(AND)g(TIME)f
+(UTILITY)g(R)m(OUTINES)1767 b Fi(101)0 555 y Fd(9.11)180
+b(Date)46 b(and)f(Time)g(Utilit)l(y)i(Routines)0 805
+y Fi(The)29 b(follo)m(wing)f(routines)h(help)f(to)j(construct)f(or)f
+(parse)h(the)g(FITS)f(date/time)h(strings.)40 b(Starting)29
+b(in)f(the)i(y)m(ear)0 918 y(2000,)k(the)d(FITS)g(D)m(A)-8
+b(TE)32 b(k)m(eyw)m(ord)g(v)-5 b(alues)30 b(\(and)i(the)f(v)-5
+b(alues)31 b(of)g(other)h(`D)m(A)-8 b(TE-')33 b(k)m(eyw)m(ords\))f(m)m
+(ust)f(ha)m(v)m(e)i(the)0 1031 y(form)j('YYYY-MM-DD')k(\(date)e(only\))
+e(or)h('YYYY-MM-DDThh:mm:ss.ddd...')61 b(\(date)38 b(and)e(time\))g
+(where)0 1144 y(the)30 b(n)m(um)m(b)s(er)f(of)i(decimal)e(places)h(in)f
+(the)h(seconds)g(v)-5 b(alue)30 b(is)f(optional.)40 b(These)30
+b(times)g(are)g(in)f(UTC.)h(The)g(older)0 1257 y('dd/mm/yy')g(date)h
+(format)g(ma)m(y)g(not)g(b)s(e)e(used)h(for)g(dates)h(after)g(01)g(Jan)
+m(uary)f(2000.)0 1486 y Fh(1)81 b Fi(Get)31 b(the)g(curren)m(t)f
+(system)g(date.)42 b(The)29 b(returned)h(y)m(ear)h(has)f(4)h(digits)e
+(\(1999,)j(2000,)h(etc.\))382 1714 y Fe(FTGSDT\()46 b(>)h(day,)g
+(month,)f(year,)g(status)g(\))0 1943 y Fh(2)81 b Fi(Get)34
+b(the)g(curren)m(t)g(system)f(date)i(and)e(time)g(string)g
+(\('YYYY-MM-DDThh:mm:ss'\).)53 b(The)33 b(time)h(will)d(b)s(e)227
+2056 y(in)25 b(UTC/GMT)h(if)f(a)m(v)-5 b(ailable,)26
+b(as)h(indicated)d(b)m(y)i(a)g(returned)f(timeref)g(v)-5
+b(alue)26 b(=)f(0.)40 b(If)26 b(the)g(returned)e(v)-5
+b(alue)227 2169 y(of)31 b(timeref)f(=)h(1)g(then)f(this)g(indicates)f
+(that)j(it)e(w)m(as)h(not)g(p)s(ossible)d(to)j(con)m(v)m(ert)i(the)d
+(lo)s(cal)g(time)h(to)g(UTC,)227 2281 y(and)f(th)m(us)g(the)h(lo)s(cal)
+e(time)h(w)m(as)h(returned.)382 2510 y Fe(FTGSTM\(>)45
+b(datestr,)h(timeref,)f(status\))0 2739 y Fh(3)81 b Fi(Construct)26
+b(a)i(date)g(string)e(from)h(the)g(input)e(date)j(v)-5
+b(alues.)39 b(If)27 b(the)g(y)m(ear)h(is)f(b)s(et)m(w)m(een)g(1900)i
+(and)e(1998,)j(inclu-)227 2852 y(siv)m(e,)37 b(then)d(the)i(returned)d
+(date)j(string)e(will)e(ha)m(v)m(e)37 b(the)e(old)f(FITS)g(format)i
+(\('dd/mm/yy'\),)h(otherwise)227 2964 y(the)32 b(date)g(string)e(will)e
+(ha)m(v)m(e)33 b(the)e(new)g(FITS)g(format)g(\('YYYY-MM-DD'\).)36
+b(Use)c(FTTM2S)f(instead)f(to)227 3077 y(alw)m(a)m(ys)h(return)e(a)i
+(date)g(string)f(using)e(the)j(new)f(FITS)g(format.)382
+3306 y Fe(FTDT2S\()46 b(year,)g(month,)g(day,)h(>)g(datestr,)f
+(status\))0 3535 y Fh(4)81 b Fi(Construct)34 b(a)i(new-format)f(date)h
+(+)f(time)g(string)f(\('YYYY-MM-DDThh:mm:ss.ddd...'\).)57
+b(If)34 b(the)i(y)m(ear,)227 3647 y(mon)m(th,)d(and)e(da)m(y)h(v)-5
+b(alues)31 b(all)g(=)g(0)h(then)g(only)f(the)h(time)f(is)g(enco)s(ded)g
+(with)g(format)h('hh:mm:ss.ddd...'.)227 3760 y(The)j(decimals)f
+(parameter)i(sp)s(eci\014es)d(ho)m(w)j(man)m(y)f(decimal)f(places)h(of)
+g(fractional)g(seconds)g(to)h(include)227 3873 y(in)29
+b(the)i(string.)40 b(If)29 b(`decimals')h(is)g(negativ)m(e,)h(then)g
+(only)e(the)i(date)g(will)c(b)s(e)j(return)f(\('YYYY-MM-DD'\).)382
+4102 y Fe(FTTM2S\()46 b(year,)g(month,)g(day,)h(hour,)f(minute,)g
+(second,)g(decimals,)764 4215 y(>)h(datestr,)f(status\))0
+4443 y Fh(5)81 b Fi(Return)44 b(the)g(date)i(as)f(read)f(from)h(the)g
+(input)d(string,)48 b(where)c(the)h(string)f(ma)m(y)h(b)s(e)f(in)g
+(either)g(the)h(old)227 4556 y(\('dd/mm/yy'\))31 b(or)g(new)e
+(\('YYYY-MM-DDThh:mm:ss')k(or)d('YYYY-MM-DD'\))k(FITS)c(format.)382
+4785 y Fe(FTS2DT\(datestr,)43 b(>)48 b(year,)e(month,)g(day,)h
+(status\))0 5013 y Fh(6)81 b Fi(Return)30 b(the)h(date)h(and)f(time)g
+(as)g(read)g(from)g(the)h(input)d(string,)h(where)h(the)h(string)e(ma)m
+(y)i(b)s(e)e(in)g(either)h(the)227 5126 y(old)d(or)g(new)g(FITS)g
+(format.)40 b(The)28 b(returned)f(hours,)h(min)m(utes,)g(and)g(seconds)
+g(v)-5 b(alues)28 b(will)d(b)s(e)j(set)h(to)g(zero)227
+5239 y(if)j(the)i(input)d(string)h(do)s(es)h(not)h(include)d(the)i
+(time)g(\('dd/mm/yy')g(or)h('YYYY-MM-DD'\))j(.)c(Similarly)-8
+b(,)227 5352 y(the)36 b(returned)e(y)m(ear,)j(mon)m(th,)g(and)d(date)i
+(v)-5 b(alues)35 b(will)d(b)s(e)j(set)h(to)g(zero)g(if)e(the)h(date)h
+(is)e(not)i(included)c(in)227 5465 y(the)f(input)d(string)i
+(\('hh:mm:ss.ddd...'\).)382 5694 y Fe(FTS2TM\(datestr,)43
+b(>)48 b(year,)e(month,)g(day,)h(hour,)f(minute,)g(second,)g(status\))p
+eop
+%%Page: 102 108
+102 107 bop 0 299 a Fi(102)1274 b Fg(CHAPTER)29 b(9.)112
+b(AD)m(V)-10 b(ANCED)32 b(INTERF)-10 b(A)m(CE)30 b(SUBR)m(OUTINES)0
+555 y Fd(9.12)136 b(General)45 b(Utilit)l(y)i(Subroutines)0
+805 y Fi(The)30 b(follo)m(wing)f(utilit)m(y)f(subroutines)h(ma)m(y)i(b)
+s(e)e(useful)g(for)h(certain)g(applications:)0 1060 y
+Fh(1)81 b Fi(Return)29 b(the)i(starting)f(b)m(yte)h(address)e(of)i(the)
+f(CHDU)h(and)f(the)h(next)f(HDU.)382 1315 y Fe(FTGHAD\(iunit,)44
+b(>)j(curaddr,nextaddr\))0 1569 y Fh(2)81 b Fi(Con)m(v)m(ert)31
+b(a)g(c)m(haracter)h(string)d(to)i(upp)s(ercase)e(\(op)s(erates)j(in)d
+(place\).)382 1824 y Fe(FTUPCH\(string\))0 2078 y Fh(3)81
+b Fi(Compare)43 b(the)i(input)d(template)i(string)f(against)h(the)h
+(reference)f(string)f(to)i(see)g(if)e(they)h(matc)m(h.)82
+b(The)227 2191 y(template)35 b(string)f(ma)m(y)h(con)m(tain)f(wildcard)
+e(c)m(haracters:)51 b('*')35 b(will)d(matc)m(h)j(an)m(y)g(sequence)g
+(of)f(c)m(haracters)227 2304 y(\(including)f(zero)j(c)m(haracters\))h
+(and)e('reference)h(string.)55 b(If)35 b(CASESN)f(=)h(.true.)56
+b(then)35 b(the)g(matc)m(h)i(will)227 2417 y(b)s(e)29
+b(case)h(sensitiv)m(e.)40 b(The)29 b(returned)f(MA)-8
+b(TCH)30 b(parameter)g(will)d(b)s(e)h(.true.)41 b(if)28
+b(the)i(2)g(strings)e(matc)m(h,)j(and)227 2530 y(EXA)m(CT)i(will)e(b)s
+(e)h(.true.)49 b(if)32 b(the)i(matc)m(h)g(is)e(exact)i(\(i.e.,)h(if)d
+(no)h(wildcard)e(c)m(haracters)j(w)m(ere)g(used)e(in)g(the)227
+2643 y(matc)m(h\).)42 b(Both)31 b(strings)e(m)m(ust)i(b)s(e)e(68)j(c)m
+(haracters)f(or)g(less)f(in)f(length.)382 2898 y Fe
+(FTCMPS\(str_template,stri)o(ng,)o(case)o(sen,)41 b(>)47
+b(match,exact\))0 3152 y Fh(4)81 b Fi(T)-8 b(est)31 b(that)g(the)f(k)m
+(eyw)m(ord)h(name)f(con)m(tains)h(only)e(legal)i(c)m(haracters:)42
+b(A-Z,0-9,)32 b(h)m(yphen,)d(and)h(underscore.)382 3407
+y Fe(FTTKEY\(keyword,)43 b(>)48 b(status\))0 3662 y Fh(5)81
+b Fi(T)-8 b(est)31 b(that)g(the)f(k)m(eyw)m(ord)h(record)f(con)m(tains)
+h(only)e(legal)h(prin)m(table)f(ASCI)s(I)g(c)m(haracters)382
+3916 y Fe(FTTREC\(card,)44 b(>)k(status\))0 4171 y Fh(6)81
+b Fi(T)-8 b(est)25 b(whether)f(the)h(curren)m(t)f(header)h(con)m(tains)
+f(an)m(y)h(NULL)g(\(ASCI)s(I)e(0\))j(c)m(haracters.)40
+b(These)24 b(c)m(haracters)j(are)227 4284 y(illegal)33
+b(in)g(the)i(header,)g(but)f(they)g(will)e(go)j(undetected)g(b)m(y)f
+(most)h(of)g(the)f(CFITSIO)f(k)m(eyw)m(ord)i(header)227
+4397 y(routines,)28 b(b)s(ecause)g(the)h(n)m(ull)d(is)h(in)m(terpreted)
+g(as)i(the)f(normal)f(end-of-string)h(terminator.)40
+b(This)26 b(routine)227 4509 y(returns)i(the)g(p)s(osition)f(of)i(the)g
+(\014rst)f(n)m(ull)e(c)m(haracter)k(in)e(the)g(header,)h(or)g(zero)g
+(if)f(there)h(are)g(no)f(n)m(ulls.)38 b(F)-8 b(or)227
+4622 y(example)36 b(a)g(returned)f(v)-5 b(alue)36 b(of)g(110)h(w)m
+(ould)e(indicate)g(that)i(the)f(\014rst)f(NULL)h(is)f(lo)s(cated)h(in)f
+(the)h(30th)227 4735 y(c)m(haracter)28 b(of)f(the)g(second)f(k)m(eyw)m
+(ord)h(in)e(the)i(header)f(\(recall)g(that)h(eac)m(h)h(header)e(record)
+h(is)e(80)i(c)m(haracters)227 4848 y(long\).)55 b(Note)36
+b(that)g(this)e(is)g(one)h(of)g(the)g(few)g(FITSIO)f(routines)g(in)f
+(whic)m(h)h(the)h(returned)f(v)-5 b(alue)35 b(is)f(not)227
+4961 y(necessarily)c(equal)f(to)j(the)e(status)h(v)-5
+b(alue\).)382 5216 y Fe(FTNCHK\(unit,)44 b(>)k(status\))0
+5470 y Fh(7)81 b Fi(P)m(arse)27 b(a)f(header)h(k)m(eyw)m(ord)g(record)f
+(and)g(return)f(the)i(name)f(of)h(the)f(k)m(eyw)m(ord)h(and)f(the)h
+(length)e(of)i(the)g(name.)227 5583 y(The)34 b(k)m(eyw)m(ord)h(name)f
+(normally)f(o)s(ccupies)g(the)i(\014rst)e(8)i(c)m(haracters)g(of)g(the)
+f(record,)i(except)f(under)e(the)227 5696 y(HIERAR)m(CH)e(con)m(v)m(en)
+m(tion)g(where)f(the)h(name)f(can)h(b)s(e)f(up)f(to)i(70)g(c)m
+(haracters)h(in)d(length.)p eop
+%%Page: 103 109
+103 108 bop 0 299 a Fg(9.12.)73 b(GENERAL)30 b(UTILITY)g(SUBR)m
+(OUTINES)1934 b Fi(103)382 555 y Fe(FTGKNM\(card,)44
+b(>)k(keyname,)d(keylength,)g(status\))0 811 y Fh(8)81
+b Fi(P)m(arse)34 b(a)h(header)f(k)m(eyw)m(ord)h(record.)52
+b(This)32 b(subroutine)g(parses)i(the)g(input)f(header)h(record)g(to)h
+(return)e(the)227 924 y(v)-5 b(alue)26 b(\(as)h(a)g(c)m(haracter)g
+(string\))f(and)g(commen)m(t)h(strings.)38 b(If)26 b(the)g(k)m(eyw)m
+(ord)h(has)f(no)g(v)-5 b(alue)26 b(\(columns)f(9-10)227
+1037 y(not)i(equal)e(to)i('=)f('\),)i(then)e(the)g(v)-5
+b(alue)26 b(string)f(is)g(returned)g(blank)g(and)g(the)h(commen)m(t)i
+(string)d(is)g(set)h(equal)227 1150 y(to)31 b(column)f(9)g(-)h(80)g(of)
+g(the)f(input)f(string.)382 1406 y Fe(FTPSVC\(card,)44
+b(>)k(value,comment,status\))0 1662 y Fh(9)81 b Fi(Construct)35
+b(a)i(sequence)f(k)m(eyw)m(ord)h(name)f(\(R)m(OOT)g(+)g(nnn\).)57
+b(This)34 b(subroutine)g(app)s(ends)g(the)j(sequence)227
+1775 y(n)m(um)m(b)s(er)29 b(to)i(the)g(ro)s(ot)g(string)e(to)i(create)h
+(a)f(k)m(eyw)m(ord)g(name)f(\(e.g.,)i('NAXIS')f(+)f(2)h(=)f('NAXIS2'\))
+382 2032 y Fe(FTKEYN\(keyroot,seq_no,)42 b(>)47 b(keyword,status\))0
+2288 y Fh(10)f Fi(Construct)30 b(a)g(sequence)g(k)m(eyw)m(ord)h(name)f
+(\(n)f(+)h(R)m(OOT\).)g(This)e(subroutine)g(concatenates)k(the)f
+(sequence)227 2401 y(n)m(um)m(b)s(er)20 b(to)j(the)e(fron)m(t)h(of)g
+(the)f(ro)s(ot)h(string)f(to)h(create)h(a)f(k)m(eyw)m(ord)g(name)g
+(\(e.g.,)j(1)d(+)f('CTYP')g(=)g('1CTYP'\))382 2657 y
+Fe(FTNKEY\(seq_no,keyroot,)42 b(>)47 b(keyword,status\))0
+2913 y Fh(11)f Fi(Determine)34 b(the)g(datat)m(yp)s(e)g(of)g(a)g(k)m
+(eyw)m(ord)h(v)-5 b(alue)33 b(string.)49 b(This)32 b(subroutine)g
+(parses)h(the)h(k)m(eyw)m(ord)g(v)-5 b(alue)227 3026
+y(string)30 b(\(usually)e(columns)h(11-30)k(of)d(the)h(header)f
+(record\))g(to)i(determine)d(its)h(datat)m(yp)s(e.)382
+3282 y Fe(FTDTYP\(value,)44 b(>)j(dtype,status\))0 3538
+y Fh(11)f Fi(Return)c(the)i(class)f(of)g(input)e(header)i(record.)79
+b(The)43 b(record)g(is)f(classi\014ed)f(in)m(to)i(one)h(of)f(the)g
+(follo)m(wing)227 3651 y(categories)35 b(\(the)f(class)e(v)-5
+b(alues)33 b(are)g(de\014ned)f(in)g(\014tsio.h\).)48
+b(Note)35 b(that)e(this)f(is)g(one)i(of)f(the)g(few)g(FITSIO)227
+3764 y(routines)d(that)g(do)s(es)h(not)f(return)f(a)i(status)g(v)-5
+b(alue.)334 4020 y Fe(Class)94 b(Value)619 b(Keywords)95
+4133 y(TYP_STRUC_KEY)92 b(10)j(SIMPLE,)46 b(BITPIX,)g(NAXIS,)g(NAXISn,)
+g(EXTEND,)g(BLOCKED,)1002 4246 y(GROUPS,)g(PCOUNT,)g(GCOUNT,)g(END)1002
+4359 y(XTENSION,)g(TFIELDS,)f(TTYPEn,)h(TBCOLn,)g(TFORMn,)g(THEAP,)1002
+4472 y(and)h(the)g(first)f(4)i(COMMENT)e(keywords)f(in)i(the)g(primary)
+f(array)1002 4585 y(that)h(define)f(the)h(FITS)g(format.)95
+4698 y(TYP_CMPRS_KEY)92 b(20)j(The)47 b(experimental)e(keywords)g(used)
+i(in)g(the)g(compressed)1002 4811 y(image)g(format)f(ZIMAGE,)g
+(ZCMPTYPE,)f(ZNAMEn,)h(ZVALn,)1002 4924 y(ZTILEn,)g(ZBITPIX,)g
+(ZNAXISn,)f(ZSCALE,)h(ZZERO,)g(ZBLANK)95 5036 y(TYP_SCAL_KEY)140
+b(30)95 b(BSCALE,)46 b(BZERO,)g(TSCALn,)g(TZEROn)95 5149
+y(TYP_NULL_KEY)140 b(40)95 b(BLANK,)46 b(TNULLn)95 5262
+y(TYP_DIM_KEY)188 b(50)95 b(TDIMn)95 5375 y(TYP_RANG_KEY)140
+b(60)95 b(TLMINn,)46 b(TLMAXn,)g(TDMINn,)g(TDMAXn,)g(DATAMIN,)f
+(DATAMAX)95 5488 y(TYP_UNIT_KEY)140 b(70)95 b(BUNIT,)46
+b(TUNITn)95 5601 y(TYP_DISP_KEY)140 b(80)95 b(TDISPn)95
+5714 y(TYP_HDUID_KEY)d(90)j(EXTNAME,)46 b(EXTVER,)g(EXTLEVEL,)f
+(HDUNAME,)g(HDUVER,)h(HDULEVEL)p eop
+%%Page: 104 110
+104 109 bop 0 299 a Fi(104)1274 b Fg(CHAPTER)29 b(9.)112
+b(AD)m(V)-10 b(ANCED)32 b(INTERF)-10 b(A)m(CE)30 b(SUBR)m(OUTINES)95
+555 y Fe(TYP_CKSUM_KEY)45 b(100)94 b(CHECKSUM,)46 b(DATASUM)95
+668 y(TYP_WCS_KEY)141 b(110)94 b(CTYPEn,)46 b(CUNITn,)g(CRVALn,)g
+(CRPIXn,)g(CROTAn,)f(CDELTn)1002 781 y(CDj_is,)h(PVj_ms,)g(LONPOLEs,)f
+(LATPOLEs)1002 894 y(TCTYPn,)h(TCTYns,)g(TCUNIn,)g(TCUNns,)g(TCRVLn,)f
+(TCRVns,)h(TCRPXn,)1002 1007 y(TCRPks,)g(TCDn_k,)g(TCn_ks,)g(TPVn_m,)g
+(TPn_ms,)f(TCDLTn,)h(TCROTn)1002 1120 y(jCTYPn,)g(jCTYns,)g(jCUNIn,)g
+(jCUNns,)g(jCRVLn,)f(jCRVns,)h(iCRPXn,)1002 1233 y(iCRPns,)g(jiCDn,)94
+b(jiCDns,)46 b(jPVn_m,)g(jPn_ms,)f(jCDLTn,)h(jCROTn)1002
+1346 y(\(i,j,m,n)g(are)h(integers,)e(s)i(is)h(any)f(letter\))95
+1458 y(TYP_REFSYS_KEY)d(120)j(EQUINOXs,)f(EPOCH,)g(MJD-OBSs,)f
+(RADECSYS,)g(RADESYSs)95 1571 y(TYP_COMM_KEY)140 b(130)47
+b(COMMENT,)f(HISTORY,)f(\(blank)h(keyword\))95 1684 y(TYP_CONT_KEY)140
+b(140)47 b(CONTINUE)95 1797 y(TYP_USER_KEY)140 b(150)47
+b(all)g(other)g(keywords)430 2023 y(class)f(=)h(FTGKCL)f(\(char)h
+(*card\))0 2275 y Fh(12)f Fi(P)m(arse)f(the)g('TF)m(ORM')h(binary)d
+(table)i(column)e(format)i(string.)83 b(This)43 b(subroutine)g(parses)h
+(the)h(input)227 2388 y(TF)m(ORM)27 b(c)m(haracter)g(string)e(and)h
+(returns)f(the)h(in)m(teger)g(datat)m(yp)s(e)h(co)s(de,)h(the)e(rep)s
+(eat)g(coun)m(t)h(of)f(the)g(\014eld,)227 2501 y(and,)f(in)d(the)i
+(case)g(of)g(c)m(haracter)h(string)d(\014elds,)i(the)f(length)g(of)h
+(the)g(unit)e(string.)37 b(The)23 b(follo)m(wing)f(datat)m(yp)s(e)227
+2613 y(co)s(des)h(are)h(returned)e(\(the)h(negativ)m(e)h(of)g(the)f(v)
+-5 b(alue)22 b(is)g(returned)g(if)g(the)h(column)f(con)m(tains)h(v)-5
+b(ariable-length)227 2726 y(arra)m(ys\):)764 2978 y Fe(Datatype)761
+b(DATACODE)46 b(value)764 3091 y(bit,)g(X)907 b(1)764
+3204 y(byte,)46 b(B)811 b(11)764 3317 y(logical,)45 b(L)668
+b(14)764 3430 y(ASCII)46 b(character,)f(A)286 b(16)764
+3543 y(short)46 b(integer,)g(I)381 b(21)764 3656 y(integer,)45
+b(J)668 b(41)764 3768 y(real,)46 b(E)811 b(42)764 3881
+y(double)46 b(precision,)f(D)238 b(82)764 3994 y(complex)809
+b(83)764 4107 y(double)46 b(complex)475 b(163)382 4333
+y(FTBNFM\(tform,)44 b(>)j(datacode,repeat,width,stat)o(us\))0
+4585 y Fh(13)f Fi(P)m(arse)38 b(the)f('TF)m(ORM')h(k)m(eyw)m(ord)g(v)-5
+b(alue)36 b(that)i(de\014nes)e(the)h(column)f(format)i(in)d(an)i(ASCI)s
+(I)f(table.)61 b(This)227 4698 y(routine)30 b(parses)h(the)g(input)f
+(TF)m(ORM)h(c)m(haracter)i(string)d(and)g(returns)g(the)i(datat)m(yp)s
+(e)g(co)s(de,)f(the)h(width)227 4811 y(of)40 b(the)h(column,)g(and)f
+(\(if)f(it)g(is)h(a)g(\015oating)g(p)s(oin)m(t)f(column\))g(the)h(n)m
+(um)m(b)s(er)f(of)h(decimal)f(places)h(to)h(the)227 4924
+y(righ)m(t)27 b(of)h(the)f(decimal)f(p)s(oin)m(t.)39
+b(The)27 b(returned)f(datat)m(yp)s(e)i(co)s(des)f(are)h(the)g(same)f
+(as)h(for)f(the)g(binary)f(table,)227 5036 y(listed)39
+b(ab)s(o)m(v)m(e,)44 b(with)39 b(the)h(follo)m(wing)f(additional)f
+(rules:)59 b(in)m(teger)41 b(columns)e(that)h(are)h(b)s(et)m(w)m(een)g
+(1)g(and)227 5149 y(4)36 b(c)m(haracters)i(wide)c(are)j(de\014ned)d(to)
+j(b)s(e)e(short)h(in)m(tegers)g(\(co)s(de)g(=)g(21\).)58
+b(Wider)35 b(in)m(teger)h(columns)f(are)227 5262 y(de\014ned)k(to)i(b)s
+(e)e(regular)g(in)m(tegers)i(\(co)s(de)f(=)g(41\).)71
+b(Similarly)-8 b(,)39 b(Fixed)g(decimal)g(p)s(oin)m(t)g(columns)g
+(\(with)227 5375 y(TF)m(ORM)30 b(=)g('Fw.d'\))g(are)g(de\014ned)f(to)h
+(b)s(e)g(single)e(precision)g(reals)h(\(co)s(de)i(=)e(42\))i(if)e(w)g
+(is)g(b)s(et)m(w)m(een)h(1)h(and)227 5488 y(7)i(c)m(haracters)h(wide,)e
+(inclusiv)m(e.)44 b(Wider)31 b('F')i(columns)e(will)f(return)h(a)i
+(double)e(precision)f(data)j(co)s(de)g(\(=)227 5601 y(82\).)54
+b('Ew.d')34 b(format)g(columns)f(will)f(ha)m(v)m(e)j(dataco)s(de)g(=)f
+(42,)j(and)c('Dw.d')i(format)f(columns)f(will)f(ha)m(v)m(e)227
+5714 y(dataco)s(de)g(=)e(82.)p eop
+%%Page: 105 111
+105 110 bop 0 299 a Fg(9.12.)73 b(GENERAL)30 b(UTILITY)g(SUBR)m
+(OUTINES)1934 b Fi(105)382 555 y Fe(FTASFM\(tform,)44
+b(>)j(datacode,width,decimals,st)o(atus)o(\))0 825 y
+Fh(14)f Fi(Calculate)30 b(the)h(starting)f(column)g(p)s(ositions)e(and)
+i(total)h(ASCI)s(I)e(table)i(width)d(based)j(on)f(the)h(input)d(arra)m
+(y)227 938 y(of)f(ASCI)s(I)e(table)h(TF)m(ORM)h(v)-5
+b(alues.)39 b(The)26 b(SP)-8 b(A)m(CE)27 b(input)d(parameter)j
+(de\014nes)f(ho)m(w)h(man)m(y)f(blank)g(spaces)227 1051
+y(to)40 b(lea)m(v)m(e)h(b)s(et)m(w)m(een)f(eac)m(h)g(column)f(\(it)g
+(is)f(recommended)h(to)h(ha)m(v)m(e)h(one)e(space)h(b)s(et)m(w)m(een)g
+(columns)e(for)227 1164 y(b)s(etter)31 b(h)m(uman)e(readabilit)m(y\).)
+382 1434 y Fe(FTGABC\(tfields,tform,spa)o(ce,)41 b(>)48
+b(rowlen,tbcol,status\))0 1704 y Fh(15)e Fi(P)m(arse)36
+b(a)f(template)g(string)f(and)h(return)f(a)h(formatted)h(80-c)m
+(haracter)h(string)d(suitable)g(for)h(app)s(ending)d(to)227
+1817 y(\(or)40 b(deleting)f(from\))g(a)h(FITS)f(header)h(\014le.)67
+b(This)38 b(subroutine)f(is)i(useful)f(for)h(parsing)f(lines)g(from)h
+(an)227 1930 y(ASCI)s(I)34 b(template)i(\014le)f(and)f(reformatting)i
+(them)f(in)m(to)h(legal)f(FITS)f(header)i(records.)55
+b(The)35 b(formatted)227 2043 y(string)30 b(ma)m(y)h(then)f(b)s(e)g
+(passed)g(to)i(the)e(FTPREC,)h(FTMCRD,)g(or)f(FTDKEY)h(subroutines)d
+(to)k(app)s(end)227 2156 y(or)f(mo)s(dify)d(a)j(FITS)f(header)g
+(record.)382 2426 y Fe(FTGTHD\(template,)43 b(>)48 b
+(card,hdtype,status\))0 2696 y Fi(The)23 b(input)g(TEMPLA)-8
+b(TE)23 b(c)m(haracter)j(string)d(generally)g(should)f(con)m(tain)i(3)h
+(tok)m(ens:)38 b(\(1\))25 b(the)f(KEYNAME,)h(\(2\))0
+2809 y(the)h(V)-10 b(ALUE,)26 b(and)f(\(3\))i(the)f(COMMENT)g(string.)
+38 b(The)25 b(TEMPLA)-8 b(TE)26 b(string)f(m)m(ust)g(adhere)h(to)g(the)
+g(follo)m(wing)0 2922 y(format:)0 3192 y Fh(-)80 b Fi(The)24
+b(KEYNAME)g(tok)m(en)h(m)m(ust)e(b)s(egin)g(in)f(columns)h(1-8)i(and)e
+(b)s(e)h(a)g(maxim)m(um)f(of)h(8)g(c)m(haracters)h(long.)38
+b(If)24 b(the)227 3305 y(\014rst)32 b(8)h(c)m(haracters)h(of)e(the)h
+(template)g(line)d(are)j(blank)e(then)h(the)h(remainder)e(of)h(the)h
+(line)e(is)g(considered)227 3418 y(to)42 b(b)s(e)e(a)h(FITS)f(commen)m
+(t)h(\(with)f(a)h(blank)e(k)m(eyw)m(ord)i(name\).)72
+b(A)41 b(legal)g(FITS)f(k)m(eyw)m(ord)h(name)f(ma)m(y)227
+3531 y(only)34 b(con)m(tain)i(the)f(c)m(haracters)h(A-Z,)f(0-9,)j(and)c
+('-')i(\(min)m(us)e(sign\))g(and)g(underscore.)54 b(This)33
+b(subroutine)227 3644 y(will)39 b(automatically)i(con)m(v)m(ert)i(an)m
+(y)f(lo)m(w)m(ercase)h(c)m(haracters)f(to)h(upp)s(ercase)d(in)g(the)i
+(output)f(string.)72 b(If)227 3757 y(KEYNAME)33 b(=)f('COMMENT')h(or)g
+('HISTOR)-8 b(Y')32 b(then)h(the)f(remainder)f(of)i(the)g(line)e(is)h
+(considered)f(to)227 3870 y(b)s(e)f(a)h(FITS)e(COMMENT)h(or)h(HISTOR)-8
+b(Y)30 b(record,)g(resp)s(ectiv)m(ely)-8 b(.)0 4140 y
+Fh(-)80 b Fi(The)26 b(V)-10 b(ALUE)26 b(tok)m(en)h(m)m(ust)e(b)s(e)h
+(separated)g(from)f(the)i(KEYNAME)f(tok)m(en)h(b)m(y)f(one)g(or)g(more)
+g(spaces)g(and/or)227 4253 y(an)i('=')g(c)m(haracter.)41
+b(The)27 b(datat)m(yp)s(e)i(of)f(the)g(V)-10 b(ALUE)27
+b(tok)m(en)i(\(n)m(umeric,)f(logical,)g(or)g(c)m(haracter)h(string\))e
+(is)227 4366 y(automatically)32 b(determined)e(and)i(the)g(output)f
+(CARD)h(string)f(is)g(formatted)h(accordingly)-8 b(.)45
+b(The)31 b(v)-5 b(alue)227 4478 y(tok)m(en)34 b(ma)m(y)f(b)s(e)f
+(forced)g(to)i(b)s(e)e(in)m(terpreted)f(as)i(a)g(string)f(\(e.g.)48
+b(if)32 b(it)g(is)f(a)i(string)f(of)g(n)m(umeric)g(digits\))f(b)m(y)227
+4591 y(enclosing)f(it)g(in)f(single)g(quotes.)0 4862
+y Fh(-)80 b Fi(The)37 b(COMMENT)f(tok)m(en)i(is)e(optional,)i(but)f(if)
+f(presen)m(t)h(m)m(ust)f(b)s(e)h(separated)g(from)g(the)g(V)-10
+b(ALUE)37 b(tok)m(en)227 4974 y(b)m(y)j(at)h(least)g(one)f(blank)f
+(space.)70 b(A)40 b(leading)f('/')i(c)m(haracter)h(ma)m(y)f(b)s(e)e
+(used)h(to)g(mark)g(the)h(b)s(eginning)227 5087 y(of)33
+b(the)f(commen)m(t)h(\014eld,)f(otherwise)f(the)i(commen)m(t)g(\014eld)
+e(b)s(egins)f(with)h(the)h(\014rst)g(non-blank)e(c)m(haracter)227
+5200 y(follo)m(wing)f(the)i(v)-5 b(alue)30 b(tok)m(en.)0
+5470 y Fh(-)80 b Fi(One)32 b(exception)h(to)g(the)g(ab)s(o)m(v)m(e)h
+(rules)d(is)g(that)i(if)f(the)g(\014rst)g(non-blank)f(c)m(haracter)j
+(in)d(the)i(template)g(string)227 5583 y(is)h(a)h(min)m(us)e(sign)h
+(\('-'\))i(follo)m(w)m(ed)e(b)m(y)h(a)g(single)e(tok)m(en,)k(or)e(a)g
+(single)e(tok)m(en)j(follo)m(w)m(ed)e(b)m(y)h(an)f(equal)h(sign,)227
+5696 y(then)29 b(it)f(is)g(in)m(terpreted)f(as)i(the)g(name)g(of)g(a)g
+(k)m(eyw)m(ord)g(whic)m(h)e(is)h(to)h(b)s(e)f(deleted)h(from)f(the)h
+(FITS)f(header.)p eop
+%%Page: 106 112
+106 111 bop 0 299 a Fi(106)1274 b Fg(CHAPTER)29 b(9.)112
+b(AD)m(V)-10 b(ANCED)32 b(INTERF)-10 b(A)m(CE)30 b(SUBR)m(OUTINES)0
+555 y Fh(-)80 b Fi(The)40 b(second)g(exception)g(is)f(that)i(if)e(the)h
+(template)g(string)f(starts)h(with)f(a)i(min)m(us)d(sign)h(and)g(is)g
+(follo)m(w)m(ed)227 668 y(b)m(y)33 b(2)g(tok)m(ens)g(then)g(the)f
+(second)h(tok)m(en)h(is)d(in)m(terpreted)h(as)h(the)g(new)f(name)g(for)
+h(the)g(k)m(eyw)m(ord)g(sp)s(eci\014ed)227 781 y(b)m(y)h(\014rst)e(tok)
+m(en.)52 b(In)33 b(this)f(case)j(the)e(old)g(k)m(eyw)m(ord)h(name)g
+(\(\014rst)f(tok)m(en\))i(is)d(returned)h(in)f(c)m(haracters)j(1-8)227
+894 y(of)e(the)g(returned)e(CARD)i(string,)f(and)g(the)h(new)f(k)m(eyw)
+m(ord)h(name)g(\(the)g(second)f(tok)m(en\))i(is)e(returned)f(in)227
+1007 y(c)m(haracters)c(41-48)h(of)e(the)f(returned)g(CARD)g(string.)39
+b(These)25 b(old)g(and)g(new)g(names)g(ma)m(y)h(then)f(b)s(e)g(passed)
+227 1120 y(to)31 b(the)g(FTMNAM)g(subroutine)e(whic)m(h)g(will)e(c)m
+(hange)32 b(the)e(k)m(eyw)m(ord)h(name.)0 1361 y(The)f(HDTYPE)g(output)
+g(parameter)h(indicates)e(ho)m(w)i(the)f(returned)g(CARD)g(string)f
+(should)g(b)s(e)h(in)m(terpreted:)382 1602 y Fe(hdtype)857
+b(interpretation)382 1715 y(------)523 b(-------------------------)o
+(----)o(---)o(----)o(----)o(---)o(----)o(--)525 1828
+y(-2)572 b(Modify)46 b(the)h(name)g(of)g(the)g(keyword)f(given)g(in)h
+(CARD\(1:8\))1193 1941 y(to)g(the)g(new)g(name)g(given)f(in)h
+(CARD\(41:48\))525 2167 y(-1)572 b(CARD\(1:8\))45 b(contains)h(the)h
+(name)g(of)g(a)g(keyword)f(to)h(be)g(deleted)1193 2280
+y(from)g(the)g(FITS)f(header.)573 2506 y(0)572 b(append)46
+b(the)h(CARD)g(string)f(to)h(the)g(FITS)g(header)f(if)h(the)1193
+2619 y(keyword)f(does)h(not)g(already)e(exist,)h(otherwise)g(update)
+1193 2732 y(the)h(value/comment)d(if)j(the)g(keyword)f(is)h(already)f
+(present)1193 2844 y(in)h(the)g(header.)573 3070 y(1)572
+b(simply)46 b(append)g(this)h(keyword)f(to)h(the)g(FITS)g(header)f
+(\(CARD)1193 3183 y(is)h(either)f(a)i(HISTORY)e(or)h(COMMENT)f
+(keyword\).)573 3409 y(2)572 b(This)47 b(is)g(a)g(FITS)g(END)g(record;)
+f(it)h(should)f(not)h(be)g(written)1193 3522 y(to)g(the)g(FITS)g
+(header)f(because)g(FITSIO)g(automatically)1193 3635
+y(appends)g(the)h(END)g(record)f(when)h(the)f(header)h(is)g(closed.)0
+3876 y Fi(EXAMPLES:)30 b(The)g(follo)m(wing)f(lines)f(illustrate)h(v)-5
+b(alid)29 b(input)f(template)j(strings:)286 4118 y Fe(INTVAL)46
+b(7)i(This)f(is)g(an)g(integer)f(keyword)286 4231 y(RVAL)524
+b(34.6)142 b(/)239 b(This)46 b(is)i(a)f(floating)f(point)g(keyword)286
+4343 y(EVAL=-12.45E-03)92 b(This)46 b(is)i(a)f(floating)f(point)g
+(keyword)g(in)h(exponential)e(notation)286 4456 y(lval)i(F)g(This)g(is)
+g(a)h(boolean)e(keyword)859 4569 y(This)h(is)g(a)g(comment)f(keyword)g
+(with)h(a)g(blank)f(keyword)g(name)286 4682 y(SVAL1)h(=)g('Hello)f
+(world')142 b(/)95 b(this)47 b(is)g(a)g(string)f(keyword)286
+4795 y(SVAL2)94 b('123.5')g(this)47 b(is)g(also)f(a)i(string)e(keyword)
+286 4908 y(sval3)94 b(123+)h(/)g(this)47 b(is)g(also)f(a)i(string)e
+(keyword)g(with)g(the)h(value)g('123+)189 b(')286 5021
+y(#)48 b(the)f(following)e(template)h(line)g(deletes)g(the)h(DATE)g
+(keyword)286 5134 y(-)h(DATE)286 5247 y(#)g(the)f(following)e(template)
+h(line)g(modifies)g(the)h(NAME)f(keyword)g(to)h(OBJECT)286
+5360 y(-)h(NAME)e(OBJECT)0 5601 y Fh(16)g Fi(P)m(arse)35
+b(the)g(input)e(string)h(con)m(taining)g(a)h(list)f(of)h(ro)m(ws)f(or)h
+(ro)m(w)g(ranges,)h(and)e(return)g(in)m(teger)h(arra)m(ys)g(con-)227
+5714 y(taining)25 b(the)h(\014rst)f(and)g(last)h(ro)m(w)g(in)e(eac)m(h)
+j(range.)40 b(F)-8 b(or)26 b(example,)h(if)d(ro)m(wlist)h(=)g("3-5,)k
+(6,)e(8-9")h(then)d(it)h(will)p eop
+%%Page: 107 113
+107 112 bop 0 299 a Fg(9.12.)73 b(GENERAL)30 b(UTILITY)g(SUBR)m
+(OUTINES)1934 b Fi(107)227 555 y(return)34 b(n)m(umranges)h(=)g(3,)h
+(rangemin)e(=)h(3,)i(6,)g(8)e(and)g(rangemax)g(=)g(5,)i(6,)g(9.)55
+b(A)m(t)36 b(most,)h('maxranges')227 668 y(n)m(um)m(b)s(er)31
+b(of)h(ranges)f(will)e(b)s(e)j(returned.)43 b('maxro)m(ws')32
+b(is)f(the)h(maxim)m(um)f(n)m(um)m(b)s(er)f(of)i(ro)m(ws)g(in)e(the)i
+(table;)227 781 y(an)m(y)e(ro)m(ws)f(or)g(ranges)g(larger)g(than)g
+(this)f(will)e(b)s(e)j(ignored.)39 b(The)29 b(ro)m(ws)g(m)m(ust)g(b)s
+(e)f(sp)s(eci\014ed)g(in)f(increasing)227 894 y(order,)33
+b(and)f(the)g(ranges)h(m)m(ust)f(not)g(o)m(v)m(erlap.)47
+b(A)33 b(min)m(us)d(sign)i(ma)m(y)h(b)s(e)e(use)h(to)h(sp)s(ecify)e
+(all)g(the)i(ro)m(ws)f(to)227 1007 y(the)h(upp)s(er)d(or)j(lo)m(w)m(er)
+g(b)s(ound,)e(so)i("50-")h(means)e(all)g(the)h(ro)m(ws)f(from)g(50)h
+(to)h(the)e(end)g(of)h(the)f(table,)i(and)227 1120 y("-")e(means)e(all)
+f(the)i(ro)m(ws)f(in)f(the)i(table,)f(from)g(1)h(-)g(maxro)m(ws.)191
+1380 y Fe(FTRWRG\(rowlist,)44 b(maxrows,)h(maxranges,)g(>)525
+1492 y(numranges,)g(rangemin,)g(rangemax,)h(status\))p
+eop
+%%Page: 108 114
+108 113 bop 0 299 a Fi(108)1274 b Fg(CHAPTER)29 b(9.)112
+b(AD)m(V)-10 b(ANCED)32 b(INTERF)-10 b(A)m(CE)30 b(SUBR)m(OUTINES)p
+eop
+%%Page: 109 115
+109 114 bop 0 1225 a Ff(Chapter)65 b(10)0 1687 y Fl(Summary)76
+b(of)i(all)f(FITSIO)0 1937 y(User-In)-6 b(terface)77
+b(Subroutines)0 2429 y Fi(Error)29 b(Status)i(Routines)e(page)i(63)382
+2696 y Fe(FTVERS\()46 b(>)h(version\))382 2809 y(FTGERR\(status,)d(>)j
+(errtext\))382 2922 y(FTGMSG\()f(>)h(errmsg\))382 3035
+y(FTRPRT)f(\(stream,)f(>)j(status\))382 3147 y(FTPMSG\(errmsg\))382
+3260 y(FTPMRK)382 3373 y(FTCMSG)382 3486 y(FTCMRK)0 3753
+y Fi(FITS)30 b(File)f(Op)s(en)g(and)h(Close)g(Subroutines:)38
+b(page)31 b(69)382 4020 y Fe(FTOPEN\(unit,filename,rwm)o(ode)o(,)42
+b(>)47 b(blocksize,status\))382 4133 y(FTDKOPEN\(unit,filename,r)o(wmo)
+o(de,)41 b(>)48 b(blocksize,status\))382 4246 y
+(FTNOPN\(unit,filename,rwm)o(ode)o(,)42 b(>)47 b(status\))382
+4359 y(FTDOPN\(unit,filename,rwm)o(ode)o(,)42 b(>)47
+b(status\))382 4472 y(FTTOPN\(unit,filename,rwm)o(ode)o(,)42
+b(>)47 b(status\))382 4585 y(FTIOPN\(unit,filename,rwm)o(ode)o(,)42
+b(>)47 b(status\))382 4698 y(FTREOPEN\(unit,)d(>)j(newunit,)f(status\))
+382 4811 y(FTINIT\(unit,filename,blo)o(cks)o(ize,)41
+b(>)48 b(status\))382 4924 y(FTDKINIT\(unit,filename,b)o(loc)o(ksiz)o
+(e,)42 b(>)47 b(status\))382 5036 y(FTTPLT\(unit,)d(filename,)i
+(tplfilename,)e(>)j(status\))382 5149 y(FTFLUS\(unit,)d(>)k(status\))
+382 5262 y(FTCLOS\(unit,)c(>)k(status\))382 5375 y(FTDELT\(unit,)c(>)k
+(status\))382 5488 y(FTGIOU\()e(>)h(iounit,)f(status\))382
+5601 y(FTFIOU\(iounit,)e(>)j(status\))0 5714 y(CFITS2Unit\(fitsfile)c
+(*ptr\))141 b(\(C)48 b(routine\))1882 5942 y Fi(109)p
+eop
+%%Page: 110 116
+110 115 bop 0 299 a Fi(110)281 b Fg(CHAPTER)30 b(10.)112
+b(SUMMAR)-8 b(Y)32 b(OF)e(ALL)g(FITSIO)f(USER-INTERF)-10
+b(A)m(CE)30 b(SUBR)m(OUTINES)382 555 y Fe(CUnit2FITS\(int)44
+b(unit\))380 b(\(C)47 b(routine\))382 668 y(FTEXTN\(filename,)c(>)48
+b(nhdu,)e(status\))382 781 y(FTFLNM\(unit,)e(>)k(filename,)d(status\))
+382 894 y(FTFLMD\(unit,)f(>)k(iomode,)e(status\))382
+1007 y(FFURLT\(unit,)e(>)k(urltype,)d(status\))382 1120
+y(FTIURL\(filename,)e(>)48 b(filetype,)d(infile,)h(outfile,)f(extspec,)
+h(filter,)716 1233 y(binspec,)f(colspec,)h(status\))382
+1346 y(FTRTNM\(filename,)d(>)48 b(rootname,)d(status\))382
+1458 y(FTEXIST\(filename,)e(>)k(exist,)f(status\))0 1695
+y Fi(HDU-Lev)m(el)32 b(Op)s(erations:)39 b(page)31 b(72)382
+1932 y Fe(FTMAHD\(unit,nhdu,)43 b(>)k(hdutype,status\))382
+2045 y(FTMRHD\(unit,nmove,)c(>)k(hdutype,status\))382
+2158 y(FTGHDN\(unit,)d(>)k(nhdu\))382 2271 y(FTMNHD\(unit,)c(hdutype,)i
+(extname,)f(extver,)h(>)i(status\))382 2384 y(FTGHDT\(unit,)c(>)k
+(hdutype,)d(status\))382 2497 y(FTTHDU\(unit,)f(>)k(hdunum,)e(status\))
+382 2610 y(FTCRHD\(unit,)e(>)k(status\))382 2723 y
+(FTIIMG\(unit,bitpix,naxis)o(,na)o(xes,)41 b(>)48 b(status\))382
+2836 y(FTITAB\(unit,rowlen,nrows)o(,tf)o(ield)o(s,tt)o(ype)o(,tbc)o
+(ol,t)o(for)o(m,tu)o(nit,)o(ext)o(name)o(,)42 b(>)716
+2949 y(status\))382 3061 y(FTIBIN\(unit,nrows,tfield)o(s,t)o(type)o
+(,tfo)o(rm,)o(tuni)o(t,ex)o(tna)o(me,v)o(arid)o(at)f(>)48
+b(status\))382 3174 y(FTRSIM\(unit,bitpix,naxis)o(,na)o(xes,)o(stat)o
+(us\))382 3287 y(FTDHDU\(unit,)c(>)k(hdutype,status\))382
+3400 y(FTCPFL\(iunit,ounit,previ)o(ous)o(,)42 b(current,)j(following,)g
+(>)j(status\))382 3513 y(FTCOPY\(iunit,ounit,morek)o(eys)o(,)42
+b(>)47 b(status\))382 3626 y(FTCPHD\(inunit,)d(outunit,)h(>)j(status\))
+382 3739 y(FTCPDT\(iunit,ounit,)42 b(>)48 b(status\))0
+3976 y Fi(Subroutines)28 b(to)j(sp)s(ecify)e(or)h(mo)s(dify)f(the)h
+(structure)g(of)h(the)f(CHDU:)h(page)h(75)382 4213 y
+Fe(FTRDEF\(unit,)44 b(>)k(status\))93 b(\(DEPRECATED\))382
+4326 y(FTPDEF\(unit,bitpix,naxis)o(,na)o(xes,)o(pcou)o(nt,)o(gcou)o
+(nt,)41 b(>)48 b(status\))93 b(\(DEPRECATED\))382 4439
+y(FTADEF\(unit,rowlen,tfiel)o(ds,)o(tbco)o(l,tf)o(orm)o(,nro)o(ws)42
+b(>)47 b(status\))94 b(\(DEPRECATED\))382 4551 y
+(FTBDEF\(unit,tfields,tfor)o(m,v)o(arid)o(at,n)o(row)o(s)42
+b(>)47 b(status\))94 b(\(DEPRECATED\))382 4664 y(FTDDEF\(unit,bytlen,)
+42 b(>)48 b(status\))93 b(\(DEPRECATED\))382 4777 y
+(FTPTHP\(unit,theap,)43 b(>)k(status\))0 5014 y Fi(Header)31
+b(Space)f(and)g(P)m(osition)g(Subroutines:)38 b(page)31
+b(76)382 5251 y Fe(FTHDEF\(unit,morekeys,)42 b(>)47 b(status\))382
+5364 y(FTGHSP\(iunit,)d(>)j(keysexist,keysadd,status\))382
+5477 y(FTGHPS\(iunit,)d(>)j(keysexist,key_no,status\))0
+5714 y Fi(Read)31 b(or)f(W)-8 b(rite)31 b(Standard)e(Header)i
+(Subroutines:)38 b(page)31 b(77)p eop
+%%Page: 111 117
+111 116 bop 3764 299 a Fi(111)382 555 y Fe(FTPHPS\(unit,bitpix,naxis)o
+(,na)o(xes,)41 b(>)48 b(status\))382 668 y(FTPHPR\(unit,simple,bitpi)o
+(x,n)o(axis)o(,nax)o(es,)o(pcou)o(nt,g)o(cou)o(nt,e)o(xten)o(d,)41
+b(>)48 b(status\))382 781 y(FTGHPR\(unit,maxdim,)42 b(>)48
+b(simple,bitpix,naxis,naxe)o(s,p)o(coun)o(t,gc)o(oun)o(t,ex)o(tend)o(,)
+716 894 y(status\))382 1007 y(FTPHTB\(unit,rowlen,nrows)o(,tf)o(ield)o
+(s,tt)o(ype)o(,tbc)o(ol,t)o(for)o(m,tu)o(nit,)o(ext)o(name)o(,)42
+b(>)716 1120 y(status\))382 1233 y(FTGHTB\(unit,maxdim,)g(>)48
+b(rowlen,nrows,tfields,tty)o(pe,)o(tbco)o(l,tf)o(orm)o(,tun)o(it,)716
+1346 y(extname,status\))382 1458 y(FTPHBN\(unit,nrows,tfield)o(s,t)o
+(type)o(,tfo)o(rm,)o(tuni)o(t,ex)o(tna)o(me,v)o(arid)o(at)41
+b(>)48 b(status\))382 1571 y(FTGHBN\(unit,maxdim,)42
+b(>)48 b(nrows,tfields,ttype,tfor)o(m,t)o(unit)o(,ext)o(nam)o(e,va)o
+(rida)o(t,)716 1684 y(status\))0 1942 y Fi(W)-8 b(rite)31
+b(Keyw)m(ord)f(Subroutines:)38 b(page)31 b(78)382 2199
+y Fe(FTPREC\(unit,card,)43 b(>)k(status\))382 2312 y
+(FTPCOM\(unit,comment,)42 b(>)48 b(status\))382 2425
+y(FTPHIS\(unit,history,)42 b(>)48 b(status\))382 2538
+y(FTPDAT\(unit,)c(>)k(status\))382 2651 y(FTPKY[JLS]\(unit,keyword,)o
+(key)o(val,)o(comm)o(ent)o(,)42 b(>)47 b(status\))382
+2764 y(FTPKY[EDFG]\(unit,keyword)o(,ke)o(yval)o(,dec)o(ima)o(ls,c)o
+(omme)o(nt,)41 b(>)48 b(status\))382 2877 y(FTPKLS\(unit,keyword,keyv)o
+(al,)o(comm)o(ent,)41 b(>)47 b(status\))382 2990 y(FTPLSW\(unit,)d(>)k
+(status\))382 3103 y(FTPKYU\(unit,keyword,comm)o(ent)o(,)42
+b(>)47 b(status\))382 3216 y(FTPKN[JLS]\(unit,keyroot,)o(sta)o(rtno)o
+(,no_)o(key)o(s,ke)o(yval)o(s,c)o(omme)o(nts,)41 b(>)47
+b(status\))382 3329 y(FTPKN[EDFG]\(unit,keyroot)o(,st)o(artn)o(o,no)o
+(_ke)o(ys,k)o(eyva)o(ls,)o(deci)o(mals)o(,co)o(mmen)o(ts,)41
+b(>)907 3441 y(status\))382 3554 y(FTCPKYinunit,)j(outunit,)i(innum,)g
+(outnum,)f(keyroot,)h(>)h(status\))382 3667 y
+(FTPKYT\(unit,keyword,intv)o(al,)o(dblv)o(al,c)o(omm)o(ent,)41
+b(>)48 b(status\))382 3780 y(FTPKTP\(unit,)c(filename,)i(>)h(status\))
+382 3893 y(FTPUNT\(unit,keyword,unit)o(s,)41 b(>)48 b(status\))0
+4151 y Fi(Insert)30 b(Keyw)m(ord)g(Subroutines:)38 b(page)31
+b(80)382 4408 y Fe(FTIREC\(unit,key_no,card,)41 b(>)47
+b(status\))382 4521 y(FTIKY[JLS]\(unit,keyword,)o(key)o(val,)o(comm)o
+(ent)o(,)42 b(>)47 b(status\))382 4634 y(FTIKLS\(unit,keyword,keyv)o
+(al,)o(comm)o(ent,)41 b(>)47 b(status\))382 4747 y
+(FTIKY[EDFG]\(unit,keyword)o(,ke)o(yval)o(,dec)o(ima)o(ls,c)o(omme)o
+(nt,)41 b(>)48 b(status\))382 4860 y(FTIKYU\(unit,keyword,comm)o(ent)o
+(,)42 b(>)47 b(status\))0 5118 y Fi(Read)31 b(Keyw)m(ord)f
+(Subroutines:)38 b(page)31 b(81)382 5375 y Fe(FTGREC\(unit,key_no,)42
+b(>)48 b(card,status\))382 5488 y(FTGKYN\(unit,key_no,)42
+b(>)48 b(keyword,value,comment,st)o(atu)o(s\))382 5601
+y(FTGCRD\(unit,keyword,)42 b(>)48 b(card,status\))382
+5714 y(FTGNXK\(unit,inclist,ninc)o(,ex)o(clis)o(t,ne)o(xc,)41
+b(>)48 b(card,status\))p eop
+%%Page: 112 118
+112 117 bop 0 299 a Fi(112)281 b Fg(CHAPTER)30 b(10.)112
+b(SUMMAR)-8 b(Y)32 b(OF)e(ALL)g(FITSIO)f(USER-INTERF)-10
+b(A)m(CE)30 b(SUBR)m(OUTINES)382 555 y Fe(FTGKEY\(unit,keyword,)42
+b(>)48 b(value,comment,status\))382 668 y(FTGKY[EDJLS]\(unit,keywor)o
+(d,)41 b(>)48 b(keyval,comment,status\))382 781 y
+(FTGKN[EDJLS]\(unit,keyroo)o(t,s)o(tart)o(no,m)o(ax_)o(keys)o(,)42
+b(>)47 b(keyvals,nfound,status\))382 894 y(FTGKYT\(unit,keyword,)42
+b(>)48 b(intval,dblval,comment,s)o(tat)o(us\))382 1007
+y(FTGUNT\(unit,keyword,)42 b(>)48 b(units,status\))0
+1263 y Fi(Mo)s(dify)29 b(Keyw)m(ord)h(Subroutines:)38
+b(page)31 b(82)382 1519 y Fe(FTMREC\(unit,key_no,card,)41
+b(>)47 b(status\))382 1632 y(FTMCRD\(unit,keyword,card)o(,)42
+b(>)47 b(status\))382 1745 y(FTMNAM\(unit,oldkey,keywo)o(rd,)41
+b(>)48 b(status\))382 1858 y(FTMCOM\(unit,keyword,comm)o(ent)o(,)42
+b(>)47 b(status\))382 1971 y(FTMKY[JLS]\(unit,keyword,)o(key)o(val,)o
+(comm)o(ent)o(,)42 b(>)47 b(status\))382 2084 y
+(FTMKLS\(unit,keyword,keyv)o(al,)o(comm)o(ent,)41 b(>)47
+b(status\))382 2197 y(FTMKY[EDFG]\(unit,keyword)o(,ke)o(yval)o(,dec)o
+(ima)o(ls,c)o(omme)o(nt,)41 b(>)48 b(status\))382 2310
+y(FTMKYU\(unit,keyword,comm)o(ent)o(,)42 b(>)47 b(status\))0
+2566 y Fi(Up)s(date)30 b(Keyw)m(ord)g(Subroutines:)38
+b(page)32 b(83)382 2822 y Fe(FTUCRD\(unit,keyword,card)o(,)42
+b(>)47 b(status\))382 2935 y(FTUKY[JLS]\(unit,keyword,)o(key)o(val,)o
+(comm)o(ent)o(,)42 b(>)47 b(status\))382 3048 y
+(FTUKLS\(unit,keyword,keyv)o(al,)o(comm)o(ent,)41 b(>)47
+b(status\))382 3161 y(FTUKY[EDFG]\(unit,keyword)o(,ke)o(yval)o(,dec)o
+(ima)o(ls,c)o(omme)o(nt,)41 b(>)48 b(status\))382 3274
+y(FTUKYU\(unit,keyword,comm)o(ent)o(,)42 b(>)47 b(status\))0
+3530 y Fi(Delete)32 b(Keyw)m(ord)e(Subroutines:)38 b(page)31
+b(84)382 3786 y Fe(FTDREC\(unit,key_no,)42 b(>)48 b(status\))382
+3899 y(FTDKEY\(unit,keyword,)42 b(>)48 b(status\))0 4155
+y Fi(De\014ne)31 b(Data)h(Scaling)d(P)m(arameters)i(and)f(Unde\014ned)f
+(Pixel)g(Flags:)41 b(page)31 b(84)382 4411 y Fe
+(FTPSCL\(unit,bscale,bzero)o(,)42 b(>)47 b(status\))382
+4524 y(FTTSCL\(unit,colnum,tscal)o(,tz)o(ero,)41 b(>)48
+b(status\))382 4637 y(FTPNUL\(unit,blank,)43 b(>)k(status\))382
+4750 y(FTSNUL\(unit,colnum,snull)41 b(>)47 b(status\))382
+4863 y(FTTNUL\(unit,colnum,tnull)41 b(>)47 b(status\))0
+5119 y Fi(FITS)30 b(Primary)e(Arra)m(y)j(or)f(IMA)m(GE)i(Extension)d
+(I/O)i(Subroutines:)38 b(page)31 b(85)382 5375 y Fe(FTGIDT\(unit,)44
+b(>)k(bitpix,status\))382 5488 y(FTGIET\(unit,)c(>)k(bitpix,status\))
+382 5601 y(FTGIDM\(unit,)c(>)k(naxis,status\))382 5714
+y(FTGISZ\(unit,)c(maxdim,)i(>)i(naxes,status\))p eop
+%%Page: 113 119
+113 118 bop 3764 299 a Fi(113)382 555 y Fe(FTGIPR\(unit,)44
+b(maxdim,)i(>)i(bitpix,naxis,naxes,stat)o(us\))382 668
+y(FTPPR[BIJED]\(unit,group,)o(fpi)o(xel,)o(nele)o(men)o(ts,v)o(alue)o
+(s,)41 b(>)48 b(status\))382 781 y(FTPPN[BIJED]\(unit,group,)o(fpi)o
+(xel,)o(nele)o(men)o(ts,v)o(alue)o(s,n)o(ullv)o(al)42
+b(>)47 b(status\))382 894 y(FTPPRU\(unit,group,fpixel)o(,ne)o(leme)o
+(nts,)41 b(>)47 b(status\))382 1007 y(FTGPV[BIJED]\(unit,group,)o(fpi)o
+(xel,)o(nele)o(men)o(ts,n)o(ullv)o(al,)41 b(>)48 b
+(values,anyf,status\))382 1120 y(FTGPF[BIJED]\(unit,group,)o(fpi)o
+(xel,)o(nele)o(men)o(ts,)41 b(>)48 b(values,flagvals,anyf,sta)o(tus)o
+(\))382 1233 y(FTPGP[BIJED]\(unit,group,)o(fpa)o(rm,n)o(parm)o(,va)o
+(lues)o(,)42 b(>)47 b(status\))382 1346 y(FTGGP[BIJED]\(unit,group,)o
+(fpa)o(rm,n)o(parm)o(,)42 b(>)47 b(values,status\))382
+1458 y(FTP2D[BIJED]\(unit,group,)o(dim)o(1,na)o(xis1)o(,na)o(xis2)o
+(,ima)o(ge,)41 b(>)48 b(status\))382 1571 y(FTP3D[BIJED]\(unit,group,)o
+(dim)o(1,di)o(m2,n)o(axi)o(s1,n)o(axis)o(2,n)o(axis)o(3,cu)o(be,)41
+b(>)48 b(status\))382 1684 y(FTG2D[BIJED]\(unit,group,)o(nul)o(lval)o
+(,dim)o(1,n)o(axis)o(1,na)o(xis)o(2,)42 b(>)47 b(image,anyf,status\))
+382 1797 y(FTG3D[BIJED]\(unit,group,)o(nul)o(lval)o(,dim)o(1,d)o(im2,)o
+(naxi)o(s1,)o(naxi)o(s2,n)o(axi)o(s3,)41 b(>)1002 1910
+y(cube,anyf,status\))382 2023 y(FTPSS[BIJED]\(unit,group,)o(nax)o(is,n)
+o(axes)o(,fp)o(ixel)o(s,lp)o(ixe)o(ls,a)o(rray)o(,)h(>)47
+b(status\))382 2136 y(FTGSV[BIJED]\(unit,group,)o(nax)o(is,n)o(axes)o
+(,fp)o(ixel)o(s,lp)o(ixe)o(ls,i)o(ncs,)o(nul)o(lval)o(,)42
+b(>)1002 2249 y(array,anyf,status\))382 2362 y
+(FTGSF[BIJED]\(unit,group,)o(nax)o(is,n)o(axes)o(,fp)o(ixel)o(s,lp)o
+(ixe)o(ls,i)o(ncs,)f(>)1002 2475 y(array,flagvals,anyf,statu)o(s\))0
+2739 y Fi(T)-8 b(able)30 b(Column)e(Information)i(Subroutines:)38
+b(page)31 b(88)382 3003 y Fe(FTGNRW\(unit,)44 b(>)k(nrows,)e(status\))
+382 3115 y(FTGNCL\(unit,)e(>)k(ncols,)e(status\))382
+3228 y(FTGCNO\(unit,casesen,colt)o(emp)o(late)o(,)c(>)47
+b(colnum,status\))382 3341 y(FTGCNN\(unit,casesen,colt)o(emp)o(late)o
+(,)42 b(>)47 b(colnam,colnum,status\))382 3454 y(FTGTCL\(unit,colnum,)
+42 b(>)48 b(datacode,repeat,width,st)o(atu)o(s\))382
+3567 y(FTEQTY\(unit,colnum,)42 b(>)48 b(datacode,repeat,width,st)o(atu)
+o(s\))382 3680 y(FTGCDW\(unit,colnum,)42 b(>)48 b(dispwidth,status\))
+382 3793 y(FTGACL\(unit,colnum,)42 b(>)716 3906 y
+(ttype,tbcol,tunit,tform,)o(tsca)o(l,t)o(zero)o(,snu)o(ll,)o(tdis)o
+(p,st)o(atu)o(s\))382 4019 y(FTGBCL\(unit,colnum,)g(>)716
+4132 y(ttype,tunit,datatype,rep)o(eat,)o(tsc)o(al,t)o(zero)o(,tn)o
+(ull,)o(tdis)o(p,s)o(tatu)o(s\))382 4245 y(FTPTDM\(unit,colnum,naxis)o
+(,na)o(xes,)f(>)48 b(status\))382 4357 y(FTGTDM\(unit,colnum,maxdi)o
+(m,)41 b(>)48 b(naxis,naxes,status\))382 4470 y
+(FTDTDM\(unit,tdimstr,coln)o(um,)o(maxd)o(im,)41 b(>)48
+b(naxis,naxes,)c(status\))382 4583 y(FFGRSZ\(unit,)g(>)k
+(nrows,status\))0 4847 y Fi(Lo)m(w-Lev)m(el)31 b(T)-8
+b(able)30 b(Access)i(Subroutines:)38 b(page)31 b(91)382
+5111 y Fe(FTGTBS\(unit,frow,startch)o(ar,)o(ncha)o(rs,)41
+b(>)48 b(string,status\))382 5224 y(FTPTBS\(unit,frow,startch)o(ar,)o
+(ncha)o(rs,s)o(tri)o(ng,)41 b(>)48 b(status\))382 5337
+y(FTGTBB\(unit,frow,startch)o(ar,)o(ncha)o(rs,)41 b(>)48
+b(array,status\))382 5450 y(FTPTBB\(unit,frow,startch)o(ar,)o(ncha)o
+(rs,a)o(rra)o(y,)42 b(>)47 b(status\))0 5714 y Fi(Edit)29
+b(Ro)m(ws)i(or)f(Columns)f(page)i(92)p eop
+%%Page: 114 120
+114 119 bop 0 299 a Fi(114)281 b Fg(CHAPTER)30 b(10.)112
+b(SUMMAR)-8 b(Y)32 b(OF)e(ALL)g(FITSIO)f(USER-INTERF)-10
+b(A)m(CE)30 b(SUBR)m(OUTINES)382 555 y Fe(FTIROW\(unit,frow,nrows,)41
+b(>)48 b(status\))382 668 y(FTDROW\(unit,frow,nrows,)41
+b(>)48 b(status\))382 781 y(FTDRRG\(unit,rowrange,)42
+b(>)47 b(status\))382 894 y(FTDRWS\(unit,rowlist,nrow)o(s,)41
+b(>)48 b(status\))382 1007 y(FTICOL\(unit,colnum,ttype)o(,tf)o(orm,)41
+b(>)48 b(status\))382 1120 y(FTICLS\(unit,colnum,ncols)o(,tt)o(ype,)o
+(tfor)o(m,)41 b(>)48 b(status\))382 1233 y(FTMVEC\(unit,colnum,newve)o
+(cle)o(n,)42 b(>)47 b(status\))382 1346 y(FTDCOL\(unit,colnum,)42
+b(>)48 b(status\))382 1458 y(FTCPCL\(inunit,outunit,in)o(col)o(num,)o
+(outc)o(oln)o(um,c)o(reat)o(eco)o(l,)42 b(>)47 b(status\);)0
+1716 y Fi(Read)31 b(and)e(W)-8 b(rite)31 b(Column)e(Data)j(Routines)d
+(page)i(93)382 1974 y Fe(FTPCL[SLBIJEDCM]\(unit,co)o(lnu)o(m,fr)o(ow,f)
+o(ele)o(m,ne)o(leme)o(nts)o(,val)o(ues,)41 b(>)47 b(status\))382
+2087 y(FTPCN[BIJED]\(unit,colnum)o(,fr)o(ow,f)o(elem)o(,ne)o(leme)o
+(nts,)o(val)o(ues,)o(null)o(val)41 b(>)48 b(status\))382
+2199 y(FTPCLX\(unit,colnum,frow,)o(fbi)o(t,nb)o(it,l)o(ray)o(,)42
+b(>)47 b(status\))382 2312 y(FTPCLU\(unit,colnum,frow,)o(fel)o(em,n)o
+(elem)o(ent)o(s,)42 b(>)47 b(status\))382 2425 y
+(FTGCL\(unit,colnum,frow,f)o(ele)o(m,ne)o(leme)o(nts)o(,)42
+b(>)47 b(values,status\))382 2538 y(FTGCV[SBIJEDCM]\(unit,col)o(num)o
+(,fro)o(w,fe)o(lem)o(,nel)o(emen)o(ts,)o(null)o(val,)41
+b(>)1098 2651 y(values,anyf,status\))382 2764 y
+(FTGCF[SLBIJEDCM]\(unit,co)o(lnu)o(m,fr)o(ow,f)o(ele)o(m,ne)o(leme)o
+(nts)o(,)h(>)1193 2877 y(values,flagvals,anyf,stat)o(us\))382
+2990 y(FTGSV[BIJED]\(unit,colnum)o(,na)o(xis,)o(naxe)o(s,f)o(pixe)o
+(ls,l)o(pix)o(els,)o(incs)o(,nu)o(llva)o(l,)g(>)1002
+3103 y(array,anyf,status\))382 3216 y(FTGSF[BIJED]\(unit,colnum)o(,na)o
+(xis,)o(naxe)o(s,f)o(pixe)o(ls,l)o(pix)o(els,)o(incs)o(,)g(>)1002
+3329 y(array,flagvals,anyf,statu)o(s\))382 3441 y
+(FTGCX\(unit,colnum,frow,f)o(bit)o(,nbi)o(t,)g(>)47 b(lray,status\))382
+3554 y(FTGCX[IJD]\(unit,colnum,f)o(row)o(,nro)o(ws,f)o(bit)o(,nbi)o(t,)
+42 b(>)47 b(array,status\))382 3667 y(FTGDES\(unit,colnum,rownu)o(m,)41
+b(>)48 b(nelements,offset,status\))382 3780 y
+(FTPDES\(unit,colnum,rownu)o(m,n)o(elem)o(ents)o(,of)o(fset)o(,)42
+b(>)47 b(status\))0 4038 y Fi(Ro)m(w)31 b(Selection)f(and)f(Calculator)
+h(Routines:)40 b(page)31 b(96)382 4295 y Fe(FTFROW\(unit,expr,firstro)o
+(w,)41 b(nrows,)47 b(>)g(n_good_rows,)d(row_status,)h(status\))382
+4408 y(FTFFRW\(unit,)f(expr,)j(>)g(rownum,)f(status\))382
+4521 y(FTSROW\(inunit,)e(outunit,)h(expr,)i(>)g(status)f(\))382
+4634 y(FTCROW\(unit,datatype,exp)o(r,f)o(irst)o(row,)o(nel)o(emen)o
+(ts,n)o(ulv)o(al,)41 b(>)620 4747 y(array,anynul,status\))382
+4860 y(FTCALC\(inunit,)j(expr,)i(outunit,)g(parName,)f(parInfo,)h(>)h
+(status\))382 4973 y(FTCALC_RNG\(inunit,)c(expr,)j(outunit,)g(parName,)
+f(parInfo,)573 5086 y(nranges,)g(firstrow,)h(lastrow,)f(>)j(status\))
+382 5199 y(FTTEXP\(unit,)c(expr,)j(>)g(datatype,)e(nelem,)h(naxis,)h
+(naxes,)f(status\))0 5456 y Fi(Celestial)29 b(Co)s(ordinate)h(System)g
+(Subroutines:)38 b(page)31 b(98)382 5714 y Fe(FTGICS\(unit,)44
+b(>)k(xrval,yrval,xrpix,yrpix)o(,xin)o(c,yi)o(nc,)o(rot,)o(coor)o(dty)o
+(pe,s)o(tatu)o(s\))p eop
+%%Page: 115 121
+115 120 bop 3764 299 a Fi(115)382 555 y Fe(FTGTCS\(unit,xcol,ycol,)42
+b(>)716 668 y(xrval,yrval,xrpix,yrpix,)o(xinc)o(,yi)o(nc,r)o(ot,c)o
+(oor)o(dtyp)o(e,st)o(atu)o(s\))382 781 y(FTWLDP\(xpix,ypix,xrval,y)o
+(rva)o(l,xr)o(pix,)o(yrp)o(ix,x)o(inc,)o(yin)o(c,ro)o(t,)1241
+894 y(coordtype,)j(>)i(xpos,ypos,status\))382 1007 y
+(FTXYPX\(xpos,ypos,xrval,y)o(rva)o(l,xr)o(pix,)o(yrp)o(ix,x)o(inc,)o
+(yin)o(c,ro)o(t,)1241 1120 y(coordtype,)e(>)i(xpix,ypix,status\))0
+1340 y Fi(File)30 b(Chec)m(ksum)f(Subroutines:)39 b(page)31
+b(99)382 1560 y Fe(FTPCKS\(unit,)44 b(>)k(status\))382
+1673 y(FTUCKS\(unit,)c(>)k(status\))382 1785 y(FTVCKS\(unit,)c(>)k
+(dataok,hduok,status\))382 1898 y(FTGCKS\(unit,)c(>)k
+(datasum,hdusum,status\))382 2011 y(FTESUM\(sum,complement,)42
+b(>)47 b(checksum\))382 2124 y(FTDSUM\(checksum,compleme)o(nt,)41
+b(>)48 b(sum\))0 2457 y Fi(Time)29 b(and)h(Date)i(Utilit)m(y)e
+(Subroutines:)38 b(page)31 b(101)382 2677 y Fe(FTGSDT\()46
+b(>)h(day,)g(month,)f(year,)g(status)g(\))382 2790 y(FTGSTM\(>)f
+(datestr,)h(timeref,)f(status\))382 2903 y(FTDT2S\()h(year,)g(month,)g
+(day,)h(>)g(datestr,)f(status\))382 3016 y(FTTM2S\()g(year,)g(month,)g
+(day,)h(hour,)f(minute,)g(second,)g(decimals,)764 3129
+y(>)h(datestr,)f(status\))382 3242 y(FTS2DT\(datestr,)d(>)48
+b(year,)e(month,)g(day,)h(status\))382 3354 y(FTS2TM\(datestr,)c(>)48
+b(year,)e(month,)g(day,)h(hour,)f(minute,)g(second,)g(status\))0
+3574 y Fi(General)30 b(Utilit)m(y)g(Subroutines:)38 b(page)31
+b(102)382 3794 y Fe(FTGHAD\(unit,)44 b(>)k(curaddr,nextaddr\))382
+3907 y(FTUPCH\(string\))382 4020 y(FTCMPS\(str_template,stri)o(ng,)o
+(case)o(sen,)41 b(>)47 b(match,exact\))382 4133 y(FTTKEY\(keyword,)c(>)
+48 b(status\))382 4246 y(FTTREC\(card,)c(>)k(status\))382
+4359 y(FTNCHK\(unit,)c(>)k(status\))382 4472 y(FTGKNM\(unit,)c(>)k
+(keyword,)d(keylength,)g(status\))382 4585 y(FTPSVC\(card,)f(>)k
+(value,comment,status\))382 4698 y(FTKEYN\(keyroot,seq_no,)42
+b(>)47 b(keyword,status\))382 4811 y(FTNKEY\(seq_no,keyroot,)42
+b(>)47 b(keyword,status\))382 4924 y(FTDTYP\(value,)d(>)j
+(dtype,status\))382 5036 y(class)f(=)i(FTGKCL\(card\))382
+5149 y(FTASFM\(tform,)c(>)j(datacode,width,decimals,st)o(atus)o(\))382
+5262 y(FTBNFM\(tform,)d(>)j(datacode,repeat,width,stat)o(us\))382
+5375 y(FTGABC\(tfields,tform,spa)o(ce,)41 b(>)48 b
+(rowlen,tbcol,status\))382 5488 y(FTGTHD\(template,)43
+b(>)48 b(card,hdtype,status\))382 5601 y(FTRWRG\(rowlist,)43
+b(maxrows,)j(maxranges,)f(>)i(numranges,)e(rangemin,)716
+5714 y(rangemax,)g(status\))p eop
+%%Page: 116 122
+116 121 bop 0 299 a Fi(116)281 b Fg(CHAPTER)30 b(10.)112
+b(SUMMAR)-8 b(Y)32 b(OF)e(ALL)g(FITSIO)f(USER-INTERF)-10
+b(A)m(CE)30 b(SUBR)m(OUTINES)p eop
+%%Page: 117 123
+117 122 bop 0 1225 a Ff(Chapter)65 b(11)0 1687 y Fl(P)-6
+b(arameter)77 b(De\014nitions)0 2180 y Fe(anyf)47 b(-)g(\(logical\))e
+(set)i(to)g(TRUE)g(if)g(any)g(of)g(the)g(returned)f(data)g(values)h
+(are)f(undefined)0 2293 y(array)g(-)i(\(any)e(datatype)g(except)g
+(character\))f(array)h(of)i(bytes)e(to)h(be)g(read)g(or)g(written.)0
+2406 y(bitpix)f(-)i(\(integer\))d(bits)h(per)h(pixel:)f(8,)i(16,)f(32,)
+f(-32,)h(or)g(-64)0 2518 y(blank)f(-)i(\(integer\))d(value)h(used)h
+(for)g(undefined)e(pixels)h(in)i(integer)d(primary)h(array)0
+2631 y(blocksize)f(-)j(\(integer\))d(2880-byte)g(logical)h(record)g
+(blocking)g(factor)477 2744 y(\(if)h(0)h(<)f(blocksize)e(<)j(11\))f(or)
+g(the)g(actual)f(block)g(size)h(in)g(bytes)477 2857 y(\(if)g(10)g(<)h
+(blocksize)d(<)j(28800\).)93 b(As)47 b(of)g(version)f(3.3)h(of)g
+(FITSIO,)477 2970 y(blocksizes)e(greater)h(than)h(2880)f(are)h(no)g
+(longer)g(supported.)0 3083 y(bscale)f(-)i(\(double)d(precision\))g
+(scaling)h(factor)g(for)h(the)g(primary)f(array)0 3196
+y(bytlen)g(-)i(\(integer\))d(length)h(of)h(the)g(data)g(unit,)f(in)h
+(bytes)0 3309 y(bzero)f(-)i(\(double)e(precision\))f(zero)h(point)h
+(for)g(primary)e(array)i(scaling)0 3422 y(card)g(-)g(\(character*80\))d
+(header)i(record)g(to)h(be)h(read)e(or)h(written)0 3535
+y(casesen)f(-)h(\(logical\))f(will)g(string)g(matching)g(be)h(case)g
+(sensitive?)0 3648 y(checksum)f(-)h(\(character*16\))d(encoded)i
+(checksum)f(string)0 3760 y(colname)h(-)h(\(character\))e(ASCII)h(name)
+h(of)g(the)g(column)0 3873 y(colnum)f(-)i(\(integer\))d(number)h(of)h
+(the)g(column)f(\(first)g(column)g(=)i(1\))0 3986 y(coltemplate)d(-)i
+(\(character\))e(template)g(string)i(to)g(be)g(matched)f(to)h(column)f
+(names)0 4099 y(comment)g(-)h(\(character\))e(the)i(keyword)f(comment)g
+(field)0 4212 y(comments)g(-)h(\(character)e(array\))h(keyword)g
+(comment)g(fields)0 4325 y(compid)g(-)i(\(integer\))d(the)i(type)f(of)i
+(computer)d(that)i(the)g(program)e(is)j(running)d(on)0
+4438 y(complement)g(-)i(\(logical\))f(should)g(the)h(checksum)e(be)i
+(complemented?)0 4551 y(coordtype)e(-)j(\(character\))c(type)j(of)g
+(coordinate)e(projection)g(\(-SIN,)h(-TAN,)h(-ARC,)477
+4664 y(-NCP,)g(-GLS,)f(-MER,)g(or)i(-AIT\))0 4777 y(cube)f(-)g(3D)g
+(data)g(cube)g(of)g(the)g(appropriate)d(datatype)0 4890
+y(curaddr)i(-)h(\(integer\))f(starting)f(address)h(\(in)h(bytes\))f(of)
+h(the)g(CHDU)0 5002 y(datacode)f(-)h(\(integer\))e(symbolic)h(code)g
+(of)i(the)f(binary)f(table)g(column)g(datatype)0 5115
+y(dataok)g(-)i(\(integer\))d(was)i(the)g(data)f(unit)h(verification)d
+(successful)h(\(=1\))i(or)430 5228 y(not)f(\(=)i(-1\).)94
+b(Equals)46 b(zero)h(if)g(the)g(DATASUM)f(keyword)f(is)j(not)f
+(present.)0 5341 y(datasum)f(-)h(\(double)f(precision\))f(32-bit)h(1's)
+h(complement)e(checksum)h(for)h(the)f(data)h(unit)0 5454
+y(datatype)f(-)h(\(character\))e(datatype)g(\(format\))h(of)h(the)g
+(binary)f(table)g(column)0 5567 y(datestr)94 b(-)47 b(\(string\))f
+(FITS)g(date/time)f(string:)h('YYYY-MM-DDThh:mm:ss.ddd')o(,)525
+5680 y('YYYY-MM-dd',)e(or)j('dd/mm/yy')1882 5942 y Fi(117)p
+eop
+%%Page: 118 124
+118 123 bop 0 299 a Fi(118)1779 b Fg(CHAPTER)30 b(11.)112
+b(P)-8 b(ARAMETER)30 b(DEFINITIONS)0 555 y Fe(day)47
+b(-)g(\(integer\))f(current)f(day)i(of)h(the)e(month)0
+668 y(dblval)g(-)i(\(double)d(precision\))g(fractional)g(part)i(of)g
+(the)g(keyword)f(value)0 781 y(decimals)g(-)h(\(integer\))e(number)h
+(of)i(decimal)d(places)h(to)i(be)f(displayed)0 894 y(dim1)g(-)g
+(\(integer\))e(actual)h(size)h(of)g(the)g(first)g(dimension)e(of)i(the)
+g(image)f(or)h(cube)g(array)0 1007 y(dim2)g(-)g(\(integer\))e(actual)h
+(size)h(of)g(the)g(second)f(dimension)g(of)h(the)g(cube)f(array)0
+1120 y(dispwidth)f(-)j(\(integer\))d(-)i(the)g(display)f(width)h
+(\(length)e(of)j(string\))d(for)i(a)h(column)0 1233 y(dtype)e(-)i
+(\(character\))d(datatype)g(of)i(the)g(keyword)f(\('C',)g('L',)h('I',)
+94 b(or)48 b('F'\))764 1346 y(C)f(=)h(character)d(string)764
+1458 y(L)i(=)h(logical)764 1571 y(I)f(=)h(integer)764
+1684 y(F)f(=)h(floating)d(point)h(number)0 1797 y(errmsg)g(-)i
+(\(character*80\))43 b(oldest)k(error)f(message)g(on)h(the)g(internal)e
+(stack)0 1910 y(errtext)h(-)h(\(character*30\))d(descriptive)h(error)h
+(message)g(corresponding)e(to)j(error)g(number)0 2023
+y(casesen)f(-)h(\(logical\))f(true)g(if)h(column)f(name)h(matching)f
+(is)h(case)f(sensitive)0 2136 y(exact)g(-)i(\(logical\))d(do)i(the)g
+(strings)f(match)g(exactly,)g(or)h(were)g(wildcards)e(used?)0
+2249 y(exclist)94 b(\(character)45 b(array\))h(list)g(of)h(names)g(to)g
+(be)g(excluded)f(from)g(search)0 2362 y(exists)142 b(-)47
+b(flag)g(indicating)e(whether)g(the)i(file)g(or)g(compressed)e(file)i
+(exists)f(on)h(disk)0 2475 y(extend)f(-)i(\(logical\))d(true)h(if)i
+(there)e(may)h(be)g(extensions)e(following)g(the)i(primary)f(data)0
+2588 y(extname)g(-)h(\(character\))e(value)h(of)i(the)e(EXTNAME)g
+(keyword)g(\(if)h(not)g(blank\))0 2700 y(fbit)g(-)g(\(integer\))e
+(first)i(bit)g(in)g(the)g(field)f(to)h(be)g(read)g(or)g(written)0
+2813 y(felem)f(-)i(\(integer\))d(first)h(pixel)h(of)g(the)g(element)f
+(vector)g(\(ignored)f(for)i(ASCII)g(tables\))0 2926 y(filename)f(-)h
+(\(character\))e(name)h(of)i(the)e(FITS)h(file)0 3039
+y(flagvals)f(-)h(\(logical)f(array\))g(True)g(if)h(corresponding)e
+(data)h(element)g(is)h(undefined)0 3152 y(fparm)f(-)i(\(integer\))d
+(sequence)h(number)g(of)h(the)g(first)f(group)h(parameter)e(to)i(read)g
+(or)g(write)0 3265 y(fpixel)f(-)i(\(integer\))d(the)i(first)f(pixel)g
+(position)0 3378 y(fpixels)g(-)h(\(integer)f(array\))g(the)h(first)f
+(included)g(pixel)g(in)h(each)g(dimension)0 3491 y(frow)g(-)g
+(\(integer\))e(beginning)h(row)h(number)f(\(first)g(row)h(of)g(table)f
+(=)i(1\))0 3604 y(gcount)e(-)i(\(integer\))d(value)h(of)h(the)g(GCOUNT)
+f(keyword)g(\(usually)g(=)h(1\))0 3717 y(group)f(-)i(\(integer\))d
+(sequence)h(number)g(of)h(the)g(data)f(group)h(\(=0)g(for)g
+(non-grouped)d(data\))0 3830 y(hdtype)i(-)i(\(integer\))d(header)h
+(record)g(type:)g(-1=delete;)93 b(0=append)46 b(or)h(replace;)907
+3942 y(1=append;)e(2=this)h(is)h(the)g(END)g(keyword)0
+4055 y(hduok)f(-)i(\(integer\))d(was)i(the)g(HDU)g(verification)d
+(successful)h(\(=1\))i(or)430 4168 y(not)f(\(=)i(-1\).)94
+b(Equals)46 b(zero)h(if)g(the)g(CHECKSUM)e(keyword)h(is)h(not)g
+(present.)0 4281 y(hdusum)f(-)i(\(double)d(precision\))g(32)j(bit)e
+(1's)h(complement)e(checksum)h(for)h(the)g(entire)f(CHDU)0
+4394 y(hdutype)g(-)h(\(integer\))f(type)g(of)h(HDU:)g(0)g(=)h(primary)e
+(array)g(or)h(IMAGE,)f(1)i(=)f(ASCII)g(table,)907 4507
+y(2)g(=)h(binary)e(table,)g(-1)h(=)h(unknown)0 4620 y(history)e(-)h
+(\(character\))e(the)i(HISTORY)f(keyword)g(comment)f(string)0
+4733 y(hour)i(-)g(\(integer\))e(hour)i(from)g(0)g(-)h(23)0
+4846 y(image)e(-)i(2D)f(image)f(of)i(the)e(appropriate)f(datatype)0
+4959 y(inclist)94 b(\(character)45 b(array\))h(list)g(of)h(names)g(to)g
+(be)g(included)f(in)h(search)0 5072 y(incs)g(-)g(\(integer)f(array\))g
+(sampling)f(interval)h(for)h(pixels)f(in)h(each)g(FITS)f(dimension)0
+5185 y(intval)g(-)i(\(integer\))d(integer)h(part)g(of)h(the)g(keyword)f
+(value)0 5297 y(iounit)g(-)i(\(integer\))d(value)h(of)h(an)h(unused)e
+(I/O)h(unit)f(number)0 5410 y(iunit)g(-)i(\(integer\))d(logical)h(unit)
+h(number)f(associated)f(with)h(the)h(input)g(FITS)f(file,)h(1-199)0
+5523 y(key_no)f(-)i(\(integer\))d(sequence)g(number)h(\(starting)g
+(with)g(1\))i(of)f(the)g(keyword)e(record)0 5636 y(keylength)g(-)j
+(\(integer\))d(length)h(of)h(the)g(keyword)f(name)p eop
+%%Page: 119 125
+119 124 bop 3764 299 a Fi(119)0 555 y Fe(keyroot)46 b(-)h
+(\(character\))e(root)i(string)f(for)h(the)g(keyword)e(name)0
+668 y(keysadd)h(-\(integer\))f(number)h(of)h(new)g(keyword)f(records)g
+(which)g(can)h(fit)g(in)g(the)g(CHU)0 781 y(keysexist)e(-)j
+(\(integer\))d(number)h(of)h(existing)f(keyword)g(records)f(in)j(the)f
+(CHU)0 894 y(keyval)f(-)i(value)e(of)h(the)g(keyword)f(in)h(the)g
+(appropriate)e(datatype)0 1007 y(keyvals)h(-)h(\(array\))f(value)g(of)i
+(the)f(keywords)e(in)i(the)g(appropriate)e(datatype)0
+1120 y(keyword)h(-)h(\(character*8\))d(name)j(of)g(a)h(keyword)0
+1233 y(lray)f(-)g(\(logical)f(array\))g(array)g(of)h(logical)f(values)g
+(corresponding)e(to)k(the)e(bit)h(array)0 1346 y(lpixels)f(-)h
+(\(integer)f(array\))g(the)h(last)f(included)g(pixel)g(in)i(each)e
+(dimension)0 1458 y(match)g(-)i(\(logical\))d(do)i(the)g(2)h(strings)d
+(match?)0 1571 y(maxdim)h(-)i(\(integer\))d(dimensioned)g(size)h(of)h
+(the)g(NAXES,)f(TTYPE,)g(TFORM)h(or)g(TUNIT)f(arrays)0
+1684 y(max_keys)g(-)h(\(integer\))e(maximum)h(number)g(of)h(keywords)f
+(to)h(search)f(for)0 1797 y(minute)g(-)i(\(integer\))d(minute)h(of)h
+(an)g(hour)g(\(0)g(-)h(59\))0 1910 y(month)e(-)i(\(integer\))d(current)
+h(month)g(of)h(the)g(year)g(\(1)g(-)h(12\))0 2023 y(morekeys)e(-)h
+(\(integer\))e(will)i(leave)f(space)h(in)g(the)g(header)f(for)h(this)f
+(many)h(more)g(keywords)0 2136 y(naxes)f(-)i(\(integer)d(array\))h
+(size)h(of)g(each)g(dimension)e(in)i(the)g(FITS)g(array)0
+2249 y(naxis)f(-)i(\(integer\))d(number)h(of)h(dimensions)e(in)j(the)e
+(FITS)h(array)0 2362 y(naxis1)f(-)i(\(integer\))d(length)h(of)h(the)g
+(X/first)f(axis)g(of)i(the)f(FITS)f(array)0 2475 y(naxis2)g(-)i
+(\(integer\))d(length)h(of)h(the)g(Y/second)f(axis)g(of)h(the)g(FITS)g
+(array)0 2588 y(naxis3)f(-)i(\(integer\))d(length)h(of)h(the)g(Z/third)
+f(axis)g(of)i(the)f(FITS)f(array)0 2700 y(nbit)h(-)g(\(integer\))e
+(number)h(of)i(bits)e(in)h(the)g(field)g(to)g(read)g(or)g(write)0
+2813 y(nchars)f(-)i(\(integer\))d(number)h(of)h(characters)e(to)i(read)
+g(and)g(return)0 2926 y(ncols)f(-)i(\(integer\))d(number)h(of)h
+(columns)0 3039 y(nelements)e(-)j(\(integer\))d(number)h(of)h(data)g
+(elements)e(to)j(read)e(or)h(write)0 3152 y(nexc)142
+b(\(integer\))93 b(number)46 b(of)h(names)g(in)g(the)g(exclusion)e
+(list)i(\(may)f(=)i(0\))0 3265 y(nhdu)f(-)g(\(integer\))e(absolute)h
+(number)g(of)h(the)g(HDU)g(\(1st)g(HDU)g(=)g(1\))0 3378
+y(ninc)142 b(\(integer\))93 b(number)46 b(of)h(names)g(in)g(the)g
+(inclusion)e(list)0 3491 y(nmove)h(-)i(\(integer\))d(number)h(of)h
+(HDUs)g(to)g(move)g(\(+)g(or)g(-\),)g(relative)f(to)h(current)f
+(position)0 3604 y(nfound)g(-)i(\(integer\))d(number)h(of)h(keywords)f
+(found)g(\(highest)g(keyword)f(number\))0 3717 y(no_keys)h(-)h
+(\(integer\))f(number)g(of)h(keywords)e(to)j(write)e(in)h(the)g
+(sequence)0 3830 y(nparm)f(-)i(\(integer\))d(number)h(of)h(group)g
+(parameters)e(to)i(read)g(or)g(write)0 3942 y(nrows)f(-)i(\(integer\))d
+(number)h(of)h(rows)g(in)g(the)g(table)0 4055 y(nullval)f(-)h(value)g
+(to)g(represent)e(undefined)g(pixels,)h(of)h(the)g(appropriate)e
+(datatype)0 4168 y(nextaddr)h(-)h(\(integer\))e(starting)h(address)g
+(\(in)h(bytes\))f(of)h(the)g(HDU)g(following)e(the)i(CHDU)0
+4281 y(offset)f(-)i(\(integer\))d(byte)h(offset)h(in)g(the)g(heap)f(to)
+h(the)g(first)g(element)f(of)h(the)g(array)0 4394 y(oldkey)f(-)i
+(\(character\))c(old)j(name)g(of)g(keyword)f(to)h(be)g(modified)0
+4507 y(ounit)f(-)i(\(integer\))d(logical)h(unit)h(number)f(associated)f
+(with)h(the)h(output)f(FITS)h(file)g(1-199)0 4620 y(pcount)f(-)i
+(\(integer\))d(value)h(of)h(the)g(PCOUNT)f(keyword)g(\(usually)g(=)h
+(0\))0 4733 y(repeat)f(-)i(\(integer\))d(length)h(of)h(element)f
+(vector)g(\(e.g.)g(12J\);)h(ignored)f(for)g(ASCII)h(table)0
+4846 y(rot)g(-)g(\(double)f(precision\))f(celestial)g(coordinate)g
+(rotation)h(angle)g(\(degrees\))0 4959 y(rowlen)g(-)i(\(integer\))d
+(length)h(of)h(a)h(table)e(row,)h(in)g(characters)e(or)i(bytes)0
+5072 y(rowlist)f(-)h(\(integer)f(array\))g(list)h(of)g(row)g(numbers)e
+(to)j(be)f(deleted)f(in)h(increasing)e(order)0 5185 y(rownum)h(-)i
+(\(integer\))d(number)h(of)h(the)g(row)g(\(first)f(row)h(=)g(1\))0
+5297 y(rowrange-)e(\(string\))h(list)g(of)i(rows)e(or)h(row)g(ranges)f
+(to)i(be)f(deleted)0 5410 y(rwmode)f(-)i(\(integer\))d(file)h(access)h
+(mode:)f(0)h(=)h(readonly,)d(1)j(=)f(readwrite)0 5523
+y(second)142 b(\(double\)-)45 b(second)h(within)g(minute)g(\(0)h(-)h
+(60.9999999999\))c(\(leap)i(second!\))0 5636 y(seq_no)g(-)i
+(\(integer\))d(the)i(sequence)e(number)h(to)i(append)e(to)h(the)g
+(keyword)f(root)g(name)p eop
+%%Page: 120 126
+120 125 bop 0 299 a Fi(120)1779 b Fg(CHAPTER)30 b(11.)112
+b(P)-8 b(ARAMETER)30 b(DEFINITIONS)0 555 y Fe(simple)46
+b(-)i(\(logical\))d(does)h(the)h(FITS)g(file)g(conform)e(to)j(all)f
+(the)f(FITS)h(standards)0 668 y(snull)f(-)i(\(character\))d(value)h
+(used)h(to)g(represent)e(undefined)g(values)h(in)i(ASCII)e(table)0
+781 y(space)g(-)i(\(integer\))d(number)h(of)h(blank)g(spaces)f(to)h
+(leave)f(between)g(ASCII)h(table)f(columns)0 894 y(startchar)f(-)j
+(\(integer\))d(first)h(character)g(in)h(the)g(row)g(to)g(be)g(read)0
+1007 y(startno)f(-)h(\(integer\))f(value)g(of)h(the)g(first)f(keyword)g
+(sequence)g(number)g(\(usually)f(1\))0 1120 y(status)h(-)i(\(integer\))
+d(returned)g(error)i(status)f(code)g(\(0)i(=)f(OK\))0
+1233 y(str_template)d(\(character\))h(template)h(string)g(to)h(be)g
+(matched)f(to)h(reference)e(string)0 1346 y(stream)h(-)i(\(character\))
+c(output)i(stream)g(for)h(the)g(report:)f(either)g('STDOUT')g(or)h
+('STDERR')0 1458 y(string)f(-)i(\(character\))c(character)i(string)0
+1571 y(sum)h(-)g(\(double)f(precision\))f(32)i(bit)g(unsigned)f
+(checksum)f(value)0 1684 y(tbcol)h(-)i(\(integer)d(array\))h(column)h
+(number)f(of)h(the)g(first)f(character)f(in)j(the)e(field\(s\))0
+1797 y(tdisp)g(-)i(\(character\))d(Fortran)g(type)i(display)f(format)g
+(for)h(the)g(table)f(column)0 1910 y(template-\(character\))c(template)
+k(string)g(for)h(a)g(FITS)g(header)f(record)0 2023 y(tfields)g(-)h
+(\(integer\))f(number)g(of)h(fields)f(\(columns\))f(in)i(the)g(table)0
+2136 y(tform)f(-)i(\(character)d(array\))h(format)g(of)h(the)g
+(column\(s\);)e(allowed)h(values)g(are:)430 2249 y(For)g(ASCII)h
+(tables:)93 b(Iw,)47 b(Aw,)g(Fww.dd,)f(Eww.dd,)g(or)h(Dww.dd)430
+2362 y(For)f(binary)h(tables:)e(rL,)i(rX,)g(rB,)g(rI,)g(rJ,)g(rA,)g
+(rAw,)f(rE,)h(rD,)g(rC,)g(rM)430 2475 y(where)f('w'=width)f(of)i(the)g
+(field,)f('d'=no.)g(of)h(decimals,)f('r'=repeat)f(count)430
+2588 y(Note)h(that)h(the)g('rAw')f(form)h(is)g(non-standard)d
+(extension)i(to)h(the)430 2700 y(TFORM)f(keyword)g(syntax)g(that)g(is)i
+(not)f(specifically)d(defined)i(in)h(the)430 2813 y(Binary)f(Tables)g
+(definition)f(document.)0 2926 y(theap)h(-)i(\(integer\))d(zero)i
+(indexed)f(byte)g(offset)g(of)h(starting)f(address)g(of)h(the)g(heap)
+430 3039 y(relative)e(to)i(the)g(beginning)e(of)j(the)f(binary)f(table)
+g(data)0 3152 y(tnull)g(-)i(\(integer\))d(value)h(used)h(to)g
+(represent)f(undefined)f(values)h(in)h(binary)f(table)0
+3265 y(ttype)g(-)i(\(character)d(array\))h(label)g(for)h(table)g
+(column\(s\))0 3378 y(tscal)f(-)i(\(double)e(precision\))f(scaling)g
+(factor)i(for)f(table)h(column)0 3491 y(tunit)f(-)i(\(character)d
+(array\))h(physical)f(unit)i(for)g(table)f(column\(s\))0
+3604 y(tzero)g(-)i(\(double)e(precision\))f(scaling)g(zero)i(point)f
+(for)h(table)g(column)0 3717 y(unit)94 b(-)48 b(\(integer\))d(logical)h
+(unit)h(number)f(associated)f(with)h(the)h(FITS)g(file)f(\(1-199\))0
+3830 y(units)g(-)i(\(character\))d(the)h(keyword)g(units)h(string)f
+(\(e.g.,)g('km/s'\))0 3942 y(value)g(-)i(\(character\))d(the)h(keyword)
+g(value)h(string)0 4055 y(values)f(-)i(array)e(of)h(data)g(values)f(of)
+h(the)g(appropriate)e(datatype)0 4168 y(varidat)h(-)h(\(integer\))f
+(size)g(in)h(bytes)g(of)g(the)g('variable)e(length)h(data)h(area')525
+4281 y(following)e(the)i(binary)f(table)h(data)f(\(usually)g(=)h(0\))0
+4394 y(version)f(-)h(\(real\))f(current)g(revision)g(number)g(of)h(the)
+g(library)0 4507 y(width)f(-)i(\(integer\))d(width)h(of)i(the)f
+(character)e(string)h(field)0 4620 y(xcol)h(-)g(\(integer\))e(number)h
+(of)i(the)f(column)f(containing)f(the)i(X)g(coordinate)e(values)0
+4733 y(xinc)i(-)g(\(double)f(precision\))f(X)i(axis)g(coordinate)e
+(increment)g(at)i(reference)f(pixel)g(\(deg\))0 4846
+y(xpix)h(-)g(\(double)f(precision\))f(X)i(axis)g(pixel)f(location)0
+4959 y(xpos)h(-)g(\(double)f(precision\))f(X)i(axis)g(celestial)e
+(coordinate)g(\(usually)h(RA\))h(\(deg\))0 5072 y(xrpix)f(-)i(\(double)
+e(precision\))f(X)i(axis)g(reference)e(pixel)h(array)h(location)0
+5185 y(xrval)f(-)i(\(double)e(precision\))f(X)i(axis)g(coordinate)e
+(value)h(at)h(the)g(reference)e(pixel)i(\(deg\))0 5297
+y(ycol)g(-)g(\(integer\))e(number)h(of)i(the)f(column)f(containing)f
+(the)i(X)g(coordinate)e(values)0 5410 y(year)i(-)g(\(integer\))e(last)i
+(2)g(digits)g(of)g(the)g(year)f(\(00)h(-)h(99\))0 5523
+y(yinc)f(-)g(\(double)f(precision\))f(Y)i(axis)g(coordinate)e
+(increment)g(at)i(reference)f(pixel)g(\(deg\))0 5636
+y(ypix)h(-)g(\(double)f(precision\))f(y)i(axis)g(pixel)f(location)p
+eop
+%%Page: 121 127
+121 126 bop 3764 299 a Fi(121)0 555 y Fe(ypos)47 b(-)g(\(double)f
+(precision\))f(y)i(axis)g(celestial)e(coordinate)g(\(usually)h(DEC\))g
+(\(deg\))0 668 y(yrpix)g(-)i(\(double)e(precision\))f(Y)i(axis)g
+(reference)e(pixel)h(array)h(location)0 781 y(yrval)f(-)i(\(double)e
+(precision\))f(Y)i(axis)g(coordinate)e(value)h(at)h(the)g(reference)e
+(pixel)i(\(deg\))p eop
+%%Page: 122 128
+122 127 bop 0 299 a Fi(122)1779 b Fg(CHAPTER)30 b(11.)112
+b(P)-8 b(ARAMETER)30 b(DEFINITIONS)p eop
+%%Page: 123 129
+123 128 bop 0 1225 a Ff(Chapter)65 b(12)0 1687 y Fl(FITSIO)76
+b(Error)h(Status)h(Co)6 b(des)0 2180 y Fe(Status)46 b(codes)g(in)i(the)
+f(range)f(-99)h(to)g(-999)94 b(and)47 b(1)h(to)f(999)g(are)g(reserved)e
+(for)i(future)0 2293 y(FITSIO)f(use.)95 2518 y(0)96 b(OK,)47
+b(no)g(error)0 2631 y(101)95 b(input)46 b(and)h(output)f(files)g(are)h
+(the)g(same)0 2744 y(103)95 b(too)47 b(many)f(FITS)h(files)f(open)h(at)
+g(once;)f(all)h(internal)f(buffers)g(full)0 2857 y(104)95
+b(error)46 b(opening)g(existing)f(file)0 2970 y(105)95
+b(error)46 b(creating)g(new)g(FITS)h(file;)f(\(does)h(a)g(file)g(with)g
+(this)f(name)h(already)f(exist?\))0 3083 y(106)95 b(error)46
+b(writing)g(record)g(to)h(FITS)g(file)0 3196 y(107)95
+b(end-of-file)44 b(encountered)h(while)h(reading)g(record)g(from)h
+(FITS)g(file)0 3309 y(108)95 b(error)46 b(reading)g(record)g(from)h
+(file)0 3422 y(110)95 b(error)46 b(closing)g(FITS)g(file)0
+3535 y(111)95 b(internal)45 b(array)i(dimensions)e(exceeded)0
+3648 y(112)95 b(Cannot)46 b(modify)g(file)g(with)h(readonly)f(access)0
+3760 y(113)95 b(Could)46 b(not)h(allocate)e(memory)0
+3873 y(114)95 b(illegal)45 b(logical)h(unit)h(number;)f(must)g(be)i
+(between)d(1)j(-)f(199,)g(inclusive)0 3986 y(115)95 b(NULL)46
+b(input)h(pointer)e(to)j(routine)0 4099 y(116)95 b(error)46
+b(seeking)g(position)f(in)j(file)0 4325 y(121)95 b(invalid)45
+b(URL)i(prefix)f(on)i(file)e(name)0 4438 y(122)95 b(tried)46
+b(to)h(register)f(too)h(many)f(IO)h(drivers)0 4551 y(123)95
+b(driver)46 b(initialization)e(failed)0 4664 y(124)95
+b(matching)45 b(driver)h(is)h(not)g(registered)0 4777
+y(125)95 b(failed)46 b(to)h(parse)f(input)h(file)f(URL)0
+4890 y(126)95 b(parse)46 b(error)g(in)i(range)e(list)0
+5115 y(151)95 b(bad)47 b(argument)e(in)i(shared)f(memory)g(driver)0
+5228 y(152)95 b(null)46 b(pointer)g(passed)g(as)h(an)h(argument)0
+5341 y(153)95 b(no)47 b(more)f(free)h(shared)f(memory)g(handles)0
+5454 y(154)95 b(shared)46 b(memory)g(driver)g(is)h(not)g(initialized)0
+5567 y(155)95 b(IPC)47 b(error)f(returned)f(by)j(a)f(system)f(call)0
+5680 y(156)95 b(no)47 b(memory)f(in)h(shared)f(memory)g(driver)1882
+5942 y Fi(123)p eop
+%%Page: 124 130
+124 129 bop 0 299 a Fi(124)1613 b Fg(CHAPTER)30 b(12.)112
+b(FITSIO)30 b(ERR)m(OR)g(ST)-8 b(A)g(TUS)30 b(CODES)0
+555 y Fe(157)95 b(resource)45 b(deadlock)h(would)g(occur)0
+668 y(158)95 b(attempt)45 b(to)j(open/create)c(lock)j(file)g(failed)0
+781 y(159)95 b(shared)46 b(memory)g(block)g(cannot)g(be)h(resized)f(at)
+h(the)g(moment)0 1120 y(201)95 b(header)46 b(not)h(empty;)f(can't)g
+(write)g(required)g(keywords)0 1233 y(202)95 b(specified)45
+b(keyword)h(name)g(was)h(not)g(found)g(in)g(the)g(header)0
+1346 y(203)95 b(specified)45 b(header)h(record)g(number)g(is)h(out)g
+(of)g(bounds)0 1458 y(204)95 b(keyword)45 b(value)i(field)f(is)h(blank)
+0 1571 y(205)95 b(keyword)45 b(value)i(string)f(is)h(missing)f(the)h
+(closing)f(quote)g(character)0 1684 y(207)95 b(illegal)45
+b(character)h(in)h(keyword)f(name)g(or)i(header)e(record)0
+1797 y(208)95 b(keyword)45 b(does)i(not)g(have)g(expected)e(name.)i
+(Keyword)e(out)i(of)g(sequence?)0 1910 y(209)95 b(keyword)45
+b(does)i(not)g(have)g(expected)e(integer)h(value)0 2023
+y(210)95 b(could)46 b(not)h(find)g(the)f(required)g(END)h(header)f
+(keyword)0 2136 y(211)95 b(illegal)45 b(BITPIX)i(keyword)e(value)0
+2249 y(212)95 b(illegal)45 b(NAXIS)i(keyword)f(value)0
+2362 y(213)95 b(illegal)45 b(NAXISn)i(keyword)e(value:)h(must)h(be)g(0)
+h(or)f(positive)e(integer)0 2475 y(214)95 b(illegal)45
+b(PCOUNT)i(keyword)e(value)0 2588 y(215)95 b(illegal)45
+b(GCOUNT)i(keyword)e(value)0 2700 y(216)95 b(illegal)45
+b(TFIELDS)h(keyword)g(value)0 2813 y(217)95 b(negative)45
+b(ASCII)i(or)g(binary)f(table)g(width)h(value)f(\(NAXIS1\))0
+2926 y(218)95 b(negative)45 b(number)h(of)h(rows)g(in)g(ASCII)g(or)g
+(binary)f(table)g(\(NAXIS2\))0 3039 y(219)95 b(column)46
+b(name)g(\(TTYPE)g(keyword\))g(not)h(found)0 3152 y(220)95
+b(illegal)45 b(SIMPLE)i(keyword)e(value)0 3265 y(221)95
+b(could)46 b(not)h(find)g(the)f(required)g(SIMPLE)g(header)g(keyword)0
+3378 y(222)95 b(could)46 b(not)h(find)g(the)f(required)g(BITPIX)g
+(header)g(keyword)0 3491 y(223)95 b(could)46 b(not)h(find)g(the)f
+(required)g(NAXIS)g(header)g(keyword)0 3604 y(224)95
+b(could)46 b(not)h(find)g(all)f(the)h(required)f(NAXISn)g(keywords)g
+(in)h(the)g(header)0 3717 y(225)95 b(could)46 b(not)h(find)g(the)f
+(required)g(XTENSION)g(header)g(keyword)0 3830 y(226)95
+b(the)47 b(CHDU)f(is)h(not)g(an)g(ASCII)g(table)f(extension)0
+3942 y(227)95 b(the)47 b(CHDU)f(is)h(not)g(a)h(binary)e(table)g
+(extension)0 4055 y(228)95 b(could)46 b(not)h(find)g(the)f(required)g
+(PCOUNT)g(header)g(keyword)0 4168 y(229)95 b(could)46
+b(not)h(find)g(the)f(required)g(GCOUNT)g(header)g(keyword)0
+4281 y(230)95 b(could)46 b(not)h(find)g(the)f(required)g(TFIELDS)g
+(header)g(keyword)0 4394 y(231)95 b(could)46 b(not)h(find)g(all)f(the)h
+(required)f(TBCOLn)g(keywords)g(in)h(the)g(header)0 4507
+y(232)95 b(could)46 b(not)h(find)g(all)f(the)h(required)f(TFORMn)g
+(keywords)g(in)h(the)g(header)0 4620 y(233)95 b(the)47
+b(CHDU)f(is)h(not)g(an)g(IMAGE)g(extension)0 4733 y(234)95
+b(illegal)45 b(TBCOL)i(keyword)f(value;)g(out)h(of)g(range)0
+4846 y(235)95 b(this)46 b(operation)g(only)g(allowed)g(for)h(ASCII)f
+(or)h(BINARY)g(table)f(extension)0 4959 y(236)95 b(column)46
+b(is)h(too)g(wide)f(to)i(fit)f(within)f(the)h(specified)e(width)h(of)h
+(the)g(ASCII)g(table)0 5072 y(237)95 b(the)47 b(specified)e(column)h
+(name)h(template)e(matched)h(more)h(than)f(one)h(column)f(name)0
+5185 y(241)95 b(binary)46 b(table)g(row)h(width)f(is)i(not)e(equal)h
+(to)g(the)g(sum)g(of)g(the)g(field)f(widths)0 5297 y(251)95
+b(unrecognizable)44 b(type)i(of)h(FITS)g(extension)0
+5410 y(252)95 b(unrecognizable)44 b(FITS)i(record)0 5523
+y(253)95 b(END)47 b(keyword)e(contains)h(non-blank)f(characters)g(in)i
+(columns)f(9-80)0 5636 y(254)95 b(Header)46 b(fill)g(area)h(contains)f
+(non-blank)f(characters)p eop
+%%Page: 125 131
+125 130 bop 3764 299 a Fi(125)0 555 y Fe(255)95 b(Data)46
+b(fill)h(area)g(contains)e(non-blank)g(on)j(non-zero)d(values)0
+668 y(261)95 b(unable)46 b(to)h(parse)f(the)h(TFORM)g(keyword)e(value)i
+(string)0 781 y(262)95 b(unrecognizable)44 b(TFORM)i(datatype)f(code)0
+894 y(263)95 b(illegal)45 b(TDIMn)i(keyword)f(value)0
+1120 y(301)95 b(illegal)45 b(HDU)i(number;)f(less)h(than)f(1)i(or)f
+(greater)f(than)h(internal)e(buffer)h(size)0 1233 y(302)95
+b(column)46 b(number)g(out)h(of)g(range)f(\(1)h(-)h(999\))0
+1346 y(304)95 b(attempt)45 b(to)j(move)e(to)h(negative)f(file)h(record)
+f(number)0 1458 y(306)95 b(attempted)45 b(to)i(read)g(or)g(write)f(a)i
+(negative)d(number)h(of)i(bytes)e(in)h(the)g(FITS)g(file)0
+1571 y(307)95 b(illegal)45 b(starting)h(row)h(number)f(for)h(table)f
+(read)h(or)g(write)f(operation)0 1684 y(308)95 b(illegal)45
+b(starting)h(element)g(number)g(for)h(table)f(read)h(or)g(write)f
+(operation)0 1797 y(309)95 b(attempted)45 b(to)i(read)g(or)g(write)f
+(character)g(string)g(in)h(non-character)d(table)i(column)0
+1910 y(310)95 b(attempted)45 b(to)i(read)g(or)g(write)f(logical)g
+(value)g(in)i(non-logical)c(table)j(column)0 2023 y(311)95
+b(illegal)45 b(ASCII)i(table)f(TFORM)h(format)f(code)g(for)h(attempted)
+e(operation)0 2136 y(312)95 b(illegal)45 b(binary)i(table)f(TFORM)g
+(format)g(code)h(for)g(attempted)e(operation)0 2249 y(314)95
+b(value)46 b(for)h(undefined)e(pixels)h(has)h(not)g(been)g(defined)0
+2362 y(317)95 b(attempted)45 b(to)i(read)g(or)g(write)f(descriptor)f
+(in)i(a)h(non-descriptor)c(field)0 2475 y(320)95 b(number)46
+b(of)h(array)f(dimensions)f(out)i(of)g(range)0 2588 y(321)95
+b(first)46 b(pixel)g(number)g(is)i(greater)d(than)i(the)g(last)g(pixel)
+f(number)0 2700 y(322)95 b(attempt)45 b(to)j(set)f(BSCALE)f(or)h
+(TSCALn)f(scaling)g(parameter)f(=)i(0)0 2813 y(323)95
+b(illegal)45 b(axis)i(length)f(less)h(than)f(1)0 3039
+y(340)h(NOT_GROUP_TABLE)d(340)142 b(Grouping)45 b(function)h(error)0
+3152 y(341)95 b(HDU_ALREADY_MEMBER)0 3265 y(342)47 b(MEMBER_NOT_FOUND)0
+3378 y(343)g(GROUP_NOT_FOUND)0 3491 y(344)g(BAD_GROUP_ID)0
+3604 y(345)g(TOO_MANY_HDUS_TRACKED)0 3717 y(346)g(HDU_ALREADY_TRACKED)0
+3830 y(347)g(BAD_OPTION)0 3942 y(348)g(IDENTICAL_POINTERS)0
+4055 y(349)g(BAD_GROUP_ATTACH)0 4168 y(350)g(BAD_GROUP_DETACH)0
+4394 y(360)g(NGP_NO_MEMORY)665 b(malloc)46 b(failed)0
+4507 y(361)h(NGP_READ_ERR)713 b(read)46 b(error)h(from)f(file)0
+4620 y(362)h(NGP_NUL_PTR)761 b(null)46 b(pointer)g(passed)g(as)h(an)g
+(argument.)1575 4733 y(Passing)f(null)g(pointer)g(as)h(a)h(name)f(of)
+1575 4846 y(template)f(file)g(raises)g(this)h(error)0
+4959 y(363)g(NGP_EMPTY_CURLINE)473 b(line)46 b(read)h(seems)f(to)h(be)h
+(empty)e(\(used)1575 5072 y(internally\))0 5185 y(364)h
+(NGP_UNREAD_QUEUE_FULL)281 b(cannot)46 b(unread)g(more)g(then)h(1)g
+(line)g(\(or)g(single)1575 5297 y(line)g(twice\))0 5410
+y(365)g(NGP_INC_NESTING)569 b(too)46 b(deep)h(include)f(file)h(nesting)
+e(\(infinite)1575 5523 y(loop,)h(template)g(includes)f(itself)i(?\))0
+5636 y(366)g(NGP_ERR_FOPEN)665 b(fopen\(\))45 b(failed,)h(cannot)g
+(open)h(template)e(file)p eop
+%%Page: 126 132
+126 131 bop 0 299 a Fi(126)1613 b Fg(CHAPTER)30 b(12.)112
+b(FITSIO)30 b(ERR)m(OR)g(ST)-8 b(A)g(TUS)30 b(CODES)0
+555 y Fe(367)47 b(NGP_EOF)953 b(end)46 b(of)i(file)e(encountered)f(and)
+i(not)g(expected)0 668 y(368)g(NGP_BAD_ARG)761 b(bad)46
+b(arguments)g(passed.)g(Usually)f(means)1575 781 y(internal)h(parser)g
+(error.)g(Should)g(not)h(happen)0 894 y(369)g(NGP_TOKEN_NOT_EXPECT)329
+b(token)46 b(not)h(expected)e(here)0 1120 y(401)95 b(error)46
+b(attempting)f(to)i(convert)f(an)h(integer)f(to)h(a)h(formatted)d
+(character)g(string)0 1233 y(402)95 b(error)46 b(attempting)f(to)i
+(convert)f(a)h(real)g(value)f(to)i(a)f(formatted)e(character)h(string)0
+1346 y(403)95 b(cannot)46 b(convert)g(a)h(quoted)f(string)g(keyword)g
+(to)h(an)g(integer)0 1458 y(404)95 b(attempted)45 b(to)i(read)g(a)g
+(non-logical)e(keyword)h(value)g(as)h(a)h(logical)e(value)0
+1571 y(405)95 b(cannot)46 b(convert)g(a)h(quoted)f(string)g(keyword)g
+(to)h(a)h(real)e(value)0 1684 y(406)95 b(cannot)46 b(convert)g(a)h
+(quoted)f(string)g(keyword)g(to)h(a)h(double)e(precision)f(value)0
+1797 y(407)95 b(error)46 b(attempting)f(to)i(read)g(character)e(string)
+h(as)h(an)h(integer)0 1910 y(408)95 b(error)46 b(attempting)f(to)i
+(read)g(character)e(string)h(as)h(a)h(real)e(value)0
+2023 y(409)95 b(error)46 b(attempting)f(to)i(read)g(character)e(string)
+h(as)h(a)h(double)e(precision)f(value)0 2136 y(410)95
+b(bad)47 b(keyword)e(datatype)h(code)0 2249 y(411)95
+b(illegal)45 b(number)i(of)g(decimal)f(places)g(while)g(formatting)f
+(floating)h(point)g(value)0 2362 y(412)95 b(numerical)45
+b(overflow)g(during)i(implicit)e(datatype)h(conversion)0
+2475 y(413)95 b(error)46 b(compressing)f(image)0 2588
+y(414)95 b(error)46 b(uncompressing)e(image)0 2700 y(420)95
+b(error)46 b(in)h(date)g(or)g(time)g(conversion)0 2926
+y(431)95 b(syntax)46 b(error)g(in)h(parser)f(expression)0
+3039 y(432)95 b(expression)45 b(did)i(not)f(evaluate)g(to)h(desired)f
+(type)0 3152 y(433)95 b(vector)46 b(result)g(too)h(large)f(to)h(return)
+f(in)i(array)0 3265 y(434)95 b(data)46 b(parser)g(failed)g(not)h(sent)g
+(an)g(out)g(column)0 3378 y(435)95 b(bad)47 b(data)f(encounter)f(while)
+i(parsing)f(column)0 3491 y(436)95 b(parse)46 b(error:)g(output)g(file)
+h(not)g(of)g(proper)f(type)0 3717 y(501)95 b(celestial)45
+b(angle)h(too)h(large)g(for)f(projection)0 3830 y(502)95
+b(bad)47 b(celestial)e(coordinate)g(or)i(pixel)f(value)0
+3942 y(503)95 b(error)46 b(in)h(celestial)e(coordinate)g(calculation)0
+4055 y(504)95 b(unsupported)44 b(type)j(of)g(celestial)e(projection)0
+4168 y(505)95 b(required)45 b(celestial)g(coordinate)g(keywords)h(not)h
+(found)0 4281 y(506)95 b(approximate)44 b(wcs)j(keyword)f(values)g
+(were)h(returned)p eop
+%%Trailer
+end
+userdict /end-hook known{end-hook}if
+%%EOF
diff --git a/pkg/tbtables/cfitsio/fitsio.tex b/pkg/tbtables/cfitsio/fitsio.tex
new file mode 100644
index 00000000..64068047
--- /dev/null
+++ b/pkg/tbtables/cfitsio/fitsio.tex
@@ -0,0 +1,7203 @@
+\documentclass[11pt]{book}
+\input{html.sty}
+\htmladdtonavigation
+ {\begin{rawhtml}
+ <A HREF="http://heasarc.gsfc.nasa.gov/docs/software/fitsio/fitsio.html">FITSIO Home</A>
+ \end{rawhtml}}
+%\oddsidemargin=0.25in
+\oddsidemargin=0.00in
+\evensidemargin=0.00in
+\textwidth=6.5in
+%\topmargin=0.0in
+\textheight=8.75in
+\parindent=0cm
+\parskip=0.2cm
+\begin{document}
+\pagenumbering{roman}
+
+\begin{titlepage}
+\normalsize
+\vspace*{4.6cm}
+\begin{center}
+{\Huge \bf FITSIO User's Guide}\\
+\end{center}
+\medskip
+\medskip
+\begin{center}
+{\LARGE \bf A Subroutine Interface to FITS Format Files}\\
+\end{center}
+\begin{center}
+{\LARGE \bf for Fortran Programmers}\\
+\end{center}
+\medskip
+\medskip
+\begin{center}
+{\Large Version 2.5\\}
+\end{center}
+\bigskip
+\vskip 2.5cm
+\begin{center}
+{HEASARC\\
+Code 662\\
+Goddard Space Flight Center\\
+Greenbelt, MD 20771\\
+USA}
+\end{center}
+
+\vfill
+\bigskip
+\begin{center}
+{\Large July 2004\\}
+\end{center}
+\vfill
+\end{titlepage}
+
+\clearpage
+
+\tableofcontents
+
+\chapter{Introduction }
+\pagenumbering{arabic}
+
+This document describes the Fortran-callable subroutine interface that
+is provided as part of the CFITSIO library (which is written in ANSI
+C). This is a companion document to the CFITSIO User's Guide which
+should be consulted for further information about the underlying
+CFITSIO library. In the remainder of this document, the terms FITSIO
+and CFITSIO are interchangeable and refer to the same library.
+
+FITSIO/CFITSIO is a machine-independent library of routines for reading
+and writing data files in the FITS (Flexible Image Transport System)
+data format. It can also read IRAF format image files and raw binary
+data arrays by converting them on the fly into a virtual FITS format
+file. This library was written to provide a powerful yet simple
+interface for accessing FITS files which will run on most commonly used
+computers and workstations. FITSIO supports all the features described
+in the official NOST definition of the FITS format and can read and
+write all the currently defined types of extensions, including ASCII
+tables (TABLE), Binary tables (BINTABLE) and IMAGE extensions. The
+FITSIO subroutines insulate the programmer from having to deal with the
+complicated formatting details in the FITS file, however, it is assumed
+that users have a general knowledge about the structure and usage of
+FITS files.
+
+The CFITSIO package was initially developed by the HEASARC (High Energy
+Astrophysics Science Archive Research Center) at the NASA Goddard Space
+Flight Center to convert various existing and newly acquired
+astronomical data sets into FITS format and to further analyze data
+already in FITS format. New features continue to be added to CFITSIO
+in large part due to contributions of ideas or actual code from users
+of the package. The Integral Science Data Center in Switzerland, and
+the XMM/ESTEC project in The Netherlands made especially significant
+contributions that resulted in many of the new features that appeared
+in v2.0 of CFITSIO.
+
+The latest version of the CFITSIO source code, documentation, and
+example programs are available on the World-Wide Web or via anonymous
+ftp from:
+
+\begin{verbatim}
+ http://heasarc.gsfc.nasa.gov/fitsio
+ ftp://legacy.gsfc.nasa.gov/software/fitsio/c
+\end{verbatim}
+\newpage
+Any questions, bug reports, or suggested enhancements related to the CFITSIO
+package should be sent to the primary author:
+
+\begin{verbatim}
+ Dr. William Pence Telephone: (301) 286-4599
+ HEASARC, Code 662 E-mail: pence@tetra.gsfc.nasa.gov
+ NASA/Goddard Space Flight Center
+ Greenbelt, MD 20771, USA
+\end{verbatim}
+This User's Guide assumes that readers already have a general
+understanding of the definition and structure of FITS format files.
+Further information about FITS formats is available from the FITS Support
+Office at {\tt http://fits.gsfc.nasa.gov}. In particular, the
+'NOST FITS Standard' gives the authoritative definition of the FITS data
+format, and the `FITS User's Guide' provides additional historical background
+and practical advice on using FITS files.
+
+CFITSIO users may also be interested in the FTOOLS package of programs
+that can be used to manipulate and analyze FITS format files.
+Information about FTOOLS can be obtained on the Web or via anonymous
+ftp at:
+
+\begin{verbatim}
+ http://heasarc.gsfc.nasa.gov/ftools
+ ftp://legacy.gsfc.nasa.gov/software/ftools/release
+\end{verbatim}
+
+\chapter{ Creating FITSIO/CFITSIO }
+
+
+\section{Building the Library}
+
+To use the FITSIO subroutines one must first build the CFITSIO library,
+which requires a C compiler. gcc is ideal, or most other ANSI-C
+compilers will also work. The CFITSIO code is contained in about 40 C
+source files (*.c) and header files (*.h). On VAX/VMS systems 2
+assembly-code files (vmsieeed.mar and vmsieeer.mar) are also needed.
+
+The Fortran interface subroutines to the C CFITSIO routines are located
+in the f77\_wrap1.c, through f77\_wrap4.c files. These are relatively simple
+'wrappers' that translate the arguments in the Fortran subroutine into
+the appropriate format for the corresponding C routine. This
+translation is performed transparently to the user by a set of C macros
+located in the cfortran.h file. Unfortunately cfortran.h does not
+support every combination of C and Fortran compilers so the Fortran
+interface is not supported on all platforms. (see further notes below).
+
+A standard combination of C and Fortran compilers will be assumed by
+default, but one may also specify a particular Fortran compiler by
+doing:
+
+\begin{verbatim}
+ > setenv CFLAGS -DcompilerName=1
+\end{verbatim}
+(where 'compilerName' is the name of the compiler) before running
+the configure command. The currently recognized compiler
+names are:
+
+\begin{verbatim}
+ g77Fortran
+ IBMR2Fortran
+ CLIPPERFortran
+ pgiFortran
+ NAGf90Fortran
+ f2cFortran
+ hpuxFortran
+ apolloFortran
+ sunFortran
+ CRAYFortran
+ mipsFortran
+ DECFortran
+ vmsFortran
+ CONVEXFortran
+ PowerStationFortran
+ AbsoftUNIXFortran
+ AbsoftProFortran
+ SXFortran
+\end{verbatim}
+Alternatively, one may edit the CFLAGS line in the Makefile to add the
+'-DcompilerName' flag after running the './configure' command.
+
+The CFITSIO library is built on Unix systems by typing:
+
+\begin{verbatim}
+ > ./configure [--prefix=/target/installation/path]
+ > make (or 'make shared')
+ > make install (this step is optional)
+\end{verbatim}
+at the operating system prompt. The configure command customizes the
+Makefile for the particular system, then the `make' command compiles the
+source files and builds the library. Type `./configure' and not simply
+`configure' to ensure that the configure script in the current directory
+is run and not some other system-wide configure script. The optional
+'prefix' argument to configure gives the path to the directory where
+the CFITSIO library and include files should be installed via the later
+'make install' command. For example,
+
+\begin{verbatim}
+ > ./configure --prefix=/usr1/local
+\end{verbatim}
+will cause the 'make install' command to copy the CFITSIO libcfitsio file
+to /usr1/local/lib and the necessary include file to /usr1/local/include
+(assuming of course that the process has permission to write to these
+directories).
+
+By default this also builds the set of Fortran-callable
+wrapper routines whose calling sequences are described later in this
+document.
+
+The 'make shared' option builds a shared or dynamic version of the
+CFITSIO library. When using the shared library the executable code is
+not copied into your program at link time and instead the program
+locates the necessary library code at run time, normally through
+LD\_LIBRARY\_PATH or some other method. The advantages of using a shared
+library are:
+
+\begin{verbatim}
+ 1. Less disk space if you build more than 1 program
+ 2. Less memory if more than one copy of a program using the shared
+ library is running at the same time since the system is smart
+ enough to share copies of the shared library at run time.
+ 3. Possibly easier maintenance since a new version of the shared
+ library can be installed without relinking all the software
+ that uses it (as long as the subroutine names and calling
+ sequences remain unchanged).
+ 4. No run-time penalty.
+\end{verbatim}
+The disadvantages are:
+
+\begin{verbatim}
+ 1. More hassle at runtime. You have to either build the programs
+ specially or have LD_LIBRARY_PATH set right.
+ 2. There may be a slight start up penalty, depending on where you are
+ reading the shared library and the program from and if your CPU is
+ either really slow or really heavily loaded.
+\end{verbatim}
+
+On HP/UX systems, the environment variable CFLAGS should be set
+to -Ae before running configure to enable "extended ANSI" features.
+
+It may not be possible to staticly link programs that use CFITSIO on
+some platforms (namely, on Solaris 2.6) due to the network drivers
+(which provide FTP and HTTP access to FITS files). It is possible to
+make both a dynamic and a static version of the CFITSIO library, but
+network file access will not be possible using the static version.
+
+On VAX/VMS and ALPHA/VMS systems the make\_gfloat.com command file may
+be executed to build the cfitsio.olb object library using the default
+G-floating point option for double variables. The make\_dfloat.com and
+make\_ieee.com files may be used instead to build the library with the
+other floating point options. Note that the getcwd function that is
+used in the group.c module may require that programs using CFITSIO be
+linked with the ALPHA\$LIBRARY:VAXCRTL.OLB library. See the example
+link line in the next section of this document.
+
+On Windows IBM-PC type platforms the situation is more complicated
+because of the wide variety of Fortran compilers that are available and
+because of the inherent complexities of calling the CFITSIO C routines
+from Fortran. Two different versions of the CFITSIO dll library are
+available, compiled with the Borland C++ compiler and the Microsoft
+Visual C++ compiler, respectively, in the files
+cfitsiodll\_2xxx\_borland.zip and cfitsiodll\_2xxx\_vcc.zip, where
+'2xxx' represents the current release number. Both these dll libraries
+contain a set of Fortran wrapper routines which may be compatible with
+some, but probably not all, available Fortran compilers. To test if
+they are compatible, compile the program testf77.f and try linking to
+these dll libraries. If these libraries do not work with a particular
+Fortran compiler, then there are 2 possible solutions. The first
+solution would be to modify the file cfortran.h for that particular
+combination of C and Fortran compilers, and then rebuild the CFITSIO
+dll library. This will require, however, a some expertise in
+mixed language programming.
+The other solution is to use the older v5.03 Fortran-77 implementation
+of FITSIO that is still available from the FITSIO web-site. This
+version is no longer supported, but it does provide the basic functions
+for reading and writing FITS files and should be compatible with most
+Fortran compilers.
+
+CFITSIO has currently been tested on the following platforms:
+
+\begin{verbatim}
+ OPERATING SYSTEM COMPILER
+ Sun OS gcc and cc (3.0.1)
+ Sun Solaris gcc and cc
+ Silicon Graphics IRIX gcc and cc
+ Silicon Graphics IRIX64 MIPS
+ Dec Alpha OSF/1 gcc and cc
+ DECstation Ultrix gcc
+ Dec Alpha OpenVMS cc
+ DEC VAX/VMS gcc and cc
+ HP-UX gcc
+ IBM AIX gcc
+ Linux gcc
+ MkLinux DR3
+ Windows 95/98/NT Borland C++ V4.5
+ Windows 95/98/NT/ME/XP Microsoft/Compaq Visual C++ v5.0, v6.0
+ Windows 95/98/NT Cygwin gcc
+ OS/2 gcc + EMX
+ MacOS 7.1 or greater Metrowerks 10.+
+\end{verbatim}
+CFITSIO will probably run on most other Unix platforms. Cray
+supercomputers are currently not supported.
+
+
+\section{Testing the Library}
+
+The CFITSIO library should be tested by building and running
+the testprog.c program that is included with the release.
+On Unix systems type:
+
+\begin{verbatim}
+ % make testprog
+ % testprog > testprog.lis
+ % diff testprog.lis testprog.out
+ % cmp testprog.fit testprog.std
+\end{verbatim}
+ On VMS systems,
+(assuming cc is the name of the C compiler command), type:
+
+\begin{verbatim}
+ $ cc testprog.c
+ $ link testprog, cfitsio/lib, alpha$library:vaxcrtl/lib
+ $ run testprog
+\end{verbatim}
+The testprog program should produce a FITS file called `testprog.fit'
+that is identical to the `testprog.std' FITS file included with this
+release. The diagnostic messages (which were piped to the file
+testprog.lis in the Unix example) should be identical to the listing
+contained in the file testprog.out. The 'diff' and 'cmp' commands
+shown above should not report any differences in the files. (There
+may be some minor formatting differences, such as the presence or
+absence of leading zeros, or 3 digit exponents in numbers,
+which can be ignored).
+
+The Fortran wrappers in CFITSIO may be tested with the testf77
+program. On Unix systems the fortran compilation and link command
+may be called 'f77' or 'g77', depending on the system.
+
+\begin{verbatim}
+ % f77 -o testf77 testf77.f -L. -lcfitsio -lnsl -lsocket
+ or
+ % f77 -f -o testf77 testf77.f -L. -lcfitsio (under SUN O/S)
+ or
+ % f77 -o testf77 testf77.f -Wl,-L. -lcfitsio -lm -lnsl -lsocket (HP/UX)
+ or
+ % g77 -o testf77 -s testf77.f -lcfitsio -lcc_dynamic -lncurses (Mac OS-X)
+
+ % testf77 > testf77.lis
+ % diff testf77.lis testf77.out
+ % cmp testf77.fit testf77.std
+\end{verbatim}
+On machines running SUN O/S, Fortran programs must be compiled with the
+'-f' option to force double precision variables to be aligned on 8-byte
+boundarys to make the fortran-declared variables compatible with C. A
+similar compiler option may be required on other platforms. Failing to
+use this option may cause the program to crash on FITSIO routines that
+read or write double precision variables.
+
+Also note that on some systems, the output listing of the testf77
+program may differ slightly from the testf77.std template, if leading
+zeros are not printed by default before the decimal point when using F
+format.
+
+A few other utility programs are included with CFITSIO:
+
+\begin{verbatim}
+ speed - measures the maximum throughput (in MB per second)
+ for writing and reading FITS files with CFITSIO
+
+ listhead - lists all the header keywords in any FITS file
+
+ fitscopy - copies any FITS file (especially useful in conjunction
+ with the CFITSIO's extended input filename syntax)
+
+ cookbook - a sample program that peforms common read and
+ write operations on a FITS file.
+
+ iter_a, iter_b, iter_c - examples of the CFITSIO iterator routine
+\end{verbatim}
+
+The first 4 of these utility programs can be compiled and linked by typing
+
+\begin{verbatim}
+ % make program_name
+\end{verbatim}
+
+
+\section{Linking Programs with FITSIO}
+
+When linking applications software with the FITSIO library, several system libraries usually need to be specified on the link comman
+Unix systems, the most reliable way to determine what libraries are required
+is to type 'make testprog' and see what libraries the configure script has
+added. The typical libraries that may need to be added are -lm (the math
+library) and -lnsl and -lsocket (needed only for FTP and HTTP file access).
+These latter 2 libraries are not needed on VMS and Windows platforms,
+because FTP file access is not currently supported on those platforms.
+
+Note that when upgrading to a newer version of CFITSIO it is usually
+necessay to recompile, as well as relink, the programs that use CFITSIO,
+because the definitions in fitsio.h often change.
+
+
+\section{Getting Started with FITSIO}
+
+In order to effectively use the FITSIO library as quickly as possible,
+it is recommended that new users follow these steps:
+
+1. Read the following `FITS Primer' chapter for a brief
+overview of the structure of FITS files. This is especially important
+for users who have not previously dealt with the FITS table and image
+extensions.
+
+2. Write a simple program to read or write a FITS file using the Basic
+Interface routines.
+
+3. Refer to the cookbook.f program that is included with this release
+for examples of routines that perform various common FITS file
+operations.
+
+4. Read Chapters 4 and 5 to become familiar with the conventions and
+advanced features of the FITSIO interface.
+
+5. Scan through the more extensive set of routines that are provided
+in the `Advanced Interface'. These routines perform more specialized
+functions than are provided by the Basic Interface routines.
+
+
+\section{Example Program}
+
+The following listing shows an example of how to use the FITSIO
+routines in a Fortran program. Refer to the cookbook.f program that
+is included with the FITSIO distribution for examples of other
+FITS programs.
+
+\begin{verbatim}
+ program writeimage
+
+C Create a FITS primary array containing a 2-D image
+
+ integer status,unit,blocksize,bitpix,naxis,naxes(2)
+ integer i,j,group,fpixel,nelements,array(300,200)
+ character filename*80
+ logical simple,extend
+
+ status=0
+C Name of the FITS file to be created:
+ filename='ATESTFILE.FITS'
+
+C Get an unused Logical Unit Number to use to create the FITS file
+ call ftgiou(unit,status)
+
+C create the new empty FITS file
+ blocksize=1
+ call ftinit(unit,filename,blocksize,status)
+
+C initialize parameters about the FITS image (300 x 200 16-bit integers)
+ simple=.true.
+ bitpix=16
+ naxis=2
+ naxes(1)=300
+ naxes(2)=200
+ extend=.true.
+
+C write the required header keywords
+ call ftphpr(unit,simple,bitpix,naxis,naxes,0,1,extend,status)
+
+C initialize the values in the image with a linear ramp function
+ do j=1,naxes(2)
+ do i=1,naxes(1)
+ array(i,j)=i+j
+ end do
+ end do
+
+C write the array to the FITS file
+ group=1
+ fpixel=1
+ nelements=naxes(1)*naxes(2)
+ call ftpprj(unit,group,fpixel,nelements,array,status)
+
+C write another optional keyword to the header
+ call ftpkyj(unit,'EXPOSURE',1500,'Total Exposure Time',status)
+
+C close the file and free the unit number
+ call ftclos(unit, status)
+ call ftfiou(unit, status)
+ end
+\end{verbatim}
+
+
+\section{Legal Stuff}
+
+Copyright (Unpublished--all rights reserved under the copyright laws of
+the United States), U.S. Government as represented by the Administrator
+of the National Aeronautics and Space Administration. No copyright is
+claimed in the United States under Title 17, U.S. Code.
+
+Permission to freely use, copy, modify, and distribute this software
+and its documentation without fee is hereby granted, provided that this
+copyright notice and disclaimer of warranty appears in all copies.
+(However, see the restriction on the use of the gzip compression code,
+below).
+
+DISCLAIMER:
+
+THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND,
+EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO,
+ANY WARRANTY THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY
+IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE, AND FREEDOM FROM INFRINGEMENT, AND ANY WARRANTY THAT THE
+DOCUMENTATION WILL CONFORM TO THE SOFTWARE, OR ANY WARRANTY THAT THE
+SOFTWARE WILL BE ERROR FREE. IN NO EVENT SHALL NASA BE LIABLE FOR ANY
+DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, INDIRECT, SPECIAL OR
+CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, OR IN ANY WAY
+CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY,
+CONTRACT, TORT , OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY
+PERSONS OR PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED
+FROM, OR AROSE OUT OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR
+SERVICES PROVIDED HEREUNDER."
+
+The file compress.c contains (slightly modified) source code that
+originally came from gzip-1.2.4, copyright (C) 1992-1993 by Jean-loup
+Gailly. This gzip code is distributed under the GNU General Public
+License and thus requires that any software that uses the CFITSIO
+library (which in turn uses the gzip code) must conform to the
+provisions in the GNU General Public License. A copy of the GNU
+license is included at the beginning of compress.c file.
+
+An alternate version of the compress.c file (called
+compress\_alternate.c) is provided for users who want to use the CFITSIO
+library but are unwilling or unable to publicly release their software
+under the terms of the GNU General Public License. This alternate
+version contains non-functional stubs for the file compression and
+uncompression routines used by CFITSIO. Replace the file `compress.c'
+with `compress\_alternate.c' before compiling the CFITSIO library. This
+will produce a version of CFITSIO which does not support reading or
+writing compressed FITS files but is otherwise identical to the
+standard version.
+
+
+\section{Acknowledgements}
+
+The development of many of the powerful features in CFITSIO was made
+possible through collaborations with many people or organizations from
+around the world. The following, in particular, have made especially
+significant contributions:
+
+Programmers from the Integral Science Data Center, Switzerland (namely,
+Jurek Borkowski, Bruce O'Neel, and Don Jennings), designed the concept
+for the plug-in I/O drivers that was introduced with CFITSIO 2.0. The
+use of `drivers' greatly simplified the low-level I/O, which in turn
+made other new features in CFITSIO (e.g., support for compressed FITS
+files and support for IRAF format image files) much easier to
+implement. Jurek Borkowski wrote the Shared Memory driver, and Bruce
+O'Neel wrote the drivers for accessing FITS files over the network
+using the FTP, HTTP, and ROOT protocols.
+
+The ISDC also provided the template parsing routines (written by Jurek
+Borkowski) and the hierarchical grouping routines (written by Don
+Jennings). The ISDC DAL (Data Access Layer) routines are layered on
+top of CFITSIO and make extensive use of these features.
+
+Uwe Lammers (XMM/ESA/ESTEC, The Netherlands) designed the
+high-performance lexical parsing algorithm that is used to do
+on-the-fly filtering of FITS tables. This algorithm essentially
+pre-compiles the user-supplied selection expression into a form that
+can be rapidly evaluated for each row. Peter Wilson (RSTX, NASA/GSFC)
+then wrote the parsing routines used by CFITSIO based on Lammers'
+design, combined with other techniques such as the CFITSIO iterator
+routine to further enhance the data processing throughput. This effort
+also benefited from a much earlier lexical parsing routine that was
+developed by Kent Blackburn (NASA/GSFC). More recently, Craig Markwardt
+(NASA/GSFC) implemented additional functions (median, average, stddev)
+and other enhancements to the lexical parser.
+
+The CFITSIO iterator function is loosely based on similar ideas
+developed for the XMM Data Access Layer.
+
+Peter Wilson (RSTX, NASA/GSFC) wrote the complete set of
+Fortran-callable wrappers for all the CFITSIO routines, which in turn
+rely on the CFORTRAN macro developed by Burkhard Burow.
+
+The syntax used by CFITSIO for filtering or binning input FITS files is
+based on ideas developed for the AXAF Science Center Data Model by
+Jonathan McDowell, Antonella Fruscione, Aneta Siemiginowska and Bill
+Joye. See http://heasarc.gsfc.nasa.gov/docs/journal/axaf7.html for
+further description of the AXAF Data Model.
+
+The file decompression code were taken directly from the gzip (GNU zip)
+program developed by Jean-loup Gailly and others.
+
+Doug Mink, SAO, provided the routines for converting IRAF format
+images into FITS format.
+
+In addition, many other people have made valuable contributions to the
+development of CFITSIO. These include (with apologies to others that may
+have inadvertently been omitted):
+
+Steve Allen, Carl Akerlof, Keith Arnaud, Morten Krabbe Barfoed, Kent
+Blackburn, G Bodammer, Romke Bontekoe, Lucio Chiappetti, Keith Costorf,
+Robin Corbet, John Davis, Richard Fink, Ning Gan, Emily Greene, Joe
+Harrington, Cheng Ho, Phil Hodge, Jim Ingham, Yoshitaka Ishisaki, Diab
+Jerius, Mark Levine, Todd Karakaskian, Edward King, Scott Koch, Claire
+Larkin, Rob Managan, Eric Mandel, John Mattox, Carsten Meyer, Emi
+Miyata, Stefan Mochnacki, Mike Noble, Oliver Oberdorf, Clive Page,
+Arvind Parmar, Jeff Pedelty, Tim Pearson, Maren Purves, Scott Randall,
+Chris Rogers, Arnold Rots, Barry Schlesinger, Robin Stebbins, Andrew
+Szymkowiak, Allyn Tennant, Peter Teuben, James Theiler, Doug Tody,
+Shiro Ueno, Steve Walton, Archie Warnock, Alan Watson, Dan Whipple, Wim
+Wimmers, Peter Young, Jianjun Xu, and Nelson Zarate.
+
+
+\chapter{ A FITS Primer }
+
+This section gives a brief overview of the structure of FITS files.
+Users should refer to the documentation available from the NOST, as
+described in the introduction, for more detailed information on FITS
+formats.
+
+FITS was first developed in the late 1970's as a standard data
+interchange format between various astronomical observatories. Since
+then FITS has become the defacto standard data format supported by most
+astronomical data analysis software packages.
+
+A FITS file consists of one or more Header + Data Units (HDUs), where
+the first HDU is called the `Primary HDU', or `Primary Array'. The
+primary array contains an N-dimensional array of pixels, such as a 1-D
+spectrum, a 2-D image, or a 3-D data cube. Five different primary
+datatypes are supported: Unsigned 8-bit bytes, 16 and 32-bit signed
+integers, and 32 and 64-bit floating point reals. FITS also has a
+convention for storing 16 and 32-bit unsigned integers (see the later
+section entitled `Unsigned Integers' for more details). The primary HDU
+may also consist of only a header with a null array containing no
+data pixels.
+
+Any number of additional HDUs may follow the primary array; these
+additional HDUs are called FITS `extensions'. There are currently 3
+types of extensions defined by the FITS standard:
+
+\begin{itemize}
+\item
+ Image Extension - a N-dimensional array of pixels, like in a primary array
+\item
+ ASCII Table Extension - rows and columns of data in ASCII character format
+\item
+ Binary Table Extension - rows and columns of data in binary representation
+\end{itemize}
+
+In each case the HDU consists of an ASCII Header Unit followed by an optional
+Data Unit. For historical reasons, each Header or Data unit must be an
+exact multiple of 2880 8-bit bytes long. Any unused space is padded
+with fill characters (ASCII blanks or zeros).
+
+Each Header Unit consists of any number of 80-character keyword records
+or `card images' which have the general form:
+
+\begin{verbatim}
+ KEYNAME = value / comment string
+ NULLKEY = / comment: This keyword has no value
+\end{verbatim}
+The keyword names may be up to 8 characters long and can only contain
+uppercase letters, the digits 0-9, the hyphen, and the underscore
+character. The keyword name is (usually) followed by an equals sign and
+a space character (= ) in columns 9 - 10 of the record, followed by the
+value of the keyword which may be either an integer, a floating point
+number, a character string (enclosed in single quotes), or a boolean
+value (the letter T or F). A keyword may also have a null or undefined
+value if there is no specified value string, as in the second example.
+
+The last keyword in the header is always the `END' keyword which has no
+value or comment fields. There are many rules governing the exact
+format of a keyword record (see the NOST FITS Standard) so it is better
+to rely on standard interface software like FITSIO to correctly
+construct or to parse the keyword records rather than try to deal
+directly with the raw FITS formats.
+
+Each Header Unit begins with a series of required keywords which depend
+on the type of HDU. These required keywords specify the size and
+format of the following Data Unit. The header may contain other
+optional keywords to describe other aspects of the data, such as the
+units or scaling values. Other COMMENT or HISTORY keywords are also
+frequently added to further document the data file.
+
+The optional Data Unit immediately follows the last 2880-byte block in
+the Header Unit. Some HDUs do not have a Data Unit and only consist of
+the Header Unit.
+
+If there is more than one HDU in the FITS file, then the Header Unit of
+the next HDU immediately follows the last 2880-byte block of the
+previous Data Unit (or Header Unit if there is no Data Unit).
+
+The main required keywords in FITS primary arrays or image extensions are:
+\begin{itemize}
+\item
+BITPIX -- defines the datatype of the array: 8, 16, 32, -32, -64 for
+unsigned 8--bit byte, 16--bit signed integer, 32--bit signed integer,
+32--bit IEEE floating point, and 64--bit IEEE double precision floating
+point, respectively.
+\item
+NAXIS -- the number of dimensions in the array, usually 0, 1, 2, 3, or 4.
+\item
+NAXISn -- (n ranges from 1 to NAXIS) defines the size of each dimension.
+\end{itemize}
+
+FITS tables start with the keyword XTENSION = `TABLE' (for ASCII
+tables) or XTENSION = `BINTABLE' (for binary tables) and have the
+following main keywords:
+\begin{itemize}
+\item
+TFIELDS -- number of fields or columns in the table
+\item
+NAXIS2 -- number of rows in the table
+\item
+TTYPEn -- for each column (n ranges from 1 to TFIELDS) gives the
+name of the column
+\item
+TFORMn -- the datatype of the column
+\item
+TUNITn -- the physical units of the column (optional)
+\end{itemize}
+
+Users should refer to the FITS Support Office at {\tt http://fits.gsfc.nasa.gov}
+for futher information about the FITS format and related software
+packages.
+
+
+\chapter{ Extended File Name Syntax }
+
+
+\section{Overview}
+
+CFITSIO supports an extended syntax when specifying the name of the
+data file to be opened or created that includes the following
+features:
+
+\begin{itemize}
+\item
+CFITSIO can read IRAF format images which have header file names that
+end with the '.imh' extension, as well as reading and writing FITS
+files, This feature is implemented in CFITSIO by first converting the
+IRAF image into a temporary FITS format file in memory, then opening
+the FITS file. Any of the usual CFITSIO routines then may be used to
+read the image header or data. Similarly, raw binary data arrays can
+be read by converting them on the fly into virtual FITS images.
+
+\item
+FITS files on the internet can be read (and sometimes written) using the FTP,
+HTTP, or ROOT protocols.
+
+\item
+FITS files can be piped between tasks on the stdin and stdout streams.
+
+\item
+FITS files can be read and written in shared memory. This can potentially
+achieve much better data I/O performance compared to reading and
+writing the same FITS files on magnetic disk.
+
+\item
+Compressed FITS files in gzip or Unix COMPRESS format can be directly read.
+
+\item
+Output FITS files can be written directly in compressed gzip format,
+thus saving disk space.
+
+\item
+FITS table columns can be created, modified, or deleted 'on-the-fly' as
+the table is opened by CFITSIO. This creates a virtual FITS file containing
+the modifications that is then opened by the application program.
+
+\item
+Table rows may be selected, or filtered out, on the fly when the table
+is opened by CFITSIO, based on an arbitrary user-specified expression.
+Only rows for which the expression evaluates to 'TRUE' are retained
+in the copy of the table that is opened by the application program.
+
+\item
+Histogram images may be created on the fly by binning the values in
+table columns, resulting in a virtual N-dimensional FITS image. The
+application program then only sees the FITS image (in the primary
+array) instead of the original FITS table.
+\end{itemize}
+
+The latter 3 features in particular add very powerful data processing
+capabilities directly into CFITSIO, and hence into every task that uses
+CFITSIO to read or write FITS files. For example, these features
+transform a very simple program that just copies an input FITS file to
+a new output file (like the `fitscopy' program that is distributed with
+CFITSIO) into a multipurpose FITS file processing tool. By appending
+fairly simple qualifiers onto the name of the input FITS file, the user
+can perform quite complex table editing operations (e.g., create new
+columns, or filter out rows in a table) or create FITS images by
+binning or histogramming the values in table columns. In addition,
+these functions have been coded using new state-of-the art algorithms
+that are, in some cases, 10 - 100 times faster than previous widely
+used implementations.
+
+Before describing the complete syntax for the extended FITS file names
+in the next section, here are a few examples of FITS file names that
+give a quick overview of the allowed syntax:
+
+\begin{itemize}
+\item
+{\tt 'myfile.fits'}: the simplest case of a FITS file on disk in the current
+directory.
+
+\item
+{\tt 'myfile.imh'}: opens an IRAF format image file and converts it on the
+fly into a temporary FITS format image in memory which can then be read with
+any other CFITSIO routine.
+
+\item
+{\tt rawfile.dat[i512,512]}: opens a raw binary data array (a 512 x 512
+short integer array in this case) and converts it on the fly into a
+temporary FITS format image in memory which can then be read with any
+other CFITSIO routine.
+
+\item
+{\tt myfile.fits.gz}: if this is the name of a new output file, the '.gz'
+suffix will cause it to be compressed in gzip format when it is written to
+disk.
+
+\item
+{\tt 'myfile.fits.gz[events, 2]'}: opens and uncompresses the gzipped file
+myfile.fits then moves to the extension which has the keywords EXTNAME
+= 'EVENTS' and EXTVER = 2.
+
+\item
+{\tt '-'}: a dash (minus sign) signifies that the input file is to be read
+from the stdin file stream, or that the output file is to be written to
+the stdout stream.
+
+\item
+{\tt 'ftp://legacy.gsfc.nasa.gov/test/vela.fits'}: FITS files in any ftp
+archive site on the internet may be directly opened with read-only
+access.
+
+\item
+{\tt 'http://legacy.gsfc.nasa.gov/software/test.fits'}: any valid URL to a
+FITS file on the Web may be opened with read-only access.
+
+\item
+{\tt 'root://legacy.gsfc.nasa.gov/test/vela.fits'}: similar to ftp access
+except that it provides write as well as read access to the files
+across the network. This uses the root protocol developed at CERN.
+
+\item
+{\tt 'shmem://h2[events]'}: opens the FITS file in a shared memory segment and
+moves to the EVENTS extension.
+
+\item
+{\tt 'mem://'}: creates a scratch output file in core computer memory. The
+resulting 'file' will disappear when the program exits, so this
+is mainly useful for testing purposes when one does not want a
+permanent copy of the output file.
+
+\item
+{\tt 'myfile.fits[3; Images(10)]'}: opens a copy of the image contained in the
+10th row of the 'Images' column in the binary table in the 3th extension
+of the FITS file. The application just sees this single image as the
+primary array.
+
+\item
+{\tt 'myfile.fits[1:512:2, 1:512:2]'}: opens a section of the input image
+ranging from the 1st to the 512th pixel in X and Y, and selects every
+second pixel in both dimensions, resulting in a 256 x 256 pixel image
+in this case.
+
+\item
+{\tt 'myfile.fits[EVENTS][col Rad = sqrt(X**2 + Y**2)]'}: creates and opens
+a temporary file on the fly (in memory or on disk) that is identical to
+myfile.fits except that it will contain a new column in the EVENTS
+extension called 'Rad' whose value is computed using the indicated
+expresson which is a function of the values in the X and Y columns.
+
+\item
+{\tt 'myfile.fits[EVENTS][PHA > 5]'}: creates and opens a temporary FITS
+files that is identical to 'myfile.fits' except that the EVENTS table
+will only contain the rows that have values of the PHA column greater
+than 5. In general, any arbitrary boolean expression using a C or
+Fortran-like syntax, which may combine AND and OR operators,
+may be used to select rows from a table.
+
+\item
+{\tt 'myfile.fits[EVENTS][bin (X,Y)=1,2048,4]'}: creates a temporary FITS
+primary array image which is computed on the fly by binning (i.e,
+computing the 2-dimensional histogram) of the values in the X and Y
+columns of the EVENTS extension. In this case the X and Y coordinates
+range from 1 to 2048 and the image pixel size is 4 units in both
+dimensions, so the resulting image is 512 x 512 pixels in size.
+
+\item
+The final example combines many of these feature into one complex
+expression (it is broken into several lines for clarity):
+
+\begin{verbatim}
+ 'ftp://legacy.gsfc.nasa.gov/data/sample.fits.gz[EVENTS]
+ [col phacorr = pha * 1.1 - 0.3][phacorr >= 5.0 && phacorr <= 14.0]
+ [bin (X,Y)=32]'
+\end{verbatim}
+In this case, CFITSIO (1) copies and uncompresses the FITS file from
+the ftp site on the legacy machine, (2) moves to the 'EVENTS'
+extension, (3) calculates a new column called 'phacorr', (4) selects
+the rows in the table that have phacorr in the range 5 to 14, and
+finally (5) bins the remaining rows on the X and Y column coordinates,
+using a pixel size = 32 to create a 2D image. All this processing is
+completely transparent to the application program, which simply sees
+the final 2-D image in the primary array of the opened file.
+\end{itemize}
+
+The full extended CFITSIO FITS file name can contain several different
+components depending on the context. These components are described in
+the following sections:
+
+\begin{verbatim}
+When creating a new file:
+ filetype://BaseFilename(templateName)
+
+When opening an existing primary array or image HDU:
+ filetype://BaseFilename(outName)[HDUlocation][ImageSection]
+
+When opening an existing table HDU:
+ filetype://BaseFilename(outName)[HDUlocation][colFilter][rowFilter][binSpec]
+\end{verbatim}
+The filetype, BaseFilename, outName, HDUlocation, and ImageSection
+components, if present, must be given in that order, but the colFilter,
+rowFilter, and binSpec specifiers may follow in any order. Regardless
+of the order, however, the colFilter specifier, if present, will be
+processed first by CFITSIO, followed by the rowFilter specifier, and
+finally by the binSpec specifier.
+
+
+\section{Filetype}
+
+The type of file determines the medium on which the file is located
+(e.g., disk or network) and, hence, which internal device driver is used by
+CFITSIO to read and/or write the file. Currently supported types are
+
+\begin{verbatim}
+ file:// - file on local magnetic disk (default)
+ ftp:// - a readonly file accessed with the anonymous FTP protocol.
+ It also supports ftp://username:password@hostname/...
+ for accessing password-protected ftp sites.
+ http:// - a readonly file accessed with the HTTP protocol. It
+ does not support username:password like the ftp driver.
+ Proxy HTTP servers are supported using the http_proxy
+ environment variable.
+ root:// - uses the CERN root protocol for writing as well as
+ reading files over the network.
+ shmem:// - opens or creates a file which persists in the computer's
+ shared memory.
+ mem:// - opens a temporary file in core memory. The file
+ disappears when the program exits so this is mainly
+ useful for test purposes when a permanent output file
+ is not desired.
+\end{verbatim}
+If the filetype is not specified, then type file:// is assumed.
+The double slashes '//' are optional and may be omitted in most cases.
+
+
+\subsection{Notes about HTTP proxy servers}
+
+A proxy HTTP server may be used by defining the address (URL) and port
+number of the proxy server with the http\_proxy environment variable.
+For example
+
+\begin{verbatim}
+ setenv http_proxy http://heasarc.gsfc.nasa.gov:3128
+\end{verbatim}
+will cause CFITSIO to use port 3128 on the heasarc proxy server whenever
+reading a FITS file with HTTP.
+
+
+\subsection{Notes about the root filetype}
+
+The original rootd server can be obtained from:
+\verb-ftp://root.cern.ch/root/rootd.tar.gz-
+but, for it to work correctly with CFITSIO one has to use a modified
+version which supports a command to return the length of the file.
+This modified version is available in rootd subdirectory
+in the CFITSIO ftp area at
+
+\begin{verbatim}
+ ftp://legacy.gsfc.nasa.gov/software/fitsio/c/root/rootd.tar.gz.
+\end{verbatim}
+
+This small server is started either by inetd when a client requests a
+connection to a rootd server or by hand (i.e. from the command line).
+The rootd server works with the ROOT TNetFile class. It allows remote
+access to ROOT database files in either read or write mode. By default
+TNetFile assumes port 432 (which requires rootd to be started as root).
+To run rootd via inetd add the following line to /etc/services:
+
+\begin{verbatim}
+ rootd 432/tcp
+\end{verbatim}
+and to /etc/inetd.conf, add the following line:
+
+\begin{verbatim}
+ rootd stream tcp nowait root /user/rdm/root/bin/rootd rootd -i
+\end{verbatim}
+Force inetd to reread its conf file with "kill -HUP <pid inetd>".
+You can also start rootd by hand running directly under your private
+account (no root system privileges needed). For example to start
+rootd listening on port 5151 just type: \verb+rootd -p 5151+
+Notice: no \& is needed. Rootd will go into background by itself.
+
+\begin{verbatim}
+ Rootd arguments:
+ -i says we were started by inetd
+ -p port# specifies a different port to listen on
+ -d level level of debug info written to syslog
+ 0 = no debug (default)
+ 1 = minimum
+ 2 = medium
+ 3 = maximum
+\end{verbatim}
+Rootd can also be configured for anonymous usage (like anonymous ftp).
+To setup rootd to accept anonymous logins do the following (while being
+logged in as root):
+
+\begin{verbatim}
+ - Add the following line to /etc/passwd:
+
+ rootd:*:71:72:Anonymous rootd:/var/spool/rootd:/bin/false
+
+ where you may modify the uid, gid (71, 72) and the home directory
+ to suite your system.
+
+ - Add the following line to /etc/group:
+
+ rootd:*:72:rootd
+
+ where the gid must match the gid in /etc/passwd.
+
+ - Create the directories:
+
+ mkdir /var/spool/rootd
+ mkdir /var/spool/rootd/tmp
+ chmod 777 /var/spool/rootd/tmp
+
+ Where /var/spool/rootd must match the rootd home directory as
+ specified in the rootd /etc/passwd entry.
+
+ - To make writeable directories for anonymous do, for example:
+
+ mkdir /var/spool/rootd/pub
+ chown rootd:rootd /var/spool/rootd/pub
+\end{verbatim}
+That's all. Several additional remarks: you can login to an anonymous
+server either with the names "anonymous" or "rootd". The password should
+be of type user@host.do.main. Only the @ is enforced for the time
+being. In anonymous mode the top of the file tree is set to the rootd
+home directory, therefore only files below the home directory can be
+accessed. Anonymous mode only works when the server is started via
+inetd.
+
+
+\subsection{Notes about the shmem filetype:}
+
+Shared memory files are currently supported on most Unix platforms,
+where the shared memory segments are managed by the operating system
+kernel and `live' independently of processes. They are not deleted (by
+default) when the process which created them terminates, although they
+will disappear if the system is rebooted. Applications can create
+shared memory files in CFITSIO by calling:
+
+\begin{verbatim}
+ fit_create_file(&fitsfileptr, "shmem://h2", &status);
+\end{verbatim}
+where the root `file' names are currently restricted to be 'h0', 'h1',
+'h2', 'h3', etc., up to a maximumn number defined by the the value of
+SHARED\_MAXSEG (equal to 16 by default). This is a prototype
+implementation of the shared memory interface and a more robust
+interface, which will have fewer restrictions on the number of files
+and on their names, may be developed in the future.
+
+When opening an already existing FITS file in shared memory one calls
+the usual CFITSIO routine:
+
+\begin{verbatim}
+ fits_open_file(&fitsfileptr, "shmem://h7", mode, &status)
+\end{verbatim}
+The file mode can be READWRITE or READONLY just as with disk files.
+More than one process can operate on READONLY mode files at the same
+time. CFITSIO supports proper file locking (both in READONLY and
+READWRITE modes), so calls to fits\_open\_file may be locked out until
+another other process closes the file.
+
+When an application is finished accessing a FITS file in a shared
+memory segment, it may close it (and the file will remain in the
+system) with fits\_close\_file, or delete it with fits\_delete\_file.
+Physical deletion is postponed until the last process calls
+ffclos/ffdelt. fits\_delete\_file tries to obtain a READWRITE lock on
+the file to be deleted, thus it can be blocked if the object was not
+opened in READWRITE mode.
+
+A shared memory management utility program called `smem', is included
+with the CFITSIO distribution. It can be built by typing `make smem';
+then type `smem -h' to get a list of valid options. Executing smem
+without any options causes it to list all the shared memory segments
+currently residing in the system and managed by the shared memory
+driver. To get a list of all the shared memory objects, run the system
+utility program `ipcs [-a]'.
+
+
+\section{Base Filename}
+
+The base filename is the name of the file optionally including the
+director/subdirectory path, and in the case of `ftp', `http', and `root'
+filetypes, the machine identifier. Examples:
+
+\begin{verbatim}
+ myfile.fits
+ !data.fits
+ /data/myfile.fits
+ fits.gsfc.nasa.gov/ftp/sampledata/myfile.fits.gz
+\end{verbatim}
+
+When creating a new output file on magnetic disk (of type file://) if
+the base filename begins with an exclamation point (!) then any
+existing file with that same basename will be deleted prior to creating
+the new FITS file. Otherwise if the file to be created already exists,
+then CFITSIO will return an error and will not overwrite the existing
+file. Note that the exclamation point, '!', is a special UNIX character,
+so if it is used on the command line rather than entered at a task
+prompt, it must be preceded by a backslash to force the UNIX
+shell to pass it verbatim to the application program.
+
+If the output disk file name ends with the suffix '.gz', then CFITSIO
+will compress the file using the gzip compression algorithm before
+writing it to disk. This can reduce the amount of disk space used by
+the file. Note that this feature requires that the uncompressed file
+be constructed in memory before it is compressed and written to disk,
+so it can fail if there is insufficient available memory.
+
+An input FITS file may be compressed with the gzip or Unix compress
+algorithms, in which case CFITSIO will uncompress the file on the fly
+into a temporary file (in memory or on disk). Compressed files may
+only be opened with read-only permission. When specifying the name of
+a compressed FITS file it is not necessary to append the file suffix
+(e.g., `.gz' or `.Z'). If CFITSIO cannot find the input file name
+without the suffix, then it will automatically search for a compressed
+file with the same root name. In the case of reading ftp and http type
+files, CFITSIO generally looks for a compressed version of the file
+first, before trying to open the uncompressed file. By default,
+CFITSIO copies (and uncompressed if necessary) the ftp or http FITS
+file into memory on the local machine before opening it. This will
+fail if the local machine does not have enough memory to hold the whole
+FITS file, so in this case, the output filename specifier (see the next
+section) can be used to further control how CFITSIO reads ftp and http
+files.
+
+If the input file is an IRAF image file (*.imh file) then CFITSIO will
+automatically convert it on the fly into a virtual FITS image before it
+is opened by the application program. IRAF images can only be opened
+with READONLY file access.
+
+Similarly, if the input file is a raw binary data array, then CFITSIO
+will convert it on the fly into a virtual FITS image with the basic set
+of required header keywords before it is opened by the application
+program (with READONLY access). In this case the data type and
+dimensions of the image must be specified in square brackets following
+the filename (e.g. rawfile.dat[ib512,512]). The first character (case
+insensitive) defines the datatype of the array:
+
+\begin{verbatim}
+ b 8-bit unsigned byte
+ i 16-bit signed integer
+ u 16-bit unsigned integer
+ j 32-bit signed integer
+ r or f 32-bit floating point
+ d 64-bit floating point
+\end{verbatim}
+An optional second character specifies the byte order of the array
+values: b or B indicates big endian (as in FITS files and the native
+format of SUN UNIX workstations and Mac PCs) and l or L indicates
+little endian (native format of DEC OSF workstations and IBM PCs). If
+this character is omitted then the array is assumed to have the native
+byte order of the local machine. These datatype characters are then
+followed by a series of one or more integer values separated by commas
+which define the size of each dimension of the raw array. Arrays with
+up to 5 dimensions are currently supported. Finally, a byte offset to
+the position of the first pixel in the data file may be specified by
+separating it with a ':' from the last dimension value. If omitted, it
+is assumed that the offset = 0. This parameter may be used to skip
+over any header information in the file that precedes the binary data.
+Further examples:
+
+\begin{verbatim}
+ raw.dat[b10000] 1-dimensional 10000 pixel byte array
+ raw.dat[rb400,400,12] 3-dimensional floating point big-endian array
+ img.fits[ib512,512:2880] reads the 512 x 512 short integer array in
+ a FITS file, skipping over the 2880 byte header
+\end{verbatim}
+
+One special case of input file is where the filename = `-' (a dash or
+minus sign) or 'stdin' or 'stdout', which signifies that the input file
+is to be read from the stdin stream, or written to the stdout stream if
+a new output file is being created. In the case of reading from stdin,
+CFITSIO first copies the whole stream into a temporary FITS file (in
+memory or on disk), and subsequent reading of the FITS file occurs in
+this copy. When writing to stdout, CFITSIO first constructs the whole
+file in memory (since random access is required), then flushes it out
+to the stdout stream when the file is closed. In addition, if the
+output filename = '-.gz' or 'stdout.gz' then it will be gzip compressed
+before being written to stdout.
+
+This ability to read and write on the stdin and stdout steams allows
+FITS files to be piped between tasks in memory rather than having to
+create temporary intermediate FITS files on disk. For example if task1
+creates an output FITS file, and task2 reads an input FITS file, the
+FITS file may be piped between the 2 tasks by specifying
+
+\begin{verbatim}
+ task1 - | task2 -
+\end{verbatim}
+where the vertical bar is the Unix piping symbol. This assumes that the 2
+tasks read the name of the FITS file off of the command line.
+
+
+\section{Output File Name when Opening an Existing File}
+
+An optional output filename may be specified in parentheses immediately
+following the base file name to be opened. This is mainly useful in
+those cases where CFITSIO creates a temporary copy of the input FITS
+file before it is opened and passed to the application program. This
+happens by default when opening a network FTP or HTTP-type file, when
+reading a compressed FITS file on a local disk, when reading from the
+stdin stream, or when a column filter, row filter, or binning specifier
+is included as part of the input file specification. By default this
+temporary file is created in memory. If there is not enough memory to
+create the file copy, then CFITSIO will exit with an error. In these
+cases one can force a permanent file to be created on disk, instead of
+a temporary file in memory, by supplying the name in parentheses
+immediately following the base file name. The output filename can
+include the '!' clobber flag.
+
+Thus, if the input filename to CFITSIO is:
+\verb+file1.fits.gz(file2.fits)+
+then CFITSIO will uncompress `file1.fits.gz' into the local disk file
+`file2.fits' before opening it. CFITSIO does not automatically delete
+the output file, so it will still exist after the application program
+exits.
+
+In some cases, several different temporary FITS files will be created
+in sequence, for instance, if one opens a remote file using FTP, then
+filters rows in a binary table extension, then create an image by
+binning a pair of columns. In this case, the remote file will be
+copied to a temporary local file, then a second temporary file will be
+created containing the filtered rows of the table, and finally a third
+temporary file containing the binned image will be created. In cases
+like this where multiple files are created, the outfile specifier will
+be interpreted the name of the final file as described below, in descending
+priority:
+
+\begin{itemize}
+\item
+as the name of the final image file if an image within a single binary
+table cell is opened or if an image is created by binning a table column.
+\item
+as the name of the file containing the filtered table if a column filter
+and/or a row filter are specified.
+\item
+as the name of the local copy of the remote FTP or HTTP file.
+\item
+as the name of the uncompressed version of the FITS file, if a
+compressed FITS file on local disk has been opened.
+\item
+otherwise, the output filename is ignored.
+\end{itemize}
+
+
+The output file specifier is useful when reading FTP or HTTP-type
+FITS files since it can be used to create a local disk copy of the file
+that can be reused in the future. If the output file name = `*' then a
+local file with the same name as the network file will be created.
+Note that CFITSIO will behave differently depending on whether the
+remote file is compressed or not as shown by the following examples:
+\begin{itemize}
+\item
+`ftp://remote.machine/tmp/myfile.fits.gz(*)' - the remote compressed
+file is copied to the local compressed file `myfile.fits.gz', which
+is then uncompressed in local memory before being opened and passed
+to the application program.
+
+\item
+`ftp://remote.machine/tmp/myfile.fits.gz(myfile.fits)' - the remote
+compressed file is copied and uncompressed into the local file
+`myfile.fits'. This example requires less local memory than the
+previous example since the file is uncompressed on disk instead of
+in memory.
+
+\item
+`ftp://remote.machine/tmp/myfile.fits(myfile.fits.gz)' - this will
+usually produce an error since CFITSIO itself cannot compress files.
+\end{itemize}
+
+The exact behavior of CFITSIO in the latter case depends on the type of
+ftp server running on the remote machine and how it is configured. In
+some cases, if the file `myfile.fits.gz' exists on the remote machine,
+then the server will copy it to the local machine. In other cases the
+ftp server will automatically create and transmit a compressed version
+of the file if only the uncompressed version exists. This can get
+rather confusing, so users should use a certain amount of caution when
+using the output file specifier with FTP or HTTP file types, to make
+sure they get the behavior that they expect.
+
+
+\section{Template File Name when Creating a New File}
+
+When a new FITS file is created with a call to fits\_create\_file, the
+name of a template file may be supplied in parentheses immediately
+following the name of the new file to be created. This template is
+used to define the structure of one or more HDUs in the new file. The
+template file may be another FITS file, in which case the newly created
+file will have exactly the same keywords in each HDU as in the template
+FITS file, but all the data units will be filled with zeros. The
+template file may also be an ASCII text file, where each line (in
+general) describes one FITS keyword record. The format of the ASCII
+template file is described below.
+
+
+\section{HDU Location Specification}
+
+The optional HDU location specifier defines which HDU (Header-Data
+Unit, also known as an `extension') within the FITS file to initially
+open. It must immediately follow the base file name (or the output
+file name if present). If it is not specified then the first HDU (the
+primary array) is opened. The HDU location specifier is required if
+the colFilter, rowFilter, or binSpec specifiers are present, because
+the primary array is not a valid HDU for these operations. The HDU may
+be specified either by absolute position number, starting with 0 for
+the primary array, or by reference to the HDU name, and optionally, the
+version number and the HDU type of the desired extension. The location
+of an image within a single cell of a binary table may also be
+specified, as described below.
+
+The absolute position of the extension is specified either by enclosed
+the number in square brackets (e.g., `[1]' = the first extension
+following the primary array) or by preceded the number with a plus sign
+(`+1'). To specify the HDU by name, give the name of the desired HDU
+(the value of the EXTNAME or HDUNAME keyword) and optionally the
+extension version number (value of the EXTVER keyword) and the
+extension type (value of the XTENSION keyword: IMAGE, ASCII or TABLE,
+or BINTABLE), separated by commas and all enclosed in square brackets.
+If the value of EXTVER and XTENSION are not specified, then the first
+extension with the correct value of EXTNAME is opened. The extension
+name and type are not case sensitive, and the extension type may be
+abbreviated to a single letter (e.g., I = IMAGE extension or primary
+array, A or T = ASCII table extension, and B = binary table BINTABLE
+extension). If the HDU location specifier is equal to `[PRIMARY]' or
+`[P]', then the primary array (the first HDU) will be opened.
+
+FITS images are most commonly stored in the primary array or an image
+extension, but images can also be stored as a vector in a single cell
+of a binary table (i.e. each row of the vector column contains a
+different image). Such an image can be opened with CFITSIO by
+specifying the desired column name and the row number after the binary
+table HDU specifier as shown in the following examples. The column name
+is separated from the HDU specifier by a semicolon and the row number
+is enclosed in parentheses. In this case CFITSIO copies the image from
+the table cell into a temporary primary array before it is opened. The
+application program then just sees the image in the primary array,
+without any extensions. The particular row to be opened may be
+specified either by giving an absolute integer row number (starting
+with 1 for the first row), or by specifying a boolean expression that
+evaluates to TRUE for the desired row. The first row that satisfies
+the expression will be used. The row selection expression has the same
+syntax as described in the Row Filter Specifier section, below.
+
+ Examples:
+
+\begin{verbatim}
+ myfile.fits[3] - open the 3rd HDU following the primary array
+ myfile.fits+3 - same as above, but using the FTOOLS-style notation
+ myfile.fits[EVENTS] - open the extension that has EXTNAME = 'EVENTS'
+ myfile.fits[EVENTS, 2] - same as above, but also requires EXTVER = 2
+ myfile.fits[events,2,b] - same, but also requires XTENSION = 'BINTABLE'
+ myfile.fits[3; images(17)] - opens the image in row 17 of the 'images'
+ column in the 3rd extension of the file.
+ myfile.fits[3; images(exposure > 100)] - as above, but opens the image
+ in the first row that has an 'exposure' column value
+ greater than 100.
+\end{verbatim}
+
+
+\section{Image Section}
+
+A virtual file containing a rectangular subsection of an image can be
+extracted and opened by specifying the range of pixels (start:end)
+along each axis to be extracted from the original image. One can also
+specify an optional pixel increment (start:end:step) for each axis of
+the input image. A pixel step = 1 will be assumed if it is not
+specified. If the start pixel is larger then the end pixel, then the
+image will be flipped (producing a mirror image) along that dimension.
+An asterisk, '*', may be used to specify the entire range of an axis,
+and '-*' will flip the entire axis. The input image can be in the
+primary array, in an image extension, or contained in a vector cell of
+a binary table. In the later 2 cases the extension name or number must
+be specified before the image section specifier.
+
+ Examples:
+
+\begin{verbatim}
+ myfile.fits[1:512:2, 2:512:2] - open a 256x256 pixel image
+ consisting of the odd numbered columns (1st axis) and
+ the even numbered rows (2nd axis) of the image in the
+ primary array of the file.
+
+ myfile.fits[*, 512:256] - open an image consisting of all the columns
+ in the input image, but only rows 256 through 512.
+ The image will be flipped along the 2nd axis since
+ the starting pixel is greater than the ending pixel.
+
+ myfile.fits[*:2, 512:256:2] - same as above but keeping only
+ every other row and column in the input image.
+
+ myfile.fits[-*, *] - copy the entire image, flipping it along
+ the first axis.
+
+ myfile.fits[3][1:256,1:256] - opens a subsection of the image that
+ is in the 3rd extension of the file.
+
+ myfile.fits[4; images(12)][1:10,1:10] - open an image consisting
+ of the first 10 pixels in both dimensions. The original
+ image resides in the 12th row of the 'images' vector
+ column in the table in the 4th extension of the file.
+\end{verbatim}
+
+When CFITSIO opens an image section it first creates a temporary file
+containing the image section plus a copy of any other HDUs in the
+file. This temporary file is then opened by the application program,
+so it is not possible to write to or modify the input file when
+specifying an image section. Note that CFITSIO automatically updates
+the world coordinate system keywords in the header of the image
+section, if they exist, so that the coordinate associated with each
+pixel in the image section will be computed correctly.
+
+
+\section{Column and Keyword Filtering Specification}
+
+The optional column/keyword filtering specifier is used to modify the
+column structure and/or the header keywords in the HDU that was
+selected with the previous HDU location specifier. This filtering
+specifier must be enclosed in square brackets and can be distinguished
+from a general row filter specifier (described below) by the fact that
+it begins with the string 'col ' and is not immediately followed by an
+equals sign. The original file is not changed by this filtering
+operation, and instead the modifications are made on a copy of the
+input FITS file (usually in memory), which also contains a copy of all
+the other HDUs in the file. This temporary file is passed to the
+application program and will persist only until the file is closed or
+until the program exits, unless the outfile specifier (see above) is
+also supplied.
+
+The column/keyword filter can be used to perform the following
+operations. More than one operation may be specified by separating
+them with semi-colons.
+
+\begin{itemize}
+
+\item
+Copy only a specified list of columns columns to the filtered input file.
+The list of column name should be separated by semi-colons. Wild card
+characters may be used in the column names to match multiple columns.
+If the expression contains both a list of columns to be included and
+columns to be deleted, then all the columns in the original table
+except the explicitly deleted columns will appear in the filtered
+table (i.e., there is no need to explicitly list the columns to
+be included if any columns are being deleted).
+
+\item
+Delete a column or keyword by listing the name preceded by a minus
+sign or an exclamation mark (!), e.g., '-TIME' will delete the TIME
+column if it exists, otherwise the TIME keyword. An error is returned
+if neither a column nor keyword with this name exists. Note that the
+exclamation point, '!', is a special UNIX character, so if it is used
+on the command line rather than entered at a task prompt, it must be
+preceded by a backslash to force the UNIX shell to ignore it.
+
+\item
+Rename an existing column or keyword with the syntax 'NewName ==
+OldName'. An error is returned if neither a column nor keyword with
+this name exists.
+
+\item
+Append a new column or keyword to the table. To create a column,
+give the new name, optionally followed by the datatype in parentheses,
+followed by a single equals sign and an expression to be used to
+compute the value (e.g., 'newcol(1J) = 0' will create a new 32-bit
+integer column called 'newcol' filled with zeros). The datatype is
+specified using the same syntax that is allowed for the value of the
+FITS TFORMn keyword (e.g., 'I', 'J', 'E', 'D', etc. for binary tables,
+and 'I8', F12.3', 'E20.12', etc. for ASCII tables). If the datatype is
+not specified then an appropriate datatype will be chosen depending on
+the form of the expression (may be a character string, logical, bit, long
+integer, or double column). An appropriate vector count (in the case
+of binary tables) will also be added if not explicitly specified.
+
+When creating a new keyword, the keyword name must be preceded by a
+pound sign '\#', and the expression must evaluate to a scalar
+(i.e., cannot have a column name in the expression). The comment
+string for the keyword may be specified in parentheses immediately
+following the keyword name (instead of supplying a datatype as in
+the case of creating a new column).
+
+\item
+Recompute (overwrite) the values in an existing column or keyword by
+giving the name followed by an equals sign and an arithmetic
+expression.
+\end{itemize}
+
+The expression that is used when appending or recomputing columns or
+keywords can be arbitrarily complex and may be a function of other
+header keyword values and other columns (in the same row). The full
+syntax and available functions for the expression are described below
+in the row filter specification section.
+
+If the expression contains both a list of columns to be included and
+columns to be deleted, then all the columns in the original table
+except the explicitly deleted columns will appear in the filtered
+table.
+
+For complex or commonly used operations, one can also place the
+operations into an external text file and import it into the column
+filter using the syntax '[col @filename.txt]'. The operations can
+extend over multiple lines of the file, but multiple operations must
+still be separated by semicolons. Any lines in the external text file
+that begin with 2 slash characters ('//') will be ignored and may be
+used to add comments into the file.
+
+Examples:
+
+\begin{verbatim}
+ [col Time;rate] - only the Time and rate columns will
+ appear in the filtered input file.
+
+ [col Time;*raw] - include the Time column and any other
+ columns whose name ends with 'raw'.
+
+ [col -TIME; Good == STATUS] - deletes the TIME column and
+ renames the status column to 'Good'
+
+ [col PI=PHA * 1.1 + 0.2] - creates new PI column from PHA values
+
+ [col rate = rate/exposure] - recomputes the rate column by dividing
+ it by the EXPOSURE keyword value.
+\end{verbatim}
+
+
+\section{Row Filtering Specification}
+
+ When entering the name of a FITS table that is to be opened by a
+ program, an optional row filter may be specified to select a subset
+ of the rows in the table. A temporary new FITS file is created on
+ the fly which contains only those rows for which the row filter
+ expression evaluates to true. (The primary array and any other
+ extensions in the input file are also copied to the temporary
+ file). The original FITS file is closed and the new virtual file
+ is opened by the application program. The row filter expression is
+ enclosed in square brackets following the file name and extension
+ name (e.g., 'file.fits[events][GRADE==50]' selects only those rows
+ where the GRADE column value equals 50). When dealing with tables
+ where each row has an associated time and/or 2D spatial position,
+ the row filter expression can also be used to select rows based on
+ the times in a Good Time Intervals (GTI) extension, or on spatial
+ position as given in a SAO-style region file.
+
+
+\subsection{General Syntax}
+
+ The row filtering expression can be an arbitrarily complex series
+ of operations performed on constants, keyword values, and column
+ data taken from the specified FITS TABLE extension. The expression
+ must evaluate to a boolean value for each row of the table, where
+ a value of FALSE means that the row will be excluded.
+
+ For complex or commonly used filters, one can place the expression
+ into a text file and import it into the row filter using the syntax
+ '[@filename.txt]'. The expression can be arbitrarily complex and
+ extend over multiple lines of the file. Any lines in the external
+ text file that begin with 2 slash characters ('//') will be ignored
+ and may be used to add comments into the file.
+
+ Keyword and column data are referenced by name. Any string of
+ characters not surrounded by quotes (ie, a constant string) or
+ followed by an open parentheses (ie, a function name) will be
+ initially interpreted as a column name and its contents for the
+ current row inserted into the expression. If no such column exists,
+ a keyword of that name will be searched for and its value used, if
+ found. To force the name to be interpreted as a keyword (in case
+ there is both a column and keyword with the same name), precede the
+ keyword name with a single pound sign, '\#', as in '\#NAXIS2'. Due to
+ the generalities of FITS column and keyword names, if the column or
+ keyword name contains a space or a character which might appear as
+ an arithmetic term then inclose the name in '\$' characters as in
+ \$MAX PHA\$ or \#\$MAX-PHA\$. Names are case insensitive.
+
+ To access a table entry in a row other than the current one, follow
+ the column's name with a row offset within curly braces. For
+ example, 'PHA\{-3\}' will evaluate to the value of column PHA, 3 rows
+ above the row currently being processed. One cannot specify an
+ absolute row number, only a relative offset. Rows that fall outside
+ the table will be treated as undefined, or NULLs.
+
+ Boolean operators can be used in the expression in either their
+ Fortran or C forms. The following boolean operators are available:
+
+\begin{verbatim}
+ "equal" .eq. .EQ. == "not equal" .ne. .NE. !=
+ "less than" .lt. .LT. < "less than/equal" .le. .LE. <= =<
+ "greater than" .gt. .GT. > "greater than/equal" .ge. .GE. >= =>
+ "or" .or. .OR. || "and" .and. .AND. &&
+ "negation" .not. .NOT. ! "approx. equal(1e-7)" ~
+\end{verbatim}
+
+Note that the exclamation
+point, '!', is a special UNIX character, so if it is used on the
+command line rather than entered at a task prompt, it must be preceded
+by a backslash to force the UNIX shell to ignore it.
+
+ The expression may also include arithmetic operators and functions.
+ Trigonometric functions use radians, not degrees. The following
+ arithmetic operators and functions can be used in the expression
+ (function names are case insensitive). A null value will be returned
+ in case of illegal operations such as divide by zero, sqrt(negative)
+ log(negative), log10(negative), arccos(.gt. 1), arcsin(.gt. 1).
+
+
+\begin{verbatim}
+ "addition" + "subtraction" -
+ "multiplication" * "division" /
+ "negation" - "exponentiation" ** ^
+ "absolute value" abs(x) "cosine" cos(x)
+ "sine" sin(x) "tangent" tan(x)
+ "arc cosine" arccos(x) "arc sine" arcsin(x)
+ "arc tangent" arctan(x) "arc tangent" arctan2(x,y)
+ "hyperbolic cos" cosh(x) "hyperbolic sin" sinh(x)
+ "hyperbolic tan" tanh(x) "round to nearest int" round(x)
+ "round down to int" floor(x) "round up to int" ceil(x)
+ "exponential" exp(x) "square root" sqrt(x)
+ "natural log" log(x) "common log" log10(x)
+ "modulus" i % j "random # [0.0,1.0)" random()
+ "minimum" min(x,y) "maximum" max(x,y)
+ "cumulative sum" accum(x) "sequential difference" seqdiff(x)
+ "if-then-else" b?x:y
+\end{verbatim}
+
+ An alternate syntax for the min and max functions has only a single
+ argument which should be a vector value (see below). The result
+ will be the minimum/maximum element contained within the vector.
+
+ The accum(x) function forms the cumulative sum of x, element by element.
+ Vector columns are supported simply by performing the summation process
+ through all the values. Null values are treated as 0. The seqdiff(x)
+ function forms the sequential difference of x, element by element.
+ The first value of seqdiff is the first value of x. A single null
+ value in x causes a pair of nulls in the output. The seqdiff and
+ accum functions are functional inverses, i.e., seqdiff(accum(x)) == x
+ as long as no null values are present.
+
+ The following type casting operators are available, where the
+ inclosing parentheses are required and taken from the C language
+ usage. Also, the integer to real casts values to double precision:
+
+\begin{verbatim}
+ "real to integer" (int) x (INT) x
+ "integer to real" (float) i (FLOAT) i
+\end{verbatim}
+
+ In addition, several constants are built in for use in numerical
+ expressions:
+
+
+\begin{verbatim}
+ #pi 3.1415... #e 2.7182...
+ #deg #pi/180 #row current row number
+ #null undefined value #snull undefined string
+\end{verbatim}
+
+ A string constant must be enclosed in quotes as in 'Crab'. The
+ "null" constants are useful for conditionally setting table values
+ to a NULL, or undefined, value (eg., "col1==-99 ? \#NULL : col1").
+
+ There is also a function for testing if two values are close to
+ each other, i.e., if they are "near" each other to within a user
+ specified tolerance. The arguments, value\_1 and value\_2 can be
+ integer or real and represent the two values who's proximity is
+ being tested to be within the specified tolerance, also an integer
+ or real:
+
+\begin{verbatim}
+ near(value_1, value_2, tolerance)
+\end{verbatim}
+ When a NULL, or undefined, value is encountered in the FITS table,
+ the expression will evaluate to NULL unless the undefined value is
+ not actually required for evaluation, e.g. "TRUE .or. NULL"
+ evaluates to TRUE. The following two functions allow some NULL
+ detection and handling:
+
+\begin{verbatim}
+ "a null value?" ISNULL(x)
+ "define a value for null" DEFNULL(x,y)
+\end{verbatim}
+ The former
+ returns a boolean value of TRUE if the argument x is NULL. The
+ later "defines" a value to be substituted for NULL values; it
+ returns the value of x if x is not NULL, otherwise it returns the
+ value of y.
+
+
+\subsection{Bit Masks}
+
+ Bit masks can be used to select out rows from bit columns (TFORMn =
+ \#X) in FITS files. To represent the mask, binary, octal, and hex
+ formats are allowed:
+
+
+\begin{verbatim}
+ binary: b0110xx1010000101xxxx0001
+ octal: o720x1 -> (b111010000xxx001)
+ hex: h0FxD -> (b00001111xxxx1101)
+\end{verbatim}
+
+ In all the representations, an x or X is allowed in the mask as a
+ wild card. Note that the x represents a different number of wild
+ card bits in each representation. All representations are case
+ insensitive.
+
+ To construct the boolean expression using the mask as the boolean
+ equal operator described above on a bit table column. For example,
+ if you had a 7 bit column named flags in a FITS table and wanted
+ all rows having the bit pattern 0010011, the selection expression
+ would be:
+
+
+\begin{verbatim}
+ flags == b0010011
+ or
+ flags .eq. b10011
+\end{verbatim}
+
+ It is also possible to test if a range of bits is less than, less
+ than equal, greater than and greater than equal to a particular
+ boolean value:
+
+
+\begin{verbatim}
+ flags <= bxxx010xx
+ flags .gt. bxxx100xx
+ flags .le. b1xxxxxxx
+\end{verbatim}
+
+ Notice the use of the x bit value to limit the range of bits being
+ compared.
+
+ It is not necessary to specify the leading (most significant) zero
+ (0) bits in the mask, as shown in the second expression above.
+
+ Bit wise AND, OR and NOT operations are also possible on two or
+ more bit fields using the '\&'(AND), '$|$'(OR), and the '!'(NOT)
+ operators. All of these operators result in a bit field which can
+ then be used with the equal operator. For example:
+
+
+\begin{verbatim}
+ (!flags) == b1101100
+ (flags & b1000001) == bx000001
+\end{verbatim}
+
+ Bit fields can be appended as well using the '+' operator. Strings
+ can be concatenated this way, too.
+
+
+\subsection{Vector Columns}
+
+ Vector columns can also be used in building the expression. No
+ special syntax is required if one wants to operate on all elements
+ of the vector. Simply use the column name as for a scalar column.
+ Vector columns can be freely intermixed with scalar columns or
+ constants in virtually all expressions. The result will be of the
+ same dimension as the vector. Two vectors in an expression, though,
+ need to have the same number of elements and have the same
+ dimensions. The only places a vector column cannot be used (for
+ now, anyway) are the SAO region functions and the NEAR boolean
+ function.
+
+ Arithmetic and logical operations are all performed on an element by
+ element basis. Comparing two vector columns, eg "COL1 == COL2",
+ thus results in another vector of boolean values indicating which
+ elements of the two vectors are equal.
+
+ Eight functions are available that operate on a vector and return a
+ scalar result:
+
+\begin{verbatim}
+ "minimum" MIN(V) "maximum" MAX(V)
+ "average" AVERAGE(V) "median" MEDIAN(V)
+ "sumation" SUM(V) "standard deviation" STDDEV(V)
+ "# of values" NELEM(V) "# of non-null values" NVALID(V)
+\end{verbatim}
+ where V represents the name of a vector column or a manually
+ constructed vector using curly brackets as described below. The
+ first 6 of these functions ignore any null values in the vector when
+ computing the result.
+
+ The SUM function literally sums all the elements in x, returning a
+ scalar value. If x is a boolean vector, SUM returns the number
+ of TRUE elements. The NELEM function returns the number of elements
+ in vector x whereas NVALID return the number of non-null elements in
+ the vector. (NELEM also operates on bit and string columns,
+ returning their column widths.) As an example, to test whether all
+ elements of two vectors satisfy a given logical comparison, one can
+ use the expression
+
+\begin{verbatim}
+ SUM( COL1 > COL2 ) == NELEM( COL1 )
+\end{verbatim}
+
+ which will return TRUE if all elements of COL1 are greater than
+ their corresponding elements in COL2.
+
+ To specify a single element of a vector, give the column name
+ followed by a comma-separated list of coordinates enclosed in
+ square brackets. For example, if a vector column named PHAS exists
+ in the table as a one dimensional, 256 component list of numbers
+ from which you wanted to select the 57th component for use in the
+ expression, then PHAS[57] would do the trick. Higher dimensional
+ arrays of data may appear in a column. But in order to interpret
+ them, the TDIMn keyword must appear in the header. Assuming that a
+ (4,4,4,4) array is packed into each row of a column named ARRAY4D,
+ the (1,2,3,4) component element of each row is accessed by
+ ARRAY4D[1,2,3,4]. Arrays up to dimension 5 are currently
+ supported. Each vector index can itself be an expression, although
+ it must evaluate to an integer value within the bounds of the
+ vector. Vector columns which contain spaces or arithmetic operators
+ must have their names enclosed in "\$" characters as with
+ \$ARRAY-4D\$[1,2,3,4].
+
+ A more C-like syntax for specifying vector indices is also
+ available. The element used in the preceding example alternatively
+ could be specified with the syntax ARRAY4D[4][3][2][1]. Note the
+ reverse order of indices (as in C), as well as the fact that the
+ values are still ones-based (as in Fortran -- adopted to avoid
+ ambiguity for 1D vectors). With this syntax, one does not need to
+ specify all of the indices. To extract a 3D slice of this 4D
+ array, use ARRAY4D[4].
+
+ Variable-length vector columns are not supported.
+
+ Vectors can be manually constructed within the expression using a
+ comma-separated list of elements surrounded by curly braces ('\{\}').
+ For example, '\{1,3,6,1\}' is a 4-element vector containing the values
+ 1, 3, 6, and 1. The vector can contain only boolean, integer, and
+ real values (or expressions). The elements will be promoted to the
+ highest datatype present. Any elements which are themselves
+ vectors, will be expanded out with each of its elements becoming an
+ element in the constructed vector.
+
+
+\subsection{Good Time Interval Filtering}
+
+ A common filtering method involves selecting rows which have a time
+ value which lies within what is called a Good Time Interval or GTI.
+ The time intervals are defined in a separate FITS table extension
+ which contains 2 columns giving the start and stop time of each
+ good interval. The filtering operation accepts only those rows of
+ the input table which have an associated time which falls within
+ one of the time intervals defined in the GTI extension. A high
+ level function, gtifilter(a,b,c,d), is available which evaluates
+ each row of the input table and returns TRUE or FALSE depending
+ whether the row is inside or outside the good time interval. The
+ syntax is
+
+\begin{verbatim}
+ gtifilter( [ "gtifile" [, expr [, "STARTCOL", "STOPCOL" ] ] ] )
+\end{verbatim}
+ where each "[]" demarks optional parameters. Note that the quotes
+ around the gtifile and START/STOP column are required. Either single
+ or double quotes may be used. In cases where this expression is
+ entered on the Unix command line, enclose the entire expression in
+ double quotes, and then use single quotes within the expression to
+ enclose the 'gtifile' and other terms. It is also usually possible
+ to do the reverse, and enclose the whole expression in single quotes
+ and then use double quotes within the expression. The gtifile,
+ if specified, can be blank ("") which will mean to use the first
+ extension with the name "*GTI*" in the current file, a plain
+ extension specifier (eg, "+2", "[2]", or "[STDGTI]") which will be
+ used to select an extension in the current file, or a regular
+ filename with or without an extension specifier which in the latter
+ case will mean to use the first extension with an extension name
+ "*GTI*". Expr can be any arithmetic expression, including simply
+ the time column name. A vector time expression will produce a
+ vector boolean result. STARTCOL and STOPCOL are the names of the
+ START/STOP columns in the GTI extension. If one of them is
+ specified, they both must be.
+
+ In its simplest form, no parameters need to be provided -- default
+ values will be used. The expression "gtifilter()" is equivalent to
+
+\begin{verbatim}
+ gtifilter( "", TIME, "*START*", "*STOP*" )
+\end{verbatim}
+ This will search the current file for a GTI extension, filter the
+ TIME column in the current table, using START/STOP times taken from
+ columns in the GTI extension with names containing the strings
+ "START" and "STOP". The wildcards ('*') allow slight variations in
+ naming conventions such as "TSTART" or "STARTTIME". The same
+ default values apply for unspecified parameters when the first one
+ or two parameters are specified. The function automatically
+ searches for TIMEZERO/I/F keywords in the current and GTI
+ extensions, applying a relative time offset, if necessary.
+
+
+\subsection{Spatial Region Filtering}
+
+ Another common filtering method selects rows based on whether the
+ spatial position associated with each row is located within a given
+ 2-dimensional region. The syntax for this high-level filter is
+
+\begin{verbatim}
+ regfilter( "regfilename" [ , Xexpr, Yexpr [ , "wcs cols" ] ] )
+\end{verbatim}
+ where each "[]" demarks optional parameters. The region file name
+ is required and must be enclosed in quotes. The remaining
+ parameters are optional. The region file is an ASCII text file
+ which contains a list of one or more geometric shapes (circle,
+ ellipse, box, etc.) which defines a region on the celestial sphere
+ or an area within a particular 2D image. The region file is
+ typically generated using an image display program such as fv/POW
+ (distribute by the HEASARC), or ds9 (distributed by the Smithsonian
+ Astrophysical Observatory). Users should refer to the documentation
+ provided with these programs for more details on the syntax used in
+ the region files.
+
+ In its simpliest form, (e.g., regfilter("region.reg") ) the
+ coordinates in the default 'X' and 'Y' columns will be used to
+ determine if each row is inside or outside the area specified in
+ the region file. Alternate position column names, or expressions,
+ may be entered if needed, as in
+
+\begin{verbatim}
+ regfilter("region.reg", XPOS, YPOS)
+\end{verbatim}
+ Region filtering can be applied most unambiguously if the positions
+ in the region file and in the table to be filtered are both give in
+ terms of absolute celestial coordinate units. In this case the
+ locations and sizes of the geometric shapes in the region file are
+ specified in angular units on the sky (e.g., positions given in
+ R.A. and Dec. and sizes in arcseconds or arcminutes). Similarly,
+ each row of the filtered table will have a celestial coordinate
+ associated with it. This association is usually implemented using
+ a set of so-called 'World Coordinate System' (or WCS) FITS keywords
+ that define the coordinate transformation that must be applied to
+ the values in the 'X' and 'Y' columns to calculate the coordinate.
+
+ Alternatively, one can perform spatial filtering using unitless
+ 'pixel' coordinates for the regions and row positions. In this
+ case the user must be careful to ensure that the positions in the 2
+ files are self-consistent. A typical problem is that the region
+ file may be generated using a binned image, but the unbinned
+ coordinates are given in the event table. The ROSAT events files,
+ for example, have X and Y pixel coordinates that range from 1 -
+ 15360. These coordinates are typically binned by a factor of 32 to
+ produce a 480x480 pixel image. If one then uses a region file
+ generated from this image (in image pixel units) to filter the
+ ROSAT events file, then the X and Y column values must be converted
+ to corresponding pixel units as in:
+
+\begin{verbatim}
+ regfilter("rosat.reg", X/32.+.5, Y/32.+.5)
+\end{verbatim}
+ Note that this binning conversion is not necessary if the region
+ file is specified using celestial coordinate units instead of pixel
+ units because CFITSIO is then able to directly compare the
+ celestial coordinate of each row in the table with the celestial
+ coordinates in the region file without having to know anything
+ about how the image may have been binned.
+
+ The last "wcs cols" parameter should rarely be needed. If supplied,
+ this string contains the names of the 2 columns (space or comma
+ separated) which have the associated WCS keywords. If not supplied,
+ the filter will scan the X and Y expressions for column names.
+ If only one is found in each expression, those columns will be
+ used, otherwise an error will be returned.
+
+ These region shapes are supported (names are case insensitive):
+
+\begin{verbatim}
+ Point ( X1, Y1 ) <- One pixel square region
+ Line ( X1, Y1, X2, Y2 ) <- One pixel wide region
+ Polygon ( X1, Y1, X2, Y2, ... ) <- Rest are interiors with
+ Rectangle ( X1, Y1, X2, Y2, A ) | boundaries considered
+ Box ( Xc, Yc, Wdth, Hght, A ) V within the region
+ Diamond ( Xc, Yc, Wdth, Hght, A )
+ Circle ( Xc, Yc, R )
+ Annulus ( Xc, Yc, Rin, Rout )
+ Ellipse ( Xc, Yc, Rx, Ry, A )
+ Elliptannulus ( Xc, Yc, Rinx, Riny, Routx, Routy, Ain, Aout )
+ Sector ( Xc, Yc, Amin, Amax )
+\end{verbatim}
+ where (Xc,Yc) is the coordinate of the shape's center; (X\#,Y\#) are
+ the coordinates of the shape's edges; Rxxx are the shapes' various
+ Radii or semimajor/minor axes; and Axxx are the angles of rotation
+ (or bounding angles for Sector) in degrees. For rotated shapes, the
+ rotation angle can be left off, indicating no rotation. Common
+ alternate names for the regions can also be used: rotbox = box;
+ rotrectangle = rectangle; (rot)rhombus = (rot)diamond; and pie
+ = sector. When a shape's name is preceded by a minus sign, '-',
+ the defined region is instead the area *outside* its boundary (ie,
+ the region is inverted). All the shapes within a single region
+ file are OR'd together to create the region, and the order is
+ significant. The overall way of looking at region files is that if
+ the first region is an excluded region then a dummy included region
+ of the whole detector is inserted in the front. Then each region
+ specification as it is processed overrides any selections inside of
+ that region specified by previous regions. Another way of thinking
+ about this is that if a previous excluded region is completely
+ inside of a subsequent included region the excluded region is
+ ignored.
+
+ The positional coordinates may be given either in pixel units,
+ decimal degrees or hh:mm:ss.s, dd:mm:ss.s units. The shape sizes
+ may be given in pixels, degrees, arcminutes, or arcseconds. Look
+ at examples of region file produced by fv/POW or ds9 for further
+ details of the region file format.
+
+ There are three functions that are primarily for use with SAO region
+ files and the FSAOI task, but they can be used directly. They
+ return a boolean true or false depending on whether a two
+ dimensional point is in the region or not:
+
+\begin{verbatim}
+ "point in a circular region"
+ circle(xcntr,ycntr,radius,Xcolumn,Ycolumn)
+
+ "point in an elliptical region"
+ ellipse(xcntr,ycntr,xhlf_wdth,yhlf_wdth,rotation,Xcolumn,Ycolumn)
+
+ "point in a rectangular region"
+ box(xcntr,ycntr,xfll_wdth,yfll_wdth,rotation,Xcolumn,Ycolumn)
+
+ where
+ (xcntr,ycntr) are the (x,y) position of the center of the region
+ (xhlf_wdth,yhlf_wdth) are the (x,y) half widths of the region
+ (xfll_wdth,yfll_wdth) are the (x,y) full widths of the region
+ (radius) is half the diameter of the circle
+ (rotation) is the angle(degrees) that the region is rotated with
+ respect to (xcntr,ycntr)
+ (Xcoord,Ycoord) are the (x,y) coordinates to test, usually column
+ names
+ NOTE: each parameter can itself be an expression, not merely a
+ column name or constant.
+\end{verbatim}
+
+
+\subsection{Example Row Filters}
+
+\begin{verbatim}
+ [ binary && mag <= 5.0] - Extract all binary stars brighter
+ than fifth magnitude (note that
+ the initial space is necessary to
+ prevent it from being treated as a
+ binning specification)
+
+ [#row >= 125 && #row <= 175] - Extract row numbers 125 through 175
+
+ [IMAGE[4,5] .gt. 100] - Extract all rows that have the
+ (4,5) component of the IMAGE column
+ greater than 100
+
+ [abs(sin(theta * #deg)) < 0.5] - Extract all rows having the
+ absolute value of the sine of theta
+ less than a half where the angles
+ are tabulated in degrees
+
+ [SUM( SPEC > 3*BACKGRND )>=1] - Extract all rows containing a
+ spectrum, held in vector column
+ SPEC, with at least one value 3
+ times greater than the background
+ level held in a keyword, BACKGRND
+
+ [VCOL=={1,4,2}] - Extract all rows whose vector column
+ VCOL contains the 3-elements 1, 4, and
+ 2.
+
+ [@rowFilter.txt] - Extract rows using the expression
+ contained within the text file
+ rowFilter.txt
+
+ [gtifilter()] - Search the current file for a GTI
+ extension, filter the TIME
+ column in the current table, using
+ START/STOP times taken from
+ columns in the GTI extension
+
+ [regfilter("pow.reg")] - Extract rows which have a coordinate
+ (as given in the X and Y columns)
+ within the spatial region specified
+ in the pow.reg region file.
+
+ [regfilter("pow.reg", Xs, Ys)] - Same as above, except that the
+ Xs and Ys columns will be used to
+ determine the coordinate of each
+ row in the table.
+\end{verbatim}
+
+
+\section{ Binning or Histogramming Specification}
+
+The optional binning specifier is enclosed in square brackets and can
+be distinguished from a general row filter specification by the fact
+that it begins with the keyword 'bin' not immediately followed by an
+equals sign. When binning is specified, a temporary N-dimensional FITS
+primary array is created by computing the histogram of the values in
+the specified columns of a FITS table extension. After the histogram
+is computed the input FITS file containing the table is then closed and
+the temporary FITS primary array is opened and passed to the
+application program. Thus, the application program never sees the
+original FITS table and only sees the image in the new temporary file
+(which has no additional extensions). Obviously, the application
+program must be expecting to open a FITS image and not a FITS table in
+this case.
+
+The data type of the FITS histogram image may be specified by appending
+'b' (for 8-bit byte), 'i' (for 16-bit integers), 'j' (for 32-bit
+integer), 'r' (for 32-bit floating points), or 'd' (for 64-bit double
+precision floating point) to the 'bin' keyword (e.g. '[binr X]'
+creates a real floating point image). If the datatype is not
+explicitly specified then a 32-bit integer image will be created by
+default, unless the weighting option is also specified in which case
+the image will have a 32-bit floating point data type by default.
+
+The histogram image may have from 1 to 4 dimensions (axes), depending
+on the number of columns that are specified. The general form of the
+binning specification is:
+
+\begin{verbatim}
+ [bin{bijrd} Xcol=min:max:binsize, Ycol= ..., Zcol=..., Tcol=...; weight]
+\end{verbatim}
+in which up to 4 columns, each corresponding to an axis of the image,
+are listed. The column names are case insensitive, and the column
+number may be given instead of the name, preceded by a pound sign
+(e.g., [bin \#4=1:512]). If the column name is not specified, then
+CFITSIO will first try to use the 'preferred column' as specified by
+the CPREF keyword if it exists (e.g., 'CPREF = 'DETX,DETY'), otherwise
+column names 'X', 'Y', 'Z', and 'T' will be assumed for each of the 4
+axes, respectively. In cases where the column name could be confused
+with an arithmetic expression, enclose the column name in parentheses to
+force the name to be interpreted literally.
+
+Each column name may be followed by an equals sign and then the lower
+and upper range of the histogram, and the size of the histogram bins,
+separated by colons. Spaces are allowed before and after the equals
+sign but not within the 'min:max:binsize' string. The min, max and
+binsize values may be integer or floating point numbers, or they may be
+the names of keywords in the header of the table. If the latter, then
+the value of that keyword is substituted into the expression.
+
+Default values for the min, max and binsize quantities will be
+used if not explicitly given in the binning expression as shown
+in these examples:
+
+\begin{verbatim}
+ [bin x = :512:2] - use default minimum value
+ [bin x = 1::2] - use default maximum value
+ [bin x = 1:512] - use default bin size
+ [bin x = 1:] - use default maximum value and bin size
+ [bin x = :512] - use default minimum value and bin size
+ [bin x = 2] - use default minimum and maximum values
+ [bin x] - use default minimum, maximum and bin size
+ [bin 4] - default 2-D image, bin size = 4 in both axes
+ [bin] - default 2-D image
+\end{verbatim}
+CFITSIO will use the value of the TLMINn, TLMAXn, and TDBINn keywords,
+if they exist, for the default min, max, and binsize, respectively. If
+they do not exist then CFITSIO will use the actual minimum and maximum
+values in the column for the histogram min and max values. The default
+binsize will be set to 1, or (max - min) / 10., whichever is smaller,
+so that the histogram will have at least 10 bins along each axis.
+
+A shortcut notation is allowed if all the columns/axes have the same
+binning specification. In this case all the column names may be listed
+within parentheses, followed by the (single) binning specification, as
+in:
+
+\begin{verbatim}
+ [bin (X,Y)=1:512:2]
+ [bin (X,Y) = 5]
+\end{verbatim}
+
+The optional weighting factor is the last item in the binning specifier
+and, if present, is separated from the list of columns by a
+semi-colon. As the histogram is accumulated, this weight is used to
+incremented the value of the appropriated bin in the histogram. If the
+weighting factor is not specified, then the default weight = 1 is
+assumed. The weighting factor may be a constant integer or floating
+point number, or the name of a keyword containing the weighting value.
+Or the weighting factor may be the name of a table column in which case
+the value in that column, on a row by row basis, will be used.
+
+In some cases, the column or keyword may give the reciprocal of the
+actual weight value that is needed. In this case, precede the weight
+keyword or column name by a slash '/' to tell CFITSIO to use the
+reciprocal of the value when constructing the histogram.
+
+For complex or commonly used histograms, one can also place its
+description into a text file and import it into the binning
+specification using the syntax '[bin @filename.txt]'. The file's
+contents can extend over multiple lines, although it must still
+conform to the no-spaces rule for the min:max:binsize syntax and each
+axis specification must still be comma-separated. Any lines in the
+external text file that begin with 2 slash characters ('//') will be
+ignored and may be used to add comments into the file.
+
+ Examples:
+
+
+\begin{verbatim}
+ [bini detx, dety] - 2-D, 16-bit integer histogram
+ of DETX and DETY columns, using
+ default values for the histogram
+ range and binsize
+
+ [bin (detx, dety)=16; /exposure] - 2-D, 32-bit real histogram of DETX
+ and DETY columns with a bin size = 16
+ in both axes. The histogram values
+ are divided by the EXPOSURE keyword
+ value.
+
+ [bin time=TSTART:TSTOP:0.1] - 1-D lightcurve, range determined by
+ the TSTART and TSTOP keywords,
+ with 0.1 unit size bins.
+
+ [bin pha, time=8000.:8100.:0.1] - 2-D image using default binning
+ of the PHA column for the X axis,
+ and 1000 bins in the range
+ 8000. to 8100. for the Y axis.
+
+ [bin @binFilter.txt] - Use the contents of the text file
+ binFilter.txt for the binning
+ specifications.
+
+\end{verbatim}
+
+
+\chapter{Template Files }
+
+When a new FITS file is created with a call to fits\_create\_file, the
+name of a template file may be supplied in parentheses immediately
+following the name of the new file to be created. This template is
+used to define the structure of one or more HDUs in the new file. The
+template file may be another FITS file, in which case the newly created
+file will have exactly the same keywords in each HDU as in the template
+FITS file, but all the data units will be filled with zeros. The
+template file may also be an ASCII text file, where each line (in
+general) describes one FITS keyword record. The format of the ASCII
+template file is described in the following sections.
+
+
+\section{Detailed Template Line Format}
+
+The format of each ASCII template line closely follows the format of a
+FITS keyword record:
+
+\begin{verbatim}
+ KEYWORD = KEYVALUE / COMMENT
+\end{verbatim}
+except that free format may be used (e.g., the equals sign may appear
+at any position in the line) and TAB characters are allowed and are
+treated the same as space characters. The KEYVALUE and COMMENT fields
+are optional. The equals sign character is also optional, but it is
+recommended that it be included for clarity. Any template line that
+begins with the pound '\#' character is ignored by the template parser
+and may be use to insert comments into the template file itself.
+
+The KEYWORD name field is limited to 8 characters in length and only
+the letters A-Z, digits 0-9, and the hyphen and underscore characters
+may be used, without any embedded spaces. Lowercase letters in the
+template keyword name will be converted to uppercase. Leading spaces
+in the template line preceding the keyword name are generally ignored,
+except if the first 8 characters of a template line are all blank, then
+the entire line is treated as a FITS comment keyword (with a blank
+keyword name) and is copied verbatim into the FITS header.
+
+The KEYVALUE field may have any allowed FITS data type: character
+string, logical, integer, real, complex integer, or complex real. The
+character string values need not be enclosed in single quote characters
+unless they are necessary to distinguish the string from a different
+data type (e.g. 2.0 is a real but '2.0' is a string). The keyword has
+an undefined (null) value if the template record only contains blanks
+following the "=" or between the "=" and the "/" comment field
+delimiter.
+
+String keyword values longer than 68 characters (the maximum length
+that will fit in a single FITS keyword record) are permitted using the
+CFITSIO long string convention. They can either be specified as a
+single long line in the template, or by using multiple lines where the
+continuing lines contain the 'CONTINUE' keyword, as in this example:
+
+\begin{verbatim}
+ LONGKEY = 'This is a long string value that is contin&'
+ CONTINUE 'ued over 2 records' / comment field goes here
+\end{verbatim}
+The format of template lines with CONTINUE keyword is very strict: 3
+spaces must follow CONTINUE and the rest of the line is copied verbatim
+to the FITS file.
+
+The start of the optional COMMENT field must be preceded by "/", which
+is used to separate it from the keyword value field. Exceptions are if
+the KEYWORD name field contains COMMENT, HISTORY, CONTINUE, or if the
+first 8 characters of the template line are blanks.
+
+More than one Header-Data Unit (HDU) may be defined in the template
+file. The start of an HDU definition is denoted with a SIMPLE or
+XTENSION template line:
+
+1) SIMPLE begins a Primary HDU definition. SIMPLE may only appear as
+the first keyword in the template file. If the template file begins
+with XTENSION instead of SIMPLE, then a default empty Primary HDU is
+created, and the template is then assumed to define the keywords
+starting with the first extension following the Primary HDU.
+
+2) XTENSION marks the beginning of a new extension HDU definition. The
+previous HDU will be closed at this point and processing of the next
+extension begins.
+
+
+\section{Auto-indexing of Keywords}
+
+If a template keyword name ends with a "\#" character, it is said to be
+'auto-indexed'. Each "\#" character will be replaced by the current
+integer index value, which gets reset = 1 at the start of each new HDU
+in the file (or 7 in the special case of a GROUP definition). The
+FIRST indexed keyword in each template HDU definition is used as the
+'incrementor'; each subsequent occurrence of this SAME keyword will
+cause the index value to be incremented. This behavior can be rather
+subtle, as illustrated in the following examples in which the TTYPE
+keyword is the incrementor in both cases:
+
+\begin{verbatim}
+ TTYPE# = TIME
+ TFORM# = 1D
+ TTYPE# = RATE
+ TFORM# = 1E
+\end{verbatim}
+will create TTYPE1, TFORM1, TTYPE2, and TFORM2 keywords. But if the
+template looks like,
+
+\begin{verbatim}
+ TTYPE# = TIME
+ TTYPE# = RATE
+ TFORM# = 1D
+ TFORM# = 1E
+\end{verbatim}
+this results in a FITS files with TTYPE1, TTYPE2, TFORM2, and TFORM2,
+which is probably not what was intended!
+
+
+\section{Template Parser Directives}
+
+In addition to the template lines which define individual keywords, the
+template parser recognizes 3 special directives which are each preceded
+by the backslash character: \verb+ \include, \group+, and \verb+ \end+.
+
+The 'include' directive must be followed by a filename. It forces the
+parser to temporarily stop reading the current template file and begin
+reading the include file. Once the parser reaches the end of the
+include file it continues parsing the current template file. Include
+files can be nested, and HDU definitions can span multiple template
+files.
+
+The start of a GROUP definition is denoted with the 'group' directive,
+and the end of a GROUP definition is denoted with the 'end' directive.
+Each GROUP contains 0 or more member blocks (HDUs or GROUPs). Member
+blocks of type GROUP can contain their own member blocks. The GROUP
+definition itself occupies one FITS file HDU of special type (GROUP
+HDU), so if a template specifies 1 group with 1 member HDU like:
+
+\begin{verbatim}
+\group
+grpdescr = 'demo'
+xtension bintable
+# this bintable has 0 cols, 0 rows
+\end
+\end{verbatim}
+then the parser creates a FITS file with 3 HDUs :
+
+\begin{verbatim}
+1) dummy PHDU
+2) GROUP HDU (has 1 member, which is bintable in HDU number 3)
+3) bintable (member of GROUP in HDU number 2)
+\end{verbatim}
+Technically speaking, the GROUP HDU is a BINTABLE with 6 columns. Applications
+can define additional columns in a GROUP HDU using TFORMn and TTYPEn
+(where n is 7, 8, ....) keywords or their auto-indexing equivalents.
+
+For a more complicated example of a template file using the group directives,
+look at the sample.tpl file that is included in the CFITSIO distribution.
+
+
+\section{Formal Template Syntax}
+
+The template syntax can formally be defined as follows:
+
+\begin{verbatim}
+ TEMPLATE = BLOCK [ BLOCK ... ]
+
+ BLOCK = { HDU | GROUP }
+
+ GROUP = \GROUP [ BLOCK ... ] \END
+
+ HDU = XTENSION [ LINE ... ] { XTENSION | \GROUP | \END | EOF }
+
+ LINE = [ KEYWORD [ = ] ] [ VALUE ] [ / COMMENT ]
+
+ X ... - X can be present 1 or more times
+ { X | Y } - X or Y
+ [ X ] - X is optional
+\end{verbatim}
+
+At the topmost level, the template defines 1 or more template blocks. Blocks
+can be either HDU (Header Data Unit) or a GROUP. For each block the parser
+creates 1 (or more for GROUPs) FITS file HDUs.
+
+
+
+\section{Errors}
+
+In general the fits\_execute\_template() function tries to be as atomic
+as possible, so either everything is done or nothing is done. If an
+error occurs during parsing of the template, fits\_execute\_template()
+will (try to) delete the top level BLOCK (with all its children if any)
+in which the error occurred, then it will stop reading the template file
+and it will return with an error.
+
+
+\section{Examples}
+
+1. This template file will create a 200 x 300 pixel image, with 4-byte
+integer pixel values, in the primary HDU:
+
+\begin{verbatim}
+ SIMPLE = T
+ BITPIX = 32
+ NAXIS = 2 / number of dimensions
+ NAXIS1 = 100 / length of first axis
+ NAXIS2 = 200 / length of second axis
+ OBJECT = NGC 253 / name of observed object
+\end{verbatim}
+The allowed values of BITPIX are 8, 16, 32, -32, or -64,
+representing, respectively, 8-bit integer, 16-bit integer, 32-bit
+integer, 32-bit floating point, or 64 bit floating point pixels.
+
+2. To create a FITS table, the template first needs to include
+XTENSION = TABLE or BINTABLE to define whether it is an ASCII or binary
+table, and NAXIS2 to define the number of rows in the table. Two
+template lines are then needed to define the name (TTYPEn) and FITS data
+format (TFORMn) of the columns, as in this example:
+
+\begin{verbatim}
+ xtension = bintable
+ naxis2 = 40
+ ttype# = Name
+ tform# = 10a
+ ttype# = Npoints
+ tform# = j
+ ttype# = Rate
+ tunit# = counts/s
+ tform# = e
+\end{verbatim}
+The above example defines a null primary array followed by a 40-row
+binary table extension with 3 columns called 'Name', 'Npoints', and
+'Rate', with data formats of '10A' (ASCII character string), '1J'
+(integer) and '1E' (floating point), respectively. Note that the other
+required FITS keywords (BITPIX, NAXIS, NAXIS1, PCOUNT, GCOUNT, TFIELDS,
+and END) do not need to be explicitly defined in the template because
+their values can be inferred from the other keywords in the template.
+This example also illustrates that the templates are generally
+case-insensitive (the keyword names and TFORMn values are converted to
+upper-case in the FITS file) and that string keyword values generally
+do not need to be enclosed in quotes.
+
+\chapter{FITSIO Conventions and Guidelines }
+
+
+\section{CFITSIO Size Limitations}
+
+CFITSIO places few restrictions on the size of FITS files that it
+reads or writes. There are a few limits, however, which may affect
+some extreme cases:
+
+1. The maximum number of FITS files that may be simultaneously opened
+by CFITSIO is set by NMAXFILES as defined in fitsio2.h. It is currently
+set = 300 by default. CFITSIO will allocate about 80 * NMAXFILES bytes
+of memory for internal use. Note that the underlying C compiler or
+operating system, may have a smaller limit on the number of opened files.
+The C symbolic constant FOPEN\_MAX is intended to define the maximum
+number of files that may open at once (including any other text or
+binary files that may be open, not just FITS files). On some systems it
+has been found that gcc supports a maximum of 255 opened files.
+
+Note that opening and operating on many FITS files simultaneously in
+parallel may be less efficient than operating on smaller groups of files
+in series. CFITSIO only has NIOBUF number of internal buffers (set = 40
+by default) that are used for temporary storage of the most recent data
+records that have been read or written in the FITS files. If the number
+of opened files is greater than NIOBUF, then CFITSIO may waste more time
+flushing and re-reading or re-writing the same records in the FITS files.
+
+2. By default, CFITSIO can handle FITS files up to 2.1 GB in size (2**31
+bytes). This file size limit is often imposed by 32-bit operating
+systems. More recently, as 64-bit operating systems become more common, an
+industry-wide standard (at least on Unix systems) has been developed to
+support larger sized files (see http://ftp.sas.com/standards/large.file/).
+Starting with version 2.1 of CFITSIO, larger FITS files up to 6 terabytes
+in size may be read and written on supported platforms. In order
+to support these larger files, CFITSIO must be compiled with the
+'-D\_LARGEFILE\_SOURCE' and `-D\_FILE\_OFFSET\_BITS=64' compiler flags.
+Some platforms may also require the `-D\_LARGE\_FILES' compiler flag.
+ This causes the compiler to allocate 8-bytes instead of
+4-bytes for the `off\_t' datatype which is used to store file offset
+positions. It appears that in most cases it is not necessary to
+also include these compiler flags when compiling programs that link to
+the CFITSIO library.
+
+If CFITSIO is compiled with the -D\_LARGEFILE\_SOURCE
+and -D\_FILE\_OFFSET\_BITS=64 flags on a
+platform that supports large files, then it can read and write FITS
+files that contain up to 2**31 2880-byte FITS records, or approximately
+6 terabytes in size. It is still required that the value of the NAXISn
+and PCOUNT keywords in each extension be within the range of a signed
+4-byte integer (max value = 2,147,483,648). Thus, each dimension of an
+image (given by the NAXISn keywords), the total width of a table
+(NAXIS1 keyword), the number of rows in a table (NAXIS2 keyword), and
+the total size of the variable-length array heap in binary tables
+(PCOUNT keyword) must be less than this limit.
+
+Currently, support for large files within CFITSIO has been tested
+on the Linux, Solaris, and IBM AIX operating systems.
+
+
+\section{Multiple Access to the Same FITS File}
+
+CFITSIO supports simultaneous read and write access to multiple HDUs in
+the same FITS file. Thus, one can open the same FITS file twice within
+a single program and move to 2 different HDUs in the file, and then
+read and write data or keywords to the 2 extensions just as if one were
+accessing 2 completely separate FITS files. Since in general it is
+not possible to physically open the same file twice and then expect to
+be able to simultaneously (or in alternating succession) write to 2
+different locations in the file, CFITSIO recognizes when the file to be
+opened (in the call to fits\_open\_file) has already been opened and
+instead of actually opening the file again, just logically links the
+new file to the old file. (This only applies if the file is opened
+more than once within the same program, and does not prevent the same
+file from being simultaneously opened by more than one program). Then
+before CFITSIO reads or writes to either (logical) file, it makes sure
+that any modifications made to the other file have been completely
+flushed from the internal buffers to the file. Thus, in principle, one
+could open a file twice, in one case pointing to the first extension
+and in the other pointing to the 2nd extension and then write data to
+both extensions, in any order, without danger of corrupting the file,
+There may be some efficiency penalties in doing this however, since
+CFITSIO has to flush all the internal buffers related to one file
+before switching to the other, so it would still be prudent to
+minimize the number of times one switches back and forth between doing
+I/O to different HDUs in the same file.
+
+
+\section{Current Header Data Unit (CHDU)}
+
+In general, a FITS file can contain multiple Header Data Units, also
+called extensions. CFITSIO only operates within one HDU at any given
+time, and the currently selected HDU is called the Current Header Data
+Unit (CHDU). When a FITS file is first created or opened the CHDU is
+automatically defined to be the first HDU (i.e., the primary array).
+CFITSIO routines are provided to move to and open any other existing
+HDU within the FITS file or to append or insert a new HDU in the FITS
+file which then becomes the CHDU.
+
+
+\section{Subroutine Names}
+
+All FITSIO subroutine names begin with the letters 'ft' to distinguish
+them from other subroutines and are 5 or 6 characters long. Users should
+not name their own subroutines beginning with 'ft' to avoid conflicts.
+(The SPP interface routines all begin with 'fs'). Subroutines which read
+or get information from the FITS file have names beginning with
+'ftg...'. Subroutines which write or put information into the FITS file
+have names beginning with 'ftp...'.
+
+
+\section{Subroutine Families and Datatypes}
+
+Many of the subroutines come in families which differ only in the
+datatype of the associated parameter(s) . The datatype of these
+subroutines is indicated by the last letter of the subroutine name
+(e.g., 'j' in 'ftpkyj') as follows:
+
+\begin{verbatim}
+ x - bit
+ b - character*1 (unsigned byte)
+ i - short integer (I*2)
+ j - integer (I*4)
+ e - real exponential floating point (R*4)
+ f - real fixed-format floating point (R*4)
+ d - double precision real floating-point (R*8)
+ g - double precision fixed-format floating point (R*8)
+ c - complex reals (pairs of R*4 values)
+ m - double precision complex (pairs of R*8 values)
+ l - logical (L*4)
+ s - character string
+\end{verbatim}
+
+When dealing with the FITS byte datatype, it is important to remember
+that the raw values (before any scaling by the BSCALE and BZERO, or
+TSCALn and TZEROn keyword values) in byte arrays (BITPIX = 8) or byte
+columns (TFORMn = 'B') are interpreted as unsigned bytes with values
+ranging from 0 to 255. Some Fortran compilers support a non-standard
+byte datatype such as INTEGER*1, LOGICAL*1, or BYTE, which can sometimes
+be used instead of CHARACTER*1 variables. Many machines permit passing a
+numeric datatype (such as INTEGER*1) to the FITSIO subroutines which are
+expecting a CHARACTER*1 datatype, but this technically violates the
+Fortran-77 standard and is not supported on all machines (e.g., on a VAX/VMS
+machine one must use the VAX-specific \%DESCR function).
+
+One feature of the CFITSIO routines is that they can operate on a `X'
+(bit) column in a binary table as though it were a `B' (byte) column.
+For example a `11X' datatype column can be interpreted the same as a
+`2B' column (i.e., 2 unsigned 8-bit bytes). In some instances, it can
+be more efficient to read and write whole bytes at a time, rather than
+reading or writing each individual bit.
+
+The double precision complex datatype is not a standard Fortran-77
+datatype. If a particular Fortran compiler does not directly support
+this datatype, then one may instead pass an array of pairs of double
+precision values to these subroutines. The first value in each pair
+is the real part, and the second is the imaginary part.
+
+
+\section{Implicit Data Type Conversion}
+
+The FITSIO routines that read and write numerical data can perform
+implicit data type conversion. This means that the data type of the
+variable or array in the program does not need to be the same as the
+data type of the value in the FITS file. Data type conversion is
+supported for numerical and string data types (if the string contains a
+valid number enclosed in quotes) when reading a FITS header keyword
+value and for numeric values when reading or writing values in the
+primary array or a table column. CFITSIO returns status =
+NUM\_OVERFLOW if the converted data value exceeds the range of the
+output data type. Implicit data type conversion is not supported
+within binary tables for string, logical, complex, or double complex
+data types.
+
+In addition, any table column may be read as if it contained string values.
+In the case of numeric columns the returned string will be formatted
+using the TDISPn display format if it exists.
+
+
+\section{Data Scaling}
+
+When reading numerical data values in the primary array or a
+table column, the values will be scaled automatically by the BSCALE and
+BZERO (or TSCALn and TZEROn) header keyword values if they are
+present in the header. The scaled data that is returned to the reading
+program will have
+
+\begin{verbatim}
+ output value = (FITS value) * BSCALE + BZERO
+\end{verbatim}
+(a corresponding formula using TSCALn and TZEROn is used when reading
+from table columns). In the case of integer output values the floating
+point scaled value is truncated to an integer (not rounded to the
+nearest integer). The ftpscl and fttscl subroutines may be used to
+override the scaling parameters defined in the header (e.g., to turn
+off the scaling so that the program can read the raw unscaled values
+from the FITS file).
+
+When writing numerical data to the primary array or to a table
+column the data values will generally be automatically inversely scaled
+by the value of the BSCALE and BZERO (or TSCALn and TZEROn) header
+keyword values if they they exist in the header. These keywords must
+have been written to the header before any data is written for them to
+have any effect. Otherwise, one may use the ftpscl and fttscl
+subroutines to define or override the scaling keywords in the header
+(e.g., to turn off the scaling so that the program can write the raw
+unscaled values into the FITS file). If scaling is performed, the
+inverse scaled output value that is written into the FITS file will
+have
+
+\begin{verbatim}
+ FITS value = ((input value) - BZERO) / BSCALE
+\end{verbatim}
+(a corresponding formula using TSCALn and TZEROn is used when
+writing to table columns). Rounding to the nearest integer, rather
+than truncation, is performed when writing integer datatypes to the
+FITS file.
+
+
+\section{Error Status Values and the Error Message Stack}
+
+The last parameter in nearly every FITSIO subroutine is the error
+status value which is both an input and an output parameter. A
+returned positive value for this parameter indicates an error was
+detected. A listing of all the FITSIO status code values is given at
+the end of this document.
+
+The FITSIO library uses an `inherited status' convention for the status
+parameter which means that if a subroutine is called with a positive
+input value of the status parameter, then the subroutine will exit
+immediately without changing the value of the status parameter. Thus,
+if one passes the status value returned from each FITSIO routine as
+input to the next FITSIO subroutine, then whenever an error is detected
+all further FITSIO processing will cease. This convention can simplify
+the error checking in application programs because it is not necessary
+to check the value of the status parameter after every single FITSIO
+subroutine call. If a program contains a sequence of several FITSIO
+calls, one can just check the status value after the last call. Since
+the returned status values are generally distinctive, it should be
+possible to determine which subroutine originally returned the error
+status.
+
+FITSIO also maintains an internal stack of error messages (80-character
+maximum length) which in many cases provide a more detailed explanation
+of the cause of the error than is provided by the error status number
+alone. It is recommended that the error message stack be printed out
+whenever a program detects a FITSIO error. To do this, call the FTGMSG
+routine repeatedly to get the successive messages on the stack. When the
+stack is empty FTGMSG will return a blank string. Note that this is a
+`First In -- First Out' stack, so the oldest error message is returned
+first by ftgmsg.
+
+
+\section{Variable-Length Array Facility in Binary Tables}
+
+FITSIO provides easy-to-use support for reading and writing data in
+variable length fields of a binary table. The variable length columns
+have TFORMn keyword values of the form `1Pt(len)' where `t' is the
+datatype code (e.g., I, J, E, D, etc.) and `len' is an integer
+specifying the maximum length of the vector in the table. If the value
+of `len' is not specified when the table is created (e.g., if the TFORM
+keyword value is simply specified as '1PE' instead of '1PE(400) ), then
+FITSIO will automatically scan the table when it is closed to
+determine the maximum length of the vector and will append this value
+to the TFORMn value.
+
+The same routines which read and write data in an ordinary fixed length
+binary table extension are also used for variable length fields,
+however, the subroutine parameters take on a slightly different
+interpretation as described below.
+
+All the data in a variable length field is written into an area called
+the `heap' which follows the main fixed-length FITS binary table. The
+size of the heap, in bytes, is specified with the PCOUNT keyword in the
+FITS header. When creating a new binary table, the initial value of
+PCOUNT should usually be set to zero. FITSIO will recompute the size
+of the heap as the data is written and will automatically update the
+PCOUNT keyword value when the table is closed. When writing variable
+length data to a table, CFITSIO will automatically extend the size
+of the heap area if necessary, so that any following HDUs do not
+get overwritten.
+
+By default the heap data area starts immediately after the last row of
+the fixed-length table. This default starting location may be
+overridden by the THEAP keyword, but this is not recommended.
+If additional rows of data are added to the table, CFITSIO will
+automatically shift the the heap down to make room for the new
+rows, but it is obviously be more efficient to initially
+create the table with the necessary number of blank rows, so that
+the heap does not needed to be constantly moved.
+
+When writing to a variable length field, the entire array of values for
+a given row of the table must be written with a single call to FTPCLx.
+The total length of the array is calculated from (NELEM+FELEM-1). One
+cannot append more elements to an existing field at a later time; any
+attempt to do so will simply overwrite all the data which was previously
+written. Note also that the new data will be written to a new area of
+the heap and the heap space used by the previous write cannot be
+reclaimed. For this reason it is advised that each row of a variable
+length field only be written once. An exception to this general rule
+occurs when setting elements of an array as undefined. One must first
+write a dummy value into the array with FTPCLx, and then call FTPCLU to
+flag the desired elements as undefined. (Do not use the FTPCNx family
+of routines with variable length fields). Note that the rows of a table,
+whether fixed or variable length, do not have to be written
+consecutively and may be written in any order.
+
+When writing to a variable length ASCII character field (e.g., TFORM =
+'1PA') only a single character string written. FTPCLS writes the whole
+length of the input string (minus any trailing blank characters), thus
+the NELEM and FELEM parameters are ignored. If the input string is
+completely blank then FITSIO will write one blank character to the FITS
+file. Similarly, FTGCVS and FTGCFS read the entire string (truncated
+to the width of the character string argument in the subroutine call)
+and also ignore the NELEM and FELEM parameters.
+
+The FTPDES subroutine is useful in situations where multiple rows of a
+variable length column have the identical array of values. One can
+simply write the array once for the first row, and then use FTPDES to
+write the same descriptor values into the other rows (use the FTGDES
+routine to read the first descriptor value); all the rows will then
+point to the same storage location thus saving disk space.
+
+When reading from a variable length array field one can only read as
+many elements as actually exist in that row of the table; reading does
+not automatically continue with the next row of the table as occurs
+when reading an ordinary fixed length table field. Attempts to read
+more than this will cause an error status to be returned. One can
+determine the number of elements in each row of a variable column with
+the FTGDES subroutine.
+
+
+\section{Support for IEEE Special Values}
+
+The ANSI/IEEE-754 floating-point number standard defines certain
+special values that are used to represent such quantities as
+Not-a-Number (NaN), denormalized, underflow, overflow, and infinity.
+(See the Appendix in the NOST FITS standard or the NOST FITS User's
+Guide for a list of these values). The FITSIO subroutines that read
+floating point data in FITS files recognize these IEEE special values
+and by default interpret the overflow and infinity values as being
+equivalent to a NaN, and convert the underflow and denormalized values
+into zeros. In some cases programmers may want access to the raw IEEE
+values, without any modification by FITSIO. This can be done by
+calling the FTGPVx or FTGCVx routines while specifying 0.0 as the value
+of the NULLVAL parameter. This will force FITSIO to simply pass the
+IEEE values through to the application program, without any
+modification. This does not work for double precision values on
+VAX/VMS machines, however, where there is no easy way to bypass the
+default interpretation of the IEEE special values.
+
+
+\section{When the Final Size of the FITS HDU is Unknown}
+
+It is not required to know the total size of a FITS data array or table
+before beginning to write the data to the FITS file. In the case of
+the primary array or an image extension, one should initially create
+the array with the size of the highest dimension (largest NAXISn
+keyword) set to a dummy value, such as 1. Then after all the data have
+been written and the true dimensions are known, then the NAXISn value
+should be updated using the fits\_ update\_key routine before moving to
+another extension or closing the FITS file.
+
+When writing to FITS tables, CFITSIO automatically keeps track of the
+highest row number that is written to, and will increase the size of
+the table if necessary. CFITSIO will also automatically insert space
+in the FITS file if necessary, to ensure that the data 'heap', if it
+exists, and/or any additional HDUs that follow the table do not get
+overwritten as new rows are written to the table.
+
+As a general rule it is best to specify the initial number of rows = 0
+when the table is created, then let CFITSIO keep track of the number of
+rows that are actually written. The application program should not
+manually update the number of rows in the table (as given by the NAXIS2
+keyword) since CFITSIO does this automatically. If a table is
+initially created with more than zero rows, then this will usually be
+considered as the minimum size of the table, even if fewer rows are
+actually written to the table. Thus, if a table is initially created
+with NAXIS2 = 20, and CFITSIO only writes 10 rows of data before
+closing the table, then NAXIS2 will remain equal to 20. If however, 30
+rows of data are written to this table, then NAXIS2 will be increased
+from 20 to 30. The one exception to this automatic updating of the
+NAXIS2 keyword is if the application program directly modifies the
+value of NAXIS2 (up or down) itself just before closing the table. In this
+case, CFITSIO does not update NAXIS2 again, since it assumes that the
+application program must have had a good reason for changing the value
+directly. This is not recommended, however, and is only provided for
+backward compatibility with software that initially creates a table
+with a large number of rows, than decreases the NAXIS2 value to the
+actual smaller value just before closing the table.
+
+
+\section{Local FITS Conventions supported by FITSIO}
+
+CFITSIO supports several local FITS conventions which are not
+defined in the official NOST FITS standard and which are not
+necessarily recognized or supported by other FITS software packages.
+Programmers should be cautious about using these features, especially
+if the FITS files that are produced are expected to be processed by
+other software systems which do not use the CFITSIO interface.
+
+
+\subsection{Support for Long String Keyword Values.}
+
+The length of a standard FITS string keyword is limited to 68
+characters because it must fit entirely within a single FITS header
+keyword record. In some instances it is necessary to encode strings
+longer than this limit, so FITSIO supports a local convention in which
+the string value is continued over multiple keywords. This
+continuation convention uses an ampersand character at the end of each
+substring to indicate that it is continued on the next keyword, and the
+continuation keywords all have the name CONTINUE without an equal sign
+in column 9. The string value may be continued in this way over as many
+additional CONTINUE keywords as is required. The following lines
+illustrate this continuation convention which is used in the value of
+the STRKEY keyword:
+
+\begin{verbatim}
+LONGSTRN= 'OGIP 1.0' / The OGIP Long String Convention may be used.
+STRKEY = 'This is a very long string keyword&' / Optional Comment
+CONTINUE ' value that is continued over 3 keywords in the & '
+CONTINUE 'FITS header.' / This is another optional comment.
+\end{verbatim}
+It is recommended that the LONGSTRN keyword, as shown
+here, always be included in any HDU that uses this longstring
+convention. A subroutine called FTPLSW
+has been provided in CFITSIO to write this keyword if it does not
+already exist.
+
+This long string convention is supported by the following FITSIO
+subroutines that deal with string-valued keywords:
+
+\begin{verbatim}
+ ftgkys - read a string keyword
+ ftpkls - write (append) a string keyword
+ ftikls - insert a string keyword
+ ftmkls - modify the value of an existing string keyword
+ ftukls - update an existing keyword, or write a new keyword
+ ftdkey - delete a keyword
+\end{verbatim}
+These routines will transparently read, write, or delete a long string
+value in the FITS file, so programmers in general do not have to be
+concerned about the details of the convention that is used to encode
+the long string in the FITS header. When reading a long string, one
+must ensure that the character string parameter used in these
+subroutine calls has been declared long enough to hold the entire
+string, otherwise the returned string value will be truncated.
+
+Note that the more commonly used FITSIO subroutine to write string
+valued keywords (FTPKYS) does NOT support this long string convention
+and only supports strings up to 68 characters in length. This has been
+done deliberately to prevent programs from inadvertently writing
+keywords using this non-standard convention without the explicit intent
+of the programmer or user. The FTPKLS subroutine must be called
+instead to write long strings. This routine can also be used to write
+ordinary string values less than 68 characters in length.
+
+
+\subsection{Arrays of Fixed-Length Strings in Binary Tables}
+
+The definition of the FITS binary table extension format does not
+provide a simple way to specify that a character column contains an
+array of fixed-length strings. To support this feature, FITSIO uses a
+local convention for the format of the TFORMn keyword value of the form
+'rAw' where 'r' is an integer specifying the total width in characters
+of the column, and 'w' is an integer specifying the (fixed) length of
+an individual unit string within the vector. For example, TFORM1 =
+'120A10' would indicate that the binary table column is 120 characters
+wide and consists of 12 10-character length strings. This convention
+is recognized by the FITSIO subroutines that read or write strings in
+binary tables. The Binary Table definition document specifies that
+other optional characters may follow the datatype code in the TFORM
+keyword, so this local convention is in compliance with the
+FITS standard, although other FITS readers are not required to
+recognize this convention.
+
+The Binary Table definition document that was approved by the IAU in
+1994 contains an appendix describing an alternate convention for
+specifying arrays of fixed or variable length strings in a binary table
+character column (with the form 'rA:SSTRw/nnn)'. This appendix was not
+officially voted on by the IAU and hence is still provisional. FITSIO
+does not currently support this proposal.
+
+
+\subsection{Keyword Units Strings}
+
+One deficiency of the current FITS Standard is that it does not define
+a specific convention for recording the physical units of a keyword
+value. The TUNITn keyword can be used to specify the physical units of
+the values in a table column, but there is no analogous convention for
+keyword values. The comment field of the keyword is often used for
+this purpose, but the units are usually not specified in a well defined
+format that FITS readers can easily recognize and extract.
+
+To solve this deficiency, FITSIO uses a local convention in which the
+keyword units are enclosed in square brackets as the first token in the
+keyword comment field; more specifically, the opening square bracket
+immediately follows the slash '/' comment field delimiter and a single
+space character. The following examples illustrate keywords that use
+this convention:
+
+
+\begin{verbatim}
+EXPOSURE= 1800.0 / [s] elapsed exposure time
+V_HELIO = 16.23 / [km s**(-1)] heliocentric velocity
+LAMBDA = 5400. / [angstrom] central wavelength
+FLUX = 4.9033487787637465E-30 / [J/cm**2/s] average flux
+\end{verbatim}
+
+In general, the units named in the IAU(1988) Style Guide are
+recommended, with the main exception that the preferred unit for angle
+is 'deg' for degrees.
+
+The FTPUNT and FTGUNT subroutines in FITSIO write and read,
+respectively, the keyword unit strings in an existing keyword.
+
+
+\subsection{HIERARCH Convention for Extended Keyword Names}
+
+CFITSIO supports the HIERARCH keyword convention which allows keyword
+names that are longer then 8 characters and may contain the full range
+of printable ASCII text characters. This convention
+was developed at the European Southern Observatory (ESO) to support
+hierarchical FITS keyword such as:
+
+\begin{verbatim}
+HIERARCH ESO INS FOCU POS = -0.00002500 / Focus position
+\end{verbatim}
+Basically, this convention uses the FITS keyword 'HIERARCH' to indicate
+that this convention is being used, then the actual keyword name
+({\tt'ESO INS FOCU POS'} in this example) begins in column 10 and can
+contain any printable ASCII text characters, including spaces. The
+equals sign marks the end of the keyword name and is followed by the
+usual value and comment fields just as in standard FITS keywords.
+Further details of this convention are described at
+http://arcdev.hq.eso.org/dicb/dicd/dic-1-1.4.html (search for
+HIERARCH).
+
+This convention allows a much broader range of keyword names
+than is allowed by the FITS Standard. Here are more examples
+of such keywords:
+
+\begin{verbatim}
+HIERARCH LongKeyword = 47.5 / Keyword has > 8 characters, and mixed case
+HIERARCH XTE$TEMP = 98.6 / Keyword contains the '$' character
+HIERARCH Earth is a star = F / Keyword contains embedded spaces
+\end{verbatim}
+CFITSIO will transparently read and write these keywords, so application
+programs do not in general need to know anything about the specific
+implementation details of the HIERARCH convention. In particular,
+application programs do not need to specify the `HIERARCH' part of the
+keyword name when reading or writing keywords (although it
+may be included if desired). When writing a keyword, CFITSIO first
+checks to see if the keyword name is legal as a standard FITS keyword
+(no more than 8 characters long and containing only letters, digits, or
+a minus sign or underscore). If so it writes it as a standard FITS
+keyword, otherwise it uses the hierarch convention to write the
+keyword. The maximum keyword name length is 67 characters, which
+leaves only 1 space for the value field. A more practical limit is
+about 40 characters, which leaves enough room for most keyword values.
+CFITSIO returns an error if there is not enough room for both the
+keyword name and the keyword value on the 80-character card, except for
+string-valued keywords which are simply truncated so that the closing
+quote character falls in column 80. In the current implementation,
+CFITSIO preserves the case of the letters when writing the keyword
+name, but it is case-insensitive when reading or searching for a
+keyword. The current implementation allows any ASCII text character
+(ASCII 32 to ASCII 126) in the keyword name except for the '='
+character. A space is also required on either side of the equal sign.
+
+
+\section{Optimizing Code for Maximum Processing Speed}
+
+CFITSIO has been carefully designed to obtain the highest possible
+speed when reading and writing FITS files. In order to achieve the
+best performance, however, application programmers must be careful to
+call the CFITSIO routines appropriately and in an efficient sequence;
+inappropriate usage of CFITSIO routines can greatly slow down the
+execution speed of a program.
+
+The maximum possible I/O speed of CFITSIO depends of course on the type
+of computer system that it is running on. As a rough guide, the
+current generation of workstations can achieve speeds of 2 -- 10 MB/s
+when reading or writing FITS images and similar, or slightly slower
+speeds with FITS binary tables. Reading of FITS files can occur at
+even higher rates (30MB/s or more) if the FITS file is still cached in
+system memory following a previous read or write operation on the same
+file. To more accurately predict the best performance that is possible
+on any particular system, a diagnostic program called ``speed.c'' is
+included with the CFITSIO distribution which can be run to
+approximately measure the maximum possible speed of writing and reading
+a test FITS file.
+
+The following 2 sections provide some background on how CFITSIO
+internally manages the data I/O and describes some strategies that may
+be used to optimize the processing speed of software that uses
+CFITSIO.
+
+
+\subsection{Background Information: How CFITSIO Manages Data I/O}
+
+Many CFITSIO operations involve transferring only a small number of
+bytes to or from the FITS file (e.g, reading a keyword, or writing a
+row in a table); it would be very inefficient to physically read or
+write such small blocks of data directly in the FITS file on disk,
+therefore CFITSIO maintains a set of internal Input--Output (IO)
+buffers in RAM memory that each contain one FITS block (2880 bytes) of
+data. Whenever CFITSIO needs to access data in the FITS file, it first
+transfers the FITS block containing those bytes into one of the IO
+buffers in memory. The next time CFITSIO needs to access bytes in the
+same block it can then go to the fast IO buffer rather than using a
+much slower system disk access routine. The number of available IO
+buffers is determined by the NIOBUF parameter (in fitsio2.h) and is
+currently set to 40.
+
+Whenever CFITSIO reads or writes data it first checks to see if that
+block of the FITS file is already loaded into one of the IO buffers.
+If not, and if there is an empty IO buffer available, then it will load
+that block into the IO buffer (when reading a FITS file) or will
+initialize a new block (when writing to a FITS file). If all the IO
+buffers are already full, it must decide which one to reuse (generally
+the one that has been accessed least recently), and flush the contents
+back to disk if it has been modified before loading the new block.
+
+The one major exception to the above process occurs whenever a large
+contiguous set of bytes are accessed, as might occur when reading or
+writing a FITS image. In this case CFITSIO bypasses the internal IO
+buffers and simply reads or writes the desired bytes directly in the
+disk file with a single call to a low-level file read or write
+routine. The minimum threshold for the number of bytes to read or
+write this way is set by the MINDIRECT parameter and is currently set
+to 3 FITS blocks = 8640 bytes. This is the most efficient way to read
+or write large chunks of data and can achieve IO transfer rates of
+5 -- 10MB/s or greater. Note that this fast direct IO process is not
+applicable when accessing columns of data in a FITS table because the
+bytes are generally not contiguous since they are interleaved by the
+other columns of data in the table. This explains why the speed for
+accessing FITS tables is generally slower than accessing
+FITS images.
+
+Given this background information, the general strategy for efficiently
+accessing FITS files should now be apparent: when dealing with FITS
+images, read or write large chunks of data at a time so that the direct
+IO mechanism will be invoked; when accessing FITS headers or FITS
+tables, on the other hand, once a particular FITS block has been
+loading into one of the IO buffers, try to access all the needed
+information in that block before it gets flushed out of the IO buffer.
+It is important to avoid the situation where the same FITS block is
+being read then flushed from a IO buffer multiple times.
+
+The following section gives more specific suggestions for optimizing
+the use of CFITSIO.
+
+1. When dealing with a FITS primary array or IMAGE extension, it is
+more efficient to read or write large chunks of the image at a time
+(at least 3 FITS blocks = 8640 bytes) so that the direct IO mechanism
+will be used as described in the previous section. Smaller chunks of
+data are read or written via the IO buffers, which is somewhat less
+efficient because of the extra copy operation and additional
+bookkeeping steps that are required. In principle it is more efficient
+to read or write as big an array of image pixels at one time as
+possible, however, if the array becomes so large that the operating
+system cannot store it all in RAM, then the performance may be degraded
+because of the increased swapping of virtual memory to disk.
+
+2. When dealing with FITS tables, the most important efficiency factor
+in the software design is to read or write the data in the FITS file in
+a single pass through the file. An example of poor program design
+would be to read a large, 3-column table by sequentially reading the
+entire first column, then going back to read the 2nd column, and
+finally the 3rd column; this obviously requires 3 passes through the
+file which could triple the execution time of an I/O limited program.
+For small tables this is not important, but when reading multi-megabyte
+sized tables these inefficiencies can become significant. The more
+efficient procedure in this case is to read or write only as many rows
+of the table as will fit into the available internal I/O buffers, then
+access all the necessary columns of data within that range of rows.
+Then after the program is completely finished with the data in those
+rows it can move on to the next range of rows that will fit in the
+buffers, continuing in this way until the entire file has been
+processed. By using this procedure of accessing all the columns of a
+table in parallel rather than sequentially, each block of the FITS file
+will only be read or written once.
+
+The optimal number of rows to read or write at one time in a given
+table depends on the width of the table row, on the number of I/O
+buffers that have been allocated in FITSIO, and also on the number of
+other FITS files that are open at the same time (since one I/O buffer
+is always reserved for each open FITS file). Fortunately, a FITSIO
+routine is available that will return the optimal number of rows for a
+given table: call ftgrsz(unit, nrows, status). It is not critical to
+use exactly the value of nrows returned by this routine, as long as one
+does not exceed it. Using a very small value however can also lead to
+poor performance because of the overhead from the larger number of
+subroutine calls.
+
+The optimal number of rows returned by ftgrsz is valid only as long as
+the application program is only reading or writing data in the
+specified table. Any other calls to access data in the table header or
+in any other FITS file would cause additional blocks of data to be
+loaded into the I/O buffers displacing data from the original table,
+and should be avoided during the critical period while the table is
+being read or written.
+
+Occasionally it is necessary to simultaneously access more than one
+FITS table, for example when transferring values from an input table to
+an output table. In cases like this, one should call ftgrsz to get the
+optimal number of rows for each table separately, than reduce the
+number of rows proportionally. For example, if the optimal number of
+rows in the input table is 3600 and is 1400 in the output table, then
+these values should be cut in half to 1800 and 700, respectively, if
+both tables are going to be accessed at the same time.
+
+3. Use binary table extensions rather than ASCII table
+extensions for better efficiency when dealing with tabular data. The
+I/O to ASCII tables is slower because of the overhead in formatting or
+parsing the ASCII data fields, and because ASCII tables are about twice
+as large as binary tables with the same information content.
+
+4. Design software so that it reads the FITS header keywords in the
+same order in which they occur in the file. When reading keywords,
+FITSIO searches forward starting from the position of the last keyword
+that was read. If it reaches the end of the header without finding the
+keyword, it then goes back to the start of the header and continues the
+search down to the position where it started. In practice, as long as
+the entire FITS header can fit at one time in the available internal I/O
+buffers, then the header keyword access will be very fast and it makes
+little difference which order they are accessed.
+
+5. Avoid the use of scaling (by using the BSCALE and BZERO or TSCAL and
+TZERO keywords) in FITS files since the scaling operations add to the
+processing time needed to read or write the data. In some cases it may
+be more efficient to temporarily turn off the scaling (using ftpscl or
+fttscl) and then read or write the raw unscaled values in the FITS
+file.
+
+6. Avoid using the 'implicit datatype conversion' capability in
+FITSIO. For instance, when reading a FITS image with BITPIX = -32
+(32-bit floating point pixels), read the data into a single precision
+floating point data array in the program. Forcing FITSIO to convert
+the data to a different datatype can significantly slow the program.
+
+7. Where feasible, design FITS binary tables using vector column
+elements so that the data are written as a contiguous set of bytes,
+rather than as single elements in multiple rows. For example, it is
+faster to access the data in a table that contains a single row
+and 2 columns with TFORM keywords equal to '10000E' and '10000J', than
+it is to access the same amount of data in a table with 10000 rows
+which has columns with the TFORM keywords equal to '1E' and '1J'. In
+the former case the 10000 floating point values in the first column are
+all written in a contiguous block of the file which can be read or
+written quickly, whereas in the second case each floating point value
+in the first column is interleaved with the integer value in the second
+column of the same row so CFITSIO has to explicitly move to the
+position of each element to be read or written.
+
+8. Avoid the use of variable length vector columns in binary tables,
+since any reading or writing of these data requires that CFITSIO first
+look up or compute the starting address of each row of data in the
+heap.
+
+9. When copying data from one FITS table to another, it is faster to
+transfer the raw bytes instead of reading then writing each column of
+the table. The FITSIO subroutines FTGTBS and FTPTBS (for ASCII
+tables), and FTGTBB and FTPTBB (for binary tables) will perform
+low-level reads or writes of any contiguous range of bytes in a table
+extension. These routines can be used to read or write a whole row (or
+multiple rows) of a table with a single subroutine call. These
+routines are fast because they bypass all the usual data scaling, error
+checking and machine dependent data conversion that is normally done by
+FITSIO, and they allow the program to write the data to the output file
+in exactly the same byte order. For these same reasons, use of these
+routines can be somewhat risky because no validation or machine
+dependent conversion is performed by these routines. In general these
+routines are only recommended for optimizing critical pieces of code
+and should only be used by programmers who thoroughly understand the
+internal byte structure of the FITS tables they are reading or
+writing.
+
+10. Another strategy for improving the speed of writing a FITS table,
+similar to the previous one, is to directly construct the entire byte
+stream for a whole table row (or multiple rows) within the application
+program and then write it to the FITS file with
+ftptbb. This avoids all the overhead normally present
+in the column-oriented CFITSIO write routines. This technique should
+only be used for critical applications, because it makes the code more
+difficult to understand and maintain, and it makes the code more system
+dependent (e.g., do the bytes need to be swapped before writing to the
+FITS file?).
+
+11. Finally, external factors such as the type of magnetic disk
+controller (SCSI or IDE), the size of the disk cache, the average seek
+speed of the disk, the amount of disk fragmentation, and the amount of
+RAM available on the system can all have a significant impact on
+overall I/O efficiency. For critical applications, a system
+administrator should review the proposed system hardware to identify any
+potential I/O bottlenecks.
+
+
+\chapter{ The CFITSIO Iterator Function }
+
+The fits\_iterate\_data function in CFITSIO provides a unique method of
+executing an arbitrary user-supplied `work' function that operates on
+rows of data in FITS tables or on pixels in FITS images. Rather than
+explicitly reading and writing the FITS images or columns of data, one
+instead calls the CFITSIO iterator routine, passing to it the name of
+the user's work function that is to be executed along with a list of
+all the table columns or image arrays that are to be passed to the work
+function. The CFITSIO iterator function then does all the work of
+allocating memory for the arrays, reading the input data from the FITS
+file, passing them to the work function, and then writing any output
+data back to the FITS file after the work function exits. Because
+it is often more efficient to process only a subset of the total table
+rows at one time, the iterator function can determine the optimum
+amount of data to pass in each iteration and repeatly call the work
+function until the entire table been processed.
+
+For many applications this single CFITSIO iterator function can
+effectively replace all the other CFITSIO routines for reading or
+writing data in FITS images or tables. Using the iterator has several
+important advantages over the traditional method of reading and writing
+FITS data files:
+
+\begin{itemize}
+\item
+It cleanly separates the data I/O from the routine that operates on
+the data. This leads to a more modular and `object oriented'
+programming style.
+
+\item
+It simplifies the application program by eliminating the need to allocate
+memory for the data arrays and eliminates most of the calls to the CFITSIO
+routines that explicitly read and write the data.
+
+\item
+It ensures that the data are processed as efficiently as possible.
+This is especially important when processing tabular data since
+the iterator function will calculate the most efficient number
+of rows in the table to be passed at one time to the user's work
+function on each iteration.
+
+\item
+Makes it possible for larger projects to develop a library of work
+functions that all have a uniform calling sequence and are all
+independent of the details of the FITS file format.
+
+\end{itemize}
+
+There are basically 2 steps in using the CFITSIO iterator function.
+The first step is to design the work function itself which must have a
+prescribed set of input parameters. One of these parameters is a
+structure containing pointers to the arrays of data; the work function
+can perform any desired operations on these arrays and does not need to
+worry about how the input data were read from the file or how the
+output data get written back to the file.
+
+The second step is to design the driver routine that opens all the
+necessary FITS files and initializes the input parameters to the
+iterator function. The driver program calls the CFITSIO iterator
+function which then reads the data and passes it to the user's work
+function.
+
+Further details on using the iterator function can be found in the
+companion CFITSIO User's Guide, and in the iter\_a.f, iter\_b.f and
+iter\_c.f example programs.
+
+
+
+\chapter{ Basic Interface Routines }
+
+This section defines a basic set of subroutines that can be
+used to perform the most common types of read and write operations
+on FITS files. New users should start with these subroutines and
+then, as needed, explore the more advance routines described in
+the following chapter to perform more complex or specialized operations.
+
+A right arrow symbol ($>$) is used to separate the input parameters from
+the output parameters in the definition of each routine. This symbol
+is not actually part of the calling sequence. Note that
+the status parameter is both an input and an output parameter
+and must be initialized = 0 prior to calling the FITSIO subroutines.
+
+Refer to Chapter 9 for the definition of all the parameters
+used by these interface routines.
+
+
+\section{FITSIO Error Status Routines \label{FTVERS}}
+
+
+\begin{description}
+\item[1 ] Return the current version number of the fitsio library.
+ The version number will be incremented with each new
+ release of CFITSIO.
+\end{description}
+
+\begin{verbatim}
+ FTVERS( > version)
+\end{verbatim}
+
+\begin{description}
+\item[2 ] Return the descriptive text string corresponding to a FITSIO error
+ status code. The 30-character length string contains a brief
+ description of the cause of the error.
+\end{description}
+
+\begin{verbatim}
+ FTGERR(status, > errtext)
+\end{verbatim}
+
+\begin{description}
+\item[3 ] Return the top (oldest) 80-character error message from the
+ internal FITSIO stack of error messages and shift any remaining
+ messages on the stack up one level. Any FITSIO error will
+ generate one or more messages on the stack. Call this routine
+ repeatedly to get each message in sequence. The error stack is empty
+ when a blank string is returned.
+\end{description}
+
+\begin{verbatim}
+ FTGMSG( > errmsg)
+\end{verbatim}
+
+\begin{description}
+\item[4 ]The FTPMRK routine puts an invisible marker on the
+ CFITSIO error stack. The FTCMRK routine can then be
+ used to delete any more recent error messages on the stack, back to
+ the position of the marker. This preserves any older error messages
+ on the stack. FTCMSG simply clears the entire error message stack.
+ These routines are called without any arguments.
+\end{description}
+
+\begin{verbatim}
+ FTPMRK
+ FTCMRK
+ FTCMSG
+\end{verbatim}
+
+
+\begin{description}
+\item[5 ] Print out the error message corresponding to the input status
+ value and all the error messages on the FITSIO stack to the specified
+ file stream (stream can be either the string 'STDOUT' or 'STDERR').
+ If the input status value = 0 then this routine does nothing.
+\end{description}
+
+\begin{verbatim}
+ FTRPRT (stream, > status)
+\end{verbatim}
+
+\begin{description}
+\item[6 ] Write an 80-character message to the FITSIO error stack. Application
+ programs should not normally write to the stack, but there may be
+ some situations where this is desirable.
+\end{description}
+
+\begin{verbatim}
+ FTPMSG(errmsg)
+\end{verbatim}
+
+
+\section{File I/O Routines}
+
+
+\begin{description}
+\item[1 ]Open an existing FITS file with readonly or readwrite access.
+ This routine always opens the primary array (the first HDU) of
+ the file, and does not move to a following extension, if one was
+ specified as part of the filename. Use the FTNOPN routine to
+ automatically move to the extension. This routine will also
+ open IRAF images (.imh format files) and raw binary data arrays
+ with READONLY access by first converting them on the fly into
+ virtual FITS images. See the `Extended File Name Syntax' chapter
+ for more details. The second routine simply opens the specified
+ file without trying to interpret the filename using the extended
+ filename syntax.
+\end{description}
+
+\begin{verbatim}
+ FTOPEN(unit,filename,rwmode, > blocksize,status)
+ FTDKOPEN(unit,filename,rwmode, > blocksize,status)
+\end{verbatim}
+
+\begin{description}
+\item[2 ]Open an existing FITS file with readonly or readwrite access
+ and move to a following extension, if one was specified as
+ part of the filename. (e.g., 'filename.fits+2' or
+ 'filename.fits[2]' will move to the 3rd HDU in the file).
+ Note that this routine differs from FTOPEN in that it does not
+ have the redundant blocksize argument.
+\end{description}
+
+\begin{verbatim}
+ FTNOPN(unit,filename,rwmode, > status)
+\end{verbatim}
+
+\begin{description}
+\item[3 ]Open an existing FITS file with readonly or readwrite access
+ and then move to the first HDU containing significant data, if a) an HDU
+ name or number to open was not explicitly specified as part of the
+ filename, and b) if the FITS file contains a null primary array (i.e.,
+ NAXIS = 0). In this case, it will look for the first IMAGE HDU with
+ NAXIS > 0, or the first table that does not contain the strings `GTI'
+ (Good Time Interval) or `OBSTABLE' in the EXTNAME keyword value. FTTOPN
+ is similar, except it will move to the first significant table HDU
+ (skipping over any image HDUs) in the file if a specific HDU name
+ or number is not specified. FTIOPN will move to the first non-null
+ image HDU, skipping over any tables.
+\end{description}
+
+\begin{verbatim}
+ FTDOPN(unit,filename,rwmode, > status)
+ FTTOPN(unit,filename,rwmode, > status)
+ FTIOPN(unit,filename,rwmode, > status)
+\end{verbatim}
+
+\begin{description}
+\item[4 ]Open and initialize a new empty FITS file. A template file may also be
+ specified to define the structure of the new file (see section 4.2.4).
+ The second routine simply creates the specified
+ file without trying to interpret the filename using the extended
+ filename syntax.
+\end{description}
+
+\begin{verbatim}
+ FTINIT(unit,filename,blocksize, > status)
+ FTDKINIT(unit,filename,blocksize, > status)
+\end{verbatim}
+
+\begin{description}
+\item[5 ]Close a FITS file previously opened with ftopen or ftinit
+\end{description}
+
+\begin{verbatim}
+ FTCLOS(unit, > status)
+\end{verbatim}
+
+\begin{description}
+\item[6 ] Move to a specified (absolute) HDU in the FITS file (nhdu = 1 for the
+ FITS primary array)
+\end{description}
+
+\begin{verbatim}
+ FTMAHD(unit,nhdu, > hdutype,status)
+\end{verbatim}
+
+\begin{description}
+\item[7 ] Create a primary array (if none already exists), or insert a
+ new IMAGE extension immediately following the CHDU, or
+ insert a new Primary Array at the beginning of the file. Any
+ following extensions in the file will be shifted down to make room
+ for the new extension. If the CHDU is the last HDU in the file
+ then the new image extension will simply be appended to the end of
+ the file. One can force a new primary array to be inserted at the
+ beginning of the FITS file by setting status = -9 prior
+ to calling the routine. In this case the old primary array will be
+ converted to an IMAGE extension. The new extension (or primary
+ array) will become the CHDU.
+\end{description}
+
+\begin{verbatim}
+ FTIIMG(unit,bitpix,naxis,naxes, > status)
+\end{verbatim}
+
+\begin{description}
+\item[8 ] Insert a new ASCII TABLE extension immediately following the CHDU.
+ Any following extensions will be shifted down to make room for
+ the new extension. If there are no other following extensions
+ then the new table extension will simply be appended to the
+ end of the file. The new extension will become the CHDU.
+\end{description}
+
+\begin{verbatim}
+ FTITAB(unit,rowlen,nrows,tfields,ttype,tbcol,tform,tunit,extname, >
+ status)
+\end{verbatim}
+
+\begin{description}
+\item[9 ] Insert a new binary table extension immediately following the CHDU.
+ Any following extensions will be shifted down to make room for
+ the new extension. If there are no other following extensions
+ then the new bintable extension will simply be appended to the
+ end of the file. The new extension will become the CHDU.
+\end{description}
+
+\begin{verbatim}
+ FTIBIN(unit,nrows,tfields,ttype,tform,tunit,extname,varidat > status)
+\end{verbatim}
+
+\section{Keyword I/O Routines}
+
+
+\begin{description}
+\item[1 ]Put (append) an 80-character record into the CHU.
+\end{description}
+
+\begin{verbatim}
+ FTPREC(unit,card, > status)
+\end{verbatim}
+
+\begin{description}
+\item[2 ] Put (append) a new keyword of the appropriate datatype into the CHU.
+ The E and D versions of this routine have the added feature that
+ if the 'decimals' parameter is negative, then the 'G' display
+ format rather then the 'E' format will be used when constructing
+ the keyword value, taking the absolute value of 'decimals' for the
+ precision. This will suppress trailing zeros, and will use a
+ fixed format rather than an exponential format,
+ depending on the magnitude of the value.
+\end{description}
+
+\begin{verbatim}
+ FTPKY[JLS](unit,keyword,keyval,comment, > status)
+ FTPKY[EDFG](unit,keyword,keyval,decimals,comment, > status)
+\end{verbatim}
+
+\begin{description}
+\item[3 ]Get the nth 80-character header record from the CHU. The first keyword
+ in the header is at key\_no = 1; if key\_no = 0 then this subroutine
+ simple moves the internal pointer to the beginning of the header
+ so that subsequent keyword operations will start at the top of
+ the header; it also returns a blank card value in this case.
+\end{description}
+
+\begin{verbatim}
+ FTGREC(unit,key_no, > card,status)
+\end{verbatim}
+
+\begin{description}
+\item[4 ] Get a keyword value (with the appropriate datatype) and comment from
+ the CHU
+\end{description}
+
+\begin{verbatim}
+ FTGKY[EDJLS](unit,keyword, > keyval,comment,status)
+\end{verbatim}
+
+\begin{description}
+\item[5 ] Delete an existing keyword record.
+\end{description}
+
+\begin{verbatim}
+ FTDKEY(unit,keyword, > status)
+\end{verbatim}
+
+
+\section{Data I/O Routines}
+
+The following routines read or write data values in the current HDU of
+the FITS file. Automatic datatype conversion
+will be attempted for numerical datatypes if the specified datatype is
+different from the actual datatype of the FITS array or table column.
+
+
+\begin{description}
+\item[1 ]Write elements into the primary data array or image extension.
+\end{description}
+
+\begin{verbatim}
+ FTPPR[BIJED](unit,group,fpixel,nelements,values, > status)
+\end{verbatim}
+
+\begin{description}
+\item[2 ] Read elements from the primary data array or image extension.
+ Undefined array elements will be
+ returned with a value = nullval, unless nullval = 0 in which case no
+ checks for undefined pixels will be performed. The anyf parameter is
+ set to true (= .true.) if any of the returned
+ elements were undefined.
+\end{description}
+
+\begin{verbatim}
+ FTGPV[BIJED](unit,group,fpixel,nelements,nullval, > values,anyf,status)
+\end{verbatim}
+
+\begin{description}
+\item[3 ] Write elements into an ASCII or binary table column. The `felem'
+ parameter applies only to vector columns in binary tables and is
+ ignored when writing to ASCII tables.
+\end{description}
+
+\begin{verbatim}
+ FTPCL[SLBIJEDCM](unit,colnum,frow,felem,nelements,values, > status)
+\end{verbatim}
+
+\begin{description}
+\item[4 ] Read elements from an ASCII or binary table column. Undefined
+ array elements will be returned with a value = nullval, unless nullval = 0
+ (or = ' ' for ftgcvs) in which case no checking for undefined values will
+ be performed. The ANYF parameter is set to true if any of the returned
+ elements are undefined.
+
+ Any column, regardless of it's intrinsic datatype, may be read as a
+ string. It should be noted however that reading a numeric column
+ as a string is 10 - 100 times slower than reading the same column
+ as a number due to the large overhead in constructing the formatted
+ strings. The display format of the returned strings will be
+ determined by the TDISPn keyword, if it exists, otherwise by the
+ datatype of the column. The length of the returned strings can be
+ determined with the ftgcdw routine. The following TDISPn display
+ formats are currently supported:
+
+\begin{verbatim}
+ Iw.m Integer
+ Ow.m Octal integer
+ Zw.m Hexadecimal integer
+ Fw.d Fixed floating point
+ Ew.d Exponential floating point
+ Dw.d Exponential floating point
+ Gw.d General; uses Fw.d if significance not lost, else Ew.d
+\end{verbatim}
+ where w is the width in characters of the displayed values, m is the minimum
+ number of digits displayed, and d is the number of digits to the right of the
+ decimal. The .m field is optional.
+\end{description}
+
+
+\begin{verbatim}
+ FTGCV[SBIJEDCM](unit,colnum,frow,felem,nelements,nullval, >
+ values,anyf,status)
+\end{verbatim}
+
+\begin{description}
+\item[5 ] Get the table column number and full name of the column whose name
+ matches the input template string. See the `Advanced Interface Routines'
+ chapter for a full description of this routine.
+\end{description}
+
+\begin{verbatim}
+ FTGCNN(unit,casesen,coltemplate, > colname,colnum,status)
+\end{verbatim}
+
+
+\chapter{ Advanced Interface Subroutines }
+
+This chapter defines all the available subroutines in the FITSIO user
+interface. For completeness, the basic subroutines described in the
+previous chapter are also repeated here. A right arrow symbol is used
+here to separate the input parameters from the output parameters in the
+definition of each subroutine. This symbol is not actually part of the
+calling sequence. An alphabetical list and definition of all the
+parameters is given at the end of this section.
+
+
+\section{FITS File Open and Close Subroutines: \label{FTOPEN}}
+
+
+\begin{description}
+\item[1 ]Open an existing FITS file with readonly or readwrite access. FTDOPN
+also moves to the first HDU containing significant data, if no specific
+HDU is specified as part of the filename. FTTOPN and FTIOPN are similar
+except that they will move to the first table HDU or image HDU, respectively,
+if a HDU name or number is not specified as part of the filename.
+\end{description}
+
+\begin{verbatim}
+ FTOPEN(unit,filename,rwmode, > blocksize,status)
+ FTDOPN(unit,filename,rwmode, > status)
+ FTTOPN(unit,filename,rwmode, > status)
+ FTIOPN(unit,filename,rwmode, > status)
+\end{verbatim}
+
+
+\begin{description}
+\item[2 ]Open an existing FITS file with readonly or readwrite access
+ and move to a following extension, if one was specified as
+ part of the filename. (e.g., 'filename.fits+2' or
+ 'filename.fits[2]' will move to the 3rd HDU in the file).
+ Note that this routine differs from FTOPEN in that it does not
+ have the redundant blocksize argument.
+\end{description}
+
+\begin{verbatim}
+ FTNOPN(unit,filename,rwmode, > status)
+\end{verbatim}
+
+\begin{description}
+\item[3 ] Reopen a FITS file that was previously opened with
+ FTOPEN, FTNOPN, or FTINIT. The newunit number
+ may then be treated as a separate file, and one may
+ simultaneously read or write to 2 (or more) different extensions in
+ the same file. The FTOPEN and FTNOPN routines (above) automatically
+ detects cases where a previously opened file is being opened again,
+ and then internally call FTREOPEN, so programs should rarely
+ need to explicitly call this routine.
+\end{description}
+
+\begin{verbatim}
+ FTREOPEN(unit, > newunit, status)
+\end{verbatim}
+
+\begin{description}
+\item[4 ]Open and initialize a new empty FITS file
+\end{description}
+
+\begin{verbatim}
+ FTINIT(unit,filename,blocksize, > status)
+\end{verbatim}
+
+\begin{description}
+\item[5 ] Create a new FITS file, using a template file to define its
+ initial size and structure. The template may be another FITS HDU
+ or an ASCII template file. If the input template file name
+ is blank, then this routine behaves the same as FTINIT.
+ The currently supported format of the ASCII template file is described
+ under the fits\_parse\_template routine (in the general Utilities
+ section), but this may change slightly later releases of
+ CFITSIO.
+\end{description}
+
+\begin{verbatim}
+ FTTPLT(unit, filename, tplfilename, > status)
+\end{verbatim}
+
+\begin{description}
+\item[6 ]Flush internal buffers of data to the output FITS file
+ previously opened with ftopen or ftinit. The routine usually
+ never needs to be called, but doing so will ensure that
+ if the program subsequently aborts, then the FITS file will
+ have at least been closed properly.
+\end{description}
+
+\begin{verbatim}
+ FTFLUS(unit, > status)
+\end{verbatim}
+
+\begin{description}
+\item[7 ]Close a FITS file previously opened with ftopen or ftinit
+\end{description}
+
+\begin{verbatim}
+ FTCLOS(unit, > status)
+\end{verbatim}
+
+\begin{description}
+\item[8 ] Close and DELETE a FITS file previously opened with ftopen or ftinit.
+ This routine may be useful in cases where a FITS file is created, but
+ an error occurs which prevents the complete file from being written.
+\end{description}
+
+\begin{verbatim}
+ FTDELT(unit, > status)
+\end{verbatim}
+
+\begin{description}
+\item[9 ] Get the value of an unused I/O unit number which may then be used
+ as input to FTOPEN or FTINIT. This routine searches for the first
+ unused unit number in the range from with 99 down to 50. This
+ routine just keeps an internal list of the allocated unit numbers
+ and does not physically check that the Fortran unit is available (to be
+ compatible with the SPP version of FITSIO). Thus users must not
+ independently allocate any unit numbers in the range 50 - 99
+ if this routine is also to be used in the same program. This
+ routine is provided for convenience only, and it is not required
+ that the unit numbers used by FITSIO be allocated by this routine.
+\end{description}
+
+\begin{verbatim}
+ FTGIOU( > iounit, status)
+\end{verbatim}
+
+\begin{description}
+\item[10] Free (deallocate) an I/O unit number which was previously allocated
+ with FTGIOU. All previously allocated unit numbers may be
+ deallocated at once by calling FTFIOU with iounit = -1.
+\end{description}
+
+\begin{verbatim}
+ FTFIOU(iounit, > status)
+\end{verbatim}
+
+\begin{description}
+\item[11] Return the Fortran unit number that corresponds to the C fitsfile
+pointer value, or vice versa. These 2 C routines may be useful in
+mixed language programs where both C and Fortran subroutines need
+to access the same file. For example, if a FITS file is opened
+with unit 12 by a Fortran subroutine, then a C routine within the
+same program could get the fitfile pointer value to access the same file
+by calling 'fptr = CUnit2FITS(12)'. These routines return a value
+of zero if an error occurs.
+\end{description}
+
+\begin{verbatim}
+ int CFITS2Unit(fitsfile *ptr);
+ fitsfile* CUnit2FITS(int unit);
+\end{verbatim}
+
+
+\begin{description}
+\item[11] Parse the input filename and return the HDU number that would be
+moved to if the file were opened with FTNOPN. The returned HDU
+number begins with 1 for the primary array, so for example, if the
+input filename = `myfile.fits[2]' then hdunum = 3 will be returned.
+FITSIO does not open the file to check if the extension actually exists
+if an extension number is specified. If an extension *name* is included
+in the file name specification (e.g. `myfile.fits[EVENTS]' then this
+routine will have to open the FITS file and look for the position of
+the named extension, then close file again. This is not possible if
+the file is being read from the stdin stream, and an error will be
+returned in this case. If the filename does not specify an explicit
+extension (e.g. 'myfile.fits') then hdunum = -99 will be returned,
+which is functionally equivalent to hdunum = 1. This routine is mainly
+used for backward compatibility in the ftools software package and is
+not recommended for general use. It is generally better and more
+efficient to first open the FITS file with FTNOPN, then use FTGHDN to
+determine which HDU in the file has been opened, rather than calling
+ FTEXTN followed by a call to FTNOPN.
+\end{description}
+
+\begin{verbatim}
+ FTEXTN(filename, > nhdu, status)
+\end{verbatim}
+
+\begin{description}
+\item[12] Return the name of the opened FITS file.
+\end{description}
+
+\begin{verbatim}
+ FTFLNM(unit, > filename, status)
+\end{verbatim}
+
+\begin{description}
+\item[13] Return the I/O mode of the open FITS file (READONLY = 0, READWRITE = 1).
+\end{description}
+
+\begin{verbatim}
+ FTFLMD(unit, > iomode, status)
+\end{verbatim}
+
+\begin{description}
+\item[14] Return the file type of the opened FITS file (e.g. 'file://', 'ftp://',
+ etc.).
+\end{description}
+
+\begin{verbatim}
+ FTURLT(unit, > urltype, status)
+\end{verbatim}
+
+\begin{description}
+\item[15] Parse the input filename or URL into its component parts: the file
+type (file://, ftp://, http://, etc), the base input file name, the
+name of the output file that the input file is to be copied to prior
+to opening, the HDU or extension specification, the filtering
+specifier, the binning specifier, and the column specifier. Blank
+strings will be returned for any components that are not present
+in the input file name.
+\end{description}
+
+\begin{verbatim}
+ FTIURL(filename, > filetype, infile, outfile, extspec, filter,
+ binspec, colspec, status)
+\end{verbatim}
+
+\begin{description}
+\item[16] Parse the input file name and return the root file name. The root
+name includes the file type if specified, (e.g. 'ftp://' or 'http://')
+and the full path name, to the extent that it is specified in the input
+filename. It does not include the HDU name or number, or any filtering
+specifications.
+\end{description}
+
+\begin{verbatim}
+ FTRTNM(filename, > rootname, status)
+\end{verbatim}
+
+
+\begin{description}
+\item[16] Test if the input file or a compressed version of the file (with
+a .gz, .Z, .z, or .zip extension) exists on disk. The returned value of
+the 'exists' parameter will have 1 of the 4 following values:
+
+\begin{verbatim}
+ 2: the file does not exist, but a compressed version does exist
+ 1: the disk file does exist
+ 0: neither the file nor a compressed version of the file exist
+ -1: the input file name is not a disk file (could be a ftp, http,
+ smem, or mem file, or a file piped in on the STDIN stream)
+\end{verbatim}
+
+\end{description}
+
+\begin{verbatim}
+ FTEXIST(filename, > exists, status);
+\end{verbatim}
+
+\section{HDU-Level Operations \label{FTMAHD}}
+
+When a FITS file is first opened or created, the internal buffers in
+FITSIO automatically point to the first HDU in the file. The following
+routines may be used to move to another HDU in the file. Note that
+the HDU numbering convention used in FITSIO denotes the primary array
+as the first HDU, the first extension in a FITS file is the second HDU,
+and so on.
+
+
+\begin{description}
+\item[1 ] Move to a specified (absolute) HDU in the FITS file (nhdu = 1 for the
+ FITS primary array)
+\end{description}
+
+\begin{verbatim}
+ FTMAHD(unit,nhdu, > hdutype,status)
+\end{verbatim}
+
+\begin{description}
+\item[2 ]Move to a new (existing) HDU forward or backwards relative to the CHDU
+\end{description}
+
+\begin{verbatim}
+ FTMRHD(unit,nmove, > hdutype,status)
+\end{verbatim}
+
+\begin{description}
+\item[3 ] Move to the (first) HDU which has the specified extension type and
+ EXTNAME (or HDUNAME) and EXTVER keyword values. The hdutype parameter
+ may have
+ a value of IMAGE\_HDU, ASCII\_TBL, BINARY\_TBL, or ANY\_HDU where
+ ANY\_HDU means that only the extname and extver values will be
+ used to locate the correct extension. If the input value of
+ extver is 0 then the EXTVER keyword is ignored and the first HDU
+ with a matching EXTNAME (or HDUNAME) keyword will be found. If no
+ matching HDU is found in the file then the current HDU will remain
+ unchanged
+ and a status = BAD\_HDU\_NUM (301) will be returned.
+\end{description}
+
+\begin{verbatim}
+ FTMNHD(unit, hdutype, extname, extver, > status)
+\end{verbatim}
+
+\begin{description}
+\item[4 ]Get the number of the current HDU in the FITS file (primary array = 1)
+\end{description}
+
+\begin{verbatim}
+ FTGHDN(unit, > nhdu)
+\end{verbatim}
+
+\begin{description}
+\item[5 ] Return the type of the current HDU in the FITS file. The possible
+ values for hdutype are IMAGE\_HDU (0), ASCII\_TBL (1), or BINARY\_TBL (2).
+\end{description}
+
+\begin{verbatim}
+ FTGHDT(unit, > hdutype, status)
+\end{verbatim}
+
+\begin{description}
+\item[6 ] Return the total number of HDUs in the FITS file.
+ The CHDU remains unchanged.
+\end{description}
+
+\begin{verbatim}
+ FTTHDU(unit, > hdunum, status)
+\end{verbatim}
+
+\begin{description}
+\item[7 ]Create (append) a new empty HDU following the last extension that
+ has been previously accessed by the program. This will overwrite
+ any extensions in an existing FITS file if the program has not already
+ moved to that (or a later) extension using the FTMAHD or FTMRHD routines.
+ For example, if an existing FITS file contains a primary array and 5
+ extensions and a program (1) opens the FITS file, (2) moves to
+ extension 4, (3) moves back to the primary array, and (4) then calls
+ FTCRHD, then the new extension will be written following the 4th
+ extension, overwriting the existing 5th extension.
+\end{description}
+
+\begin{verbatim}
+ FTCRHD(unit, > status)
+\end{verbatim}
+
+\begin{description}
+\item[8 ] Insert a new IMAGE extension immediately following the CHDU.
+ Any following extensions will be shifted down to make room for
+ the new extension. If there are no other following extensions
+ then the new image extension will simply be appended to the
+ end of the file. The new extension will become the CHDU.
+\end{description}
+
+\begin{verbatim}
+ FTIIMG(unit,bitpix,naxis,naxes, > status)
+\end{verbatim}
+
+\begin{description}
+\item[9 ] Insert a new ASCII TABLE extension immediately following the CHDU.
+ Any following extensions will be shifted down to make room for
+ the new extension. If there are no other following extensions
+ then the new table extension will simply be appended to the
+ end of the file. The new extension will become the CHDU.
+\end{description}
+
+\begin{verbatim}
+ FTITAB(unit,rowlen,nrows,tfields,ttype,tbcol,tform,tunit,extname, >
+ status)
+\end{verbatim}
+
+\begin{description}
+\item[10] Insert a new binary table extension immediately following the CHDU.
+ Any following extensions will be shifted down to make room for
+ the new extension. If there are no other following extensions
+ then the new bintable extension will simply be appended to the
+ end of the file. The new extension will become the CHDU.
+\end{description}
+
+\begin{verbatim}
+ FTIBIN(unit,nrows,tfields,ttype,tform,tunit,extname,varidat > status)
+\end{verbatim}
+
+\begin{description}
+\item[11] Resize an image by modifing the size, dimensions, and/or datatype of the
+ current primary array or image extension. If the new image, as specified
+ by the input arguments, is larger than the current existing image
+ in the FITS file then zero fill data will be inserted at the end
+ of the current image and any following extensions will be moved
+ further back in the file. Similarly, if the new image is
+ smaller than the current image then any following extensions
+ will be shifted up towards the beginning of the FITS file
+ and the image data will be truncated to the new size.
+ This routine rewrites the BITPIX, NAXIS, and NAXISn keywords
+ with the appropriate values for new image.
+\end{description}
+
+\begin{verbatim}
+ FTRSIM(unit,bitpix,naxis,naxes,status)
+\end{verbatim}
+
+\begin{description}
+\item[12] Delete the CHDU in the FITS file. Any following HDUs will be shifted
+ forward in the file, to fill in the gap created by the deleted
+ HDU. In the case of deleting the primary array (the first HDU in
+ the file) then the current primary array will be replace by a null
+ primary array containing the minimum set of required keywords and
+ no data. If there are more extensions in the file following the
+ one that is deleted, then the the CHDU will be redefined to point
+ to the following extension. If there are no following extensions
+ then the CHDU will be redefined to point to the previous HDU. The
+ output HDUTYPE parameter indicates the type of the new CHDU after
+ the previous CHDU has been deleted.
+\end{description}
+
+\begin{verbatim}
+ FTDHDU(unit, > hdutype,status)
+\end{verbatim}
+
+\begin{description}
+\item[13] Copy all or part of the input FITS file and append it
+ to the end of the output FITS file. If 'previous' is
+ true (not 0), then any HDUs preceding the current HDU in the input file
+ will be copied to the output file. Similarly, 'current' and 'following'
+ determine whether the current HDU, and/or any following HDUs in the
+ input file will be copied to the output file. If all 3 parameters are
+ true, then the entire input file will be copied. On return, the current
+ HDU in the input file will be unchanged, and the last copied HDU will be the
+ current HDU in the output file.
+\end{description}
+
+\begin{verbatim}
+ FTCPFL(iunit, ounit, previous, current, following, > status)
+\end{verbatim}
+
+\begin{description}
+\item[14] Copy the entire CHDU from the FITS file associated with IUNIT to the CHDU
+ of the FITS file associated with OUNIT. The output HDU must be empty and
+ not already contain any keywords. Space will be reserved for MOREKEYS
+ additional keywords in the output header if there is not already enough
+ space.
+\end{description}
+
+\begin{verbatim}
+ FTCOPY(iunit,ounit,morekeys, > status)
+\end{verbatim}
+
+\begin{description}
+\item[15] Copy the header (and not the data) from the CHDU associated with inunit
+ to the CHDU associated with outunit. If the current output HDU
+ is not completely empty, then the CHDU will be closed and a new
+ HDU will be appended to the output file. This routine will automatically
+ transform the necessary keywords when copying a primary array to
+ and image extension, or an image extension to a primary array.
+ An empty output data unit will be created (all values = 0).
+\end{description}
+
+\begin{verbatim}
+ FTCPHD(inunit, outunit, > status)
+\end{verbatim}
+
+\begin{description}
+\item[16] Copy just the data from the CHDU associated with IUNIT
+ to the CHDU associated with OUNIT. This will overwrite
+ any data previously in the OUNIT CHDU. This low level routine is used
+ by FTCOPY, but it may also be useful in certain application programs
+ which want to copy the data from one FITS file to another but also
+ want to modify the header keywords in the process. all the required
+ header keywords must be written to the OUNIT CHDU before calling
+ this routine
+\end{description}
+
+\begin{verbatim}
+ FTCPDT(iunit,ounit, > status)
+\end{verbatim}
+
+
+\section{Define or Redefine the structure of the CHDU \label{FTRDEF}}
+
+It should rarely be necessary to call the subroutines in this section.
+FITSIO internally calls these routines whenever necessary, so any calls
+to these routines by application programs will likely be redundant.
+
+
+\begin{description}
+\item[1 ] This routine forces FITSIO to scan the current header keywords that
+ define the structure of the HDU (such as the NAXISn, PCOUNT and GCOUNT
+ keywords) so that it can initialize the internal buffers that describe
+ the HDU structure. This routine may be used instead of the more
+ complicated calls to ftpdef, ftadef or ftbdef. This routine is
+ also very useful for reinitializing the structure of an HDU,
+ if the number of rows in a table, as specified by the NAXIS2 keyword,
+ has been modified from its initial value.
+\end{description}
+
+\begin{verbatim}
+ FTRDEF(unit, > status) (DEPRECATED)
+\end{verbatim}
+
+\begin{description}
+\item[2 ]Define the structure of the primary array or IMAGE extension. When
+ writing GROUPed FITS files that by convention set the NAXIS1 keyword
+ equal to 0, ftpdef must be called with naxes(1) = 1, NOT 0, otherwise
+ FITSIO will report an error status=308 when trying to write data
+ to a group. Note: it is usually simpler to call FTRDEF rather
+ than this routine.
+\end{description}
+
+\begin{verbatim}
+ FTPDEF(unit,bitpix,naxis,naxes,pcount,gcount, > status) (DEPRECATED)
+\end{verbatim}
+
+\begin{description}
+\item[3 ] Define the structure of an ASCII table (TABLE) extension. Note: it
+ is usually simpler to call FTRDEF rather than this routine.
+\end{description}
+
+\begin{verbatim}
+ FTADEF(unit,rowlen,tfields,tbcol,tform,nrows > status) (DEPRECATED)
+\end{verbatim}
+
+\begin{description}
+\item[4 ] Define the structure of a binary table (BINTABLE) extension. Note: it
+ is usually simpler to call FTRDEF rather than this routine.
+\end{description}
+
+\begin{verbatim}
+ FTBDEF(unit,tfields,tform,varidat,nrows > status) (DEPRECATED)
+\end{verbatim}
+
+\begin{description}
+\item[5 ] Define the size of the Current Data Unit, overriding the length
+ of the data unit as previously defined by ftpdef, ftadef, or ftbdef.
+ This is useful if one does not know the total size of the data unit until
+ after the data have been written. The size (in bytes) of an ASCII or
+ Binary table is given by NAXIS1 * NAXIS2. (Note that to determine the
+ value of NAXIS1 it is often more convenient to read the value of the
+ NAXIS1 keyword from the output file, rather than computing the row
+ length directly from all the TFORM keyword values). Note: it
+ is usually simpler to call FTRDEF rather than this routine.
+\end{description}
+
+\begin{verbatim}
+ FTDDEF(unit,bytlen, > status) (DEPRECATED)
+\end{verbatim}
+
+\begin{description}
+\item[6 ] Define the zero indexed byte offset of the 'heap' measured from
+ the start of the binary table data. By default the heap is assumed
+ to start immediately following the regular table data, i.e., at
+ location NAXIS1 x NAXIS2. This routine is only relevant for
+ binary tables which contain variable length array columns (with
+ TFORMn = 'Pt'). This subroutine also automatically writes
+ the value of theap to a keyword in the extension header. This
+ subroutine must be called after the required keywords have been
+ written (with ftphbn) and after the table structure has been defined
+ (with ftbdef) but before any data is written to the table.
+\end{description}
+
+\begin{verbatim}
+ FTPTHP(unit,theap, > status)
+\end{verbatim}
+
+
+\section{FITS Header I/O Subroutines}
+
+
+\subsection{Header Space and Position Routines \label{FTHDEF}}
+
+
+\begin{description}
+\item[1 ] Reserve space in the CHU for MOREKEYS more header keywords.
+ This subroutine may be called to reserve space for keywords which are
+ to be written at a later time, after the data unit or subsequent
+ extensions have been written to the FITS file. If this subroutine is
+ not explicitly called, then the initial size of the FITS header will be
+ limited to the space available at the time that the first data is written
+ to the associated data unit. FITSIO has the ability to dynamically
+ add more space to the header if needed, however it is more efficient
+ to preallocate the required space if the size is known in advance.
+\end{description}
+
+\begin{verbatim}
+ FTHDEF(unit,morekeys, > status)
+\end{verbatim}
+
+\begin{description}
+\item[2 ] Return the number of existing keywords in the CHU (NOT including the
+ END keyword which is not considered a real keyword) and the remaining
+ space available to write additional keywords in the CHU. (returns
+ KEYSADD = -1 if the header has not yet been closed).
+ Note that FITSIO will attempt to dynamically add space for more
+ keywords if required when appending new keywords to a header.
+\end{description}
+
+\begin{verbatim}
+ FTGHSP(iunit, > keysexist,keysadd,status)
+\end{verbatim}
+
+\begin{description}
+\item[3 ] Return the number of keywords in the header and the current position
+ in the header. This returns the number of the keyword record that
+ will be read next (or one greater than the position of the last keyword
+ that was read or written). A value of 1 is returned if the pointer is
+ positioned at the beginning of the header.
+\end{description}
+
+\begin{verbatim}
+ FTGHPS(iunit, > keysexist,key_no,status)
+\end{verbatim}
+
+\subsection{Read or Write Standard Header Routines \label{FTPHPR}}
+
+These subroutines provide a simple method of reading or writing most of
+the keyword values that are normally required in a FITS files. These
+subroutines are provided for convenience only and are not required to
+be used. If preferred, users may call the lower-level subroutines
+described in the previous section to individually read or write the
+required keywords. Note that in most cases, the required keywords such
+as NAXIS, TFIELD, TTYPEn, etc, which define the structure of the HDU
+must be written to the header before any data can be written to the
+image or table.
+
+
+\begin{description}
+\item[1 ] Put the primary header or IMAGE extension keywords into the CHU.
+There are 2 available routines: The simpler FTPHPS routine is
+equivalent to calling ftphpr with the default values of SIMPLE = true,
+pcount = 0, gcount = 1, and EXTEND = true. PCOUNT, GCOUNT and EXTEND
+keywords are not required in the primary header and are only written if
+pcount is not equal to zero, gcount is not equal to zero or one, and if
+extend is TRUE, respectively. When writing to an IMAGE extension, the
+SIMPLE and EXTEND parameters are ignored.
+\end{description}
+
+\begin{verbatim}
+ FTPHPS(unit,bitpix,naxis,naxes, > status)
+
+ FTPHPR(unit,simple,bitpix,naxis,naxes,pcount,gcount,extend, > status)
+\end{verbatim}
+
+\begin{description}
+\item[2 ] Get primary header or IMAGE extension keywords from the CHU. When
+ reading from an IMAGE extension the SIMPLE and EXTEND parameters are
+ ignored.
+\end{description}
+
+\begin{verbatim}
+ FTGHPR(unit,maxdim, > simple,bitpix,naxis,naxes,pcount,gcount,extend,
+ status)
+\end{verbatim}
+
+\begin{description}
+\item[3 ] Put the ASCII table header keywords into the CHU. The optional
+TUNITn and EXTNAME keywords are written only if the input string
+values are not blank.
+\end{description}
+
+\begin{verbatim}
+ FTPHTB(unit,rowlen,nrows,tfields,ttype,tbcol,tform,tunit,extname, >
+ status)
+\end{verbatim}
+
+\begin{description}
+\item[4 ] Get the ASCII table header keywords from the CHU
+\end{description}
+
+\begin{verbatim}
+ FTGHTB(unit,maxdim, > rowlen,nrows,tfields,ttype,tbcol,tform,tunit,
+ extname,status)
+\end{verbatim}
+
+\begin{description}
+\item[5 ]Put the binary table header keywords into the CHU. The optional
+ TUNITn and EXTNAME keywords are written only if the input string
+ values are not blank. The pcount parameter, which specifies the
+ size of the variable length array heap, should initially = 0;
+ FITSIO will automatically update the PCOUNT keyword value if any
+ variable length array data is written to the heap. The TFORM keyword
+ value for variable length vector columns should have the form 'Pt(len)'
+ or '1Pt(len)' where `t' is the data type code letter (A,I,J,E,D, etc.)
+ and `len' is an integer specifying the maximum length of the vectors
+ in that column (len must be greater than or equal to the longest
+ vector in the column). If `len' is not specified when the table is
+ created (e.g., the input TFORMn value is just '1Pt') then FITSIO will
+ scan the column when the table is first closed and will append the
+ maximum length to the TFORM keyword value. Note that if the table
+ is subsequently modified to increase the maximum length of the vectors
+ then the modifying program is responsible for also updating the TFORM
+ keyword value.
+\end{description}
+
+
+\begin{verbatim}
+ FTPHBN(unit,nrows,tfields,ttype,tform,tunit,extname,varidat, > status)
+\end{verbatim}
+
+\begin{description}
+\item[6 ]Get the binary table header keywords from the CHU
+\end{description}
+
+\begin{verbatim}
+ FTGHBN(unit,maxdim, > nrows,tfields,ttype,tform,tunit,extname,varidat,
+ status)
+\end{verbatim}
+
+\subsection{Write Keyword Subroutines \label{FTPREC}}
+
+
+\begin{description}
+\item[1 ]Put (append) an 80-character record into the CHU.
+\end{description}
+
+\begin{verbatim}
+ FTPREC(unit,card, > status)
+\end{verbatim}
+
+\begin{description}
+\item[2 ] Put (append) a COMMENT keyword into the CHU. Multiple COMMENT keywords
+ will be written if the input comment string is longer than 72 characters.
+\end{description}
+
+\begin{verbatim}
+ FTPCOM(unit,comment, > status)
+\end{verbatim}
+
+\begin{description}
+\item[3 ]Put (append) a HISTORY keyword into the CHU. Multiple HISTORY keywords
+ will be written if the input history string is longer than 72 characters.
+\end{description}
+
+\begin{verbatim}
+ FTPHIS(unit,history, > status)
+\end{verbatim}
+
+\begin{description}
+\item[4 ] Put (append) the DATE keyword into the CHU. The keyword value will contain
+ the current system date as a character string in 'dd/mm/yy' format. If
+ a DATE keyword already exists in the header, then this subroutine will
+ simply update the keyword value in-place with the current date.
+\end{description}
+
+\begin{verbatim}
+ FTPDAT(unit, > status)
+\end{verbatim}
+
+\begin{description}
+\item[5 ] Put (append) a new keyword of the appropriate datatype into the CHU.
+ Note that FTPKYS will only write string values up to 68 characters in
+ length; longer strings will be truncated. The FTPKLS routine can be
+ used to write longer strings, using a non-standard FITS convention.
+ The E and D versions of this routine have the added feature that
+ if the 'decimals' parameter is negative, then the 'G' display
+ format rather then the 'E' format will be used when constructing
+ the keyword value, taking the absolute value of 'decimals' for the
+ precision. This will suppress trailing zeros, and will use a
+ fixed format rather than an exponential format,
+ depending on the magnitude of the value.
+\end{description}
+
+\begin{verbatim}
+ FTPKY[JLS](unit,keyword,keyval,comment, > status)
+ FTPKY[EDFG](unit,keyword,keyval,decimals,comment, > status)
+\end{verbatim}
+
+\begin{description}
+\item[6 ] Put (append) a string valued keyword into the CHU which may be longer
+ than 68 characters in length. This uses the Long String Keyword
+ convention that is described in the "Usage Guidelines and Suggestions"
+ section of this document. Since this uses a non-standard FITS
+ convention to encode the long keyword string, programs which use
+ this routine should also call the FTPLSW routine to add some COMMENT
+ keywords to warn users of the FITS file that this convention is
+ being used. FTPLSW also writes a keyword called LONGSTRN to record
+ the version of the longstring convention that has been used, in case
+ a new convention is adopted at some point in the future. If the
+ LONGSTRN keyword is already present in the header, then FTPLSW will
+ simply return and will not write duplicate keywords.
+\end{description}
+
+\begin{verbatim}
+ FTPKLS(unit,keyword,keyval,comment, > status)
+ FTPLSW(unit, > status)
+\end{verbatim}
+
+\begin{description}
+\item[7 ] Put (append) a new keyword with an undefined, or null, value into the CHU.
+ The value string of the keyword is left blank in this case.
+\end{description}
+
+\begin{verbatim}
+ FTPKYU(unit,keyword,comment, > status)
+\end{verbatim}
+
+\begin{description}
+\item[8 ] Put (append) a numbered sequence of keywords into the CHU. One may
+ append the same comment to every keyword (and eliminate the need
+ to have an array of identical comment strings, one for each keyword) by
+ including the ampersand character as the last non-blank character in the
+ (first) COMMENTS string parameter. This same string
+ will then be used for the comment field in all the keywords. (Note
+ that the SPP version of these routines only supports a single comment
+ string).
+\end{description}
+
+\begin{verbatim}
+ FTPKN[JLS](unit,keyroot,startno,no_keys,keyvals,comments, > status)
+ FTPKN[EDFG](unit,keyroot,startno,no_keys,keyvals,decimals,comments, >
+ status)
+\end{verbatim}
+
+\begin{description}
+\item[9 ]Copy an indexed keyword from one HDU to another, modifying
+ the index number of the keyword name in the process. For example,
+ this routine could read the TLMIN3 keyword from the input HDU
+ (by giving keyroot = "TLMIN" and innum = 3) and write it to the
+ output HDU with the keyword name TLMIN4 (by setting outnum = 4).
+ If the input keyword does not exist, then this routine simply
+ returns without indicating an error.
+\end{description}
+
+\begin{verbatim}
+ FTCPKYinunit, outunit, innum, outnum, keyroot, > status)
+\end{verbatim}
+
+\begin{description}
+\item[10] Put (append) a 'triple precision' keyword into the CHU in F28.16 format.
+ The floating point keyword value is constructed by concatenating the
+ input integer value with the input double precision fraction value
+ (which must have a value between 0.0 and 1.0). The FTGKYT routine should
+ be used to read this keyword value, because the other keyword reading
+ subroutines will not preserve the full precision of the value.
+\end{description}
+
+\begin{verbatim}
+ FTPKYT(unit,keyword,intval,dblval,comment, > status)
+\end{verbatim}
+
+\begin{description}
+\item[11] Write keywords to the CHDU that are defined in an ASCII template file.
+ The format of the template file is described under the ftgthd
+ routine below.
+\end{description}
+
+\begin{verbatim}
+ FTPKTP(unit, filename, > status)
+\end{verbatim}
+
+\begin{description}
+\item[12] Append the physical units string to an existing keyword. This
+ routine uses a local convention, shown in the following example,
+ in which the keyword units are enclosed in square brackets in the
+ beginning of the keyword comment field.
+\end{description}
+
+
+\begin{verbatim}
+ VELOCITY= 12.3 / [km/s] orbital speed
+
+ FTPUNT(unit,keyword,units, > status)
+\end{verbatim}
+
+\subsection{Insert Keyword Subroutines \label{FTIREC}}
+
+
+\begin{description}
+\item[1 ] Insert a new keyword record into the CHU at the specified position
+ (i.e., immediately preceding the (keyno)th keyword in the header.)
+ This 'insert record' subroutine is somewhat less efficient
+ then the 'append record' subroutine (FTPREC) described above because
+ the remaining keywords in the header have to be shifted down one slot.
+\end{description}
+
+\begin{verbatim}
+ FTIREC(unit,key_no,card, > status)
+\end{verbatim}
+
+\begin{description}
+\item[2 ] Insert a new keyword into the CHU. The new keyword is inserted
+ immediately following the last keyword that has been read from the header.
+ The FTIKLS subroutine works the same as the FTIKYS subroutine, except
+ it also supports long string values greater than 68 characters in length.
+ These 'insert keyword' subroutines are somewhat less efficient then
+ the 'append keyword' subroutines described above because the remaining
+ keywords in the header have to be shifted down one slot.
+\end{description}
+
+\begin{verbatim}
+ FTIKEY(unit, card, > status)
+ FTIKY[JLS](unit,keyword,keyval,comment, > status)
+ FTIKLS(unit,keyword,keyval,comment, > status)
+ FTIKY[EDFG](unit,keyword,keyval,decimals,comment, > status)
+\end{verbatim}
+
+\begin{description}
+\item[3 ] Insert a new keyword with an undefined, or null, value into the CHU.
+ The value string of the keyword is left blank in this case.
+\end{description}
+
+\begin{verbatim}
+ FTIKYU(unit,keyword,comment, > status)
+\end{verbatim}
+
+\subsection{Read Keyword Subroutines \label{FTGREC}}
+
+These routines return the value of the specified keyword(s). Wild card
+characters (*, ?, or \#) may be used when specifying the name of the keyword
+to be read: a '?' will match any single character at that position in the
+keyword name and a '*' will match any length (including zero) string of
+characters. The '\#' character will match any consecutive string of
+decimal digits (0 - 9). Note that when a wild card is used in the input
+keyword name, the routine will only search for a match from the current
+header position to the end of the header. It will not resume the search
+from the top of the header back to the original header position as is done
+when no wildcards are included in the keyword name. If the desired
+keyword string is 8-characters long (the maximum length of a keyword
+name) then a '*' may be appended as the ninth character of the input
+name to force the keyword search to stop at the end of the header
+(e.g., 'COMMENT *' will search for the next COMMENT keyword). The
+ffgrec routine may be used to set the starting position when doing
+wild card searches.
+
+
+\begin{description}
+\item[1 ]Get the nth 80-character header record from the CHU. The first keyword
+ in the header is at key\_no = 1; if key\_no = 0 then this subroutine
+ simple moves the internal pointer to the beginning of the header
+ so that subsequent keyword operations will start at the top of
+ the header; it also returns a blank card value in this case.
+\end{description}
+
+\begin{verbatim}
+ FTGREC(unit,key_no, > card,status)
+\end{verbatim}
+
+\begin{description}
+\item[2 ] Get the name, value (as a string), and comment of the nth keyword in CHU.
+ This routine also checks that the returned keyword name (KEYWORD) contains
+ only legal ASCII characters. Call FTGREC and FTPSVC to bypass this error
+ check.
+\end{description}
+
+\begin{verbatim}
+ FTGKYN(unit,key_no, > keyword,value,comment,status)
+\end{verbatim}
+
+\begin{description}
+\item[3 ] Get the 80-character header record for the named keyword
+\end{description}
+
+\begin{verbatim}
+ FTGCRD(unit,keyword, > card,status)
+\end{verbatim}
+
+\begin{description}
+\item[4 ] Get the next keyword whose name matches one of the strings in
+ 'inclist' but does not match any of the strings in 'exclist'.
+ The strings in inclist and exclist may contain wild card characters
+ (*, ?, and \#) as described at the beginning of this section.
+ This routine searches from the current header position to the
+ end of the header, only, and does not continue the search from
+ the top of the header back to the original position. The current
+ header position may be reset with the ftgrec routine. Note
+ that nexc may be set = 0 if there are no keywords to be excluded.
+ This routine returns status = 202 if a matching
+ keyword is not found.
+\end{description}
+
+\begin{verbatim}
+ FTGNXK(unit,inclist,ninc,exclist,nexc, > card,status)
+\end{verbatim}
+
+\begin{description}
+\item[5 ] Get the literal keyword value as a character string. Regardless
+ of the datatype of the keyword, this routine simply returns the
+ string of characters in the value field of the keyword along with
+ the comment field.
+\end{description}
+
+\begin{verbatim}
+ FTGKEY(unit,keyword, > value,comment,status)
+\end{verbatim}
+
+\begin{description}
+\item[6 ] Get a keyword value (with the appropriate datatype) and comment from
+ the CHU
+\end{description}
+
+\begin{verbatim}
+ FTGKY[EDJLS](unit,keyword, > keyval,comment,status)
+\end{verbatim}
+
+\begin{description}
+\item[7 ] Get a sequence of numbered keyword values. These
+ routines do not support wild card characters in the root name.
+\end{description}
+
+\begin{verbatim}
+ FTGKN[EDJLS](unit,keyroot,startno,max_keys, > keyvals,nfound,status)
+\end{verbatim}
+
+\begin{description}
+\item[8 ] Get the value of a floating point keyword, returning the integer and
+ fractional parts of the value in separate subroutine arguments.
+ This subroutine may be used to read any keyword but is especially
+ useful for reading the 'triple precision' keywords written by FTPKYT.
+\end{description}
+
+\begin{verbatim}
+ FTGKYT(unit,keyword, > intval,dblval,comment,status)
+\end{verbatim}
+
+\begin{description}
+\item[9 ] Get the physical units string in an existing keyword. This
+ routine uses a local convention, shown in the following example,
+ in which the keyword units are
+ enclosed in square brackets in the beginning of the keyword comment
+ field. A blank string is returned if no units are defined
+ for the keyword.
+\end{description}
+
+\begin{verbatim}
+ VELOCITY= 12.3 / [km/s] orbital speed
+
+ FTGUNT(unit,keyword, > units,status)
+\end{verbatim}
+
+\subsection{Modify Keyword Subroutines \label{FTMREC}}
+
+Wild card characters, as described in the Read Keyword section, above,
+may be used when specifying the name of the keyword to be modified.
+
+
+\begin{description}
+\item[1 ] Modify (overwrite) the nth 80-character header record in the CHU
+\end{description}
+
+\begin{verbatim}
+ FTMREC(unit,key_no,card, > status)
+\end{verbatim}
+
+\begin{description}
+\item[2 ] Modify (overwrite) the 80-character header record for the named keyword
+ in the CHU. This can be used to overwrite the name of the keyword as
+ well as its value and comment fields.
+\end{description}
+
+\begin{verbatim}
+ FTMCRD(unit,keyword,card, > status)
+\end{verbatim}
+
+\begin{description}
+\item[3 ] Modify (overwrite) the name of an existing keyword in the CHU
+ preserving the current value and comment fields.
+\end{description}
+
+\begin{verbatim}
+ FTMNAM(unit,oldkey,keyword, > status)
+\end{verbatim}
+
+\begin{description}
+\item[4 ] Modify (overwrite) the comment field of an existing keyword in the CHU
+\end{description}
+
+\begin{verbatim}
+ FTMCOM(unit,keyword,comment, > status)
+\end{verbatim}
+
+\begin{description}
+\item[5 ] Modify the value and comment fields of an existing keyword in the CHU.
+ The FTMKLS subroutine works the same as the FTMKYS subroutine, except
+ it also supports long string values greater than 68 characters in length.
+ Optionally, one may modify only the value field and leave the comment
+ field unchanged by setting the input COMMENT parameter equal to
+ the ampersand character (\&).
+ The E and D versions of this routine have the added feature that
+ if the 'decimals' parameter is negative, then the 'G' display
+ format rather then the 'E' format will be used when constructing
+ the keyword value, taking the absolute value of 'decimals' for the
+ precision. This will suppress trailing zeros, and will use a
+ fixed format rather than an exponential format,
+ depending on the magnitude of the value.
+\end{description}
+
+\begin{verbatim}
+ FTMKY[JLS](unit,keyword,keyval,comment, > status)
+ FTMKLS(unit,keyword,keyval,comment, > status)
+ FTMKY[EDFG](unit,keyword,keyval,decimals,comment, > status)
+\end{verbatim}
+
+\begin{description}
+\item[6 ] Modify the value of an existing keyword to be undefined, or null.
+ The value string of the keyword is set to blank.
+ Optionally, one may leave the comment field unchanged by setting the
+ input COMMENT parameter equal to the ampersand character (\&).
+\end{description}
+
+\begin{verbatim}
+ FTMKYU(unit,keyword,comment, > status)
+\end{verbatim}
+
+\subsection{Update Keyword Subroutines \label{FTUCRD}}
+
+
+\begin{description}
+\item[1 ] Update an 80-character record in the CHU. If the specified keyword
+ already exists then that header record will be replaced with
+ the input CARD string. If it does not exist then the new record will
+ be added to the header.
+ The FTUKLS subroutine works the same as the FTUKYS subroutine, except
+ it also supports long string values greater than 68 characters in length.
+\end{description}
+
+\begin{verbatim}
+ FTUCRD(unit,keyword,card, > status)
+\end{verbatim}
+
+\begin{description}
+\item[2 ] Update the value and comment fields of a keyword in the CHU.
+ The specified keyword is modified if it already exists (by calling
+ FTMKYx) otherwise a new keyword is created by calling FTPKYx.
+ The E and D versions of this routine have the added feature that
+ if the 'decimals' parameter is negative, then the 'G' display
+ format rather then the 'E' format will be used when constructing
+ the keyword value, taking the absolute value of 'decimals' for the
+ precision. This will suppress trailing zeros, and will use a
+ fixed format rather than an exponential format,
+ depending on the magnitude of the value.
+\end{description}
+
+\begin{verbatim}
+ FTUKY[JLS](unit,keyword,keyval,comment, > status)
+ FTUKLS(unit,keyword,keyval,comment, > status)
+ FTUKY[EDFG](unit,keyword,keyval,decimals,comment, > status)
+\end{verbatim}
+
+\begin{description}
+\item[3 ] Update the value of an existing keyword to be undefined, or null,
+ or insert a new undefined-value keyword if it doesn't already exist.
+ The value string of the keyword is left blank in this case.
+\end{description}
+
+\begin{verbatim}
+ FTUKYU(unit,keyword,comment, > status)
+\end{verbatim}
+
+\subsection{Delete Keyword Subroutines \label{FTDREC}}
+
+
+\begin{description}
+\item[1 ] Delete an existing keyword record. The space previously occupied by
+ the keyword is reclaimed by moving all the following header records up
+ one row in the header. The first routine deletes a keyword at a
+ specified position in the header (the first keyword is at position 1),
+ whereas the second routine deletes a specifically named keyword.
+ Wild card characters, as described in the Read Keyword section, above,
+ may be used when specifying the name of the keyword to be deleted
+ (be careful!).
+\end{description}
+
+\begin{verbatim}
+ FTDREC(unit,key_no, > status)
+ FTDKEY(unit,keyword, > status)
+\end{verbatim}
+
+
+\section{Data Scaling and Undefined Pixel Parameters \label{FTPSCL}}
+
+These subroutines define or modify the internal parameters used by
+FITSIO to either scale the data or to represent undefined pixels.
+Generally FITSIO will scale the data according to the values of the BSCALE
+and BZERO (or TSCALn and TZEROn) keywords, however these subroutines
+may be used to override the keyword values. This may be useful when
+one wants to read or write the raw unscaled values in the FITS file.
+Similarly, FITSIO generally uses the value of the BLANK or TNULLn
+keyword to signify an undefined pixel, but these routines may be used
+to override this value. These subroutines do not create or modify the
+corresponding header keyword values.
+
+
+\begin{description}
+\item[1 ] Reset the scaling factors in the primary array or image extension; does
+ not change the BSCALE and BZERO keyword values and only affects the
+ automatic scaling performed when the data elements are written/read
+ to/from the FITS file. When reading from a FITS file the returned
+ data value = (the value given in the FITS array) * BSCALE + BZERO.
+ The inverse formula is used when writing data values to the FITS
+ file. (NOTE: BSCALE and BZERO must be declared as Double Precision
+ variables).
+\end{description}
+
+\begin{verbatim}
+ FTPSCL(unit,bscale,bzero, > status)
+\end{verbatim}
+
+\begin{description}
+\item[2 ] Reset the scaling parameters for a table column; does not change
+ the TSCALn or TZEROn keyword values and only affects the automatic
+ scaling performed when the data elements are written/read to/from
+ the FITS file. When reading from a FITS file the returned data
+ value = (the value given in the FITS array) * TSCAL + TZERO. The
+ inverse formula is used when writing data values to the FITS file.
+ (NOTE: TSCAL and TZERO must be declared as Double Precision
+ variables).
+\end{description}
+
+\begin{verbatim}
+ FTTSCL(unit,colnum,tscal,tzero, > status)
+\end{verbatim}
+
+\begin{description}
+\item[3 ] Define the integer value to be used to signify undefined pixels in the
+ primary array or image extension. This is only used if BITPIX = 8, 16,
+ or 32. This does not create or change the value of the BLANK keyword in
+ the header.
+\end{description}
+
+\begin{verbatim}
+ FTPNUL(unit,blank, > status)
+\end{verbatim}
+
+\begin{description}
+\item[4 ] Define the string to be used to signify undefined pixels in
+ a column in an ASCII table. This does not create or change the value
+ of the TNULLn keyword.
+\end{description}
+
+\begin{verbatim}
+ FTSNUL(unit,colnum,snull > status)
+\end{verbatim}
+
+\begin{description}
+\item[5 ] Define the value to be used to signify undefined pixels in
+ an integer column in a binary table (where TFORMn = 'B', 'I', or 'J').
+ This does not create or change the value of the TNULLn keyword.
+\end{description}
+
+\begin{verbatim}
+ FTTNUL(unit,colnum,tnull > status)
+\end{verbatim}
+
+
+\section{FITS Primary Array or IMAGE Extension I/O Subroutines \label{FTPPR}}
+
+ These subroutines put or get data values in the primary data array
+(i.e., the first HDU in the FITS file) or an IMAGE extension. The
+data array is represented as a single one-dimensional array of
+pixels regardless of the actual dimensionality of the array, and the
+FPIXEL parameter gives the position within this 1-D array of the first
+pixel to read or write. Automatic data type conversion is performed
+for numeric data (except for complex data types) if the data type of
+the primary array (defined by the BITPIX keyword) differs from the data
+type of the array in the calling subroutine. The data values are also
+scaled by the BSCALE and BZERO header values as they are being written
+or read from the FITS array. The ftpscl subroutine MUST be
+called to define the scaling parameters when writing data to the FITS
+array or to override the default scaling value given in the header when
+reading the FITS array.
+
+ Two sets of subroutines are provided to read the data array which
+differ in the way undefined pixels are handled. The first set of
+routines (FTGPVx) simply return an array of data elements in which
+undefined pixels are set equal to a value specified by the user in the
+'nullval' parameter. An additional feature of these subroutines is
+that if the user sets nullval = 0, then no checks for undefined pixels
+will be performed, thus increasing the speed of the program. The
+second set of routines (FTGPFx) returns the data element array and, in
+addition, a logical array which defines whether the corresponding data
+pixel is undefined. The latter set of subroutines may be more
+convenient to use in some circumstances, however, it requires an
+additional array of logical values which can be unwieldy when working
+with large data arrays. Also for programmer convenience, sets of
+subroutines to directly read or write 2 and 3 dimensional arrays have
+been provided, as well as a set of subroutines to read or write any
+contiguous rectangular subset of pixels within the n-dimensional array.
+
+
+\begin{description}
+\item[1 ] Get the data type of the image (= BITPIX value). Possible returned
+ values are: 8, 16, 32, -32, or -64 corresponding to unsigned byte,
+ signed 2-byte integer, signed 4-byte integer, real, and double.
+
+ The second subroutine is similar to FTGIDT, except that if the image
+ pixel values are scaled, with non-default values for the BZERO and
+ BSCALE keywords, then this routine will return the 'equivalent'
+ data type that is needed to store the scaled values. For example,
+ if BITPIX = 16 and BSCALE = 0.1 then the equivalent data type is
+ floating point, and -32 will be returned. There are 2 special cases:
+ if the image contains unsigned 2-byte integer values, with BITPIX =
+ 16, BSCALE = 1, and BZERO = 32768, then this routine will return
+ a non-standard value of 20 for the bitpix value. Similarly if the
+ image contains unsigned 4-byte integers, then bitpix will
+ be returned with a value of 40.
+\end{description}
+
+
+\begin{verbatim}
+ FTGIDT(unit, > bitpix,status)
+ FTGIET(unit, > bitpix,status)
+\end{verbatim}
+
+\begin{description}
+\item[2 ] Get the dimension (number of axes = NAXIS) of the image
+\end{description}
+
+\begin{verbatim}
+ FTGIDM(unit, > naxis,status)
+\end{verbatim}
+
+\begin{description}
+\item[3 ] Get the size of all the dimensions of the image
+\end{description}
+
+\begin{verbatim}
+ FTGISZ(unit, maxdim, > naxes,status)
+\end{verbatim}
+
+\begin{description}
+\item[4 ] Get the parameters that define the type and size of the image. This
+ routine simply combines calls to the above 3 routines.
+\end{description}
+
+\begin{verbatim}
+ FTGIPR(unit, maxdim, > bitpix, naxis, naxes, int *status)
+\end{verbatim}
+
+\begin{description}
+\item[5 ]Put elements into the data array
+\end{description}
+
+\begin{verbatim}
+ FTPPR[BIJED](unit,group,fpixel,nelements,values, > status)
+\end{verbatim}
+
+\begin{description}
+\item[6 ]Put elements into the data array, substituting the appropriate FITS null
+ value for all elements which are equal to the value of NULLVAL. For
+ integer FITS arrays, the null value defined by the previous call to FTPNUL
+ will be substituted; for floating point FITS arrays (BITPIX = -32
+ or -64) then the special IEEE NaN (Not-a-Number) value will be
+ substituted.
+\end{description}
+
+\begin{verbatim}
+ FTPPN[BIJED](unit,group,fpixel,nelements,values,nullval > status)
+\end{verbatim}
+
+\begin{description}
+\item[7 ]Set data array elements as undefined
+\end{description}
+
+\begin{verbatim}
+ FTPPRU(unit,group,fpixel,nelements, > status)
+\end{verbatim}
+
+\begin{description}
+\item[8 ] Get elements from the data array. Undefined array elements will be
+ returned with a value = nullval, unless nullval = 0 in which case no
+ checks for undefined pixels will be performed.
+\end{description}
+
+\begin{verbatim}
+ FTGPV[BIJED](unit,group,fpixel,nelements,nullval, > values,anyf,status)
+\end{verbatim}
+
+\begin{description}
+\item[9 ] Get elements and nullflags from data array.
+ Any undefined array elements will have the corresponding flagvals element
+ set equal to .TRUE.
+\end{description}
+
+\begin{verbatim}
+ FTGPF[BIJED](unit,group,fpixel,nelements, > values,flagvals,anyf,status)
+\end{verbatim}
+
+\begin{description}
+\item[10] Put values into group parameters
+\end{description}
+
+\begin{verbatim}
+ FTPGP[BIJED](unit,group,fparm,nparm,values, > status)
+\end{verbatim}
+
+\begin{description}
+\item[11] Get values from group parameters
+\end{description}
+
+\begin{verbatim}
+ FTGGP[BIJED](unit,group,fparm,nparm, > values,status)
+\end{verbatim}
+The following 4 subroutines transfer FITS images with 2 or 3 dimensions
+to or from a data array which has been declared in the calling program.
+The dimensionality of the FITS image is passed by the naxis1, naxis2,
+and naxis3 parameters and the declared dimensions of the program array
+are passed in the dim1 and dim2 parameters. Note that the program array
+does not have to have the same dimensions as the FITS array, but must
+be at least as big. For example if a FITS image with NAXIS1 = NAXIS2 = 400
+is read into a program array which is dimensioned as 512 x 512 pixels,
+then the image will just fill the lower left corner of the array
+with pixels in the range 1 - 400 in the X an Y directions. This has
+the effect of taking a contiguous set of pixel value in the FITS array
+and writing them to a non-contiguous array in program memory
+(i.e., there are now some blank pixels around the edge of the image
+in the program array).
+
+
+\begin{description}
+\item[11] Put 2-D image into the data array
+\end{description}
+
+\begin{verbatim}
+ FTP2D[BIJED](unit,group,dim1,naxis1,naxis2,image, > status)
+\end{verbatim}
+
+\begin{description}
+\item[12] Put 3-D cube into the data array
+\end{description}
+
+\begin{verbatim}
+ FTP3D[BIJED](unit,group,dim1,dim2,naxis1,naxis2,naxis3,cube, > status)
+\end{verbatim}
+
+\begin{description}
+\item[13] Get 2-D image from the data array. Undefined
+ pixels in the array will be set equal to the value of 'nullval',
+ unless nullval=0 in which case no testing for undefined pixels will
+ be performed.
+\end{description}
+
+\begin{verbatim}
+ FTG2D[BIJED](unit,group,nullval,dim1,naxis1,naxis2, > image,anyf,status)
+\end{verbatim}
+
+\begin{description}
+\item[14] Get 3-D cube from the data array. Undefined
+ pixels in the array will be set equal to the value of 'nullval',
+ unless nullval=0 in which case no testing for undefined pixels will
+ be performed.
+\end{description}
+
+\begin{verbatim}
+ FTG3D[BIJED](unit,group,nullval,dim1,dim2,naxis1,naxis2,naxis3, >
+ cube,anyf,status)
+\end{verbatim}
+
+The following subroutines transfer a rectangular subset of the pixels
+in a FITS N-dimensional image to or from an array which has been
+declared in the calling program. The fpixels and lpixels parameters
+are integer arrays which specify the starting and ending pixels in each
+dimension of the FITS image that are to be read or written. (Note that
+these are the starting and ending pixels in the FITS image, not in the
+declared array). The array parameter is treated simply as a large
+one-dimensional array of the appropriate datatype containing the pixel
+values; The pixel values in the FITS array are read/written from/to
+this program array in strict sequence without any gaps; it is up to
+the calling routine to correctly interpret the dimensionality of this
+array. The two families of FITS reading routines (FTGSVx and FTGSFx
+subroutines) also have an 'incs' parameter which defines the
+data sampling interval in each dimension of the FITS array. For
+example, if incs(1)=2 and incs(2)=3 when reading a 2-dimensional
+FITS image, then only every other pixel in the first dimension
+and every 3rd pixel in the second dimension will be returned in
+the 'array' parameter. [Note: the FTGSSx family of routines which
+were present in previous versions of FITSIO have been superseded
+by the more general FTGSVx family of routines.]
+
+
+\begin{description}
+\item[15] Put an arbitrary data subsection into the data array.
+\end{description}
+
+\begin{verbatim}
+ FTPSS[BIJED](unit,group,naxis,naxes,fpixels,lpixels,array, > status)
+\end{verbatim}
+
+\begin{description}
+\item[16] Get an arbitrary data subsection from the data array. Undefined
+ pixels in the array will be set equal to the value of 'nullval',
+ unless nullval=0 in which case no testing for undefined pixels will
+ be performed.
+\end{description}
+
+\begin{verbatim}
+ FTGSV[BIJED](unit,group,naxis,naxes,fpixels,lpixels,incs,nullval, >
+ array,anyf,status)
+\end{verbatim}
+
+\begin{description}
+\item[17] Get an arbitrary data subsection from the data array. Any Undefined
+ pixels in the array will have the corresponding 'flagvals'
+ element set equal to .TRUE.
+\end{description}
+
+\begin{verbatim}
+ FTGSF[BIJED](unit,group,naxis,naxes,fpixels,lpixels,incs, >
+ array,flagvals,anyf,status)
+\end{verbatim}
+
+
+\section{FITS ASCII and Binary Table Data I/O Subroutines}
+
+
+\subsection{Column Information Subroutines \label{FTGCNO}}
+
+
+\begin{description}
+\item[1 ] Get the number of rows or columns in the current FITS table.
+ The number of rows is given by the NAXIS2 keyword and the
+ number of columns is given by the TFIELDS keyword in the header
+ of the table.
+\end{description}
+
+\begin{verbatim}
+ FTGNRW(unit, > nrows, status)
+ FTGNCL(unit, > ncols, status)
+\end{verbatim}
+
+\begin{description}
+\item[2 ] Get the table column number (and name) of the column whose name
+matches an input template name. The table column names are defined by
+the TTYPEn keywords in the FITS header. If a column does not have a
+TTYPEn keyword, then these routines assume that the name consists of
+all blank characters. These 2 subroutines perform the same function
+except that FTGCNO only returns the number of the matching column whereas
+FTGCNN also returns the name of the column. If CASESEN = .true. then
+the column name match will be case-sensitive.
+
+The input column name template (COLTEMPLATE) is (1) either the exact
+name of the column to be searched for, or (2) it may contain wild cards
+characters (*, ?, or \#), or (3) it may contain the number of the desired
+column (where the number is expressed as ASCII digits). The first 2 wild
+cards behave similarly to UNIX filename matching: the '*' character matches
+any sequence of characters (including zero characters) and the '?'
+character matches any single character. The \# wildcard will match
+any consecutive string of decimal digits (0-9). As an example, the template
+strings 'AB?DE', 'AB*E', and 'AB*CDE' will all match the string
+'ABCDE'. If more than one column name in the table matches the
+template string, then the first match is returned and the status value
+will be set to 237 as a warning that a unique match was not found. To
+find the other cases that match the template, simply call the
+subroutine again leaving the input status value equal to 237 and the
+next matching name will then be returned. Repeat this process until a
+status = 219 (column name not found) is returned. If these subroutines
+fail to match the template to any of the columns in the table, they
+lastly check if the template can be interpreted as a simple positive
+integer (e.g., '7', or '512') and if so, they return that column
+number. If no matches are found then a status = 219 error is
+returned.
+
+Note that the FITS Standard recommends that only letters, digits, and
+the underscore character be used in column names (with no embedded
+spaces in the name). Trailing blank characters are not significant.
+It is recommended that the column names in a given table be unique
+within the first 8 characters.
+\end{description}
+
+\begin{verbatim}
+ FTGCNO(unit,casesen,coltemplate, > colnum,status)
+ FTGCNN(unit,casesen,coltemplate, > colname,colnum,status)
+\end{verbatim}
+
+\begin{description}
+\item[3 ] Get the datatype of a column in an ASCII or binary table. This
+ routine returns an integer code value corresponding to the datatype
+ of the column. (See the FTBNFM and FTASFM subroutines in the Utilities
+ section of this document for a list of the code values). The vector
+ repeat count (which is alway 1 for ASCII table columns) is also returned.
+ If the specified column has an ASCII character datatype (code = 16) then
+ the width of a unit string in the column is also returned. Note that
+ this routine supports the local convention for specifying arrays of
+ strings within a binary table character column, using the syntax
+ TFORM = 'rAw' where 'r' is the total number of characters (= the width
+ of the column) and 'w' is the width of a unit string within the column.
+ Thus if the column has TFORM = '60A12' then this routine will return
+ datacode = 16, repeat = 60, and width = 12.
+
+ The second routine, FTEQTY is similar except that in
+ the case of scaled integer columns it returns the 'equivalent' data
+ type that is needed to store the scaled values, and not necessarily
+ the physical data type of the unscaled values as stored in the FITS
+ table. For example if a '1I' column in a binary table has TSCALn =
+ 1 and TZEROn = 32768, then this column effectively contains unsigned
+ short integer values, and thus the returned value of typecode will
+ be the code for an unsigned short integer, not a signed short integer.
+ Similarly, if a column has TTYPEn = '1I'
+ and TSCALn = 0.12, then the returned typecode
+ will be the code for a 'real' column.
+\end{description}
+
+\begin{verbatim}
+ FTGTCL(unit,colnum, > datacode,repeat,width,status)
+ FTEQTY(unit,colnum, > datacode,repeat,width,status)
+\end{verbatim}
+
+\begin{description}
+\item[4 ] Return the display width of a column. This is the length
+ of the string that will be returned
+ when reading the column as a formatted string. The display width is
+ determined by the TDISPn keyword, if present, otherwise by the data
+ type of the column.
+\end{description}
+
+\begin{verbatim}
+ FTGCDW(unit, colnum, > dispwidth, status)
+\end{verbatim}
+
+\begin{description}
+\item[5 ] Get information about an existing ASCII table column. (NOTE: TSCAL and
+ TZERO must be declared as Double Precision variables). All the
+ returned parameters are scalar quantities.
+\end{description}
+
+\begin{verbatim}
+ FTGACL(unit,colnum, >
+ ttype,tbcol,tunit,tform,tscal,tzero,snull,tdisp,status)
+\end{verbatim}
+
+\begin{description}
+\item[6 ] Get information about an existing binary table column. (NOTE: TSCAL and
+ TZERO must be declared as Double Precision variables). DATATYPE is a
+ character string which returns the datatype of the column as defined
+ by the TFORMn keyword (e.g., 'I', 'J','E', 'D', etc.). In the case
+ of an ASCII character column, DATATYPE will have a value of the
+ form 'An' where 'n' is an integer expressing the width of the field
+ in characters. For example, if TFORM = '160A8' then FTGBCL will return
+ DATATYPE='A8' and REPEAT=20. All the returned parameters are scalar
+ quantities.
+\end{description}
+
+\begin{verbatim}
+ FTGBCL(unit,colnum, >
+ ttype,tunit,datatype,repeat,tscal,tzero,tnull,tdisp,status)
+\end{verbatim}
+
+\begin{description}
+\item[7 ] Put (append) a TDIMn keyword whose value has the form '(l,m,n...)'
+ where l, m, n... are the dimensions of a multidimension array
+ column in a binary table.
+\end{description}
+
+\begin{verbatim}
+ FTPTDM(unit,colnum,naxis,naxes, > status)
+\end{verbatim}
+
+\begin{description}
+\item[8 ] Return the number of and size of the dimensions of a table column.
+ Normally this information is given by the TDIMn keyword, but if
+ this keyword is not present then this routine returns NAXIS = 1
+ and NAXES(1) equal to the repeat count in the TFORM keyword.
+\end{description}
+
+\begin{verbatim}
+ FTGTDM(unit,colnum,maxdim, > naxis,naxes,status)
+\end{verbatim}
+
+\begin{description}
+\item[9 ] Decode the input TDIMn keyword string (e.g. '(100,200)') and return the
+ number of and size of the dimensions of a binary table column. If the input
+ tdimstr character string is null, then this routine returns naxis = 1
+ and naxes[0] equal to the repeat count in the TFORM keyword. This routine
+ is called by FTGTDM.
+\end{description}
+
+\begin{verbatim}
+ FTDTDM(unit,tdimstr,colnum,maxdim, > naxis,naxes, status)
+\end{verbatim}
+
+\begin{description}
+\item[10] Return the optimal number of rows to read or write at one time for
+ maximum I/O efficiency. Refer to the ``Optimizing Code'' section
+ in Chapter 5 for more discussion on how to use this routine.
+\end{description}
+
+
+\begin{verbatim}
+ FFGRSZ(unit, > nrows,status)
+\end{verbatim}
+
+
+\subsection{Low-Level Table Access Subroutines \label{FTGTBS}}
+
+The following subroutines provide low-level access to the data in ASCII
+or binary tables and are mainly useful as an efficient way to copy all
+or part of a table from one location to another. These routines simply
+read or write the specified number of consecutive bytes in an ASCII or
+binary table, without regard for column boundaries or the row length in
+the table. The first two subroutines read or write consecutive bytes
+in a table to or from a character string variable, while the last two
+subroutines read or write consecutive bytes to or from a variable
+declared as a numeric data type (e.g., INTEGER, INTEGER*2, REAL, DOUBLE
+PRECISION). These routines do not perform any machine dependent data
+conversion or byte swapping, except that conversion to/from ASCII
+format is performed by the FTGTBS and FTPTBS routines on machines which
+do not use ASCII character codes in the internal data representations
+(e.g., on IBM mainframe computers).
+
+
+\begin{description}
+\item[1 ] Read a consecutive string of characters from an ASCII table
+ into a character variable (spanning columns and multiple rows if necessary)
+ This routine should not be used with binary tables because of
+ complications related to passing string variables between C and Fortran.
+\end{description}
+
+\begin{verbatim}
+ FTGTBS(unit,frow,startchar,nchars, > string,status)
+\end{verbatim}
+
+\begin{description}
+\item[2 ] Write a consecutive string of characters to an ASCII table
+ from a character variable (spanning columns and multiple rows if necessary)
+ This routine should not be used with binary tables because of
+ complications related to passing string variables between C and Fortran.
+\end{description}
+
+\begin{verbatim}
+ FTPTBS(unit,frow,startchar,nchars,string, > status)
+\end{verbatim}
+
+\begin{description}
+\item[3 ] Read a consecutive array of bytes from an ASCII or binary table
+ into a numeric variable (spanning columns and multiple rows if necessary).
+ The array parameter may be declared as any numerical datatype as long
+ as the array is at least 'nchars' bytes long, e.g., if nchars = 17,
+ then declare the array as INTEGER*4 ARRAY(5).
+\end{description}
+
+\begin{verbatim}
+ FTGTBB(unit,frow,startchar,nchars, > array,status)
+\end{verbatim}
+
+\begin{description}
+\item[4 ] Write a consecutive array of bytes to an ASCII or binary table
+ from a numeric variable (spanning columns and multiple rows if necessary)
+ The array parameter may be declared as any numerical datatype as long
+ as the array is at least 'nchars' bytes long, e.g., if nchars = 17,
+ then declare the array as INTEGER*4 ARRAY(5).
+\end{description}
+
+\begin{verbatim}
+ FTPTBB(unit,frow,startchar,nchars,array, > status)
+\end{verbatim}
+
+
+\subsection{Edit Rows or Columns \label{FTIROW}}
+
+
+\begin{description}
+\item[1 ] Insert blank rows into an existing ASCII or binary table (in the CDU).
+ All the rows FOLLOWING row FROW are shifted down by NROWS rows. If
+ FROW = 0 then the blank rows are inserted at the beginning of the
+ table. This routine modifies the NAXIS2 keyword to reflect the new
+ number of rows in the table.
+\end{description}
+
+\begin{verbatim}
+ FTIROW(unit,frow,nrows, > status)
+\end{verbatim}
+
+\begin{description}
+\item[2 ] Delete rows from an existing ASCII or binary table (in the CDU).
+ The NROWS number of rows are deleted, starting with row FROW, and
+ any remaining rows in the table are shifted up to fill in the space.
+ This routine modifies the NAXIS2 keyword to reflect the new number
+ of rows in the table.
+\end{description}
+
+\begin{verbatim}
+ FTDROW(unit,frow,nrows, > status)
+\end{verbatim}
+
+\begin{description}
+\item[3 ] Delete a list of rows from an ASCII or binary table (in the CDU).
+ In the first routine, 'rowrange' is a character string listing the
+ rows or row ranges to delete (e.g., '2-4, 5, 8-9'). In the second
+ routine, 'rowlist' is an integer array of row numbers to be deleted
+ from the table. nrows is the number of row numbers in the list.
+ The first row in the table is 1 not 0. The list of row numbers
+ must be sorted in ascending order.
+\end{description}
+
+\begin{verbatim}
+ FTDRRG(unit,rowrange, > status)
+ FTDRWS(unit,rowlist,nrows, > status)
+\end{verbatim}
+
+\begin{description}
+\item[4 ] Insert a blank column (or columns) into an existing ASCII or binary
+ table (in the CDU). COLNUM specifies the column number that the (first)
+ new column should occupy in the table. NCOLS specifies how many
+ columns are to be inserted. Any existing columns from this position and
+ higher are moved over to allow room for the new column(s).
+ The index number on all the following keywords will be incremented
+ if necessary to reflect the new position of the column(s) in the table:
+ TBCOLn, TFORMn, TTYPEn, TUNITn, TNULLn, TSCALn, TZEROn, TDISPn, TDIMn,
+ TLMINn, TLMAXn, TDMINn, TDMAXn, TCTYPn, TCRPXn, TCRVLn, TCDLTn, TCROTn,
+ and TCUNIn.
+\end{description}
+
+\begin{verbatim}
+ FTICOL(unit,colnum,ttype,tform, > status)
+ FTICLS(unit,colnum,ncols,ttype,tform, > status)
+\end{verbatim}
+
+\begin{description}
+\item[5 ] Modify the vector length of a binary table column (e.g.,
+ change a column from TFORMn = '1E' to '20E'). The vector
+ length may be increased or decreased from the current value.
+\end{description}
+
+\begin{verbatim}
+ FTMVEC(unit,colnum,newveclen, > status)
+\end{verbatim}
+
+\begin{description}
+\item[6 ] Delete a column from an existing ASCII or binary table (in the CDU).
+ The index number of all the keywords listed above (for FTICOL) will be
+ decremented if necessary to reflect the new position of the column(s) in
+ the table. Those index keywords that refer to the deleted column will
+ also be deleted. Note that the physical size of the FITS file will
+ not be reduced by this operation, and the empty FITS blocks if any
+ at the end of the file will be padded with zeros.
+\end{description}
+
+\begin{verbatim}
+ FTDCOL(unit,colnum, > status)
+\end{verbatim}
+
+\begin{description}
+\item[7 ] Copy a column from one HDU to another (or to the same HDU). If
+ createcol = TRUE, then a new column will be inserted in the output
+ table, at position `outcolumn', otherwise the existing output column will
+ be overwritten (in which case it must have a compatible datatype).
+ Note that the first column in a table is at colnum = 1.
+\end{description}
+
+\begin{verbatim}
+ FTCPCL(inunit,outunit,incolnum,outcolnum,createcol, > status);
+\end{verbatim}
+
+\subsection{Read and Write Column Data Routines \label{FTPCLS}}
+
+These subroutines put or get data values in the current ASCII or Binary table
+extension. Automatic data type conversion is performed for numerical data
+types (B,I,J,E,D) if the data type of the column (defined by the TFORM keyword)
+differs from the data type of the calling subroutine. The data values are also
+scaled by the TSCALn and TZEROn header values as they are being written to
+or read from the FITS array. The fttscl subroutine MUST be used to define the
+scaling parameters when writing data to the table or to override the default
+scaling values given in the header
+when reading from the table.
+
+ In the case of binary tables with vector elements, the 'felem'
+parameter defines the starting pixel within the element vector. This
+parameter is ignored with ASCII tables. Similarly, in the case of
+binary tables the 'nelements' parameter specifies the total number of
+vector values read or written (continuing on subsequent rows if
+required) and not the number of table elements. Two sets of
+subroutines are provided to get the column data which differ in the way
+undefined pixels are handled. The first set of routines (FTGCV)
+simply return an array of data elements in which undefined pixels are
+set equal to a value specified by the user in the 'nullval' parameter.
+An additional feature of these subroutines is that if the user sets
+nullval = 0, then no checks for undefined pixels will be performed,
+thus increasing the speed of the program. The second set of routines
+(FTGCF) returns the data element array and in addition a logical array
+of flags which defines whether the corresponding data pixel is undefined.
+
+ Any column, regardless of it's intrinsic datatype, may be read as a
+ string. It should be noted however that reading a numeric column
+ as a string is 10 - 100 times slower than reading the same column as
+ a number due to the large overhead in constructing the formatted
+ strings. The display format of the returned strings will be
+ determined by the TDISPn keyword, if it exists, otherwise by the
+ datatype of the column. The length of the returned strings can be
+ determined with the ftgcdw routine. The following TDISPn display
+ formats are currently supported:
+
+\begin{verbatim}
+ Iw.m Integer
+ Ow.m Octal integer
+ Zw.m Hexadecimal integer
+ Fw.d Fixed floating point
+ Ew.d Exponential floating point
+ Dw.d Exponential floating point
+ Gw.d General; uses Fw.d if significance not lost, else Ew.d
+\end{verbatim}
+ where w is the width in characters of the displayed values, m is the minimum
+ number of digits displayed, and d is the number of digits to the right of the
+ decimal. The .m field is optional.
+
+
+\begin{description}
+\item[1 ] Put elements into an ASCII or binary table column (in the CDU).
+ (The SPP FSPCLS routine has an additional integer argument after
+ the VALUES character string which specifies the size of the 1st
+ dimension of this 2-D CHAR array).
+\end{description}
+
+\begin{verbatim}
+ FTPCL[SLBIJEDCM](unit,colnum,frow,felem,nelements,values, > status)
+\end{verbatim}
+
+\begin{description}
+\item[2 ] Put elements into an ASCII or binary table column (in the CDU)
+ substituting the appropriate FITS null value for any elements that
+ are equal to NULLVAL. This family of routines must NOT be used to
+ write to variable length array columns. For ASCII TABLE extensions, the
+ null value defined by the previous call to FTSNUL will be substituted;
+ For integer FITS columns, in a binary table the null value
+ defined by the previous call to FTTNUL will be substituted;
+ For floating point FITS columns a special IEEE NaN (Not-a-Number)
+ value will be substituted.
+\end{description}
+
+\begin{verbatim}
+ FTPCN[BIJED](unit,colnum,frow,felem,nelements,values,nullval > status)
+\end{verbatim}
+
+\begin{description}
+\item[3 ] Put bit values into a binary byte ('B') or bit ('X') table column (in the
+ CDU). LRAY is an array of logical values corresponding to the sequence of
+ bits to be written. If LRAY is true then the corresponding bit is
+ set to 1, otherwise the bit is set to 0. Note that in the case of
+ 'X' columns, FITSIO will write to all 8 bits of each byte whether
+ they are formally valid or not. Thus if the column is defined as
+ '4X', and one calls FTPCLX with fbit=1 and nbit=8, then all 8 bits
+ will be written into the first byte (as opposed to writing the
+ first 4 bits into the first row and then the next 4 bits into the
+ next row), even though the last 4 bits of each byte are formally
+ not defined.
+\end{description}
+
+\begin{verbatim}
+ FTPCLX(unit,colnum,frow,fbit,nbit,lray, > status)
+\end{verbatim}
+
+\begin{description}
+\item[4 ] Set table elements in a column as undefined
+\end{description}
+
+\begin{verbatim}
+ FTPCLU(unit,colnum,frow,felem,nelements, > status)
+\end{verbatim}
+
+\begin{description}
+\item[5 ] Get elements from an ASCII or binary table column (in the CDU). These
+ routines return the values of the table column array elements. Undefined
+ array elements will be returned with a value = nullval, unless nullval = 0
+ (or = ' ' for ftgcvs) in which case no checking for undefined values will
+ be performed. The ANYF parameter is set to true if any of the returned
+ elements are undefined. (Note: the ftgcl routine simple gets an array
+ of logical data values without any checks for undefined values; use
+ the ftgcfl routine to check for undefined logical elements).
+ (The SPP FSGCVS routine has an additional integer argument after
+ the VALUES character string which specifies the size of the 1st
+ dimension of this 2-D CHAR array).
+\end{description}
+
+\begin{verbatim}
+ FTGCL(unit,colnum,frow,felem,nelements, > values,status)
+ FTGCV[SBIJEDCM](unit,colnum,frow,felem,nelements,nullval, >
+ values,anyf,status)
+\end{verbatim}
+
+\begin{description}
+\item[6 ] Get elements and null flags from an ASCII or binary table column (in the
+ CHDU). These routines return the values of the table column array elements.
+ Any undefined array elements will have the corresponding flagvals element
+ set equal to .TRUE. The ANYF parameter is set to true if any of the
+ returned elements are undefined.
+ (The SPP FSGCFS routine has an additional integer argument after
+ the VALUES character string which specifies the size of the 1st
+ dimension of this 2-D CHAR array).
+\end{description}
+
+\begin{verbatim}
+ FTGCF[SLBIJEDCM](unit,colnum,frow,felem,nelements, >
+ values,flagvals,anyf,status)
+\end{verbatim}
+
+\begin{description}
+\item[7 ] Get an arbitrary data subsection from an N-dimensional array
+ in a binary table vector column. Undefined pixels
+ in the array will be set equal to the value of 'nullval',
+ unless nullval=0 in which case no testing for undefined pixels will
+ be performed. The first and last rows in the table to be read
+ are specified by fpixels(naxis+1) and lpixels(naxis+1), and hence
+ are treated as the next higher dimension of the FITS N-dimensional
+ array. The INCS parameter specifies the sampling interval in
+ each dimension between the data elements that will be returned.
+\end{description}
+
+\begin{verbatim}
+ FTGSV[BIJED](unit,colnum,naxis,naxes,fpixels,lpixels,incs,nullval, >
+ array,anyf,status)
+\end{verbatim}
+
+\begin{description}
+\item[8 ] Get an arbitrary data subsection from an N-dimensional array
+ in a binary table vector column. Any Undefined
+ pixels in the array will have the corresponding 'flagvals'
+ element set equal to .TRUE. The first and last rows in the table
+ to be read are specified by fpixels(naxis+1) and lpixels(naxis+1),
+ and hence are treated as the next higher dimension of the FITS
+ N-dimensional array. The INCS parameter specifies the sampling
+ interval in each dimension between the data elements that will be
+ returned.
+\end{description}
+
+\begin{verbatim}
+ FTGSF[BIJED](unit,colnum,naxis,naxes,fpixels,lpixels,incs, >
+ array,flagvals,anyf,status)
+\end{verbatim}
+
+\begin{description}
+\item[9 ] Get bit values from a byte ('B') or bit (`X`) table column (in the
+ CDU). LRAY is an array of logical values corresponding to the
+ sequence of bits to be read. If LRAY is true then the
+ corresponding bit was set to 1, otherwise the bit was set to 0.
+ Note that in the case of 'X' columns, FITSIO will read all 8 bits
+ of each byte whether they are formally valid or not. Thus if the
+ column is defined as '4X', and one calls FTGCX with fbit=1 and
+ nbit=8, then all 8 bits will be read from the first byte (as
+ opposed to reading the first 4 bits from the first row and then the
+ first 4 bits from the next row), even though the last 4 bits of
+ each byte are formally not defined.
+\end{description}
+
+\begin{verbatim}
+ FTGCX(unit,colnum,frow,fbit,nbit, > lray,status)
+\end{verbatim}
+
+\begin{description}
+\item[10] Read any consecutive set of bits from an 'X' or 'B' column and
+ interpret them as an unsigned n-bit integer. NBIT must be less than
+ or equal to 16 when calling FTGCXI, and less than or equal to 32 when
+ calling FTGCXJ; there is no limit on the value of NBIT for FTGCXD, but
+ the returned double precision value only has 48 bits of precision on
+ most 32-bit word machines. The NBITS bits are interpreted as an
+ unsigned integer unless NBITS = 16 (in FTGCXI) or 32 (in FTGCXJ) in which
+ case the string of bits are interpreted as 16-bit or 32-bit 2's
+ complement signed integers. If NROWS is greater than 1 then the
+ same set of bits will be read from sequential rows in the table
+ starting with row FROW. Note that the numbering convention
+ used here for the FBIT parameter adopts 1 for the first element of the
+ vector of bits; this is the Most Significant Bit of the integer value.
+\end{description}
+
+\begin{verbatim}
+ FTGCX[IJD](unit,colnum,frow,nrows,fbit,nbit, > array,status)
+\end{verbatim}
+
+\begin{description}
+\item[11] Get the descriptor for a variable length column in a binary table.
+ The descriptor consists of 2 integer parameters: the number of elements
+ in the array and the starting offset relative to the start of the heap.
+ The first routine returns a single descriptor whereas the second routine
+ returns the descriptors for a range of rows in the table.
+\end{description}
+
+\begin{verbatim}
+ FTGDES(unit,colnum,rownum, > nelements,offset,status)
+ FFGDESSunit,colnum,firstrow,nrows > nelements,offset, status)
+\end{verbatim}
+
+\begin{description}
+\item[12] Put the descriptor for a variable length column in a binary table.
+ This subroutine can be used in conjunction with FTGDES to enable
+ 2 or more arrays to point to the same storage location to save
+ storage space if the arrays are identical.
+\end{description}
+
+\begin{verbatim}
+ FTPDES(unit,colnum,rownum,nelements,offset, > status)
+\end{verbatim}
+
+
+\section{Row Selection and Calculator Routines \label{FTFROW}}
+
+These routines all parse and evaluate an input string containing a user
+defined arithmetic expression. The first 3 routines select rows in a
+FITS table, based on whether the expression evaluates to true (not
+equal to zero) or false (zero). The other routines evaluate the
+expression and calculate a value for each row of the table. The
+allowed expression syntax is described in the row filter section in the
+earlier `Extended File Name Syntax' chapter of this document. The
+expression may also be written to a text file, and the name of the
+file, prepended with a '@' character may be supplied for the 'expr'
+parameter (e.g. '@filename.txt'). The expression in the file can
+be arbitrarily complex and extend over multiple lines of the file.
+Lines that begin with 2 slash characters ('//') will be ignored and
+may be used to add comments to the file.
+
+
+\begin{description}
+\item[1 ] Evaluate a boolean expression over the indicated rows, returning an
+ array of flags indicating which rows evaluated to TRUE/FALSE
+\end{description}
+
+\begin{verbatim}
+ FTFROW(unit,expr,firstrow, nrows, > n_good_rows, row_status, status)
+\end{verbatim}
+
+\begin{description}
+\item[2 ] Find the first row which satisfies the input boolean expression
+\end{description}
+
+\begin{verbatim}
+ FTFFRW(unit, expr, > rownum, status)
+\end{verbatim}
+
+\begin{description}
+\item[3 ]Evaluate an expression on all rows of a table. If the input and output
+files are not the same, copy the TRUE rows to the output file. If the
+files are the same, delete the FALSE rows (preserve the TRUE rows).
+\end{description}
+
+\begin{verbatim}
+ FTSROW(inunit, outunit, expr, > status)
+\end{verbatim}
+
+\begin{description}
+\item[4 ] Calculate an expression for the indicated rows of a table, returning
+the results, cast as datatype (TSHORT, TDOUBLE, etc), in array. If
+nulval==NULL, UNDEFs will be zeroed out. For vector results, the number
+of elements returned may be less than nelements if nelements is not an
+even multiple of the result dimension. Call FTTEXP to obtain
+the dimensions of the results.
+\end{description}
+
+\begin{verbatim}
+ FTCROW(unit,datatype,expr,firstrow,nelements,nulval, >
+ array,anynul,status)
+\end{verbatim}
+
+\begin{description}
+\item[5 ]Evaluate an expression and write the result either to a column (if
+the expression is a function of other columns in the table) or to a
+keyword (if the expression evaluates to a constant and is not a
+function of other columns in the table). In the former case, the
+parName parameter is the name of the column (which may or may not already
+exist) into which to write the results, and parInfo contains an
+optional TFORM keyword value if a new column is being created. If a
+TFORM value is not specified then a default format will be used,
+depending on the expression. If the expression evaluates to a constant,
+then the result will be written to the keyword name given by the
+parName parameter, and the parInfo parameter may be used to supply an
+optional comment for the keyword. If the keyword does not already
+exist, then the name of the keyword must be preceded with a '\#' character,
+otherwise the result will be written to a column with that name.
+\end{description}
+
+
+\begin{verbatim}
+ FTCALC(inunit, expr, outunit, parName, parInfo, > status)
+\end{verbatim}
+
+\begin{description}
+\item[6 ] This calculator routine is similar to the previous routine, except
+that the expression is only evaluated over the specified
+row ranges. nranges specifies the number of row ranges, and firstrow
+and lastrow give the starting and ending row number of each range.
+\end{description}
+
+\begin{verbatim}
+ FTCALC_RNG(inunit, expr, outunit, parName, parInfo,
+ nranges, firstrow, lastrow, > status)
+\end{verbatim}
+
+\begin{description}
+\item[7 ]Evaluate the given expression and return information on the result.
+\end{description}
+
+\begin{verbatim}
+ FTTEXP(unit, expr, > datatype, nelem, naxis, naxes, status)
+\end{verbatim}
+
+
+
+\section{Celestial Coordinate System Subroutines \label{FTGICS}}
+
+The FITS community has adopted a set of keyword conventions that define
+the transformations needed to convert between pixel locations in an
+image and the corresponding celestial coordinates on the sky, or more
+generally, that define world coordinates that are to be associated with
+any pixel location in an n-dimensional FITS array. CFITSIO is distributed
+with a couple of self-contained World Coordinate System (WCS) routines,
+however, these routines DO NOT support all the latest WCS conventions,
+so it is STRONGLY RECOMMENDED that software developers use a more robust
+external WCS library. Several recommended libraries are:
+
+\begin{verbatim}
+ WCSLIB - supported by Mark Calabretta
+ WCSTools - supported by Doug Mink
+ AST library - developed by the U.K. Starlink project
+\end{verbatim}
+
+More information about the WCS keyword conventions and links to all of
+these WCS libraries can be found on the FITS Support Office web site at
+http://fits.gsfc.nasa.gov under the WCS link.
+
+The functions provided in these external WCS libraries will need access to
+the WCS information contained in the FITS file headers. One convenient
+way to pass this information to the extermal library is to use FITSIO
+to copy the header keywords into one long character string, and then
+pass this string to an interface routine in the external library that
+will extract the necessary WCS information (e.g., see the astFitsChan
+and astPutCards routines in the Starlink AST library).
+
+The following FITSIO routines DO NOT support the more recent WCS conventions
+that have been approved as part of the FITS standard. Consequently,
+the following routines ARE NOW DEPRECATED. It is STRONGLY RECOMMENDED
+that software developers not use these routines, and instead use an
+external WCS library, as described above.
+
+These routines are included mainly for backward compatibility with
+existing software. They support the following standard map
+projections: -SIN, -TAN, -ARC, -NCP, -GLS, -MER, and -AIT (these are the
+legal values for the coordtype parameter). These routines are based
+on similar functions in Classic AIPS. All the angular quantities are
+given in units of degrees.
+
+
+\begin{description}
+\item[1 ] Get the values of all the standard FITS celestial coordinate system
+ keywords from the header of a FITS image (i.e., the primary array or
+ an image extension). These values may then be passed to the subroutines
+ that perform the coordinate transformations. If any or all of the WCS
+ keywords are not present, then default values will be returned. If
+ the first coordinate axis is the declination-like coordinate, then
+ this routine will swap them so that the longitudinal-like coordinate
+ is returned as the first axis.
+
+ If the file uses the newer 'CDj\_i' WCS transformation matrix
+ keywords instead of old style 'CDELTn' and 'CROTA2' keywords, then
+ this routine will calculate and return the values of the equivalent
+ old-style keywords. Note that the conversion from the new-style
+ keywords to the old-style values is sometimes only an
+ approximation, so if the approximation is larger than an internally
+ defined threshold level, then CFITSIO will still return the
+ approximate WCS keyword values, but will also return with status =
+ 506, to warn the calling program that approximations have been
+ made. It is then up to the calling program to decide whether the
+ approximations are sufficiently accurate for the particular
+ application, or whether more precise WCS transformations must be
+ performed using new-style WCS keywords directly.
+\end{description}
+
+\begin{verbatim}
+ FTGICS(unit, > xrval,yrval,xrpix,yrpix,xinc,yinc,rot,coordtype,status)
+\end{verbatim}
+
+\begin{description}
+\item[2 ] Get the values of all the standard FITS celestial coordinate system
+ keywords from the header of a FITS table where the X and Y (or RA and
+ DEC coordinates are stored in 2 separate columns of the table.
+ These values may then be passed to the subroutines that perform the
+ coordinate transformations.
+\end{description}
+
+\begin{verbatim}
+ FTGTCS(unit,xcol,ycol, >
+ xrval,yrval,xrpix,yrpix,xinc,yinc,rot,coordtype,status)
+\end{verbatim}
+
+\begin{description}
+\item[3 ] Calculate the celestial coordinate corresponding to the input
+ X and Y pixel location in the image.
+\end{description}
+
+\begin{verbatim}
+ FTWLDP(xpix,ypix,xrval,yrval,xrpix,yrpix,xinc,yinc,rot,
+ coordtype, > xpos,ypos,status)
+\end{verbatim}
+
+\begin{description}
+\item[4 ] Calculate the X and Y pixel location corresponding to the input
+ celestial coordinate in the image.
+\end{description}
+
+\begin{verbatim}
+ FTXYPX(xpos,ypos,xrval,yrval,xrpix,yrpix,xinc,yinc,rot,
+ coordtype, > xpix,ypix,status)
+\end{verbatim}
+
+
+\section{File Checksum Subroutines \label{FTPCKS}}
+
+The following routines either compute or validate the checksums for the
+CHDU. The DATASUM keyword is used to store the numerical value of the
+32-bit, 1's complement checksum for the data unit alone. If there is
+no data unit then the value is set to zero. The numerical value is
+stored as an ASCII string of digits, enclosed in quotes, because the
+value may be too large to represent as a 32-bit signed integer. The
+CHECKSUM keyword is used to store the ASCII encoded COMPLEMENT of the
+checksum for the entire HDU. Storing the complement, rather than the
+actual checksum, forces the checksum for the whole HDU to equal zero.
+If the file has been modified since the checksums were computed, then
+the HDU checksum will usually not equal zero. These checksum keyword
+conventions are based on a paper by Rob Seaman published in the
+proceedings of the ADASS IV conference in Baltimore in November 1994
+and a later revision in June 1995.
+
+
+\begin{description}
+\item[1 ] Compute and write the DATASUM and CHECKSUM keyword values for the CHDU
+ into the current header. The DATASUM value is the 32-bit checksum
+ for the data unit, expressed as a decimal integer enclosed in single
+ quotes. The CHECKSUM keyword value is a 16-character string which
+ is the ASCII-encoded value for the complement of the checksum for
+ the whole HDU. If these keywords already exist, their values
+ will be updated only if necessary (i.e., if the file has been modified
+ since the original keyword values were computed).
+\end{description}
+
+\begin{verbatim}
+ FTPCKS(unit, > status)
+\end{verbatim}
+
+\begin{description}
+\item[2 ] Update the CHECKSUM keyword value in the CHDU, assuming that the
+ DATASUM keyword exists and already has the correct value. This routine
+ calculates the new checksum for the current header unit, adds it to the
+ data unit checksum, encodes the value into an ASCII string, and writes
+ the string to the CHECKSUM keyword.
+\end{description}
+
+\begin{verbatim}
+ FTUCKS(unit, > status)
+\end{verbatim}
+
+\begin{description}
+\item[3 ] Verify the CHDU by computing the checksums and comparing
+ them with the keywords. The data unit is verified correctly
+ if the computed checksum equals the value of the DATASUM
+ keyword. The checksum for the entire HDU (header plus data unit) is
+ correct if it equals zero. The output DATAOK and HDUOK parameters
+ in this subroutine are integers which will have a value = 1
+ if the data or HDU is verified correctly, a value = 0
+ if the DATASUM or CHECKSUM keyword is not present, or value = -1
+ if the computed checksum is not correct.
+\end{description}
+
+\begin{verbatim}
+ FTVCKS(unit, > dataok,hduok,status)
+\end{verbatim}
+
+\begin{description}
+\item[4 ] Compute and return the checksum values for the CHDU (as
+ double precision variables) without creating or modifying the
+ CHECKSUM and DATASUM keywords. This routine is used internally by
+ FTVCKS, but may be useful in other situations as well.
+\end{description}
+
+\begin{verbatim}
+ FTGCKS(unit, > datasum,hdusum,status)
+\end{verbatim}
+
+\begin{description}
+\item[5 ] Encode a checksum value (stored in a double precision variable)
+ into a 16-character string. If COMPLEMENT = .true. then the 32-bit
+ sum value will be complemented before encoding.
+\end{description}
+
+\begin{verbatim}
+ FTESUM(sum,complement, > checksum)
+\end{verbatim}
+
+\begin{description}
+\item[6 ] Decode a 16 character checksum string into a double precision value.
+ If COMPLEMENT = .true. then the 32-bit sum value will be complemented
+ after decoding.
+\end{description}
+
+\begin{verbatim}
+ FTDSUM(checksum,complement, > sum)
+\end{verbatim}
+
+
+\section{ Date and Time Utility Routines \label{FTGSDT}}
+
+The following routines help to construct or parse the FITS date/time
+strings. Starting in the year 2000, the FITS DATE keyword values (and
+the values of other `DATE-' keywords) must have the form 'YYYY-MM-DD'
+(date only) or 'YYYY-MM-DDThh:mm:ss.ddd...' (date and time) where the
+number of decimal places in the seconds value is optional. These times
+are in UTC. The older 'dd/mm/yy' date format may not be used for dates
+after 01 January 2000.
+
+
+\begin{description}
+\item[1 ] Get the current system date. The returned year has 4 digits
+ (1999, 2000, etc.)
+\end{description}
+
+\begin{verbatim}
+ FTGSDT( > day, month, year, status )
+\end{verbatim}
+
+
+\begin{description}
+\item[2 ] Get the current system date and time string ('YYYY-MM-DDThh:mm:ss').
+The time will be in UTC/GMT if available, as indicated by a returned timeref
+value = 0. If the returned value of timeref = 1 then this indicates that
+it was not possible to convert the local time to UTC, and thus the local
+time was returned.
+\end{description}
+
+\begin{verbatim}
+ FTGSTM(> datestr, timeref, status)
+\end{verbatim}
+
+
+\begin{description}
+\item[3 ] Construct a date string from the input date values. If the year
+is between 1900 and 1998, inclusive, then the returned date string will
+have the old FITS format ('dd/mm/yy'), otherwise the date string will
+have the new FITS format ('YYYY-MM-DD'). Use FTTM2S instead
+ to always return a date string using the new FITS format.
+\end{description}
+
+\begin{verbatim}
+ FTDT2S( year, month, day, > datestr, status)
+\end{verbatim}
+
+
+\begin{description}
+\item[4 ] Construct a new-format date + time string ('YYYY-MM-DDThh:mm:ss.ddd...').
+ If the year, month, and day values all = 0 then only the time is encoded
+ with format 'hh:mm:ss.ddd...'. The decimals parameter specifies how many
+ decimal places of fractional seconds to include in the string. If `decimals'
+ is negative, then only the date will be return ('YYYY-MM-DD').
+\end{description}
+
+\begin{verbatim}
+ FTTM2S( year, month, day, hour, minute, second, decimals,
+ > datestr, status)
+\end{verbatim}
+
+
+\begin{description}
+\item[5 ] Return the date as read from the input string, where the string may be
+in either the old ('dd/mm/yy') or new ('YYYY-MM-DDThh:mm:ss' or
+'YYYY-MM-DD') FITS format.
+\end{description}
+
+\begin{verbatim}
+ FTS2DT(datestr, > year, month, day, status)
+\end{verbatim}
+
+
+\begin{description}
+\item[6 ] Return the date and time as read from the input string, where the
+string may be in either the old or new FITS format. The returned hours,
+minutes, and seconds values will be set to zero if the input string
+does not include the time ('dd/mm/yy' or 'YYYY-MM-DD') . Similarly,
+the returned year, month, and date values will be set to zero if the
+date is not included in the input string ('hh:mm:ss.ddd...').
+\end{description}
+
+\begin{verbatim}
+ FTS2TM(datestr, > year, month, day, hour, minute, second, status)
+\end{verbatim}
+
+
+\section{General Utility Subroutines \label{FTGHAD}}
+
+The following utility subroutines may be useful for certain applications:
+
+
+\begin{description}
+\item[1 ] Return the starting byte address of the CHDU and the next HDU.
+\end{description}
+
+\begin{verbatim}
+ FTGHAD(iunit, > curaddr,nextaddr)
+\end{verbatim}
+
+\begin{description}
+\item[2 ] Convert a character string to uppercase (operates in place).
+\end{description}
+
+\begin{verbatim}
+ FTUPCH(string)
+\end{verbatim}
+
+\begin{description}
+\item[3 ] Compare the input template string against the reference string
+ to see if they match. The template string may contain wildcard
+ characters: '*' will match any sequence of characters (including
+ zero characters) and '%' will match any single character in the
+ reference string. If CASESN = .true. then the match will be
+ case sensitive. The returned MATCH parameter will be .true. if
+ the 2 strings match, and EXACT will be .true. if the match is
+ exact (i.e., if no wildcard characters were used in the match).
+ Both strings must be 68 characters or less in length.
+\end{description}
+
+\begin{verbatim}
+ FTCMPS(str_template,string,casesen, > match,exact)
+\end{verbatim}
+
+
+\begin{description}
+\item[4 ] Test that the keyword name contains only legal characters: A-Z,0-9,
+ hyphen, and underscore.
+\end{description}
+
+\begin{verbatim}
+ FTTKEY(keyword, > status)
+\end{verbatim}
+
+\begin{description}
+\item[5 ] Test that the keyword record contains only legal printable ASCII
+ characters
+\end{description}
+
+\begin{verbatim}
+ FTTREC(card, > status)
+\end{verbatim}
+
+\begin{description}
+\item[6 ] Test whether the current header contains any NULL (ASCII 0) characters.
+ These characters are illegal in the header, but they will go undetected
+ by most of the CFITSIO keyword header routines, because the null is
+ interpreted as the normal end-of-string terminator. This routine returns
+ the position of the first null character in the header, or zero if there
+ are no nulls. For example a returned value of 110 would indicate that
+ the first NULL is located in the 30th character of the second keyword
+ in the header (recall that each header record is 80 characters long).
+ Note that this is one of the few FITSIO routines in which the returned
+ value is not necessarily equal to the status value).
+\end{description}
+
+\begin{verbatim}
+ FTNCHK(unit, > status)
+\end{verbatim}
+
+\begin{description}
+\item[7 ] Parse a header keyword record and return the name of the keyword
+ and the length of the name.
+ The keyword name normally occupies the first 8 characters of the
+ record, except under the HIERARCH convention where the name can
+ be up to 70 characters in length.
+\end{description}
+
+\begin{verbatim}
+ FTGKNM(card, > keyname, keylength, status)
+\end{verbatim}
+
+\begin{description}
+\item[8 ] Parse a header keyword record.
+ This subroutine parses the input header record to return the value (as
+ a character string) and comment strings. If the keyword has no
+ value (columns 9-10 not equal to '= '), then the value string is returned
+ blank and the comment string is set equal to column 9 - 80 of the
+ input string.
+\end{description}
+
+\begin{verbatim}
+ FTPSVC(card, > value,comment,status)
+\end{verbatim}
+
+\begin{description}
+\item[9 ] Construct a sequence keyword name (ROOT + nnn).
+ This subroutine appends the sequence number to the root string to create
+ a keyword name (e.g., 'NAXIS' + 2 = 'NAXIS2')
+\end{description}
+
+\begin{verbatim}
+ FTKEYN(keyroot,seq_no, > keyword,status)
+\end{verbatim}
+
+\begin{description}
+\item[10] Construct a sequence keyword name (n + ROOT).
+ This subroutine concatenates the sequence number to the front of the
+ root string to create a keyword name (e.g., 1 + 'CTYP' = '1CTYP')
+\end{description}
+
+\begin{verbatim}
+ FTNKEY(seq_no,keyroot, > keyword,status)
+\end{verbatim}
+
+\begin{description}
+\item[11] Determine the datatype of a keyword value string.
+ This subroutine parses the keyword value string (usually columns 11-30
+ of the header record) to determine its datatype.
+\end{description}
+
+\begin{verbatim}
+ FTDTYP(value, > dtype,status)
+\end{verbatim}
+
+\begin{description}
+\item[11] Return the class of input header record. The record is classified
+ into one of the following categories (the class values are
+ defined in fitsio.h). Note that this is one of the few FITSIO
+ routines that does not return a status value.
+\end{description}
+
+\begin{verbatim}
+ Class Value Keywords
+ TYP_STRUC_KEY 10 SIMPLE, BITPIX, NAXIS, NAXISn, EXTEND, BLOCKED,
+ GROUPS, PCOUNT, GCOUNT, END
+ XTENSION, TFIELDS, TTYPEn, TBCOLn, TFORMn, THEAP,
+ and the first 4 COMMENT keywords in the primary array
+ that define the FITS format.
+ TYP_CMPRS_KEY 20 The experimental keywords used in the compressed
+ image format ZIMAGE, ZCMPTYPE, ZNAMEn, ZVALn,
+ ZTILEn, ZBITPIX, ZNAXISn, ZSCALE, ZZERO, ZBLANK
+ TYP_SCAL_KEY 30 BSCALE, BZERO, TSCALn, TZEROn
+ TYP_NULL_KEY 40 BLANK, TNULLn
+ TYP_DIM_KEY 50 TDIMn
+ TYP_RANG_KEY 60 TLMINn, TLMAXn, TDMINn, TDMAXn, DATAMIN, DATAMAX
+ TYP_UNIT_KEY 70 BUNIT, TUNITn
+ TYP_DISP_KEY 80 TDISPn
+ TYP_HDUID_KEY 90 EXTNAME, EXTVER, EXTLEVEL, HDUNAME, HDUVER, HDULEVEL
+ TYP_CKSUM_KEY 100 CHECKSUM, DATASUM
+ TYP_WCS_KEY 110 CTYPEn, CUNITn, CRVALn, CRPIXn, CROTAn, CDELTn
+ CDj_is, PVj_ms, LONPOLEs, LATPOLEs
+ TCTYPn, TCTYns, TCUNIn, TCUNns, TCRVLn, TCRVns, TCRPXn,
+ TCRPks, TCDn_k, TCn_ks, TPVn_m, TPn_ms, TCDLTn, TCROTn
+ jCTYPn, jCTYns, jCUNIn, jCUNns, jCRVLn, jCRVns, iCRPXn,
+ iCRPns, jiCDn, jiCDns, jPVn_m, jPn_ms, jCDLTn, jCROTn
+ (i,j,m,n are integers, s is any letter)
+ TYP_REFSYS_KEY 120 EQUINOXs, EPOCH, MJD-OBSs, RADECSYS, RADESYSs
+ TYP_COMM_KEY 130 COMMENT, HISTORY, (blank keyword)
+ TYP_CONT_KEY 140 CONTINUE
+ TYP_USER_KEY 150 all other keywords
+
+ class = FTGKCL (char *card)
+\end{verbatim}
+
+\begin{description}
+\item[12] Parse the 'TFORM' binary table column format string.
+ This subroutine parses the input TFORM character string and returns the
+ integer datatype code, the repeat count of the field, and, in the case
+ of character string fields, the length of the unit string. The following
+ datatype codes are returned (the negative of the value is returned
+ if the column contains variable-length arrays):
+\end{description}
+
+\begin{verbatim}
+ Datatype DATACODE value
+ bit, X 1
+ byte, B 11
+ logical, L 14
+ ASCII character, A 16
+ short integer, I 21
+ integer, J 41
+ real, E 42
+ double precision, D 82
+ complex 83
+ double complex 163
+
+ FTBNFM(tform, > datacode,repeat,width,status)
+\end{verbatim}
+
+\begin{description}
+\item[13] Parse the 'TFORM' keyword value that defines the column format in
+ an ASCII table. This routine parses the input TFORM character
+ string and returns the datatype code, the width of the column,
+ and (if it is a floating point column) the number of decimal places
+ to the right of the decimal point. The returned datatype codes are
+ the same as for the binary table, listed above, with the following
+ additional rules: integer columns that are between 1 and 4 characters
+ wide are defined to be short integers (code = 21). Wider integer
+ columns are defined to be regular integers (code = 41). Similarly,
+ Fixed decimal point columns (with TFORM = 'Fw.d') are defined to
+ be single precision reals (code = 42) if w is between 1 and 7 characters
+ wide, inclusive. Wider 'F' columns will return a double precision
+ data code (= 82). 'Ew.d' format columns will have datacode = 42,
+ and 'Dw.d' format columns will have datacode = 82.
+\end{description}
+
+\begin{verbatim}
+ FTASFM(tform, > datacode,width,decimals,status)
+\end{verbatim}
+
+\begin{description}
+\item[14] Calculate the starting column positions and total ASCII table width
+ based on the input array of ASCII table TFORM values. The SPACE input
+ parameter defines how many blank spaces to leave between each column
+ (it is recommended to have one space between columns for better human
+ readability).
+\end{description}
+
+\begin{verbatim}
+ FTGABC(tfields,tform,space, > rowlen,tbcol,status)
+\end{verbatim}
+
+\begin{description}
+\item[15] Parse a template string and return a formatted 80-character string
+ suitable for appending to (or deleting from) a FITS header file.
+ This subroutine is useful for parsing lines from an ASCII template file
+ and reformatting them into legal FITS header records. The formatted
+ string may then be passed to the FTPREC, FTMCRD, or FTDKEY subroutines
+ to append or modify a FITS header record.
+\end{description}
+
+\begin{verbatim}
+ FTGTHD(template, > card,hdtype,status)
+\end{verbatim}
+ The input TEMPLATE character string generally should contain 3 tokens:
+ (1) the KEYNAME, (2) the VALUE, and (3) the COMMENT string. The
+ TEMPLATE string must adhere to the following format:
+
+
+\begin{description}
+\item[- ] The KEYNAME token must begin in columns 1-8 and be a maximum of 8
+ characters long. If the first 8 characters of the template line are
+ blank then the remainder of the line is considered to be a FITS comment
+ (with a blank keyword name). A legal FITS keyword name may only
+ contain the characters A-Z, 0-9, and '-' (minus sign) and
+ underscore. This subroutine will automatically convert any lowercase
+ characters to uppercase in the output string. If KEYNAME = 'COMMENT'
+ or 'HISTORY' then the remainder of the line is considered to be a FITS
+ COMMENT or HISTORY record, respectively.
+\end{description}
+
+
+\begin{description}
+\item[- ] The VALUE token must be separated from the KEYNAME token by one or more
+ spaces and/or an '=' character. The datatype of the VALUE token
+ (numeric, logical, or character string) is automatically determined
+ and the output CARD string is formatted accordingly. The value
+ token may be forced to be interpreted as a string (e.g. if it is a
+ string of numeric digits) by enclosing it in single quotes.
+\end{description}
+
+
+\begin{description}
+\item[- ] The COMMENT token is optional, but if present must be separated from
+ the VALUE token by at least one blank space. A leading '/' character
+ may be used to mark the beginning of the comment field, otherwise the
+ comment field begins with the first non-blank character following the
+ value token.
+\end{description}
+
+
+\begin{description}
+\item[- ] One exception to the above rules is that if the first non-blank
+ character in the template string is a minus sign ('-') followed
+ by a single token, or a single token followed by an equal sign,
+ then it is interpreted as the name of a keyword which is to be
+ deleted from the FITS header.
+\end{description}
+
+
+\begin{description}
+\item[- ] The second exception is that if the template string starts with
+ a minus sign and is followed by 2 tokens then the second token
+ is interpreted as the new name for the keyword specified by
+ first token. In this case the old keyword name (first token)
+ is returned in characters 1-8 of the returned CARD string, and
+ the new keyword name (the second token) is returned in characters
+ 41-48 of the returned CARD string. These old and new names
+ may then be passed to the FTMNAM subroutine which will change
+ the keyword name.
+\end{description}
+
+ The HDTYPE output parameter indicates how the returned CARD string
+ should be interpreted:
+
+\begin{verbatim}
+ hdtype interpretation
+ ------ -------------------------------------------------
+ -2 Modify the name of the keyword given in CARD(1:8)
+ to the new name given in CARD(41:48)
+
+ -1 CARD(1:8) contains the name of a keyword to be deleted
+ from the FITS header.
+
+ 0 append the CARD string to the FITS header if the
+ keyword does not already exist, otherwise update
+ the value/comment if the keyword is already present
+ in the header.
+
+ 1 simply append this keyword to the FITS header (CARD
+ is either a HISTORY or COMMENT keyword).
+
+ 2 This is a FITS END record; it should not be written
+ to the FITS header because FITSIO automatically
+ appends the END record when the header is closed.
+\end{verbatim}
+ EXAMPLES: The following lines illustrate valid input template strings:
+
+\begin{verbatim}
+ INTVAL 7 This is an integer keyword
+ RVAL 34.6 / This is a floating point keyword
+ EVAL=-12.45E-03 This is a floating point keyword in exponential notation
+ lval F This is a boolean keyword
+ This is a comment keyword with a blank keyword name
+ SVAL1 = 'Hello world' / this is a string keyword
+ SVAL2 '123.5' this is also a string keyword
+ sval3 123+ / this is also a string keyword with the value '123+ '
+ # the following template line deletes the DATE keyword
+ - DATE
+ # the following template line modifies the NAME keyword to OBJECT
+ - NAME OBJECT
+\end{verbatim}
+
+\begin{description}
+\item[16] Parse the input string containing a list of rows or row ranges, and
+ return integer arrays containing the first and last row in each
+ range. For example, if rowlist = "3-5, 6, 8-9" then it will
+ return numranges = 3, rangemin = 3, 6, 8 and rangemax = 5, 6, 9.
+ At most, 'maxranges' number of ranges will be returned. 'maxrows'
+ is the maximum number of rows in the table; any rows or ranges
+ larger than this will be ignored. The rows must be specified in
+ increasing order, and the ranges must not overlap. A minus sign
+ may be use to specify all the rows to the upper or lower bound, so
+ "50-" means all the rows from 50 to the end of the table, and "-"
+ means all the rows in the table, from 1 - maxrows.
+\end{description}
+
+\begin{verbatim}
+ FTRWRG(rowlist, maxrows, maxranges, >
+ numranges, rangemin, rangemax, status)
+\end{verbatim}
+
+
+\chapter{ Summary of all FITSIO User-Interface Subroutines }
+
+ Error Status Routines page~\pageref{FTVERS}
+
+\begin{verbatim}
+ FTVERS( > version)
+ FTGERR(status, > errtext)
+ FTGMSG( > errmsg)
+ FTRPRT (stream, > status)
+ FTPMSG(errmsg)
+ FTPMRK
+ FTCMSG
+ FTCMRK
+\end{verbatim}
+ FITS File Open and Close Subroutines: page~\pageref{FTOPEN}
+
+\begin{verbatim}
+ FTOPEN(unit,filename,rwmode, > blocksize,status)
+ FTDKOPEN(unit,filename,rwmode, > blocksize,status)
+ FTNOPN(unit,filename,rwmode, > status)
+ FTDOPN(unit,filename,rwmode, > status)
+ FTTOPN(unit,filename,rwmode, > status)
+ FTIOPN(unit,filename,rwmode, > status)
+ FTREOPEN(unit, > newunit, status)
+ FTINIT(unit,filename,blocksize, > status)
+ FTDKINIT(unit,filename,blocksize, > status)
+ FTTPLT(unit, filename, tplfilename, > status)
+ FTFLUS(unit, > status)
+ FTCLOS(unit, > status)
+ FTDELT(unit, > status)
+ FTGIOU( > iounit, status)
+ FTFIOU(iounit, > status)
+ CFITS2Unit(fitsfile *ptr) (C routine)
+ CUnit2FITS(int unit) (C routine)
+ FTEXTN(filename, > nhdu, status)
+ FTFLNM(unit, > filename, status)
+ FTFLMD(unit, > iomode, status)
+ FFURLT(unit, > urltype, status)
+ FTIURL(filename, > filetype, infile, outfile, extspec, filter,
+ binspec, colspec, status)
+ FTRTNM(filename, > rootname, status)
+ FTEXIST(filename, > exist, status)
+\end{verbatim}
+ HDU-Level Operations: page~\pageref{FTMAHD}
+
+\begin{verbatim}
+ FTMAHD(unit,nhdu, > hdutype,status)
+ FTMRHD(unit,nmove, > hdutype,status)
+ FTGHDN(unit, > nhdu)
+ FTMNHD(unit, hdutype, extname, extver, > status)
+ FTGHDT(unit, > hdutype, status)
+ FTTHDU(unit, > hdunum, status)
+ FTCRHD(unit, > status)
+ FTIIMG(unit,bitpix,naxis,naxes, > status)
+ FTITAB(unit,rowlen,nrows,tfields,ttype,tbcol,tform,tunit,extname, >
+ status)
+ FTIBIN(unit,nrows,tfields,ttype,tform,tunit,extname,varidat > status)
+ FTRSIM(unit,bitpix,naxis,naxes,status)
+ FTDHDU(unit, > hdutype,status)
+ FTCPFL(iunit,ounit,previous, current, following, > status)
+ FTCOPY(iunit,ounit,morekeys, > status)
+ FTCPHD(inunit, outunit, > status)
+ FTCPDT(iunit,ounit, > status)
+\end{verbatim}
+ Subroutines to specify or modify the structure of the CHDU: page~\pageref{FTRDEF}
+
+\begin{verbatim}
+ FTRDEF(unit, > status) (DEPRECATED)
+ FTPDEF(unit,bitpix,naxis,naxes,pcount,gcount, > status) (DEPRECATED)
+ FTADEF(unit,rowlen,tfields,tbcol,tform,nrows > status) (DEPRECATED)
+ FTBDEF(unit,tfields,tform,varidat,nrows > status) (DEPRECATED)
+ FTDDEF(unit,bytlen, > status) (DEPRECATED)
+ FTPTHP(unit,theap, > status)
+\end{verbatim}
+ Header Space and Position Subroutines: page~\pageref{FTHDEF}
+
+\begin{verbatim}
+ FTHDEF(unit,morekeys, > status)
+ FTGHSP(iunit, > keysexist,keysadd,status)
+ FTGHPS(iunit, > keysexist,key_no,status)
+\end{verbatim}
+ Read or Write Standard Header Subroutines: page~\pageref{FTPHPR}
+
+\begin{verbatim}
+ FTPHPS(unit,bitpix,naxis,naxes, > status)
+ FTPHPR(unit,simple,bitpix,naxis,naxes,pcount,gcount,extend, > status)
+ FTGHPR(unit,maxdim, > simple,bitpix,naxis,naxes,pcount,gcount,extend,
+ status)
+ FTPHTB(unit,rowlen,nrows,tfields,ttype,tbcol,tform,tunit,extname, >
+ status)
+ FTGHTB(unit,maxdim, > rowlen,nrows,tfields,ttype,tbcol,tform,tunit,
+ extname,status)
+ FTPHBN(unit,nrows,tfields,ttype,tform,tunit,extname,varidat > status)
+ FTGHBN(unit,maxdim, > nrows,tfields,ttype,tform,tunit,extname,varidat,
+ status)
+\end{verbatim}
+ Write Keyword Subroutines: page~\pageref{FTPREC}
+
+\begin{verbatim}
+ FTPREC(unit,card, > status)
+ FTPCOM(unit,comment, > status)
+ FTPHIS(unit,history, > status)
+ FTPDAT(unit, > status)
+ FTPKY[JLS](unit,keyword,keyval,comment, > status)
+ FTPKY[EDFG](unit,keyword,keyval,decimals,comment, > status)
+ FTPKLS(unit,keyword,keyval,comment, > status)
+ FTPLSW(unit, > status)
+ FTPKYU(unit,keyword,comment, > status)
+ FTPKN[JLS](unit,keyroot,startno,no_keys,keyvals,comments, > status)
+ FTPKN[EDFG](unit,keyroot,startno,no_keys,keyvals,decimals,comments, >
+ status)
+ FTCPKYinunit, outunit, innum, outnum, keyroot, > status)
+ FTPKYT(unit,keyword,intval,dblval,comment, > status)
+ FTPKTP(unit, filename, > status)
+ FTPUNT(unit,keyword,units, > status)
+\end{verbatim}
+ Insert Keyword Subroutines: page~\pageref{FTIREC}
+
+\begin{verbatim}
+ FTIREC(unit,key_no,card, > status)
+ FTIKY[JLS](unit,keyword,keyval,comment, > status)
+ FTIKLS(unit,keyword,keyval,comment, > status)
+ FTIKY[EDFG](unit,keyword,keyval,decimals,comment, > status)
+ FTIKYU(unit,keyword,comment, > status)
+\end{verbatim}
+ Read Keyword Subroutines: page~\pageref{FTGREC}
+
+\begin{verbatim}
+ FTGREC(unit,key_no, > card,status)
+ FTGKYN(unit,key_no, > keyword,value,comment,status)
+ FTGCRD(unit,keyword, > card,status)
+ FTGNXK(unit,inclist,ninc,exclist,nexc, > card,status)
+ FTGKEY(unit,keyword, > value,comment,status)
+ FTGKY[EDJLS](unit,keyword, > keyval,comment,status)
+ FTGKN[EDJLS](unit,keyroot,startno,max_keys, > keyvals,nfound,status)
+ FTGKYT(unit,keyword, > intval,dblval,comment,status)
+ FTGUNT(unit,keyword, > units,status)
+\end{verbatim}
+ Modify Keyword Subroutines: page~\pageref{FTMREC}
+
+\begin{verbatim}
+ FTMREC(unit,key_no,card, > status)
+ FTMCRD(unit,keyword,card, > status)
+ FTMNAM(unit,oldkey,keyword, > status)
+ FTMCOM(unit,keyword,comment, > status)
+ FTMKY[JLS](unit,keyword,keyval,comment, > status)
+ FTMKLS(unit,keyword,keyval,comment, > status)
+ FTMKY[EDFG](unit,keyword,keyval,decimals,comment, > status)
+ FTMKYU(unit,keyword,comment, > status)
+\end{verbatim}
+ Update Keyword Subroutines: page~\pageref{FTUCRD}
+
+\begin{verbatim}
+ FTUCRD(unit,keyword,card, > status)
+ FTUKY[JLS](unit,keyword,keyval,comment, > status)
+ FTUKLS(unit,keyword,keyval,comment, > status)
+ FTUKY[EDFG](unit,keyword,keyval,decimals,comment, > status)
+ FTUKYU(unit,keyword,comment, > status)
+\end{verbatim}
+ Delete Keyword Subroutines: page~\pageref{FTDREC}
+
+\begin{verbatim}
+ FTDREC(unit,key_no, > status)
+ FTDKEY(unit,keyword, > status)
+\end{verbatim}
+ Define Data Scaling Parameters and Undefined Pixel Flags: page~\pageref{FTPSCL}
+
+\begin{verbatim}
+ FTPSCL(unit,bscale,bzero, > status)
+ FTTSCL(unit,colnum,tscal,tzero, > status)
+ FTPNUL(unit,blank, > status)
+ FTSNUL(unit,colnum,snull > status)
+ FTTNUL(unit,colnum,tnull > status)
+\end{verbatim}
+ FITS Primary Array or IMAGE Extension I/O Subroutines: page~\pageref{FTPPR}
+
+\begin{verbatim}
+ FTGIDT(unit, > bitpix,status)
+ FTGIET(unit, > bitpix,status)
+ FTGIDM(unit, > naxis,status)
+ FTGISZ(unit, maxdim, > naxes,status)
+ FTGIPR(unit, maxdim, > bitpix,naxis,naxes,status)
+ FTPPR[BIJED](unit,group,fpixel,nelements,values, > status)
+ FTPPN[BIJED](unit,group,fpixel,nelements,values,nullval > status)
+ FTPPRU(unit,group,fpixel,nelements, > status)
+ FTGPV[BIJED](unit,group,fpixel,nelements,nullval, > values,anyf,status)
+ FTGPF[BIJED](unit,group,fpixel,nelements, > values,flagvals,anyf,status)
+ FTPGP[BIJED](unit,group,fparm,nparm,values, > status)
+ FTGGP[BIJED](unit,group,fparm,nparm, > values,status)
+ FTP2D[BIJED](unit,group,dim1,naxis1,naxis2,image, > status)
+ FTP3D[BIJED](unit,group,dim1,dim2,naxis1,naxis2,naxis3,cube, > status)
+ FTG2D[BIJED](unit,group,nullval,dim1,naxis1,naxis2, > image,anyf,status)
+ FTG3D[BIJED](unit,group,nullval,dim1,dim2,naxis1,naxis2,naxis3, >
+ cube,anyf,status)
+ FTPSS[BIJED](unit,group,naxis,naxes,fpixels,lpixels,array, > status)
+ FTGSV[BIJED](unit,group,naxis,naxes,fpixels,lpixels,incs,nullval, >
+ array,anyf,status)
+ FTGSF[BIJED](unit,group,naxis,naxes,fpixels,lpixels,incs, >
+ array,flagvals,anyf,status)
+\end{verbatim}
+ Table Column Information Subroutines: page~\pageref{FTGCNO}
+
+\begin{verbatim}
+ FTGNRW(unit, > nrows, status)
+ FTGNCL(unit, > ncols, status)
+ FTGCNO(unit,casesen,coltemplate, > colnum,status)
+ FTGCNN(unit,casesen,coltemplate, > colnam,colnum,status)
+ FTGTCL(unit,colnum, > datacode,repeat,width,status)
+ FTEQTY(unit,colnum, > datacode,repeat,width,status)
+ FTGCDW(unit,colnum, > dispwidth,status)
+ FTGACL(unit,colnum, >
+ ttype,tbcol,tunit,tform,tscal,tzero,snull,tdisp,status)
+ FTGBCL(unit,colnum, >
+ ttype,tunit,datatype,repeat,tscal,tzero,tnull,tdisp,status)
+ FTPTDM(unit,colnum,naxis,naxes, > status)
+ FTGTDM(unit,colnum,maxdim, > naxis,naxes,status)
+ FTDTDM(unit,tdimstr,colnum,maxdim, > naxis,naxes, status)
+ FFGRSZ(unit, > nrows,status)
+\end{verbatim}
+ Low-Level Table Access Subroutines: page~\pageref{FTGTBS}
+
+\begin{verbatim}
+ FTGTBS(unit,frow,startchar,nchars, > string,status)
+ FTPTBS(unit,frow,startchar,nchars,string, > status)
+ FTGTBB(unit,frow,startchar,nchars, > array,status)
+ FTPTBB(unit,frow,startchar,nchars,array, > status)
+\end{verbatim}
+ Edit Rows or Columns page~\pageref{FTIROW}
+
+\begin{verbatim}
+ FTIROW(unit,frow,nrows, > status)
+ FTDROW(unit,frow,nrows, > status)
+ FTDRRG(unit,rowrange, > status)
+ FTDRWS(unit,rowlist,nrows, > status)
+ FTICOL(unit,colnum,ttype,tform, > status)
+ FTICLS(unit,colnum,ncols,ttype,tform, > status)
+ FTMVEC(unit,colnum,newveclen, > status)
+ FTDCOL(unit,colnum, > status)
+ FTCPCL(inunit,outunit,incolnum,outcolnum,createcol, > status);
+\end{verbatim}
+ Read and Write Column Data Routines page~\pageref{FTPCLS}
+
+\begin{verbatim}
+ FTPCL[SLBIJEDCM](unit,colnum,frow,felem,nelements,values, > status)
+ FTPCN[BIJED](unit,colnum,frow,felem,nelements,values,nullval > status)
+ FTPCLX(unit,colnum,frow,fbit,nbit,lray, > status)
+ FTPCLU(unit,colnum,frow,felem,nelements, > status)
+ FTGCL(unit,colnum,frow,felem,nelements, > values,status)
+ FTGCV[SBIJEDCM](unit,colnum,frow,felem,nelements,nullval, >
+ values,anyf,status)
+ FTGCF[SLBIJEDCM](unit,colnum,frow,felem,nelements, >
+ values,flagvals,anyf,status)
+ FTGSV[BIJED](unit,colnum,naxis,naxes,fpixels,lpixels,incs,nullval, >
+ array,anyf,status)
+ FTGSF[BIJED](unit,colnum,naxis,naxes,fpixels,lpixels,incs, >
+ array,flagvals,anyf,status)
+ FTGCX(unit,colnum,frow,fbit,nbit, > lray,status)
+ FTGCX[IJD](unit,colnum,frow,nrows,fbit,nbit, > array,status)
+ FTGDES(unit,colnum,rownum, > nelements,offset,status)
+ FTPDES(unit,colnum,rownum,nelements,offset, > status)
+\end{verbatim}
+ Row Selection and Calculator Routines: page~\pageref{FTFROW}
+
+\begin{verbatim}
+ FTFROW(unit,expr,firstrow, nrows, > n_good_rows, row_status, status)
+ FTFFRW(unit, expr, > rownum, status)
+ FTSROW(inunit, outunit, expr, > status )
+ FTCROW(unit,datatype,expr,firstrow,nelements,nulval, >
+ array,anynul,status)
+ FTCALC(inunit, expr, outunit, parName, parInfo, > status)
+ FTCALC_RNG(inunit, expr, outunit, parName, parInfo,
+ nranges, firstrow, lastrow, > status)
+ FTTEXP(unit, expr, > datatype, nelem, naxis, naxes, status)
+\end{verbatim}
+ Celestial Coordinate System Subroutines: page~\pageref{FTGICS}
+
+\begin{verbatim}
+ FTGICS(unit, > xrval,yrval,xrpix,yrpix,xinc,yinc,rot,coordtype,status)
+ FTGTCS(unit,xcol,ycol, >
+ xrval,yrval,xrpix,yrpix,xinc,yinc,rot,coordtype,status)
+ FTWLDP(xpix,ypix,xrval,yrval,xrpix,yrpix,xinc,yinc,rot,
+ coordtype, > xpos,ypos,status)
+ FTXYPX(xpos,ypos,xrval,yrval,xrpix,yrpix,xinc,yinc,rot,
+ coordtype, > xpix,ypix,status)
+\end{verbatim}
+ File Checksum Subroutines: page~\pageref{FTPCKS}
+
+\begin{verbatim}
+ FTPCKS(unit, > status)
+ FTUCKS(unit, > status)
+ FTVCKS(unit, > dataok,hduok,status)
+ FTGCKS(unit, > datasum,hdusum,status)
+ FTESUM(sum,complement, > checksum)
+ FTDSUM(checksum,complement, > sum)
+
+\end{verbatim}
+ Time and Date Utility Subroutines: page~\pageref{FTGSDT}
+
+\begin{verbatim}
+ FTGSDT( > day, month, year, status )
+ FTGSTM(> datestr, timeref, status)
+ FTDT2S( year, month, day, > datestr, status)
+ FTTM2S( year, month, day, hour, minute, second, decimals,
+ > datestr, status)
+ FTS2DT(datestr, > year, month, day, status)
+ FTS2TM(datestr, > year, month, day, hour, minute, second, status)
+\end{verbatim}
+ General Utility Subroutines: page~\pageref{FTGHAD}
+
+\begin{verbatim}
+ FTGHAD(unit, > curaddr,nextaddr)
+ FTUPCH(string)
+ FTCMPS(str_template,string,casesen, > match,exact)
+ FTTKEY(keyword, > status)
+ FTTREC(card, > status)
+ FTNCHK(unit, > status)
+ FTGKNM(unit, > keyword, keylength, status)
+ FTPSVC(card, > value,comment,status)
+ FTKEYN(keyroot,seq_no, > keyword,status)
+ FTNKEY(seq_no,keyroot, > keyword,status)
+ FTDTYP(value, > dtype,status)
+ class = FTGKCL(card)
+ FTASFM(tform, > datacode,width,decimals,status)
+ FTBNFM(tform, > datacode,repeat,width,status)
+ FTGABC(tfields,tform,space, > rowlen,tbcol,status)
+ FTGTHD(template, > card,hdtype,status)
+ FTRWRG(rowlist, maxrows, maxranges, > numranges, rangemin,
+ rangemax, status)
+\end{verbatim}
+
+\chapter{ Parameter Definitions }
+
+\begin{verbatim}
+anyf - (logical) set to TRUE if any of the returned data values are undefined
+array - (any datatype except character) array of bytes to be read or written.
+bitpix - (integer) bits per pixel: 8, 16, 32, -32, or -64
+blank - (integer) value used for undefined pixels in integer primary array
+blocksize - (integer) 2880-byte logical record blocking factor
+ (if 0 < blocksize < 11) or the actual block size in bytes
+ (if 10 < blocksize < 28800). As of version 3.3 of FITSIO,
+ blocksizes greater than 2880 are no longer supported.
+bscale - (double precision) scaling factor for the primary array
+bytlen - (integer) length of the data unit, in bytes
+bzero - (double precision) zero point for primary array scaling
+card - (character*80) header record to be read or written
+casesen - (logical) will string matching be case sensitive?
+checksum - (character*16) encoded checksum string
+colname - (character) ASCII name of the column
+colnum - (integer) number of the column (first column = 1)
+coltemplate - (character) template string to be matched to column names
+comment - (character) the keyword comment field
+comments - (character array) keyword comment fields
+compid - (integer) the type of computer that the program is running on
+complement - (logical) should the checksum be complemented?
+coordtype - (character) type of coordinate projection (-SIN, -TAN, -ARC,
+ -NCP, -GLS, -MER, or -AIT)
+cube - 3D data cube of the appropriate datatype
+curaddr - (integer) starting address (in bytes) of the CHDU
+datacode - (integer) symbolic code of the binary table column datatype
+dataok - (integer) was the data unit verification successful (=1) or
+ not (= -1). Equals zero if the DATASUM keyword is not present.
+datasum - (double precision) 32-bit 1's complement checksum for the data unit
+datatype - (character) datatype (format) of the binary table column
+datestr - (string) FITS date/time string: 'YYYY-MM-DDThh:mm:ss.ddd',
+ 'YYYY-MM-dd', or 'dd/mm/yy'
+day - (integer) current day of the month
+dblval - (double precision) fractional part of the keyword value
+decimals - (integer) number of decimal places to be displayed
+dim1 - (integer) actual size of the first dimension of the image or cube array
+dim2 - (integer) actual size of the second dimension of the cube array
+dispwidth - (integer) - the display width (length of string) for a column
+dtype - (character) datatype of the keyword ('C', 'L', 'I', or 'F')
+ C = character string
+ L = logical
+ I = integer
+ F = floating point number
+errmsg - (character*80) oldest error message on the internal stack
+errtext - (character*30) descriptive error message corresponding to error number
+casesen - (logical) true if column name matching is case sensitive
+exact - (logical) do the strings match exactly, or were wildcards used?
+exclist (character array) list of names to be excluded from search
+exists - flag indicating whether the file or compressed file exists on disk
+extend - (logical) true if there may be extensions following the primary data
+extname - (character) value of the EXTNAME keyword (if not blank)
+fbit - (integer) first bit in the field to be read or written
+felem - (integer) first pixel of the element vector (ignored for ASCII tables)
+filename - (character) name of the FITS file
+flagvals - (logical array) True if corresponding data element is undefined
+fparm - (integer) sequence number of the first group parameter to read or write
+fpixel - (integer) the first pixel position
+fpixels - (integer array) the first included pixel in each dimension
+frow - (integer) beginning row number (first row of table = 1)
+gcount - (integer) value of the GCOUNT keyword (usually = 1)
+group - (integer) sequence number of the data group (=0 for non-grouped data)
+hdtype - (integer) header record type: -1=delete; 0=append or replace;
+ 1=append; 2=this is the END keyword
+hduok - (integer) was the HDU verification successful (=1) or
+ not (= -1). Equals zero if the CHECKSUM keyword is not present.
+hdusum - (double precision) 32 bit 1's complement checksum for the entire CHDU
+hdutype - (integer) type of HDU: 0 = primary array or IMAGE, 1 = ASCII table,
+ 2 = binary table, -1 = unknown
+history - (character) the HISTORY keyword comment string
+hour - (integer) hour from 0 - 23
+image - 2D image of the appropriate datatype
+inclist (character array) list of names to be included in search
+incs - (integer array) sampling interval for pixels in each FITS dimension
+intval - (integer) integer part of the keyword value
+iounit - (integer) value of an unused I/O unit number
+iunit - (integer) logical unit number associated with the input FITS file, 1-199
+key_no - (integer) sequence number (starting with 1) of the keyword record
+keylength - (integer) length of the keyword name
+keyroot - (character) root string for the keyword name
+keysadd -(integer) number of new keyword records which can fit in the CHU
+keysexist - (integer) number of existing keyword records in the CHU
+keyval - value of the keyword in the appropriate datatype
+keyvals - (array) value of the keywords in the appropriate datatype
+keyword - (character*8) name of a keyword
+lray - (logical array) array of logical values corresponding to the bit array
+lpixels - (integer array) the last included pixel in each dimension
+match - (logical) do the 2 strings match?
+maxdim - (integer) dimensioned size of the NAXES, TTYPE, TFORM or TUNIT arrays
+max_keys - (integer) maximum number of keywords to search for
+minute - (integer) minute of an hour (0 - 59)
+month - (integer) current month of the year (1 - 12)
+morekeys - (integer) will leave space in the header for this many more keywords
+naxes - (integer array) size of each dimension in the FITS array
+naxis - (integer) number of dimensions in the FITS array
+naxis1 - (integer) length of the X/first axis of the FITS array
+naxis2 - (integer) length of the Y/second axis of the FITS array
+naxis3 - (integer) length of the Z/third axis of the FITS array
+nbit - (integer) number of bits in the field to read or write
+nchars - (integer) number of characters to read and return
+ncols - (integer) number of columns
+nelements - (integer) number of data elements to read or write
+nexc (integer) number of names in the exclusion list (may = 0)
+nhdu - (integer) absolute number of the HDU (1st HDU = 1)
+ninc (integer) number of names in the inclusion list
+nmove - (integer) number of HDUs to move (+ or -), relative to current position
+nfound - (integer) number of keywords found (highest keyword number)
+no_keys - (integer) number of keywords to write in the sequence
+nparm - (integer) number of group parameters to read or write
+nrows - (integer) number of rows in the table
+nullval - value to represent undefined pixels, of the appropriate datatype
+nextaddr - (integer) starting address (in bytes) of the HDU following the CHDU
+offset - (integer) byte offset in the heap to the first element of the array
+oldkey - (character) old name of keyword to be modified
+ounit - (integer) logical unit number associated with the output FITS file 1-199
+pcount - (integer) value of the PCOUNT keyword (usually = 0)
+repeat - (integer) length of element vector (e.g. 12J); ignored for ASCII table
+rot - (double precision) celestial coordinate rotation angle (degrees)
+rowlen - (integer) length of a table row, in characters or bytes
+rowlist - (integer array) list of row numbers to be deleted in increasing order
+rownum - (integer) number of the row (first row = 1)
+rowrange- (string) list of rows or row ranges to be deleted
+rwmode - (integer) file access mode: 0 = readonly, 1 = readwrite
+second (double)- second within minute (0 - 60.9999999999) (leap second!)
+seq_no - (integer) the sequence number to append to the keyword root name
+simple - (logical) does the FITS file conform to all the FITS standards
+snull - (character) value used to represent undefined values in ASCII table
+space - (integer) number of blank spaces to leave between ASCII table columns
+startchar - (integer) first character in the row to be read
+startno - (integer) value of the first keyword sequence number (usually 1)
+status - (integer) returned error status code (0 = OK)
+str_template (character) template string to be matched to reference string
+stream - (character) output stream for the report: either 'STDOUT' or 'STDERR'
+string - (character) character string
+sum - (double precision) 32 bit unsigned checksum value
+tbcol - (integer array) column number of the first character in the field(s)
+tdisp - (character) Fortran type display format for the table column
+template-(character) template string for a FITS header record
+tfields - (integer) number of fields (columns) in the table
+tform - (character array) format of the column(s); allowed values are:
+ For ASCII tables: Iw, Aw, Fww.dd, Eww.dd, or Dww.dd
+ For binary tables: rL, rX, rB, rI, rJ, rA, rAw, rE, rD, rC, rM
+ where 'w'=width of the field, 'd'=no. of decimals, 'r'=repeat count
+ Note that the 'rAw' form is non-standard extension to the
+ TFORM keyword syntax that is not specifically defined in the
+ Binary Tables definition document.
+theap - (integer) zero indexed byte offset of starting address of the heap
+ relative to the beginning of the binary table data
+tnull - (integer) value used to represent undefined values in binary table
+ttype - (character array) label for table column(s)
+tscal - (double precision) scaling factor for table column
+tunit - (character array) physical unit for table column(s)
+tzero - (double precision) scaling zero point for table column
+unit - (integer) logical unit number associated with the FITS file (1-199)
+units - (character) the keyword units string (e.g., 'km/s')
+value - (character) the keyword value string
+values - array of data values of the appropriate datatype
+varidat - (integer) size in bytes of the 'variable length data area'
+ following the binary table data (usually = 0)
+version - (real) current revision number of the library
+width - (integer) width of the character string field
+xcol - (integer) number of the column containing the X coordinate values
+xinc - (double precision) X axis coordinate increment at reference pixel (deg)
+xpix - (double precision) X axis pixel location
+xpos - (double precision) X axis celestial coordinate (usually RA) (deg)
+xrpix - (double precision) X axis reference pixel array location
+xrval - (double precision) X axis coordinate value at the reference pixel (deg)
+ycol - (integer) number of the column containing the X coordinate values
+year - (integer) last 2 digits of the year (00 - 99)
+yinc - (double precision) Y axis coordinate increment at reference pixel (deg)
+ypix - (double precision) y axis pixel location
+ypos - (double precision) y axis celestial coordinate (usually DEC) (deg)
+yrpix - (double precision) Y axis reference pixel array location
+yrval - (double precision) Y axis coordinate value at the reference pixel (deg)
+\end{verbatim}
+
+\chapter{ FITSIO Error Status Codes }
+
+\begin{verbatim}
+Status codes in the range -99 to -999 and 1 to 999 are reserved for future
+FITSIO use.
+
+ 0 OK, no error
+101 input and output files are the same
+103 too many FITS files open at once; all internal buffers full
+104 error opening existing file
+105 error creating new FITS file; (does a file with this name already exist?)
+106 error writing record to FITS file
+107 end-of-file encountered while reading record from FITS file
+108 error reading record from file
+110 error closing FITS file
+111 internal array dimensions exceeded
+112 Cannot modify file with readonly access
+113 Could not allocate memory
+114 illegal logical unit number; must be between 1 - 199, inclusive
+115 NULL input pointer to routine
+116 error seeking position in file
+
+121 invalid URL prefix on file name
+122 tried to register too many IO drivers
+123 driver initialization failed
+124 matching driver is not registered
+125 failed to parse input file URL
+126 parse error in range list
+
+151 bad argument in shared memory driver
+152 null pointer passed as an argument
+153 no more free shared memory handles
+154 shared memory driver is not initialized
+155 IPC error returned by a system call
+156 no memory in shared memory driver
+157 resource deadlock would occur
+158 attempt to open/create lock file failed
+159 shared memory block cannot be resized at the moment
+
+
+201 header not empty; can't write required keywords
+202 specified keyword name was not found in the header
+203 specified header record number is out of bounds
+204 keyword value field is blank
+205 keyword value string is missing the closing quote character
+207 illegal character in keyword name or header record
+208 keyword does not have expected name. Keyword out of sequence?
+209 keyword does not have expected integer value
+210 could not find the required END header keyword
+211 illegal BITPIX keyword value
+212 illegal NAXIS keyword value
+213 illegal NAXISn keyword value: must be 0 or positive integer
+214 illegal PCOUNT keyword value
+215 illegal GCOUNT keyword value
+216 illegal TFIELDS keyword value
+217 negative ASCII or binary table width value (NAXIS1)
+218 negative number of rows in ASCII or binary table (NAXIS2)
+219 column name (TTYPE keyword) not found
+220 illegal SIMPLE keyword value
+221 could not find the required SIMPLE header keyword
+222 could not find the required BITPIX header keyword
+223 could not find the required NAXIS header keyword
+224 could not find all the required NAXISn keywords in the header
+225 could not find the required XTENSION header keyword
+226 the CHDU is not an ASCII table extension
+227 the CHDU is not a binary table extension
+228 could not find the required PCOUNT header keyword
+229 could not find the required GCOUNT header keyword
+230 could not find the required TFIELDS header keyword
+231 could not find all the required TBCOLn keywords in the header
+232 could not find all the required TFORMn keywords in the header
+233 the CHDU is not an IMAGE extension
+234 illegal TBCOL keyword value; out of range
+235 this operation only allowed for ASCII or BINARY table extension
+236 column is too wide to fit within the specified width of the ASCII table
+237 the specified column name template matched more than one column name
+241 binary table row width is not equal to the sum of the field widths
+251 unrecognizable type of FITS extension
+252 unrecognizable FITS record
+253 END keyword contains non-blank characters in columns 9-80
+254 Header fill area contains non-blank characters
+255 Data fill area contains non-blank on non-zero values
+261 unable to parse the TFORM keyword value string
+262 unrecognizable TFORM datatype code
+263 illegal TDIMn keyword value
+
+301 illegal HDU number; less than 1 or greater than internal buffer size
+302 column number out of range (1 - 999)
+304 attempt to move to negative file record number
+306 attempted to read or write a negative number of bytes in the FITS file
+307 illegal starting row number for table read or write operation
+308 illegal starting element number for table read or write operation
+309 attempted to read or write character string in non-character table column
+310 attempted to read or write logical value in non-logical table column
+311 illegal ASCII table TFORM format code for attempted operation
+312 illegal binary table TFORM format code for attempted operation
+314 value for undefined pixels has not been defined
+317 attempted to read or write descriptor in a non-descriptor field
+320 number of array dimensions out of range
+321 first pixel number is greater than the last pixel number
+322 attempt to set BSCALE or TSCALn scaling parameter = 0
+323 illegal axis length less than 1
+
+340 NOT_GROUP_TABLE 340 Grouping function error
+341 HDU_ALREADY_MEMBER
+342 MEMBER_NOT_FOUND
+343 GROUP_NOT_FOUND
+344 BAD_GROUP_ID
+345 TOO_MANY_HDUS_TRACKED
+346 HDU_ALREADY_TRACKED
+347 BAD_OPTION
+348 IDENTICAL_POINTERS
+349 BAD_GROUP_ATTACH
+350 BAD_GROUP_DETACH
+
+360 NGP_NO_MEMORY malloc failed
+361 NGP_READ_ERR read error from file
+362 NGP_NUL_PTR null pointer passed as an argument.
+ Passing null pointer as a name of
+ template file raises this error
+363 NGP_EMPTY_CURLINE line read seems to be empty (used
+ internally)
+364 NGP_UNREAD_QUEUE_FULL cannot unread more then 1 line (or single
+ line twice)
+365 NGP_INC_NESTING too deep include file nesting (infinite
+ loop, template includes itself ?)
+366 NGP_ERR_FOPEN fopen() failed, cannot open template file
+367 NGP_EOF end of file encountered and not expected
+368 NGP_BAD_ARG bad arguments passed. Usually means
+ internal parser error. Should not happen
+369 NGP_TOKEN_NOT_EXPECT token not expected here
+
+401 error attempting to convert an integer to a formatted character string
+402 error attempting to convert a real value to a formatted character string
+403 cannot convert a quoted string keyword to an integer
+404 attempted to read a non-logical keyword value as a logical value
+405 cannot convert a quoted string keyword to a real value
+406 cannot convert a quoted string keyword to a double precision value
+407 error attempting to read character string as an integer
+408 error attempting to read character string as a real value
+409 error attempting to read character string as a double precision value
+410 bad keyword datatype code
+411 illegal number of decimal places while formatting floating point value
+412 numerical overflow during implicit datatype conversion
+413 error compressing image
+414 error uncompressing image
+420 error in date or time conversion
+
+431 syntax error in parser expression
+432 expression did not evaluate to desired type
+433 vector result too large to return in array
+434 data parser failed not sent an out column
+435 bad data encounter while parsing column
+436 parse error: output file not of proper type
+
+501 celestial angle too large for projection
+502 bad celestial coordinate or pixel value
+503 error in celestial coordinate calculation
+504 unsupported type of celestial projection
+505 required celestial coordinate keywords not found
+506 approximate wcs keyword values were returned
+\end{verbatim}
+\end{document}
diff --git a/pkg/tbtables/cfitsio/fitsio.toc b/pkg/tbtables/cfitsio/fitsio.toc
new file mode 100644
index 00000000..2f800381
--- /dev/null
+++ b/pkg/tbtables/cfitsio/fitsio.toc
@@ -0,0 +1,90 @@
+\contentsline {chapter}{\numberline {1}Introduction }{1}
+\contentsline {chapter}{\numberline {2} Creating FITSIO/CFITSIO }{3}
+\contentsline {section}{\numberline {2.1}Building the Library}{3}
+\contentsline {section}{\numberline {2.2}Testing the Library}{6}
+\contentsline {section}{\numberline {2.3}Linking Programs with FITSIO}{7}
+\contentsline {section}{\numberline {2.4}Getting Started with FITSIO}{8}
+\contentsline {section}{\numberline {2.5}Example Program}{8}
+\contentsline {section}{\numberline {2.6}Legal Stuff}{9}
+\contentsline {section}{\numberline {2.7}Acknowledgements}{10}
+\contentsline {chapter}{\numberline {3} A FITS Primer }{13}
+\contentsline {chapter}{\numberline {4} Extended File Name Syntax }{15}
+\contentsline {section}{\numberline {4.1}Overview}{15}
+\contentsline {section}{\numberline {4.2}Filetype}{18}
+\contentsline {subsection}{\numberline {4.2.1}Notes about HTTP proxy servers}{18}
+\contentsline {subsection}{\numberline {4.2.2}Notes about the root filetype}{18}
+\contentsline {subsection}{\numberline {4.2.3}Notes about the shmem filetype:}{20}
+\contentsline {section}{\numberline {4.3}Base Filename}{21}
+\contentsline {section}{\numberline {4.4}Output File Name when Opening an Existing File}{23}
+\contentsline {section}{\numberline {4.5}Template File Name when Creating a New File}{24}
+\contentsline {section}{\numberline {4.6}HDU Location Specification}{24}
+\contentsline {section}{\numberline {4.7}Image Section}{25}
+\contentsline {section}{\numberline {4.8}Column and Keyword Filtering Specification}{26}
+\contentsline {section}{\numberline {4.9}Row Filtering Specification}{28}
+\contentsline {subsection}{\numberline {4.9.1}General Syntax}{28}
+\contentsline {subsection}{\numberline {4.9.2}Bit Masks}{30}
+\contentsline {subsection}{\numberline {4.9.3}Vector Columns}{31}
+\contentsline {subsection}{\numberline {4.9.4}Good Time Interval Filtering}{33}
+\contentsline {subsection}{\numberline {4.9.5}Spatial Region Filtering}{33}
+\contentsline {subsection}{\numberline {4.9.6}Example Row Filters}{36}
+\contentsline {section}{\numberline {4.10} Binning or Histogramming Specification}{37}
+\contentsline {chapter}{\numberline {5}Template Files }{41}
+\contentsline {section}{\numberline {5.1}Detailed Template Line Format}{41}
+\contentsline {section}{\numberline {5.2}Auto-indexing of Keywords}{42}
+\contentsline {section}{\numberline {5.3}Template Parser Directives}{43}
+\contentsline {section}{\numberline {5.4}Formal Template Syntax}{43}
+\contentsline {section}{\numberline {5.5}Errors}{44}
+\contentsline {section}{\numberline {5.6}Examples}{44}
+\contentsline {chapter}{\numberline {6}FITSIO Conventions and Guidelines }{47}
+\contentsline {section}{\numberline {6.1}CFITSIO Size Limitations}{47}
+\contentsline {section}{\numberline {6.2}Multiple Access to the Same FITS File}{48}
+\contentsline {section}{\numberline {6.3}Current Header Data Unit (CHDU)}{48}
+\contentsline {section}{\numberline {6.4}Subroutine Names}{48}
+\contentsline {section}{\numberline {6.5}Subroutine Families and Datatypes}{49}
+\contentsline {section}{\numberline {6.6}Implicit Data Type Conversion}{50}
+\contentsline {section}{\numberline {6.7}Data Scaling}{50}
+\contentsline {section}{\numberline {6.8}Error Status Values and the Error Message Stack}{51}
+\contentsline {section}{\numberline {6.9}Variable-Length Array Facility in Binary Tables}{51}
+\contentsline {section}{\numberline {6.10}Support for IEEE Special Values}{52}
+\contentsline {section}{\numberline {6.11}When the Final Size of the FITS HDU is Unknown}{53}
+\contentsline {section}{\numberline {6.12}Local FITS Conventions supported by FITSIO}{53}
+\contentsline {subsection}{\numberline {6.12.1}Support for Long String Keyword Values.}{54}
+\contentsline {subsection}{\numberline {6.12.2}Arrays of Fixed-Length Strings in Binary Tables}{54}
+\contentsline {subsection}{\numberline {6.12.3}Keyword Units Strings}{55}
+\contentsline {subsection}{\numberline {6.12.4}HIERARCH Convention for Extended Keyword Names}{55}
+\contentsline {section}{\numberline {6.13}Optimizing Code for Maximum Processing Speed}{56}
+\contentsline {subsection}{\numberline {6.13.1}Background Information: How CFITSIO Manages Data I/O}{57}
+\contentsline {chapter}{\numberline {7} The CFITSIO Iterator Function }{61}
+\contentsline {chapter}{\numberline {8} Basic Interface Routines }{63}
+\contentsline {section}{\numberline {8.1}FITSIO Error Status Routines }{63}
+\contentsline {section}{\numberline {8.2}File I/O Routines}{64}
+\contentsline {section}{\numberline {8.3}Keyword I/O Routines}{66}
+\contentsline {section}{\numberline {8.4}Data I/O Routines}{66}
+\contentsline {chapter}{\numberline {9} Advanced Interface Subroutines }{69}
+\contentsline {section}{\numberline {9.1}FITS File Open and Close Subroutines: }{69}
+\contentsline {section}{\numberline {9.2}HDU-Level Operations }{72}
+\contentsline {section}{\numberline {9.3}Define or Redefine the structure of the CHDU }{75}
+\contentsline {section}{\numberline {9.4}FITS Header I/O Subroutines}{76}
+\contentsline {subsection}{\numberline {9.4.1}Header Space and Position Routines }{76}
+\contentsline {subsection}{\numberline {9.4.2}Read or Write Standard Header Routines }{77}
+\contentsline {subsection}{\numberline {9.4.3}Write Keyword Subroutines }{78}
+\contentsline {subsection}{\numberline {9.4.4}Insert Keyword Subroutines }{80}
+\contentsline {subsection}{\numberline {9.4.5}Read Keyword Subroutines }{81}
+\contentsline {subsection}{\numberline {9.4.6}Modify Keyword Subroutines }{82}
+\contentsline {subsection}{\numberline {9.4.7}Update Keyword Subroutines }{83}
+\contentsline {subsection}{\numberline {9.4.8}Delete Keyword Subroutines }{84}
+\contentsline {section}{\numberline {9.5}Data Scaling and Undefined Pixel Parameters }{84}
+\contentsline {section}{\numberline {9.6}FITS Primary Array or IMAGE Extension I/O Subroutines }{85}
+\contentsline {section}{\numberline {9.7}FITS ASCII and Binary Table Data I/O Subroutines}{88}
+\contentsline {subsection}{\numberline {9.7.1}Column Information Subroutines }{88}
+\contentsline {subsection}{\numberline {9.7.2}Low-Level Table Access Subroutines }{91}
+\contentsline {subsection}{\numberline {9.7.3}Edit Rows or Columns }{92}
+\contentsline {subsection}{\numberline {9.7.4}Read and Write Column Data Routines }{93}
+\contentsline {section}{\numberline {9.8}Row Selection and Calculator Routines }{96}
+\contentsline {section}{\numberline {9.9}Celestial Coordinate System Subroutines }{98}
+\contentsline {section}{\numberline {9.10}File Checksum Subroutines }{99}
+\contentsline {section}{\numberline {9.11} Date and Time Utility Routines }{101}
+\contentsline {section}{\numberline {9.12}General Utility Subroutines }{102}
+\contentsline {chapter}{\numberline {10} Summary of all FITSIO User-Interface Subroutines }{109}
+\contentsline {chapter}{\numberline {11} Parameter Definitions }{117}
+\contentsline {chapter}{\numberline {12} FITSIO Error Status Codes }{123}
diff --git a/pkg/tbtables/cfitsio/fitsio2.h b/pkg/tbtables/cfitsio/fitsio2.h
new file mode 100644
index 00000000..6910a57e
--- /dev/null
+++ b/pkg/tbtables/cfitsio/fitsio2.h
@@ -0,0 +1,1135 @@
+#ifndef _FITSIO2_H
+#define _FITSIO2_H
+
+#include "fitsio.h"
+
+/* Setting SUPPORT_64_BIT_INTEGERS to 1 will enable CFITSIO to read */
+/* and write images with BITPIX = 64 and binary table columns with */
+/* TFORMn = 'K'. Otherwise, setting SUPPORT_64_BIT_INTEGERS to 0 */
+/* will cause CFITSIO to not recognize these non-standard 64-bit */
+/* FITS datatypes. */
+
+#define SUPPORT_64BIT_INTEGERS 1
+
+/*
+ If REPLACE_LINKS is defined, then whenever CFITSIO fails to open
+ a file with write access because it is a soft link to a file that
+ only has read access, then CFITSIO will attempt to replace
+ the link with a local copy of the file, with write access. This
+ feature was originally added to support the ftools in the Hera
+ environment, where many of the user's data file are soft links.
+*/
+#if defined(BUILD_HERA)
+#define REPLACE_LINKS 1
+#endif
+
+#define USE_LARGE_VALUE -99 /* flag used when writing images */
+
+#define DBUFFSIZE 28800 /* size of data buffer in bytes */
+
+#define NIOBUF 40 /* number of IO buffers to create */
+ /* !! Significantly increasing NIOBUF may degrade performance !! */
+#define NMAXFILES 300 /* maximum number of FITS files that can be opened */
+ /* CFITSIO will allocate (NMAXFILES * 80) bytes of memory */
+
+#define IOBUFLEN 2880 /* size in bytes of each IO buffer (DONT CHANGE!) */
+#define MINDIRECT 8640 /* minimum size for direct reads and writes */
+ /* MINDIRECT must have a value >= 8640 */
+
+#define NATIVE 0 /* a generic machine that uses IEEE formats */
+#define ULTRIX 1
+#define ALPHA_OSF 2
+#define VAXVMS 3
+#define ALPHAVMS 4
+#define IBMPC 5
+#define CRAY 6
+#define PC64BIT 7
+
+#define GFLOAT 1
+#define IEEEFLOAT 2
+
+/* the following are used to determine what type machine we are running on */
+
+/* the following block determines the size of longs on SGI IRIX machines */
+#if defined(_MIPS_SZLONG)
+# if _MIPS_SZLONG == 32
+# define LONGSIZE 32
+# elif _MIPS_SZLONG == 64
+# define LONGSIZE 64
+# else
+# error "can't handle long size given by _MIPS_SZLONG"
+# endif
+#endif
+
+#if defined(vax) && defined(VMS)
+
+#define MACHINE VAXVMS
+#define BYTESWAPPED TRUE
+
+#elif defined(__alpha) && defined(__VMS)
+
+#if (__D_FLOAT == TRUE)
+
+/* this float option is the same as for VAX/VMS machines. */
+#define MACHINE VAXVMS
+#define BYTESWAPPED TRUE
+
+#elif (__G_FLOAT == TRUE)
+
+/* G_FLOAT is the default for ALPHA VMS systems */
+#define MACHINE ALPHAVMS
+#define BYTESWAPPED TRUE
+#define FLOATTYPE GFLOAT
+
+#elif (__IEEE_FLOAT == TRUE)
+
+#define MACHINE ALPHAVMS
+#define BYTESWAPPED TRUE
+#define FLOATTYPE IEEEFLOAT
+
+#endif
+
+#elif defined(__alpha) && ( defined(__unix__) || defined(__NetBSD__) )
+
+#define MACHINE ALPHA_OSF
+#define BYTESWAPPED TRUE
+#define LONGSIZE 64
+
+#elif defined(ultrix) && defined(unix)
+
+#define MACHINE ULTRIX
+#define BYTESWAPPED TRUE
+
+#elif defined(__sparcv9)
+
+/* SUN Solaris7 in 64-bit mode */
+#define BYTESWAPPED FALSE
+#define MACHINE NATIVE
+#define LONGSIZE 64
+
+#elif defined(__i386) || defined(__i386__) || defined(__i486__) || defined(__i586__)
+
+/* IBM PC */
+#define MACHINE IBMPC
+#define BYTESWAPPED TRUE
+
+#elif defined(_MSC_VER) || defined(__BORLANDC__) || defined(__TURBOC__)
+
+/* IBM PC running DOS or Windows */
+#define MACHINE IBMPC
+#define BYTESWAPPED TRUE
+
+#elif defined(_NI_mswin_) || defined(__EMX__)
+
+/* LabWindows/CVI with Windows, or PC runnin OS/2 */
+#define MACHINE IBMPC
+#define BYTESWAPPED TRUE
+
+#elif defined(__ia64__) || defined(__x86_64__)
+
+/* Intel itanium 64-bit PC, or AMD opteron 64-bit PC */
+#define BYTESWAPPED TRUE
+#define MACHINE PC64BIT
+#define LONGSIZE 64
+
+#else
+
+/* assume machine uses the same IEEE formats as used in FITS files */
+#define MACHINE NATIVE
+#define BYTESWAPPED FALSE
+
+#endif
+
+/* assume longs are 4 bytes long, unless previously set otherwise */
+#ifndef LONGSIZE
+#define LONGSIZE 32
+#endif
+
+#define IGNORE_EOF 1
+#define REPORT_EOF 0
+#define DATA_UNDEFINED -1
+#define NULL_UNDEFINED 1234554321
+#define ASCII_NULL_UNDEFINED 1 /* indicate no defined null value */
+
+#define maxvalue(A,B) ((A) > (B) ? (A) : (B))
+#define minvalue(A,B) ((A) < (B) ? (A) : (B))
+
+/* faster string comparison macros */
+#define FSTRCMP(a,b) ((a)[0]<(b)[0]? -1:(a)[0]>(b)[0]?1:strcmp((a),(b)))
+#define FSTRNCMP(a,b,n) ((a)[0]<(b)[0]?-1:(a)[0]>(b)[0]?1:strncmp((a),(b),(n)))
+
+#if defined(__VMS) || defined(VMS)
+
+#define FNANMASK 0xFFFF /* mask all bits */
+#define DNANMASK 0xFFFF /* mask all bits */
+
+#else
+
+#define FNANMASK 0x7F80 /* mask bits 1 - 8; all set on NaNs */
+ /* all 0 on underflow or 0. */
+
+#define DNANMASK 0x7FF0 /* mask bits 1 - 11; all set on NaNs */
+ /* all 0 on underflow or 0. */
+
+#endif
+
+#if MACHINE == CRAY
+ /*
+ Cray machines: the large negative integer corresponds
+ to the 3 most sig digits set to 1. If these
+ 3 bits are set in a floating point number (64 bits), then it represents
+ a reserved value (i.e., a NaN)
+ */
+#define fnan(L) ( (L) >= 0xE000000000000000 ? 1 : 0) )
+
+#else
+ /* these functions work for both big and little endian machines */
+ /* that use the IEEE floating point format for internal numbers */
+
+ /* These functions tests whether the float value is a reserved IEEE */
+ /* value such as a Not-a-Number (NaN), or underflow, overflow, or */
+ /* infinity. The functions returns 1 if the value is a NaN, overflow */
+ /* or infinity; it returns 2 if the value is an denormalized underflow */
+ /* value; otherwise it returns 0. fnan tests floats, dnan tests doubles */
+
+#define fnan(L) \
+ ( (L & FNANMASK) == FNANMASK ? 1 : (L & FNANMASK) == 0 ? 2 : 0)
+
+#define dnan(L) \
+ ( (L & DNANMASK) == DNANMASK ? 1 : (L & DNANMASK) == 0 ? 2 : 0)
+
+#endif
+
+#define DSCHAR_MAX 127.49 /* max double value that fits in an signed char */
+#define DSCHAR_MIN -128.49 /* min double value that fits in an signed char */
+#define DUCHAR_MAX 255.49 /* max double value that fits in an unsigned char */
+#define DUCHAR_MIN -0.49 /* min double value that fits in an unsigned char */
+#define DUSHRT_MAX 65535.49 /* max double value that fits in a unsigned short*/
+#define DUSHRT_MIN -0.49 /* min double value that fits in an unsigned short */
+#define DSHRT_MAX 32767.49 /* max double value that fits in a short */
+#define DSHRT_MIN -32768.49 /* min double value that fits in a short */
+
+#if LONGSIZE == 32
+# define DLONG_MAX 2147483647.49 /* max double value that fits in a long */
+# define DLONG_MIN -2147483648.49 /* min double value that fits in a long */
+# define DULONG_MAX 4294967295.49 /* max double that fits in a unsigned long */
+#else
+# define DLONG_MAX 9.2233720368547752E18 /* max double value long */
+# define DLONG_MIN -9.2233720368547752E18 /* min double value long */
+# define DULONG_MAX 1.84467440737095504E19 /* max double value ulong */
+#endif
+
+#define DULONG_MIN -0.49 /* min double value that fits in an unsigned long */
+#define DLONGLONG_MAX 9.2233720368547752E18 /* max double value longlong */
+#define DLONGLONG_MIN -9.2233720368547752E18 /* min double value longlong */
+#define DUINT_MAX 4294967295.49 /* max dbl that fits in a unsigned 4-byte int */
+#define DUINT_MIN -0.49 /* min dbl that fits in an unsigned 4-byte int */
+#define DINT_MAX 2147483647.49 /* max double value that fits in a 4-byte int */
+#define DINT_MIN -2147483648.49 /* min double value that fits in a 4-byte int */
+
+#ifndef UINT32_MAX
+#define UINT32_MAX 4294967295U /* max unsigned 32-bit integer */
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX 2147483647 /* max 32-bit integer */
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN (-INT32_MAX -1) /* min 32-bit integer */
+#endif
+
+#ifndef LONGLONG_MAX
+
+#ifdef LLONG_MAX
+/* Linux and Solaris definition */
+#define LONGLONG_MAX LLONG_MAX
+#define LONGLONG_MIN LLONG_MIN
+
+#elif defined(LONG_LONG_MAX)
+#define LONGLONG_MAX LONG_LONG_MAX
+#define LONGLONG_MIN LONG_LONG_MIN
+
+#elif defined(__LONG_LONG_MAX__)
+/* Mac OS X & CYGWIN defintion */
+#define LONGLONG_MAX __LONG_LONG_MAX__
+#define LONGLONG_MIN (-LONGLONG_MAX -1LL)
+
+#elif defined(INT64_MAX)
+/* windows definition */
+#define LONGLONG_MAX INT64_MAX
+#define LONGLONG_MIN INT64_MIN
+
+#elif defined(_I64_MAX)
+/* windows definition */
+#define LONGLONG_MAX _I64_MAX
+#define LONGLONG_MIN _I64_MIN
+
+#elif defined(HAVE_LONGLONG)
+/* compiler has a 'long long' or equivalent type */
+#define LONGLONG_MAX 9223372036854775807LL /* max 64-bit integer */
+#define LONGLONG_MIN (-LONGLONG_MAX -1LL) /* min 64-bit integer */
+
+#elif (LONGSIZE == 64)
+/* Compiler may not have a 'long long' type, but sizeof(long) = 64 */
+#define LONGLONG_MAX 9223372036854775807L /* max 64-bit integer */
+#define LONGLONG_MIN (-LONGLONG_MAX -1L) /* min 64-bit integer */
+
+#else
+/* define a default value, even if it is never used */
+#define LONGLONG_MAX LONG_MAX
+#define LONGLONG_MIN LONG_MIN
+#endif
+#endif /* end of ndef LONGLONG_MAX section */
+
+
+#define COMPRESS_NULL_VALUE -2147483647
+
+int ffmkky(char *keyname, char *keyval, char *comm, char *card, int *status);
+int ffgnky(fitsfile *fptr, char *card, int *status);
+void ffcfmt(char *tform, char *cform);
+void ffcdsp(char *tform, char *cform);
+void ffswap2(short *values, long nvalues);
+void ffswap4(INT32BIT *values, long nvalues);
+void ffswap8(double *values, long nvalues);
+int ffi2c(long ival, char *cval, int *status);
+int ffl2c(int lval, char *cval, int *status);
+int ffs2c(char *instr, char *outstr, int *status);
+int ffr2f(float fval, int decim, char *cval, int *status);
+int ffr2e(float fval, int decim, char *cval, int *status);
+int ffd2f(double dval, int decim, char *cval, int *status);
+int ffd2e(double dval, int decim, char *cval, int *status);
+int ffc2ii(char *cval, long *ival, int *status);
+int ffc2ll(char *cval, int *lval, int *status);
+int ffc2rr(char *cval, float *fval, int *status);
+int ffc2dd(char *cval, double *dval, int *status);
+int ffc2x(char *cval, char *dtype, long *ival, int *lval, char *sval,
+ double *dval, int *status);
+int ffc2s(char *instr, char *outstr, int *status);
+int ffc2i(char *cval, long *ival, int *status);
+int ffc2r(char *cval, float *fval, int *status);
+int ffc2d(char *cval, double *dval, int *status);
+int ffc2l(char *cval, int *lval, int *status);
+void ffxmsg(int action, char *err_message);
+int ffgcnt(fitsfile *fptr, char *value, int *status);
+int ffgtkn(fitsfile *fptr, int numkey, char *keyname, long *value, int *status);
+int fftkyn(fitsfile *fptr, int numkey, char *keyname, char *value, int *status);
+int ffgphd(fitsfile *fptr, int maxdim, int *simple, int *bitpix, int *naxis,
+ long naxes[], long *pcount, long *gcount, int *extend, double *bscale,
+ double *bzero, long *blank, int *nspace, int *status);
+int ffgttb(fitsfile *fptr, long *rowlen, long *nrows, long *pcount,
+ long *tfield, int *status);
+
+int ffmkey(fitsfile *fptr, char *card, int *status);
+
+int ffmbyt(fitsfile *fptr, OFF_T bytpos, int ignore_err, int *status);
+int ffgbyt(fitsfile *fptr, long nbytes, void *buffer, int *status);
+int ffpbyt(fitsfile *fptr, long nbytes, void *buffer, int *status);
+int ffgbytoff(fitsfile *fptr, long gsize, long ngroups, long offset,
+ void *buffer, int *status);
+int ffpbytoff(fitsfile *fptr, long gsize, long ngroups, long offset,
+ void *buffer, int *status);
+int ffldrc(fitsfile *fptr, long record, int err_mode, int *status);
+int ffwhbf(fitsfile *fptr, int *nbuff);
+int ffbfeof(fitsfile *fptr, int *status);
+int ffbfwt(int nbuff, int *status);
+int fits_get_num_files(void);
+int ffpxsz(int datatype);
+
+int ffourl(char *url, char *urltype, char *outfile, char *tmplfile,
+ char *compspec, int *status);
+int ffparsecompspec(fitsfile *fptr, char *compspec, int *status);
+int ffoptplt(fitsfile *fptr, const char *tempname, int *status);
+int fits_is_this_a_copy(char *urltype);
+int fits_store_Fptr(FITSfile *Fptr, int *status);
+int fits_clear_Fptr(FITSfile *Fptr, int *status);
+int fits_already_open(fitsfile **fptr, char *url,
+ char *urltype, char *infile, char *extspec, char *rowfilter,
+ char *binspec, char *colspec, int mode,int *isopen, int *status);
+int ffedit_columns(fitsfile **fptr, char *outfile, char *expr, int *status);
+int fits_get_col_minmax(fitsfile *fptr, int colnum, float *datamin,
+ float *datamax, int *status);
+int ffwritehisto(long totaln, long offset, long firstn, long nvalues,
+ int narrays, iteratorCol *imagepars, void *userPointer);
+int ffcalchist(long totalrows, long offset, long firstrow, long nrows,
+ int ncols, iteratorCol *colpars, void *userPointer);
+int fits_copy_image_cell(fitsfile **fptr, char *outfile, char *colname,
+ long rownum, int *status);
+int fits_copy_image_keywords(fitsfile *infptr, fitsfile *outfptr, int *status);
+int ffrhdu(fitsfile *fptr, int *hdutype, int *status);
+int ffpinit(fitsfile *fptr, int *status);
+int ffainit(fitsfile *fptr, int *status);
+int ffbinit(fitsfile *fptr, int *status);
+int ffchdu(fitsfile *fptr, int *status);
+int ffwend(fitsfile *fptr, int *status);
+int ffpdfl(fitsfile *fptr, int *status);
+int ffuptf(fitsfile *fptr, int *status);
+
+int ffdblk(fitsfile *fptr, long nblocks, int *status);
+int ffgext(fitsfile *fptr, int moveto, int *exttype, int *status);
+int ffgtbc(fitsfile *fptr, long *totalwidth, int *status);
+int ffgtbp(fitsfile *fptr, char *name, char *value, int *status);
+int ffiblk(fitsfile *fptr, long nblock, int headdata, int *status);
+int ffshft(fitsfile *fptr, OFF_T firstbyte, OFF_T nbytes, OFF_T nshift,
+ int *status);
+
+int ffgcpr(fitsfile *fptr, int colnum, long firstrow, OFF_T firstelem,
+ long nelem, int writemode, double *scale, double *zero, char *tform,
+ long *twidth, int *tcode, int *maxelem, OFF_T *startpos,
+ OFF_T *elemnum, long *incre, OFF_T *repeat, OFF_T *rowlen,
+ int *hdutype, long *tnull, char *snull, int *status);
+
+int ffflushx(FITSfile *fptr);
+int ffseek(FITSfile *fptr, OFF_T position);
+int ffread(FITSfile *fptr, long nbytes, void *buffer,
+ int *status);
+int ffwrite(FITSfile *fptr, long nbytes, void *buffer,
+ int *status);
+int fftrun(fitsfile *fptr, OFF_T filesize, int *status);
+
+int ffpcluc(fitsfile *fptr, int colnum, long firstrow, long firstelem, long
+ nelem, int *status);
+
+int ffgcll(fitsfile *fptr, int colnum, long firstrow, OFF_T firstelem, long
+ nelem, int nultyp, char nulval, char *array, char *nularray,
+ int *anynul, int *status);
+int ffgcls(fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelem, int nultyp, char *nulval,
+ char **array, char *nularray, int *anynul, int *status);
+int ffgcls2(fitsfile *fptr, int colnum, long firstrow, long firstelem,
+ long nelem, int nultyp, char *nulval,
+ char **array, char *nularray, int *anynul, int *status);
+int ffgclb(fitsfile *fptr, int colnum, long firstrow, OFF_T firstelem,
+ long nelem, long elemincre, int nultyp, unsigned char nulval,
+ unsigned char *array, char *nularray, int *anynul, int *status);
+int ffgclsb(fitsfile *fptr, int colnum, long firstrow, OFF_T firstelem,
+ long nelem, long elemincre, int nultyp, signed char nulval,
+ signed char *array, char *nularray, int *anynul, int *status);
+int ffgclui(fitsfile *fptr, int colnum, long firstrow, OFF_T firstelem,
+ long nelem, long elemincre, int nultyp, unsigned short nulval,
+ unsigned short *array, char *nularray, int *anynul, int *status);
+int ffgcli(fitsfile *fptr, int colnum, long firstrow, OFF_T firstelem,
+ long nelem, long elemincre, int nultyp, short nulval,
+ short *array, char *nularray, int *anynul, int *status);
+int ffgcluj(fitsfile *fptr, int colnum, long firstrow, OFF_T firstelem,
+ long nelem, long elemincre, int nultyp, unsigned long nulval,
+ unsigned long *array, char *nularray, int *anynul, int *status);
+int ffgcljj(fitsfile *fptr, int colnum, long firstrow, OFF_T firstelem,
+ long nelem, long elemincre, int nultyp, LONGLONG nulval,
+ LONGLONG *array, char *nularray, int *anynul, int *status);
+int ffgclj(fitsfile *fptr, int colnum, long firstrow, OFF_T firstelem,
+ long nelem, long elemincre, int nultyp, long nulval, long *array,
+ char *nularray, int *anynul, int *status);
+int ffgcluk(fitsfile *fptr, int colnum, long firstrow, OFF_T firstelem,
+ long nelem, long elemincre, int nultyp, unsigned int nulval,
+ unsigned int *array, char *nularray, int *anynul, int *status);
+int ffgclk(fitsfile *fptr, int colnum, long firstrow, OFF_T firstelem,
+ long nelem, long elemincre, int nultyp, int nulval, int *array,
+ char *nularray, int *anynul, int *status);
+int ffgcle(fitsfile *fptr, int colnum, long firstrow, OFF_T firstelem,
+ long nelem, long elemincre, int nultyp, float nulval, float *array,
+ char *nularray, int *anynul, int *status);
+int ffgcld(fitsfile *fptr, int colnum, long firstrow, OFF_T firstelem,
+ long nelem, long elemincre, int nultyp, double nulval,
+ double *array, char *nularray, int *anynul, int *status);
+
+int ffpi1b(fitsfile *fptr, long nelem, long incre, unsigned char *buffer,
+ int *status);
+int ffpi2b(fitsfile *fptr, long nelem, long incre, short *buffer, int *status);
+int ffpi4b(fitsfile *fptr, long nelem, long incre, INT32BIT *buffer,
+ int *status);
+int ffpi8b(fitsfile *fptr, long nelem, long incre, long *buffer, int *status);
+int ffpr4b(fitsfile *fptr, long nelem, long incre, float *buffer, int *status);
+int ffpr8b(fitsfile *fptr, long nelem, long incre, double *buffer, int *status);
+
+int ffgi1b(fitsfile *fptr, OFF_T pos, long nelem, long incre,
+ unsigned char *buffer, int *status);
+int ffgi2b(fitsfile *fptr, OFF_T pos, long nelem, long incre, short *buffer,
+ int *status);
+int ffgi4b(fitsfile *fptr, OFF_T pos, long nelem, long incre, INT32BIT *buffer,
+ int *status);
+int ffgi8b(fitsfile *fptr, OFF_T pos, long nelem, long incre, long *buffer,
+ int *status);
+int ffgr4b(fitsfile *fptr, OFF_T pos, long nelem, long incre, float *buffer,
+ int *status);
+int ffgr8b(fitsfile *fptr, OFF_T pos, long nelem, long incre, double *buffer,
+ int *status);
+
+int ffcins(fitsfile *fptr, long naxis1, long naxis2, long nbytes,
+ long bytepos, int *status);
+int ffcdel(fitsfile *fptr, long naxis1, long naxis2, long nbytes,
+ long bytepos, int *status);
+int ffkshf(fitsfile *fptr, int firstcol, int tfields, int nshift, int *status);
+
+int fffi1i1(unsigned char *input, long ntodo, double scale, double zero,
+ int nullcheck, unsigned char tnull, unsigned char nullval, char
+ *nullarray, int *anynull, unsigned char *output, int *status);
+int fffi2i1(short *input, long ntodo, double scale, double zero,
+ int nullcheck, short tnull, unsigned char nullval, char *nullarray,
+ int *anynull, unsigned char *output, int *status);
+int fffi4i1(INT32BIT *input, long ntodo, double scale, double zero,
+ int nullcheck, INT32BIT tnull, unsigned char nullval, char *nullarray,
+ int *anynull, unsigned char *output, int *status);
+int fffi8i1(LONGLONG *input, long ntodo, double scale, double zero,
+ int nullcheck, long tnull, unsigned char nullval, char *nullarray,
+ int *anynull, unsigned char *output, int *status);
+int fffr4i1(float *input, long ntodo, double scale, double zero,
+ int nullcheck, unsigned char nullval, char *nullarray,
+ int *anynull, unsigned char *output, int *status);
+int fffr8i1(double *input, long ntodo, double scale, double zero,
+ int nullcheck, unsigned char nullval, char *nullarray,
+ int *anynull, unsigned char *output, int *status);
+int fffstri1(char *input, long ntodo, double scale, double zero,
+ long twidth, double power, int nullcheck, char *snull,
+ unsigned char nullval, char *nullarray, int *anynull,
+ unsigned char *output, int *status);
+
+int fffi1s1(unsigned char *input, long ntodo, double scale, double zero,
+ int nullcheck, unsigned char tnull, signed char nullval, char
+ *nullarray, int *anynull, signed char *output, int *status);
+int fffi2s1(short *input, long ntodo, double scale, double zero,
+ int nullcheck, short tnull, signed char nullval, char *nullarray,
+ int *anynull, signed char *output, int *status);
+int fffi4s1(INT32BIT *input, long ntodo, double scale, double zero,
+ int nullcheck, INT32BIT tnull, signed char nullval, char *nullarray,
+ int *anynull, signed char *output, int *status);
+int fffi8s1(LONGLONG *input, long ntodo, double scale, double zero,
+ int nullcheck, long tnull, signed char nullval, char *nullarray,
+ int *anynull, signed char *output, int *status);
+int fffr4s1(float *input, long ntodo, double scale, double zero,
+ int nullcheck, signed char nullval, char *nullarray,
+ int *anynull, signed char *output, int *status);
+int fffr8s1(double *input, long ntodo, double scale, double zero,
+ int nullcheck, signed char nullval, char *nullarray,
+ int *anynull, signed char *output, int *status);
+int fffstrs1(char *input, long ntodo, double scale, double zero,
+ long twidth, double power, int nullcheck, char *snull,
+ signed char nullval, char *nullarray, int *anynull,
+ signed char *output, int *status);
+
+int fffi1u2(unsigned char *input, long ntodo, double scale, double zero,
+ int nullcheck, unsigned char tnull, unsigned short nullval,
+ char *nullarray,
+ int *anynull, unsigned short *output, int *status);
+int fffi2u2(short *input, long ntodo, double scale, double zero,
+ int nullcheck, short tnull, unsigned short nullval, char *nullarray,
+ int *anynull, unsigned short *output, int *status);
+int fffi4u2(INT32BIT *input, long ntodo, double scale, double zero,
+ int nullcheck, INT32BIT tnull, unsigned short nullval, char *nullarray,
+ int *anynull, unsigned short *output, int *status);
+int fffi8u2(LONGLONG *input, long ntodo, double scale, double zero,
+ int nullcheck, long tnull, unsigned short nullval, char *nullarray,
+ int *anynull, unsigned short *output, int *status);
+int fffr4u2(float *input, long ntodo, double scale, double zero,
+ int nullcheck, unsigned short nullval, char *nullarray,
+ int *anynull, unsigned short *output, int *status);
+int fffr8u2(double *input, long ntodo, double scale, double zero,
+ int nullcheck, unsigned short nullval, char *nullarray,
+ int *anynull, unsigned short *output, int *status);
+int fffstru2(char *input, long ntodo, double scale, double zero,
+ long twidth, double power, int nullcheck, char *snull,
+ unsigned short nullval, char *nullarray, int *anynull,
+ unsigned short *output, int *status);
+
+int fffi1i2(unsigned char *input, long ntodo, double scale, double zero,
+ int nullcheck, unsigned char tnull, short nullval, char *nullarray,
+ int *anynull, short *output, int *status);
+int fffi2i2(short *input, long ntodo, double scale, double zero,
+ int nullcheck, short tnull, short nullval, char *nullarray,
+ int *anynull, short *output, int *status);
+int fffi4i2(INT32BIT *input, long ntodo, double scale, double zero,
+ int nullcheck, INT32BIT tnull, short nullval, char *nullarray,
+ int *anynull, short *output, int *status);
+int fffi8i2(LONGLONG *input, long ntodo, double scale, double zero,
+ int nullcheck, long tnull, short nullval, char *nullarray,
+ int *anynull, short *output, int *status);
+int fffr4i2(float *input, long ntodo, double scale, double zero,
+ int nullcheck, short nullval, char *nullarray,
+ int *anynull, short *output, int *status);
+int fffr8i2(double *input, long ntodo, double scale, double zero,
+ int nullcheck, short nullval, char *nullarray,
+ int *anynull, short *output, int *status);
+int fffstri2(char *input, long ntodo, double scale, double zero,
+ long twidth, double power, int nullcheck, char *snull,
+ short nullval, char *nullarray, int *anynull, short *output,
+ int *status);
+
+int fffi1u4(unsigned char *input, long ntodo, double scale, double zero,
+ int nullcheck, unsigned char tnull, unsigned long nullval,
+ char *nullarray,
+ int *anynull, unsigned long *output, int *status);
+int fffi2u4(short *input, long ntodo, double scale, double zero,
+ int nullcheck, short tnull, unsigned long nullval, char *nullarray,
+ int *anynull, unsigned long *output, int *status);
+int fffi4u4(INT32BIT *input, long ntodo, double scale, double zero,
+ int nullcheck, INT32BIT tnull, unsigned long nullval, char *nullarray,
+ int *anynull, unsigned long *output, int *status);
+int fffi8u4(LONGLONG *input, long ntodo, double scale, double zero,
+ int nullcheck, long tnull, unsigned long nullval, char *nullarray,
+ int *anynull, unsigned long *output, int *status);
+int fffr4u4(float *input, long ntodo, double scale, double zero,
+ int nullcheck, unsigned long nullval, char *nullarray,
+ int *anynull, unsigned long *output, int *status);
+int fffr8u4(double *input, long ntodo, double scale, double zero,
+ int nullcheck, unsigned long nullval, char *nullarray,
+ int *anynull, unsigned long *output, int *status);
+int fffstru4(char *input, long ntodo, double scale, double zero,
+ long twidth, double power, int nullcheck, char *snull,
+ unsigned long nullval, char *nullarray, int *anynull,
+ unsigned long *output, int *status);
+
+int fffi1i4(unsigned char *input, long ntodo, double scale, double zero,
+ int nullcheck, unsigned char tnull, long nullval, char *nullarray,
+ int *anynull, long *output, int *status);
+int fffi2i4(short *input, long ntodo, double scale, double zero,
+ int nullcheck, short tnull, long nullval, char *nullarray,
+ int *anynull, long *output, int *status);
+int fffi4i4(INT32BIT *input, long ntodo, double scale, double zero,
+ int nullcheck, INT32BIT tnull, long nullval, char *nullarray,
+ int *anynull, long *output, int *status);
+int fffi8i4(LONGLONG *input, long ntodo, double scale, double zero,
+ int nullcheck, long tnull, long nullval, char *nullarray,
+ int *anynull, long *output, int *status);
+int fffr4i4(float *input, long ntodo, double scale, double zero,
+ int nullcheck, long nullval, char *nullarray,
+ int *anynull, long *output, int *status);
+int fffr8i4(double *input, long ntodo, double scale, double zero,
+ int nullcheck, long nullval, char *nullarray,
+ int *anynull, long *output, int *status);
+int fffstri4(char *input, long ntodo, double scale, double zero,
+ long twidth, double power, int nullcheck, char *snull,
+ long nullval, char *nullarray, int *anynull, long *output,
+ int *status);
+
+int fffi1int(unsigned char *input, long ntodo, double scale, double zero,
+ int nullcheck, unsigned char tnull, int nullval, char *nullarray,
+ int *anynull, int *output, int *status);
+int fffi2int(short *input, long ntodo, double scale, double zero,
+ int nullcheck, short tnull, int nullval, char *nullarray,
+ int *anynull, int *output, int *status);
+int fffi4int(INT32BIT *input, long ntodo, double scale, double zero,
+ int nullcheck, INT32BIT tnull, int nullval, char *nullarray,
+ int *anynull, int *output, int *status);
+int fffi8int(LONGLONG *input, long ntodo, double scale, double zero,
+ int nullcheck, long tnull, int nullval, char *nullarray,
+ int *anynull, int *output, int *status);
+int fffr4int(float *input, long ntodo, double scale, double zero,
+ int nullcheck, int nullval, char *nullarray,
+ int *anynull, int *output, int *status);
+int fffr8int(double *input, long ntodo, double scale, double zero,
+ int nullcheck, int nullval, char *nullarray,
+ int *anynull, int *output, int *status);
+int fffstrint(char *input, long ntodo, double scale, double zero,
+ long twidth, double power, int nullcheck, char *snull,
+ int nullval, char *nullarray, int *anynull, int *output,
+ int *status);
+
+int fffi1uint(unsigned char *input, long ntodo, double scale, double zero,
+ int nullcheck, unsigned char tnull, unsigned int nullval,
+ char *nullarray, int *anynull, unsigned int *output, int *status);
+int fffi2uint(short *input, long ntodo, double scale, double zero,
+ int nullcheck, short tnull, unsigned int nullval, char *nullarray,
+ int *anynull, unsigned int *output, int *status);
+int fffi4uint(INT32BIT *input, long ntodo, double scale, double zero,
+ int nullcheck, INT32BIT tnull, unsigned int nullval, char *nullarray,
+ int *anynull, unsigned int *output, int *status);
+int fffi8uint(LONGLONG *input, long ntodo, double scale, double zero,
+ int nullcheck, long tnull, unsigned int nullval, char *nullarray,
+ int *anynull, unsigned int *output, int *status);
+int fffr4uint(float *input, long ntodo, double scale, double zero,
+ int nullcheck, unsigned int nullval, char *nullarray,
+ int *anynull, unsigned int *output, int *status);
+int fffr8uint(double *input, long ntodo, double scale, double zero,
+ int nullcheck, unsigned int nullval, char *nullarray,
+ int *anynull, unsigned int *output, int *status);
+int fffstruint(char *input, long ntodo, double scale, double zero,
+ long twidth, double power, int nullcheck, char *snull,
+ unsigned int nullval, char *nullarray, int *anynull,
+ unsigned int *output, int *status);
+
+int fffi1i8(unsigned char *input, long ntodo, double scale, double zero,
+ int nullcheck, unsigned char tnull, LONGLONG nullval,
+ char *nullarray, int *anynull, LONGLONG *output, int *status);
+int fffi2i8(short *input, long ntodo, double scale, double zero,
+ int nullcheck, short tnull, LONGLONG nullval, char *nullarray,
+ int *anynull, LONGLONG *output, int *status);
+int fffi4i8(INT32BIT *input, long ntodo, double scale, double zero,
+ int nullcheck, INT32BIT tnull, LONGLONG nullval, char *nullarray,
+ int *anynull, LONGLONG *output, int *status);
+int fffi8i8(LONGLONG *input, long ntodo, double scale, double zero,
+ int nullcheck, LONGLONG tnull, LONGLONG nullval, char *nullarray,
+ int *anynull, LONGLONG *output, int *status);
+int fffr4i8(float *input, long ntodo, double scale, double zero,
+ int nullcheck, LONGLONG nullval, char *nullarray,
+ int *anynull, LONGLONG *output, int *status);
+int fffr8i8(double *input, long ntodo, double scale, double zero,
+ int nullcheck, LONGLONG nullval, char *nullarray,
+ int *anynull, LONGLONG *output, int *status);
+int fffstri8(char *input, long ntodo, double scale, double zero,
+ long twidth, double power, int nullcheck, char *snull,
+ LONGLONG nullval, char *nullarray, int *anynull, LONGLONG *output,
+ int *status);
+
+int fffi1r4(unsigned char *input, long ntodo, double scale, double zero,
+ int nullcheck, unsigned char tnull, float nullval, char *nullarray,
+ int *anynull, float *output, int *status);
+int fffi2r4(short *input, long ntodo, double scale, double zero,
+ int nullcheck, short tnull, float nullval, char *nullarray,
+ int *anynull, float *output, int *status);
+int fffi4r4(INT32BIT *input, long ntodo, double scale, double zero,
+ int nullcheck, INT32BIT tnull, float nullval, char *nullarray,
+ int *anynull, float *output, int *status);
+int fffi8r4(LONGLONG *input, long ntodo, double scale, double zero,
+ int nullcheck, long tnull, float nullval, char *nullarray,
+ int *anynull, float *output, int *status);
+int fffr4r4(float *input, long ntodo, double scale, double zero,
+ int nullcheck, float nullval, char *nullarray,
+ int *anynull, float *output, int *status);
+int fffr8r4(double *input, long ntodo, double scale, double zero,
+ int nullcheck, float nullval, char *nullarray,
+ int *anynull, float *output, int *status);
+int fffstrr4(char *input, long ntodo, double scale, double zero,
+ long twidth, double power, int nullcheck, char *snull,
+ float nullval, char *nullarray, int *anynull, float *output,
+ int *status);
+
+int fffi1r8(unsigned char *input, long ntodo, double scale, double zero,
+ int nullcheck, unsigned char tnull, double nullval, char *nullarray,
+ int *anynull, double *output, int *status);
+int fffi2r8(short *input, long ntodo, double scale, double zero,
+ int nullcheck, short tnull, double nullval, char *nullarray,
+ int *anynull, double *output, int *status);
+int fffi4r8(INT32BIT *input, long ntodo, double scale, double zero,
+ int nullcheck, INT32BIT tnull, double nullval, char *nullarray,
+ int *anynull, double *output, int *status);
+int fffi8r8(LONGLONG *input, long ntodo, double scale, double zero,
+ int nullcheck, long tnull, double nullval, char *nullarray,
+ int *anynull, double *output, int *status);
+int fffr4r8(float *input, long ntodo, double scale, double zero,
+ int nullcheck, double nullval, char *nullarray,
+ int *anynull, double *output, int *status);
+int fffr8r8(double *input, long ntodo, double scale, double zero,
+ int nullcheck, double nullval, char *nullarray,
+ int *anynull, double *output, int *status);
+int fffstrr8(char *input, long ntodo, double scale, double zero,
+ long twidth, double power, int nullcheck, char *snull,
+ double nullval, char *nullarray, int *anynull, double *output,
+ int *status);
+
+int ffi1fi1(unsigned char *array, long ntodo, double scale, double zero,
+ unsigned char *buffer, int *status);
+int ffs1fi1(signed char *array, long ntodo, double scale, double zero,
+ unsigned char *buffer, int *status);
+int ffu2fi1(unsigned short *array, long ntodo, double scale, double zero,
+ unsigned char *buffer, int *status);
+int ffi2fi1(short *array, long ntodo, double scale, double zero,
+ unsigned char *buffer, int *status);
+int ffu4fi1(unsigned long *array, long ntodo, double scale, double zero,
+ unsigned char *buffer, int *status);
+int ffi4fi1(long *array, long ntodo, double scale, double zero,
+ unsigned char *buffer, int *status);
+int ffi8fi1(LONGLONG *array, long ntodo, double scale, double zero,
+ unsigned char *buffer, int *status);
+int ffuintfi1(unsigned int *array, long ntodo, double scale, double zero,
+ unsigned char *buffer, int *status);
+int ffintfi1(int *array, long ntodo, double scale, double zero,
+ unsigned char *buffer, int *status);
+int ffr4fi1(float *array, long ntodo, double scale, double zero,
+ unsigned char *buffer, int *status);
+int ffr8fi1(double *array, long ntodo, double scale, double zero,
+ unsigned char *buffer, int *status);
+
+int ffi1fi2(unsigned char *array, long ntodo, double scale, double zero,
+ short *buffer, int *status);
+int ffs1fi2(signed char *array, long ntodo, double scale, double zero,
+ short *buffer, int *status);
+int ffu2fi2(unsigned short *array, long ntodo, double scale, double zero,
+ short *buffer, int *status);
+int ffi2fi2(short *array, long ntodo, double scale, double zero,
+ short *buffer, int *status);
+int ffu4fi2(unsigned long *array, long ntodo, double scale, double zero,
+ short *buffer, int *status);
+int ffi4fi2(long *array, long ntodo, double scale, double zero,
+ short *buffer, int *status);
+int ffi8fi2(LONGLONG *array, long ntodo, double scale, double zero,
+ short *buffer, int *status);
+int ffuintfi2(unsigned int *array, long ntodo, double scale, double zero,
+ short *buffer, int *status);
+int ffintfi2(int *array, long ntodo, double scale, double zero,
+ short *buffer, int *status);
+int ffr4fi2(float *array, long ntodo, double scale, double zero,
+ short *buffer, int *status);
+int ffr8fi2(double *array, long ntodo, double scale, double zero,
+ short *buffer, int *status);
+
+int ffi1fi4(unsigned char *array, long ntodo, double scale, double zero,
+ INT32BIT *buffer, int *status);
+int ffs1fi4(signed char *array, long ntodo, double scale, double zero,
+ INT32BIT *buffer, int *status);
+int ffu2fi4(unsigned short *array, long ntodo, double scale, double zero,
+ INT32BIT *buffer, int *status);
+int ffi2fi4(short *array, long ntodo, double scale, double zero,
+ INT32BIT *buffer, int *status);
+int ffu4fi4(unsigned long *array, long ntodo, double scale, double zero,
+ INT32BIT *buffer, int *status);
+int ffi4fi4(long *array, long ntodo, double scale, double zero,
+ INT32BIT *buffer, int *status);
+int ffi8fi4(LONGLONG *array, long ntodo, double scale, double zero,
+ INT32BIT *buffer, int *status);
+int ffuintfi4(unsigned int *array, long ntodo, double scale, double zero,
+ INT32BIT *buffer, int *status);
+int ffintfi4(int *array, long ntodo, double scale, double zero,
+ INT32BIT *buffer, int *status);
+int ffr4fi4(float *array, long ntodo, double scale, double zero,
+ INT32BIT *buffer, int *status);
+int ffr8fi4(double *array, long ntodo, double scale, double zero,
+ INT32BIT *buffer, int *status);
+
+int fflongfi8(long *array, long ntodo, double scale, double zero,
+ LONGLONG *buffer, int *status);
+int ffi8fi8(LONGLONG *array, long ntodo, double scale, double zero,
+ LONGLONG *buffer, int *status);
+int ffi2fi8(short *array, long ntodo, double scale, double zero,
+ LONGLONG *buffer, int *status);
+int ffi1fi8(unsigned char *array, long ntodo, double scale, double zero,
+ LONGLONG *buffer, int *status);
+int ffs1fi8(signed char *array, long ntodo, double scale, double zero,
+ LONGLONG *buffer, int *status);
+int ffr4fi8(float *array, long ntodo, double scale, double zero,
+ LONGLONG *buffer, int *status);
+int ffr8fi8(double *array, long ntodo, double scale, double zero,
+ LONGLONG *buffer, int *status);
+int ffintfi8(int *array, long ntodo, double scale, double zero,
+ LONGLONG *buffer, int *status);
+int ffu2fi8(unsigned short *array, long ntodo, double scale, double zero,
+ LONGLONG *buffer, int *status);
+int ffu4fi8(unsigned long *array, long ntodo, double scale, double zero,
+ LONGLONG *buffer, int *status);
+int ffuintfi8(unsigned int *array, long ntodo, double scale, double zero,
+ LONGLONG *buffer, int *status);
+
+int ffi1fr4(unsigned char *array, long ntodo, double scale, double zero,
+ float *buffer, int *status);
+int ffs1fr4(signed char *array, long ntodo, double scale, double zero,
+ float *buffer, int *status);
+int ffu2fr4(unsigned short *array, long ntodo, double scale, double zero,
+ float *buffer, int *status);
+int ffi2fr4(short *array, long ntodo, double scale, double zero,
+ float *buffer, int *status);
+int ffu4fr4(unsigned long *array, long ntodo, double scale, double zero,
+ float *buffer, int *status);
+int ffi4fr4(long *array, long ntodo, double scale, double zero,
+ float *buffer, int *status);
+int ffi8fr4(LONGLONG *array, long ntodo, double scale, double zero,
+ float *buffer, int *status);
+int ffuintfr4(unsigned int *array, long ntodo, double scale, double zero,
+ float *buffer, int *status);
+int ffintfr4(int *array, long ntodo, double scale, double zero,
+ float *buffer, int *status);
+int ffr4fr4(float *array, long ntodo, double scale, double zero,
+ float *buffer, int *status);
+int ffr8fr4(double *array, long ntodo, double scale, double zero,
+ float *buffer, int *status);
+
+int ffi1fr8(unsigned char *array, long ntodo, double scale, double zero,
+ double *buffer, int *status);
+int ffs1fr8(signed char *array, long ntodo, double scale, double zero,
+ double *buffer, int *status);
+int ffu2fr8(unsigned short *array, long ntodo, double scale, double zero,
+ double *buffer, int *status);
+int ffi2fr8(short *array, long ntodo, double scale, double zero,
+ double *buffer, int *status);
+int ffu4fr8(unsigned long *array, long ntodo, double scale, double zero,
+ double *buffer, int *status);
+int ffi4fr8(long *array, long ntodo, double scale, double zero,
+ double *buffer, int *status);
+int ffi8fr8(LONGLONG *array, long ntodo, double scale, double zero,
+ double *buffer, int *status);
+int ffuintfr8(unsigned int *array, long ntodo, double scale, double zero,
+ double *buffer, int *status);
+int ffintfr8(int *array, long ntodo, double scale, double zero,
+ double *buffer, int *status);
+int ffr4fr8(float *array, long ntodo, double scale, double zero,
+ double *buffer, int *status);
+int ffr8fr8(double *array, long ntodo, double scale, double zero,
+ double *buffer, int *status);
+
+int ffi1fstr(unsigned char *input, long ntodo, double scale, double zero,
+ char *cform, long twidth, char *output, int *status);
+int ffs1fstr(signed char *input, long ntodo, double scale, double zero,
+ char *cform, long twidth, char *output, int *status);
+int ffu2fstr(unsigned short *input, long ntodo, double scale, double zero,
+ char *cform, long twidth, char *output, int *status);
+int ffi2fstr(short *input, long ntodo, double scale, double zero,
+ char *cform, long twidth, char *output, int *status);
+int ffu4fstr(unsigned long *input, long ntodo, double scale, double zero,
+ char *cform, long twidth, char *output, int *status);
+int ffi4fstr(long *input, long ntodo, double scale, double zero,
+ char *cform, long twidth, char *output, int *status);
+int ffi8fstr(LONGLONG *input, long ntodo, double scale, double zero,
+ char *cform, long twidth, char *output, int *status);
+int ffintfstr(int *input, long ntodo, double scale, double zero,
+ char *cform, long twidth, char *output, int *status);
+int ffuintfstr(unsigned int *input, long ntodo, double scale, double zero,
+ char *cform, long twidth, char *output, int *status);
+int ffr4fstr(float *input, long ntodo, double scale, double zero,
+ char *cform, long twidth, char *output, int *status);
+int ffr8fstr(double *input, long ntodo, double scale, double zero,
+ char *cform, long twidth, char *output, int *status);
+
+/* the following 4 routines are VMS macros used on VAX or Alpha VMS */
+void ieevpd(double *inarray, double *outarray, long *nvals);
+void ieevud(double *inarray, double *outarray, long *nvals);
+void ieevpr(float *inarray, float *outarray, long *nvals);
+void ieevur(float *inarray, float *outarray, long *nvals);
+
+/* routines related to the lexical parser */
+int ffselect_table(fitsfile **fptr, char *outfile, char *expr, int *status);
+int ffiprs( fitsfile *fptr, int compressed, char *expr, int maxdim,
+ int *datatype, long *nelem, int *naxis, long *naxes,
+ int *status );
+void ffcprs( void );
+int ffcvtn( int inputType, void *input, char *undef, long ntodo,
+ int outputType, void *nulval, void *output,
+ int *anynull, int *status );
+int parse_data( long totalrows, long offset, long firstrow,
+ long nrows, int nCols, iteratorCol *colData,
+ void *userPtr );
+int uncompress_hkdata( fitsfile *fptr, long ntimes,
+ double *times, int *status );
+int ffffrw_work( long totalrows, long offset, long firstrow,
+ long nrows, int nCols, iteratorCol *colData,
+ void *userPtr );
+
+
+/* image compression routines */
+int fits_write_compressed_img(fitsfile *fptr,
+ int datatype, long *fpixel, long *lpixel,
+ int nullcheck, void *array, void *nulval,
+ int *status);
+int fits_write_compressed_pixels(fitsfile *fptr,
+ int datatype, OFF_T fpixel, long npixels,
+ int nullcheck, void *array, void *nulval,
+ int *status);
+int fits_write_compressed_img_plane(fitsfile *fptr, int datatype,
+ int bytesperpixel, long nplane, long *firstcoord, long *lastcoord,
+ long *naxes, int nullcheck,
+ void *array, void *nullval, long *nread, int *status);
+
+int imcomp_init_table(fitsfile *outfptr, int compress_type,
+ int bitpix, int naxis,long *naxes,long *tilesize,
+ int rice_blocksize,int rice_nbits,int *status);
+int imcomp_calc_max_elem (int comptype, int nx, int blocksize);
+int imcomp_copy_imheader(fitsfile *infptr, fitsfile *outfptr,
+ int *status);
+int imcomp_compress_image (fitsfile *infptr, fitsfile *outfptr,
+ int *status);
+int imcomp_compress_tile (fitsfile *outfptr, long row,
+ int datatype, void *tiledata, long tilelen, int *status);
+
+/* image decompression routines */
+
+int fits_read_compressed_img(fitsfile *fptr,
+ int datatype, long *fpixel,long *lpixel,long *inc,
+ int nullcheck, void *nulval, void *array, char *nullarray,
+ int *anynul, int *status);
+int fits_read_compressed_pixels(fitsfile *fptr,
+ int datatype, OFF_T fpixel, long npixels,
+ int nullcheck, void *nulval, void *array, char *nullarray,
+ int *anynul, int *status);
+int fits_read_compressed_img_plane(fitsfile *fptr, int datatype,
+ int bytesperpixel, long nplane, long *firstcoord, long *lastcoord,
+ long *inc, long *naxes, int nullcheck, void *nullval,
+ void *array, char *nullarray, int *anynul, long *nread, int *status);
+
+int imcomp_get_compressed_image_par(fitsfile *infptr, int *status);
+int imcomp_decompress_tile (fitsfile *infptr,
+ int nrow, int tilesize, int datatype, int nullcheck,
+ void *nulval, void *buffer, char *bnullarray, int *anynul,
+ int *status);
+int imcomp_copy_overlap (char *tile, int pixlen, int ndim,
+ long *tfpixel, long *tlpixel, char *bnullarray, char *image,
+ long *fpixel, long *lpixel, long *inc, int nullcheck, char *nullarray,
+ int *status);
+int imcomp_merge_overlap (char *tile, int pixlen, int ndim,
+ long *tfpixel, long *tlpixel, char *bnullarray, char *image,
+ long *fpixel, long *lpixel, int nullcheck, int *status);
+
+int fits_quantize_float (float fdata[], int nx, float in_null_value,
+ int noise_bits, int idata[], double *bscale, double *bzero,
+ int *iminval, int *imaxval);
+int fits_quantize_double (double fdata[], int nx, double in_null_value,
+ int noise_bits, int idata[], double *bscale, double *bzero,
+ int *iminval, int *imaxval);
+int fits_rcomp(int a[], int nx, unsigned char *c, int clen,int nblock);
+int fits_rdecomp (unsigned char *c, int clen, unsigned int array[], int nx,
+ int nblock);
+
+int pl_p2li (int *pxsrc, int xs, short *lldst, int npix);
+int pl_l2pi (short *ll_src, int xs, int *px_dst, int npix);
+
+/* general driver routines */
+
+int urltype2driver(char *urltype, int *driver);
+int fits_init_cfitsio(void);
+
+int fits_register_driver( char *prefix,
+ int (*init)(void),
+ int (*fitsshutdown)(void),
+ int (*setoptions)(int option),
+ int (*getoptions)(int *options),
+ int (*getversion)(int *version),
+ int (*checkfile) (char *urltype, char *infile, char *outfile),
+ int (*fitsopen)(char *filename, int rwmode, int *driverhandle),
+ int (*fitscreate)(char *filename, int *driverhandle),
+ int (*fitstruncate)(int driverhandle, OFF_T filesize),
+ int (*fitsclose)(int driverhandle),
+ int (*fremove)(char *filename),
+ int (*size)(int driverhandle, OFF_T *size),
+ int (*flush)(int driverhandle),
+ int (*seek)(int driverhandle, OFF_T offset),
+ int (*fitsread) (int driverhandle, void *buffer, long nbytes),
+ int (*fitswrite)(int driverhandle, void *buffer, long nbytes));
+
+/* file driver I/O routines */
+
+int file_init(void);
+int file_setoptions(int options);
+int file_getoptions(int *options);
+int file_getversion(int *version);
+int file_shutdown(void);
+int file_checkfile(char *urltype, char *infile, char *outfile);
+int file_open(char *filename, int rwmode, int *driverhandle);
+int file_compress_open(char *filename, int rwmode, int *hdl);
+int file_openfile(char *filename, int rwmode, FILE **diskfile);
+int file_create(char *filename, int *driverhandle);
+int file_truncate(int driverhandle, OFF_T filesize);
+int file_size(int driverhandle, OFF_T *filesize);
+int file_close(int driverhandle);
+int file_remove(char *filename);
+int file_flush(int driverhandle);
+int file_seek(int driverhandle, OFF_T offset);
+int file_read (int driverhandle, void *buffer, long nbytes);
+int file_write(int driverhandle, void *buffer, long nbytes);
+int file_is_compressed(char *filename);
+
+/* memory driver I/O routines */
+
+int mem_init(void);
+int mem_setoptions(int options);
+int mem_getoptions(int *options);
+int mem_getversion(int *version);
+int mem_shutdown(void);
+int mem_create(char *filename, int *handle);
+int mem_create_comp(char *filename, int *handle);
+int mem_openmem(void **buffptr, size_t *buffsize, size_t deltasize,
+ void *(*memrealloc)(void *p, size_t newsize), int *handle);
+int mem_createmem(size_t memsize, int *handle);
+int stdin_checkfile(char *urltype, char *infile, char *outfile);
+int stdin_open(char *filename, int rwmode, int *handle);
+int stdin2mem(int hd);
+int stdin2file(int hd);
+int stdout_close(int handle);
+int mem_compress_openrw(char *filename, int rwmode, int *hdl);
+int mem_compress_open(char *filename, int rwmode, int *hdl);
+int mem_compress_stdin_open(char *filename, int rwmode, int *hdl);
+int mem_iraf_open(char *filename, int rwmode, int *hdl);
+int mem_rawfile_open(char *filename, int rwmode, int *hdl);
+int mem_size(int handle, OFF_T *filesize);
+int mem_truncate(int handle, OFF_T filesize);
+int mem_close_free(int handle);
+int mem_close_keep(int handle);
+int mem_close_comp(int handle);
+int mem_seek(int handle, OFF_T offset);
+int mem_read(int hdl, void *buffer, long nbytes);
+int mem_write(int hdl, void *buffer, long nbytes);
+int mem_uncompress2mem(char *filename, FILE *diskfile, int hdl);
+
+int iraf2mem(char *filename, char **buffptr, size_t *buffsize,
+ size_t *filesize, int *status);
+
+/* root driver I/O routines */
+
+int root_init(void);
+int root_setoptions(int options);
+int root_getoptions(int *options);
+int root_getversion(int *version);
+int root_shutdown(void);
+int root_open(char *filename, int rwmode, int *driverhandle);
+int root_create(char *filename, int *driverhandle);
+int root_close(int driverhandle);
+int root_flush(int driverhandle);
+int root_seek(int driverhandle, OFF_T offset);
+int root_read (int driverhandle, void *buffer, long nbytes);
+int root_write(int driverhandle, void *buffer, long nbytes);
+int root_size(int handle, OFF_T *filesize);
+
+/* http driver I/O routines */
+
+int http_checkfile(char *urltype, char *infile, char *outfile);
+int http_open(char *filename, int rwmode, int *driverhandle);
+int http_file_open(char *filename, int rwmode, int *driverhandle);
+int http_compress_open(char *filename, int rwmode, int *driverhandle);
+
+/* ftp driver I/O routines */
+
+int ftp_checkfile(char *urltype, char *infile, char *outfile);
+int ftp_open(char *filename, int rwmode, int *driverhandle);
+int ftp_file_open(char *filename, int rwmode, int *driverhandle);
+int ftp_compress_open(char *filename, int rwmode, int *driverhandle);
+
+
+int uncompress2mem(char *filename, FILE *diskfile,
+ char **buffptr, size_t *buffsize,
+ void *(*mem_realloc)(void *p, size_t newsize),
+ size_t *filesize, int *status);
+
+int uncompress2mem_from_mem(
+ char *inmemptr,
+ size_t inmemsize,
+ char **buffptr,
+ size_t *buffsize,
+ void *(*mem_realloc)(void *p, size_t newsize),
+ size_t *filesize,
+ int *status);
+
+int uncompress2file(char *filename,
+ FILE *indiskfile,
+ FILE *outdiskfile,
+ int *status);
+
+int compress2mem_from_mem(
+ char *inmemptr,
+ size_t inmemsize,
+ char **buffptr,
+ size_t *buffsize,
+ void *(*mem_realloc)(void *p, size_t newsize),
+ size_t *filesize,
+ int *status);
+
+int compress2file_from_mem(
+ char *inmemptr,
+ size_t inmemsize,
+ FILE *outdiskfile,
+ size_t *filesize, /* O - size of file, in bytes */
+ int *status);
+
+/* ==================== SHARED MEMORY DRIVER SECTION ======================= */
+
+#ifdef HAVE_SHMEM_SERVICES
+#include "drvrsmem.h"
+#endif
+
+/* ==================== END OF SHARED MEMORY DRIVER SECTION ================ */
+
+#endif
+
+
+#if defined(vms) || defined(__vms) || defined(WIN32) || defined(__WIN32__) || (defined(macintosh) && !defined(TARGET_API_MAC_CARBON))
+
+/* ================================================================== */
+/* A hack for nonunix machines, which lack strcasecmp and strncasecmp */
+/* ================================================================== */
+
+int strcasecmp (const char *s1, const char *s2 );
+int strncasecmp(const char *s1, const char *s2, size_t n);
+
+#endif
diff --git a/pkg/tbtables/cfitsio/getcol.c b/pkg/tbtables/cfitsio/getcol.c
new file mode 100644
index 00000000..31506d9f
--- /dev/null
+++ b/pkg/tbtables/cfitsio/getcol.c
@@ -0,0 +1,919 @@
+
+/* This file, getcol.c, contains routines that read data elements from */
+/* a FITS image or table. There are generic datatype routines. */
+
+/* The FITSIO software was written by William Pence at the High Energy */
+/* Astrophysic Science Archive Research Center (HEASARC) at the NASA */
+/* Goddard Space Flight Center. */
+
+#include <stdlib.h>
+#include "fitsio2.h"
+/*--------------------------------------------------------------------------*/
+int ffgpxv( fitsfile *fptr, /* I - FITS file pointer */
+ int datatype, /* I - datatype of the value */
+ long *firstpix, /* I - coord of first pixel to read (1s based) */
+ long nelem, /* I - number of values to read */
+ void *nulval, /* I - value for undefined pixels */
+ void *array, /* O - array of values that are returned */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from the primary array. The datatype of the
+ input array is defined by the 2nd argument. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being read).
+ Undefined elements will be set equal to NULVAL, unless NULVAL=0
+ in which case no checking for undefined values will be performed.
+ ANYNUL is returned with a value of .true. if any pixels are undefined.
+*/
+{
+ int naxis, ii;
+ long naxes[9];
+ OFF_T dimsize = 1, firstelem;
+
+ if (*status > 0 || nelem == 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ /* get the size of the image */
+ ffgidm(fptr, &naxis, status);
+ ffgisz(fptr, 9, naxes, status);
+
+ /* calculate the position of the first element in the array */
+ firstelem = 0;
+ for (ii=0; ii < naxis; ii++)
+ {
+ firstelem += ((firstpix[ii] - 1) * dimsize);
+ dimsize *= naxes[ii];
+ }
+ firstelem++;
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ if (datatype == TBYTE)
+ {
+ if (nulval == 0)
+ ffgpvb(fptr, 1, firstelem, nelem, 0,
+ (unsigned char *) array, anynul, status);
+ else
+ ffgpvb(fptr, 1, firstelem, nelem, *(unsigned char *) nulval,
+ (unsigned char *) array, anynul, status);
+ }
+ else if (datatype == TSBYTE)
+ {
+ if (nulval == 0)
+ ffgpvsb(fptr, 1, firstelem, nelem, 0,
+ (signed char *) array, anynul, status);
+ else
+ ffgpvsb(fptr, 1, firstelem, nelem, *(signed char *) nulval,
+ (signed char *) array, anynul, status);
+ }
+ else if (datatype == TUSHORT)
+ {
+ if (nulval == 0)
+ ffgpvui(fptr, 1, firstelem, nelem, 0,
+ (unsigned short *) array, anynul, status);
+ else
+ ffgpvui(fptr, 1, firstelem, nelem, *(unsigned short *) nulval,
+ (unsigned short *) array, anynul, status);
+ }
+ else if (datatype == TSHORT)
+ {
+ if (nulval == 0)
+ ffgpvi(fptr, 1, firstelem, nelem, 0,
+ (short *) array, anynul, status);
+ else
+ ffgpvi(fptr, 1, firstelem, nelem, *(short *) nulval,
+ (short *) array, anynul, status);
+ }
+ else if (datatype == TUINT)
+ {
+ if (nulval == 0)
+ ffgpvuk(fptr, 1, firstelem, nelem, 0,
+ (unsigned int *) array, anynul, status);
+ else
+ ffgpvuk(fptr, 1, firstelem, nelem, *(unsigned int *) nulval,
+ (unsigned int *) array, anynul, status);
+ }
+ else if (datatype == TINT)
+ {
+ if (nulval == 0)
+ ffgpvk(fptr, 1, firstelem, nelem, 0,
+ (int *) array, anynul, status);
+ else
+ ffgpvk(fptr, 1, firstelem, nelem, *(int *) nulval,
+ (int *) array, anynul, status);
+ }
+ else if (datatype == TULONG)
+ {
+ if (nulval == 0)
+ ffgpvuj(fptr, 1, firstelem, nelem, 0,
+ (unsigned long *) array, anynul, status);
+ else
+ ffgpvuj(fptr, 1, firstelem, nelem, *(unsigned long *) nulval,
+ (unsigned long *) array, anynul, status);
+ }
+ else if (datatype == TLONG)
+ {
+ if (nulval == 0)
+ ffgpvj(fptr, 1, firstelem, nelem, 0,
+ (long *) array, anynul, status);
+ else
+ ffgpvj(fptr, 1, firstelem, nelem, *(long *) nulval,
+ (long *) array, anynul, status);
+ }
+ else if (datatype == TLONGLONG)
+ {
+ if (nulval == 0)
+ ffgpvjj(fptr, 1, firstelem, nelem, 0,
+ (LONGLONG *) array, anynul, status);
+ else
+ ffgpvjj(fptr, 1, firstelem, nelem, *(LONGLONG *) nulval,
+ (LONGLONG *) array, anynul, status);
+ }
+ else if (datatype == TFLOAT)
+ {
+ if (nulval == 0)
+ ffgpve(fptr, 1, firstelem, nelem, 0,
+ (float *) array, anynul, status);
+ else
+ ffgpve(fptr, 1, firstelem, nelem, *(float *) nulval,
+ (float *) array, anynul, status);
+ }
+ else if (datatype == TDOUBLE)
+ {
+ if (nulval == 0)
+ ffgpvd(fptr, 1, firstelem, nelem, 0,
+ (double *) array, anynul, status);
+ else
+ {
+ ffgpvd(fptr, 1, firstelem, nelem, *(double *) nulval,
+ (double *) array, anynul, status);
+ }
+ }
+ else
+ *status = BAD_DATATYPE;
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgpxf( fitsfile *fptr, /* I - FITS file pointer */
+ int datatype, /* I - datatype of the value */
+ long *firstpix, /* I - coord of first pixel to read (1s based) */
+ long nelem, /* I - number of values to read */
+ void *array, /* O - array of values that are returned */
+ char *nullarray, /* O - returned array of null value flags */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from the primary array. The datatype of the
+ input array is defined by the 2nd argument. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being read).
+ The nullarray values will = 1 if the corresponding array value is null.
+ ANYNUL is returned with a value of .true. if any pixels are undefined.
+*/
+{
+ int naxis, ii;
+ long naxes[9];
+ OFF_T dimsize = 1, firstelem;
+
+ if (*status > 0 || nelem == 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ /* get the size of the image */
+ ffgidm(fptr, &naxis, status);
+ ffgisz(fptr, 9, naxes, status);
+
+ /* calculate the position of the first element in the array */
+ firstelem = 0;
+ for (ii=0; ii < naxis; ii++)
+ {
+ firstelem += ((firstpix[ii] - 1) * dimsize);
+ dimsize *= naxes[ii];
+ }
+ firstelem++;
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ if (datatype == TBYTE)
+ {
+ ffgpfb(fptr, 1, firstelem, nelem,
+ (unsigned char *) array, nullarray, anynul, status);
+ }
+ else if (datatype == TSBYTE)
+ {
+ ffgpfsb(fptr, 1, firstelem, nelem,
+ (signed char *) array, nullarray, anynul, status);
+ }
+ else if (datatype == TUSHORT)
+ {
+ ffgpfui(fptr, 1, firstelem, nelem,
+ (unsigned short *) array, nullarray, anynul, status);
+ }
+ else if (datatype == TSHORT)
+ {
+ ffgpfi(fptr, 1, firstelem, nelem,
+ (short *) array, nullarray, anynul, status);
+ }
+ else if (datatype == TUINT)
+ {
+ ffgpfuk(fptr, 1, firstelem, nelem,
+ (unsigned int *) array, nullarray, anynul, status);
+ }
+ else if (datatype == TINT)
+ {
+ ffgpfk(fptr, 1, firstelem, nelem,
+ (int *) array, nullarray, anynul, status);
+ }
+ else if (datatype == TULONG)
+ {
+ ffgpfuj(fptr, 1, firstelem, nelem,
+ (unsigned long *) array, nullarray, anynul, status);
+ }
+ else if (datatype == TLONG)
+ {
+ ffgpfj(fptr, 1, firstelem, nelem,
+ (long *) array, nullarray, anynul, status);
+ }
+ else if (datatype == TLONGLONG)
+ {
+ ffgpfjj(fptr, 1, firstelem, nelem,
+ (LONGLONG *) array, nullarray, anynul, status);
+ }
+ else if (datatype == TFLOAT)
+ {
+ ffgpfe(fptr, 1, firstelem, nelem,
+ (float *) array, nullarray, anynul, status);
+ }
+ else if (datatype == TDOUBLE)
+ {
+ ffgpfd(fptr, 1, firstelem, nelem,
+ (double *) array, nullarray, anynul, status);
+ }
+ else
+ *status = BAD_DATATYPE;
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgsv( fitsfile *fptr, /* I - FITS file pointer */
+ int datatype, /* I - datatype of the value */
+ long *blc, /* I - 'bottom left corner' of the subsection */
+ long *trc , /* I - 'top right corner' of the subsection */
+ long *inc, /* I - increment to be applied in each dim. */
+ void *nulval, /* I - value for undefined pixels */
+ void *array, /* O - array of values that are returned */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an section of values from the primary array. The datatype of the
+ input array is defined by the 2nd argument. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being read).
+ Undefined elements will be set equal to NULVAL, unless NULVAL=0
+ in which case no checking for undefined values will be performed.
+ ANYNUL is returned with a value of .true. if any pixels are undefined.
+*/
+{
+ int naxis;
+ long naxes[9];
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ /* get the size of the image */
+ ffgidm(fptr, &naxis, status);
+ ffgisz(fptr, 9, naxes, status);
+
+ if (datatype == TBYTE)
+ {
+ if (nulval == 0)
+ ffgsvb(fptr, 1, naxis, naxes, blc, trc, inc, 0,
+ (unsigned char *) array, anynul, status);
+ else
+ ffgsvb(fptr, 1, naxis, naxes, blc, trc, inc, *(unsigned char *) nulval,
+ (unsigned char *) array, anynul, status);
+ }
+ else if (datatype == TSBYTE)
+ {
+ if (nulval == 0)
+ ffgsvsb(fptr, 1, naxis, naxes, blc, trc, inc, 0,
+ (signed char *) array, anynul, status);
+ else
+ ffgsvsb(fptr, 1, naxis, naxes, blc, trc, inc, *(signed char *) nulval,
+ (signed char *) array, anynul, status);
+ }
+ else if (datatype == TUSHORT)
+ {
+ if (nulval == 0)
+ ffgsvui(fptr, 1, naxis, naxes, blc, trc, inc, 0,
+ (unsigned short *) array, anynul, status);
+ else
+ ffgsvui(fptr, 1, naxis, naxes,blc, trc, inc, *(unsigned short *) nulval,
+ (unsigned short *) array, anynul, status);
+ }
+ else if (datatype == TSHORT)
+ {
+ if (nulval == 0)
+ ffgsvi(fptr, 1, naxis, naxes, blc, trc, inc, 0,
+ (short *) array, anynul, status);
+ else
+ ffgsvi(fptr, 1, naxis, naxes, blc, trc, inc, *(short *) nulval,
+ (short *) array, anynul, status);
+ }
+ else if (datatype == TUINT)
+ {
+ if (nulval == 0)
+ ffgsvuk(fptr, 1, naxis, naxes, blc, trc, inc, 0,
+ (unsigned int *) array, anynul, status);
+ else
+ ffgsvuk(fptr, 1, naxis, naxes, blc, trc, inc, *(unsigned int *) nulval,
+ (unsigned int *) array, anynul, status);
+ }
+ else if (datatype == TINT)
+ {
+ if (nulval == 0)
+ ffgsvk(fptr, 1, naxis, naxes, blc, trc, inc, 0,
+ (int *) array, anynul, status);
+ else
+ ffgsvk(fptr, 1, naxis, naxes, blc, trc, inc, *(int *) nulval,
+ (int *) array, anynul, status);
+ }
+ else if (datatype == TULONG)
+ {
+ if (nulval == 0)
+ ffgsvuj(fptr, 1, naxis, naxes, blc, trc, inc, 0,
+ (unsigned long *) array, anynul, status);
+ else
+ ffgsvuj(fptr, 1, naxis, naxes, blc, trc, inc, *(unsigned long *) nulval,
+ (unsigned long *) array, anynul, status);
+ }
+ else if (datatype == TLONG)
+ {
+ if (nulval == 0)
+ ffgsvj(fptr, 1, naxis, naxes, blc, trc, inc, 0,
+ (long *) array, anynul, status);
+ else
+ ffgsvj(fptr, 1, naxis, naxes, blc, trc, inc, *(long *) nulval,
+ (long *) array, anynul, status);
+ }
+ else if (datatype == TLONGLONG)
+ {
+ if (nulval == 0)
+ ffgsvjj(fptr, 1, naxis, naxes, blc, trc, inc, 0,
+ (LONGLONG *) array, anynul, status);
+ else
+ ffgsvjj(fptr, 1, naxis, naxes, blc, trc, inc, *(LONGLONG *) nulval,
+ (LONGLONG *) array, anynul, status);
+ }
+ else if (datatype == TFLOAT)
+ {
+ if (nulval == 0)
+ ffgsve(fptr, 1, naxis, naxes, blc, trc, inc, 0,
+ (float *) array, anynul, status);
+ else
+ ffgsve(fptr, 1, naxis, naxes, blc, trc, inc, *(float *) nulval,
+ (float *) array, anynul, status);
+ }
+ else if (datatype == TDOUBLE)
+ {
+ if (nulval == 0)
+ ffgsvd(fptr, 1, naxis, naxes, blc, trc, inc, 0,
+ (double *) array, anynul, status);
+ else
+ ffgsvd(fptr, 1, naxis, naxes, blc, trc, inc, *(double *) nulval,
+ (double *) array, anynul, status);
+ }
+ else
+ *status = BAD_DATATYPE;
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgpv( fitsfile *fptr, /* I - FITS file pointer */
+ int datatype, /* I - datatype of the value */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ void *nulval, /* I - value for undefined pixels */
+ void *array, /* O - array of values that are returned */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from the primary array. The datatype of the
+ input array is defined by the 2nd argument. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being read).
+ Undefined elements will be set equal to NULVAL, unless NULVAL=0
+ in which case no checking for undefined values will be performed.
+ ANYNUL is returned with a value of .true. if any pixels are undefined.
+*/
+{
+
+ if (*status > 0 || nelem == 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ if (datatype == TBYTE)
+ {
+ if (nulval == 0)
+ ffgpvb(fptr, 1, firstelem, nelem, 0,
+ (unsigned char *) array, anynul, status);
+ else
+ ffgpvb(fptr, 1, firstelem, nelem, *(unsigned char *) nulval,
+ (unsigned char *) array, anynul, status);
+ }
+ else if (datatype == TSBYTE)
+ {
+ if (nulval == 0)
+ ffgpvsb(fptr, 1, firstelem, nelem, 0,
+ (signed char *) array, anynul, status);
+ else
+ ffgpvsb(fptr, 1, firstelem, nelem, *(signed char *) nulval,
+ (signed char *) array, anynul, status);
+ }
+ else if (datatype == TUSHORT)
+ {
+ if (nulval == 0)
+ ffgpvui(fptr, 1, firstelem, nelem, 0,
+ (unsigned short *) array, anynul, status);
+ else
+ ffgpvui(fptr, 1, firstelem, nelem, *(unsigned short *) nulval,
+ (unsigned short *) array, anynul, status);
+ }
+ else if (datatype == TSHORT)
+ {
+ if (nulval == 0)
+ ffgpvi(fptr, 1, firstelem, nelem, 0,
+ (short *) array, anynul, status);
+ else
+ ffgpvi(fptr, 1, firstelem, nelem, *(short *) nulval,
+ (short *) array, anynul, status);
+ }
+ else if (datatype == TUINT)
+ {
+ if (nulval == 0)
+ ffgpvuk(fptr, 1, firstelem, nelem, 0,
+ (unsigned int *) array, anynul, status);
+ else
+ ffgpvuk(fptr, 1, firstelem, nelem, *(unsigned int *) nulval,
+ (unsigned int *) array, anynul, status);
+ }
+ else if (datatype == TINT)
+ {
+ if (nulval == 0)
+ ffgpvk(fptr, 1, firstelem, nelem, 0,
+ (int *) array, anynul, status);
+ else
+ ffgpvk(fptr, 1, firstelem, nelem, *(int *) nulval,
+ (int *) array, anynul, status);
+ }
+ else if (datatype == TULONG)
+ {
+ if (nulval == 0)
+ ffgpvuj(fptr, 1, firstelem, nelem, 0,
+ (unsigned long *) array, anynul, status);
+ else
+ ffgpvuj(fptr, 1, firstelem, nelem, *(unsigned long *) nulval,
+ (unsigned long *) array, anynul, status);
+ }
+ else if (datatype == TLONG)
+ {
+ if (nulval == 0)
+ ffgpvj(fptr, 1, firstelem, nelem, 0,
+ (long *) array, anynul, status);
+ else
+ ffgpvj(fptr, 1, firstelem, nelem, *(long *) nulval,
+ (long *) array, anynul, status);
+ }
+ else if (datatype == TLONGLONG)
+ {
+ if (nulval == 0)
+ ffgpvjj(fptr, 1, firstelem, nelem, 0,
+ (LONGLONG *) array, anynul, status);
+ else
+ ffgpvjj(fptr, 1, firstelem, nelem, *(LONGLONG *) nulval,
+ (LONGLONG *) array, anynul, status);
+ }
+ else if (datatype == TFLOAT)
+ {
+ if (nulval == 0)
+ ffgpve(fptr, 1, firstelem, nelem, 0,
+ (float *) array, anynul, status);
+ else
+ ffgpve(fptr, 1, firstelem, nelem, *(float *) nulval,
+ (float *) array, anynul, status);
+ }
+ else if (datatype == TDOUBLE)
+ {
+ if (nulval == 0)
+ ffgpvd(fptr, 1, firstelem, nelem, 0,
+ (double *) array, anynul, status);
+ else
+ {
+ ffgpvd(fptr, 1, firstelem, nelem, *(double *) nulval,
+ (double *) array, anynul, status);
+ }
+ }
+ else
+ *status = BAD_DATATYPE;
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgpf( fitsfile *fptr, /* I - FITS file pointer */
+ int datatype, /* I - datatype of the value */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ void *array, /* O - array of values that are returned */
+ char *nullarray, /* O - array of null value flags */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from the primary array. The datatype of the
+ input array is defined by the 2nd argument. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being read).
+ The nullarray values will = 1 if the corresponding array value is null.
+ ANYNUL is returned with a value of .true. if any pixels are undefined.
+*/
+{
+
+ if (*status > 0 || nelem == 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ if (datatype == TBYTE)
+ {
+ ffgpfb(fptr, 1, firstelem, nelem,
+ (unsigned char *) array, nullarray, anynul, status);
+ }
+ else if (datatype == TSBYTE)
+ {
+ ffgpfsb(fptr, 1, firstelem, nelem,
+ (signed char *) array, nullarray, anynul, status);
+ }
+ else if (datatype == TUSHORT)
+ {
+ ffgpfui(fptr, 1, firstelem, nelem,
+ (unsigned short *) array, nullarray, anynul, status);
+ }
+ else if (datatype == TSHORT)
+ {
+ ffgpfi(fptr, 1, firstelem, nelem,
+ (short *) array, nullarray, anynul, status);
+ }
+ else if (datatype == TUINT)
+ {
+ ffgpfuk(fptr, 1, firstelem, nelem,
+ (unsigned int *) array, nullarray, anynul, status);
+ }
+ else if (datatype == TINT)
+ {
+ ffgpfk(fptr, 1, firstelem, nelem,
+ (int *) array, nullarray, anynul, status);
+ }
+ else if (datatype == TULONG)
+ {
+ ffgpfuj(fptr, 1, firstelem, nelem,
+ (unsigned long *) array, nullarray, anynul, status);
+ }
+ else if (datatype == TLONG)
+ {
+ ffgpfj(fptr, 1, firstelem, nelem,
+ (long *) array, nullarray, anynul, status);
+ }
+ else if (datatype == TLONGLONG)
+ {
+ ffgpfjj(fptr, 1, firstelem, nelem,
+ (LONGLONG *) array, nullarray, anynul, status);
+ }
+ else if (datatype == TFLOAT)
+ {
+ ffgpfe(fptr, 1, firstelem, nelem,
+ (float *) array, nullarray, anynul, status);
+ }
+ else if (datatype == TDOUBLE)
+ {
+ ffgpfd(fptr, 1, firstelem, nelem,
+ (double *) array, nullarray, anynul, status);
+ }
+ else
+ *status = BAD_DATATYPE;
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgcv( fitsfile *fptr, /* I - FITS file pointer */
+ int datatype, /* I - datatype of the value */
+ int colnum, /* I - number of column to write (1 = 1st col) */
+ long firstrow, /* I - first row to write (1 = 1st row) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ void *nulval, /* I - value for undefined pixels */
+ void *array, /* O - array of values that are returned */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from a table column. The datatype of the
+ input array is defined by the 2nd argument. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being read).
+ Undefined elements will be set equal to NULVAL, unless NULVAL=0
+ in which case no checking for undefined values will be performed.
+ ANYNUL is returned with a value of true if any pixels are undefined.
+*/
+{
+ char cdummy[2];
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ if (datatype == TBIT)
+ {
+ ffgcx(fptr, colnum, firstrow, firstelem, nelem, (char *) array, status);
+ }
+ else if (datatype == TBYTE)
+ {
+ if (nulval == 0)
+ ffgclb(fptr, colnum, firstrow, firstelem, nelem, 1, 1, 0,
+ (unsigned char *) array, cdummy, anynul, status);
+ else
+ ffgclb(fptr, colnum, firstrow, firstelem, nelem, 1, 1, *(unsigned char *)
+ nulval, (unsigned char *) array, cdummy, anynul, status);
+ }
+ else if (datatype == TSBYTE)
+ {
+ if (nulval == 0)
+ ffgclsb(fptr, colnum, firstrow, firstelem, nelem, 1, 1, 0,
+ (signed char *) array, cdummy, anynul, status);
+ else
+ ffgclsb(fptr, colnum, firstrow, firstelem, nelem, 1, 1, *(signed char *)
+ nulval, (signed char *) array, cdummy, anynul, status);
+ }
+ else if (datatype == TUSHORT)
+ {
+ if (nulval == 0)
+ ffgclui(fptr, colnum, firstrow, firstelem, nelem, 1, 1, 0,
+ (unsigned short *) array, cdummy, anynul, status);
+ else
+ ffgclui(fptr, colnum, firstrow, firstelem, nelem, 1, 1,
+ *(unsigned short *) nulval,
+ (unsigned short *) array, cdummy, anynul, status);
+ }
+ else if (datatype == TSHORT)
+ {
+ if (nulval == 0)
+ ffgcli(fptr, colnum, firstrow, firstelem, nelem, 1, 1, 0,
+ (short *) array, cdummy, anynul, status);
+ else
+ ffgcli(fptr, colnum, firstrow, firstelem, nelem, 1, 1, *(short *)
+ nulval, (short *) array, cdummy, anynul, status);
+ }
+ else if (datatype == TUINT)
+ {
+ if (nulval == 0)
+ ffgcluk(fptr, colnum, firstrow, firstelem, nelem, 1, 1, 0,
+ (unsigned int *) array, cdummy, anynul, status);
+ else
+ ffgcluk(fptr, colnum, firstrow, firstelem, nelem, 1, 1,
+ *(unsigned int *) nulval, (unsigned int *) array, cdummy, anynul,
+ status);
+ }
+ else if (datatype == TINT)
+ {
+ if (nulval == 0)
+ ffgclk(fptr, colnum, firstrow, firstelem, nelem, 1, 1, 0,
+ (int *) array, cdummy, anynul, status);
+ else
+ ffgclk(fptr, colnum, firstrow, firstelem, nelem, 1, 1, *(int *)
+ nulval, (int *) array, cdummy, anynul, status);
+ }
+ else if (datatype == TULONG)
+ {
+ if (nulval == 0)
+ ffgcluj(fptr, colnum, firstrow, firstelem, nelem, 1, 1, 0,
+ (unsigned long *) array, cdummy, anynul, status);
+ else
+ ffgcluj(fptr, colnum, firstrow, firstelem, nelem, 1, 1,
+ *(unsigned long *) nulval,
+ (unsigned long *) array, cdummy, anynul, status);
+ }
+ else if (datatype == TLONG)
+ {
+ if (nulval == 0)
+ ffgclj(fptr, colnum, firstrow, firstelem, nelem, 1, 1, 0,
+ (long *) array, cdummy, anynul, status);
+ else
+ ffgclj(fptr, colnum, firstrow, firstelem, nelem, 1, 1, *(long *)
+ nulval, (long *) array, cdummy, anynul, status);
+ }
+ else if (datatype == TLONGLONG)
+ {
+ if (nulval == 0)
+ ffgcljj(fptr, colnum, firstrow, firstelem, nelem, 1, 1, 0,
+ (LONGLONG *) array, cdummy, anynul, status);
+ else
+ ffgcljj(fptr, colnum, firstrow, firstelem, nelem, 1, 1, *(LONGLONG *)
+ nulval, (LONGLONG *) array, cdummy, anynul, status);
+ }
+ else if (datatype == TFLOAT)
+ {
+ if (nulval == 0)
+ ffgcle(fptr, colnum, firstrow, firstelem, nelem, 1, 1, 0.,
+ (float *) array, cdummy, anynul, status);
+ else
+ ffgcle(fptr, colnum, firstrow, firstelem, nelem, 1, 1, *(float *)
+ nulval,(float *) array, cdummy, anynul, status);
+ }
+ else if (datatype == TDOUBLE)
+ {
+ if (nulval == 0)
+ ffgcld(fptr, colnum, firstrow, firstelem, nelem, 1, 1, 0.,
+ (double *) array, cdummy, anynul, status);
+ else
+ ffgcld(fptr, colnum, firstrow, firstelem, nelem, 1, 1, *(double *)
+ nulval, (double *) array, cdummy, anynul, status);
+ }
+ else if (datatype == TCOMPLEX)
+ {
+ if (nulval == 0)
+ ffgcle(fptr, colnum, firstrow, (firstelem - 1) * 2 + 1, nelem * 2,
+ 1, 1, 0., (float *) array, cdummy, anynul, status);
+ else
+ ffgcle(fptr, colnum, firstrow, (firstelem - 1) * 2 + 1, nelem * 2,
+ 1, 1, *(float *) nulval, (float *) array, cdummy, anynul, status);
+ }
+ else if (datatype == TDBLCOMPLEX)
+ {
+ if (nulval == 0)
+ ffgcld(fptr, colnum, firstrow, (firstelem - 1) * 2 + 1, nelem * 2,
+ 1, 1, 0., (double *) array, cdummy, anynul, status);
+ else
+ ffgcld(fptr, colnum, firstrow, (firstelem - 1) * 2 + 1, nelem * 2,
+ 1, 1, *(double *) nulval, (double *) array, cdummy, anynul, status);
+ }
+
+ else if (datatype == TLOGICAL)
+ {
+ if (nulval == 0)
+ ffgcll(fptr, colnum, firstrow, firstelem, nelem, 1, 0,
+ (char *) array, cdummy, anynul, status);
+ else
+ ffgcll(fptr, colnum, firstrow, firstelem, nelem, 1, *(char *) nulval,
+ (char *) array, cdummy, anynul, status);
+ }
+ else if (datatype == TSTRING)
+ {
+ if (nulval == 0)
+ {
+ cdummy[0] = '\0';
+ ffgcls(fptr, colnum, firstrow, firstelem, nelem, 1,
+ cdummy, (char **) array, cdummy, anynul, status);
+ }
+ else
+ ffgcls(fptr, colnum, firstrow, firstelem, nelem, 1, (char *)
+ nulval, (char **) array, cdummy, anynul, status);
+ }
+ else
+ *status = BAD_DATATYPE;
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgcf( fitsfile *fptr, /* I - FITS file pointer */
+ int datatype, /* I - datatype of the value */
+ int colnum, /* I - number of column to write (1 = 1st col) */
+ long firstrow, /* I - first row to write (1 = 1st row) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ void *array, /* O - array of values that are returned */
+ char *nullarray, /* O - array of null value flags */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from a table column. The datatype of the
+ input array is defined by the 2nd argument. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being read).
+ ANYNUL is returned with a value of true if any pixels are undefined.
+*/
+{
+ void *nulval; /* dummy argument */
+ double dnulval = 0.;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ nulval = &dnulval; /* set to a harmless value; this is never used */
+
+ if (datatype == TBIT)
+ {
+ ffgcx(fptr, colnum, firstrow, firstelem, nelem, (char *) array, status);
+ }
+ else if (datatype == TBYTE)
+ {
+ ffgclb(fptr, colnum, firstrow, firstelem, nelem, 1, 2, *(unsigned char *)
+ nulval, (unsigned char *) array, nullarray, anynul, status);
+ }
+ else if (datatype == TSBYTE)
+ {
+ ffgclsb(fptr, colnum, firstrow, firstelem, nelem, 1, 2, *(signed char *)
+ nulval, (signed char *) array, nullarray, anynul, status);
+ }
+ else if (datatype == TUSHORT)
+ {
+ ffgclui(fptr, colnum, firstrow, firstelem, nelem, 1, 2,
+ *(unsigned short *) nulval,
+ (unsigned short *) array, nullarray, anynul, status);
+ }
+ else if (datatype == TSHORT)
+ {
+ ffgcli(fptr, colnum, firstrow, firstelem, nelem, 1, 2, *(short *)
+ nulval, (short *) array, nullarray, anynul, status);
+ }
+ else if (datatype == TUINT)
+ {
+ ffgcluk(fptr, colnum, firstrow, firstelem, nelem, 1, 2,
+ *(unsigned int *) nulval, (unsigned int *) array, nullarray, anynul,
+ status);
+ }
+ else if (datatype == TINT)
+ {
+ ffgclk(fptr, colnum, firstrow, firstelem, nelem, 1, 2, *(int *)
+ nulval, (int *) array, nullarray, anynul, status);
+ }
+ else if (datatype == TULONG)
+ {
+ ffgcluj(fptr, colnum, firstrow, firstelem, nelem, 1, 2,
+ *(unsigned long *) nulval,
+ (unsigned long *) array, nullarray, anynul, status);
+ }
+ else if (datatype == TLONG)
+ {
+ ffgclj(fptr, colnum, firstrow, firstelem, nelem, 1, 2, *(long *)
+ nulval, (long *) array, nullarray, anynul, status);
+ }
+ else if (datatype == TLONGLONG)
+ {
+ ffgcljj(fptr, colnum, firstrow, firstelem, nelem, 1, 2, *(LONGLONG *)
+ nulval, (LONGLONG *) array, nullarray, anynul, status);
+ }
+ else if (datatype == TFLOAT)
+ {
+ ffgcle(fptr, colnum, firstrow, firstelem, nelem, 1, 2, *(float *)
+ nulval,(float *) array, nullarray, anynul, status);
+ }
+ else if (datatype == TDOUBLE)
+ {
+ ffgcld(fptr, colnum, firstrow, firstelem, nelem, 1, 2, *(double *)
+ nulval, (double *) array, nullarray, anynul, status);
+ }
+ else if (datatype == TCOMPLEX)
+ {
+ ffgcfc(fptr, colnum, firstrow, firstelem, nelem,
+ (float *) array, nullarray, anynul, status);
+ }
+ else if (datatype == TDBLCOMPLEX)
+ {
+ ffgcfm(fptr, colnum, firstrow, firstelem, nelem,
+ (double *) array, nullarray, anynul, status);
+ }
+
+ else if (datatype == TLOGICAL)
+ {
+ ffgcll(fptr, colnum, firstrow, firstelem, nelem, 2, *(char *) nulval,
+ (char *) array, nullarray, anynul, status);
+ }
+ else if (datatype == TSTRING)
+ {
+ ffgcls(fptr, colnum, firstrow, firstelem, nelem, 2, (char *)
+ nulval, (char **) array, nullarray, anynul, status);
+ }
+ else
+ *status = BAD_DATATYPE;
+
+ return(*status);
+}
+
diff --git a/pkg/tbtables/cfitsio/getcolb.c b/pkg/tbtables/cfitsio/getcolb.c
new file mode 100644
index 00000000..9390064a
--- /dev/null
+++ b/pkg/tbtables/cfitsio/getcolb.c
@@ -0,0 +1,2111 @@
+/* This file, getcolb.c, contains routines that read data elements from */
+/* a FITS image or table, with unsigned char (unsigned byte) data type. */
+
+/* The FITSIO software was written by William Pence at the High Energy */
+/* Astrophysic Science Archive Research Center (HEASARC) at the NASA */
+/* Goddard Space Flight Center. */
+
+#include <math.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include "fitsio2.h"
+
+/*--------------------------------------------------------------------------*/
+int ffgpvb( fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to read (1 = 1st group) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ unsigned char nulval, /* I - value for undefined pixels */
+ unsigned char *array, /* O - array of values that are returned */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being read).
+ Undefined elements will be set equal to NULVAL, unless NULVAL=0
+ in which case no checking for undefined values will be performed.
+ ANYNUL is returned with a value of .true. if any pixels are undefined.
+*/
+{
+ long row;
+ char cdummy;
+ int nullcheck = 1;
+ unsigned char nullvalue;
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+ nullvalue = nulval; /* set local variable */
+
+ fits_read_compressed_pixels(fptr, TBYTE, firstelem, nelem,
+ nullcheck, &nullvalue, array, NULL, anynul, status);
+ return(*status);
+ }
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ row=maxvalue(1,group);
+
+ ffgclb(fptr, 2, row, firstelem, nelem, 1, 1, nulval,
+ array, &cdummy, anynul, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgpfb( fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to read (1 = 1st group) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ unsigned char *array, /* O - array of values that are returned */
+ char *nularray, /* O - array of null pixel flags */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being read).
+ Any undefined pixels in the returned array will be set = 0 and the
+ corresponding nularray value will be set = 1.
+ ANYNUL is returned with a value of .true. if any pixels are undefined.
+*/
+{
+ long row;
+ int nullcheck = 2;
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ fits_read_compressed_pixels(fptr, TBYTE, firstelem, nelem,
+ nullcheck, NULL, array, nularray, anynul, status);
+ return(*status);
+ }
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ row=maxvalue(1,group);
+
+ ffgclb(fptr, 2, row, firstelem, nelem, 1, 2, 0,
+ array, nularray, anynul, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffg2db(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to read (1 = 1st group) */
+ unsigned char nulval, /* set undefined pixels equal to this */
+ long ncols, /* I - number of pixels in each row of array */
+ long naxis1, /* I - FITS image NAXIS1 value */
+ long naxis2, /* I - FITS image NAXIS2 value */
+ unsigned char *array, /* O - array to be filled and returned */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an entire 2-D array of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of the
+ FITS array is not the same as the array being read). Any null
+ values in the array will be set equal to the value of nulval, unless
+ nulval = 0 in which case no null checking will be performed.
+*/
+{
+ /* call the 3D reading routine, with the 3rd dimension = 1 */
+
+ ffg3db(fptr, group, nulval, ncols, naxis2, naxis1, naxis2, 1, array,
+ anynul, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffg3db(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to read (1 = 1st group) */
+ unsigned char nulval, /* set undefined pixels equal to this */
+ long ncols, /* I - number of pixels in each row of array */
+ long nrows, /* I - number of rows in each plane of array */
+ long naxis1, /* I - FITS image NAXIS1 value */
+ long naxis2, /* I - FITS image NAXIS2 value */
+ long naxis3, /* I - FITS image NAXIS3 value */
+ unsigned char *array, /* O - array to be filled and returned */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an entire 3-D array of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of the
+ FITS array is not the same as the array being read). Any null
+ values in the array will be set equal to the value of nulval, unless
+ nulval = 0 in which case no null checking will be performed.
+*/
+{
+ long tablerow, nfits, narray, ii, jj;
+ char cdummy;
+ int nullcheck = 1;
+ long inc[] = {1,1,1};
+ long fpixel[] = {1,1,1};
+ long lpixel[3];
+ unsigned char nullvalue;
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ lpixel[0] = ncols;
+ lpixel[1] = nrows;
+ lpixel[2] = naxis3;
+ nullvalue = nulval; /* set local variable */
+
+ fits_read_compressed_img(fptr, TBYTE, fpixel, lpixel, inc,
+ nullcheck, &nullvalue, array, NULL, anynul, status);
+ return(*status);
+ }
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+ tablerow=maxvalue(1,group);
+
+ if (ncols == naxis1 && nrows == naxis2) /* arrays have same size? */
+ {
+ /* all the image pixels are contiguous, so read all at once */
+ ffgclb(fptr, 2, tablerow, 1, naxis1 * naxis2 * naxis3, 1, 1, nulval,
+ array, &cdummy, anynul, status);
+ return(*status);
+ }
+
+ if (ncols < naxis1 || nrows < naxis2)
+ return(*status = BAD_DIMEN);
+
+ nfits = 1; /* next pixel in FITS image to read */
+ narray = 0; /* next pixel in output array to be filled */
+
+ /* loop over naxis3 planes in the data cube */
+ for (jj = 0; jj < naxis3; jj++)
+ {
+ /* loop over the naxis2 rows in the FITS image, */
+ /* reading naxis1 pixels to each row */
+
+ for (ii = 0; ii < naxis2; ii++)
+ {
+ if (ffgclb(fptr, 2, tablerow, nfits, naxis1, 1, 1, nulval,
+ &array[narray], &cdummy, anynul, status) > 0)
+ return(*status);
+
+ nfits += naxis1;
+ narray += ncols;
+ }
+ narray += (nrows - naxis2) * ncols;
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgsvb(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of the column to read (1 = 1st) */
+ int naxis, /* I - number of dimensions in the FITS array */
+ long *naxes, /* I - size of each dimension */
+ long *blc, /* I - 'bottom left corner' of the subsection */
+ long *trc, /* I - 'top right corner' of the subsection */
+ long *inc, /* I - increment to be applied in each dimension */
+ unsigned char nulval, /* I - value to set undefined pixels */
+ unsigned char *array, /* O - array to be filled and returned */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read a subsection of data values from an image or a table column.
+ This routine is set up to handle a maximum of nine dimensions.
+*/
+{
+ long ii, i0, i1, i2, i3, i4, i5, i6, i7, i8, row, rstr, rstp, rinc;
+ long str[9], stp[9], incr[9], dir[9];
+ long nelem, nultyp, ninc, numcol;
+ OFF_T felem, dsize[10];
+ int hdutype, anyf;
+ char ldummy, msg[FLEN_ERRMSG];
+ int nullcheck = 1;
+ unsigned char nullvalue;
+
+ if (naxis < 1 || naxis > 9)
+ {
+ sprintf(msg, "NAXIS = %d in call to ffgsvb is out of range", naxis);
+ ffpmsg(msg);
+ return(*status = BAD_DIMEN);
+ }
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ nullvalue = nulval; /* set local variable */
+
+ fits_read_compressed_img(fptr, TBYTE, blc, trc, inc,
+ nullcheck, &nullvalue, array, NULL, anynul, status);
+ return(*status);
+ }
+
+/*
+ if this is a primary array, then the input COLNUM parameter should
+ be interpreted as the row number, and we will alway read the image
+ data from column 2 (any group parameters are in column 1).
+*/
+ if (ffghdt(fptr, &hdutype, status) > 0)
+ return(*status);
+
+ if (hdutype == IMAGE_HDU)
+ {
+ /* this is a primary array, or image extension */
+ if (colnum == 0)
+ {
+ rstr = 1;
+ rstp = 1;
+ }
+ else
+ {
+ rstr = colnum;
+ rstp = colnum;
+ }
+ rinc = 1;
+ numcol = 2;
+ }
+ else
+ {
+ /* this is a table, so the row info is in the (naxis+1) elements */
+ rstr = blc[naxis];
+ rstp = trc[naxis];
+ rinc = inc[naxis];
+ numcol = colnum;
+ }
+
+ nultyp = 1;
+ if (anynul)
+ *anynul = FALSE;
+
+ i0 = 0;
+ for (ii = 0; ii < 9; ii++)
+ {
+ str[ii] = 1;
+ stp[ii] = 1;
+ incr[ii] = 1;
+ dsize[ii] = 1;
+ dir[ii] = 1;
+ }
+
+ for (ii = 0; ii < naxis; ii++)
+ {
+ if (trc[ii] < blc[ii])
+ {
+ if (hdutype == IMAGE_HDU)
+ {
+ dir[ii] = -1;
+ }
+ else
+ {
+ sprintf(msg, "ffgsvb: illegal range specified for axis %ld", ii + 1);
+ ffpmsg(msg);
+ return(*status = BAD_PIX_NUM);
+ }
+ }
+
+ str[ii] = blc[ii];
+ stp[ii] = trc[ii];
+ incr[ii] = inc[ii];
+ dsize[ii + 1] = dsize[ii] * naxes[ii];
+ dsize[ii] = dsize[ii] * dir[ii];
+ }
+ dsize[naxis] = dsize[naxis] * dir[naxis];
+
+ if (naxis == 1 && naxes[0] == 1)
+ {
+ /* This is not a vector column, so read all the rows at once */
+ nelem = (rstp - rstr) / rinc + 1;
+ ninc = rinc;
+ rstp = rstr;
+ }
+ else
+ {
+ /* have to read each row individually, in all dimensions */
+ nelem = (stp[0]*dir[0] - str[0]*dir[0]) / inc[0] + 1;
+ ninc = incr[0] * dir[0];
+ }
+
+ for (row = rstr; row <= rstp; row += rinc)
+ {
+ for (i8 = str[8]*dir[8]; i8 <= stp[8]*dir[8]; i8 += incr[8])
+ {
+ for (i7 = str[7]*dir[7]; i7 <= stp[7]*dir[7]; i7 += incr[7])
+ {
+ for (i6 = str[6]*dir[6]; i6 <= stp[6]*dir[6]; i6 += incr[6])
+ {
+ for (i5 = str[5]*dir[5]; i5 <= stp[5]*dir[5]; i5 += incr[5])
+ {
+ for (i4 = str[4]*dir[4]; i4 <= stp[4]*dir[4]; i4 += incr[4])
+ {
+ for (i3 = str[3]*dir[3]; i3 <= stp[3]*dir[3]; i3 += incr[3])
+ {
+ for (i2 = str[2]*dir[2]; i2 <= stp[2]*dir[2]; i2 += incr[2])
+ {
+ for (i1 = str[1]*dir[1]; i1 <= stp[1]*dir[1]; i1 += incr[1])
+ {
+
+ felem=str[0] + (i1 - dir[1]) * dsize[1] + (i2 - dir[2]) * dsize[2] +
+ (i3 - dir[3]) * dsize[3] + (i4 - dir[4]) * dsize[4] +
+ (i5 - dir[5]) * dsize[5] + (i6 - dir[6]) * dsize[6] +
+ (i7 - dir[7]) * dsize[7] + (i8 - dir[8]) * dsize[8];
+
+ if ( ffgclb(fptr, numcol, row, felem, nelem, ninc, nultyp,
+ nulval, &array[i0], &ldummy, &anyf, status) > 0)
+ return(*status);
+
+ if (anyf && anynul)
+ *anynul = TRUE;
+
+ i0 += nelem;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgsfb(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of the column to read (1 = 1st) */
+ int naxis, /* I - number of dimensions in the FITS array */
+ long *naxes, /* I - size of each dimension */
+ long *blc, /* I - 'bottom left corner' of the subsection */
+ long *trc, /* I - 'top right corner' of the subsection */
+ long *inc, /* I - increment to be applied in each dimension */
+ unsigned char *array, /* O - array to be filled and returned */
+ char *flagval, /* O - set to 1 if corresponding value is null */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read a subsection of data values from an image or a table column.
+ This routine is set up to handle a maximum of nine dimensions.
+*/
+{
+ long ii,i0, i1,i2,i3,i4,i5,i6,i7,i8,row,rstr,rstp,rinc;
+ long str[9],stp[9],incr[9],dsize[10];
+ long felem, nelem, nultyp, ninc, numcol;
+ int hdutype, anyf;
+ unsigned char nulval = 0;
+ char msg[FLEN_ERRMSG];
+ int nullcheck = 2;
+
+ if (naxis < 1 || naxis > 9)
+ {
+ sprintf(msg, "NAXIS = %d in call to ffgsvb is out of range", naxis);
+ ffpmsg(msg);
+ return(*status = BAD_DIMEN);
+ }
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ fits_read_compressed_img(fptr, TBYTE, blc, trc, inc,
+ nullcheck, NULL, array, flagval, anynul, status);
+ return(*status);
+ }
+
+/*
+ if this is a primary array, then the input COLNUM parameter should
+ be interpreted as the row number, and we will alway read the image
+ data from column 2 (any group parameters are in column 1).
+*/
+ if (ffghdt(fptr, &hdutype, status) > 0)
+ return(*status);
+
+ if (hdutype == IMAGE_HDU)
+ {
+ /* this is a primary array, or image extension */
+ if (colnum == 0)
+ {
+ rstr = 1;
+ rstp = 1;
+ }
+ else
+ {
+ rstr = colnum;
+ rstp = colnum;
+ }
+ rinc = 1;
+ numcol = 2;
+ }
+ else
+ {
+ /* this is a table, so the row info is in the (naxis+1) elements */
+ rstr = blc[naxis];
+ rstp = trc[naxis];
+ rinc = inc[naxis];
+ numcol = colnum;
+ }
+
+ nultyp = 2;
+ if (anynul)
+ *anynul = FALSE;
+
+ i0 = 0;
+ for (ii = 0; ii < 9; ii++)
+ {
+ str[ii] = 1;
+ stp[ii] = 1;
+ incr[ii] = 1;
+ dsize[ii] = 1;
+ }
+
+ for (ii = 0; ii < naxis; ii++)
+ {
+ if (trc[ii] < blc[ii])
+ {
+ sprintf(msg, "ffgsvb: illegal range specified for axis %ld", ii + 1);
+ ffpmsg(msg);
+ return(*status = BAD_PIX_NUM);
+ }
+
+ str[ii] = blc[ii];
+ stp[ii] = trc[ii];
+ incr[ii] = inc[ii];
+ dsize[ii + 1] = dsize[ii] * naxes[ii];
+ }
+
+ if (naxis == 1 && naxes[0] == 1)
+ {
+ /* This is not a vector column, so read all the rows at once */
+ nelem = (rstp - rstr) / rinc + 1;
+ ninc = rinc;
+ rstp = rstr;
+ }
+ else
+ {
+ /* have to read each row individually, in all dimensions */
+ nelem = (stp[0] - str[0]) / inc[0] + 1;
+ ninc = incr[0];
+ }
+
+ for (row = rstr; row <= rstp; row += rinc)
+ {
+ for (i8 = str[8]; i8 <= stp[8]; i8 += incr[8])
+ {
+ for (i7 = str[7]; i7 <= stp[7]; i7 += incr[7])
+ {
+ for (i6 = str[6]; i6 <= stp[6]; i6 += incr[6])
+ {
+ for (i5 = str[5]; i5 <= stp[5]; i5 += incr[5])
+ {
+ for (i4 = str[4]; i4 <= stp[4]; i4 += incr[4])
+ {
+ for (i3 = str[3]; i3 <= stp[3]; i3 += incr[3])
+ {
+ for (i2 = str[2]; i2 <= stp[2]; i2 += incr[2])
+ {
+ for (i1 = str[1]; i1 <= stp[1]; i1 += incr[1])
+ {
+ felem=str[0] + (i1 - 1) * dsize[1] + (i2 - 1) * dsize[2] +
+ (i3 - 1) * dsize[3] + (i4 - 1) * dsize[4] +
+ (i5 - 1) * dsize[5] + (i6 - 1) * dsize[6] +
+ (i7 - 1) * dsize[7] + (i8 - 1) * dsize[8];
+
+ if ( ffgclb(fptr, numcol, row, felem, nelem, ninc, nultyp,
+ nulval, &array[i0], &flagval[i0], &anyf, status) > 0)
+ return(*status);
+
+ if (anyf && anynul)
+ *anynul = TRUE;
+
+ i0 += nelem;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffggpb( fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to read (1 = 1st group) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ unsigned char *array, /* O - array of values that are returned */
+ int *status) /* IO - error status */
+/*
+ Read an array of group parameters from the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being read).
+*/
+{
+ long row;
+ int idummy;
+ char cdummy;
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ row=maxvalue(1,group);
+
+ ffgclb(fptr, 1, row, firstelem, nelem, 1, 1, 0,
+ array, &cdummy, &idummy, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgcvb(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to read (1 = 1st col) */
+ long firstrow, /* I - first row to read (1 = 1st row) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ unsigned char nulval, /* I - value for null pixels */
+ unsigned char *array, /* O - array of values that are read */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from a column in the current FITS HDU. Automatic
+ datatype conversion will be performed if the datatype of the column does not
+ match the datatype of the array parameter. The output values will be scaled
+ by the FITS TSCALn and TZEROn values if these values have been defined.
+ Any undefined pixels will be set equal to the value of 'nulval' unless
+ nulval = 0 in which case no checks for undefined pixels will be made.
+*/
+{
+ char cdummy;
+
+ ffgclb(fptr, colnum, firstrow, firstelem, nelem, 1, 1, nulval,
+ array, &cdummy, anynul, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgcfb(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to read (1 = 1st col) */
+ long firstrow, /* I - first row to read (1 = 1st row) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ unsigned char *array, /* O - array of values that are read */
+ char *nularray, /* O - array of flags: 1 if null pixel; else 0 */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from a column in the current FITS HDU. Automatic
+ datatype conversion will be performed if the datatype of the column does not
+ match the datatype of the array parameter. The output values will be scaled
+ by the FITS TSCALn and TZEROn values if these values have been defined.
+ Nularray will be set = 1 if the corresponding array pixel is undefined,
+ otherwise nularray will = 0.
+*/
+{
+ unsigned char dummy = 0;
+
+ ffgclb(fptr, colnum, firstrow, firstelem, nelem, 1, 2, dummy,
+ array, nularray, anynul, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgclb( fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to read (1 = 1st col) */
+ long firstrow, /* I - first row to read (1 = 1st row) */
+ OFF_T firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ long elemincre, /* I - pixel increment; e.g., 2 = every other */
+ int nultyp, /* I - null value handling code: */
+ /* 1: set undefined pixels = nulval */
+ /* 2: set nularray=1 for undefined pixels */
+ unsigned char nulval, /* I - value for null pixels if nultyp = 1 */
+ unsigned char *array, /* O - array of values that are read */
+ char *nularray, /* O - array of flags = 1 if nultyp = 2 */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from a column in the current FITS HDU.
+ The column number may refer to a real column in an ASCII or binary table,
+ or it may refer be a virtual column in a 1 or more grouped FITS primary
+ array or image extension. FITSIO treats a primary array as a binary table
+ with 2 vector columns: the first column contains the group parameters (often
+ with length = 0) and the second column contains the array of image pixels.
+ Each row of the table represents a group in the case of multigroup FITS
+ images.
+
+ The output array of values will be converted from the datatype of the column
+ and will be scaled by the FITS TSCALn and TZEROn values if necessary.
+*/
+{
+ double scale, zero, power = 1.;
+ int tcode, maxelem, hdutype, xcode, decimals;
+ long twidth, incre, rownum, remain, next, ntodo;
+ long ii, rowincre, tnull, xwidth;
+ int convert, nulcheck, readcheck = 0;
+ OFF_T repeat, startpos, elemnum, readptr, rowlen;
+ char tform[20];
+ char message[81];
+ char snull[20]; /* the FITS null value if reading from ASCII table */
+
+ double cbuff[DBUFFSIZE / sizeof(double)]; /* align cbuff on word boundary */
+ void *buffer;
+
+ union u_tag {
+ char charval;
+ unsigned char ucharval;
+ } u;
+
+ if (*status > 0 || nelem == 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ buffer = cbuff;
+
+ if (anynul)
+ *anynul = 0;
+
+ if (nultyp == 2)
+ memset(nularray, 0, nelem); /* initialize nullarray */
+
+ /*---------------------------------------------------*/
+ /* Check input and get parameters about the column: */
+ /*---------------------------------------------------*/
+ if (elemincre < 0)
+ readcheck = -1; /* don't do range checking in this case */
+
+ ffgcpr( fptr, colnum, firstrow, firstelem, nelem, readcheck, &scale, &zero,
+ tform, &twidth, &tcode, &maxelem, &startpos, &elemnum, &incre,
+ &repeat, &rowlen, &hdutype, &tnull, snull, status);
+
+ /* special case */
+ if (tcode == TLOGICAL && elemincre == 1)
+ {
+ u.ucharval = nulval;
+ ffgcll(fptr, colnum, firstrow, firstelem, nelem, nultyp,
+ u.charval, (char *) array, nularray, anynul, status);
+
+ return(*status);
+ }
+
+ if (strchr(tform,'A') != NULL)
+ {
+ if (*status == BAD_ELEM_NUM)
+ {
+ /* ignore this error message */
+ *status = 0;
+ ffcmsg(); /* clear error stack */
+ }
+
+ /* interpret a 'A' ASCII column as a 'B' byte column ('8A' == '8B') */
+ /* This is an undocumented 'feature' in CFITSIO */
+
+ /* we have to reset some of the values returned by ffgcpr */
+
+ tcode = TBYTE;
+ incre = 1; /* each element is 1 byte wide */
+ repeat = twidth; /* total no. of chars in the col */
+ twidth = 1; /* width of each element */
+ scale = 1.0; /* no scaling */
+ zero = 0.0;
+ tnull = NULL_UNDEFINED; /* don't test for nulls */
+ maxelem = DBUFFSIZE;
+ }
+
+ if (*status > 0)
+ return(*status);
+
+ incre *= elemincre; /* multiply incre to just get every nth pixel */
+
+ if (tcode == TSTRING && hdutype == ASCII_TBL) /* setup for ASCII tables */
+ {
+ /* get the number of implied decimal places if no explicit decmal point */
+ ffasfm(tform, &xcode, &xwidth, &decimals, status);
+ for(ii = 0; ii < decimals; ii++)
+ power *= 10.;
+ }
+ /*------------------------------------------------------------------*/
+ /* Decide whether to check for null values in the input FITS file: */
+ /*------------------------------------------------------------------*/
+ nulcheck = nultyp; /* by default, check for null values in the FITS file */
+
+ if (nultyp == 1 && nulval == 0)
+ nulcheck = 0; /* calling routine does not want to check for nulls */
+
+ else if (tcode%10 == 1 && /* if reading an integer column, and */
+ tnull == NULL_UNDEFINED) /* if a null value is not defined, */
+ nulcheck = 0; /* then do not check for null values. */
+
+ else if (tcode == TSHORT && (tnull > SHRT_MAX || tnull < SHRT_MIN) )
+ nulcheck = 0; /* Impossible null value */
+
+ else if (tcode == TBYTE && (tnull > 255 || tnull < 0) )
+ nulcheck = 0; /* Impossible null value */
+
+ else if (tcode == TSTRING && snull[0] == ASCII_NULL_UNDEFINED)
+ nulcheck = 0;
+
+ /*----------------------------------------------------------------------*/
+ /* If FITS column and output data array have same datatype, then we do */
+ /* not need to use a temporary buffer to store intermediate datatype. */
+ /*----------------------------------------------------------------------*/
+ convert = 1;
+ if (tcode == TBYTE) /* Special Case: */
+ { /* no type convertion required, so read */
+ maxelem = nelem; /* data directly into output buffer. */
+
+ if (nulcheck == 0 && scale == 1. && zero == 0.)
+ convert = 0; /* no need to scale data or find nulls */
+ }
+
+ /*---------------------------------------------------------------------*/
+ /* Now read the pixels from the FITS column. If the column does not */
+ /* have the same datatype as the output array, then we have to read */
+ /* the raw values into a temporary buffer (of limited size). In */
+ /* the case of a vector colum read only 1 vector of values at a time */
+ /* then skip to the next row if more values need to be read. */
+ /* After reading the raw values, then call the fffXXYY routine to (1) */
+ /* test for undefined values, (2) convert the datatype if necessary, */
+ /* and (3) scale the values by the FITS TSCALn and TZEROn linear */
+ /* scaling parameters. */
+ /*---------------------------------------------------------------------*/
+ remain = nelem; /* remaining number of values to read */
+ next = 0; /* next element in array to be read */
+ rownum = 0; /* row number, relative to firstrow */
+
+ while (remain)
+ {
+ /* limit the number of pixels to read at one time to the number that
+ will fit in the buffer or to the number of pixels that remain in
+ the current vector, which ever is smaller.
+ */
+ ntodo = minvalue(remain, maxelem);
+ if (elemincre >= 0)
+ {
+ ntodo = minvalue(ntodo, ((repeat - elemnum - 1)/elemincre +1));
+ }
+ else
+ {
+ ntodo = minvalue(ntodo, (elemnum/(-elemincre) +1));
+ }
+
+ readptr = startpos + ((OFF_T)rownum * rowlen) + (elemnum * (incre / elemincre));
+
+ switch (tcode)
+ {
+ case (TBYTE):
+ ffgi1b(fptr, readptr, ntodo, incre, &array[next], status);
+ if (convert)
+ fffi1i1(&array[next], ntodo, scale, zero, nulcheck,
+ (unsigned char) tnull, nulval, &nularray[next], anynul,
+ &array[next], status);
+ break;
+ case (TSHORT):
+ ffgi2b(fptr, readptr, ntodo, incre, (short *) buffer, status);
+ fffi2i1((short *) buffer, ntodo, scale, zero, nulcheck,
+ (short) tnull, nulval, &nularray[next], anynul,
+ &array[next], status);
+ break;
+ case (TLONG):
+ ffgi4b(fptr, readptr, ntodo, incre, (INT32BIT *) buffer,
+ status);
+ fffi4i1((INT32BIT *) buffer, ntodo, scale, zero, nulcheck,
+ (INT32BIT) tnull, nulval, &nularray[next], anynul,
+ &array[next], status);
+ break;
+ case (TLONGLONG):
+ ffgi8b(fptr, readptr, ntodo, incre, (long *) buffer, status);
+ fffi8i1( (LONGLONG *) buffer, ntodo, scale, zero,
+ nulcheck, (long) tnull, nulval, &nularray[next],
+ anynul, &array[next], status);
+ break;
+ case (TFLOAT):
+ ffgr4b(fptr, readptr, ntodo, incre, (float *) buffer, status);
+ fffr4i1((float *) buffer, ntodo, scale, zero, nulcheck,
+ nulval, &nularray[next], anynul,
+ &array[next], status);
+ break;
+ case (TDOUBLE):
+ ffgr8b(fptr, readptr, ntodo, incre, (double *) buffer, status);
+ fffr8i1((double *) buffer, ntodo, scale, zero, nulcheck,
+ nulval, &nularray[next], anynul,
+ &array[next], status);
+ break;
+ case (TSTRING):
+ ffmbyt(fptr, readptr, REPORT_EOF, status);
+
+ if (incre == twidth) /* contiguous bytes */
+ ffgbyt(fptr, ntodo * twidth, buffer, status);
+ else
+ ffgbytoff(fptr, twidth, ntodo, incre - twidth, buffer,
+ status);
+
+ /* interpret the string as an ASCII formated number */
+ fffstri1((char *) buffer, ntodo, scale, zero, twidth, power,
+ nulcheck, snull, nulval, &nularray[next], anynul,
+ &array[next], status);
+ break;
+
+ default: /* error trap for invalid column format */
+ sprintf(message,
+ "Cannot read bytes from column %d which has format %s",
+ colnum, tform);
+ ffpmsg(message);
+ if (hdutype == ASCII_TBL)
+ return(*status = BAD_ATABLE_FORMAT);
+ else
+ return(*status = BAD_BTABLE_FORMAT);
+
+ } /* End of switch block */
+
+ /*-------------------------*/
+ /* Check for fatal error */
+ /*-------------------------*/
+ if (*status > 0) /* test for error during previous read operation */
+ {
+ if (hdutype > 0)
+ sprintf(message,
+ "Error reading elements %ld thru %ld from column %d (ffgclb).",
+ next+1, next+ntodo, colnum);
+ else
+ sprintf(message,
+ "Error reading elements %ld thru %ld from image (ffgclb).",
+ next+1, next+ntodo);
+
+ ffpmsg(message);
+ return(*status);
+ }
+
+ /*--------------------------------------------*/
+ /* increment the counters for the next loop */
+ /*--------------------------------------------*/
+ remain -= ntodo;
+ if (remain)
+ {
+ next += ntodo;
+ elemnum = elemnum + (ntodo * elemincre);
+
+ if (elemnum >= repeat) /* completed a row; start on later row */
+ {
+ rowincre = elemnum / repeat;
+ rownum += rowincre;
+ elemnum = elemnum - (rowincre * repeat);
+ }
+ else if (elemnum < 0) /* completed a row; start on a previous row */
+ {
+ rowincre = (-elemnum - 1) / repeat + 1;
+ rownum -= rowincre;
+ elemnum = (rowincre * repeat) + elemnum;
+ }
+ }
+ } /* End of main while Loop */
+
+
+ /*--------------------------------*/
+ /* check for numerical overflow */
+ /*--------------------------------*/
+ if (*status == OVERFLOW_ERR)
+ {
+ ffpmsg(
+ "Numerical overflow during type conversion while reading FITS data.");
+ *status = NUM_OVERFLOW;
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffi1i1(unsigned char *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ unsigned char tnull, /* I - value of FITS TNULLn keyword if any */
+ unsigned char nullval,/* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ unsigned char *output,/* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to tnull. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ { /* this routine is normally not called in this case */
+ memcpy(output, input, ntodo );
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DUCHAR_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DUCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UCHAR_MAX;
+ }
+ else
+ output[ii] = (unsigned char) dvalue;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ output[ii] = input[ii];
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DUCHAR_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DUCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UCHAR_MAX;
+ }
+ else
+ output[ii] = (unsigned char) dvalue;
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffi2i1(short *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ short tnull, /* I - value of FITS TNULLn keyword if any */
+ unsigned char nullval,/* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ unsigned char *output,/* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to tnull. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] < 0)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (input[ii] > UCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UCHAR_MAX;
+ }
+ else
+ output[ii] = (unsigned char) input[ii];
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DUCHAR_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DUCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UCHAR_MAX;
+ }
+ else
+ output[ii] = (unsigned char) dvalue;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+
+ else
+ {
+ if (input[ii] < 0)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (input[ii] > UCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UCHAR_MAX;
+ }
+ else
+ output[ii] = (unsigned char) input[ii];
+ }
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DUCHAR_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DUCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UCHAR_MAX;
+ }
+ else
+ output[ii] = (unsigned char) dvalue;
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffi4i1(INT32BIT *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ INT32BIT tnull, /* I - value of FITS TNULLn keyword if any */
+ unsigned char nullval,/* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ unsigned char *output,/* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to tnull. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] < 0)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (input[ii] > UCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UCHAR_MAX;
+ }
+ else
+ output[ii] = (unsigned char) input[ii];
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DUCHAR_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DUCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UCHAR_MAX;
+ }
+ else
+ output[ii] = (unsigned char) dvalue;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ if (input[ii] < 0)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (input[ii] > UCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UCHAR_MAX;
+ }
+ else
+ output[ii] = (unsigned char) input[ii];
+ }
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DUCHAR_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DUCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UCHAR_MAX;
+ }
+ else
+ output[ii] = (unsigned char) dvalue;
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffi8i1(LONGLONG *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ long tnull, /* I - value of FITS TNULLn keyword if any */
+ unsigned char nullval,/* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ unsigned char *output,/* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to tnull. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+#if (LONGSIZE == 32) && (! defined HAVE_LONGLONG)
+
+ /* This block of code is only used in cases where there is */
+ /* no native 8-byte integer support. We have to interpret */
+ /* the corresponding pair of 4-byte integers which are */
+ /* are equivalent to the 8-byte integer. */
+
+ long ii,jj, kk;
+ double dvalue;
+ unsigned long *uinput;
+
+ uinput = (unsigned long *) input;
+
+#if BYTESWAPPED /* jj points to the most significant part of the 8-byte int */
+ jj = 1;
+ kk = 0;
+#else
+ jj = 0;
+ kk = 1;
+#endif
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++, jj += 2, kk += 2)
+ {
+ if (uinput[jj] & 0x80000000) /* negative number */
+ dvalue = (uinput[jj] ^ 0xffffffff) * -4294967296. -
+ (uinput[kk] ^ 0xffffffff) - 1.;
+ else /* positive number */
+ dvalue = uinput[jj] * 4294967296. + uinput[kk];
+
+ if (dvalue < DUCHAR_MIN )
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DUCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UCHAR_MAX;
+ }
+ else
+ output[ii] = (unsigned char) dvalue;
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++, jj += 2, kk += 2)
+ {
+ if (uinput[jj] & 0x80000000) /* negative number */
+ dvalue = ((uinput[jj] ^ 0xffffffff) * -4294967296. -
+ (uinput[kk] ^ 0xffffffff) - 1.) * scale + zero;
+ else /* positive number */
+ dvalue = (uinput[jj] * 4294967296. + uinput[kk])
+ * scale + zero;
+
+ if (dvalue < DUCHAR_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DUCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UCHAR_MAX;
+ }
+ else
+ output[ii] = (unsigned char) dvalue;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++, jj += 2, kk += 2)
+ {
+ if (uinput[jj] & 0x80000000) /* negative number */
+ dvalue = (uinput[jj] ^ 0xffffffff) * -4294967296. -
+ (uinput[kk] ^ 0xffffffff) - 1.;
+ else /* positive number */
+ dvalue = uinput[jj] * 4294967296. + uinput[kk];
+
+ if (dvalue == (double) tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ if (dvalue < DUCHAR_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DUCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UCHAR_MAX;
+ }
+ else
+ output[ii] = (unsigned char) dvalue;
+ }
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++, jj += 2, kk += 2)
+ {
+ if (uinput[jj] & 0x80000000) /* negative number */
+ dvalue = (uinput[jj] ^ 0xffffffff) * -4294967296. -
+ (uinput[kk] ^ 0xffffffff) - 1.;
+ else /* positive number */
+ dvalue = uinput[jj] * 4294967296. + uinput[kk];
+
+ if (dvalue == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ dvalue = dvalue * scale + zero;
+
+ if (dvalue < DUCHAR_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DUCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UCHAR_MAX;
+ }
+ else
+ output[ii] = (unsigned char) dvalue;
+ }
+ }
+ }
+ }
+
+#else
+
+ /* this block works on machines which support an 8-byte integer type */
+
+ long ii;
+ double dvalue;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] < 0)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (input[ii] > UCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UCHAR_MAX;
+ }
+ else
+ output[ii] = (unsigned char) input[ii];
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DUCHAR_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DUCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UCHAR_MAX;
+ }
+ else
+ output[ii] = (unsigned char) dvalue;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ if (input[ii] < 0)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (input[ii] > UCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UCHAR_MAX;
+ }
+ else
+ output[ii] = (unsigned char) input[ii];
+ }
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DUCHAR_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DUCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UCHAR_MAX;
+ }
+ else
+ output[ii] = (unsigned char) dvalue;
+ }
+ }
+ }
+ }
+
+#endif
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffr4i1(float *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ unsigned char nullval,/* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ unsigned char *output,/* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to NaN. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ long ii;
+ double dvalue;
+ short *sptr, iret;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] < DUCHAR_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (input[ii] > DUCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UCHAR_MAX;
+ }
+ else
+ output[ii] = (unsigned char) input[ii];
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DUCHAR_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DUCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UCHAR_MAX;
+ }
+ else
+ output[ii] = (unsigned char) dvalue;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ sptr = (short *) input;
+
+#if BYTESWAPPED && MACHINE != VAXVMS && MACHINE != ALPHAVMS
+ sptr++; /* point to MSBs */
+#endif
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++, sptr += 2)
+ {
+ /* use redundant boolean logic in following statement */
+ /* to suppress irritating Borland compiler warning message */
+ if (0 != (iret = fnan(*sptr) ) ) /* test for NaN or underflow */
+ {
+ if (iret == 1) /* is it a NaN? */
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else /* it's an underflow */
+ output[ii] = 0;
+ }
+ else
+ {
+ if (input[ii] < DUCHAR_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (input[ii] > DUCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UCHAR_MAX;
+ }
+ else
+ output[ii] = (unsigned char) input[ii];
+ }
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++, sptr += 2)
+ {
+ if (0 != (iret = fnan(*sptr) ) ) /* test for NaN or underflow */
+ {
+ if (iret == 1) /* is it a NaN? */
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else /* it's an underflow */
+ {
+ if (zero < DUCHAR_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (zero > DUCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UCHAR_MAX;
+ }
+ else
+ output[ii] = (unsigned char) zero;
+ }
+ }
+ else
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DUCHAR_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DUCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UCHAR_MAX;
+ }
+ else
+ output[ii] = (unsigned char) dvalue;
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffr8i1(double *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ unsigned char nullval,/* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ unsigned char *output,/* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to NaN. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ long ii;
+ double dvalue;
+ short *sptr, iret;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] < DUCHAR_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (input[ii] > DUCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UCHAR_MAX;
+ }
+ else
+ output[ii] = (unsigned char) input[ii];
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DUCHAR_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DUCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UCHAR_MAX;
+ }
+ else
+ output[ii] = (unsigned char) dvalue;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ sptr = (short *) input;
+
+#if BYTESWAPPED && MACHINE != VAXVMS && MACHINE != ALPHAVMS
+ sptr += 3; /* point to MSBs */
+#endif
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++, sptr += 4)
+ {
+ if (0 != (iret = dnan(*sptr)) ) /* test for NaN or underflow */
+ {
+ if (iret == 1) /* is it a NaN? */
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else /* it's an underflow */
+ output[ii] = 0;
+ }
+ else
+ {
+ if (input[ii] < DUCHAR_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (input[ii] > DUCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UCHAR_MAX;
+ }
+ else
+ output[ii] = (unsigned char) input[ii];
+ }
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++, sptr += 4)
+ {
+ if (0 != (iret = dnan(*sptr)) ) /* test for NaN or underflow */
+ {
+ if (iret == 1) /* is it a NaN? */
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else /* it's an underflow */
+ {
+ if (zero < DUCHAR_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (zero > DUCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UCHAR_MAX;
+ }
+ else
+ output[ii] = (unsigned char) zero;
+ }
+ }
+ else
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DUCHAR_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DUCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UCHAR_MAX;
+ }
+ else
+ output[ii] = (unsigned char) dvalue;
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffstri1(char *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ long twidth, /* I - width of each substring of chars */
+ double implipower, /* I - power of 10 of implied decimal */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ char *snull, /* I - value of FITS null string, if any */
+ unsigned char nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ unsigned char *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file. Check
+ for null values and do scaling if required. The nullcheck code value
+ determines how any null values in the input array are treated. A null
+ value is an input pixel that is equal to snull. If nullcheck= 0, then
+ no special checking for nulls is performed. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ int nullen;
+ long ii;
+ double dvalue;
+ char *cstring, message[81];
+ char *cptr, *tpos;
+ char tempstore, chrzero = '0';
+ double val, power;
+ int exponent, sign, esign, decpt;
+
+ nullen = strlen(snull);
+ cptr = input; /* pointer to start of input string */
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ cstring = cptr;
+ /* temporarily insert a null terminator at end of the string */
+ tpos = cptr + twidth;
+ tempstore = *tpos;
+ *tpos = 0;
+
+ /* check if null value is defined, and if the */
+ /* column string is identical to the null string */
+ if (snull[0] != ASCII_NULL_UNDEFINED &&
+ !strncmp(snull, cptr, nullen) )
+ {
+ if (nullcheck)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ cptr += twidth;
+ }
+ else
+ {
+ /* value is not the null value, so decode it */
+ /* remove any embedded blank characters from the string */
+
+ decpt = 0;
+ sign = 1;
+ val = 0.;
+ power = 1.;
+ exponent = 0;
+ esign = 1;
+
+ while (*cptr == ' ') /* skip leading blanks */
+ cptr++;
+
+ if (*cptr == '-' || *cptr == '+') /* check for leading sign */
+ {
+ if (*cptr == '-')
+ sign = -1;
+
+ cptr++;
+
+ while (*cptr == ' ') /* skip blanks between sign and value */
+ cptr++;
+ }
+
+ while (*cptr >= '0' && *cptr <= '9')
+ {
+ val = val * 10. + *cptr - chrzero; /* accumulate the value */
+ cptr++;
+
+ while (*cptr == ' ') /* skip embedded blanks in the value */
+ cptr++;
+ }
+
+ if (*cptr == '.') /* check for decimal point */
+ {
+ decpt = 1;
+ cptr++;
+ while (*cptr == ' ') /* skip any blanks */
+ cptr++;
+
+ while (*cptr >= '0' && *cptr <= '9')
+ {
+ val = val * 10. + *cptr - chrzero; /* accumulate the value */
+ power = power * 10.;
+ cptr++;
+
+ while (*cptr == ' ') /* skip embedded blanks in the value */
+ cptr++;
+ }
+ }
+
+ if (*cptr == 'E' || *cptr == 'D') /* check for exponent */
+ {
+ cptr++;
+ while (*cptr == ' ') /* skip blanks */
+ cptr++;
+
+ if (*cptr == '-' || *cptr == '+') /* check for exponent sign */
+ {
+ if (*cptr == '-')
+ esign = -1;
+
+ cptr++;
+
+ while (*cptr == ' ') /* skip blanks between sign and exp */
+ cptr++;
+ }
+
+ while (*cptr >= '0' && *cptr <= '9')
+ {
+ exponent = exponent * 10 + *cptr - chrzero; /* accumulate exp */
+ cptr++;
+
+ while (*cptr == ' ') /* skip embedded blanks */
+ cptr++;
+ }
+ }
+
+ if (*cptr != 0) /* should end up at the null terminator */
+ {
+ sprintf(message, "Cannot read number from ASCII table");
+ ffpmsg(message);
+ sprintf(message, "Column field = %s.", cstring);
+ ffpmsg(message);
+ /* restore the char that was overwritten by the null */
+ *tpos = tempstore;
+ return(*status = BAD_C2D);
+ }
+
+ if (!decpt) /* if no explicit decimal, use implied */
+ power = implipower;
+
+ dvalue = (sign * val / power) * pow(10., (double) (esign * exponent));
+
+ dvalue = dvalue * scale + zero; /* apply the scaling */
+
+ if (dvalue < DUCHAR_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DUCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UCHAR_MAX;
+ }
+ else
+ output[ii] = (unsigned char) dvalue;
+ }
+ /* restore the char that was overwritten by the null */
+ *tpos = tempstore;
+ }
+ return(*status);
+}
diff --git a/pkg/tbtables/cfitsio/getcold.c b/pkg/tbtables/cfitsio/getcold.c
new file mode 100644
index 00000000..dfe77f89
--- /dev/null
+++ b/pkg/tbtables/cfitsio/getcold.c
@@ -0,0 +1,1768 @@
+/* This file, getcold.c, contains routines that read data elements from */
+/* a FITS image or table, with double datatype. */
+
+/* The FITSIO software was written by William Pence at the High Energy */
+/* Astrophysic Science Archive Research Center (HEASARC) at the NASA */
+/* Goddard Space Flight Center. */
+
+#include <math.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include "fitsio2.h"
+
+/*--------------------------------------------------------------------------*/
+int ffgpvd( fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to read (1 = 1st group) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ double nulval, /* I - value for undefined pixels */
+ double *array, /* O - array of values that are returned */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being read).
+ Undefined elements will be set equal to NULVAL, unless NULVAL=0
+ in which case no checking for undefined values will be performed.
+ ANYNUL is returned with a value of .true. if any pixels are undefined.
+*/
+{
+ long row;
+ char cdummy;
+ int nullcheck = 1;
+ double nullvalue;
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+ nullvalue = nulval; /* set local variable */
+
+ fits_read_compressed_pixels(fptr, TDOUBLE, firstelem, nelem,
+ nullcheck, &nullvalue, array, NULL, anynul, status);
+ return(*status);
+ }
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ row=maxvalue(1,group);
+
+ ffgcld(fptr, 2, row, firstelem, nelem, 1, 1, nulval,
+ array, &cdummy, anynul, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgpfd( fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to read (1 = 1st group) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ double *array, /* O - array of values that are returned */
+ char *nularray, /* O - array of null pixel flags */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being read).
+ Any undefined pixels in the returned array will be set = 0 and the
+ corresponding nularray value will be set = 1.
+ ANYNUL is returned with a value of .true. if any pixels are undefined.
+*/
+{
+ long row;
+ int nullcheck = 2;
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ fits_read_compressed_pixels(fptr, TDOUBLE, firstelem, nelem,
+ nullcheck, NULL, array, nularray, anynul, status);
+ return(*status);
+ }
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ row=maxvalue(1,group);
+
+ ffgcld(fptr, 2, row, firstelem, nelem, 1, 2, 0.,
+ array, nularray, anynul, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffg2dd(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to read (1 = 1st group) */
+ double nulval, /* set undefined pixels equal to this */
+ long ncols, /* I - number of pixels in each row of array */
+ long naxis1, /* I - FITS image NAXIS1 value */
+ long naxis2, /* I - FITS image NAXIS2 value */
+ double *array, /* O - array to be filled and returned */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an entire 2-D array of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of the
+ FITS array is not the same as the array being read). Any null
+ values in the array will be set equal to the value of nulval, unless
+ nulval = 0 in which case no null checking will be performed.
+*/
+{
+ /* call the 3D reading routine, with the 3rd dimension = 1 */
+
+ ffg3dd(fptr, group, nulval, ncols, naxis2, naxis1, naxis2, 1, array,
+ anynul, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffg3dd(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to read (1 = 1st group) */
+ double nulval, /* set undefined pixels equal to this */
+ long ncols, /* I - number of pixels in each row of array */
+ long nrows, /* I - number of rows in each plane of array */
+ long naxis1, /* I - FITS image NAXIS1 value */
+ long naxis2, /* I - FITS image NAXIS2 value */
+ long naxis3, /* I - FITS image NAXIS3 value */
+ double *array, /* O - array to be filled and returned */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an entire 3-D array of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of the
+ FITS array is not the same as the array being read). Any null
+ values in the array will be set equal to the value of nulval, unless
+ nulval = 0 in which case no null checking will be performed.
+*/
+{
+ long tablerow, nfits, narray, ii, jj;
+ char cdummy;
+ int nullcheck = 1;
+ long inc[] = {1,1,1};
+ long fpixel[] = {1,1,1};
+ long lpixel[3];
+ double nullvalue;
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ lpixel[0] = ncols;
+ lpixel[1] = nrows;
+ lpixel[2] = naxis3;
+ nullvalue = nulval; /* set local variable */
+
+ fits_read_compressed_img(fptr, TDOUBLE, fpixel, lpixel, inc,
+ nullcheck, &nullvalue, array, NULL, anynul, status);
+ return(*status);
+ }
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+ tablerow=maxvalue(1,group);
+
+ if (ncols == naxis1 && nrows == naxis2) /* arrays have same size? */
+ {
+ /* all the image pixels are contiguous, so read all at once */
+ ffgcld(fptr, 2, tablerow, 1, naxis1 * naxis2 * naxis3, 1, 1, nulval,
+ array, &cdummy, anynul, status);
+ return(*status);
+ }
+
+ if (ncols < naxis1 || nrows < naxis2)
+ return(*status = BAD_DIMEN);
+
+ nfits = 1; /* next pixel in FITS image to read */
+ narray = 0; /* next pixel in output array to be filled */
+
+ /* loop over naxis3 planes in the data cube */
+ for (jj = 0; jj < naxis3; jj++)
+ {
+ /* loop over the naxis2 rows in the FITS image, */
+ /* reading naxis1 pixels to each row */
+
+ for (ii = 0; ii < naxis2; ii++)
+ {
+ if (ffgcld(fptr, 2, tablerow, nfits, naxis1, 1, 1, nulval,
+ &array[narray], &cdummy, anynul, status) > 0)
+ return(*status);
+
+ nfits += naxis1;
+ narray += ncols;
+ }
+ narray += (nrows - naxis2) * ncols;
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgsvd(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of the column to read (1 = 1st) */
+ int naxis, /* I - number of dimensions in the FITS array */
+ long *naxes, /* I - size of each dimension */
+ long *blc, /* I - 'bottom left corner' of the subsection */
+ long *trc, /* I - 'top right corner' of the subsection */
+ long *inc, /* I - increment to be applied in each dimension */
+ double nulval, /* I - value to set undefined pixels */
+ double *array, /* O - array to be filled and returned */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read a subsection of data values from an image or a table column.
+ This routine is set up to handle a maximum of nine dimensions.
+*/
+{
+ long ii,i0, i1,i2,i3,i4,i5,i6,i7,i8,row,rstr,rstp,rinc;
+ long str[9],stp[9],incr[9],dir[9];
+ long nelem, nultyp, ninc, numcol;
+ OFF_T felem, dsize[10];
+ int hdutype, anyf;
+ char ldummy, msg[FLEN_ERRMSG];
+ int nullcheck = 1;
+ double nullvalue;
+
+ if (naxis < 1 || naxis > 9)
+ {
+ sprintf(msg, "NAXIS = %d in call to ffgsvd is out of range", naxis);
+ ffpmsg(msg);
+ return(*status = BAD_DIMEN);
+ }
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ nullvalue = nulval; /* set local variable */
+
+ fits_read_compressed_img(fptr, TDOUBLE, blc, trc, inc,
+ nullcheck, &nullvalue, array, NULL, anynul, status);
+ return(*status);
+ }
+
+/*
+ if this is a primary array, then the input COLNUM parameter should
+ be interpreted as the row number, and we will alway read the image
+ data from column 2 (any group parameters are in column 1).
+*/
+ if (ffghdt(fptr, &hdutype, status) > 0)
+ return(*status);
+
+ if (hdutype == IMAGE_HDU)
+ {
+ /* this is a primary array, or image extension */
+ if (colnum == 0)
+ {
+ rstr = 1;
+ rstp = 1;
+ }
+ else
+ {
+ rstr = colnum;
+ rstp = colnum;
+ }
+ rinc = 1;
+ numcol = 2;
+ }
+ else
+ {
+ /* this is a table, so the row info is in the (naxis+1) elements */
+ rstr = blc[naxis];
+ rstp = trc[naxis];
+ rinc = inc[naxis];
+ numcol = colnum;
+ }
+
+ nultyp = 1;
+ if (anynul)
+ *anynul = FALSE;
+
+ i0 = 0;
+ for (ii = 0; ii < 9; ii++)
+ {
+ str[ii] = 1;
+ stp[ii] = 1;
+ incr[ii] = 1;
+ dsize[ii] = 1;
+ dir[ii] = 1;
+ }
+
+ for (ii = 0; ii < naxis; ii++)
+ {
+ if (trc[ii] < blc[ii])
+ {
+ if (hdutype == IMAGE_HDU)
+ {
+ dir[ii] = -1;
+ }
+ else
+ {
+ sprintf(msg, "ffgsvd: illegal range specified for axis %ld", ii + 1);
+ ffpmsg(msg);
+ return(*status = BAD_PIX_NUM);
+ }
+ }
+
+ str[ii] = blc[ii];
+ stp[ii] = trc[ii];
+ incr[ii] = inc[ii];
+ dsize[ii + 1] = dsize[ii] * naxes[ii];
+ dsize[ii] = dsize[ii] * dir[ii];
+ }
+ dsize[naxis] = dsize[naxis] * dir[naxis];
+
+ if (naxis == 1 && naxes[0] == 1)
+ {
+ /* This is not a vector column, so read all the rows at once */
+ nelem = (rstp - rstr) / rinc + 1;
+ ninc = rinc;
+ rstp = rstr;
+ }
+ else
+ {
+ /* have to read each row individually, in all dimensions */
+ nelem = (stp[0]*dir[0] - str[0]*dir[0]) / inc[0] + 1;
+ ninc = incr[0] * dir[0];
+ }
+
+ for (row = rstr; row <= rstp; row += rinc)
+ {
+ for (i8 = str[8]*dir[8]; i8 <= stp[8]*dir[8]; i8 += incr[8])
+ {
+ for (i7 = str[7]*dir[7]; i7 <= stp[7]*dir[7]; i7 += incr[7])
+ {
+ for (i6 = str[6]*dir[6]; i6 <= stp[6]*dir[6]; i6 += incr[6])
+ {
+ for (i5 = str[5]*dir[5]; i5 <= stp[5]*dir[5]; i5 += incr[5])
+ {
+ for (i4 = str[4]*dir[4]; i4 <= stp[4]*dir[4]; i4 += incr[4])
+ {
+ for (i3 = str[3]*dir[3]; i3 <= stp[3]*dir[3]; i3 += incr[3])
+ {
+ for (i2 = str[2]*dir[2]; i2 <= stp[2]*dir[2]; i2 += incr[2])
+ {
+ for (i1 = str[1]*dir[1]; i1 <= stp[1]*dir[1]; i1 += incr[1])
+ {
+
+ felem=str[0] + (i1 - dir[1]) * dsize[1] + (i2 - dir[2]) * dsize[2] +
+ (i3 - dir[3]) * dsize[3] + (i4 - dir[4]) * dsize[4] +
+ (i5 - dir[5]) * dsize[5] + (i6 - dir[6]) * dsize[6] +
+ (i7 - dir[7]) * dsize[7] + (i8 - dir[8]) * dsize[8];
+
+ if ( ffgcld(fptr, numcol, row, felem, nelem, ninc, nultyp,
+ nulval, &array[i0], &ldummy, &anyf, status) > 0)
+ return(*status);
+
+ if (anyf && anynul)
+ *anynul = TRUE;
+
+ i0 += nelem;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgsfd(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of the column to read (1 = 1st) */
+ int naxis, /* I - number of dimensions in the FITS array */
+ long *naxes, /* I - size of each dimension */
+ long *blc, /* I - 'bottom left corner' of the subsection */
+ long *trc, /* I - 'top right corner' of the subsection */
+ long *inc, /* I - increment to be applied in each dimension */
+ double *array, /* O - array to be filled and returned */
+ char *flagval, /* O - set to 1 if corresponding value is null */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read a subsection of data values from an image or a table column.
+ This routine is set up to handle a maximum of nine dimensions.
+*/
+{
+ long ii,i0, i1,i2,i3,i4,i5,i6,i7,i8,row,rstr,rstp,rinc;
+ long str[9],stp[9],incr[9],dsize[10];
+ long felem, nelem, nultyp, ninc, numcol;
+ int hdutype, anyf;
+ double nulval = 0;
+ char msg[FLEN_ERRMSG];
+ int nullcheck = 2;
+
+ if (naxis < 1 || naxis > 9)
+ {
+ sprintf(msg, "NAXIS = %d in call to ffgsvd is out of range", naxis);
+ ffpmsg(msg);
+ return(*status = BAD_DIMEN);
+ }
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ fits_read_compressed_img(fptr, TDOUBLE, blc, trc, inc,
+ nullcheck, NULL, array, flagval, anynul, status);
+ return(*status);
+ }
+/*
+ if this is a primary array, then the input COLNUM parameter should
+ be interpreted as the row number, and we will alway read the image
+ data from column 2 (any group parameters are in column 1).
+*/
+ if (ffghdt(fptr, &hdutype, status) > 0)
+ return(*status);
+
+ if (hdutype == IMAGE_HDU)
+ {
+ /* this is a primary array, or image extension */
+ if (colnum == 0)
+ {
+ rstr = 1;
+ rstp = 1;
+ }
+ else
+ {
+ rstr = colnum;
+ rstp = colnum;
+ }
+ rinc = 1;
+ numcol = 2;
+ }
+ else
+ {
+ /* this is a table, so the row info is in the (naxis+1) elements */
+ rstr = blc[naxis];
+ rstp = trc[naxis];
+ rinc = inc[naxis];
+ numcol = colnum;
+ }
+
+ nultyp = 2;
+ if (anynul)
+ *anynul = FALSE;
+
+ i0 = 0;
+ for (ii = 0; ii < 9; ii++)
+ {
+ str[ii] = 1;
+ stp[ii] = 1;
+ incr[ii] = 1;
+ dsize[ii] = 1;
+ }
+
+ for (ii = 0; ii < naxis; ii++)
+ {
+ if (trc[ii] < blc[ii])
+ {
+ sprintf(msg, "ffgsvd: illegal range specified for axis %ld", ii + 1);
+ ffpmsg(msg);
+ return(*status = BAD_PIX_NUM);
+ }
+
+ str[ii] = blc[ii];
+ stp[ii] = trc[ii];
+ incr[ii] = inc[ii];
+ dsize[ii + 1] = dsize[ii] * naxes[ii];
+ }
+
+ if (naxis == 1 && naxes[0] == 1)
+ {
+ /* This is not a vector column, so read all the rows at once */
+ nelem = (rstp - rstr) / rinc + 1;
+ ninc = rinc;
+ rstp = rstr;
+ }
+ else
+ {
+ /* have to read each row individually, in all dimensions */
+ nelem = (stp[0] - str[0]) / inc[0] + 1;
+ ninc = incr[0];
+ }
+
+ for (row = rstr; row <= rstp; row += rinc)
+ {
+ for (i8 = str[8]; i8 <= stp[8]; i8 += incr[8])
+ {
+ for (i7 = str[7]; i7 <= stp[7]; i7 += incr[7])
+ {
+ for (i6 = str[6]; i6 <= stp[6]; i6 += incr[6])
+ {
+ for (i5 = str[5]; i5 <= stp[5]; i5 += incr[5])
+ {
+ for (i4 = str[4]; i4 <= stp[4]; i4 += incr[4])
+ {
+ for (i3 = str[3]; i3 <= stp[3]; i3 += incr[3])
+ {
+ for (i2 = str[2]; i2 <= stp[2]; i2 += incr[2])
+ {
+ for (i1 = str[1]; i1 <= stp[1]; i1 += incr[1])
+ {
+ felem=str[0] + (i1 - 1) * dsize[1] + (i2 - 1) * dsize[2] +
+ (i3 - 1) * dsize[3] + (i4 - 1) * dsize[4] +
+ (i5 - 1) * dsize[5] + (i6 - 1) * dsize[6] +
+ (i7 - 1) * dsize[7] + (i8 - 1) * dsize[8];
+
+ if ( ffgcld(fptr, numcol, row, felem, nelem, ninc, nultyp,
+ nulval, &array[i0], &flagval[i0], &anyf, status) > 0)
+ return(*status);
+
+ if (anyf && anynul)
+ *anynul = TRUE;
+
+ i0 += nelem;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffggpd( fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to read (1 = 1st group) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ double *array, /* O - array of values that are returned */
+ int *status) /* IO - error status */
+/*
+ Read an array of group parameters from the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being read).
+*/
+{
+ long row;
+ int idummy;
+ char cdummy;
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ row=maxvalue(1,group);
+
+ ffgcld(fptr, 1, row, firstelem, nelem, 1, 1, 0.,
+ array, &cdummy, &idummy, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgcvd(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to read (1 = 1st col) */
+ long firstrow, /* I - first row to read (1 = 1st row) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ double nulval, /* I - value for null pixels */
+ double *array, /* O - array of values that are read */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from a column in the current FITS HDU. Automatic
+ datatype conversion will be performed if the datatype of the column does not
+ match the datatype of the array parameter. The output values will be scaled
+ by the FITS TSCALn and TZEROn values if these values have been defined.
+ Any undefined pixels will be set equal to the value of 'nulval' unless
+ nulval = 0 in which case no checks for undefined pixels will be made.
+*/
+{
+ char cdummy;
+
+ ffgcld(fptr, colnum, firstrow, firstelem, nelem, 1, 1, nulval,
+ array, &cdummy, anynul, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgcvm(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to read (1 = 1st col) */
+ long firstrow, /* I - first row to read (1 = 1st row) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ double nulval, /* I - value for null pixels */
+ double *array, /* O - array of values that are read */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from a column in the current FITS HDU. Automatic
+ datatype conversion will be performed if the datatype of the column does not
+ match the datatype of the array parameter. The output values will be scaled
+ by the FITS TSCALn and TZEROn values if these values have been defined.
+ Any undefined pixels will be set equal to the value of 'nulval' unless
+ nulval = 0 in which case no checks for undefined pixels will be made.
+
+ TSCAL and ZERO should not be used with complex values.
+*/
+{
+ char cdummy;
+
+ /* a complex double value is interpreted as a pair of double values, */
+ /* thus need to multiply the first element and number of elements by 2 */
+
+ ffgcld(fptr, colnum, firstrow, (firstelem - 1) * 2 + 1, nelem * 2,
+ 1, 1, nulval, array, &cdummy, anynul, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgcfd(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to read (1 = 1st col) */
+ long firstrow, /* I - first row to read (1 = 1st row) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ double *array, /* O - array of values that are read */
+ char *nularray, /* O - array of flags: 1 if null pixel; else 0 */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from a column in the current FITS HDU. Automatic
+ datatype conversion will be performed if the datatype of the column does not
+ match the datatype of the array parameter. The output values will be scaled
+ by the FITS TSCALn and TZEROn values if these values have been defined.
+ Nularray will be set = 1 if the corresponding array pixel is undefined,
+ otherwise nularray will = 0.
+*/
+{
+ double dummy = 0;
+
+ ffgcld(fptr, colnum, firstrow, firstelem, nelem, 1, 2, dummy,
+ array, nularray, anynul, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgcfm(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to read (1 = 1st col) */
+ long firstrow, /* I - first row to read (1 = 1st row) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ double *array, /* O - array of values that are read */
+ char *nularray, /* O - array of flags: 1 if null pixel; else 0 */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from a column in the current FITS HDU. Automatic
+ datatype conversion will be performed if the datatype of the column does not
+ match the datatype of the array parameter. The output values will be scaled
+ by the FITS TSCALn and TZEROn values if these values have been defined.
+ Nularray will be set = 1 if the corresponding array pixel is undefined,
+ otherwise nularray will = 0.
+
+ TSCAL and ZERO should not be used with complex values.
+*/
+{
+ long ii, jj;
+ float dummy = 0;
+ char *carray;
+
+ /* a complex double value is interpreted as a pair of double values, */
+ /* thus need to multiply the first element and number of elements by 2 */
+
+ /* allocate temporary array */
+ carray = (char *) calloc(nelem * 2, 1);
+
+ ffgcld(fptr, colnum, firstrow, (firstelem - 1) * 2 + 1, nelem * 2,
+ 1, 2, dummy, array, carray, anynul, status);
+
+ for (ii = 0, jj = 0; jj < nelem; ii += 2, jj++)
+ {
+ if (carray[ii] || carray[ii + 1])
+ nularray[jj] = 1;
+ else
+ nularray[jj] = 0;
+ }
+
+ free(carray);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgcld( fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to read (1 = 1st col) */
+ long firstrow, /* I - first row to read (1 = 1st row) */
+ OFF_T firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ long elemincre, /* I - pixel increment; e.g., 2 = every other */
+ int nultyp, /* I - null value handling code: */
+ /* 1: set undefined pixels = nulval */
+ /* 2: set nularray=1 for undefined pixels */
+ double nulval, /* I - value for null pixels if nultyp = 1 */
+ double *array, /* O - array of values that are read */
+ char *nularray, /* O - array of flags = 1 if nultyp = 2 */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from a column in the current FITS HDU.
+ The column number may refer to a real column in an ASCII or binary table,
+ or it may refer be a virtual column in a 1 or more grouped FITS primary
+ array or image extension. FITSIO treats a primary array as a binary table
+ with 2 vector columns: the first column contains the group parameters (often
+ with length = 0) and the second column contains the array of image pixels.
+ Each row of the table represents a group in the case of multigroup FITS
+ images.
+
+ The output array of values will be converted from the datatype of the column
+ and will be scaled by the FITS TSCALn and TZEROn values if necessary.
+*/
+{
+ double scale, zero, power = 1;
+ int tcode, maxelem, hdutype, xcode, decimals;
+ long twidth, incre, rownum, remain, next, ntodo;
+ long ii, rowincre, tnull, xwidth;
+ int convert, nulcheck, readcheck = 0;
+ OFF_T repeat, startpos, elemnum, readptr, rowlen;
+ char tform[20];
+ char message[81];
+ char snull[20]; /* the FITS null value if reading from ASCII table */
+
+ double cbuff[DBUFFSIZE / sizeof(double)]; /* align cbuff on word boundary */
+ void *buffer;
+
+ if (*status > 0 || nelem == 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ buffer = cbuff;
+
+ if (anynul)
+ *anynul = 0;
+
+ if (nultyp == 2)
+ memset(nularray, 0, nelem); /* initialize nullarray */
+
+ /*---------------------------------------------------*/
+ /* Check input and get parameters about the column: */
+ /*---------------------------------------------------*/
+ if (elemincre < 0)
+ readcheck = -1; /* don't do range checking in this case */
+
+ if ( ffgcpr( fptr, colnum, firstrow, firstelem, nelem, readcheck, &scale, &zero,
+ tform, &twidth, &tcode, &maxelem, &startpos, &elemnum, &incre,
+ &repeat, &rowlen, &hdutype, &tnull, snull, status) > 0 )
+ return(*status);
+
+ incre *= elemincre; /* multiply incre to just get every nth pixel */
+
+ if (tcode == TSTRING) /* setup for ASCII tables */
+ {
+ /* get the number of implied decimal places if no explicit decmal point */
+ ffasfm(tform, &xcode, &xwidth, &decimals, status);
+ for(ii = 0; ii < decimals; ii++)
+ power *= 10.;
+ }
+
+ /*------------------------------------------------------------------*/
+ /* Decide whether to check for null values in the input FITS file: */
+ /*------------------------------------------------------------------*/
+ nulcheck = nultyp; /* by default check for null values in the FITS file */
+
+ if (nultyp == 1 && nulval == 0)
+ nulcheck = 0; /* calling routine does not want to check for nulls */
+
+ else if (tcode%10 == 1 && /* if reading an integer column, and */
+ tnull == NULL_UNDEFINED) /* if a null value is not defined, */
+ nulcheck = 0; /* then do not check for null values. */
+
+ else if (tcode == TSHORT && (tnull > SHRT_MAX || tnull < SHRT_MIN) )
+ nulcheck = 0; /* Impossible null value */
+
+ else if (tcode == TBYTE && (tnull > 255 || tnull < 0) )
+ nulcheck = 0; /* Impossible null value */
+
+ else if (tcode == TSTRING && snull[0] == ASCII_NULL_UNDEFINED)
+ nulcheck = 0;
+
+ /*----------------------------------------------------------------------*/
+ /* If FITS column and output data array have same datatype, then we do */
+ /* not need to use a temporary buffer to store intermediate datatype. */
+ /*----------------------------------------------------------------------*/
+ convert = 1;
+ if (tcode == TDOUBLE) /* Special Case: */
+ { /* no type convertion required, so read */
+ maxelem = nelem; /* data directly into output buffer. */
+
+ if (nulcheck == 0 && scale == 1. && zero == 0.)
+ convert = 0; /* no need to scale data or find nulls */
+ }
+
+ /*---------------------------------------------------------------------*/
+ /* Now read the pixels from the FITS column. If the column does not */
+ /* have the same datatype as the output array, then we have to read */
+ /* the raw values into a temporary buffer (of limited size). In */
+ /* the case of a vector colum read only 1 vector of values at a time */
+ /* then skip to the next row if more values need to be read. */
+ /* After reading the raw values, then call the fffXXYY routine to (1) */
+ /* test for undefined values, (2) convert the datatype if necessary, */
+ /* and (3) scale the values by the FITS TSCALn and TZEROn linear */
+ /* scaling parameters. */
+ /*---------------------------------------------------------------------*/
+ remain = nelem; /* remaining number of values to read */
+ next = 0; /* next element in array to be read */
+ rownum = 0; /* row number, relative to firstrow */
+
+ while (remain)
+ {
+ /* limit the number of pixels to read at one time to the number that
+ will fit in the buffer or to the number of pixels that remain in
+ the current vector, which ever is smaller.
+ */
+ ntodo = minvalue(remain, maxelem);
+ if (elemincre >= 0)
+ {
+ ntodo = minvalue(ntodo, ((repeat - elemnum - 1)/elemincre +1));
+ }
+ else
+ {
+ ntodo = minvalue(ntodo, (elemnum/(-elemincre) +1));
+ }
+
+ readptr = startpos + ((OFF_T)rownum * rowlen) + (elemnum * (incre / elemincre));
+
+ switch (tcode)
+ {
+ case (TDOUBLE):
+ ffgr8b(fptr, readptr, ntodo, incre, &array[next], status);
+ if (convert)
+ fffr8r8(&array[next], ntodo, scale, zero, nulcheck,
+ nulval, &nularray[next], anynul,
+ &array[next], status);
+ break;
+ case (TBYTE):
+ ffgi1b(fptr, readptr, ntodo, incre, (unsigned char *) buffer,
+ status);
+ fffi1r8((unsigned char *) buffer, ntodo, scale, zero, nulcheck,
+ (unsigned char) tnull, nulval, &nularray[next], anynul,
+ &array[next], status);
+ break;
+ case (TSHORT):
+ ffgi2b(fptr, readptr, ntodo, incre, (short *) buffer, status);
+ fffi2r8((short *) buffer, ntodo, scale, zero, nulcheck,
+ (short) tnull, nulval, &nularray[next], anynul,
+ &array[next], status);
+ break;
+ case (TLONG):
+ ffgi4b(fptr, readptr, ntodo, incre, (INT32BIT *) buffer,
+ status);
+ fffi4r8((INT32BIT *) buffer, ntodo, scale, zero, nulcheck,
+ (INT32BIT) tnull, nulval, &nularray[next], anynul,
+ &array[next], status);
+ break;
+ case (TLONGLONG):
+ ffgi8b(fptr, readptr, ntodo, incre, (long *) buffer, status);
+ fffi8r8( (LONGLONG *) buffer, ntodo, scale, zero,
+ nulcheck, (long) tnull, nulval, &nularray[next],
+ anynul, &array[next], status);
+ break;
+ case (TFLOAT):
+ ffgr4b(fptr, readptr, ntodo, incre, (float *) buffer, status);
+ fffr4r8((float *) buffer, ntodo, scale, zero, nulcheck,
+ nulval, &nularray[next], anynul,
+ &array[next], status);
+ break;
+ case (TSTRING):
+ ffmbyt(fptr, readptr, REPORT_EOF, status);
+
+ if (incre == twidth) /* contiguous bytes */
+ ffgbyt(fptr, ntodo * twidth, buffer, status);
+ else
+ ffgbytoff(fptr, twidth, ntodo, incre - twidth, buffer,
+ status);
+
+ fffstrr8((char *) buffer, ntodo, scale, zero, twidth, power,
+ nulcheck, snull, nulval, &nularray[next], anynul,
+ &array[next], status);
+ break;
+
+
+ default: /* error trap for invalid column format */
+ sprintf(message,
+ "Cannot read numbers from column %d which has format %s",
+ colnum, tform);
+ ffpmsg(message);
+ if (hdutype == ASCII_TBL)
+ return(*status = BAD_ATABLE_FORMAT);
+ else
+ return(*status = BAD_BTABLE_FORMAT);
+
+ } /* End of switch block */
+
+ /*-------------------------*/
+ /* Check for fatal error */
+ /*-------------------------*/
+ if (*status > 0) /* test for error during previous read operation */
+ {
+ if (hdutype > 0)
+ sprintf(message,
+ "Error reading elements %ld thru %ld from column %d (ffgcld).",
+ next+1, next+ntodo, colnum);
+ else
+ sprintf(message,
+ "Error reading elements %ld thru %ld from image (ffgcld).",
+ next+1, next+ntodo);
+
+ ffpmsg(message);
+ return(*status);
+ }
+
+ /*--------------------------------------------*/
+ /* increment the counters for the next loop */
+ /*--------------------------------------------*/
+ remain -= ntodo;
+ if (remain)
+ {
+ next += ntodo;
+ elemnum = elemnum + (ntodo * elemincre);
+
+ if (elemnum >= repeat) /* completed a row; start on later row */
+ {
+ rowincre = elemnum / repeat;
+ rownum += rowincre;
+ elemnum = elemnum - (rowincre * repeat);
+ }
+ else if (elemnum < 0) /* completed a row; start on a previous row */
+ {
+ rowincre = (-elemnum - 1) / repeat + 1;
+ rownum -= rowincre;
+ elemnum = (rowincre * repeat) + elemnum;
+ }
+ }
+ } /* End of main while Loop */
+
+
+ /*--------------------------------*/
+ /* check for numerical overflow */
+ /*--------------------------------*/
+ if (*status == OVERFLOW_ERR)
+ {
+ ffpmsg(
+ "Numerical overflow during type conversion while reading FITS data.");
+ *status = NUM_OVERFLOW;
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffi1r8(unsigned char *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ unsigned char tnull, /* I - value of FITS TNULLn keyword if any */
+ double nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ double *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to tnull. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ long ii;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = (double) input[ii]; /* copy input to output */
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ output[ii] = input[ii] * scale + zero;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ output[ii] = (double) input[ii];
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ output[ii] = input[ii] * scale + zero;
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffi2r8(short *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ short tnull, /* I - value of FITS TNULLn keyword if any */
+ double nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ double *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to tnull. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ long ii;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = (double) input[ii]; /* copy input to output */
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ output[ii] = input[ii] * scale + zero;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ output[ii] = (double) input[ii];
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ output[ii] = input[ii] * scale + zero;
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffi4r8(INT32BIT *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ INT32BIT tnull, /* I - value of FITS TNULLn keyword if any */
+ double nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ double *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to tnull. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ long ii;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = (double) input[ii]; /* copy input to output */
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ output[ii] = input[ii] * scale + zero;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ output[ii] = (double) input[ii];
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ output[ii] = input[ii] * scale + zero;
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffi8r8(LONGLONG *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ long tnull, /* I - value of FITS TNULLn keyword if any */
+ double nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ double *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to tnull. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+#if (LONGSIZE == 32) && (! defined HAVE_LONGLONG)
+
+ /* This block of code is only used in cases where there is */
+ /* no native 8-byte integer support. We have to interpret */
+ /* the corresponding pair of 4-byte integers which are */
+ /* are equivalent to the 8-byte integer. */
+
+ unsigned long *uinput;
+ long ii,jj, kk;
+ double dvalue;
+
+ uinput = (unsigned long *) input;
+
+#if BYTESWAPPED /* jj points to the most significant part of the 8-byte int */
+ jj = 1;
+ kk = 0;
+#else
+ jj = 0;
+ kk = 1;
+#endif
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++, jj += 2, kk += 2)
+ {
+ if (uinput[jj] & 0x80000000) /* negative number */
+ output[ii] = (uinput[jj] ^ 0xffffffff) * -4294967296. -
+ (uinput[kk] ^ 0xffffffff) - 1.;
+ else /* positive number */
+ output[ii] = (double) uinput[jj] * 4294967296. + uinput[kk];
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++, jj += 2, kk += 2)
+ {
+ if (uinput[jj] & 0x80000000) /* negative number */
+ output[ii] = ((uinput[jj] ^ 0xffffffff) * -4294967296. -
+ (uinput[kk] ^ 0xffffffff) - 1.) * scale + zero;
+ else /* positive number */
+ output[ii] = (uinput[jj] * 4294967296. + uinput[kk])
+ * scale + zero;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++, jj += 2, kk += 2)
+ {
+ if (uinput[jj] & 0x80000000) /* negative number */
+ dvalue = (uinput[jj] ^ 0xffffffff) * -4294967296. -
+ (uinput[kk] ^ 0xffffffff) - 1.;
+ else /* positive number */
+ dvalue = uinput[jj] * 4294967296. + uinput[kk];
+
+ if (dvalue == (double) tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ output[ii] = dvalue;
+ }
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++, jj += 2, kk += 2)
+ {
+ if (uinput[jj] & 0x80000000) /* negative number */
+ dvalue = (uinput[jj] ^ 0xffffffff) * -4294967296. -
+ (uinput[kk] ^ 0xffffffff) - 1.;
+ else /* positive number */
+ dvalue = uinput[jj] * 4294967296. + uinput[kk];
+
+ if (dvalue == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ output[ii] = dvalue * scale + zero;
+ }
+ }
+ }
+ }
+
+#else
+
+ /* this block works on machines which support an 8-byte integer type */
+
+ long ii;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = (double) input[ii]; /* copy input to output */
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ output[ii] = input[ii] * scale + zero;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ output[ii] = (double) input[ii];
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ output[ii] = input[ii] * scale + zero;
+ }
+ }
+ }
+ }
+
+#endif
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffr4r8(float *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ double nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ double *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to NaN. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ long ii;
+ short *sptr, iret;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = (double) input[ii]; /* copy input to output */
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ output[ii] = input[ii] * scale + zero;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ sptr = (short *) input;
+
+#if BYTESWAPPED && MACHINE != VAXVMS && MACHINE != ALPHAVMS
+ sptr++; /* point to MSBs */
+#endif
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++, sptr += 2)
+ {
+ if (0 != (iret = fnan(*sptr) ) ) /* test for NaN or underflow */
+ {
+ if (iret == 1) /* is it a NaN? */
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else /* it's an underflow */
+ output[ii] = 0;
+ }
+ else
+ output[ii] = (double) input[ii];
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++, sptr += 2)
+ {
+ if (0 != (iret = fnan(*sptr) ) ) /* test for NaN or underflow */
+ {
+ if (iret == 1) /* is it a NaN? */
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else /* it's an underflow */
+ output[ii] = zero;
+ }
+ else
+ output[ii] = input[ii] * scale + zero;
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffr8r8(double *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ double nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ double *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to NaN. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ long ii;
+ short *sptr, iret;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ memcpy(output, input, ntodo * sizeof(double) );
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ output[ii] = input[ii] * scale + zero;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ sptr = (short *) input;
+
+#if BYTESWAPPED && MACHINE != VAXVMS && MACHINE != ALPHAVMS
+ sptr += 3; /* point to MSBs */
+#endif
+
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++, sptr += 4)
+ {
+ if (0 != (iret = dnan(*sptr)) ) /* test for NaN or underflow */
+ {
+ if (iret == 1) /* is it a NaN? */
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ {
+ nullarray[ii] = 1;
+ /* explicitly set value in case output contains a NaN */
+ output[ii] = DOUBLENULLVALUE;
+ }
+ }
+ else /* it's an underflow */
+ output[ii] = 0;
+ }
+ else
+ output[ii] = input[ii];
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++, sptr += 4)
+ {
+ if (0 != (iret = dnan(*sptr)) ) /* test for NaN or underflow */
+ {
+ if (iret == 1) /* is it a NaN? */
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ {
+ nullarray[ii] = 1;
+ /* explicitly set value in case output contains a NaN */
+ output[ii] = DOUBLENULLVALUE;
+ }
+ }
+ else /* it's an underflow */
+ output[ii] = zero;
+ }
+ else
+ output[ii] = input[ii] * scale + zero;
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffstrr8(char *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ long twidth, /* I - width of each substring of chars */
+ double implipower, /* I - power of 10 of implied decimal */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ char *snull, /* I - value of FITS null string, if any */
+ double nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ double *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file. Check
+ for null values and do scaling if required. The nullcheck code value
+ determines how any null values in the input array are treated. A null
+ value is an input pixel that is equal to snull. If nullcheck= 0, then
+ no special checking for nulls is performed. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ int nullen;
+ long ii;
+ double dvalue;
+ char *cstring, message[81];
+ char *cptr, *tpos;
+ char tempstore, chrzero = '0';
+ double val, power;
+ int exponent, sign, esign, decpt;
+
+ nullen = strlen(snull);
+ cptr = input; /* pointer to start of input string */
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ cstring = cptr;
+ /* temporarily insert a null terminator at end of the string */
+ tpos = cptr + twidth;
+ tempstore = *tpos;
+ *tpos = 0;
+
+ /* check if null value is defined, and if the */
+ /* column string is identical to the null string */
+ if (snull[0] != ASCII_NULL_UNDEFINED &&
+ !strncmp(snull, cptr, nullen) )
+ {
+ if (nullcheck)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ cptr += twidth;
+ }
+ else
+ {
+ /* value is not the null value, so decode it */
+ /* remove any embedded blank characters from the string */
+
+ decpt = 0;
+ sign = 1;
+ val = 0.;
+ power = 1.;
+ exponent = 0;
+ esign = 1;
+
+ while (*cptr == ' ') /* skip leading blanks */
+ cptr++;
+
+ if (*cptr == '-' || *cptr == '+') /* check for leading sign */
+ {
+ if (*cptr == '-')
+ sign = -1;
+
+ cptr++;
+
+ while (*cptr == ' ') /* skip blanks between sign and value */
+ cptr++;
+ }
+
+ while (*cptr >= '0' && *cptr <= '9')
+ {
+ val = val * 10. + *cptr - chrzero; /* accumulate the value */
+ cptr++;
+
+ while (*cptr == ' ') /* skip embedded blanks in the value */
+ cptr++;
+ }
+
+ if (*cptr == '.') /* check for decimal point */
+ {
+ decpt = 1; /* set flag to show there was a decimal point */
+ cptr++;
+ while (*cptr == ' ') /* skip any blanks */
+ cptr++;
+
+ while (*cptr >= '0' && *cptr <= '9')
+ {
+ val = val * 10. + *cptr - chrzero; /* accumulate the value */
+ power = power * 10.;
+ cptr++;
+
+ while (*cptr == ' ') /* skip embedded blanks in the value */
+ cptr++;
+ }
+ }
+
+ if (*cptr == 'E' || *cptr == 'D') /* check for exponent */
+ {
+ cptr++;
+ while (*cptr == ' ') /* skip blanks */
+ cptr++;
+
+ if (*cptr == '-' || *cptr == '+') /* check for exponent sign */
+ {
+ if (*cptr == '-')
+ esign = -1;
+
+ cptr++;
+
+ while (*cptr == ' ') /* skip blanks between sign and exp */
+ cptr++;
+ }
+
+ while (*cptr >= '0' && *cptr <= '9')
+ {
+ exponent = exponent * 10 + *cptr - chrzero; /* accumulate exp */
+ cptr++;
+
+ while (*cptr == ' ') /* skip embedded blanks */
+ cptr++;
+ }
+ }
+
+ if (*cptr != 0) /* should end up at the null terminator */
+ {
+ sprintf(message, "Cannot read number from ASCII table");
+ ffpmsg(message);
+ sprintf(message, "Column field = %s.", cstring);
+ ffpmsg(message);
+ /* restore the char that was overwritten by the null */
+ *tpos = tempstore;
+ return(*status = BAD_C2D);
+ }
+
+ if (!decpt) /* if no explicit decimal, use implied */
+ power = implipower;
+
+ dvalue = (sign * val / power) * pow(10., (double) (esign * exponent));
+
+ output[ii] = (dvalue * scale + zero); /* apply the scaling */
+ }
+ /* restore the char that was overwritten by the null */
+ *tpos = tempstore;
+ }
+ return(*status);
+}
diff --git a/pkg/tbtables/cfitsio/getcole.c b/pkg/tbtables/cfitsio/getcole.c
new file mode 100644
index 00000000..1e6d40d0
--- /dev/null
+++ b/pkg/tbtables/cfitsio/getcole.c
@@ -0,0 +1,1775 @@
+/* This file, getcole.c, contains routines that read data elements from */
+/* a FITS image or table, with float datatype */
+
+/* The FITSIO software was written by William Pence at the High Energy */
+/* Astrophysic Science Archive Research Center (HEASARC) at the NASA */
+/* Goddard Space Flight Center. */
+
+#include <math.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include "fitsio2.h"
+
+/*--------------------------------------------------------------------------*/
+int ffgpve( fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to read (1 = 1st group) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ float nulval, /* I - value for undefined pixels */
+ float *array, /* O - array of values that are returned */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being read).
+ Undefined elements will be set equal to NULVAL, unless NULVAL=0
+ in which case no checking for undefined values will be performed.
+ ANYNUL is returned with a value of .true. if any pixels are undefined.
+*/
+{
+ long row;
+ char cdummy;
+ int nullcheck = 1;
+ float nullvalue;
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+ nullvalue = nulval; /* set local variable */
+
+ fits_read_compressed_pixels(fptr, TFLOAT, firstelem, nelem,
+ nullcheck, &nullvalue, array, NULL, anynul, status);
+ return(*status);
+ }
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ row=maxvalue(1,group);
+
+ ffgcle(fptr, 2, row, firstelem, nelem, 1, 1, nulval,
+ array, &cdummy, anynul, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgpfe( fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to read (1 = 1st group) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ float *array, /* O - array of values that are returned */
+ char *nularray, /* O - array of null pixel flags */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being read).
+ Any undefined pixels in the returned array will be set = 0 and the
+ corresponding nularray value will be set = 1.
+ ANYNUL is returned with a value of .true. if any pixels are undefined.
+*/
+{
+ long row;
+ int nullcheck = 2;
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ fits_read_compressed_pixels(fptr, TFLOAT, firstelem, nelem,
+ nullcheck, NULL, array, nularray, anynul, status);
+ return(*status);
+ }
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ row=maxvalue(1,group);
+
+ ffgcle(fptr, 2, row, firstelem, nelem, 1, 2, 0.F,
+ array, nularray, anynul, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffg2de(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to read (1 = 1st group) */
+ float nulval, /* set undefined pixels equal to this */
+ long ncols, /* I - number of pixels in each row of array */
+ long naxis1, /* I - FITS image NAXIS1 value */
+ long naxis2, /* I - FITS image NAXIS2 value */
+ float *array, /* O - array to be filled and returned */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an entire 2-D array of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of the
+ FITS array is not the same as the array being read). Any null
+ values in the array will be set equal to the value of nulval, unless
+ nulval = 0 in which case no null checking will be performed.
+*/
+{
+ /* call the 3D reading routine, with the 3rd dimension = 1 */
+
+ ffg3de(fptr, group, nulval, ncols, naxis2, naxis1, naxis2, 1, array,
+ anynul, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffg3de(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to read (1 = 1st group) */
+ float nulval, /* set undefined pixels equal to this */
+ long ncols, /* I - number of pixels in each row of array */
+ long nrows, /* I - number of rows in each plane of array */
+ long naxis1, /* I - FITS image NAXIS1 value */
+ long naxis2, /* I - FITS image NAXIS2 value */
+ long naxis3, /* I - FITS image NAXIS3 value */
+ float *array, /* O - array to be filled and returned */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an entire 3-D array of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of the
+ FITS array is not the same as the array being read). Any null
+ values in the array will be set equal to the value of nulval, unless
+ nulval = 0 in which case no null checking will be performed.
+*/
+{
+ long tablerow, nfits, narray, ii, jj;
+ char cdummy;
+ int nullcheck = 1;
+ long inc[] = {1,1,1};
+ long fpixel[] = {1,1,1};
+ long lpixel[3];
+ float nullvalue;
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ lpixel[0] = ncols;
+ lpixel[1] = nrows;
+ lpixel[2] = naxis3;
+ nullvalue = nulval; /* set local variable */
+
+ fits_read_compressed_img(fptr, TFLOAT, fpixel, lpixel, inc,
+ nullcheck, &nullvalue, array, NULL, anynul, status);
+ return(*status);
+ }
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+ tablerow=maxvalue(1,group);
+
+ if (ncols == naxis1 && nrows == naxis2) /* arrays have same size? */
+ {
+ /* all the image pixels are contiguous, so read all at once */
+ ffgcle(fptr, 2, tablerow, 1, naxis1 * naxis2 * naxis3, 1, 1, nulval,
+ array, &cdummy, anynul, status);
+ return(*status);
+ }
+
+ if (ncols < naxis1 || nrows < naxis2)
+ return(*status = BAD_DIMEN);
+
+ nfits = 1; /* next pixel in FITS image to read */
+ narray = 0; /* next pixel in output array to be filled */
+
+ /* loop over naxis3 planes in the data cube */
+ for (jj = 0; jj < naxis3; jj++)
+ {
+ /* loop over the naxis2 rows in the FITS image, */
+ /* reading naxis1 pixels to each row */
+
+ for (ii = 0; ii < naxis2; ii++)
+ {
+ if (ffgcle(fptr, 2, tablerow, nfits, naxis1, 1, 1, nulval,
+ &array[narray], &cdummy, anynul, status) > 0)
+ return(*status);
+
+ nfits += naxis1;
+ narray += ncols;
+ }
+ narray += (nrows - naxis2) * ncols;
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgsve(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of the column to read (1 = 1st) */
+ int naxis, /* I - number of dimensions in the FITS array */
+ long *naxes, /* I - size of each dimension */
+ long *blc, /* I - 'bottom left corner' of the subsection */
+ long *trc, /* I - 'top right corner' of the subsection */
+ long *inc, /* I - increment to be applied in each dimension */
+ float nulval, /* I - value to set undefined pixels */
+ float *array, /* O - array to be filled and returned */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read a subsection of data values from an image or a table column.
+ This routine is set up to handle a maximum of nine dimensions.
+*/
+{
+ long ii,i0, i1,i2,i3,i4,i5,i6,i7,i8,row,rstr,rstp,rinc;
+ long str[9],stp[9],incr[9],dir[9];
+ long nelem, nultyp, ninc, numcol;
+ OFF_T felem, dsize[10];
+ int hdutype, anyf;
+ char ldummy, msg[FLEN_ERRMSG];
+ int nullcheck = 1;
+ float nullvalue;
+
+ if (naxis < 1 || naxis > 9)
+ {
+ sprintf(msg, "NAXIS = %d in call to ffgsve is out of range", naxis);
+ ffpmsg(msg);
+ return(*status = BAD_DIMEN);
+ }
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ nullvalue = nulval; /* set local variable */
+
+ fits_read_compressed_img(fptr, TFLOAT, blc, trc, inc,
+ nullcheck, &nullvalue, array, NULL, anynul, status);
+ return(*status);
+ }
+
+/*
+ if this is a primary array, then the input COLNUM parameter should
+ be interpreted as the row number, and we will alway read the image
+ data from column 2 (any group parameters are in column 1).
+*/
+ if (ffghdt(fptr, &hdutype, status) > 0)
+ return(*status);
+
+ if (hdutype == IMAGE_HDU)
+ {
+ /* this is a primary array, or image extension */
+ if (colnum == 0)
+ {
+ rstr = 1;
+ rstp = 1;
+ }
+ else
+ {
+ rstr = colnum;
+ rstp = colnum;
+ }
+ rinc = 1;
+ numcol = 2;
+ }
+ else
+ {
+ /* this is a table, so the row info is in the (naxis+1) elements */
+ rstr = blc[naxis];
+ rstp = trc[naxis];
+ rinc = inc[naxis];
+ numcol = colnum;
+ }
+
+ nultyp = 1;
+ if (anynul)
+ *anynul = FALSE;
+
+ i0 = 0;
+ for (ii = 0; ii < 9; ii++)
+ {
+ str[ii] = 1;
+ stp[ii] = 1;
+ incr[ii] = 1;
+ dsize[ii] = 1;
+ dir[ii] = 1;
+ }
+
+ for (ii = 0; ii < naxis; ii++)
+ {
+ if (trc[ii] < blc[ii])
+ {
+ if (hdutype == IMAGE_HDU)
+ {
+ dir[ii] = -1;
+ }
+ else
+ {
+ sprintf(msg, "ffgsve: illegal range specified for axis %ld", ii + 1);
+ ffpmsg(msg);
+ return(*status = BAD_PIX_NUM);
+ }
+ }
+
+ str[ii] = blc[ii];
+ stp[ii] = trc[ii];
+ incr[ii] = inc[ii];
+ dsize[ii + 1] = dsize[ii] * naxes[ii];
+ dsize[ii] = dsize[ii] * dir[ii];
+ }
+ dsize[naxis] = dsize[naxis] * dir[naxis];
+
+ if (naxis == 1 && naxes[0] == 1)
+ {
+ /* This is not a vector column, so read all the rows at once */
+ nelem = (rstp - rstr) / rinc + 1;
+ ninc = rinc;
+ rstp = rstr;
+ }
+ else
+ {
+ /* have to read each row individually, in all dimensions */
+ nelem = (stp[0]*dir[0] - str[0]*dir[0]) / inc[0] + 1;
+ ninc = incr[0] * dir[0];
+ }
+
+ for (row = rstr; row <= rstp; row += rinc)
+ {
+ for (i8 = str[8]*dir[8]; i8 <= stp[8]*dir[8]; i8 += incr[8])
+ {
+ for (i7 = str[7]*dir[7]; i7 <= stp[7]*dir[7]; i7 += incr[7])
+ {
+ for (i6 = str[6]*dir[6]; i6 <= stp[6]*dir[6]; i6 += incr[6])
+ {
+ for (i5 = str[5]*dir[5]; i5 <= stp[5]*dir[5]; i5 += incr[5])
+ {
+ for (i4 = str[4]*dir[4]; i4 <= stp[4]*dir[4]; i4 += incr[4])
+ {
+ for (i3 = str[3]*dir[3]; i3 <= stp[3]*dir[3]; i3 += incr[3])
+ {
+ for (i2 = str[2]*dir[2]; i2 <= stp[2]*dir[2]; i2 += incr[2])
+ {
+ for (i1 = str[1]*dir[1]; i1 <= stp[1]*dir[1]; i1 += incr[1])
+ {
+
+ felem=str[0] + (i1 - dir[1]) * dsize[1] + (i2 - dir[2]) * dsize[2] +
+ (i3 - dir[3]) * dsize[3] + (i4 - dir[4]) * dsize[4] +
+ (i5 - dir[5]) * dsize[5] + (i6 - dir[6]) * dsize[6] +
+ (i7 - dir[7]) * dsize[7] + (i8 - dir[8]) * dsize[8];
+
+ if ( ffgcle(fptr, numcol, row, felem, nelem, ninc, nultyp,
+ nulval, &array[i0], &ldummy, &anyf, status) > 0)
+ return(*status);
+
+ if (anyf && anynul)
+ *anynul = TRUE;
+
+ i0 += nelem;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgsfe(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of the column to read (1 = 1st) */
+ int naxis, /* I - number of dimensions in the FITS array */
+ long *naxes, /* I - size of each dimension */
+ long *blc, /* I - 'bottom left corner' of the subsection */
+ long *trc, /* I - 'top right corner' of the subsection */
+ long *inc, /* I - increment to be applied in each dimension */
+ float *array, /* O - array to be filled and returned */
+ char *flagval, /* O - set to 1 if corresponding value is null */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read a subsection of data values from an image or a table column.
+ This routine is set up to handle a maximum of nine dimensions.
+*/
+{
+ long ii,i0, i1,i2,i3,i4,i5,i6,i7,i8,row,rstr,rstp,rinc;
+ long str[9],stp[9],incr[9],dsize[10];
+ long felem, nelem, nultyp, ninc, numcol;
+ int hdutype, anyf;
+ float nulval = 0;
+ char msg[FLEN_ERRMSG];
+ int nullcheck = 2;
+
+ if (naxis < 1 || naxis > 9)
+ {
+ sprintf(msg, "NAXIS = %d in call to ffgsve is out of range", naxis);
+ ffpmsg(msg);
+ return(*status = BAD_DIMEN);
+ }
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ fits_read_compressed_img(fptr, TFLOAT, blc, trc, inc,
+ nullcheck, NULL, array, flagval, anynul, status);
+ return(*status);
+ }
+
+/*
+ if this is a primary array, then the input COLNUM parameter should
+ be interpreted as the row number, and we will alway read the image
+ data from column 2 (any group parameters are in column 1).
+*/
+ if (ffghdt(fptr, &hdutype, status) > 0)
+ return(*status);
+
+ if (hdutype == IMAGE_HDU)
+ {
+ /* this is a primary array, or image extension */
+ if (colnum == 0)
+ {
+ rstr = 1;
+ rstp = 1;
+ }
+ else
+ {
+ rstr = colnum;
+ rstp = colnum;
+ }
+ rinc = 1;
+ numcol = 2;
+ }
+ else
+ {
+ /* this is a table, so the row info is in the (naxis+1) elements */
+ rstr = blc[naxis];
+ rstp = trc[naxis];
+ rinc = inc[naxis];
+ numcol = colnum;
+ }
+
+ nultyp = 2;
+ if (anynul)
+ *anynul = FALSE;
+
+ i0 = 0;
+ for (ii = 0; ii < 9; ii++)
+ {
+ str[ii] = 1;
+ stp[ii] = 1;
+ incr[ii] = 1;
+ dsize[ii] = 1;
+ }
+
+ for (ii = 0; ii < naxis; ii++)
+ {
+ if (trc[ii] < blc[ii])
+ {
+ sprintf(msg, "ffgsve: illegal range specified for axis %ld", ii + 1);
+ ffpmsg(msg);
+ return(*status = BAD_PIX_NUM);
+ }
+
+ str[ii] = blc[ii];
+ stp[ii] = trc[ii];
+ incr[ii] = inc[ii];
+ dsize[ii + 1] = dsize[ii] * naxes[ii];
+ }
+
+ if (naxis == 1 && naxes[0] == 1)
+ {
+ /* This is not a vector column, so read all the rows at once */
+ nelem = (rstp - rstr) / rinc + 1;
+ ninc = rinc;
+ rstp = rstr;
+ }
+ else
+ {
+ /* have to read each row individually, in all dimensions */
+ nelem = (stp[0] - str[0]) / inc[0] + 1;
+ ninc = incr[0];
+ }
+
+ for (row = rstr; row <= rstp; row += rinc)
+ {
+ for (i8 = str[8]; i8 <= stp[8]; i8 += incr[8])
+ {
+ for (i7 = str[7]; i7 <= stp[7]; i7 += incr[7])
+ {
+ for (i6 = str[6]; i6 <= stp[6]; i6 += incr[6])
+ {
+ for (i5 = str[5]; i5 <= stp[5]; i5 += incr[5])
+ {
+ for (i4 = str[4]; i4 <= stp[4]; i4 += incr[4])
+ {
+ for (i3 = str[3]; i3 <= stp[3]; i3 += incr[3])
+ {
+ for (i2 = str[2]; i2 <= stp[2]; i2 += incr[2])
+ {
+ for (i1 = str[1]; i1 <= stp[1]; i1 += incr[1])
+ {
+ felem=str[0] + (i1 - 1) * dsize[1] + (i2 - 1) * dsize[2] +
+ (i3 - 1) * dsize[3] + (i4 - 1) * dsize[4] +
+ (i5 - 1) * dsize[5] + (i6 - 1) * dsize[6] +
+ (i7 - 1) * dsize[7] + (i8 - 1) * dsize[8];
+
+ if ( ffgcle(fptr, numcol, row, felem, nelem, ninc, nultyp,
+ nulval, &array[i0], &flagval[i0], &anyf, status) > 0)
+ return(*status);
+
+ if (anyf && anynul)
+ *anynul = TRUE;
+
+ i0 += nelem;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffggpe( fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to read (1 = 1st group) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ float *array, /* O - array of values that are returned */
+ int *status) /* IO - error status */
+/*
+ Read an array of group parameters from the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being read).
+*/
+{
+ long row;
+ int idummy;
+ char cdummy;
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ row=maxvalue(1,group);
+
+ ffgcle(fptr, 1, row, firstelem, nelem, 1, 1, 0.F,
+ array, &cdummy, &idummy, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgcve(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to read (1 = 1st col) */
+ long firstrow, /* I - first row to read (1 = 1st row) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ float nulval, /* I - value for null pixels */
+ float *array, /* O - array of values that are read */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from a column in the current FITS HDU. Automatic
+ datatype conversion will be performed if the datatype of the column does not
+ match the datatype of the array parameter. The output values will be scaled
+ by the FITS TSCALn and TZEROn values if these values have been defined.
+ Any undefined pixels will be set equal to the value of 'nulval' unless
+ nulval = 0 in which case no checks for undefined pixels will be made.
+*/
+{
+ char cdummy;
+
+ ffgcle(fptr, colnum, firstrow, firstelem, nelem, 1, 1, nulval,
+ array, &cdummy, anynul, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgcvc(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to read (1 = 1st col) */
+ long firstrow, /* I - first row to read (1 = 1st row) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ float nulval, /* I - value for null pixels */
+ float *array, /* O - array of values that are read */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from a column in the current FITS HDU. Automatic
+ datatype conversion will be performed if the datatype of the column does not
+ match the datatype of the array parameter. The output values will be scaled
+ by the FITS TSCALn and TZEROn values if these values have been defined.
+ Any undefined pixels will be set equal to the value of 'nulval' unless
+ nulval = 0 in which case no checks for undefined pixels will be made.
+
+ TSCAL and ZERO should not be used with complex values.
+*/
+{
+ char cdummy;
+
+ /* a complex value is interpreted as a pair of float values, thus */
+ /* need to multiply the first element and number of elements by 2 */
+
+ ffgcle(fptr, colnum, firstrow, (firstelem - 1) * 2 + 1, nelem *2,
+ 1, 1, nulval, array, &cdummy, anynul, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgcfe(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to read (1 = 1st col) */
+ long firstrow, /* I - first row to read (1 = 1st row) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ float *array, /* O - array of values that are read */
+ char *nularray, /* O - array of flags: 1 if null pixel; else 0 */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from a column in the current FITS HDU. Automatic
+ datatype conversion will be performed if the datatype of the column does not
+ match the datatype of the array parameter. The output values will be scaled
+ by the FITS TSCALn and TZEROn values if these values have been defined.
+ Nularray will be set = 1 if the corresponding array pixel is undefined,
+ otherwise nularray will = 0.
+*/
+{
+ float dummy = 0;
+
+ ffgcle(fptr, colnum, firstrow, firstelem, nelem, 1, 2, dummy,
+ array, nularray, anynul, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgcfc(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to read (1 = 1st col) */
+ long firstrow, /* I - first row to read (1 = 1st row) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ float *array, /* O - array of values that are read */
+ char *nularray, /* O - array of flags: 1 if null pixel; else 0 */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from a column in the current FITS HDU. Automatic
+ datatype conversion will be performed if the datatype of the column does not
+ match the datatype of the array parameter. The output values will be scaled
+ by the FITS TSCALn and TZEROn values if these values have been defined.
+ Nularray will be set = 1 if the corresponding array pixel is undefined,
+ otherwise nularray will = 0.
+
+ TSCAL and ZERO should not be used with complex values.
+*/
+{
+ long ii, jj;
+ float dummy = 0;
+ char *carray;
+
+ /* a complex value is interpreted as a pair of float values, thus */
+ /* need to multiply the first element and number of elements by 2 */
+
+ /* allocate temporary array */
+ carray = (char *) calloc(nelem * 2, 1);
+
+ ffgcle(fptr, colnum, firstrow, (firstelem - 1) * 2 + 1, nelem * 2,
+ 1, 2, dummy, array, carray, anynul, status);
+
+ for (ii = 0, jj = 0; jj < nelem; ii += 2, jj++)
+ {
+ if (carray[ii] || carray[ii + 1])
+ nularray[jj] = 1;
+ else
+ nularray[jj] = 0;
+ }
+
+ free(carray);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgcle( fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to read (1 = 1st col) */
+ long firstrow, /* I - first row to read (1 = 1st row) */
+ OFF_T firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ long elemincre, /* I - pixel increment; e.g., 2 = every other */
+ int nultyp, /* I - null value handling code: */
+ /* 1: set undefined pixels = nulval */
+ /* 2: set nularray=1 for undefined pixels */
+ float nulval, /* I - value for null pixels if nultyp = 1 */
+ float *array, /* O - array of values that are read */
+ char *nularray, /* O - array of flags = 1 if nultyp = 2 */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from a column in the current FITS HDU.
+ The column number may refer to a real column in an ASCII or binary table,
+ or it may refer be a virtual column in a 1 or more grouped FITS primary
+ array or image extension. FITSIO treats a primary array as a binary table
+ with 2 vector columns: the first column contains the group parameters (often
+ with length = 0) and the second column contains the array of image pixels.
+ Each row of the table represents a group in the case of multigroup FITS
+ images.
+
+ The output array of values will be converted from the datatype of the column
+ and will be scaled by the FITS TSCALn and TZEROn values if necessary.
+*/
+{
+ double scale, zero, power = 1.;
+ int tcode, maxelem, hdutype, xcode, decimals;
+ long twidth, incre, rownum, remain, next, ntodo;
+ long ii, rowincre, tnull, xwidth;
+ int convert, nulcheck, readcheck = 0;
+ OFF_T repeat, startpos, elemnum, readptr, rowlen;
+ char tform[20];
+ char message[81];
+ char snull[20]; /* the FITS null value if reading from ASCII table */
+
+ double cbuff[DBUFFSIZE / sizeof(double)]; /* align cbuff on word boundary */
+ void *buffer;
+
+ if (*status > 0 || nelem == 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ buffer = cbuff;
+
+ if (anynul)
+ *anynul = 0;
+
+ if (nultyp == 2)
+ memset(nularray, 0, nelem); /* initialize nullarray */
+
+ /*---------------------------------------------------*/
+ /* Check input and get parameters about the column: */
+ /*---------------------------------------------------*/
+ if (elemincre < 0)
+ readcheck = -1; /* don't do range checking in this case */
+
+ if ( ffgcpr( fptr, colnum, firstrow, firstelem, nelem, readcheck, &scale, &zero,
+ tform, &twidth, &tcode, &maxelem, &startpos, &elemnum, &incre,
+ &repeat, &rowlen, &hdutype, &tnull, snull, status) > 0 )
+ return(*status);
+
+ incre *= elemincre; /* multiply incre to just get every nth pixel */
+
+ if (tcode == TSTRING) /* setup for ASCII tables */
+ {
+ /* get the number of implied decimal places if no explicit decmal point */
+ ffasfm(tform, &xcode, &xwidth, &decimals, status);
+ for(ii = 0; ii < decimals; ii++)
+ power *= 10.;
+ }
+
+ /*------------------------------------------------------------------*/
+ /* Decide whether to check for null values in the input FITS file: */
+ /*------------------------------------------------------------------*/
+ nulcheck = nultyp; /* by default check for null values in the FITS file */
+
+ if (nultyp == 1 && nulval == 0)
+ nulcheck = 0; /* calling routine does not want to check for nulls */
+
+ else if (tcode%10 == 1 && /* if reading an integer column, and */
+ tnull == NULL_UNDEFINED) /* if a null value is not defined, */
+ nulcheck = 0; /* then do not check for null values. */
+
+ else if (tcode == TSHORT && (tnull > SHRT_MAX || tnull < SHRT_MIN) )
+ nulcheck = 0; /* Impossible null value */
+
+ else if (tcode == TBYTE && (tnull > 255 || tnull < 0) )
+ nulcheck = 0; /* Impossible null value */
+
+ else if (tcode == TSTRING && snull[0] == ASCII_NULL_UNDEFINED)
+ nulcheck = 0;
+
+ /*----------------------------------------------------------------------*/
+ /* If FITS column and output data array have same datatype, then we do */
+ /* not need to use a temporary buffer to store intermediate datatype. */
+ /*----------------------------------------------------------------------*/
+ convert = 1;
+ if (tcode == TFLOAT) /* Special Case: */
+ { /* no type convertion required, so read */
+ maxelem = nelem; /* data directly into output buffer. */
+
+ if (nulcheck == 0 && scale == 1. && zero == 0.)
+ convert = 0; /* no need to scale data or find nulls */
+ }
+
+ /*---------------------------------------------------------------------*/
+ /* Now read the pixels from the FITS column. If the column does not */
+ /* have the same datatype as the output array, then we have to read */
+ /* the raw values into a temporary buffer (of limited size). In */
+ /* the case of a vector colum read only 1 vector of values at a time */
+ /* then skip to the next row if more values need to be read. */
+ /* After reading the raw values, then call the fffXXYY routine to (1) */
+ /* test for undefined values, (2) convert the datatype if necessary, */
+ /* and (3) scale the values by the FITS TSCALn and TZEROn linear */
+ /* scaling parameters. */
+ /*---------------------------------------------------------------------*/
+ remain = nelem; /* remaining number of values to read */
+ next = 0; /* next element in array to be read */
+ rownum = 0; /* row number, relative to firstrow */
+
+ while (remain)
+ {
+ /* limit the number of pixels to read at one time to the number that
+ will fit in the buffer or to the number of pixels that remain in
+ the current vector, which ever is smaller.
+ */
+ ntodo = minvalue(remain, maxelem);
+ if (elemincre >= 0)
+ {
+ ntodo = minvalue(ntodo, ((repeat - elemnum - 1)/elemincre +1));
+ }
+ else
+ {
+ ntodo = minvalue(ntodo, (elemnum/(-elemincre) +1));
+ }
+
+ readptr = startpos + ((OFF_T)rownum * rowlen) + (elemnum * (incre / elemincre));
+
+ switch (tcode)
+ {
+ case (TFLOAT):
+ ffgr4b(fptr, readptr, ntodo, incre, &array[next], status);
+ if (convert)
+ fffr4r4(&array[next], ntodo, scale, zero, nulcheck,
+ nulval, &nularray[next], anynul,
+ &array[next], status);
+ break;
+ case (TBYTE):
+ ffgi1b(fptr, readptr, ntodo, incre, (unsigned char *) buffer,
+ status);
+ fffi1r4((unsigned char *) buffer, ntodo, scale, zero, nulcheck,
+ (unsigned char) tnull, nulval, &nularray[next], anynul,
+ &array[next], status);
+ break;
+ case (TSHORT):
+ ffgi2b(fptr, readptr, ntodo, incre, (short *) buffer, status);
+ fffi2r4((short *) buffer, ntodo, scale, zero, nulcheck,
+ (short) tnull, nulval, &nularray[next], anynul,
+ &array[next], status);
+ break;
+ case (TLONG):
+ ffgi4b(fptr, readptr, ntodo, incre, (INT32BIT *) buffer,
+ status);
+ fffi4r4((INT32BIT *) buffer, ntodo, scale, zero, nulcheck,
+ (INT32BIT) tnull, nulval, &nularray[next], anynul,
+ &array[next], status);
+ break;
+
+ case (TLONGLONG):
+ ffgi8b(fptr, readptr, ntodo, incre, (long *) buffer, status);
+ fffi8r4( (LONGLONG *) buffer, ntodo, scale, zero,
+ nulcheck, (long) tnull, nulval, &nularray[next],
+ anynul, &array[next], status);
+ break;
+ case (TDOUBLE):
+ ffgr8b(fptr, readptr, ntodo, incre, (double *) buffer, status);
+ fffr8r4((double *) buffer, ntodo, scale, zero, nulcheck,
+ nulval, &nularray[next], anynul,
+ &array[next], status);
+ break;
+ case (TSTRING):
+ ffmbyt(fptr, readptr, REPORT_EOF, status);
+
+ if (incre == twidth) /* contiguous bytes */
+ ffgbyt(fptr, ntodo * twidth, buffer, status);
+ else
+ ffgbytoff(fptr, twidth, ntodo, incre - twidth, buffer,
+ status);
+
+ fffstrr4((char *) buffer, ntodo, scale, zero, twidth, power,
+ nulcheck, snull, nulval, &nularray[next], anynul,
+ &array[next], status);
+ break;
+
+
+ default: /* error trap for invalid column format */
+ sprintf(message,
+ "Cannot read numbers from column %d which has format %s",
+ colnum, tform);
+ ffpmsg(message);
+ if (hdutype == ASCII_TBL)
+ return(*status = BAD_ATABLE_FORMAT);
+ else
+ return(*status = BAD_BTABLE_FORMAT);
+
+ } /* End of switch block */
+
+ /*-------------------------*/
+ /* Check for fatal error */
+ /*-------------------------*/
+ if (*status > 0) /* test for error during previous read operation */
+ {
+ if (hdutype > 0)
+ sprintf(message,
+ "Error reading elements %ld thru %ld from column %d (ffgcle).",
+ next+1, next+ntodo, colnum);
+ else
+ sprintf(message,
+ "Error reading elements %ld thru %ld from image (ffgcle).",
+ next+1, next+ntodo);
+
+ ffpmsg(message);
+ return(*status);
+ }
+
+ /*--------------------------------------------*/
+ /* increment the counters for the next loop */
+ /*--------------------------------------------*/
+ remain -= ntodo;
+ if (remain)
+ {
+ next += ntodo;
+ elemnum = elemnum + (ntodo * elemincre);
+
+ if (elemnum >= repeat) /* completed a row; start on later row */
+ {
+ rowincre = elemnum / repeat;
+ rownum += rowincre;
+ elemnum = elemnum - (rowincre * repeat);
+ }
+ else if (elemnum < 0) /* completed a row; start on a previous row */
+ {
+ rowincre = (-elemnum - 1) / repeat + 1;
+ rownum -= rowincre;
+ elemnum = (rowincre * repeat) + elemnum;
+ }
+ }
+ } /* End of main while Loop */
+
+
+ /*--------------------------------*/
+ /* check for numerical overflow */
+ /*--------------------------------*/
+ if (*status == OVERFLOW_ERR)
+ {
+ ffpmsg(
+ "Numerical overflow during type conversion while reading FITS data.");
+ *status = NUM_OVERFLOW;
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffi1r4(unsigned char *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ unsigned char tnull, /* I - value of FITS TNULLn keyword if any */
+ float nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ float *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to tnull. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ long ii;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = (float) input[ii]; /* copy input to output */
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ output[ii] = ( (double) input[ii] ) * scale + zero;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ output[ii] = (float) input[ii];
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ output[ii] = ( (double) input[ii] ) * scale + zero;
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffi2r4(short *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ short tnull, /* I - value of FITS TNULLn keyword if any */
+ float nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ float *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to tnull. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ long ii;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = (float) input[ii]; /* copy input to output */
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ output[ii] = input[ii] * scale + zero;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ output[ii] = (float) input[ii];
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ output[ii] = input[ii] * scale + zero;
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffi4r4(INT32BIT *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ INT32BIT tnull, /* I - value of FITS TNULLn keyword if any */
+ float nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ float *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to tnull. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ long ii;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = (float) input[ii]; /* copy input to output */
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ output[ii] = input[ii] * scale + zero;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ output[ii] = (float) input[ii];
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ output[ii] = input[ii] * scale + zero;
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffi8r4(LONGLONG *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ long tnull, /* I - value of FITS TNULLn keyword if any */
+ float nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ float *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to tnull. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+#if (LONGSIZE == 32) && (! defined HAVE_LONGLONG)
+
+ /* This block of code is only used in cases where there is */
+ /* no native 8-byte integer support. We have to interpret */
+ /* the corresponding pair of 4-byte integers which are */
+ /* are equivalent to the 8-byte integer. */
+
+ unsigned long *uinput;
+ long ii,jj, kk;
+ double dvalue;
+
+ uinput = (unsigned long *) input;
+
+#if BYTESWAPPED /* jj points to the most significant part of the 8-byte int */
+ jj = 1;
+ kk = 0;
+#else
+ jj = 0;
+ kk = 1;
+#endif
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++, jj += 2, kk += 2)
+ {
+ if (uinput[jj] & 0x80000000) /* negative number */
+ dvalue = (uinput[jj] ^ 0xffffffff) * -4294967296. -
+ (uinput[kk] ^ 0xffffffff) - 1.;
+ else /* positive number */
+ dvalue = uinput[jj] * 4294967296. + uinput[kk];
+
+ output[ii] = (float) dvalue;
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++, jj += 2, kk += 2)
+ {
+ if (uinput[jj] & 0x80000000) /* negative number */
+ dvalue = ((uinput[jj] ^ 0xffffffff) * -4294967296. -
+ (uinput[kk] ^ 0xffffffff) - 1.) * scale + zero;
+ else /* positive number */
+ dvalue = (uinput[jj] * 4294967296. + uinput[kk])
+ * scale + zero;
+
+ output[ii] = (float) dvalue;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++, jj += 2, kk += 2)
+ {
+ if (uinput[jj] & 0x80000000) /* negative number */
+ dvalue = (uinput[jj] ^ 0xffffffff) * -4294967296. -
+ (uinput[kk] ^ 0xffffffff) - 1.;
+ else /* positive number */
+ dvalue = uinput[jj] * 4294967296. + uinput[kk];
+
+ if (dvalue == (double) tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ output[ii] = (float) dvalue;
+ }
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++, jj += 2, kk += 2)
+ {
+ if (uinput[jj] & 0x80000000) /* negative number */
+ dvalue = (uinput[jj] ^ 0xffffffff) * -4294967296. -
+ (uinput[kk] ^ 0xffffffff) - 1.;
+ else /* positive number */
+ dvalue = uinput[jj] * 4294967296. + uinput[kk];
+
+ if (dvalue == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ output[ii] = dvalue * scale + zero;
+ }
+ }
+ }
+ }
+
+#else
+
+ /* this block works on machines which support an 8-byte integer type */
+
+ long ii;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = (float) input[ii]; /* copy input to output */
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ output[ii] = input[ii] * scale + zero;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ output[ii] = (float) input[ii];
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ output[ii] = input[ii] * scale + zero;
+ }
+ }
+ }
+ }
+
+#endif
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffr4r4(float *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ float nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ float *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to NaN. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ long ii;
+ short *sptr, iret;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ memcpy(output, input, ntodo * sizeof(float) );
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ output[ii] = input[ii] * scale + zero;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ sptr = (short *) input;
+
+#if BYTESWAPPED && MACHINE != VAXVMS && MACHINE != ALPHAVMS
+ sptr++; /* point to MSBs */
+#endif
+
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++, sptr += 2)
+ {
+ if (0 != (iret = fnan(*sptr) ) ) /* test for NaN or underflow */
+ {
+ if (iret == 1) /* is it a NaN? */
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ {
+ nullarray[ii] = 1;
+ /* explicitly set value in case output contains a NaN */
+ output[ii] = FLOATNULLVALUE;
+ }
+ }
+ else /* it's an underflow */
+ output[ii] = 0;
+ }
+ else
+ output[ii] = input[ii];
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++, sptr += 2)
+ {
+ if (0 != (iret = fnan(*sptr) ) ) /* test for NaN or underflow */
+ {
+ if (iret == 1) /* is it a NaN? */
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ {
+ nullarray[ii] = 1;
+ /* explicitly set value in case output contains a NaN */
+ output[ii] = FLOATNULLVALUE;
+ }
+ }
+ else /* it's an underflow */
+ output[ii] = zero;
+ }
+ else
+ output[ii] = input[ii] * scale + zero;
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffr8r4(double *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ float nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ float *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to NaN. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ long ii;
+ short *sptr, iret;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = (double) input[ii]; /* copy input to output */
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ output[ii] = input[ii] * scale + zero;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ sptr = (short *) input;
+
+#if BYTESWAPPED && MACHINE != VAXVMS && MACHINE != ALPHAVMS
+ sptr += 3; /* point to MSBs */
+#endif
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++, sptr += 4)
+ {
+ if (0 != (iret = dnan(*sptr)) ) /* test for NaN or underflow */
+ {
+ if (iret == 1) /* is it a NaN? */
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else /* it's an underflow */
+ output[ii] = 0;
+ }
+ else
+ output[ii] = (double) input[ii];
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++, sptr += 4)
+ {
+ if (0 != (iret = dnan(*sptr)) ) /* test for NaN or underflow */
+ {
+ if (iret == 1) /* is it a NaN? */
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else /* it's an underflow */
+ output[ii] = zero;
+ }
+ else
+ output[ii] = input[ii] * scale + zero;
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffstrr4(char *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ long twidth, /* I - width of each substring of chars */
+ double implipower, /* I - power of 10 of implied decimal */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ char *snull, /* I - value of FITS null string, if any */
+ float nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ float *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file. Check
+ for null values and do scaling if required. The nullcheck code value
+ determines how any null values in the input array are treated. A null
+ value is an input pixel that is equal to snull. If nullcheck= 0, then
+ no special checking for nulls is performed. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ int nullen;
+ long ii;
+ double dvalue;
+ char *cstring, message[81];
+ char *cptr, *tpos;
+ char tempstore, chrzero = '0';
+ double val, power;
+ int exponent, sign, esign, decpt;
+
+ nullen = strlen(snull);
+ cptr = input; /* pointer to start of input string */
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ cstring = cptr;
+ /* temporarily insert a null terminator at end of the string */
+ tpos = cptr + twidth;
+ tempstore = *tpos;
+ *tpos = 0;
+
+ /* check if null value is defined, and if the */
+ /* column string is identical to the null string */
+ if (snull[0] != ASCII_NULL_UNDEFINED &&
+ !strncmp(snull, cptr, nullen) )
+ {
+ if (nullcheck)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ cptr += twidth;
+ }
+ else
+ {
+ /* value is not the null value, so decode it */
+ /* remove any embedded blank characters from the string */
+
+ decpt = 0;
+ sign = 1;
+ val = 0.;
+ power = 1.;
+ exponent = 0;
+ esign = 1;
+
+ while (*cptr == ' ') /* skip leading blanks */
+ cptr++;
+
+ if (*cptr == '-' || *cptr == '+') /* check for leading sign */
+ {
+ if (*cptr == '-')
+ sign = -1;
+
+ cptr++;
+
+ while (*cptr == ' ') /* skip blanks between sign and value */
+ cptr++;
+ }
+
+ while (*cptr >= '0' && *cptr <= '9')
+ {
+ val = val * 10. + *cptr - chrzero; /* accumulate the value */
+ cptr++;
+
+ while (*cptr == ' ') /* skip embedded blanks in the value */
+ cptr++;
+ }
+
+ if (*cptr == '.') /* check for decimal point */
+ {
+ decpt = 1; /* set flag to show there was a decimal point */
+ cptr++;
+ while (*cptr == ' ') /* skip any blanks */
+ cptr++;
+
+ while (*cptr >= '0' && *cptr <= '9')
+ {
+ val = val * 10. + *cptr - chrzero; /* accumulate the value */
+ power = power * 10.;
+ cptr++;
+
+ while (*cptr == ' ') /* skip embedded blanks in the value */
+ cptr++;
+ }
+ }
+
+ if (*cptr == 'E' || *cptr == 'D') /* check for exponent */
+ {
+ cptr++;
+ while (*cptr == ' ') /* skip blanks */
+ cptr++;
+
+ if (*cptr == '-' || *cptr == '+') /* check for exponent sign */
+ {
+ if (*cptr == '-')
+ esign = -1;
+
+ cptr++;
+
+ while (*cptr == ' ') /* skip blanks between sign and exp */
+ cptr++;
+ }
+
+ while (*cptr >= '0' && *cptr <= '9')
+ {
+ exponent = exponent * 10 + *cptr - chrzero; /* accumulate exp */
+ cptr++;
+
+ while (*cptr == ' ') /* skip embedded blanks */
+ cptr++;
+ }
+ }
+
+ if (*cptr != 0) /* should end up at the null terminator */
+ {
+ sprintf(message, "Cannot read number from ASCII table");
+ ffpmsg(message);
+ sprintf(message, "Column field = %s.", cstring);
+ ffpmsg(message);
+ /* restore the char that was overwritten by the null */
+ *tpos = tempstore;
+ return(*status = BAD_C2D);
+ }
+
+ if (!decpt) /* if no explicit decimal, use implied */
+ power = implipower;
+
+ dvalue = (sign * val / power) * pow(10., (double) (esign * exponent));
+
+ output[ii] = (float) (dvalue * scale + zero); /* apply the scaling */
+
+ }
+ /* restore the char that was overwritten by the null */
+ *tpos = tempstore;
+ }
+ return(*status);
+}
diff --git a/pkg/tbtables/cfitsio/getcoli.c b/pkg/tbtables/cfitsio/getcoli.c
new file mode 100644
index 00000000..2ec1dd1f
--- /dev/null
+++ b/pkg/tbtables/cfitsio/getcoli.c
@@ -0,0 +1,2043 @@
+/* This file, getcoli.c, contains routines that read data elements from */
+/* a FITS image or table, with short datatype. */
+
+/* The FITSIO software was written by William Pence at the High Energy */
+/* Astrophysic Science Archive Research Center (HEASARC) at the NASA */
+/* Goddard Space Flight Center. */
+
+#include <math.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include "fitsio2.h"
+
+/*--------------------------------------------------------------------------*/
+int ffgpvi( fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to read (1 = 1st group) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ short nulval, /* I - value for undefined pixels */
+ short *array, /* O - array of values that are returned */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being read).
+ Undefined elements will be set equal to NULVAL, unless NULVAL=0
+ in which case no checking for undefined values will be performed.
+ ANYNUL is returned with a value of .true. if any pixels are undefined.
+*/
+{
+ long row;
+ char cdummy;
+ int nullcheck = 1;
+ short nullvalue;
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+ nullvalue = nulval; /* set local variable */
+ fits_read_compressed_pixels(fptr, TSHORT, firstelem, nelem,
+ nullcheck, &nullvalue, array, NULL, anynul, status);
+ return(*status);
+ }
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ row=maxvalue(1,group);
+
+ ffgcli(fptr, 2, row, firstelem, nelem, 1, 1, nulval,
+ array, &cdummy, anynul, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgpfi( fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to read (1 = 1st group) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ short *array, /* O - array of values that are returned */
+ char *nularray, /* O - array of null pixel flags */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being read).
+ Any undefined pixels in the returned array will be set = 0 and the
+ corresponding nularray value will be set = 1.
+ ANYNUL is returned with a value of .true. if any pixels are undefined.
+*/
+{
+ long row;
+ int nullcheck = 2;
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ fits_read_compressed_pixels(fptr, TSHORT, firstelem, nelem,
+ nullcheck, NULL, array, nularray, anynul, status);
+ return(*status);
+ }
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ row=maxvalue(1,group);
+
+ ffgcli(fptr, 2, row, firstelem, nelem, 1, 2, 0,
+ array, nularray, anynul, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffg2di(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to read (1 = 1st group) */
+ short nulval, /* set undefined pixels equal to this */
+ long ncols, /* I - number of pixels in each row of array */
+ long naxis1, /* I - FITS image NAXIS1 value */
+ long naxis2, /* I - FITS image NAXIS2 value */
+ short *array, /* O - array to be filled and returned */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an entire 2-D array of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of the
+ FITS array is not the same as the array being read). Any null
+ values in the array will be set equal to the value of nulval, unless
+ nulval = 0 in which case no null checking will be performed.
+*/
+{
+ /* call the 3D reading routine, with the 3rd dimension = 1 */
+
+ ffg3di(fptr, group, nulval, ncols, naxis2, naxis1, naxis2, 1, array,
+ anynul, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffg3di(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to read (1 = 1st group) */
+ short nulval, /* set undefined pixels equal to this */
+ long ncols, /* I - number of pixels in each row of array */
+ long nrows, /* I - number of rows in each plane of array */
+ long naxis1, /* I - FITS image NAXIS1 value */
+ long naxis2, /* I - FITS image NAXIS2 value */
+ long naxis3, /* I - FITS image NAXIS3 value */
+ short *array, /* O - array to be filled and returned */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an entire 3-D array of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of the
+ FITS array is not the same as the array being read). Any null
+ values in the array will be set equal to the value of nulval, unless
+ nulval = 0 in which case no null checking will be performed.
+*/
+{
+ long tablerow, nfits, narray, ii, jj;
+ char cdummy;
+ int nullcheck = 1;
+ long inc[] = {1,1,1};
+ long fpixel[] = {1,1,1};
+ long lpixel[3];
+ short nullvalue;
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ lpixel[0] = ncols;
+ lpixel[1] = nrows;
+ lpixel[2] = naxis3;
+ nullvalue = nulval; /* set local variable */
+
+ fits_read_compressed_img(fptr, TSHORT, fpixel, lpixel, inc,
+ nullcheck, &nullvalue, array, NULL, anynul, status);
+ return(*status);
+ }
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+ tablerow=maxvalue(1,group);
+
+ if (ncols == naxis1 && nrows == naxis2) /* arrays have same size? */
+ {
+ /* all the image pixels are contiguous, so read all at once */
+ ffgcli(fptr, 2, tablerow, 1, naxis1 * naxis2 * naxis3, 1, 1, nulval,
+ array, &cdummy, anynul, status);
+ return(*status);
+ }
+
+ if (ncols < naxis1 || nrows < naxis2)
+ return(*status = BAD_DIMEN);
+
+ nfits = 1; /* next pixel in FITS image to read */
+ narray = 0; /* next pixel in output array to be filled */
+
+ /* loop over naxis3 planes in the data cube */
+ for (jj = 0; jj < naxis3; jj++)
+ {
+ /* loop over the naxis2 rows in the FITS image, */
+ /* reading naxis1 pixels to each row */
+
+ for (ii = 0; ii < naxis2; ii++)
+ {
+ if (ffgcli(fptr, 2, tablerow, nfits, naxis1, 1, 1, nulval,
+ &array[narray], &cdummy, anynul, status) > 0)
+ return(*status);
+
+ nfits += naxis1;
+ narray += ncols;
+ }
+ narray += (nrows - naxis2) * ncols;
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgsvi(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of the column to read (1 = 1st) */
+ int naxis, /* I - number of dimensions in the FITS array */
+ long *naxes, /* I - size of each dimension */
+ long *blc, /* I - 'bottom left corner' of the subsection */
+ long *trc, /* I - 'top right corner' of the subsection */
+ long *inc, /* I - increment to be applied in each dimension */
+ short nulval, /* I - value to set undefined pixels */
+ short *array, /* O - array to be filled and returned */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read a subsection of data values from an image or a table column.
+ This routine is set up to handle a maximum of nine dimensions.
+*/
+{
+ long ii,i0, i1,i2,i3,i4,i5,i6,i7,i8,row,rstr,rstp,rinc;
+ long str[9],stp[9],incr[9],dir[9];
+ long nelem, nultyp, ninc, numcol;
+ OFF_T felem, dsize[10];
+ int hdutype, anyf;
+ char ldummy, msg[FLEN_ERRMSG];
+ int nullcheck = 1;
+ short nullvalue;
+
+ if (naxis < 1 || naxis > 9)
+ {
+ sprintf(msg, "NAXIS = %d in call to ffgsvi is out of range", naxis);
+ ffpmsg(msg);
+ return(*status = BAD_DIMEN);
+ }
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ nullvalue = nulval; /* set local variable */
+
+ fits_read_compressed_img(fptr, TSHORT, blc, trc, inc,
+ nullcheck, &nullvalue, array, NULL, anynul, status);
+
+ return(*status);
+ }
+
+/*
+ if this is a primary array, then the input COLNUM parameter should
+ be interpreted as the row number, and we will alway read the image
+ data from column 2 (any group parameters are in column 1).
+*/
+ if (ffghdt(fptr, &hdutype, status) > 0)
+ return(*status);
+
+ if (hdutype == IMAGE_HDU)
+ {
+ /* this is a primary array, or image extension */
+ if (colnum == 0)
+ {
+ rstr = 1;
+ rstp = 1;
+ }
+ else
+ {
+ rstr = colnum;
+ rstp = colnum;
+ }
+ rinc = 1;
+ numcol = 2;
+ }
+ else
+ {
+ /* this is a table, so the row info is in the (naxis+1) elements */
+ rstr = blc[naxis];
+ rstp = trc[naxis];
+ rinc = inc[naxis];
+ numcol = colnum;
+ }
+
+ nultyp = 1;
+ if (anynul)
+ *anynul = FALSE;
+
+ i0 = 0;
+ for (ii = 0; ii < 9; ii++)
+ {
+ str[ii] = 1;
+ stp[ii] = 1;
+ incr[ii] = 1;
+ dsize[ii] = 1;
+ dir[ii] = 1;
+ }
+
+ for (ii = 0; ii < naxis; ii++)
+ {
+ if (trc[ii] < blc[ii])
+ {
+ if (hdutype == IMAGE_HDU)
+ {
+ dir[ii] = -1;
+ }
+ else
+ {
+ sprintf(msg, "ffgsvi: illegal range specified for axis %ld", ii + 1);
+ ffpmsg(msg);
+ return(*status = BAD_PIX_NUM);
+ }
+ }
+
+ str[ii] = blc[ii];
+ stp[ii] = trc[ii];
+ incr[ii] = inc[ii];
+ dsize[ii + 1] = dsize[ii] * naxes[ii];
+ dsize[ii] = dsize[ii] * dir[ii];
+ }
+ dsize[naxis] = dsize[naxis] * dir[naxis];
+
+ if (naxis == 1 && naxes[0] == 1)
+ {
+ /* This is not a vector column, so read all the rows at once */
+ nelem = (rstp - rstr) / rinc + 1;
+ ninc = rinc;
+ rstp = rstr;
+ }
+ else
+ {
+ /* have to read each row individually, in all dimensions */
+ nelem = (stp[0]*dir[0] - str[0]*dir[0]) / inc[0] + 1;
+ ninc = incr[0] * dir[0];
+ }
+
+ for (row = rstr; row <= rstp; row += rinc)
+ {
+ for (i8 = str[8]*dir[8]; i8 <= stp[8]*dir[8]; i8 += incr[8])
+ {
+ for (i7 = str[7]*dir[7]; i7 <= stp[7]*dir[7]; i7 += incr[7])
+ {
+ for (i6 = str[6]*dir[6]; i6 <= stp[6]*dir[6]; i6 += incr[6])
+ {
+ for (i5 = str[5]*dir[5]; i5 <= stp[5]*dir[5]; i5 += incr[5])
+ {
+ for (i4 = str[4]*dir[4]; i4 <= stp[4]*dir[4]; i4 += incr[4])
+ {
+ for (i3 = str[3]*dir[3]; i3 <= stp[3]*dir[3]; i3 += incr[3])
+ {
+ for (i2 = str[2]*dir[2]; i2 <= stp[2]*dir[2]; i2 += incr[2])
+ {
+ for (i1 = str[1]*dir[1]; i1 <= stp[1]*dir[1]; i1 += incr[1])
+ {
+
+ felem=str[0] + (i1 - dir[1]) * dsize[1] + (i2 - dir[2]) * dsize[2] +
+ (i3 - dir[3]) * dsize[3] + (i4 - dir[4]) * dsize[4] +
+ (i5 - dir[5]) * dsize[5] + (i6 - dir[6]) * dsize[6] +
+ (i7 - dir[7]) * dsize[7] + (i8 - dir[8]) * dsize[8];
+
+ if ( ffgcli(fptr, numcol, row, felem, nelem, ninc, nultyp,
+ nulval, &array[i0], &ldummy, &anyf, status) > 0)
+ return(*status);
+
+ if (anyf && anynul)
+ *anynul = TRUE;
+
+ i0 += nelem;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgsfi(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of the column to read (1 = 1st) */
+ int naxis, /* I - number of dimensions in the FITS array */
+ long *naxes, /* I - size of each dimension */
+ long *blc, /* I - 'bottom left corner' of the subsection */
+ long *trc, /* I - 'top right corner' of the subsection */
+ long *inc, /* I - increment to be applied in each dimension */
+ short *array, /* O - array to be filled and returned */
+ char *flagval, /* O - set to 1 if corresponding value is null */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read a subsection of data values from an image or a table column.
+ This routine is set up to handle a maximum of nine dimensions.
+*/
+{
+ long ii,i0, i1,i2,i3,i4,i5,i6,i7,i8,row,rstr,rstp,rinc;
+ long str[9],stp[9],incr[9],dsize[10];
+ long felem, nelem, nultyp, ninc, numcol;
+ int hdutype, anyf;
+ short nulval = 0;
+ char msg[FLEN_ERRMSG];
+ int nullcheck = 2;
+
+ if (naxis < 1 || naxis > 9)
+ {
+ sprintf(msg, "NAXIS = %d in call to ffgsvi is out of range", naxis);
+ ffpmsg(msg);
+ return(*status = BAD_DIMEN);
+ }
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ fits_read_compressed_img(fptr, TSHORT, blc, trc, inc,
+ nullcheck, NULL, array, flagval, anynul, status);
+ return(*status);
+ }
+
+/*
+ if this is a primary array, then the input COLNUM parameter should
+ be interpreted as the row number, and we will alway read the image
+ data from column 2 (any group parameters are in column 1).
+*/
+ if (ffghdt(fptr, &hdutype, status) > 0)
+ return(*status);
+
+ if (hdutype == IMAGE_HDU)
+ {
+ /* this is a primary array, or image extension */
+ if (colnum == 0)
+ {
+ rstr = 1;
+ rstp = 1;
+ }
+ else
+ {
+ rstr = colnum;
+ rstp = colnum;
+ }
+ rinc = 1;
+ numcol = 2;
+ }
+ else
+ {
+ /* this is a table, so the row info is in the (naxis+1) elements */
+ rstr = blc[naxis];
+ rstp = trc[naxis];
+ rinc = inc[naxis];
+ numcol = colnum;
+ }
+
+ nultyp = 2;
+ if (anynul)
+ *anynul = FALSE;
+
+ i0 = 0;
+ for (ii = 0; ii < 9; ii++)
+ {
+ str[ii] = 1;
+ stp[ii] = 1;
+ incr[ii] = 1;
+ dsize[ii] = 1;
+ }
+
+ for (ii = 0; ii < naxis; ii++)
+ {
+ if (trc[ii] < blc[ii])
+ {
+ sprintf(msg, "ffgsvi: illegal range specified for axis %ld", ii + 1);
+ ffpmsg(msg);
+ return(*status = BAD_PIX_NUM);
+ }
+
+ str[ii] = blc[ii];
+ stp[ii] = trc[ii];
+ incr[ii] = inc[ii];
+ dsize[ii + 1] = dsize[ii] * naxes[ii];
+ }
+
+ if (naxis == 1 && naxes[0] == 1)
+ {
+ /* This is not a vector column, so read all the rows at once */
+ nelem = (rstp - rstr) / rinc + 1;
+ ninc = rinc;
+ rstp = rstr;
+ }
+ else
+ {
+ /* have to read each row individually, in all dimensions */
+ nelem = (stp[0] - str[0]) / inc[0] + 1;
+ ninc = incr[0];
+ }
+
+ for (row = rstr; row <= rstp; row += rinc)
+ {
+ for (i8 = str[8]; i8 <= stp[8]; i8 += incr[8])
+ {
+ for (i7 = str[7]; i7 <= stp[7]; i7 += incr[7])
+ {
+ for (i6 = str[6]; i6 <= stp[6]; i6 += incr[6])
+ {
+ for (i5 = str[5]; i5 <= stp[5]; i5 += incr[5])
+ {
+ for (i4 = str[4]; i4 <= stp[4]; i4 += incr[4])
+ {
+ for (i3 = str[3]; i3 <= stp[3]; i3 += incr[3])
+ {
+ for (i2 = str[2]; i2 <= stp[2]; i2 += incr[2])
+ {
+ for (i1 = str[1]; i1 <= stp[1]; i1 += incr[1])
+ {
+ felem=str[0] + (i1 - 1) * dsize[1] + (i2 - 1) * dsize[2] +
+ (i3 - 1) * dsize[3] + (i4 - 1) * dsize[4] +
+ (i5 - 1) * dsize[5] + (i6 - 1) * dsize[6] +
+ (i7 - 1) * dsize[7] + (i8 - 1) * dsize[8];
+
+ if ( ffgcli(fptr, numcol, row, felem, nelem, ninc, nultyp,
+ nulval, &array[i0], &flagval[i0], &anyf, status) > 0)
+ return(*status);
+
+ if (anyf && anynul)
+ *anynul = TRUE;
+
+ i0 += nelem;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffggpi( fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to read (1 = 1st group) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ short *array, /* O - array of values that are returned */
+ int *status) /* IO - error status */
+/*
+ Read an array of group parameters from the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being read).
+*/
+{
+ long row;
+ int idummy;
+ char cdummy;
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ row=maxvalue(1,group);
+
+ ffgcli(fptr, 1, row, firstelem, nelem, 1, 1, 0,
+ array, &cdummy, &idummy, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgcvi(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to read (1 = 1st col) */
+ long firstrow, /* I - first row to read (1 = 1st row) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ short nulval, /* I - value for null pixels */
+ short *array, /* O - array of values that are read */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from a column in the current FITS HDU. Automatic
+ datatype conversion will be performed if the datatype of the column does not
+ match the datatype of the array parameter. The output values will be scaled
+ by the FITS TSCALn and TZEROn values if these values have been defined.
+ Any undefined pixels will be set equal to the value of 'nulval' unless
+ nulval = 0 in which case no checks for undefined pixels will be made.
+*/
+{
+ char cdummy;
+
+ ffgcli(fptr, colnum, firstrow, firstelem, nelem, 1, 1, nulval,
+ array, &cdummy, anynul, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgcfi(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to read (1 = 1st col) */
+ long firstrow, /* I - first row to read (1 = 1st row) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ short *array, /* O - array of values that are read */
+ char *nularray, /* O - array of flags: 1 if null pixel; else 0 */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from a column in the current FITS HDU. Automatic
+ datatype conversion will be performed if the datatype of the column does not
+ match the datatype of the array parameter. The output values will be scaled
+ by the FITS TSCALn and TZEROn values if these values have been defined.
+ Nularray will be set = 1 if the corresponding array pixel is undefined,
+ otherwise nularray will = 0.
+*/
+{
+ short dummy = 0;
+
+ ffgcli(fptr, colnum, firstrow, firstelem, nelem, 1, 2, dummy,
+ array, nularray, anynul, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgcli( fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to read (1 = 1st col) */
+ long firstrow, /* I - first row to read (1 = 1st row) */
+ OFF_T firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ long elemincre, /* I - pixel increment; e.g., 2 = every other */
+ int nultyp, /* I - null value handling code: */
+ /* 1: set undefined pixels = nulval */
+ /* 2: set nularray=1 for undefined pixels */
+ short nulval, /* I - value for null pixels if nultyp = 1 */
+ short *array, /* O - array of values that are read */
+ char *nularray, /* O - array of flags = 1 if nultyp = 2 */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from a column in the current FITS HDU.
+ The column number may refer to a real column in an ASCII or binary table,
+ or it may refer be a virtual column in a 1 or more grouped FITS primary
+ array or image extension. FITSIO treats a primary array as a binary table
+ with 2 vector columns: the first column contains the group parameters (often
+ with length = 0) and the second column contains the array of image pixels.
+ Each row of the table represents a group in the case of multigroup FITS
+ images.
+
+ The output array of values will be converted from the datatype of the column
+ and will be scaled by the FITS TSCALn and TZEROn values if necessary.
+*/
+{
+ double scale, zero, power = 1.;
+ int tcode, maxelem, hdutype, xcode, decimals;
+ long twidth, incre, rownum, remain, next, ntodo;
+ long ii, rowincre, tnull, xwidth;
+ int convert, nulcheck, readcheck = 0;
+ OFF_T repeat, startpos, elemnum, readptr, rowlen;
+ char tform[20];
+ char message[81];
+ char snull[20]; /* the FITS null value if reading from ASCII table */
+
+ double cbuff[DBUFFSIZE / sizeof(double)]; /* align cbuff on word boundary */
+ void *buffer;
+
+ if (*status > 0 || nelem == 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ buffer = cbuff;
+
+ if (anynul)
+ *anynul = 0;
+
+ if (nultyp == 2)
+ memset(nularray, 0, nelem); /* initialize nullarray */
+
+ /*---------------------------------------------------*/
+ /* Check input and get parameters about the column: */
+ /*---------------------------------------------------*/
+ if (elemincre < 0)
+ readcheck = -1; /* don't do range checking in this case */
+
+ if ( ffgcpr( fptr, colnum, firstrow, firstelem, nelem, readcheck, &scale, &zero,
+ tform, &twidth, &tcode, &maxelem, &startpos, &elemnum, &incre,
+ &repeat, &rowlen, &hdutype, &tnull, snull, status) > 0 )
+ return(*status);
+
+ incre *= elemincre; /* multiply incre to just get every nth pixel */
+
+ if (tcode == TSTRING) /* setup for ASCII tables */
+ {
+ /* get the number of implied decimal places if no explicit decmal point */
+ ffasfm(tform, &xcode, &xwidth, &decimals, status);
+ for(ii = 0; ii < decimals; ii++)
+ power *= 10.;
+ }
+ /*------------------------------------------------------------------*/
+ /* Decide whether to check for null values in the input FITS file: */
+ /*------------------------------------------------------------------*/
+ nulcheck = nultyp; /* by default check for null values in the FITS file */
+
+ if (nultyp == 1 && nulval == 0)
+ nulcheck = 0; /* calling routine does not want to check for nulls */
+
+ else if (tcode%10 == 1 && /* if reading an integer column, and */
+ tnull == NULL_UNDEFINED) /* if a null value is not defined, */
+ nulcheck = 0; /* then do not check for null values. */
+
+ else if (tcode == TSHORT && (tnull > SHRT_MAX || tnull < SHRT_MIN) )
+ nulcheck = 0; /* Impossible null value */
+
+ else if (tcode == TBYTE && (tnull > 255 || tnull < 0) )
+ nulcheck = 0; /* Impossible null value */
+
+ else if (tcode == TSTRING && snull[0] == ASCII_NULL_UNDEFINED)
+ nulcheck = 0;
+
+ /*----------------------------------------------------------------------*/
+ /* If FITS column and output data array have same datatype, then we do */
+ /* not need to use a temporary buffer to store intermediate datatype. */
+ /*----------------------------------------------------------------------*/
+ convert = 1;
+ if (tcode == TSHORT) /* Special Case: */
+ { /* no type convertion required, so read */
+ maxelem = nelem; /* data directly into output buffer. */
+
+ if (nulcheck == 0 && scale == 1. && zero == 0.)
+ convert = 0; /* no need to scale data or find nulls */
+ }
+
+ /*---------------------------------------------------------------------*/
+ /* Now read the pixels from the FITS column. If the column does not */
+ /* have the same datatype as the output array, then we have to read */
+ /* the raw values into a temporary buffer (of limited size). In */
+ /* the case of a vector colum read only 1 vector of values at a time */
+ /* then skip to the next row if more values need to be read. */
+ /* After reading the raw values, then call the fffXXYY routine to (1) */
+ /* test for undefined values, (2) convert the datatype if necessary, */
+ /* and (3) scale the values by the FITS TSCALn and TZEROn linear */
+ /* scaling parameters. */
+ /*---------------------------------------------------------------------*/
+ remain = nelem; /* remaining number of values to read */
+ next = 0; /* next element in array to be read */
+ rownum = 0; /* row number, relative to firstrow */
+
+ while (remain)
+ {
+ /* limit the number of pixels to read at one time to the number that
+ will fit in the buffer or to the number of pixels that remain in
+ the current vector, which ever is smaller.
+ */
+ ntodo = minvalue(remain, maxelem);
+ if (elemincre >= 0)
+ {
+ ntodo = minvalue(ntodo, ((repeat - elemnum - 1)/elemincre +1));
+ }
+ else
+ {
+ ntodo = minvalue(ntodo, (elemnum/(-elemincre) +1));
+ }
+
+ readptr = startpos + ((OFF_T)rownum * rowlen) + (elemnum * (incre / elemincre));
+
+ switch (tcode)
+ {
+ case (TSHORT):
+ ffgi2b(fptr, readptr, ntodo, incre, &array[next], status);
+ if (convert)
+ fffi2i2(&array[next], ntodo, scale, zero, nulcheck,
+ (short) tnull, nulval, &nularray[next], anynul,
+ &array[next], status);
+ break;
+ case (TLONGLONG):
+
+ ffgi8b(fptr, readptr, ntodo, incre, (long *) buffer, status);
+ fffi8i2( (LONGLONG *) buffer, ntodo, scale, zero,
+ nulcheck, (long) tnull, nulval, &nularray[next],
+ anynul, &array[next], status);
+ break;
+ case (TBYTE):
+ ffgi1b(fptr, readptr, ntodo, incre, (unsigned char *) buffer,
+ status);
+ fffi1i2((unsigned char *) buffer, ntodo, scale, zero, nulcheck,
+ (unsigned char) tnull, nulval, &nularray[next], anynul,
+ &array[next], status);
+ break;
+ case (TLONG):
+ ffgi4b(fptr, readptr, ntodo, incre, (INT32BIT *) buffer,
+ status);
+ fffi4i2((INT32BIT *) buffer, ntodo, scale, zero, nulcheck,
+ (INT32BIT) tnull, nulval, &nularray[next], anynul,
+ &array[next], status);
+ break;
+ case (TFLOAT):
+ ffgr4b(fptr, readptr, ntodo, incre, (float *) buffer, status);
+ fffr4i2((float *) buffer, ntodo, scale, zero, nulcheck,
+ nulval, &nularray[next], anynul,
+ &array[next], status);
+ break;
+ case (TDOUBLE):
+ ffgr8b(fptr, readptr, ntodo, incre, (double *) buffer, status);
+ fffr8i2((double *) buffer, ntodo, scale, zero, nulcheck,
+ nulval, &nularray[next], anynul,
+ &array[next], status);
+ break;
+ case (TSTRING):
+ ffmbyt(fptr, readptr, REPORT_EOF, status);
+
+ if (incre == twidth) /* contiguous bytes */
+ ffgbyt(fptr, ntodo * twidth, buffer, status);
+ else
+ ffgbytoff(fptr, twidth, ntodo, incre - twidth, buffer,
+ status);
+
+ fffstri2((char *) buffer, ntodo, scale, zero, twidth, power,
+ nulcheck, snull, nulval, &nularray[next], anynul,
+ &array[next], status);
+ break;
+
+ default: /* error trap for invalid column format */
+ sprintf(message,
+ "Cannot read numbers from column %d which has format %s",
+ colnum, tform);
+ ffpmsg(message);
+ if (hdutype == ASCII_TBL)
+ return(*status = BAD_ATABLE_FORMAT);
+ else
+ return(*status = BAD_BTABLE_FORMAT);
+
+ } /* End of switch block */
+
+ /*-------------------------*/
+ /* Check for fatal error */
+ /*-------------------------*/
+ if (*status > 0) /* test for error during previous read operation */
+ {
+ if (hdutype > 0)
+ sprintf(message,
+ "Error reading elements %ld thru %ld from column %d (ffgcli).",
+ next+1, next+ntodo, colnum);
+ else
+ sprintf(message,
+ "Error reading elements %ld thru %ld from image (ffgcli).",
+ next+1, next+ntodo);
+
+ ffpmsg(message);
+ return(*status);
+ }
+
+ /*--------------------------------------------*/
+ /* increment the counters for the next loop */
+ /*--------------------------------------------*/
+ remain -= ntodo;
+ if (remain)
+ {
+ next += ntodo;
+ elemnum = elemnum + (ntodo * elemincre);
+
+ if (elemnum >= repeat) /* completed a row; start on later row */
+ {
+ rowincre = elemnum / repeat;
+ rownum += rowincre;
+ elemnum = elemnum - (rowincre * repeat);
+ }
+ else if (elemnum < 0) /* completed a row; start on a previous row */
+ {
+ rowincre = (-elemnum - 1) / repeat + 1;
+ rownum -= rowincre;
+ elemnum = (rowincre * repeat) + elemnum;
+ }
+ }
+ } /* End of main while Loop */
+
+
+ /*--------------------------------*/
+ /* check for numerical overflow */
+ /*--------------------------------*/
+ if (*status == OVERFLOW_ERR)
+ {
+ ffpmsg(
+ "Numerical overflow during type conversion while reading FITS data.");
+ *status = NUM_OVERFLOW;
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffi1i2(unsigned char *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ unsigned char tnull, /* I - value of FITS TNULLn keyword if any */
+ short nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ short *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to tnull. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = (short) input[ii]; /* copy input to output */
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DSHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MIN;
+ }
+ else if (dvalue > DSHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MAX;
+ }
+ else
+ output[ii] = (short) dvalue;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ output[ii] = (short) input[ii];
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DSHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MIN;
+ }
+ else if (dvalue > DSHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MAX;
+ }
+ else
+ output[ii] = (short) dvalue;
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffi2i2(short *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ short tnull, /* I - value of FITS TNULLn keyword if any */
+ short nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ short *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to tnull. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ memcpy(output, input, ntodo * sizeof(short) );
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DSHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MIN;
+ }
+ else if (dvalue > DSHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MAX;
+ }
+ else
+ output[ii] = (short) dvalue;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ output[ii] = input[ii];
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DSHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MIN;
+ }
+ else if (dvalue > DSHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MAX;
+ }
+ else
+ output[ii] = (short) dvalue;
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffi4i2(INT32BIT *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ INT32BIT tnull, /* I - value of FITS TNULLn keyword if any */
+ short nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ short *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to tnull. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] < SHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MIN;
+ }
+ else if (input[ii] > SHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MAX;
+ }
+ else
+ output[ii] = (short) input[ii];
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DSHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MIN;
+ }
+ else if (dvalue > DSHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MAX;
+ }
+ else
+ output[ii] = (short) dvalue;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ if (input[ii] < SHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MIN;
+ }
+ else if (input[ii] > SHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MAX;
+ }
+ else
+ output[ii] = (short) input[ii];
+ }
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DSHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MIN;
+ }
+ else if (dvalue > DSHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MAX;
+ }
+ else
+ output[ii] = (short) dvalue;
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffi8i2(LONGLONG *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ long tnull, /* I - value of FITS TNULLn keyword if any */
+ short nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ short *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to tnull. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+#if (LONGSIZE == 32) && (! defined HAVE_LONGLONG)
+
+ /* This block of code is only used in cases where there is */
+ /* no native 8-byte integer support. We have to interpret */
+ /* the corresponding pair of 4-byte integers which are */
+ /* are equivalent to the 8-byte integer. */
+
+ long ii,jj,kk;
+ double dvalue;
+ unsigned long *uinput;
+
+ uinput = (unsigned long *) input;
+
+#if BYTESWAPPED /* jj points to the most significant part of the 8-byte int */
+ jj = 1;
+ kk = 0;
+#else
+ jj = 0;
+ kk = 1;
+#endif
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++, jj += 2, kk += 2)
+ {
+ if (uinput[jj] & 0x80000000) /* negative number */
+ dvalue = (uinput[jj] ^ 0xffffffff) * -4294967296. -
+ (uinput[kk] ^ 0xffffffff) - 1.;
+ else /* positive number */
+ dvalue = uinput[jj] * 4294967296. + uinput[kk];
+
+ if (dvalue < DSHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MIN;
+ }
+ else if (dvalue > DSHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MAX;
+ }
+ else
+ output[ii] = (short) dvalue;
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++, jj += 2, kk += 2)
+ {
+ if (uinput[jj] & 0x80000000) /* negative number */
+ dvalue = ((uinput[jj] ^ 0xffffffff) * -4294967296. -
+ (uinput[kk] ^ 0xffffffff) - 1.) * scale + zero;
+ else /* positive number */
+ dvalue = (uinput[jj] * 4294967296. + uinput[kk])
+ * scale + zero;
+
+ if (dvalue < DSHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MIN;
+ }
+ else if (dvalue > DSHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MAX;
+ }
+ else
+ output[ii] = (short) dvalue;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++, jj += 2, kk += 2)
+ {
+ if (uinput[jj] & 0x80000000) /* negative number */
+ dvalue = (uinput[jj] ^ 0xffffffff) * -4294967296. -
+ (uinput[kk] ^ 0xffffffff) - 1.;
+ else /* positive number */
+ dvalue = uinput[jj] * 4294967296. + uinput[kk];
+
+ if (dvalue == (double) tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ if (dvalue < DSHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MIN;
+ }
+ else if (dvalue > DSHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MAX;
+ }
+ else
+ output[ii] = (short) dvalue;
+ }
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0, jj = 0; ii < ntodo; ii++, jj += 2, kk += 2)
+ {
+ if (uinput[jj] & 0x80000000) /* negative number */
+ dvalue = (uinput[jj] ^ 0xffffffff) * -4294967296. -
+ (uinput[kk] ^ 0xffffffff) - 1.;
+ else /* positive number */
+ dvalue = uinput[jj] * 4294967296. + uinput[kk];
+
+ if (dvalue == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ dvalue = dvalue * scale + zero;
+
+ if (dvalue < DSHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MIN;
+ }
+ else if (dvalue > DSHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MAX;
+ }
+ else
+ output[ii] = (short) dvalue;
+ }
+ }
+ }
+ }
+
+#else
+
+ /* this block works on machines which support an 8-byte integer type */
+
+ long ii;
+ double dvalue;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] < SHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MIN;
+ }
+ else if (input[ii] > SHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MAX;
+ }
+ else
+ output[ii] = (short) input[ii];
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DSHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MIN;
+ }
+ else if (dvalue > DSHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MAX;
+ }
+ else
+ output[ii] = (short) dvalue;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ if (input[ii] < SHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MIN;
+ }
+ else if (input[ii] > SHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MAX;
+ }
+ else
+ output[ii] = (short) input[ii];
+ }
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DSHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MIN;
+ }
+ else if (dvalue > DSHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MAX;
+ }
+ else
+ output[ii] = (short) dvalue;
+ }
+ }
+ }
+ }
+
+#endif
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffr4i2(float *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ short nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ short *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to NaN. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ long ii;
+ double dvalue;
+ short *sptr, iret;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] < DSHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MIN;
+ }
+ else if (input[ii] > DSHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MAX;
+ }
+ else
+ output[ii] = (short) input[ii];
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DSHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MIN;
+ }
+ else if (dvalue > DSHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MAX;
+ }
+ else
+ output[ii] = (short) dvalue;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ sptr = (short *) input;
+
+#if BYTESWAPPED && MACHINE != VAXVMS && MACHINE != ALPHAVMS
+ sptr++; /* point to MSBs */
+#endif
+
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++, sptr += 2)
+ {
+ if (0 != (iret = fnan(*sptr) ) ) /* test for NaN or underflow */
+ {
+ if (iret == 1) /* is it a NaN? */
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else /* it's an underflow */
+ output[ii] = 0;
+ }
+ else
+ {
+ if (input[ii] < DSHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MIN;
+ }
+ else if (input[ii] > DSHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MAX;
+ }
+ else
+ output[ii] = (short) input[ii];
+ }
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++, sptr += 2)
+ {
+ if (0 != (iret = fnan(*sptr) ) ) /* test for NaN or underflow */
+ {
+ if (iret == 1) /* is it a NaN? */
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else /* it's an underflow */
+ {
+ if (zero < DSHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MIN;
+ }
+ else if (zero > DSHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MAX;
+ }
+ else
+ output[ii] = (short) zero;
+ }
+ }
+ else
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DSHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MIN;
+ }
+ else if (dvalue > DSHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MAX;
+ }
+ else
+ output[ii] = (short) dvalue;
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffr8i2(double *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ short nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ short *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to NaN. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ long ii;
+ double dvalue;
+ short *sptr, iret;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] < DSHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MIN;
+ }
+ else if (input[ii] > DSHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MAX;
+ }
+ else
+ output[ii] = (short) input[ii];
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DSHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MIN;
+ }
+ else if (dvalue > DSHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MAX;
+ }
+ else
+ output[ii] = (short) dvalue;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ sptr = (short *) input;
+
+#if BYTESWAPPED && MACHINE != VAXVMS && MACHINE != ALPHAVMS
+ sptr += 3; /* point to MSBs */
+#endif
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++, sptr += 4)
+ {
+ if (0 != (iret = dnan(*sptr)) ) /* test for NaN or underflow */
+ {
+ if (iret == 1) /* is it a NaN? */
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else /* it's an underflow */
+ output[ii] = 0;
+ }
+ else
+ {
+ if (input[ii] < DSHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MIN;
+ }
+ else if (input[ii] > DSHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MAX;
+ }
+ else
+ output[ii] = (short) input[ii];
+ }
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++, sptr += 4)
+ {
+ if (0 != (iret = dnan(*sptr)) ) /* test for NaN or underflow */
+ {
+ if (iret == 1) /* is it a NaN? */
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else /* it's an underflow */
+ {
+ if (zero < DSHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MIN;
+ }
+ else if (zero > DSHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MAX;
+ }
+ else
+ output[ii] = (short) zero;
+ }
+ }
+ else
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DSHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MIN;
+ }
+ else if (dvalue > DSHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MAX;
+ }
+ else
+ output[ii] = (short) dvalue;
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffstri2(char *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ long twidth, /* I - width of each substring of chars */
+ double implipower, /* I - power of 10 of implied decimal */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ char *snull, /* I - value of FITS null string, if any */
+ short nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ short *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file. Check
+ for null values and do scaling if required. The nullcheck code value
+ determines how any null values in the input array are treated. A null
+ value is an input pixel that is equal to snull. If nullcheck= 0, then
+ no special checking for nulls is performed. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ int nullen;
+ long ii;
+ double dvalue;
+ char *cstring, message[81];
+ char *cptr, *tpos;
+ char tempstore, chrzero = '0';
+ double val, power;
+ int exponent, sign, esign, decpt;
+
+ nullen = strlen(snull);
+ cptr = input; /* pointer to start of input string */
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ cstring = cptr;
+ /* temporarily insert a null terminator at end of the string */
+ tpos = cptr + twidth;
+ tempstore = *tpos;
+ *tpos = 0;
+
+ /* check if null value is defined, and if the */
+ /* column string is identical to the null string */
+ if (snull[0] != ASCII_NULL_UNDEFINED &&
+ !strncmp(snull, cptr, nullen) )
+ {
+ if (nullcheck)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ cptr += twidth;
+ }
+ else
+ {
+ /* value is not the null value, so decode it */
+ /* remove any embedded blank characters from the string */
+
+ decpt = 0;
+ sign = 1;
+ val = 0.;
+ power = 1.;
+ exponent = 0;
+ esign = 1;
+
+ while (*cptr == ' ') /* skip leading blanks */
+ cptr++;
+
+ if (*cptr == '-' || *cptr == '+') /* check for leading sign */
+ {
+ if (*cptr == '-')
+ sign = -1;
+
+ cptr++;
+
+ while (*cptr == ' ') /* skip blanks between sign and value */
+ cptr++;
+ }
+
+ while (*cptr >= '0' && *cptr <= '9')
+ {
+ val = val * 10. + *cptr - chrzero; /* accumulate the value */
+ cptr++;
+
+ while (*cptr == ' ') /* skip embedded blanks in the value */
+ cptr++;
+ }
+
+ if (*cptr == '.') /* check for decimal point */
+ {
+ decpt = 1; /* set flag to show there was a decimal point */
+ cptr++;
+ while (*cptr == ' ') /* skip any blanks */
+ cptr++;
+
+ while (*cptr >= '0' && *cptr <= '9')
+ {
+ val = val * 10. + *cptr - chrzero; /* accumulate the value */
+ power = power * 10.;
+ cptr++;
+
+ while (*cptr == ' ') /* skip embedded blanks in the value */
+ cptr++;
+ }
+ }
+
+ if (*cptr == 'E' || *cptr == 'D') /* check for exponent */
+ {
+ cptr++;
+ while (*cptr == ' ') /* skip blanks */
+ cptr++;
+
+ if (*cptr == '-' || *cptr == '+') /* check for exponent sign */
+ {
+ if (*cptr == '-')
+ esign = -1;
+
+ cptr++;
+
+ while (*cptr == ' ') /* skip blanks between sign and exp */
+ cptr++;
+ }
+
+ while (*cptr >= '0' && *cptr <= '9')
+ {
+ exponent = exponent * 10 + *cptr - chrzero; /* accumulate exp */
+ cptr++;
+
+ while (*cptr == ' ') /* skip embedded blanks */
+ cptr++;
+ }
+ }
+
+ if (*cptr != 0) /* should end up at the null terminator */
+ {
+ sprintf(message, "Cannot read number from ASCII table");
+ ffpmsg(message);
+ sprintf(message, "Column field = %s.", cstring);
+ ffpmsg(message);
+ /* restore the char that was overwritten by the null */
+ *tpos = tempstore;
+ return(*status = BAD_C2D);
+ }
+
+ if (!decpt) /* if no explicit decimal, use implied */
+ power = implipower;
+
+ dvalue = (sign * val / power) * pow(10., (double) (esign * exponent));
+
+ dvalue = dvalue * scale + zero; /* apply the scaling */
+
+ if (dvalue < DSHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MIN;
+ }
+ else if (dvalue > DSHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MAX;
+ }
+ else
+ output[ii] = (short) dvalue;
+ }
+ /* restore the char that was overwritten by the null */
+ *tpos = tempstore;
+ }
+ return(*status);
+}
diff --git a/pkg/tbtables/cfitsio/getcolj.c b/pkg/tbtables/cfitsio/getcolj.c
new file mode 100644
index 00000000..f7df81c6
--- /dev/null
+++ b/pkg/tbtables/cfitsio/getcolj.c
@@ -0,0 +1,3856 @@
+/* This file, getcolj.c, contains routines that read data elements from */
+/* a FITS image or table, with long data type. */
+
+/* The FITSIO software was written by William Pence at the High Energy */
+/* Astrophysic Science Archive Research Center (HEASARC) at the NASA */
+/* Goddard Space Flight Center. */
+
+#include <math.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include "fitsio2.h"
+
+/*--------------------------------------------------------------------------*/
+int ffgpvj( fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to read (1 = 1st group) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ long nulval, /* I - value for undefined pixels */
+ long *array, /* O - array of values that are returned */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being read).
+ Undefined elements will be set equal to NULVAL, unless NULVAL=0
+ in which case no checking for undefined values will be performed.
+ ANYNUL is returned with a value of .true. if any pixels are undefined.
+*/
+{
+ long row;
+ char cdummy;
+ int nullcheck = 1;
+ long nullvalue;
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+ nullvalue = nulval; /* set local variable */
+
+ fits_read_compressed_pixels(fptr, TLONG, firstelem, nelem,
+ nullcheck, &nullvalue, array, NULL, anynul, status);
+ return(*status);
+ }
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ row=maxvalue(1,group);
+
+ ffgclj(fptr, 2, row, firstelem, nelem, 1, 1, nulval,
+ array, &cdummy, anynul, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgpfj( fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to read (1 = 1st group) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ long *array, /* O - array of values that are returned */
+ char *nularray, /* O - array of null pixel flags */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being read).
+ Any undefined pixels in the returned array will be set = 0 and the
+ corresponding nularray value will be set = 1.
+ ANYNUL is returned with a value of .true. if any pixels are undefined.
+*/
+{
+ long row;
+ int nullcheck = 2;
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ fits_read_compressed_pixels(fptr, TLONG, firstelem, nelem,
+ nullcheck, NULL, array, nularray, anynul, status);
+ return(*status);
+ }
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ row=maxvalue(1,group);
+
+ ffgclj(fptr, 2, row, firstelem, nelem, 1, 2, 0L,
+ array, nularray, anynul, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffg2dj(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to read (1 = 1st group) */
+ long nulval, /* set undefined pixels equal to this */
+ long ncols, /* I - number of pixels in each row of array */
+ long naxis1, /* I - FITS image NAXIS1 value */
+ long naxis2, /* I - FITS image NAXIS2 value */
+ long *array, /* O - array to be filled and returned */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an entire 2-D array of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of the
+ FITS array is not the same as the array being read). Any null
+ values in the array will be set equal to the value of nulval, unless
+ nulval = 0 in which case no null checking will be performed.
+*/
+{
+ /* call the 3D reading routine, with the 3rd dimension = 1 */
+
+ ffg3dj(fptr, group, nulval, ncols, naxis2, naxis1, naxis2, 1, array,
+ anynul, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffg3dj(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to read (1 = 1st group) */
+ long nulval, /* set undefined pixels equal to this */
+ long ncols, /* I - number of pixels in each row of array */
+ long nrows, /* I - number of rows in each plane of array */
+ long naxis1, /* I - FITS image NAXIS1 value */
+ long naxis2, /* I - FITS image NAXIS2 value */
+ long naxis3, /* I - FITS image NAXIS3 value */
+ long *array, /* O - array to be filled and returned */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an entire 3-D array of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of the
+ FITS array is not the same as the array being read). Any null
+ values in the array will be set equal to the value of nulval, unless
+ nulval = 0 in which case no null checking will be performed.
+*/
+{
+ long tablerow, nfits, narray, ii, jj;
+ char cdummy;
+ int nullcheck = 1;
+ long inc[] = {1,1,1};
+ long fpixel[] = {1,1,1};
+ long lpixel[3], nullvalue;
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ lpixel[0] = ncols;
+ lpixel[1] = nrows;
+ lpixel[2] = naxis3;
+ nullvalue = nulval; /* set local variable */
+
+ fits_read_compressed_img(fptr, TLONG, fpixel, lpixel, inc,
+ nullcheck, &nullvalue, array, NULL, anynul, status);
+ return(*status);
+ }
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+ tablerow=maxvalue(1,group);
+
+ if (ncols == naxis1 && nrows == naxis2) /* arrays have same size? */
+ {
+ /* all the image pixels are contiguous, so read all at once */
+ ffgclj(fptr, 2, tablerow, 1, naxis1 * naxis2 * naxis3, 1, 1, nulval,
+ array, &cdummy, anynul, status);
+ return(*status);
+ }
+
+ if (ncols < naxis1 || nrows < naxis2)
+ return(*status = BAD_DIMEN);
+
+ nfits = 1; /* next pixel in FITS image to read */
+ narray = 0; /* next pixel in output array to be filled */
+
+ /* loop over naxis3 planes in the data cube */
+ for (jj = 0; jj < naxis3; jj++)
+ {
+ /* loop over the naxis2 rows in the FITS image, */
+ /* reading naxis1 pixels to each row */
+
+ for (ii = 0; ii < naxis2; ii++)
+ {
+ if (ffgclj(fptr, 2, tablerow, nfits, naxis1, 1, 1, nulval,
+ &array[narray], &cdummy, anynul, status) > 0)
+ return(*status);
+
+ nfits += naxis1;
+ narray += ncols;
+ }
+ narray += (nrows - naxis2) * ncols;
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgsvj(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of the column to read (1 = 1st) */
+ int naxis, /* I - number of dimensions in the FITS array */
+ long *naxes, /* I - size of each dimension */
+ long *blc, /* I - 'bottom left corner' of the subsection */
+ long *trc, /* I - 'top right corner' of the subsection */
+ long *inc, /* I - increment to be applied in each dimension */
+ long nulval, /* I - value to set undefined pixels */
+ long *array, /* O - array to be filled and returned */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read a subsection of data values from an image or a table column.
+ This routine is set up to handle a maximum of nine dimensions.
+*/
+{
+ long ii,i0, i1,i2,i3,i4,i5,i6,i7,i8,row,rstr,rstp,rinc;
+ long str[9],stp[9],incr[9],dir[9];
+ long nelem, nultyp, ninc, numcol;
+ OFF_T felem, dsize[10];
+ int hdutype, anyf;
+ char ldummy, msg[FLEN_ERRMSG];
+ int nullcheck = 1;
+ long nullvalue;
+
+ if (naxis < 1 || naxis > 9)
+ {
+ sprintf(msg, "NAXIS = %d in call to ffgsvj is out of range", naxis);
+ ffpmsg(msg);
+ return(*status = BAD_DIMEN);
+ }
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ nullvalue = nulval; /* set local variable */
+
+ fits_read_compressed_img(fptr, TLONG, blc, trc, inc,
+ nullcheck, &nullvalue, array, NULL, anynul, status);
+ return(*status);
+ }
+
+/*
+ if this is a primary array, then the input COLNUM parameter should
+ be interpreted as the row number, and we will alway read the image
+ data from column 2 (any group parameters are in column 1).
+*/
+ if (ffghdt(fptr, &hdutype, status) > 0)
+ return(*status);
+
+ if (hdutype == IMAGE_HDU)
+ {
+ /* this is a primary array, or image extension */
+ if (colnum == 0)
+ {
+ rstr = 1;
+ rstp = 1;
+ }
+ else
+ {
+ rstr = colnum;
+ rstp = colnum;
+ }
+ rinc = 1;
+ numcol = 2;
+ }
+ else
+ {
+ /* this is a table, so the row info is in the (naxis+1) elements */
+ rstr = blc[naxis];
+ rstp = trc[naxis];
+ rinc = inc[naxis];
+ numcol = colnum;
+ }
+
+ nultyp = 1;
+ if (anynul)
+ *anynul = FALSE;
+
+ i0 = 0;
+ for (ii = 0; ii < 9; ii++)
+ {
+ str[ii] = 1;
+ stp[ii] = 1;
+ incr[ii] = 1;
+ dsize[ii] = 1;
+ dir[ii] = 1;
+ }
+
+ for (ii = 0; ii < naxis; ii++)
+ {
+ if (trc[ii] < blc[ii])
+ {
+ if (hdutype == IMAGE_HDU)
+ {
+ dir[ii] = -1;
+ }
+ else
+ {
+ sprintf(msg, "ffgsvj: illegal range specified for axis %ld", ii + 1);
+ ffpmsg(msg);
+ return(*status = BAD_PIX_NUM);
+ }
+ }
+
+ str[ii] = blc[ii];
+ stp[ii] = trc[ii];
+ incr[ii] = inc[ii];
+ dsize[ii + 1] = dsize[ii] * naxes[ii];
+ dsize[ii] = dsize[ii] * dir[ii];
+ }
+ dsize[naxis] = dsize[naxis] * dir[naxis];
+
+ if (naxis == 1 && naxes[0] == 1)
+ {
+ /* This is not a vector column, so read all the rows at once */
+ nelem = (rstp - rstr) / rinc + 1;
+ ninc = rinc;
+ rstp = rstr;
+ }
+ else
+ {
+ /* have to read each row individually, in all dimensions */
+ nelem = (stp[0]*dir[0] - str[0]*dir[0]) / inc[0] + 1;
+ ninc = incr[0] * dir[0];
+ }
+
+ for (row = rstr; row <= rstp; row += rinc)
+ {
+ for (i8 = str[8]*dir[8]; i8 <= stp[8]*dir[8]; i8 += incr[8])
+ {
+ for (i7 = str[7]*dir[7]; i7 <= stp[7]*dir[7]; i7 += incr[7])
+ {
+ for (i6 = str[6]*dir[6]; i6 <= stp[6]*dir[6]; i6 += incr[6])
+ {
+ for (i5 = str[5]*dir[5]; i5 <= stp[5]*dir[5]; i5 += incr[5])
+ {
+ for (i4 = str[4]*dir[4]; i4 <= stp[4]*dir[4]; i4 += incr[4])
+ {
+ for (i3 = str[3]*dir[3]; i3 <= stp[3]*dir[3]; i3 += incr[3])
+ {
+ for (i2 = str[2]*dir[2]; i2 <= stp[2]*dir[2]; i2 += incr[2])
+ {
+ for (i1 = str[1]*dir[1]; i1 <= stp[1]*dir[1]; i1 += incr[1])
+ {
+
+ felem=str[0] + (i1 - dir[1]) * dsize[1] + (i2 - dir[2]) * dsize[2] +
+ (i3 - dir[3]) * dsize[3] + (i4 - dir[4]) * dsize[4] +
+ (i5 - dir[5]) * dsize[5] + (i6 - dir[6]) * dsize[6] +
+ (i7 - dir[7]) * dsize[7] + (i8 - dir[8]) * dsize[8];
+
+ if ( ffgclj(fptr, numcol, row, felem, nelem, ninc, nultyp,
+ nulval, &array[i0], &ldummy, &anyf, status) > 0)
+ return(*status);
+
+ if (anyf && anynul)
+ *anynul = TRUE;
+
+ i0 += nelem;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgsfj(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of the column to read (1 = 1st) */
+ int naxis, /* I - number of dimensions in the FITS array */
+ long *naxes, /* I - size of each dimension */
+ long *blc, /* I - 'bottom left corner' of the subsection */
+ long *trc, /* I - 'top right corner' of the subsection */
+ long *inc, /* I - increment to be applied in each dimension */
+ long *array, /* O - array to be filled and returned */
+ char *flagval, /* O - set to 1 if corresponding value is null */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read a subsection of data values from an image or a table column.
+ This routine is set up to handle a maximum of nine dimensions.
+*/
+{
+ long ii,i0, i1,i2,i3,i4,i5,i6,i7,i8,row,rstr,rstp,rinc;
+ long str[9],stp[9],incr[9],dsize[10];
+ long felem, nelem, nultyp, ninc, numcol;
+ long nulval = 0;
+ int hdutype, anyf;
+ char msg[FLEN_ERRMSG];
+ int nullcheck = 2;
+
+ if (naxis < 1 || naxis > 9)
+ {
+ sprintf(msg, "NAXIS = %d in call to ffgsvj is out of range", naxis);
+ ffpmsg(msg);
+ return(*status = BAD_DIMEN);
+ }
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ fits_read_compressed_img(fptr, TLONG, blc, trc, inc,
+ nullcheck, NULL, array, flagval, anynul, status);
+ return(*status);
+ }
+
+/*
+ if this is a primary array, then the input COLNUM parameter should
+ be interpreted as the row number, and we will alway read the image
+ data from column 2 (any group parameters are in column 1).
+*/
+ if (ffghdt(fptr, &hdutype, status) > 0)
+ return(*status);
+
+ if (hdutype == IMAGE_HDU)
+ {
+ /* this is a primary array, or image extension */
+ if (colnum == 0)
+ {
+ rstr = 1;
+ rstp = 1;
+ }
+ else
+ {
+ rstr = colnum;
+ rstp = colnum;
+ }
+ rinc = 1;
+ numcol = 2;
+ }
+ else
+ {
+ /* this is a table, so the row info is in the (naxis+1) elements */
+ rstr = blc[naxis];
+ rstp = trc[naxis];
+ rinc = inc[naxis];
+ numcol = colnum;
+ }
+
+ nultyp = 2;
+ if (anynul)
+ *anynul = FALSE;
+
+ i0 = 0;
+ for (ii = 0; ii < 9; ii++)
+ {
+ str[ii] = 1;
+ stp[ii] = 1;
+ incr[ii] = 1;
+ dsize[ii] = 1;
+ }
+
+ for (ii = 0; ii < naxis; ii++)
+ {
+ if (trc[ii] < blc[ii])
+ {
+ sprintf(msg, "ffgsvj: illegal range specified for axis %ld", ii + 1);
+ ffpmsg(msg);
+ return(*status = BAD_PIX_NUM);
+ }
+
+ str[ii] = blc[ii];
+ stp[ii] = trc[ii];
+ incr[ii] = inc[ii];
+ dsize[ii + 1] = dsize[ii] * naxes[ii];
+ }
+
+ if (naxis == 1 && naxes[0] == 1)
+ {
+ /* This is not a vector column, so read all the rows at once */
+ nelem = (rstp - rstr) / rinc + 1;
+ ninc = rinc;
+ rstp = rstr;
+ }
+ else
+ {
+ /* have to read each row individually, in all dimensions */
+ nelem = (stp[0] - str[0]) / inc[0] + 1;
+ ninc = incr[0];
+ }
+
+ for (row = rstr; row <= rstp; row += rinc)
+ {
+ for (i8 = str[8]; i8 <= stp[8]; i8 += incr[8])
+ {
+ for (i7 = str[7]; i7 <= stp[7]; i7 += incr[7])
+ {
+ for (i6 = str[6]; i6 <= stp[6]; i6 += incr[6])
+ {
+ for (i5 = str[5]; i5 <= stp[5]; i5 += incr[5])
+ {
+ for (i4 = str[4]; i4 <= stp[4]; i4 += incr[4])
+ {
+ for (i3 = str[3]; i3 <= stp[3]; i3 += incr[3])
+ {
+ for (i2 = str[2]; i2 <= stp[2]; i2 += incr[2])
+ {
+ for (i1 = str[1]; i1 <= stp[1]; i1 += incr[1])
+ {
+ felem=str[0] + (i1 - 1) * dsize[1] + (i2 - 1) * dsize[2] +
+ (i3 - 1) * dsize[3] + (i4 - 1) * dsize[4] +
+ (i5 - 1) * dsize[5] + (i6 - 1) * dsize[6] +
+ (i7 - 1) * dsize[7] + (i8 - 1) * dsize[8];
+
+ if ( ffgclj(fptr, numcol, row, felem, nelem, ninc, nultyp,
+ nulval, &array[i0], &flagval[i0], &anyf, status) > 0)
+ return(*status);
+
+ if (anyf && anynul)
+ *anynul = TRUE;
+
+ i0 += nelem;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffggpj( fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to read (1 = 1st group) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ long *array, /* O - array of values that are returned */
+ int *status) /* IO - error status */
+/*
+ Read an array of group parameters from the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being read).
+*/
+{
+ long row;
+ int idummy;
+ char cdummy;
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ row=maxvalue(1,group);
+
+ ffgclj(fptr, 1, row, firstelem, nelem, 1, 1, 0L,
+ array, &cdummy, &idummy, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgcvj(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to read (1 = 1st col) */
+ long firstrow, /* I - first row to read (1 = 1st row) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ long nulval, /* I - value for null pixels */
+ long *array, /* O - array of values that are read */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from a column in the current FITS HDU. Automatic
+ datatype conversion will be performed if the datatype of the column does not
+ match the datatype of the array parameter. The output values will be scaled
+ by the FITS TSCALn and TZEROn values if these values have been defined.
+ Any undefined pixels will be set equal to the value of 'nulval' unless
+ nulval = 0 in which case no checks for undefined pixels will be made.
+*/
+{
+ char cdummy;
+
+ ffgclj(fptr, colnum, firstrow, firstelem, nelem, 1, 1, nulval,
+ array, &cdummy, anynul, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgcfj(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to read (1 = 1st col) */
+ long firstrow, /* I - first row to read (1 = 1st row) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ long *array, /* O - array of values that are read */
+ char *nularray, /* O - array of flags: 1 if null pixel; else 0 */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from a column in the current FITS HDU. Automatic
+ datatype conversion will be performed if the datatype of the column does not
+ match the datatype of the array parameter. The output values will be scaled
+ by the FITS TSCALn and TZEROn values if these values have been defined.
+ Nularray will be set = 1 if the corresponding array pixel is undefined,
+ otherwise nularray will = 0.
+*/
+{
+ long dummy = 0;
+
+ ffgclj(fptr, colnum, firstrow, firstelem, nelem, 1, 2, dummy,
+ array, nularray, anynul, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgclj( fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to read (1 = 1st col) */
+ long firstrow, /* I - first row to read (1 = 1st row) */
+ OFF_T firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ long elemincre, /* I - pixel increment; e.g., 2 = every other */
+ int nultyp, /* I - null value handling code: */
+ /* 1: set undefined pixels = nulval */
+ /* 2: set nularray=1 for undefined pixels */
+ long nulval, /* I - value for null pixels if nultyp = 1 */
+ long *array, /* O - array of values that are read */
+ char *nularray, /* O - array of flags = 1 if nultyp = 2 */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from a column in the current FITS HDU.
+ The column number may refer to a real column in an ASCII or binary table,
+ or it may refer be a virtual column in a 1 or more grouped FITS primary
+ array or image extension. FITSIO treats a primary array as a binary table
+ with 2 vector columns: the first column contains the group parameters (often
+ with length = 0) and the second column contains the array of image pixels.
+ Each row of the table represents a group in the case of multigroup FITS
+ images.
+
+ The output array of values will be converted from the datatype of the column
+ and will be scaled by the FITS TSCALn and TZEROn values if necessary.
+*/
+{
+ double scale, zero, power = 1.;
+ int tcode, maxelem, hdutype, xcode, decimals;
+ long twidth, incre, rownum, remain, next, ntodo;
+ long ii, rowincre, tnull, xwidth;
+ int convert, nulcheck, readcheck = 0;
+ OFF_T repeat, startpos, elemnum, readptr, rowlen;
+ char tform[20];
+ char message[81];
+ char snull[20]; /* the FITS null value if reading from ASCII table */
+
+ double cbuff[DBUFFSIZE / sizeof(double)]; /* align cbuff on word boundary */
+ void *buffer;
+
+ if (*status > 0 || nelem == 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ buffer = cbuff;
+
+ if (anynul)
+ *anynul = 0;
+
+ if (nultyp == 2)
+ memset(nularray, 0, nelem); /* initialize nullarray */
+
+ /*---------------------------------------------------*/
+ /* Check input and get parameters about the column: */
+ /*---------------------------------------------------*/
+ if (elemincre < 0)
+ readcheck = -1; /* don't do range checking in this case */
+
+ if (ffgcpr(fptr, colnum, firstrow, firstelem, nelem, readcheck, &scale, &zero,
+ tform, &twidth, &tcode, &maxelem, &startpos, &elemnum, &incre,
+ &repeat, &rowlen, &hdutype, &tnull, snull, status) > 0 )
+ return(*status);
+
+ incre *= elemincre; /* multiply incre to just get every nth pixel */
+
+ if (tcode == TSTRING) /* setup for ASCII tables */
+ {
+ /* get the number of implied decimal places if no explicit decmal point */
+ ffasfm(tform, &xcode, &xwidth, &decimals, status);
+ for(ii = 0; ii < decimals; ii++)
+ power *= 10.;
+ }
+ /*------------------------------------------------------------------*/
+ /* Decide whether to check for null values in the input FITS file: */
+ /*------------------------------------------------------------------*/
+ nulcheck = nultyp; /* by default check for null values in the FITS file */
+
+ if (nultyp == 1 && nulval == 0)
+ nulcheck = 0; /* calling routine does not want to check for nulls */
+
+ else if (tcode%10 == 1 && /* if reading an integer column, and */
+ tnull == NULL_UNDEFINED) /* if a null value is not defined, */
+ nulcheck = 0; /* then do not check for null values. */
+
+ else if (tcode == TSHORT && (tnull > SHRT_MAX || tnull < SHRT_MIN) )
+ nulcheck = 0; /* Impossible null value */
+
+ else if (tcode == TBYTE && (tnull > 255 || tnull < 0) )
+ nulcheck = 0; /* Impossible null value */
+
+ else if (tcode == TSTRING && snull[0] == ASCII_NULL_UNDEFINED)
+ nulcheck = 0;
+
+ /*----------------------------------------------------------------------*/
+ /* If FITS column and output data array have same datatype, then we do */
+ /* not need to use a temporary buffer to store intermediate datatype. */
+ /*----------------------------------------------------------------------*/
+ convert = 1;
+ if (tcode == TLONG) /* Special Case: */
+ { /* no type convertion required, so read */
+ maxelem = nelem; /* data directly into output buffer. */
+
+ if (nulcheck == 0 && scale == 1. && zero == 0. && LONGSIZE == 32)
+ convert = 0; /* no need to scale data or find nulls */
+ }
+
+ /*---------------------------------------------------------------------*/
+ /* Now read the pixels from the FITS column. If the column does not */
+ /* have the same datatype as the output array, then we have to read */
+ /* the raw values into a temporary buffer (of limited size). In */
+ /* the case of a vector colum read only 1 vector of values at a time */
+ /* then skip to the next row if more values need to be read. */
+ /* After reading the raw values, then call the fffXXYY routine to (1) */
+ /* test for undefined values, (2) convert the datatype if necessary, */
+ /* and (3) scale the values by the FITS TSCALn and TZEROn linear */
+ /* scaling parameters. */
+ /*---------------------------------------------------------------------*/
+ remain = nelem; /* remaining number of values to read */
+ next = 0; /* next element in array to be read */
+ rownum = 0; /* row number, relative to firstrow */
+
+ while (remain)
+ {
+ /* limit the number of pixels to read at one time to the number that
+ will fit in the buffer or to the number of pixels that remain in
+ the current vector, which ever is smaller.
+ */
+ ntodo = minvalue(remain, maxelem);
+ if (elemincre >= 0)
+ {
+ ntodo = minvalue(ntodo, ((repeat - elemnum - 1)/elemincre +1));
+ }
+ else
+ {
+ ntodo = minvalue(ntodo, (elemnum/(-elemincre) +1));
+ }
+
+ readptr = startpos + ((OFF_T)rownum * rowlen) + (elemnum * (incre / elemincre));
+
+ switch (tcode)
+ {
+ case (TLONG):
+ ffgi4b(fptr, readptr, ntodo, incre, (INT32BIT *) &array[next],
+ status);
+ if (convert)
+ fffi4i4((INT32BIT *) &array[next], ntodo, scale, zero,
+ nulcheck, (INT32BIT) tnull, nulval, &nularray[next],
+ anynul, &array[next], status);
+ break;
+ case (TLONGLONG):
+ ffgi8b(fptr, readptr, ntodo, incre, (long *) buffer, status);
+ fffi8i4((LONGLONG *) buffer, ntodo, scale, zero,
+ nulcheck, tnull, nulval, &nularray[next],
+ anynul, &array[next], status);
+ break;
+ case (TBYTE):
+ ffgi1b(fptr, readptr, ntodo, incre, (unsigned char *) buffer,
+ status);
+ fffi1i4((unsigned char *) buffer, ntodo, scale, zero, nulcheck,
+ (unsigned char) tnull, nulval, &nularray[next], anynul,
+ &array[next], status);
+ break;
+ case (TSHORT):
+ ffgi2b(fptr, readptr, ntodo, incre, (short *) buffer, status);
+ fffi2i4((short *) buffer, ntodo, scale, zero, nulcheck,
+ (short) tnull, nulval, &nularray[next], anynul,
+ &array[next], status);
+ break;
+ case (TFLOAT):
+ ffgr4b(fptr, readptr, ntodo, incre, (float *) buffer, status);
+ fffr4i4((float *) buffer, ntodo, scale, zero, nulcheck,
+ nulval, &nularray[next], anynul,
+ &array[next], status);
+ break;
+ case (TDOUBLE):
+ ffgr8b(fptr, readptr, ntodo, incre, (double *) buffer, status);
+ fffr8i4((double *) buffer, ntodo, scale, zero, nulcheck,
+ nulval, &nularray[next], anynul,
+ &array[next], status);
+ break;
+ case (TSTRING):
+ ffmbyt(fptr, readptr, REPORT_EOF, status);
+
+ if (incre == twidth) /* contiguous bytes */
+ ffgbyt(fptr, ntodo * twidth, buffer, status);
+ else
+ ffgbytoff(fptr, twidth, ntodo, incre - twidth, buffer,
+ status);
+
+ fffstri4((char *) buffer, ntodo, scale, zero, twidth, power,
+ nulcheck, snull, nulval, &nularray[next], anynul,
+ &array[next], status);
+ break;
+
+ default: /* error trap for invalid column format */
+ sprintf(message,
+ "Cannot read numbers from column %d which has format %s",
+ colnum, tform);
+ ffpmsg(message);
+ if (hdutype == ASCII_TBL)
+ return(*status = BAD_ATABLE_FORMAT);
+ else
+ return(*status = BAD_BTABLE_FORMAT);
+
+ } /* End of switch block */
+
+ /*-------------------------*/
+ /* Check for fatal error */
+ /*-------------------------*/
+ if (*status > 0) /* test for error during previous read operation */
+ {
+ if (hdutype > 0)
+ sprintf(message,
+ "Error reading elements %ld thru %ld from column %d (ffgclj).",
+ next+1, next+ntodo, colnum);
+ else
+ sprintf(message,
+ "Error reading elements %ld thru %ld from image (ffgclj).",
+ next+1, next+ntodo);
+
+ ffpmsg(message);
+ return(*status);
+ }
+
+ /*--------------------------------------------*/
+ /* increment the counters for the next loop */
+ /*--------------------------------------------*/
+ remain -= ntodo;
+ if (remain)
+ {
+ next += ntodo;
+ elemnum = elemnum + (ntodo * elemincre);
+
+ if (elemnum >= repeat) /* completed a row; start on later row */
+ {
+ rowincre = elemnum / repeat;
+ rownum += rowincre;
+ elemnum = elemnum - (rowincre * repeat);
+ }
+ else if (elemnum < 0) /* completed a row; start on a previous row */
+ {
+ rowincre = (-elemnum - 1) / repeat + 1;
+ rownum -= rowincre;
+ elemnum = (rowincre * repeat) + elemnum;
+ }
+ }
+ } /* End of main while Loop */
+
+
+ /*--------------------------------*/
+ /* check for numerical overflow */
+ /*--------------------------------*/
+ if (*status == OVERFLOW_ERR)
+ {
+ ffpmsg(
+ "Numerical overflow during type conversion while reading FITS data.");
+ *status = NUM_OVERFLOW;
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffi1i4(unsigned char *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ unsigned char tnull, /* I - value of FITS TNULLn keyword if any */
+ long nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ long *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to tnull. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = (long) input[ii]; /* copy input to output */
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONG_MIN;
+ }
+ else if (dvalue > DLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONG_MAX;
+ }
+ else
+ output[ii] = (long) dvalue;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ output[ii] = (long) input[ii];
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONG_MIN;
+ }
+ else if (dvalue > DLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONG_MAX;
+ }
+ else
+ output[ii] = (long) dvalue;
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffi2i4(short *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ short tnull, /* I - value of FITS TNULLn keyword if any */
+ long nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ long *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to tnull. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = (long) input[ii]; /* copy input to output */
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONG_MIN;
+ }
+ else if (dvalue > DLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONG_MAX;
+ }
+ else
+ output[ii] = (long) dvalue;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ output[ii] = (long) input[ii];
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONG_MIN;
+ }
+ else if (dvalue > DLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONG_MAX;
+ }
+ else
+ output[ii] = (long) dvalue;
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffi4i4(INT32BIT *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ INT32BIT tnull, /* I - value of FITS TNULLn keyword if any */
+ long nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ long *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to tnull. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+
+ Process the array of data in reverse order, to handle the case where
+ the input data is 4-bytes and the output is 8-bytes and the conversion
+ is being done in place in the same array.
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = ntodo - 1; ii >= 0; ii--)
+ output[ii] = (long) input[ii]; /* copy input to output */
+ }
+ else /* must scale the data */
+ {
+ for (ii = ntodo - 1; ii >= 0; ii--)
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONG_MIN;
+ }
+ else if (dvalue > DLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONG_MAX;
+ }
+ else
+ output[ii] = (long) dvalue;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = ntodo - 1; ii >= 0; ii--)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ output[ii] = input[ii];
+
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = ntodo - 1; ii >= 0; ii--)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONG_MIN;
+ }
+ else if (dvalue > DLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONG_MAX;
+ }
+ else
+ output[ii] = (long) dvalue;
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffi8i4(LONGLONG *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ long tnull, /* I - value of FITS TNULLn keyword if any */
+ long nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ long *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to tnull. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+#if (LONGSIZE == 32) && (! defined HAVE_LONGLONG)
+
+ /* This block of code is only used in cases where there is */
+ /* no native 8-byte integer support. We have to interpret */
+ /* the corresponding pair of 4-byte integers which are */
+ /* are equivalent to the 8-byte integer. */
+
+ long ii,jj,kk;
+ double dvalue;
+ unsigned long *uinput;
+
+ uinput = (unsigned long *) input;
+
+#if BYTESWAPPED /* jj points to the most significant part of the 8-byte int */
+ jj = 1;
+ kk = 0;
+#else
+ jj = 0;
+ kk = 1;
+#endif
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++, jj += 2, kk += 2)
+ {
+ if (uinput[jj] & 0x80000000) /* negative number */
+ dvalue = (uinput[jj] ^ 0xffffffff) * -4294967296. -
+ (uinput[kk] ^ 0xffffffff) - 1.;
+ else /* positive number */
+ dvalue = uinput[jj] * 4294967296. + uinput[kk];
+
+ if (dvalue < DLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONG_MIN;
+ }
+ else if (dvalue > DLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONG_MAX;
+ }
+ else
+ output[ii] = (long) dvalue;
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++, jj += 2, kk += 2)
+ {
+ if (uinput[jj] & 0x80000000) /* negative number */
+ dvalue = ((uinput[jj] ^ 0xffffffff) * -4294967296. -
+ (uinput[kk] ^ 0xffffffff) - 1.) * scale + zero;
+ else /* positive number */
+ dvalue = (uinput[jj] * 4294967296. + uinput[kk])
+ * scale + zero;
+
+ if (dvalue < DLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONG_MIN;
+ }
+ else if (dvalue > DLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONG_MAX;
+ }
+ else
+ output[ii] = (long) dvalue;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++, jj += 2, kk += 2)
+ {
+ if (uinput[jj] & 0x80000000) /* negative number */
+ dvalue = (uinput[jj] ^ 0xffffffff) * -4294967296. -
+ (uinput[kk] ^ 0xffffffff) - 1.;
+ else /* positive number */
+ dvalue = uinput[jj] * 4294967296. + uinput[kk];
+
+ if (dvalue == (double) tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ if (dvalue < DLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONG_MIN;
+ }
+ else if (dvalue > DLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONG_MAX;
+ }
+ else
+ output[ii] = (long) dvalue;
+ }
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++, jj += 2, kk += 2)
+ {
+ if (uinput[jj] & 0x80000000) /* negative number */
+ dvalue = (uinput[jj] ^ 0xffffffff) * -4294967296. -
+ (uinput[kk] ^ 0xffffffff) - 1.;
+ else /* positive number */
+ dvalue = uinput[jj] * 4294967296. + uinput[kk];
+
+ if (dvalue == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ dvalue = dvalue * scale + zero;
+
+ if (dvalue < DLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONG_MIN;
+ }
+ else if (dvalue > DLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONG_MAX;
+ }
+ else
+ output[ii] = (long) dvalue;
+ }
+ }
+ }
+ }
+
+#else
+
+ /* this block works on machines which support an 8-byte integer type */
+
+ long ii;
+ double dvalue;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] < LONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONG_MIN;
+ }
+ else if (input[ii] > LONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONG_MAX;
+ }
+ else
+ output[ii] = (long) input[ii];
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONG_MIN;
+ }
+ else if (dvalue > DLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONG_MAX;
+ }
+ else
+ output[ii] = (long) dvalue;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ if (input[ii] < LONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONG_MIN;
+ }
+ else if (input[ii] > LONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONG_MAX;
+ }
+ else
+ output[ii] = (long) input[ii];
+ }
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONG_MIN;
+ }
+ else if (dvalue > DLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONG_MAX;
+ }
+ else
+ output[ii] = (long) dvalue;
+ }
+ }
+ }
+ }
+
+#endif
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffr4i4(float *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ long nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ long *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to NaN. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ long ii;
+ double dvalue;
+ short *sptr, iret;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] < DLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONG_MIN;
+ }
+ else if (input[ii] > DLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONG_MAX;
+ }
+ else
+ output[ii] = (long) input[ii];
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONG_MIN;
+ }
+ else if (dvalue > DLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONG_MAX;
+ }
+ else
+ output[ii] = (long) dvalue;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ sptr = (short *) input;
+
+#if BYTESWAPPED && MACHINE != VAXVMS && MACHINE != ALPHAVMS
+ sptr++; /* point to MSBs */
+#endif
+
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++, sptr += 2)
+ {
+ if (0 != (iret = fnan(*sptr) ) ) /* test for NaN or underflow */
+ {
+ if (iret == 1) /* is it a NaN? */
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else /* it's an underflow */
+ output[ii] = 0;
+ }
+ else
+ {
+ if (input[ii] < DLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONG_MIN;
+ }
+ else if (input[ii] > DLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONG_MAX;
+ }
+ else
+ output[ii] = (long) input[ii];
+ }
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++, sptr += 2)
+ {
+ if (0 != (iret = fnan(*sptr) ) ) /* test for NaN or underflow */
+ {
+ if (iret == 1) /* is it a NaN? */
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else /* it's an underflow */
+ {
+ if (zero < DLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONG_MIN;
+ }
+ else if (zero > DLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONG_MAX;
+ }
+ else
+ output[ii] = (long) zero;
+ }
+ }
+ else
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONG_MIN;
+ }
+ else if (dvalue > DLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONG_MAX;
+ }
+ else
+ output[ii] = (long) dvalue;
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffr8i4(double *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ long nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ long *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to NaN. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ long ii;
+ double dvalue;
+ short *sptr, iret;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] < DLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONG_MIN;
+ }
+ else if (input[ii] > DLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONG_MAX;
+ }
+ else
+ output[ii] = (long) input[ii];
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONG_MIN;
+ }
+ else if (dvalue > DLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONG_MAX;
+ }
+ else
+ output[ii] = (long) dvalue;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ sptr = (short *) input;
+
+#if BYTESWAPPED && MACHINE != VAXVMS && MACHINE != ALPHAVMS
+ sptr += 3; /* point to MSBs */
+#endif
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++, sptr += 4)
+ {
+ if (0 != (iret = dnan(*sptr)) ) /* test for NaN or underflow */
+ {
+ if (iret == 1) /* is it a NaN? */
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else /* it's an underflow */
+ output[ii] = 0;
+ }
+ else
+ {
+ if (input[ii] < DLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONG_MIN;
+ }
+ else if (input[ii] > DLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONG_MAX;
+ }
+ else
+ output[ii] = (long) input[ii];
+ }
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++, sptr += 4)
+ {
+ if (0 != (iret = dnan(*sptr)) ) /* test for NaN or underflow */
+ {
+ if (iret == 1) /* is it a NaN? */
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else /* it's an underflow */
+ {
+ if (zero < DLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONG_MIN;
+ }
+ else if (zero > DLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONG_MAX;
+ }
+ else
+ output[ii] = (long) zero;
+ }
+ }
+ else
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONG_MIN;
+ }
+ else if (dvalue > DLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONG_MAX;
+ }
+ else
+ output[ii] = (long) dvalue;
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffstri4(char *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ long twidth, /* I - width of each substring of chars */
+ double implipower, /* I - power of 10 of implied decimal */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ char *snull, /* I - value of FITS null string, if any */
+ long nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ long *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file. Check
+ for null values and do scaling if required. The nullcheck code value
+ determines how any null values in the input array are treated. A null
+ value is an input pixel that is equal to snull. If nullcheck= 0, then
+ no special checking for nulls is performed. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ int nullen;
+ long ii;
+ double dvalue;
+ char *cstring, message[81];
+ char *cptr, *tpos;
+ char tempstore, chrzero = '0';
+ double val, power;
+ int exponent, sign, esign, decpt;
+
+ nullen = strlen(snull);
+ cptr = input; /* pointer to start of input string */
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ cstring = cptr;
+ /* temporarily insert a null terminator at end of the string */
+ tpos = cptr + twidth;
+ tempstore = *tpos;
+ *tpos = 0;
+
+ /* check if null value is defined, and if the */
+ /* column string is identical to the null string */
+ if (snull[0] != ASCII_NULL_UNDEFINED &&
+ !strncmp(snull, cptr, nullen) )
+ {
+ if (nullcheck)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ cptr += twidth;
+ }
+ else
+ {
+ /* value is not the null value, so decode it */
+ /* remove any embedded blank characters from the string */
+
+ decpt = 0;
+ sign = 1;
+ val = 0.;
+ power = 1.;
+ exponent = 0;
+ esign = 1;
+
+ while (*cptr == ' ') /* skip leading blanks */
+ cptr++;
+
+ if (*cptr == '-' || *cptr == '+') /* check for leading sign */
+ {
+ if (*cptr == '-')
+ sign = -1;
+
+ cptr++;
+
+ while (*cptr == ' ') /* skip blanks between sign and value */
+ cptr++;
+ }
+
+ while (*cptr >= '0' && *cptr <= '9')
+ {
+ val = val * 10. + *cptr - chrzero; /* accumulate the value */
+ cptr++;
+
+ while (*cptr == ' ') /* skip embedded blanks in the value */
+ cptr++;
+ }
+
+ if (*cptr == '.') /* check for decimal point */
+ {
+ decpt = 1; /* set flag to show there was a decimal point */
+ cptr++;
+ while (*cptr == ' ') /* skip any blanks */
+ cptr++;
+
+ while (*cptr >= '0' && *cptr <= '9')
+ {
+ val = val * 10. + *cptr - chrzero; /* accumulate the value */
+ power = power * 10.;
+ cptr++;
+
+ while (*cptr == ' ') /* skip embedded blanks in the value */
+ cptr++;
+ }
+ }
+
+ if (*cptr == 'E' || *cptr == 'D') /* check for exponent */
+ {
+ cptr++;
+ while (*cptr == ' ') /* skip blanks */
+ cptr++;
+
+ if (*cptr == '-' || *cptr == '+') /* check for exponent sign */
+ {
+ if (*cptr == '-')
+ esign = -1;
+
+ cptr++;
+
+ while (*cptr == ' ') /* skip blanks between sign and exp */
+ cptr++;
+ }
+
+ while (*cptr >= '0' && *cptr <= '9')
+ {
+ exponent = exponent * 10 + *cptr - chrzero; /* accumulate exp */
+ cptr++;
+
+ while (*cptr == ' ') /* skip embedded blanks */
+ cptr++;
+ }
+ }
+
+ if (*cptr != 0) /* should end up at the null terminator */
+ {
+ sprintf(message, "Cannot read number from ASCII table");
+ ffpmsg(message);
+ sprintf(message, "Column field = %s.", cstring);
+ ffpmsg(message);
+ /* restore the char that was overwritten by the null */
+ *tpos = tempstore;
+ return(*status = BAD_C2D);
+ }
+
+ if (!decpt) /* if no explicit decimal, use implied */
+ power = implipower;
+
+ dvalue = (sign * val / power) * pow(10., (double) (esign * exponent));
+
+ dvalue = dvalue * scale + zero; /* apply the scaling */
+
+ if (dvalue < DLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONG_MIN;
+ }
+ else if (dvalue > DLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONG_MAX;
+ }
+ else
+ output[ii] = (long) dvalue;
+ }
+ /* restore the char that was overwritten by the null */
+ *tpos = tempstore;
+ }
+ return(*status);
+}
+
+/* ======================================================================== */
+/* the following routines support the 'long long' data type */
+/* ======================================================================== */
+
+/*--------------------------------------------------------------------------*/
+int ffgpvjj(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to read (1 = 1st group) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ LONGLONG nulval, /* I - value for undefined pixels */
+ LONGLONG *array, /* O - array of values that are returned */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being read).
+ Undefined elements will be set equal to NULVAL, unless NULVAL=0
+ in which case no checking for undefined values will be performed.
+ ANYNUL is returned with a value of .true. if any pixels are undefined.
+*/
+{
+ long row;
+ char cdummy;
+ int nullcheck = 1;
+ LONGLONG nullvalue;
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+ nullvalue = nulval; /* set local variable */
+
+ fits_read_compressed_pixels(fptr, TLONGLONG, firstelem, nelem,
+ nullcheck, &nullvalue, array, NULL, anynul, status);
+ return(*status);
+ }
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ row=maxvalue(1,group);
+
+ ffgcljj(fptr, 2, row, firstelem, nelem, 1, 1, nulval,
+ array, &cdummy, anynul, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgpfjj(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to read (1 = 1st group) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ LONGLONG *array, /* O - array of values that are returned */
+ char *nularray, /* O - array of null pixel flags */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being read).
+ Any undefined pixels in the returned array will be set = 0 and the
+ corresponding nularray value will be set = 1.
+ ANYNUL is returned with a value of .true. if any pixels are undefined.
+*/
+{
+ long row;
+ int nullcheck = 2;
+ LONGLONG dummy = 0;
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ fits_read_compressed_pixels(fptr, TLONGLONG, firstelem, nelem,
+ nullcheck, NULL, array, nularray, anynul, status);
+ return(*status);
+ }
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ row=maxvalue(1,group);
+
+ ffgcljj(fptr, 2, row, firstelem, nelem, 1, 2, dummy,
+ array, nularray, anynul, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffg2djj(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to read (1 = 1st group) */
+ LONGLONG nulval ,/* set undefined pixels equal to this */
+ long ncols, /* I - number of pixels in each row of array */
+ long naxis1, /* I - FITS image NAXIS1 value */
+ long naxis2, /* I - FITS image NAXIS2 value */
+ LONGLONG *array,/* O - array to be filled and returned */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an entire 2-D array of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of the
+ FITS array is not the same as the array being read). Any null
+ values in the array will be set equal to the value of nulval, unless
+ nulval = 0 in which case no null checking will be performed.
+*/
+{
+ /* call the 3D reading routine, with the 3rd dimension = 1 */
+
+ ffg3djj(fptr, group, nulval, ncols, naxis2, naxis1, naxis2, 1, array,
+ anynul, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffg3djj(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to read (1 = 1st group) */
+ LONGLONG nulval, /* set undefined pixels equal to this */
+ long ncols, /* I - number of pixels in each row of array */
+ long nrows, /* I - number of rows in each plane of array */
+ long naxis1, /* I - FITS image NAXIS1 value */
+ long naxis2, /* I - FITS image NAXIS2 value */
+ long naxis3, /* I - FITS image NAXIS3 value */
+ LONGLONG *array,/* O - array to be filled and returned */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an entire 3-D array of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of the
+ FITS array is not the same as the array being read). Any null
+ values in the array will be set equal to the value of nulval, unless
+ nulval = 0 in which case no null checking will be performed.
+*/
+{
+ long tablerow, nfits, narray, ii, jj;
+ char cdummy;
+ int nullcheck = 1;
+ long inc[] = {1,1,1};
+ long fpixel[] = {1,1,1};
+ long lpixel[3];
+ LONGLONG nullvalue;
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ lpixel[0] = ncols;
+ lpixel[1] = nrows;
+ lpixel[2] = naxis3;
+ nullvalue = nulval; /* set local variable */
+
+ fits_read_compressed_img(fptr, TLONGLONG, fpixel, lpixel, inc,
+ nullcheck, &nullvalue, array, NULL, anynul, status);
+ return(*status);
+ }
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+ tablerow=maxvalue(1,group);
+
+ if (ncols == naxis1 && nrows == naxis2) /* arrays have same size? */
+ {
+ /* all the image pixels are contiguous, so read all at once */
+ ffgcljj(fptr, 2, tablerow, 1, naxis1 * naxis2 * naxis3, 1, 1, nulval,
+ array, &cdummy, anynul, status);
+ return(*status);
+ }
+
+ if (ncols < naxis1 || nrows < naxis2)
+ return(*status = BAD_DIMEN);
+
+ nfits = 1; /* next pixel in FITS image to read */
+ narray = 0; /* next pixel in output array to be filled */
+
+ /* loop over naxis3 planes in the data cube */
+ for (jj = 0; jj < naxis3; jj++)
+ {
+ /* loop over the naxis2 rows in the FITS image, */
+ /* reading naxis1 pixels to each row */
+
+ for (ii = 0; ii < naxis2; ii++)
+ {
+ if (ffgcljj(fptr, 2, tablerow, nfits, naxis1, 1, 1, nulval,
+ &array[narray], &cdummy, anynul, status) > 0)
+ return(*status);
+
+ nfits += naxis1;
+ narray += ncols;
+ }
+ narray += (nrows - naxis2) * ncols;
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgsvjj(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of the column to read (1 = 1st) */
+ int naxis, /* I - number of dimensions in the FITS array */
+ long *naxes, /* I - size of each dimension */
+ long *blc, /* I - 'bottom left corner' of the subsection */
+ long *trc, /* I - 'top right corner' of the subsection */
+ long *inc, /* I - increment to be applied in each dimension */
+ LONGLONG nulval,/* I - value to set undefined pixels */
+ LONGLONG *array,/* O - array to be filled and returned */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read a subsection of data values from an image or a table column.
+ This routine is set up to handle a maximum of nine dimensions.
+*/
+{
+ long ii,i0, i1,i2,i3,i4,i5,i6,i7,i8,row,rstr,rstp,rinc;
+ long str[9],stp[9],incr[9],dir[9];
+ long nelem, nultyp, ninc, numcol;
+ OFF_T felem, dsize[10];
+ int hdutype, anyf;
+ char ldummy, msg[FLEN_ERRMSG];
+ int nullcheck = 1;
+ LONGLONG nullvalue;
+
+ if (naxis < 1 || naxis > 9)
+ {
+ sprintf(msg, "NAXIS = %d in call to ffgsvj is out of range", naxis);
+ ffpmsg(msg);
+ return(*status = BAD_DIMEN);
+ }
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ nullvalue = nulval; /* set local variable */
+
+ fits_read_compressed_img(fptr, TLONGLONG, blc, trc, inc,
+ nullcheck, &nullvalue, array, NULL, anynul, status);
+ return(*status);
+ }
+
+/*
+ if this is a primary array, then the input COLNUM parameter should
+ be interpreted as the row number, and we will alway read the image
+ data from column 2 (any group parameters are in column 1).
+*/
+ if (ffghdt(fptr, &hdutype, status) > 0)
+ return(*status);
+
+ if (hdutype == IMAGE_HDU)
+ {
+ /* this is a primary array, or image extension */
+ if (colnum == 0)
+ {
+ rstr = 1;
+ rstp = 1;
+ }
+ else
+ {
+ rstr = colnum;
+ rstp = colnum;
+ }
+ rinc = 1;
+ numcol = 2;
+ }
+ else
+ {
+ /* this is a table, so the row info is in the (naxis+1) elements */
+ rstr = blc[naxis];
+ rstp = trc[naxis];
+ rinc = inc[naxis];
+ numcol = colnum;
+ }
+
+ nultyp = 1;
+ if (anynul)
+ *anynul = FALSE;
+
+ i0 = 0;
+ for (ii = 0; ii < 9; ii++)
+ {
+ str[ii] = 1;
+ stp[ii] = 1;
+ incr[ii] = 1;
+ dsize[ii] = 1;
+ dir[ii] = 1;
+ }
+
+ for (ii = 0; ii < naxis; ii++)
+ {
+ if (trc[ii] < blc[ii])
+ {
+ if (hdutype == IMAGE_HDU)
+ {
+ dir[ii] = -1;
+ }
+ else
+ {
+ sprintf(msg, "ffgsvj: illegal range specified for axis %ld", ii + 1);
+ ffpmsg(msg);
+ return(*status = BAD_PIX_NUM);
+ }
+ }
+
+ str[ii] = blc[ii];
+ stp[ii] = trc[ii];
+ incr[ii] = inc[ii];
+ dsize[ii + 1] = dsize[ii] * naxes[ii];
+ dsize[ii] = dsize[ii] * dir[ii];
+ }
+ dsize[naxis] = dsize[naxis] * dir[naxis];
+
+ if (naxis == 1 && naxes[0] == 1)
+ {
+ /* This is not a vector column, so read all the rows at once */
+ nelem = (rstp - rstr) / rinc + 1;
+ ninc = rinc;
+ rstp = rstr;
+ }
+ else
+ {
+ /* have to read each row individually, in all dimensions */
+ nelem = (stp[0]*dir[0] - str[0]*dir[0]) / inc[0] + 1;
+ ninc = incr[0] * dir[0];
+ }
+
+ for (row = rstr; row <= rstp; row += rinc)
+ {
+ for (i8 = str[8]*dir[8]; i8 <= stp[8]*dir[8]; i8 += incr[8])
+ {
+ for (i7 = str[7]*dir[7]; i7 <= stp[7]*dir[7]; i7 += incr[7])
+ {
+ for (i6 = str[6]*dir[6]; i6 <= stp[6]*dir[6]; i6 += incr[6])
+ {
+ for (i5 = str[5]*dir[5]; i5 <= stp[5]*dir[5]; i5 += incr[5])
+ {
+ for (i4 = str[4]*dir[4]; i4 <= stp[4]*dir[4]; i4 += incr[4])
+ {
+ for (i3 = str[3]*dir[3]; i3 <= stp[3]*dir[3]; i3 += incr[3])
+ {
+ for (i2 = str[2]*dir[2]; i2 <= stp[2]*dir[2]; i2 += incr[2])
+ {
+ for (i1 = str[1]*dir[1]; i1 <= stp[1]*dir[1]; i1 += incr[1])
+ {
+
+ felem=str[0] + (i1 - dir[1]) * dsize[1] + (i2 - dir[2]) * dsize[2] +
+ (i3 - dir[3]) * dsize[3] + (i4 - dir[4]) * dsize[4] +
+ (i5 - dir[5]) * dsize[5] + (i6 - dir[6]) * dsize[6] +
+ (i7 - dir[7]) * dsize[7] + (i8 - dir[8]) * dsize[8];
+
+ if ( ffgcljj(fptr, numcol, row, felem, nelem, ninc, nultyp,
+ nulval, &array[i0], &ldummy, &anyf, status) > 0)
+ return(*status);
+
+ if (anyf && anynul)
+ *anynul = TRUE;
+
+ i0 += nelem;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgsfjj(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of the column to read (1 = 1st) */
+ int naxis, /* I - number of dimensions in the FITS array */
+ long *naxes, /* I - size of each dimension */
+ long *blc, /* I - 'bottom left corner' of the subsection */
+ long *trc, /* I - 'top right corner' of the subsection */
+ long *inc, /* I - increment to be applied in each dimension */
+ LONGLONG *array,/* O - array to be filled and returned */
+ char *flagval, /* O - set to 1 if corresponding value is null */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read a subsection of data values from an image or a table column.
+ This routine is set up to handle a maximum of nine dimensions.
+*/
+{
+ long ii,i0, i1,i2,i3,i4,i5,i6,i7,i8,row,rstr,rstp,rinc;
+ long str[9],stp[9],incr[9],dsize[10];
+ long felem, nelem, nultyp, ninc, numcol;
+ LONGLONG nulval = 0;
+ int hdutype, anyf;
+ char msg[FLEN_ERRMSG];
+ int nullcheck = 2;
+
+ if (naxis < 1 || naxis > 9)
+ {
+ sprintf(msg, "NAXIS = %d in call to ffgsvj is out of range", naxis);
+ ffpmsg(msg);
+ return(*status = BAD_DIMEN);
+ }
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ fits_read_compressed_img(fptr, TLONGLONG, blc, trc, inc,
+ nullcheck, NULL, array, flagval, anynul, status);
+ return(*status);
+ }
+
+/*
+ if this is a primary array, then the input COLNUM parameter should
+ be interpreted as the row number, and we will alway read the image
+ data from column 2 (any group parameters are in column 1).
+*/
+ if (ffghdt(fptr, &hdutype, status) > 0)
+ return(*status);
+
+ if (hdutype == IMAGE_HDU)
+ {
+ /* this is a primary array, or image extension */
+ if (colnum == 0)
+ {
+ rstr = 1;
+ rstp = 1;
+ }
+ else
+ {
+ rstr = colnum;
+ rstp = colnum;
+ }
+ rinc = 1;
+ numcol = 2;
+ }
+ else
+ {
+ /* this is a table, so the row info is in the (naxis+1) elements */
+ rstr = blc[naxis];
+ rstp = trc[naxis];
+ rinc = inc[naxis];
+ numcol = colnum;
+ }
+
+ nultyp = 2;
+ if (anynul)
+ *anynul = FALSE;
+
+ i0 = 0;
+ for (ii = 0; ii < 9; ii++)
+ {
+ str[ii] = 1;
+ stp[ii] = 1;
+ incr[ii] = 1;
+ dsize[ii] = 1;
+ }
+
+ for (ii = 0; ii < naxis; ii++)
+ {
+ if (trc[ii] < blc[ii])
+ {
+ sprintf(msg, "ffgsvj: illegal range specified for axis %ld", ii + 1);
+ ffpmsg(msg);
+ return(*status = BAD_PIX_NUM);
+ }
+
+ str[ii] = blc[ii];
+ stp[ii] = trc[ii];
+ incr[ii] = inc[ii];
+ dsize[ii + 1] = dsize[ii] * naxes[ii];
+ }
+
+ if (naxis == 1 && naxes[0] == 1)
+ {
+ /* This is not a vector column, so read all the rows at once */
+ nelem = (rstp - rstr) / rinc + 1;
+ ninc = rinc;
+ rstp = rstr;
+ }
+ else
+ {
+ /* have to read each row individually, in all dimensions */
+ nelem = (stp[0] - str[0]) / inc[0] + 1;
+ ninc = incr[0];
+ }
+
+ for (row = rstr; row <= rstp; row += rinc)
+ {
+ for (i8 = str[8]; i8 <= stp[8]; i8 += incr[8])
+ {
+ for (i7 = str[7]; i7 <= stp[7]; i7 += incr[7])
+ {
+ for (i6 = str[6]; i6 <= stp[6]; i6 += incr[6])
+ {
+ for (i5 = str[5]; i5 <= stp[5]; i5 += incr[5])
+ {
+ for (i4 = str[4]; i4 <= stp[4]; i4 += incr[4])
+ {
+ for (i3 = str[3]; i3 <= stp[3]; i3 += incr[3])
+ {
+ for (i2 = str[2]; i2 <= stp[2]; i2 += incr[2])
+ {
+ for (i1 = str[1]; i1 <= stp[1]; i1 += incr[1])
+ {
+ felem=str[0] + (i1 - 1) * dsize[1] + (i2 - 1) * dsize[2] +
+ (i3 - 1) * dsize[3] + (i4 - 1) * dsize[4] +
+ (i5 - 1) * dsize[5] + (i6 - 1) * dsize[6] +
+ (i7 - 1) * dsize[7] + (i8 - 1) * dsize[8];
+
+ if ( ffgcljj(fptr, numcol, row, felem, nelem, ninc, nultyp,
+ nulval, &array[i0], &flagval[i0], &anyf, status) > 0)
+ return(*status);
+
+ if (anyf && anynul)
+ *anynul = TRUE;
+
+ i0 += nelem;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffggpjj(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to read (1 = 1st group) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ LONGLONG *array, /* O - array of values that are returned */
+ int *status) /* IO - error status */
+/*
+ Read an array of group parameters from the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being read).
+*/
+{
+ long row;
+ int idummy;
+ char cdummy;
+ LONGLONG dummy = 0;
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ row=maxvalue(1,group);
+
+ ffgcljj(fptr, 1, row, firstelem, nelem, 1, 1, dummy,
+ array, &cdummy, &idummy, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgcvjj(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to read (1 = 1st col) */
+ long firstrow, /* I - first row to read (1 = 1st row) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ LONGLONG nulval, /* I - value for null pixels */
+ LONGLONG *array, /* O - array of values that are read */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from a column in the current FITS HDU. Automatic
+ datatype conversion will be performed if the datatype of the column does not
+ match the datatype of the array parameter. The output values will be scaled
+ by the FITS TSCALn and TZEROn values if these values have been defined.
+ Any undefined pixels will be set equal to the value of 'nulval' unless
+ nulval = 0 in which case no checks for undefined pixels will be made.
+*/
+{
+ char cdummy;
+
+ ffgcljj(fptr, colnum, firstrow, firstelem, nelem, 1, 1, nulval,
+ array, &cdummy, anynul, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgcfjj(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to read (1 = 1st col) */
+ long firstrow, /* I - first row to read (1 = 1st row) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ LONGLONG *array, /* O - array of values that are read */
+ char *nularray, /* O - array of flags: 1 if null pixel; else 0 */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from a column in the current FITS HDU. Automatic
+ datatype conversion will be performed if the datatype of the column does not
+ match the datatype of the array parameter. The output values will be scaled
+ by the FITS TSCALn and TZEROn values if these values have been defined.
+ Nularray will be set = 1 if the corresponding array pixel is undefined,
+ otherwise nularray will = 0.
+*/
+{
+ LONGLONG dummy = 0;
+
+ ffgcljj(fptr, colnum, firstrow, firstelem, nelem, 1, 2, dummy,
+ array, nularray, anynul, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgcljj( fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to read (1 = 1st col) */
+ long firstrow, /* I - first row to read (1 = 1st row) */
+ OFF_T firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ long elemincre, /* I - pixel increment; e.g., 2 = every other */
+ int nultyp, /* I - null value handling code: */
+ /* 1: set undefined pixels = nulval */
+ /* 2: set nularray=1 for undefined pixels */
+ LONGLONG nulval, /* I - value for null pixels if nultyp = 1 */
+ LONGLONG *array, /* O - array of values that are read */
+ char *nularray, /* O - array of flags = 1 if nultyp = 2 */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from a column in the current FITS HDU.
+ The column number may refer to a real column in an ASCII or binary table,
+ or it may refer be a virtual column in a 1 or more grouped FITS primary
+ array or image extension. FITSIO treats a primary array as a binary table
+ with 2 vector columns: the first column contains the group parameters (often
+ with length = 0) and the second column contains the array of image pixels.
+ Each row of the table represents a group in the case of multigroup FITS
+ images.
+
+ The output array of values will be converted from the datatype of the column
+ and will be scaled by the FITS TSCALn and TZEROn values if necessary.
+*/
+{
+ double scale, zero, power = 1.;
+ int tcode, maxelem, hdutype, xcode, decimals;
+ long twidth, incre, rownum, remain, next, ntodo;
+ long ii, rowincre, tnull, xwidth;
+ int convert, nulcheck, readcheck = 0;
+ OFF_T repeat, startpos, elemnum, readptr, rowlen;
+ char tform[20];
+ char message[81];
+ char snull[20]; /* the FITS null value if reading from ASCII table */
+
+ double cbuff[DBUFFSIZE / sizeof(double)]; /* align cbuff on word boundary */
+ void *buffer;
+
+ if (*status > 0 || nelem == 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ buffer = cbuff;
+
+ if (anynul)
+ *anynul = 0;
+
+ if (nultyp == 2)
+ memset(nularray, 0, nelem); /* initialize nullarray */
+
+ /*---------------------------------------------------*/
+ /* Check input and get parameters about the column: */
+ /*---------------------------------------------------*/
+ if (elemincre < 0)
+ readcheck = -1; /* don't do range checking in this case */
+
+ if (ffgcpr(fptr, colnum, firstrow, firstelem, nelem, readcheck, &scale, &zero,
+ tform, &twidth, &tcode, &maxelem, &startpos, &elemnum, &incre,
+ &repeat, &rowlen, &hdutype, &tnull, snull, status) > 0 )
+ return(*status);
+
+ incre *= elemincre; /* multiply incre to just get every nth pixel */
+
+ if (tcode == TSTRING) /* setup for ASCII tables */
+ {
+ /* get the number of implied decimal places if no explicit decmal point */
+ ffasfm(tform, &xcode, &xwidth, &decimals, status);
+ for(ii = 0; ii < decimals; ii++)
+ power *= 10.;
+ }
+ /*------------------------------------------------------------------*/
+ /* Decide whether to check for null values in the input FITS file: */
+ /*------------------------------------------------------------------*/
+ nulcheck = nultyp; /* by default check for null values in the FITS file */
+
+ if (nultyp == 1 && nulval == 0)
+ nulcheck = 0; /* calling routine does not want to check for nulls */
+
+ else if (tcode%10 == 1 && /* if reading an integer column, and */
+ tnull == NULL_UNDEFINED) /* if a null value is not defined, */
+ nulcheck = 0; /* then do not check for null values. */
+
+ else if (tcode == TSHORT && (tnull > SHRT_MAX || tnull < SHRT_MIN) )
+ nulcheck = 0; /* Impossible null value */
+
+ else if (tcode == TBYTE && (tnull > 255 || tnull < 0) )
+ nulcheck = 0; /* Impossible null value */
+
+ else if (tcode == TSTRING && snull[0] == ASCII_NULL_UNDEFINED)
+ nulcheck = 0;
+
+ /*----------------------------------------------------------------------*/
+ /* If FITS column and output data array have same datatype, then we do */
+ /* not need to use a temporary buffer to store intermediate datatype. */
+ /*----------------------------------------------------------------------*/
+ convert = 1;
+ if (tcode == TLONGLONG) /* Special Case: */
+ { /* no type convertion required, so read */
+ maxelem = nelem; /* data directly into output buffer. */
+
+ if (nulcheck == 0 && scale == 1. && zero == 0.)
+ convert = 0; /* no need to scale data or find nulls */
+ }
+
+ /*---------------------------------------------------------------------*/
+ /* Now read the pixels from the FITS column. If the column does not */
+ /* have the same datatype as the output array, then we have to read */
+ /* the raw values into a temporary buffer (of limited size). In */
+ /* the case of a vector colum read only 1 vector of values at a time */
+ /* then skip to the next row if more values need to be read. */
+ /* After reading the raw values, then call the fffXXYY routine to (1) */
+ /* test for undefined values, (2) convert the datatype if necessary, */
+ /* and (3) scale the values by the FITS TSCALn and TZEROn linear */
+ /* scaling parameters. */
+ /*---------------------------------------------------------------------*/
+ remain = nelem; /* remaining number of values to read */
+ next = 0; /* next element in array to be read */
+ rownum = 0; /* row number, relative to firstrow */
+
+ while (remain)
+ {
+ /* limit the number of pixels to read at one time to the number that
+ will fit in the buffer or to the number of pixels that remain in
+ the current vector, which ever is smaller.
+ */
+ ntodo = minvalue(remain, maxelem);
+ if (elemincre >= 0)
+ {
+ ntodo = minvalue(ntodo, ((repeat - elemnum - 1)/elemincre +1));
+ }
+ else
+ {
+ ntodo = minvalue(ntodo, (elemnum/(-elemincre) +1));
+ }
+
+ readptr = startpos + ((OFF_T)rownum * rowlen) + (elemnum * (incre / elemincre));
+
+ switch (tcode)
+ {
+ case (TLONGLONG):
+ ffgi8b(fptr, readptr, ntodo, incre, (long *) &array[next],
+ status);
+ if (convert)
+ fffi8i8((LONGLONG *) &array[next], ntodo, scale, zero,
+ nulcheck, (LONGLONG) tnull, nulval, &nularray[next],
+ anynul, &array[next], status);
+ break;
+ case (TLONG):
+ ffgi4b(fptr, readptr, ntodo, incre, (INT32BIT *) buffer,
+ status);
+ fffi4i8((INT32BIT *) buffer, ntodo, scale, zero,
+ nulcheck, (INT32BIT) tnull, nulval, &nularray[next],
+ anynul, &array[next], status);
+ break;
+ case (TBYTE):
+ ffgi1b(fptr, readptr, ntodo, incre, (unsigned char *) buffer,
+ status);
+ fffi1i8((unsigned char *) buffer, ntodo, scale, zero, nulcheck,
+ (unsigned char) tnull, nulval, &nularray[next], anynul,
+ &array[next], status);
+ break;
+ case (TSHORT):
+ ffgi2b(fptr, readptr, ntodo, incre, (short *) buffer, status);
+ fffi2i8((short *) buffer, ntodo, scale, zero, nulcheck,
+ (short) tnull, nulval, &nularray[next], anynul,
+ &array[next], status);
+ break;
+ case (TFLOAT):
+ ffgr4b(fptr, readptr, ntodo, incre, (float *) buffer, status);
+ fffr4i8((float *) buffer, ntodo, scale, zero, nulcheck,
+ nulval, &nularray[next], anynul,
+ &array[next], status);
+ break;
+ case (TDOUBLE):
+ ffgr8b(fptr, readptr, ntodo, incre, (double *) buffer, status);
+ fffr8i8((double *) buffer, ntodo, scale, zero, nulcheck,
+ nulval, &nularray[next], anynul,
+ &array[next], status);
+ break;
+ case (TSTRING):
+ ffmbyt(fptr, readptr, REPORT_EOF, status);
+
+ if (incre == twidth) /* contiguous bytes */
+ ffgbyt(fptr, ntodo * twidth, buffer, status);
+ else
+ ffgbytoff(fptr, twidth, ntodo, incre - twidth, buffer,
+ status);
+
+ fffstri8((char *) buffer, ntodo, scale, zero, twidth, power,
+ nulcheck, snull, nulval, &nularray[next], anynul,
+ &array[next], status);
+ break;
+
+ default: /* error trap for invalid column format */
+ sprintf(message,
+ "Cannot read numbers from column %d which has format %s",
+ colnum, tform);
+ ffpmsg(message);
+ if (hdutype == ASCII_TBL)
+ return(*status = BAD_ATABLE_FORMAT);
+ else
+ return(*status = BAD_BTABLE_FORMAT);
+
+ } /* End of switch block */
+
+ /*-------------------------*/
+ /* Check for fatal error */
+ /*-------------------------*/
+ if (*status > 0) /* test for error during previous read operation */
+ {
+ if (hdutype > 0)
+ sprintf(message,
+ "Error reading elements %ld thru %ld from column %d (ffgclj).",
+ next+1, next+ntodo, colnum);
+ else
+ sprintf(message,
+ "Error reading elements %ld thru %ld from image (ffgclj).",
+ next+1, next+ntodo);
+
+ ffpmsg(message);
+ return(*status);
+ }
+
+ /*--------------------------------------------*/
+ /* increment the counters for the next loop */
+ /*--------------------------------------------*/
+ remain -= ntodo;
+ if (remain)
+ {
+ next += ntodo;
+ elemnum = elemnum + (ntodo * elemincre);
+
+ if (elemnum >= repeat) /* completed a row; start on later row */
+ {
+ rowincre = elemnum / repeat;
+ rownum += rowincre;
+ elemnum = elemnum - (rowincre * repeat);
+ }
+ else if (elemnum < 0) /* completed a row; start on a previous row */
+ {
+ rowincre = (-elemnum - 1) / repeat + 1;
+ rownum -= rowincre;
+ elemnum = (rowincre * repeat) + elemnum;
+ }
+ }
+ } /* End of main while Loop */
+
+
+ /*--------------------------------*/
+ /* check for numerical overflow */
+ /*--------------------------------*/
+ if (*status == OVERFLOW_ERR)
+ {
+ ffpmsg(
+ "Numerical overflow during type conversion while reading FITS data.");
+ *status = NUM_OVERFLOW;
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffi1i8(unsigned char *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ unsigned char tnull, /* I - value of FITS TNULLn keyword if any */
+ LONGLONG nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ LONGLONG *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to tnull. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = (LONGLONG) input[ii]; /* copy input to output */
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DLONGLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONGLONG_MIN;
+ }
+ else if (dvalue > DLONGLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONGLONG_MAX;
+ }
+ else
+ output[ii] = (LONGLONG) dvalue;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ output[ii] = (LONGLONG) input[ii];
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DLONGLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONGLONG_MIN;
+ }
+ else if (dvalue > DLONGLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONGLONG_MAX;
+ }
+ else
+ output[ii] = (LONGLONG) dvalue;
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffi2i8(short *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ short tnull, /* I - value of FITS TNULLn keyword if any */
+ LONGLONG nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ LONGLONG *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to tnull. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = (LONGLONG) input[ii]; /* copy input to output */
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DLONGLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONGLONG_MIN;
+ }
+ else if (dvalue > DLONGLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONGLONG_MAX;
+ }
+ else
+ output[ii] = (LONGLONG) dvalue;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ output[ii] = (LONGLONG) input[ii];
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DLONGLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONGLONG_MIN;
+ }
+ else if (dvalue > DLONGLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONGLONG_MAX;
+ }
+ else
+ output[ii] = (LONGLONG) dvalue;
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffi4i8(INT32BIT *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ INT32BIT tnull, /* I - value of FITS TNULLn keyword if any */
+ LONGLONG nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ LONGLONG *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to tnull. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = (LONGLONG) input[ii]; /* copy input to output */
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DLONGLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONGLONG_MIN;
+ }
+ else if (dvalue > DLONGLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONGLONG_MAX;
+ }
+ else
+ output[ii] = (LONGLONG) dvalue;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ output[ii] = (LONGLONG) input[ii];
+
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DLONGLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONGLONG_MIN;
+ }
+ else if (dvalue > DLONGLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONGLONG_MAX;
+ }
+ else
+ output[ii] = (LONGLONG) dvalue;
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffi8i8(LONGLONG *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ LONGLONG tnull, /* I - value of FITS TNULLn keyword if any */
+ LONGLONG nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ LONGLONG *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to tnull. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = input[ii]; /* copy input to output */
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DLONGLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONGLONG_MIN;
+ }
+ else if (dvalue > DLONGLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONGLONG_MAX;
+ }
+ else
+ output[ii] = (LONGLONG) dvalue;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ output[ii] = input[ii];
+
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DLONGLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONGLONG_MIN;
+ }
+ else if (dvalue > DLONGLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONGLONG_MAX;
+ }
+ else
+ output[ii] = (LONGLONG) dvalue;
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffr4i8(float *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ LONGLONG nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ LONGLONG *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to NaN. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ long ii;
+ double dvalue;
+ short *sptr, iret;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] < DLONGLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONGLONG_MIN;
+ }
+ else if (input[ii] > DLONGLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONGLONG_MAX;
+ }
+ else
+ output[ii] = (LONGLONG) input[ii];
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DLONGLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONGLONG_MIN;
+ }
+ else if (dvalue > DLONGLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONGLONG_MAX;
+ }
+ else
+ output[ii] = (LONGLONG) dvalue;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ sptr = (short *) input;
+
+#if BYTESWAPPED && MACHINE != VAXVMS && MACHINE != ALPHAVMS
+ sptr++; /* point to MSBs */
+#endif
+
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++, sptr += 2)
+ {
+ if (0 != (iret = fnan(*sptr) ) ) /* test for NaN or underflow */
+ {
+ if (iret == 1) /* is it a NaN? */
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else /* it's an underflow */
+ output[ii] = 0;
+ }
+ else
+ {
+ if (input[ii] < DLONGLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONGLONG_MIN;
+ }
+ else if (input[ii] > DLONGLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONGLONG_MAX;
+ }
+ else
+ output[ii] = (LONGLONG) input[ii];
+ }
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++, sptr += 2)
+ {
+ if (0 != (iret = fnan(*sptr) ) ) /* test for NaN or underflow */
+ {
+ if (iret == 1) /* is it a NaN? */
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else /* it's an underflow */
+ {
+ if (zero < DLONGLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONGLONG_MIN;
+ }
+ else if (zero > DLONGLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONGLONG_MAX;
+ }
+ else
+ output[ii] = (LONGLONG) zero;
+ }
+ }
+ else
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DLONGLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONGLONG_MIN;
+ }
+ else if (dvalue > DLONGLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONGLONG_MAX;
+ }
+ else
+ output[ii] = (LONGLONG) dvalue;
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffr8i8(double *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ LONGLONG nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ LONGLONG *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to NaN. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ long ii;
+ double dvalue;
+ short *sptr, iret;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] < DLONGLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONGLONG_MIN;
+ }
+ else if (input[ii] > DLONGLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONGLONG_MAX;
+ }
+ else
+ output[ii] = (LONGLONG) input[ii];
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DLONGLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONGLONG_MIN;
+ }
+ else if (dvalue > DLONGLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONGLONG_MAX;
+ }
+ else
+ output[ii] = (LONGLONG) dvalue;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ sptr = (short *) input;
+
+#if BYTESWAPPED && MACHINE != VAXVMS && MACHINE != ALPHAVMS
+ sptr += 3; /* point to MSBs */
+#endif
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++, sptr += 4)
+ {
+ if (0 != (iret = dnan(*sptr)) ) /* test for NaN or underflow */
+ {
+ if (iret == 1) /* is it a NaN? */
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else /* it's an underflow */
+ output[ii] = 0;
+ }
+ else
+ {
+ if (input[ii] < DLONGLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONGLONG_MIN;
+ }
+ else if (input[ii] > DLONGLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONGLONG_MAX;
+ }
+ else
+ output[ii] = (LONGLONG) input[ii];
+ }
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++, sptr += 4)
+ {
+ if (0 != (iret = dnan(*sptr)) ) /* test for NaN or underflow */
+ {
+ if (iret == 1) /* is it a NaN? */
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else /* it's an underflow */
+ {
+ if (zero < DLONGLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONGLONG_MIN;
+ }
+ else if (zero > DLONGLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONGLONG_MAX;
+ }
+ else
+ output[ii] = (LONGLONG) zero;
+ }
+ }
+ else
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DLONGLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONGLONG_MIN;
+ }
+ else if (dvalue > DLONGLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONGLONG_MAX;
+ }
+ else
+ output[ii] = (LONGLONG) dvalue;
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffstri8(char *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ long twidth, /* I - width of each substring of chars */
+ double implipower, /* I - power of 10 of implied decimal */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ char *snull, /* I - value of FITS null string, if any */
+ LONGLONG nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ LONGLONG *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file. Check
+ for null values and do scaling if required. The nullcheck code value
+ determines how any null values in the input array are treated. A null
+ value is an input pixel that is equal to snull. If nullcheck= 0, then
+ no special checking for nulls is performed. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ int nullen;
+ long ii;
+ double dvalue;
+ char *cstring, message[81];
+ char *cptr, *tpos;
+ char tempstore, chrzero = '0';
+ double val, power;
+ int exponent, sign, esign, decpt;
+
+ nullen = strlen(snull);
+ cptr = input; /* pointer to start of input string */
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ cstring = cptr;
+ /* temporarily insert a null terminator at end of the string */
+ tpos = cptr + twidth;
+ tempstore = *tpos;
+ *tpos = 0;
+
+ /* check if null value is defined, and if the */
+ /* column string is identical to the null string */
+ if (snull[0] != ASCII_NULL_UNDEFINED &&
+ !strncmp(snull, cptr, nullen) )
+ {
+ if (nullcheck)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ cptr += twidth;
+ }
+ else
+ {
+ /* value is not the null value, so decode it */
+ /* remove any embedded blank characters from the string */
+
+ decpt = 0;
+ sign = 1;
+ val = 0.;
+ power = 1.;
+ exponent = 0;
+ esign = 1;
+
+ while (*cptr == ' ') /* skip leading blanks */
+ cptr++;
+
+ if (*cptr == '-' || *cptr == '+') /* check for leading sign */
+ {
+ if (*cptr == '-')
+ sign = -1;
+
+ cptr++;
+
+ while (*cptr == ' ') /* skip blanks between sign and value */
+ cptr++;
+ }
+
+ while (*cptr >= '0' && *cptr <= '9')
+ {
+ val = val * 10. + *cptr - chrzero; /* accumulate the value */
+ cptr++;
+
+ while (*cptr == ' ') /* skip embedded blanks in the value */
+ cptr++;
+ }
+
+ if (*cptr == '.') /* check for decimal point */
+ {
+ decpt = 1; /* set flag to show there was a decimal point */
+ cptr++;
+ while (*cptr == ' ') /* skip any blanks */
+ cptr++;
+
+ while (*cptr >= '0' && *cptr <= '9')
+ {
+ val = val * 10. + *cptr - chrzero; /* accumulate the value */
+ power = power * 10.;
+ cptr++;
+
+ while (*cptr == ' ') /* skip embedded blanks in the value */
+ cptr++;
+ }
+ }
+
+ if (*cptr == 'E' || *cptr == 'D') /* check for exponent */
+ {
+ cptr++;
+ while (*cptr == ' ') /* skip blanks */
+ cptr++;
+
+ if (*cptr == '-' || *cptr == '+') /* check for exponent sign */
+ {
+ if (*cptr == '-')
+ esign = -1;
+
+ cptr++;
+
+ while (*cptr == ' ') /* skip blanks between sign and exp */
+ cptr++;
+ }
+
+ while (*cptr >= '0' && *cptr <= '9')
+ {
+ exponent = exponent * 10 + *cptr - chrzero; /* accumulate exp */
+ cptr++;
+
+ while (*cptr == ' ') /* skip embedded blanks */
+ cptr++;
+ }
+ }
+
+ if (*cptr != 0) /* should end up at the null terminator */
+ {
+ sprintf(message, "Cannot read number from ASCII table");
+ ffpmsg(message);
+ sprintf(message, "Column field = %s.", cstring);
+ ffpmsg(message);
+ /* restore the char that was overwritten by the null */
+ *tpos = tempstore;
+ return(*status = BAD_C2D);
+ }
+
+ if (!decpt) /* if no explicit decimal, use implied */
+ power = implipower;
+
+ dvalue = (sign * val / power) * pow(10., (double) (esign * exponent));
+
+ dvalue = dvalue * scale + zero; /* apply the scaling */
+
+ if (dvalue < DLONGLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONGLONG_MIN;
+ }
+ else if (dvalue > DLONGLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONGLONG_MAX;
+ }
+ else
+ output[ii] = (LONGLONG) dvalue;
+ }
+ /* restore the char that was overwritten by the null */
+ *tpos = tempstore;
+ }
+ return(*status);
+}
diff --git a/pkg/tbtables/cfitsio/getcolk.c b/pkg/tbtables/cfitsio/getcolk.c
new file mode 100644
index 00000000..f9a72d69
--- /dev/null
+++ b/pkg/tbtables/cfitsio/getcolk.c
@@ -0,0 +1,2037 @@
+/* This file, getcolk.c, contains routines that read data elements from */
+/* a FITS image or table, with 'int' data type. */
+
+/* The FITSIO software was written by William Pence at the High Energy */
+/* Astrophysic Science Archive Research Center (HEASARC) at the NASA */
+/* Goddard Space Flight Center. */
+
+#include <math.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include "fitsio2.h"
+
+/*--------------------------------------------------------------------------*/
+int ffgpvk( fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to read (1 = 1st group) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ int nulval, /* I - value for undefined pixels */
+ int *array, /* O - array of values that are returned */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being read).
+ Undefined elements will be set equal to NULVAL, unless NULVAL=0
+ in which case no checking for undefined values will be performed.
+ ANYNUL is returned with a value of .true. if any pixels are undefined.
+*/
+{
+ long row;
+ char cdummy;
+ int nullcheck = 1;
+ int nullvalue;
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+ nullvalue = nulval; /* set local variable */
+
+ fits_read_compressed_pixels(fptr, TINT, firstelem, nelem,
+ nullcheck, &nullvalue, array, NULL, anynul, status);
+ return(*status);
+ }
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ row=maxvalue(1,group);
+
+ ffgclk(fptr, 2, row, firstelem, nelem, 1, 1, nulval,
+ array, &cdummy, anynul, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgpfk( fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to read (1 = 1st group) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ int *array, /* O - array of values that are returned */
+ char *nularray, /* O - array of null pixel flags */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being read).
+ Any undefined pixels in the returned array will be set = 0 and the
+ corresponding nularray value will be set = 1.
+ ANYNUL is returned with a value of .true. if any pixels are undefined.
+*/
+{
+ long row;
+ int nullcheck = 2;
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ fits_read_compressed_pixels(fptr, TINT, firstelem, nelem,
+ nullcheck, NULL, array, nularray, anynul, status);
+ return(*status);
+ }
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ row=maxvalue(1,group);
+
+ ffgclk(fptr, 2, row, firstelem, nelem, 1, 2, 0L,
+ array, nularray, anynul, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffg2dk(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to read (1 = 1st group) */
+ int nulval, /* set undefined pixels equal to this */
+ long ncols, /* I - number of pixels in each row of array */
+ long naxis1, /* I - FITS image NAXIS1 value */
+ long naxis2, /* I - FITS image NAXIS2 value */
+ int *array, /* O - array to be filled and returned */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an entire 2-D array of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of the
+ FITS array is not the same as the array being read). Any null
+ values in the array will be set equal to the value of nulval, unless
+ nulval = 0 in which case no null checking will be performed.
+*/
+{
+ /* call the 3D reading routine, with the 3rd dimension = 1 */
+
+ ffg3dk(fptr, group, nulval, ncols, naxis2, naxis1, naxis2, 1, array,
+ anynul, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffg3dk(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to read (1 = 1st group) */
+ int nulval, /* set undefined pixels equal to this */
+ long ncols, /* I - number of pixels in each row of array */
+ long nrows, /* I - number of rows in each plane of array */
+ long naxis1, /* I - FITS image NAXIS1 value */
+ long naxis2, /* I - FITS image NAXIS2 value */
+ long naxis3, /* I - FITS image NAXIS3 value */
+ int *array, /* O - array to be filled and returned */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an entire 3-D array of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of the
+ FITS array is not the same as the array being read). Any null
+ values in the array will be set equal to the value of nulval, unless
+ nulval = 0 in which case no null checking will be performed.
+*/
+{
+ long tablerow, nfits, narray, ii, jj;
+ char cdummy;
+ int nullcheck = 1;
+ long inc[] = {1,1,1};
+ long fpixel[] = {1,1,1};
+ long lpixel[3];
+ int nullvalue;
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ lpixel[0] = ncols;
+ lpixel[1] = nrows;
+ lpixel[2] = naxis3;
+ nullvalue = nulval; /* set local variable */
+
+ fits_read_compressed_img(fptr, TINT, fpixel, lpixel, inc,
+ nullcheck, &nullvalue, array, NULL, anynul, status);
+ return(*status);
+ }
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+ tablerow=maxvalue(1,group);
+
+ if (ncols == naxis1 && nrows == naxis2) /* arrays have same size? */
+ {
+ /* all the image pixels are contiguous, so read all at once */
+ ffgclk(fptr, 2, tablerow, 1, naxis1 * naxis2 * naxis3, 1, 1, nulval,
+ array, &cdummy, anynul, status);
+ return(*status);
+ }
+
+ if (ncols < naxis1 || nrows < naxis2)
+ return(*status = BAD_DIMEN);
+
+ nfits = 1; /* next pixel in FITS image to read */
+ narray = 0; /* next pixel in output array to be filled */
+
+ /* loop over naxis3 planes in the data cube */
+ for (jj = 0; jj < naxis3; jj++)
+ {
+ /* loop over the naxis2 rows in the FITS image, */
+ /* reading naxis1 pixels to each row */
+
+ for (ii = 0; ii < naxis2; ii++)
+ {
+ if (ffgclk(fptr, 2, tablerow, nfits, naxis1, 1, 1, nulval,
+ &array[narray], &cdummy, anynul, status) > 0)
+ return(*status);
+
+ nfits += naxis1;
+ narray += ncols;
+ }
+ narray += (nrows - naxis2) * ncols;
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgsvk(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of the column to read (1 = 1st) */
+ int naxis, /* I - number of dimensions in the FITS array */
+ long *naxes, /* I - size of each dimension */
+ long *blc, /* I - 'bottom left corner' of the subsection */
+ long *trc, /* I - 'top right corner' of the subsection */
+ long *inc, /* I - increment to be applied in each dimension */
+ int nulval, /* I - value to set undefined pixels */
+ int *array, /* O - array to be filled and returned */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read a subsection of data values from an image or a table column.
+ This routine is set up to handle a maximum of nine dimensions.
+*/
+{
+ long ii,i0, i1,i2,i3,i4,i5,i6,i7,i8,row,rstr,rstp,rinc;
+ long str[9],stp[9],incr[9],dir[9];
+ long nelem, nultyp, ninc, numcol;
+ OFF_T felem, dsize[10];
+ int hdutype, anyf;
+ char ldummy, msg[FLEN_ERRMSG];
+ int nullcheck = 1;
+ int nullvalue;
+
+ if (naxis < 1 || naxis > 9)
+ {
+ sprintf(msg, "NAXIS = %d in call to ffgsvj is out of range", naxis);
+ ffpmsg(msg);
+ return(*status = BAD_DIMEN);
+ }
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ nullvalue = nulval; /* set local variable */
+
+ fits_read_compressed_img(fptr, TINT, blc, trc, inc,
+ nullcheck, &nullvalue, array, NULL, anynul, status);
+ return(*status);
+ }
+
+/*
+ if this is a primary array, then the input COLNUM parameter should
+ be interpreted as the row number, and we will alway read the image
+ data from column 2 (any group parameters are in column 1).
+*/
+ if (ffghdt(fptr, &hdutype, status) > 0)
+ return(*status);
+
+ if (hdutype == IMAGE_HDU)
+ {
+ /* this is a primary array, or image extension */
+ if (colnum == 0)
+ {
+ rstr = 1;
+ rstp = 1;
+ }
+ else
+ {
+ rstr = colnum;
+ rstp = colnum;
+ }
+ rinc = 1;
+ numcol = 2;
+ }
+ else
+ {
+ /* this is a table, so the row info is in the (naxis+1) elements */
+ rstr = blc[naxis];
+ rstp = trc[naxis];
+ rinc = inc[naxis];
+ numcol = colnum;
+ }
+
+ nultyp = 1;
+ if (anynul)
+ *anynul = FALSE;
+
+ i0 = 0;
+ for (ii = 0; ii < 9; ii++)
+ {
+ str[ii] = 1;
+ stp[ii] = 1;
+ incr[ii] = 1;
+ dsize[ii] = 1;
+ dir[ii] = 1;
+ }
+
+ for (ii = 0; ii < naxis; ii++)
+ {
+ if (trc[ii] < blc[ii])
+ {
+ if (hdutype == IMAGE_HDU)
+ {
+ dir[ii] = -1;
+ }
+ else
+ {
+ sprintf(msg, "ffgsvk: illegal range specified for axis %ld", ii + 1);
+ ffpmsg(msg);
+ return(*status = BAD_PIX_NUM);
+ }
+ }
+
+ str[ii] = blc[ii];
+ stp[ii] = trc[ii];
+ incr[ii] = inc[ii];
+ dsize[ii + 1] = dsize[ii] * naxes[ii];
+ dsize[ii] = dsize[ii] * dir[ii];
+ }
+ dsize[naxis] = dsize[naxis] * dir[naxis];
+
+ if (naxis == 1 && naxes[0] == 1)
+ {
+ /* This is not a vector column, so read all the rows at once */
+ nelem = (rstp - rstr) / rinc + 1;
+ ninc = rinc;
+ rstp = rstr;
+ }
+ else
+ {
+ /* have to read each row individually, in all dimensions */
+ nelem = (stp[0]*dir[0] - str[0]*dir[0]) / inc[0] + 1;
+ ninc = incr[0] * dir[0];
+ }
+
+ for (row = rstr; row <= rstp; row += rinc)
+ {
+ for (i8 = str[8]*dir[8]; i8 <= stp[8]*dir[8]; i8 += incr[8])
+ {
+ for (i7 = str[7]*dir[7]; i7 <= stp[7]*dir[7]; i7 += incr[7])
+ {
+ for (i6 = str[6]*dir[6]; i6 <= stp[6]*dir[6]; i6 += incr[6])
+ {
+ for (i5 = str[5]*dir[5]; i5 <= stp[5]*dir[5]; i5 += incr[5])
+ {
+ for (i4 = str[4]*dir[4]; i4 <= stp[4]*dir[4]; i4 += incr[4])
+ {
+ for (i3 = str[3]*dir[3]; i3 <= stp[3]*dir[3]; i3 += incr[3])
+ {
+ for (i2 = str[2]*dir[2]; i2 <= stp[2]*dir[2]; i2 += incr[2])
+ {
+ for (i1 = str[1]*dir[1]; i1 <= stp[1]*dir[1]; i1 += incr[1])
+ {
+
+ felem=str[0] + (i1 - dir[1]) * dsize[1] + (i2 - dir[2]) * dsize[2] +
+ (i3 - dir[3]) * dsize[3] + (i4 - dir[4]) * dsize[4] +
+ (i5 - dir[5]) * dsize[5] + (i6 - dir[6]) * dsize[6] +
+ (i7 - dir[7]) * dsize[7] + (i8 - dir[8]) * dsize[8];
+
+ if ( ffgclk(fptr, numcol, row, felem, nelem, ninc, nultyp,
+ nulval, &array[i0], &ldummy, &anyf, status) > 0)
+ return(*status);
+
+ if (anyf && anynul)
+ *anynul = TRUE;
+
+ i0 += nelem;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgsfk(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of the column to read (1 = 1st) */
+ int naxis, /* I - number of dimensions in the FITS array */
+ long *naxes, /* I - size of each dimension */
+ long *blc, /* I - 'bottom left corner' of the subsection */
+ long *trc, /* I - 'top right corner' of the subsection */
+ long *inc, /* I - increment to be applied in each dimension */
+ int *array, /* O - array to be filled and returned */
+ char *flagval, /* O - set to 1 if corresponding value is null */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read a subsection of data values from an image or a table column.
+ This routine is set up to handle a maximum of nine dimensions.
+*/
+{
+ long ii,i0, i1,i2,i3,i4,i5,i6,i7,i8,row,rstr,rstp,rinc;
+ long str[9],stp[9],incr[9],dsize[10];
+ long felem, nelem, nultyp, ninc, numcol;
+ long nulval = 0;
+ int hdutype, anyf;
+ char msg[FLEN_ERRMSG];
+ int nullcheck = 2;
+
+ if (naxis < 1 || naxis > 9)
+ {
+ sprintf(msg, "NAXIS = %d in call to ffgsvj is out of range", naxis);
+ ffpmsg(msg);
+ return(*status = BAD_DIMEN);
+ }
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ fits_read_compressed_img(fptr, TINT, blc, trc, inc,
+ nullcheck, NULL, array, flagval, anynul, status);
+ return(*status);
+ }
+
+/*
+ if this is a primary array, then the input COLNUM parameter should
+ be interpreted as the row number, and we will alway read the image
+ data from column 2 (any group parameters are in column 1).
+*/
+ if (ffghdt(fptr, &hdutype, status) > 0)
+ return(*status);
+
+ if (hdutype == IMAGE_HDU)
+ {
+ /* this is a primary array, or image extension */
+ if (colnum == 0)
+ {
+ rstr = 1;
+ rstp = 1;
+ }
+ else
+ {
+ rstr = colnum;
+ rstp = colnum;
+ }
+ rinc = 1;
+ numcol = 2;
+ }
+ else
+ {
+ /* this is a table, so the row info is in the (naxis+1) elements */
+ rstr = blc[naxis];
+ rstp = trc[naxis];
+ rinc = inc[naxis];
+ numcol = colnum;
+ }
+
+ nultyp = 2;
+ if (anynul)
+ *anynul = FALSE;
+
+ i0 = 0;
+ for (ii = 0; ii < 9; ii++)
+ {
+ str[ii] = 1;
+ stp[ii] = 1;
+ incr[ii] = 1;
+ dsize[ii] = 1;
+ }
+
+ for (ii = 0; ii < naxis; ii++)
+ {
+ if (trc[ii] < blc[ii])
+ {
+ sprintf(msg, "ffgsvj: illegal range specified for axis %ld", ii + 1);
+ ffpmsg(msg);
+ return(*status = BAD_PIX_NUM);
+ }
+
+ str[ii] = blc[ii];
+ stp[ii] = trc[ii];
+ incr[ii] = inc[ii];
+ dsize[ii + 1] = dsize[ii] * naxes[ii];
+ }
+
+ if (naxis == 1 && naxes[0] == 1)
+ {
+ /* This is not a vector column, so read all the rows at once */
+ nelem = (rstp - rstr) / rinc + 1;
+ ninc = rinc;
+ rstp = rstr;
+ }
+ else
+ {
+ /* have to read each row individually, in all dimensions */
+ nelem = (stp[0] - str[0]) / inc[0] + 1;
+ ninc = incr[0];
+ }
+
+ for (row = rstr; row <= rstp; row += rinc)
+ {
+ for (i8 = str[8]; i8 <= stp[8]; i8 += incr[8])
+ {
+ for (i7 = str[7]; i7 <= stp[7]; i7 += incr[7])
+ {
+ for (i6 = str[6]; i6 <= stp[6]; i6 += incr[6])
+ {
+ for (i5 = str[5]; i5 <= stp[5]; i5 += incr[5])
+ {
+ for (i4 = str[4]; i4 <= stp[4]; i4 += incr[4])
+ {
+ for (i3 = str[3]; i3 <= stp[3]; i3 += incr[3])
+ {
+ for (i2 = str[2]; i2 <= stp[2]; i2 += incr[2])
+ {
+ for (i1 = str[1]; i1 <= stp[1]; i1 += incr[1])
+ {
+ felem=str[0] + (i1 - 1) * dsize[1] + (i2 - 1) * dsize[2] +
+ (i3 - 1) * dsize[3] + (i4 - 1) * dsize[4] +
+ (i5 - 1) * dsize[5] + (i6 - 1) * dsize[6] +
+ (i7 - 1) * dsize[7] + (i8 - 1) * dsize[8];
+
+ if ( ffgclk(fptr, numcol, row, felem, nelem, ninc, nultyp,
+ nulval, &array[i0], &flagval[i0], &anyf, status) > 0)
+ return(*status);
+
+ if (anyf && anynul)
+ *anynul = TRUE;
+
+ i0 += nelem;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffggpk( fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to read (1 = 1st group) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ int *array, /* O - array of values that are returned */
+ int *status) /* IO - error status */
+/*
+ Read an array of group parameters from the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being read).
+*/
+{
+ long row;
+ int idummy;
+ char cdummy;
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ row=maxvalue(1,group);
+
+ ffgclk(fptr, 1, row, firstelem, nelem, 1, 1, 0L,
+ array, &cdummy, &idummy, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgcvk(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to read (1 = 1st col) */
+ long firstrow, /* I - first row to read (1 = 1st row) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ int nulval, /* I - value for null pixels */
+ int *array, /* O - array of values that are read */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from a column in the current FITS HDU. Automatic
+ datatype conversion will be performed if the datatype of the column does not
+ match the datatype of the array parameter. The output values will be scaled
+ by the FITS TSCALn and TZEROn values if these values have been defined.
+ Any undefined pixels will be set equal to the value of 'nulval' unless
+ nulval = 0 in which case no checks for undefined pixels will be made.
+*/
+{
+ char cdummy;
+
+ ffgclk(fptr, colnum, firstrow, firstelem, nelem, 1, 1, nulval,
+ array, &cdummy, anynul, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgcfk(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to read (1 = 1st col) */
+ long firstrow, /* I - first row to read (1 = 1st row) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ int *array, /* O - array of values that are read */
+ char *nularray, /* O - array of flags: 1 if null pixel; else 0 */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from a column in the current FITS HDU. Automatic
+ datatype conversion will be performed if the datatype of the column does not
+ match the datatype of the array parameter. The output values will be scaled
+ by the FITS TSCALn and TZEROn values if these values have been defined.
+ Nularray will be set = 1 if the corresponding array pixel is undefined,
+ otherwise nularray will = 0.
+*/
+{
+ int dummy = 0;
+
+ ffgclk(fptr, colnum, firstrow, firstelem, nelem, 1, 2, dummy,
+ array, nularray, anynul, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgclk( fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to read (1 = 1st col) */
+ long firstrow, /* I - first row to read (1 = 1st row) */
+ OFF_T firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ long elemincre, /* I - pixel increment; e.g., 2 = every other */
+ int nultyp, /* I - null value handling code: */
+ /* 1: set undefined pixels = nulval */
+ /* 2: set nularray=1 for undefined pixels */
+ int nulval, /* I - value for null pixels if nultyp = 1 */
+ int *array, /* O - array of values that are read */
+ char *nularray, /* O - array of flags = 1 if nultyp = 2 */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from a column in the current FITS HDU.
+ The column number may refer to a real column in an ASCII or binary table,
+ or it may refer be a virtual column in a 1 or more grouped FITS primary
+ array or image extension. FITSIO treats a primary array as a binary table
+ with 2 vector columns: the first column contains the group parameters (often
+ with length = 0) and the second column contains the array of image pixels.
+ Each row of the table represents a group in the case of multigroup FITS
+ images.
+
+ The output array of values will be converted from the datatype of the column
+ and will be scaled by the FITS TSCALn and TZEROn values if necessary.
+*/
+{
+ double scale, zero, power;
+ int tcode, maxelem, hdutype, xcode, decimals;
+ long twidth, incre, rownum, remain, next, ntodo;
+ long ii, rowincre, tnull, xwidth;
+ int convert, nulcheck, readcheck = 0;
+ OFF_T repeat, startpos, elemnum, readptr, rowlen;
+ char tform[20];
+ char message[81];
+ char snull[20]; /* the FITS null value if reading from ASCII table */
+
+ double cbuff[DBUFFSIZE / sizeof(double)]; /* align cbuff on word boundary */
+ void *buffer;
+
+ if (*status > 0 || nelem == 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ /* call the 'short' or 'long' version of this routine, if possible */
+ if (sizeof(int) == sizeof(short))
+ ffgcli(fptr, colnum, firstrow, firstelem, nelem, elemincre, nultyp,
+ (short) nulval, (short *) array, nularray, anynul, status);
+ else if (sizeof(int) == sizeof(long))
+ ffgclj(fptr, colnum, firstrow, firstelem, nelem, elemincre, nultyp,
+ (long) nulval, (long *) array, nularray, anynul, status);
+ else
+ {
+ /*
+ This is a special case: sizeof(int) is not equal to sizeof(short) or
+ sizeof(long). This occurs on Alpha OSF systems where short = 2 bytes,
+ int = 4 bytes, and long = 8 bytes.
+ */
+
+ buffer = cbuff;
+ power = 1.;
+
+ if (anynul)
+ *anynul = 0;
+
+ if (nultyp == 2)
+ memset(nularray, 0, nelem); /* initialize nullarray */
+
+ /*---------------------------------------------------*/
+ /* Check input and get parameters about the column: */
+ /*---------------------------------------------------*/
+ if (elemincre < 0)
+ readcheck = -1; /* don't do range checking in this case */
+
+ if ( ffgcpr( fptr, colnum, firstrow, firstelem, nelem, readcheck, &scale, &zero,
+ tform, &twidth, &tcode, &maxelem, &startpos, &elemnum, &incre,
+ &repeat, &rowlen, &hdutype, &tnull, snull, status) > 0 )
+ return(*status);
+
+ incre *= elemincre; /* multiply incre to just get every nth pixel */
+
+ if (tcode == TSTRING) /* setup for ASCII tables */
+ {
+ /* get the number of implied decimal places if no explicit decmal point */
+ ffasfm(tform, &xcode, &xwidth, &decimals, status);
+ for(ii = 0; ii < decimals; ii++)
+ power *= 10.;
+ }
+ /*------------------------------------------------------------------*/
+ /* Decide whether to check for null values in the input FITS file: */
+ /*------------------------------------------------------------------*/
+ nulcheck = nultyp; /* by default check for null values in the FITS file */
+
+ if (nultyp == 1 && nulval == 0)
+ nulcheck = 0; /* calling routine does not want to check for nulls */
+
+ else if (tcode%10 == 1 && /* if reading an integer column, and */
+ tnull == NULL_UNDEFINED) /* if a null value is not defined, */
+ nulcheck = 0; /* then do not check for null values. */
+
+ else if (tcode == TSHORT && (tnull > SHRT_MAX || tnull < SHRT_MIN) )
+ nulcheck = 0; /* Impossible null value */
+
+ else if (tcode == TBYTE && (tnull > 255 || tnull < 0) )
+ nulcheck = 0; /* Impossible null value */
+
+ else if (tcode == TSTRING && snull[0] == ASCII_NULL_UNDEFINED)
+ nulcheck = 0;
+
+ /*----------------------------------------------------------------------*/
+ /* If FITS column and output data array have same datatype, then we do */
+ /* not need to use a temporary buffer to store intermediate datatype. */
+ /*----------------------------------------------------------------------*/
+ convert = 1;
+ if (tcode == TLONG) /* Special Case: */
+ { /* no type convertion required, so read */
+ maxelem = nelem; /* data directly into output buffer. */
+
+ if (nulcheck == 0 && scale == 1. && zero == 0.)
+ convert = 0; /* no need to scale data or find nulls */
+ }
+
+ /*---------------------------------------------------------------------*/
+ /* Now read the pixels from the FITS column. If the column does not */
+ /* have the same datatype as the output array, then we have to read */
+ /* the raw values into a temporary buffer (of limited size). In */
+ /* the case of a vector colum read only 1 vector of values at a time */
+ /* then skip to the next row if more values need to be read. */
+ /* After reading the raw values, then call the fffXXYY routine to (1) */
+ /* test for undefined values, (2) convert the datatype if necessary, */
+ /* and (3) scale the values by the FITS TSCALn and TZEROn linear */
+ /* scaling parameters. */
+ /*---------------------------------------------------------------------*/
+ remain = nelem; /* remaining number of values to read */
+ next = 0; /* next element in array to be read */
+ rownum = 0; /* row number, relative to firstrow */
+
+ while (remain)
+ {
+ /* limit the number of pixels to read at one time to the number that
+ will fit in the buffer or to the number of pixels that remain in
+ the current vector, which ever is smaller.
+ */
+ ntodo = minvalue(remain, maxelem);
+ if (elemincre >= 0)
+ {
+ ntodo = minvalue(ntodo, ((repeat - elemnum - 1)/elemincre +1));
+ }
+ else
+ {
+ ntodo = minvalue(ntodo, (elemnum/(-elemincre) +1));
+ }
+
+ readptr = startpos + ((OFF_T)rownum * rowlen) + (elemnum * (incre / elemincre));
+
+ switch (tcode)
+ {
+ case (TLONG):
+ ffgi4b(fptr, readptr, ntodo, incre, (INT32BIT *) &array[next],
+ status);
+ if (convert)
+ fffi4int((INT32BIT *) &array[next], ntodo, scale, zero,
+ nulcheck, (INT32BIT) tnull, nulval,
+ &nularray[next], anynul, &array[next], status);
+ break;
+ case (TLONGLONG):
+
+ ffgi8b(fptr, readptr, ntodo, incre, (long *) buffer, status);
+ fffi8int( (LONGLONG *) buffer, ntodo, scale, zero,
+ nulcheck, (long) tnull, nulval, &nularray[next],
+ anynul, &array[next], status);
+ break;
+ case (TBYTE):
+ ffgi1b(fptr, readptr, ntodo, incre, (unsigned char *) buffer,
+ status);
+ fffi1int((unsigned char *) buffer, ntodo, scale, zero, nulcheck,
+ (unsigned char) tnull, nulval, &nularray[next], anynul,
+ &array[next], status);
+ break;
+ case (TSHORT):
+ ffgi2b(fptr, readptr, ntodo, incre, (short *) buffer, status);
+ fffi2int((short *) buffer, ntodo, scale, zero, nulcheck,
+ (short) tnull, nulval, &nularray[next], anynul,
+ &array[next], status);
+ break;
+ case (TFLOAT):
+ ffgr4b(fptr, readptr, ntodo, incre, (float *) buffer, status);
+ fffr4int((float *) buffer, ntodo, scale, zero, nulcheck,
+ nulval, &nularray[next], anynul,
+ &array[next], status);
+ break;
+ case (TDOUBLE):
+ ffgr8b(fptr, readptr, ntodo, incre, (double *) buffer, status);
+ fffr8int((double *) buffer, ntodo, scale, zero, nulcheck,
+ nulval, &nularray[next], anynul,
+ &array[next], status);
+ break;
+ case (TSTRING):
+ ffmbyt(fptr, readptr, REPORT_EOF, status);
+
+ if (incre == twidth) /* contiguous bytes */
+ ffgbyt(fptr, ntodo * twidth, buffer, status);
+ else
+ ffgbytoff(fptr, twidth, ntodo, incre - twidth, buffer,
+ status);
+
+ fffstrint((char *) buffer, ntodo, scale, zero, twidth, power,
+ nulcheck, snull, nulval, &nularray[next], anynul,
+ &array[next], status);
+ break;
+
+ default: /* error trap for invalid column format */
+ sprintf(message,
+ "Cannot read numbers from column %d which has format %s",
+ colnum, tform);
+ ffpmsg(message);
+ if (hdutype == ASCII_TBL)
+ return(*status = BAD_ATABLE_FORMAT);
+ else
+ return(*status = BAD_BTABLE_FORMAT);
+
+ } /* End of switch block */
+
+ /*-------------------------*/
+ /* Check for fatal error */
+ /*-------------------------*/
+ if (*status > 0) /* test for error during previous read operation */
+ {
+ if (hdutype > 0)
+ sprintf(message,
+ "Error reading elements %ld thru %ld from column %d (ffgclk).",
+ next+1, next+ntodo, colnum);
+ else
+ sprintf(message,
+ "Error reading elements %ld thru %ld from image (ffgclk).",
+ next+1, next+ntodo);
+
+ ffpmsg(message);
+ return(*status);
+ }
+
+ /*--------------------------------------------*/
+ /* increment the counters for the next loop */
+ /*--------------------------------------------*/
+ remain -= ntodo;
+ if (remain)
+ {
+ next += ntodo;
+ elemnum = elemnum + (ntodo * elemincre);
+
+ if (elemnum >= repeat) /* completed a row; start on later row */
+ {
+ rowincre = elemnum / repeat;
+ rownum += rowincre;
+ elemnum = elemnum - (rowincre * repeat);
+ }
+ else if (elemnum < 0) /* completed a row; start on a previous row */
+ {
+ rowincre = (-elemnum - 1) / repeat + 1;
+ rownum -= rowincre;
+ elemnum = (rowincre * repeat) + elemnum;
+ }
+ }
+ } /* End of main while Loop */
+
+
+ /*--------------------------------*/
+ /* check for numerical overflow */
+ /*--------------------------------*/
+ if (*status == OVERFLOW_ERR)
+ {
+ ffpmsg(
+ "Numerical overflow during type conversion while reading FITS data.");
+ *status = NUM_OVERFLOW;
+ }
+
+ } /* end of DEC Alpha special case */
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffi1int(unsigned char *input,/* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ unsigned char tnull, /* I - value of FITS TNULLn keyword if any */
+ int nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ int *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to tnull. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = (int) input[ii]; /* copy input to output */
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT_MIN;
+ }
+ else if (dvalue > DINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT_MAX;
+ }
+ else
+ output[ii] = (int) dvalue;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ output[ii] = (int) input[ii];
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT_MIN;
+ }
+ else if (dvalue > DINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT_MAX;
+ }
+ else
+ output[ii] = (int) dvalue;
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffi2int(short *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ short tnull, /* I - value of FITS TNULLn keyword if any */
+ int nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ int *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to tnull. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = (int) input[ii]; /* copy input to output */
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT_MIN;
+ }
+ else if (dvalue > DINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT_MAX;
+ }
+ else
+ output[ii] = (int) dvalue;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ output[ii] = (int) input[ii];
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT_MIN;
+ }
+ else if (dvalue > DINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT_MAX;
+ }
+ else
+ output[ii] = (int) dvalue;
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffi4int(INT32BIT *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ INT32BIT tnull, /* I - value of FITS TNULLn keyword if any */
+ int nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ int *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to tnull. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ long ii;
+ double dvalue;
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = (int) input[ii]; /* copy input to output */
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT_MIN;
+ }
+ else if (dvalue > DINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT_MAX;
+ }
+ else
+ output[ii] = (int) dvalue;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ output[ii] = (int) input[ii];
+
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT_MIN;
+ }
+ else if (dvalue > DINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT_MAX;
+ }
+ else
+ output[ii] = (int) dvalue;
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffi8int(LONGLONG *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ long tnull, /* I - value of FITS TNULLn keyword if any */
+ int nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ int *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to tnull. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+#if (LONGSIZE == 32) && (! defined HAVE_LONGLONG)
+
+ /* This block of code is only used in cases where there is */
+ /* no native 8-byte integer support. We have to interpret */
+ /* the corresponding pair of 4-byte integers which are */
+ /* are equivalent to the 8-byte integer. */
+
+ long ii,jj,kk;
+ double dvalue;
+ unsigned long *uinput;
+
+ uinput = (unsigned long *) input;
+
+#if BYTESWAPPED /* jj points to the most significant part of the 8-byte int */
+ jj = 1;
+ kk = 0;
+#else
+ jj = 0;
+ kk = 1;
+#endif
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++, jj += 2, kk += 2)
+ {
+ if (uinput[jj] & 0x80000000) /* negative number */
+ dvalue = (uinput[jj] ^ 0xffffffff) * -4294967296. -
+ (uinput[kk] ^ 0xffffffff) - 1.;
+ else /* positive number */
+ dvalue = uinput[jj] * 4294967296. + uinput[kk];
+
+ if (dvalue < DINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT_MIN;
+ }
+ else if (dvalue > DINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT_MAX;
+ }
+ else
+ output[ii] = (int) dvalue;
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++, jj += 2, kk += 2)
+ {
+ if (uinput[jj] & 0x80000000) /* negative number */
+ dvalue = ((uinput[jj] ^ 0xffffffff) * -4294967296. -
+ (uinput[kk] ^ 0xffffffff) - 1.) * scale + zero;
+ else /* positive number */
+ dvalue = (uinput[jj] * 4294967296. + uinput[kk])
+ * scale + zero;
+
+ if (dvalue < DINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT_MIN;
+ }
+ else if (dvalue > DINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT_MAX;
+ }
+ else
+ output[ii] = (int) dvalue;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++, jj += 2, kk += 2)
+ {
+ if (uinput[jj] & 0x80000000) /* negative number */
+ dvalue = (uinput[jj] ^ 0xffffffff) * -4294967296. -
+ (uinput[kk] ^ 0xffffffff) - 1.;
+ else /* positive number */
+ dvalue = uinput[jj] * 4294967296. + uinput[kk];
+
+ if (dvalue == (double) tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ if (dvalue < DINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT_MIN;
+ }
+ else if (dvalue > DINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT_MAX;
+ }
+ else
+ output[ii] = (int) dvalue;
+ }
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++, jj += 2, kk += 2)
+ {
+ if (uinput[jj] & 0x80000000) /* negative number */
+ dvalue = (uinput[jj] ^ 0xffffffff) * -4294967296. -
+ (uinput[kk] ^ 0xffffffff) - 1.;
+ else /* positive number */
+ dvalue = uinput[jj] * 4294967296. + uinput[kk];
+
+ if (dvalue == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ dvalue = dvalue * scale + zero;
+
+ if (dvalue < DINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT_MIN;
+ }
+ else if (dvalue > DINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT_MAX;
+ }
+ else
+ output[ii] = (int) dvalue;
+ }
+ }
+ }
+ }
+
+#else
+
+ /* this block works on machines which support an 8-byte integer type */
+
+ long ii;
+ double dvalue;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] < INT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT_MIN;
+ }
+ else if (input[ii] > INT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT_MAX;
+ }
+ else
+ output[ii] = (int) input[ii];
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT_MIN;
+ }
+ else if (dvalue > DINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT_MAX;
+ }
+ else
+ output[ii] = (int) dvalue;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ if (input[ii] < INT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT_MIN;
+ }
+ else if (input[ii] > INT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT_MAX;
+ }
+ else
+ output[ii] = (int) input[ii];
+ }
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT_MIN;
+ }
+ else if (dvalue > DINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT_MAX;
+ }
+ else
+ output[ii] = (int) dvalue;
+ }
+ }
+ }
+ }
+
+#endif
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffr4int(float *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ int nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ int *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to NaN. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ long ii;
+ double dvalue;
+ short *sptr, iret;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] < DINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT_MIN;
+ }
+ else if (input[ii] > DINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT_MAX;
+ }
+ else
+ output[ii] = (int) input[ii];
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT_MIN;
+ }
+ else if (dvalue > DINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT_MAX;
+ }
+ else
+ output[ii] = (int) dvalue;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ sptr = (short *) input;
+
+#if BYTESWAPPED && MACHINE != VAXVMS && MACHINE != ALPHAVMS
+ sptr++; /* point to MSBs */
+#endif
+
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++, sptr += 2)
+ {
+ if (0 != (iret = fnan(*sptr) ) ) /* test for NaN or underflow */
+ {
+ if (iret == 1) /* is it a NaN? */
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else /* it's an underflow */
+ output[ii] = 0;
+ }
+ else
+ {
+ if (input[ii] < DINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT_MIN;
+ }
+ else if (input[ii] > DINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT_MAX;
+ }
+ else
+ output[ii] = (int) input[ii];
+ }
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++, sptr += 2)
+ {
+ if (0 != (iret = fnan(*sptr) ) ) /* test for NaN or underflow */
+ {
+ if (iret == 1) /* is it a NaN? */
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else /* it's an underflow */
+ {
+ if (zero < DINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT_MIN;
+ }
+ else if (zero > DINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT_MAX;
+ }
+ else
+ output[ii] = (int) zero;
+ }
+ }
+ else
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT_MIN;
+ }
+ else if (dvalue > DINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT_MAX;
+ }
+ else
+ output[ii] = (int) dvalue;
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffr8int(double *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ int nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ int *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to NaN. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ long ii;
+ double dvalue;
+ short *sptr, iret;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] < DINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT_MIN;
+ }
+ else if (input[ii] > DINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT_MAX;
+ }
+ else
+ output[ii] = (int) input[ii];
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT_MIN;
+ }
+ else if (dvalue > DINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT_MAX;
+ }
+ else
+ output[ii] = (int) dvalue;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ sptr = (short *) input;
+
+#if BYTESWAPPED && MACHINE != VAXVMS && MACHINE != ALPHAVMS
+ sptr += 3; /* point to MSBs */
+#endif
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++, sptr += 4)
+ {
+ if (0 != (iret = dnan(*sptr)) ) /* test for NaN or underflow */
+ {
+ if (iret == 1) /* is it a NaN? */
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else /* it's an underflow */
+ output[ii] = 0;
+ }
+ else
+ {
+ if (input[ii] < DINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT_MIN;
+ }
+ else if (input[ii] > DINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT_MAX;
+ }
+ else
+ output[ii] = (int) input[ii];
+ }
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++, sptr += 4)
+ {
+ if (0 != (iret = dnan(*sptr)) ) /* test for NaN or underflow */
+ {
+ if (iret == 1) /* is it a NaN? */
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else /* it's an underflow */
+ {
+ if (zero < DINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT_MIN;
+ }
+ else if (zero > DINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT_MAX;
+ }
+ else
+ output[ii] = (int) zero;
+ }
+ }
+ else
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT_MIN;
+ }
+ else if (dvalue > DINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT_MAX;
+ }
+ else
+ output[ii] = (int) dvalue;
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffstrint(char *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ long twidth, /* I - width of each substring of chars */
+ double implipower, /* I - power of 10 of implied decimal */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ char *snull, /* I - value of FITS null string, if any */
+ int nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ int *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file. Check
+ for null values and do scaling if required. The nullcheck code value
+ determines how any null values in the input array are treated. A null
+ value is an input pixel that is equal to snull. If nullcheck= 0, then
+ no special checking for nulls is performed. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ int nullen;
+ long ii;
+ double dvalue;
+ char *cstring, message[81];
+ char *cptr, *tpos;
+ char tempstore, chrzero = '0';
+ double val, power;
+ int exponent, sign, esign, decpt;
+
+ nullen = strlen(snull);
+ cptr = input; /* pointer to start of input string */
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ cstring = cptr;
+ /* temporarily insert a null terminator at end of the string */
+ tpos = cptr + twidth;
+ tempstore = *tpos;
+ *tpos = 0;
+
+ /* check if null value is defined, and if the */
+ /* column string is identical to the null string */
+ if (snull[0] != ASCII_NULL_UNDEFINED &&
+ !strncmp(snull, cptr, nullen) )
+ {
+ if (nullcheck)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ cptr += twidth;
+ }
+ else
+ {
+ /* value is not the null value, so decode it */
+ /* remove any embedded blank characters from the string */
+
+ decpt = 0;
+ sign = 1;
+ val = 0.;
+ power = 1.;
+ exponent = 0;
+ esign = 1;
+
+ while (*cptr == ' ') /* skip leading blanks */
+ cptr++;
+
+ if (*cptr == '-' || *cptr == '+') /* check for leading sign */
+ {
+ if (*cptr == '-')
+ sign = -1;
+
+ cptr++;
+
+ while (*cptr == ' ') /* skip blanks between sign and value */
+ cptr++;
+ }
+
+ while (*cptr >= '0' && *cptr <= '9')
+ {
+ val = val * 10. + *cptr - chrzero; /* accumulate the value */
+ cptr++;
+
+ while (*cptr == ' ') /* skip embedded blanks in the value */
+ cptr++;
+ }
+
+ if (*cptr == '.') /* check for decimal point */
+ {
+ decpt = 1; /* set flag to show there was a decimal point */
+ cptr++;
+ while (*cptr == ' ') /* skip any blanks */
+ cptr++;
+
+ while (*cptr >= '0' && *cptr <= '9')
+ {
+ val = val * 10. + *cptr - chrzero; /* accumulate the value */
+ power = power * 10.;
+ cptr++;
+
+ while (*cptr == ' ') /* skip embedded blanks in the value */
+ cptr++;
+ }
+ }
+
+ if (*cptr == 'E' || *cptr == 'D') /* check for exponent */
+ {
+ cptr++;
+ while (*cptr == ' ') /* skip blanks */
+ cptr++;
+
+ if (*cptr == '-' || *cptr == '+') /* check for exponent sign */
+ {
+ if (*cptr == '-')
+ esign = -1;
+
+ cptr++;
+
+ while (*cptr == ' ') /* skip blanks between sign and exp */
+ cptr++;
+ }
+
+ while (*cptr >= '0' && *cptr <= '9')
+ {
+ exponent = exponent * 10 + *cptr - chrzero; /* accumulate exp */
+ cptr++;
+
+ while (*cptr == ' ') /* skip embedded blanks */
+ cptr++;
+ }
+ }
+
+ if (*cptr != 0) /* should end up at the null terminator */
+ {
+ sprintf(message, "Cannot read number from ASCII table");
+ ffpmsg(message);
+ sprintf(message, "Column field = %s.", cstring);
+ ffpmsg(message);
+ /* restore the char that was overwritten by the null */
+ *tpos = tempstore;
+ return(*status = BAD_C2D);
+ }
+
+ if (!decpt) /* if no explicit decimal, use implied */
+ power = implipower;
+
+ dvalue = (sign * val / power) * pow(10., (double) (esign * exponent));
+
+ dvalue = dvalue * scale + zero; /* apply the scaling */
+
+ if (dvalue < DINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT_MIN;
+ }
+ else if (dvalue > DINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT_MAX;
+ }
+ else
+ output[ii] = (long) dvalue;
+ }
+ /* restore the char that was overwritten by the null */
+ *tpos = tempstore;
+ }
+ return(*status);
+}
diff --git a/pkg/tbtables/cfitsio/getcoll.c b/pkg/tbtables/cfitsio/getcoll.c
new file mode 100644
index 00000000..a8a8516b
--- /dev/null
+++ b/pkg/tbtables/cfitsio/getcoll.c
@@ -0,0 +1,612 @@
+/* This file, getcoll.c, contains routines that read data elements from */
+/* a FITS image or table, with logical datatype. */
+
+/* The FITSIO software was written by William Pence at the High Energy */
+/* Astrophysic Science Archive Research Center (HEASARC) at the NASA */
+/* Goddard Space Flight Center. */
+
+#include <stdlib.h>
+#include <string.h>
+#include "fitsio2.h"
+/*--------------------------------------------------------------------------*/
+int ffgcvl( fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to read (1 = 1st col) */
+ long firstrow, /* I - first row to read (1 = 1st row) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ char nulval, /* I - value for null pixels */
+ char *array, /* O - array of values */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of logical values from a column in the current FITS HDU.
+ Any undefined pixels will be set equal to the value of 'nulval' unless
+ nulval = 0 in which case no checks for undefined pixels will be made.
+*/
+{
+ char cdummy;
+
+ ffgcll( fptr, colnum, firstrow, firstelem, nelem, 1, nulval, array,
+ &cdummy, anynul, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgcl( fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to read (1 = 1st col) */
+ long firstrow, /* I - first row to read (1 = 1st row) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ char *array, /* O - array of values */
+ int *status) /* IO - error status */
+/*
+ !!!! THIS ROUTINE IS DEPRECATED AND SHOULD NOT BE USED !!!!!!
+ !!!! USE ffgcvl INSTEAD !!!!!!
+ Read an array of logical values from a column in the current FITS HDU.
+ No checking for null values will be performed.
+*/
+{
+ char nulval = 0;
+ int anynul;
+
+ ffgcvl( fptr, colnum, firstrow, firstelem, nelem, nulval, array,
+ &anynul, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgcfl( fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to read (1 = 1st col) */
+ long firstrow, /* I - first row to read (1 = 1st row) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ char *array, /* O - array of values */
+ char *nularray, /* O - array of flags = 1 if nultyp = 2 */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of logical values from a column in the current FITS HDU.
+*/
+{
+ char nulval = 0;
+
+ ffgcll( fptr, colnum, firstrow, firstelem, nelem, 2, nulval, array,
+ nularray, anynul, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgcll( fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to read (1 = 1st col) */
+ long firstrow, /* I - first row to read (1 = 1st row) */
+ OFF_T firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ int nultyp, /* I - null value handling code: */
+ /* 1: set undefined pixels = nulval */
+ /* 2: set nularray=1 for undefined pixels */
+ char nulval, /* I - value for null pixels if nultyp = 1 */
+ char *array, /* O - array of values */
+ char *nularray, /* O - array of flags = 1 if nultyp = 2 */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of logical values from a column in the current FITS HDU.
+*/
+{
+ int tcode, maxelem, hdutype, ii, nulcheck;
+ long twidth, incre, rownum;
+ long tnull, remain, next, ntodo;
+ OFF_T repeat, startpos, elemnum, readptr, rowlen;
+ double scale, zero;
+ char tform[20];
+ char message[FLEN_ERRMSG];
+ char snull[20]; /* the FITS null value */
+ unsigned char buffer[DBUFFSIZE], *buffptr;
+
+ if (*status > 0 || nelem == 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ if (anynul)
+ *anynul = 0;
+
+ if (nultyp == 2)
+ memset(nularray, 0, nelem); /* initialize nullarray */
+
+ /*---------------------------------------------------*/
+ /* Check input and get parameters about the column: */
+ /*---------------------------------------------------*/
+ if (ffgcpr( fptr, colnum, firstrow, firstelem, nelem, 0, &scale, &zero,
+ tform, &twidth, &tcode, &maxelem, &startpos, &elemnum, &incre,
+ &repeat, &rowlen, &hdutype, &tnull, snull, status) > 0)
+ return(*status);
+
+ if (tcode != TLOGICAL)
+ return(*status = NOT_LOGICAL_COL);
+
+ /*------------------------------------------------------------------*/
+ /* Decide whether to check for null values in the input FITS file: */
+ /*------------------------------------------------------------------*/
+ nulcheck = nultyp; /* by default, check for null values in the FITS file */
+
+ if (nultyp == 1 && nulval == 0)
+ nulcheck = 0; /* calling routine does not want to check for nulls */
+
+ /*---------------------------------------------------------------------*/
+ /* Now read the logical values from the FITS column. */
+ /*---------------------------------------------------------------------*/
+
+ remain = nelem; /* remaining number of values to read */
+ next = 0; /* next element in array to be read */
+ rownum = 0; /* row number, relative to firstrow */
+ ntodo = remain; /* max number of elements to read at one time */
+
+ while (ntodo)
+ {
+ /*
+ limit the number of pixels to read at one time to the number that
+ remain in the current vector.
+ */
+ ntodo = minvalue(ntodo, maxelem);
+ ntodo = minvalue(ntodo, (repeat - elemnum));
+
+ readptr = startpos + (rowlen * rownum) + (elemnum * incre);
+
+ ffgi1b(fptr, readptr, ntodo, incre, buffer, status);
+
+ /* convert from T or F to 1 or 0 */
+ buffptr = buffer;
+ for (ii = 0; ii < ntodo; ii++, next++, buffptr++)
+ {
+ if (*buffptr == 'T')
+ array[next] = 1;
+ else if (*buffptr =='F')
+ array[next] = 0;
+ else if (*buffptr == 0)
+ {
+ array[next] = nulval; /* set null values to input nulval */
+ if (anynul)
+ *anynul = 1;
+
+ if (nulcheck == 2)
+ {
+ nularray[next] = 1; /* set null flags */
+ }
+ }
+ else /* some other illegal character; return the char value */
+ {
+ array[next] = (char) *buffptr;
+ }
+ }
+
+ if (*status > 0) /* test for error during previous read operation */
+ {
+ sprintf(message,
+ "Error reading elements %ld thruough %ld of logical array (ffgcl).",
+ next+1, next + ntodo);
+ ffpmsg(message);
+ return(*status);
+ }
+
+ /*--------------------------------------------*/
+ /* increment the counters for the next loop */
+ /*--------------------------------------------*/
+ remain -= ntodo;
+ if (remain)
+ {
+ elemnum += ntodo;
+
+ if (elemnum == repeat) /* completed a row; start on later row */
+ {
+ elemnum = 0;
+ rownum++;
+ }
+ }
+ ntodo = remain; /* this is the maximum number to do in next loop */
+
+ } /* End of main while Loop */
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgcx( fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to write (1 = 1st col) */
+ long frow, /* I - first row to write (1 = 1st row) */
+ long fbit, /* I - first bit to write (1 = 1st) */
+ long nbit, /* I - number of bits to write */
+ char *larray, /* O - array of logicals corresponding to bits */
+ int *status) /* IO - error status */
+/*
+ read an array of logical values from a specified bit or byte
+ column of the binary table. larray is set = TRUE, if the corresponding
+ bit = 1, otherwise it is set to FALSE.
+ The binary table column being read from must have datatype 'B' or 'X'.
+*/
+{
+ OFF_T bstart;
+ long offset, fbyte, bitloc, ndone;
+ long ii, repeat, rstart, estart;
+ int tcode, descrp;
+ unsigned char cbuff;
+ static unsigned char onbit[8] = {128, 64, 32, 16, 8, 4, 2, 1};
+ tcolumn *colptr;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ /* check input parameters */
+ if (nbit < 1)
+ return(*status);
+ else if (frow < 1)
+ return(*status = BAD_ROW_NUM);
+ else if (fbit < 1)
+ return(*status = BAD_ELEM_NUM);
+
+ /* position to the correct HDU */
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+
+ /* rescan header if data structure is undefined */
+ else if ((fptr->Fptr)->datastart == DATA_UNDEFINED)
+ if ( ffrdef(fptr, status) > 0)
+ return(*status);
+
+ fbyte = (fbit + 7) / 8;
+ bitloc = fbit - 1 - ((fbit - 1) / 8 * 8);
+ ndone = 0;
+ rstart = frow - 1;
+ estart = fbyte - 1;
+
+ colptr = (fptr->Fptr)->tableptr; /* point to first column */
+ colptr += (colnum - 1); /* offset to correct column structure */
+
+ tcode = colptr->tdatatype;
+
+ if (abs(tcode) > TBYTE)
+ return(*status = NOT_LOGICAL_COL); /* not correct datatype column */
+
+ if (tcode > 0)
+ {
+ descrp = FALSE; /* not a variable length descriptor column */
+ /* N.B: REPEAT is the number of bytes, not number of bits */
+ repeat = (long) colptr->trepeat;
+
+ if (tcode == TBIT)
+ repeat = (repeat + 7) / 8; /* convert from bits to bytes */
+
+ if (fbyte > repeat)
+ return(*status = BAD_ELEM_NUM);
+
+ /* calc the i/o pointer location to start of sequence of pixels */
+ bstart = (fptr->Fptr)->datastart + ((fptr->Fptr)->rowlength * rstart) +
+ colptr->tbcol + estart;
+ }
+ else
+ {
+ descrp = TRUE; /* a variable length descriptor column */
+ /* only bit arrays (tform = 'X') are supported for variable */
+ /* length arrays. REPEAT is the number of BITS in the array. */
+
+ ffgdes(fptr, colnum, frow, &repeat, &offset, status);
+
+ if (tcode == -TBIT)
+ repeat = (repeat + 7) / 8;
+
+ if ((fbit + nbit + 6) / 8 > repeat)
+ return(*status = BAD_ELEM_NUM);
+
+ /* calc the i/o pointer location to start of sequence of pixels */
+ bstart = (fptr->Fptr)->datastart + offset + (fptr->Fptr)->heapstart + estart;
+ }
+
+ /* move the i/o pointer to the start of the pixel sequence */
+ if (ffmbyt(fptr, bstart, REPORT_EOF, status) > 0)
+ return(*status);
+
+ /* read the next byte */
+ while (1)
+ {
+ if (ffgbyt(fptr, 1, &cbuff, status) > 0)
+ return(*status);
+
+ for (ii = bitloc; (ii < 8) && (ndone < nbit); ii++, ndone++)
+ {
+ if(cbuff & onbit[ii]) /* test if bit is set */
+ larray[ndone] = TRUE;
+ else
+ larray[ndone] = FALSE;
+ }
+
+ if (ndone == nbit) /* finished all the bits */
+ return(*status);
+
+ /* not done, so get the next byte */
+ if (!descrp)
+ {
+ estart++;
+ if (estart == repeat)
+ {
+ /* move the i/o pointer to the next row of pixels */
+ estart = 0;
+ rstart = rstart + 1;
+ bstart = (fptr->Fptr)->datastart + ((fptr->Fptr)->rowlength * rstart) +
+ colptr->tbcol;
+
+ ffmbyt(fptr, bstart, REPORT_EOF, status);
+ }
+ }
+ bitloc = 0;
+ }
+}
+/*--------------------------------------------------------------------------*/
+int ffgcxui(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to read (1 = 1st col) */
+ long firstrow, /* I - first row to read (1 = 1st row) */
+ long nrows, /* I - no. of rows to read */
+ long input_first_bit, /* I - first bit to read (1 = 1st) */
+ int input_nbits, /* I - number of bits to read (<= 32) */
+ unsigned short *array, /* O - array of integer values */
+ int *status) /* IO - error status */
+/*
+ Read a consecutive string of bits from an 'X' or 'B' column and
+ interprete them as an unsigned integer. The number of bits must be
+ less than or equal to 16 or the total number of bits in the column,
+ which ever is less.
+*/
+{
+ int ii, firstbit, nbits, bytenum, startbit, numbits, endbit;
+ int firstbyte, lastbyte, nbytes, rshift, lshift;
+ unsigned short colbyte[5];
+ tcolumn *colptr;
+ char message[81];
+
+ if (*status > 0 || nrows == 0)
+ return(*status);
+
+ /* check input parameters */
+ if (firstrow < 1)
+ {
+ sprintf(message, "Starting row number is less than 1: %ld (ffgcxui)",
+ firstrow);
+ ffpmsg(message);
+ return(*status = BAD_ROW_NUM);
+ }
+ else if (input_first_bit < 1)
+ {
+ sprintf(message, "Starting bit number is less than 1: %ld (ffgcxui)",
+ input_first_bit);
+ ffpmsg(message);
+ return(*status = BAD_ELEM_NUM);
+ }
+ else if (input_nbits > 16)
+ {
+ sprintf(message, "Number of bits to read is > 16: %d (ffgcxui)",
+ input_nbits);
+ ffpmsg(message);
+ return(*status = BAD_ELEM_NUM);
+ }
+
+ /* position to the correct HDU */
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+
+ /* rescan header if data structure is undefined */
+ else if ((fptr->Fptr)->datastart == DATA_UNDEFINED)
+ if ( ffrdef(fptr, status) > 0)
+ return(*status);
+
+ if ((fptr->Fptr)->hdutype != BINARY_TBL)
+ {
+ ffpmsg("This is not a binary table extension (ffgcxui)");
+ return(*status = NOT_BTABLE);
+ }
+
+ if (colnum > (fptr->Fptr)->tfield)
+ {
+ sprintf(message, "Specified column number is out of range: %d (ffgcxui)",
+ colnum);
+ ffpmsg(message);
+ sprintf(message, " There are %d columns in this table.",
+ (fptr->Fptr)->tfield );
+ ffpmsg(message);
+
+ return(*status = BAD_COL_NUM);
+ }
+
+ colptr = (fptr->Fptr)->tableptr; /* point to first column */
+ colptr += (colnum - 1); /* offset to correct column structure */
+
+ if (abs(colptr->tdatatype) > TBYTE)
+ {
+ ffpmsg("Can only read bits from X or B type columns. (ffgcxui)");
+ return(*status = NOT_LOGICAL_COL); /* not correct datatype column */
+ }
+
+ firstbyte = (input_first_bit - 1 ) / 8 + 1;
+ lastbyte = (input_first_bit + input_nbits - 2) / 8 + 1;
+ nbytes = lastbyte - firstbyte + 1;
+
+ if (colptr->tdatatype == TBIT &&
+ input_first_bit + input_nbits - 1 > (long) colptr->trepeat)
+ {
+ ffpmsg("Too many bits. Tried to read past width of column (ffgcxui)");
+ return(*status = BAD_ELEM_NUM);
+ }
+ else if (colptr->tdatatype == TBYTE && lastbyte > (long) colptr->trepeat)
+ {
+ ffpmsg("Too many bits. Tried to read past width of column (ffgcxui)");
+ return(*status = BAD_ELEM_NUM);
+ }
+
+ for (ii = 0; ii < nrows; ii++)
+ {
+ /* read the relevant bytes from the row */
+ if (ffgcvui(fptr, colnum, firstrow+ii, firstbyte, nbytes, 0,
+ colbyte, NULL, status) > 0)
+ {
+ ffpmsg("Error reading bytes from column (ffgcxui)");
+ return(*status);
+ }
+
+ firstbit = (input_first_bit - 1) % 8; /* modulus operator */
+ nbits = input_nbits;
+
+ array[ii] = 0;
+
+ /* select and shift the bits from each byte into the output word */
+ while(nbits)
+ {
+ bytenum = firstbit / 8;
+
+ startbit = firstbit % 8;
+ numbits = minvalue(nbits, 8 - startbit);
+ endbit = startbit + numbits - 1;
+
+ rshift = 7 - endbit;
+ lshift = nbits - numbits;
+
+ array[ii] = ((colbyte[bytenum] >> rshift) << lshift) | array[ii];
+
+ nbits -= numbits;
+ firstbit += numbits;
+ }
+ }
+
+ return(*status);
+}
+
+/*--------------------------------------------------------------------------*/
+int ffgcxuk(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to read (1 = 1st col) */
+ long firstrow, /* I - first row to read (1 = 1st row) */
+ long nrows, /* I - no. of rows to read */
+ long input_first_bit, /* I - first bit to read (1 = 1st) */
+ int input_nbits, /* I - number of bits to read (<= 32) */
+ unsigned int *array, /* O - array of integer values */
+ int *status) /* IO - error status */
+/*
+ Read a consecutive string of bits from an 'X' or 'B' column and
+ interprete them as an unsigned integer. The number of bits must be
+ less than or equal to 32 or the total number of bits in the column,
+ which ever is less.
+*/
+{
+ int ii, firstbit, nbits, bytenum, startbit, numbits, endbit;
+ int firstbyte, lastbyte, nbytes, rshift, lshift;
+ unsigned int colbyte[5];
+ tcolumn *colptr;
+ char message[81];
+
+ if (*status > 0 || nrows == 0)
+ return(*status);
+
+ /* check input parameters */
+ if (firstrow < 1)
+ {
+ sprintf(message, "Starting row number is less than 1: %ld (ffgcxuk)",
+ firstrow);
+ ffpmsg(message);
+ return(*status = BAD_ROW_NUM);
+ }
+ else if (input_first_bit < 1)
+ {
+ sprintf(message, "Starting bit number is less than 1: %ld (ffgcxuk)",
+ input_first_bit);
+ ffpmsg(message);
+ return(*status = BAD_ELEM_NUM);
+ }
+ else if (input_nbits > 32)
+ {
+ sprintf(message, "Number of bits to read is > 32: %d (ffgcxuk)",
+ input_nbits);
+ ffpmsg(message);
+ return(*status = BAD_ELEM_NUM);
+ }
+
+ /* position to the correct HDU */
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+
+ /* rescan header if data structure is undefined */
+ else if ((fptr->Fptr)->datastart == DATA_UNDEFINED)
+ if ( ffrdef(fptr, status) > 0)
+ return(*status);
+
+ if ((fptr->Fptr)->hdutype != BINARY_TBL)
+ {
+ ffpmsg("This is not a binary table extension (ffgcxuk)");
+ return(*status = NOT_BTABLE);
+ }
+
+ if (colnum > (fptr->Fptr)->tfield)
+ {
+ sprintf(message, "Specified column number is out of range: %d (ffgcxuk)",
+ colnum);
+ ffpmsg(message);
+ sprintf(message, " There are %d columns in this table.",
+ (fptr->Fptr)->tfield );
+ ffpmsg(message);
+
+ return(*status = BAD_COL_NUM);
+ }
+
+ colptr = (fptr->Fptr)->tableptr; /* point to first column */
+ colptr += (colnum - 1); /* offset to correct column structure */
+
+ if (abs(colptr->tdatatype) > TBYTE)
+ {
+ ffpmsg("Can only read bits from X or B type columns. (ffgcxuk)");
+ return(*status = NOT_LOGICAL_COL); /* not correct datatype column */
+ }
+
+ firstbyte = (input_first_bit - 1 ) / 8 + 1;
+ lastbyte = (input_first_bit + input_nbits - 2) / 8 + 1;
+ nbytes = lastbyte - firstbyte + 1;
+
+ if (colptr->tdatatype == TBIT &&
+ input_first_bit + input_nbits - 1 > (long) colptr->trepeat)
+ {
+ ffpmsg("Too many bits. Tried to read past width of column (ffgcxuk)");
+ return(*status = BAD_ELEM_NUM);
+ }
+ else if (colptr->tdatatype == TBYTE && lastbyte > (long) colptr->trepeat)
+ {
+ ffpmsg("Too many bits. Tried to read past width of column (ffgcxuk)");
+ return(*status = BAD_ELEM_NUM);
+ }
+
+ for (ii = 0; ii < nrows; ii++)
+ {
+ /* read the relevant bytes from the row */
+ if (ffgcvuk(fptr, colnum, firstrow+ii, firstbyte, nbytes, 0,
+ colbyte, NULL, status) > 0)
+ {
+ ffpmsg("Error reading bytes from column (ffgcxuk)");
+ return(*status);
+ }
+
+ firstbit = (input_first_bit - 1) % 8; /* modulus operator */
+ nbits = input_nbits;
+
+ array[ii] = 0;
+
+ /* select and shift the bits from each byte into the output word */
+ while(nbits)
+ {
+ bytenum = firstbit / 8;
+
+ startbit = firstbit % 8;
+ numbits = minvalue(nbits, 8 - startbit);
+ endbit = startbit + numbits - 1;
+
+ rshift = 7 - endbit;
+ lshift = nbits - numbits;
+
+ array[ii] = ((colbyte[bytenum] >> rshift) << lshift) | array[ii];
+
+ nbits -= numbits;
+ firstbit += numbits;
+ }
+ }
+
+ return(*status);
+}
diff --git a/pkg/tbtables/cfitsio/getcols.c b/pkg/tbtables/cfitsio/getcols.c
new file mode 100644
index 00000000..b3c25209
--- /dev/null
+++ b/pkg/tbtables/cfitsio/getcols.c
@@ -0,0 +1,743 @@
+/* This file, getcols.c, contains routines that read data elements from */
+/* a FITS image or table, with a character string datatype. */
+
+/* The FITSIO software was written by William Pence at the High Energy */
+/* Astrophysic Science Archive Research Center (HEASARC) at the NASA */
+/* Goddard Space Flight Center. */
+
+#include <stdlib.h>
+#include <string.h>
+/* stddef.h is apparently needed to define size_t */
+#include <stddef.h>
+#include <ctype.h>
+#include "fitsio2.h"
+/*--------------------------------------------------------------------------*/
+int ffgcvs( fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to read (1 = 1st col) */
+ long firstrow, /* I - first row to read (1 = 1st row) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of strings to read */
+ char *nulval, /* I - string for null pixels */
+ char **array, /* O - array of values that are read */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of string values from a column in the current FITS HDU.
+ Any undefined pixels will be set equal to the value of 'nulval' unless
+ nulval = null in which case no checks for undefined pixels will be made.
+*/
+{
+ char cdummy[2];
+
+ ffgcls(fptr, colnum, firstrow, firstelem, nelem, 1, nulval,
+ array, cdummy, anynul, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgcfs( fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to read (1 = 1st col) */
+ long firstrow, /* I - first row to read (1 = 1st row) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of strings to read */
+ char **array, /* O - array of values that are read */
+ char *nularray, /* O - array of flags = 1 if nultyp = 2 */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of string values from a column in the current FITS HDU.
+ Nularray will be set = 1 if the corresponding array pixel is undefined,
+ otherwise nularray will = 0.
+*/
+{
+ char dummy[2];
+
+ ffgcls(fptr, colnum, firstrow, firstelem, nelem, 2, dummy,
+ array, nularray, anynul, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgcls( fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to read (1 = 1st col) */
+ long firstrow, /* I - first row to read (1 = 1st row) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of strings to read */
+ int nultyp, /* I - null value handling code: */
+ /* 1: set undefined pixels = nulval */
+ /* 2: set nularray=1 for undefined pixels */
+ char *nulval, /* I - value for null pixels if nultyp = 1 */
+ char **array, /* O - array of values that are read */
+ char *nularray, /* O - array of flags = 1 if nultyp = 2 */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of string values from a column in the current FITS HDU.
+ Returns a formated string value, regardless of the datatype of the column
+*/
+{
+ int tcode, hdutype, tstatus, scaled, intcol, dwidth, nulwidth, ll;
+ long ii, jj;
+ tcolumn *colptr;
+ char message[FLEN_ERRMSG], *carray, keyname[FLEN_KEYWORD];
+ char cform[20], dispfmt[20], tmpstr[80];
+ unsigned char byteval;
+ float *earray;
+ double *darray, tscale = 1.0;
+
+ if (*status > 0 || nelem == 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ /* reset position to the correct HDU if necessary */
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+
+ /* rescan header if data structure is undefined */
+ else if ((fptr->Fptr)->datastart == DATA_UNDEFINED)
+ if ( ffrdef(fptr, status) > 0)
+ return(*status);
+
+ if (colnum < 1 || colnum > (fptr->Fptr)->tfield)
+ {
+ sprintf(message, "Specified column number is out of range: %d",
+ colnum);
+ ffpmsg(message);
+ return(*status = BAD_COL_NUM);
+ }
+
+ colptr = (fptr->Fptr)->tableptr; /* point to first column */
+ colptr += (colnum - 1); /* offset to correct column structure */
+ tcode = abs(colptr->tdatatype);
+
+ if (tcode == TSTRING)
+ {
+ /* simply call the string column reading routine */
+ ffgcls2(fptr, colnum, firstrow, firstelem, nelem, nultyp, nulval,
+ array, nularray, anynul, status);
+ }
+ else if (tcode == TLOGICAL)
+ {
+ /* allocate memory for the array of logical values */
+ carray = (char *) malloc(nelem);
+
+ /* call the logical column reading routine */
+ ffgcll(fptr, colnum, firstrow, firstelem, nelem, nultyp, *nulval,
+ carray, nularray, anynul, status);
+
+ if (*status <= 0)
+ {
+ /* convert logical values to "T", "F", or "N" (Null) */
+ for (ii = 0; ii < nelem; ii++)
+ {
+ if (carray[ii] == 1)
+ strcpy(array[ii], "T");
+ else if (carray[ii] == 0)
+ strcpy(array[ii], "F");
+ else /* undefined values = 2 */
+ strcpy(array[ii],"N");
+ }
+ }
+
+ free(carray); /* free the memory */
+ }
+ else if (tcode == TCOMPLEX)
+ {
+ /* allocate memory for the array of double values */
+ earray = (float *) calloc(nelem * 2, sizeof(float) );
+
+ ffgcle(fptr, colnum, firstrow, (firstelem - 1) * 2 + 1, nelem * 2,
+ 1, 1, FLOATNULLVALUE, earray, nularray, anynul, status);
+
+ if (*status <= 0)
+ {
+
+ /* determine the format for the output strings */
+
+ ffgcdw(fptr, colnum, &dwidth, status);
+ dwidth = (dwidth - 3) / 2;
+
+ /* use the TDISPn keyword if it exists */
+ ffkeyn("TDISP", colnum, keyname, status);
+ tstatus = 0;
+ cform[0] = '\0';
+
+ if (ffgkys(fptr, keyname, dispfmt, NULL, &tstatus) == 0)
+ {
+ /* convert the Fortran style format to a C style format */
+ ffcdsp(dispfmt, cform);
+ }
+
+ if (!cform[0])
+ strcpy(cform, "%14.6E");
+
+ /* write the formated string for each value: "(real,imag)" */
+ jj = 0;
+ for (ii = 0; ii < nelem; ii++)
+ {
+ strcpy(array[ii], "(");
+
+ /* test for null value */
+ if (earray[jj] == FLOATNULLVALUE)
+ {
+ strcpy(tmpstr, "NULL");
+ if (nultyp == 2)
+ nularray[ii] = 1;
+ }
+ else
+ sprintf(tmpstr, cform, earray[jj]);
+
+ strncat(array[ii], tmpstr, dwidth);
+ strcat(array[ii], ",");
+ jj++;
+
+ /* test for null value */
+ if (earray[jj] == FLOATNULLVALUE)
+ {
+ strcpy(tmpstr, "NULL");
+ if (nultyp == 2)
+ nularray[ii] = 1;
+ }
+ else
+ sprintf(tmpstr, cform, earray[jj]);
+
+ strncat(array[ii], tmpstr, dwidth);
+ strcat(array[ii], ")");
+ jj++;
+ }
+ }
+
+ free(earray); /* free the memory */
+ }
+ else if (tcode == TDBLCOMPLEX)
+ {
+ /* allocate memory for the array of double values */
+ darray = (double *) calloc(nelem * 2, sizeof(double) );
+
+ ffgcld(fptr, colnum, firstrow, (firstelem - 1) * 2 + 1, nelem * 2,
+ 1, 1, DOUBLENULLVALUE, darray, nularray, anynul, status);
+
+ if (*status <= 0)
+ {
+ /* determine the format for the output strings */
+
+ ffgcdw(fptr, colnum, &dwidth, status);
+ dwidth = (dwidth - 3) / 2;
+
+ /* use the TDISPn keyword if it exists */
+ ffkeyn("TDISP", colnum, keyname, status);
+ tstatus = 0;
+ cform[0] = '\0';
+
+ if (ffgkys(fptr, keyname, dispfmt, NULL, &tstatus) == 0)
+ {
+ /* convert the Fortran style format to a C style format */
+ ffcdsp(dispfmt, cform);
+ }
+
+ if (!cform[0])
+ strcpy(cform, "%23.15E");
+
+ /* write the formated string for each value: "(real,imag)" */
+ jj = 0;
+ for (ii = 0; ii < nelem; ii++)
+ {
+ strcpy(array[ii], "(");
+
+ /* test for null value */
+ if (darray[jj] == DOUBLENULLVALUE)
+ {
+ strcpy(tmpstr, "NULL");
+ if (nultyp == 2)
+ nularray[ii] = 1;
+ }
+ else
+ sprintf(tmpstr, cform, darray[jj]);
+
+ strncat(array[ii], tmpstr, dwidth);
+ strcat(array[ii], ",");
+ jj++;
+
+ /* test for null value */
+ if (darray[jj] == DOUBLENULLVALUE)
+ {
+ strcpy(tmpstr, "NULL");
+ if (nultyp == 2)
+ nularray[ii] = 1;
+ }
+ else
+ sprintf(tmpstr, cform, darray[jj]);
+
+ strncat(array[ii], tmpstr, dwidth);
+ strcat(array[ii], ")");
+ jj++;
+ }
+ }
+
+ free(darray); /* free the memory */
+ }
+ else
+ {
+ /* allocate memory for the array of double values */
+ darray = (double *) calloc(nelem, sizeof(double) );
+
+ /* read all other numeric type columns as doubles */
+ if (ffgcld(fptr, colnum, firstrow, firstelem, nelem, 1, nultyp,
+ DOUBLENULLVALUE, darray, nularray, anynul, status) > 0)
+ {
+ free(darray);
+ return(*status);
+ }
+
+ /* determine the format for the output strings */
+
+ ffgcdw(fptr, colnum, &dwidth, status);
+
+ /* check if column is scaled */
+ ffkeyn("TSCAL", colnum, keyname, status);
+ tstatus = 0;
+ scaled = 0;
+ if (ffgkyd(fptr, keyname, &tscale, NULL, &tstatus) == 0)
+ {
+ if (tscale != 1.0)
+ scaled = 1; /* yes, this is a scaled column */
+ }
+
+ intcol = 0;
+ if (tcode <= TLONG && !scaled)
+ intcol = 1; /* this is an unscaled integer column */
+
+ /* use the TDISPn keyword if it exists */
+ ffkeyn("TDISP", colnum, keyname, status);
+ tstatus = 0;
+ cform[0] = '\0';
+
+ if (ffgkys(fptr, keyname, dispfmt, NULL, &tstatus) == 0)
+ {
+ /* convert the Fortran style TDISPn to a C style format */
+ ffcdsp(dispfmt, cform);
+ }
+
+ if (!cform[0])
+ {
+ /* no TDISPn keyword; use TFORMn instead */
+
+ ffkeyn("TFORM", colnum, keyname, status);
+ ffgkys(fptr, keyname, dispfmt, NULL, status);
+
+ if (scaled && tcode <= TSHORT)
+ {
+ /* scaled short integer column == float */
+ strcpy(cform, "%#14.6G");
+ }
+ else if (scaled && tcode == TLONG)
+ {
+ /* scaled long integer column == double */
+ strcpy(cform, "%#23.15G");
+ }
+ else
+ {
+ ffghdt(fptr, &hdutype, status);
+ if (hdutype == ASCII_TBL)
+ {
+ /* convert the Fortran style TFORMn to a C style format */
+ ffcdsp(dispfmt, cform);
+ }
+ else
+ {
+ /* this is a binary table, need to convert the format */
+ if (tcode == TBIT) { /* 'X' */
+ strcpy(cform, "%4d");
+ } else if (tcode == TBYTE) { /* 'B' */
+ strcpy(cform, "%4d");
+ } else if (tcode == TSHORT) { /* 'I' */
+ strcpy(cform, "%6d");
+ } else if (tcode == TLONG) { /* 'J' */
+ strcpy(cform, "%11.0f");
+ intcol = 0; /* needed to support unsigned int */
+ } else if (tcode == TFLOAT) { /* 'E' */
+ strcpy(cform, "%#14.6G");
+ } else if (tcode == TDOUBLE) { /* 'D' */
+ strcpy(cform, "%#23.15G");
+ }
+ }
+ }
+ }
+
+ /* write the formated string for each value */
+ nulwidth = strlen(nulval);
+ for (ii = 0; ii < nelem; ii++)
+ {
+ if (tcode == TBIT)
+ {
+ byteval = (char) darray[ii];
+
+ for (ll=0; ll < 8; ll++)
+ {
+ if ( ((unsigned char) (byteval << ll)) >> 7 )
+ *(array[ii] + ll) = '1';
+ else
+ *(array[ii] + ll) = '0';
+ }
+ *(array[ii] + 8) = '\0';
+ }
+ /* test for null value */
+ else if ( (nultyp == 1 && darray[ii] == DOUBLENULLVALUE) ||
+ (nultyp == 2 && nularray[ii]) )
+ {
+ *array[ii] = '\0';
+ if (dwidth < nulwidth)
+ strncat(array[ii], nulval, dwidth);
+ else
+ sprintf(array[ii],"%*s",dwidth,nulval);
+ }
+ else
+ {
+ if (intcol)
+ sprintf(tmpstr, cform, (int) darray[ii]);
+ else
+ sprintf(tmpstr, cform, darray[ii]);
+
+ *array[ii] = '\0';
+ strncat(array[ii], tmpstr, dwidth);
+ }
+ }
+
+ free(darray); /* free the memory */
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgcdw( fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column (1 = 1st col) */
+ int *width, /* O - display width */
+ int *status) /* IO - error status */
+/*
+ Get Column Display Width.
+*/
+{
+ tcolumn *colptr;
+ char *cptr;
+ char message[FLEN_ERRMSG], keyname[FLEN_KEYWORD], dispfmt[20];
+ int tcode, hdutype, tstatus, scaled;
+ double tscale;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+
+ if (colnum < 1 || colnum > (fptr->Fptr)->tfield)
+ {
+ sprintf(message, "Specified column number is out of range: %d",
+ colnum);
+ ffpmsg(message);
+ return(*status = BAD_COL_NUM);
+ }
+
+ colptr = (fptr->Fptr)->tableptr; /* point to first column */
+ colptr += (colnum - 1); /* offset to correct column structure */
+ tcode = abs(colptr->tdatatype);
+
+ /* use the TDISPn keyword if it exists */
+ ffkeyn("TDISP", colnum, keyname, status);
+
+ *width = 0;
+ tstatus = 0;
+ if (ffgkys(fptr, keyname, dispfmt, NULL, &tstatus) == 0)
+ {
+ /* parse TDISPn get the display width */
+ cptr = dispfmt;
+ while(*cptr == ' ') /* skip leading blanks */
+ cptr++;
+
+ if (*cptr == 'A' || *cptr == 'a' ||
+ *cptr == 'I' || *cptr == 'i' ||
+ *cptr == 'O' || *cptr == 'o' ||
+ *cptr == 'Z' || *cptr == 'z' ||
+ *cptr == 'F' || *cptr == 'f' ||
+ *cptr == 'E' || *cptr == 'e' ||
+ *cptr == 'D' || *cptr == 'd' ||
+ *cptr == 'G' || *cptr == 'g')
+ {
+
+ while(!isdigit((int) *cptr) && *cptr != '\0') /* find 1st digit */
+ cptr++;
+
+ *width = atoi(cptr);
+ if (tcode >= TCOMPLEX)
+ *width = (2 * (*width)) + 3;
+ }
+ }
+
+ if (*width == 0)
+ {
+ /* no valid TDISPn keyword; use TFORMn instead */
+
+ ffkeyn("TFORM", colnum, keyname, status);
+ ffgkys(fptr, keyname, dispfmt, NULL, status);
+
+ /* check if column is scaled */
+ ffkeyn("TSCAL", colnum, keyname, status);
+ tstatus = 0;
+ scaled = 0;
+
+ if (ffgkyd(fptr, keyname, &tscale, NULL, &tstatus) == 0)
+ {
+ if (tscale != 1.0)
+ scaled = 1; /* yes, this is a scaled column */
+ }
+
+ if (scaled && tcode <= TSHORT)
+ {
+ /* scaled short integer col == float; default format is 14.6G */
+ *width = 14;
+ }
+ else if (scaled && tcode == TLONG)
+ {
+ /* scaled long integer col == double; default format is 23.15G */
+ *width = 23;
+ }
+ else
+ {
+ ffghdt(fptr, &hdutype, status); /* get type of table */
+ if (hdutype == ASCII_TBL)
+ {
+ /* parse TFORMn get the display width */
+ cptr = dispfmt;
+ while(!isdigit((int) *cptr) && *cptr != '\0') /* find 1st digit */
+ cptr++;
+
+ *width = atoi(cptr);
+ }
+ else
+ {
+ /* this is a binary table */
+ if (tcode == TBIT) /* 'X' */
+ *width = 8;
+ else if (tcode == TBYTE) /* 'B' */
+ *width = 4;
+ else if (tcode == TSHORT) /* 'I' */
+ *width = 6;
+ else if (tcode == TLONG) /* 'J' */
+ *width = 11;
+ else if (tcode == TFLOAT) /* 'E' */
+ *width = 14;
+ else if (tcode == TDOUBLE) /* 'D' */
+ *width = 23;
+ else if (tcode == TCOMPLEX) /* 'C' */
+ *width = 31;
+ else if (tcode == TDBLCOMPLEX) /* 'M' */
+ *width = 49;
+ else if (tcode == TLOGICAL) /* 'L' */
+ *width = 1;
+ else if (tcode == TSTRING) /* 'A' */
+ {
+ cptr = dispfmt;
+ while(!isdigit((int) *cptr) && *cptr != '\0')
+ cptr++;
+
+ *width = atoi(cptr);
+
+ if (*width < 1)
+ *width = 1; /* default is at least 1 column */
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgcls2 ( fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to read (1 = 1st col) */
+ long firstrow, /* I - first row to read (1 = 1st row) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of strings to read */
+ int nultyp, /* I - null value handling code: */
+ /* 1: set undefined pixels = nulval */
+ /* 2: set nularray=1 for undefined pixels */
+ char *nulval, /* I - value for null pixels if nultyp = 1 */
+ char **array, /* O - array of values that are read */
+ char *nularray, /* O - array of flags = 1 if nultyp = 2 */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of string values from a column in the current FITS HDU.
+*/
+{
+ long nullen;
+ int tcode, maxelem, hdutype, nulcheck;
+ long twidth, incre, rownum;
+ long ii, jj, ntodo, tnull, remain, next;
+ OFF_T repeat, startpos, elemnum, readptr, rowlen;
+ double scale, zero;
+ char tform[20];
+ char message[FLEN_ERRMSG];
+ char snull[20]; /* the FITS null value */
+ tcolumn *colptr;
+
+ double cbuff[DBUFFSIZE / sizeof(double)]; /* align cbuff on word boundary */
+ char *buffer, *arrayptr;
+
+ if (*status > 0 || nelem == 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+
+ if (anynul)
+ *anynul = 0;
+
+ if (nultyp == 2)
+ memset(nularray, 0, nelem); /* initialize nullarray */
+
+ /*---------------------------------------------------*/
+ /* Check input and get parameters about the column: */
+ /*---------------------------------------------------*/
+ if (colnum < 1 || colnum > (fptr->Fptr)->tfield)
+ {
+ sprintf(message, "Specified column number is out of range: %d",
+ colnum);
+ ffpmsg(message);
+ return(*status = BAD_COL_NUM);
+ }
+
+ colptr = (fptr->Fptr)->tableptr; /* point to first column */
+ colptr += (colnum - 1); /* offset to correct column structure */
+ tcode = colptr->tdatatype;
+
+ if (tcode == -TSTRING) /* variable length column in a binary table? */
+ {
+ /* only read a single string; ignore value of firstelem */
+
+ if (ffgcpr( fptr, colnum, firstrow, 1, 1, 0, &scale, &zero,
+ tform, &twidth, &tcode, &maxelem, &startpos, &elemnum, &incre,
+ &repeat, &rowlen, &hdutype, &tnull, snull, status) > 0)
+ return(*status);
+
+ remain = 1;
+ twidth = repeat;
+ }
+ else if (tcode == TSTRING)
+ {
+ if (ffgcpr( fptr, colnum, firstrow, firstelem, nelem, 0, &scale, &zero,
+ tform, &twidth, &tcode, &maxelem, &startpos, &elemnum, &incre,
+ &repeat, &rowlen, &hdutype, &tnull, snull, status) > 0)
+ return(*status);
+
+ remain = nelem;
+ }
+ else
+ return(*status = NOT_ASCII_COL);
+
+ nullen = strlen(snull); /* length of the undefined pixel string */
+ if (nullen == 0)
+ nullen = 1;
+
+ /*------------------------------------------------------------------*/
+ /* Decide whether to check for null values in the input FITS file: */
+ /*------------------------------------------------------------------*/
+ nulcheck = nultyp; /* by default check for null values in the FITS file */
+
+ if (nultyp == 1 && nulval[0] == 0)
+ nulcheck = 0; /* calling routine does not want to check for nulls */
+
+ else if (snull[0] == ASCII_NULL_UNDEFINED)
+ nulcheck = 0; /* null value string in ASCII table not defined */
+
+ else if (nullen > twidth)
+ nulcheck = 0; /* null value string is longer than width of column */
+ /* thus impossible for any column elements to = null */
+
+ /*---------------------------------------------------------------------*/
+ /* Now read the strings one at a time from the FITS column. */
+ /*---------------------------------------------------------------------*/
+ next = 0; /* next element in array to be read */
+ rownum = 0; /* row number, relative to firstrow */
+
+ while (remain)
+ {
+ /* limit the number of pixels to process a one time to the number that
+ will fit in the buffer space or to the number of pixels that remain
+ in the current vector, which ever is smaller.
+ */
+ ntodo = minvalue(remain, maxelem);
+ ntodo = minvalue(ntodo, (repeat - elemnum));
+
+ readptr = startpos + ((OFF_T)rownum * rowlen) + (elemnum * incre);
+ ffmbyt(fptr, readptr, REPORT_EOF, status); /* move to read position */
+
+ /* read the array of strings from the FITS file into the buffer */
+
+ if (incre == twidth)
+ ffgbyt(fptr, ntodo * twidth, cbuff, status);
+ else
+ ffgbytoff(fptr, twidth, ntodo, incre - twidth, cbuff, status);
+
+ /* copy from the buffer into the user's array of strings */
+ /* work backwards from last char of last string to 1st char of 1st */
+
+ buffer = ((char *) cbuff) + (ntodo * twidth) - 1;
+
+ for (ii = next + ntodo - 1; ii >= next; ii--)
+ {
+ arrayptr = array[ii] + twidth - 1;
+
+ for (jj = twidth - 1; jj > 0; jj--) /* ignore trailing blanks */
+ {
+ if (*buffer == ' ')
+ {
+ buffer--;
+ arrayptr--;
+ }
+ else
+ break;
+ }
+ *(arrayptr + 1) = 0; /* write the string terminator */
+
+ for (; jj >= 0; jj--) /* copy the string itself */
+ {
+ *arrayptr = *buffer;
+ buffer--;
+ arrayptr--;
+ }
+
+ /* check if null value is defined, and if the */
+ /* column string is identical to the null string */
+ if (nulcheck && !strncmp(snull, array[ii], nullen) )
+ {
+ *anynul = 1; /* this is a null value */
+ if (nultyp == 1)
+ strcpy(array[ii], nulval);
+ else
+ nularray[ii] = 1;
+ }
+ }
+
+ if (*status > 0) /* test for error during previous read operation */
+ {
+ sprintf(message,
+ "Error reading elements %ld thru %ld of data array (ffpcls).",
+ next+1, next+ntodo);
+
+ ffpmsg(message);
+ return(*status);
+ }
+
+ /*--------------------------------------------*/
+ /* increment the counters for the next loop */
+ /*--------------------------------------------*/
+ next += ntodo;
+ remain -= ntodo;
+ if (remain)
+ {
+ elemnum += ntodo;
+ if (elemnum == repeat) /* completed a row; start on next row */
+ {
+ elemnum = 0;
+ rownum++;
+ }
+ }
+ } /* End of main while Loop */
+
+ return(*status);
+}
+
diff --git a/pkg/tbtables/cfitsio/getcolsb.c b/pkg/tbtables/cfitsio/getcolsb.c
new file mode 100644
index 00000000..b04c6795
--- /dev/null
+++ b/pkg/tbtables/cfitsio/getcolsb.c
@@ -0,0 +1,2133 @@
+/* This file, getcolsb.c, contains routines that read data elements from */
+/* a FITS image or table, with signed char (signed byte) data type. */
+
+/* The FITSIO software was written by William Pence at the High Energy */
+/* Astrophysic Science Archive Research Center (HEASARC) at the NASA */
+/* Goddard Space Flight Center. */
+
+#include <math.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include "fitsio2.h"
+
+/*--------------------------------------------------------------------------*/
+int ffgpvsb(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to read (1 = 1st group) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ signed char nulval, /* I - value for undefined pixels */
+ signed char *array, /* O - array of values that are returned */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being read).
+ Undefined elements will be set equal to NULVAL, unless NULVAL=0
+ in which case no checking for undefined values will be performed.
+ ANYNUL is returned with a value of .true. if any pixels are undefined.
+*/
+{
+ long row;
+ char cdummy;
+ int nullcheck = 1;
+ signed char nullvalue;
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+ nullvalue = nulval; /* set local variable */
+
+ fits_read_compressed_pixels(fptr, TSBYTE, firstelem, nelem,
+ nullcheck, &nullvalue, array, NULL, anynul, status);
+ return(*status);
+ }
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ row=maxvalue(1,group);
+
+ ffgclsb(fptr, 2, row, firstelem, nelem, 1, 1, nulval,
+ array, &cdummy, anynul, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgpfsb(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to read (1 = 1st group) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ signed char *array, /* O - array of values that are returned */
+ char *nularray, /* O - array of null pixel flags */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being read).
+ Any undefined pixels in the returned array will be set = 0 and the
+ corresponding nularray value will be set = 1.
+ ANYNUL is returned with a value of .true. if any pixels are undefined.
+*/
+{
+ long row;
+ int nullcheck = 2;
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ fits_read_compressed_pixels(fptr, TSBYTE, firstelem, nelem,
+ nullcheck, NULL, array, nularray, anynul, status);
+ return(*status);
+ }
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ row=maxvalue(1,group);
+
+ ffgclsb(fptr, 2, row, firstelem, nelem, 1, 2, 0,
+ array, nularray, anynul, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffg2dsb(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to read (1 = 1st group) */
+ signed char nulval, /* set undefined pixels equal to this */
+ long ncols, /* I - number of pixels in each row of array */
+ long naxis1, /* I - FITS image NAXIS1 value */
+ long naxis2, /* I - FITS image NAXIS2 value */
+ signed char *array, /* O - array to be filled and returned */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an entire 2-D array of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of the
+ FITS array is not the same as the array being read). Any null
+ values in the array will be set equal to the value of nulval, unless
+ nulval = 0 in which case no null checking will be performed.
+*/
+{
+ /* call the 3D reading routine, with the 3rd dimension = 1 */
+
+ ffg3dsb(fptr, group, nulval, ncols, naxis2, naxis1, naxis2, 1, array,
+ anynul, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffg3dsb(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to read (1 = 1st group) */
+ signed char nulval, /* set undefined pixels equal to this */
+ long ncols, /* I - number of pixels in each row of array */
+ long nrows, /* I - number of rows in each plane of array */
+ long naxis1, /* I - FITS image NAXIS1 value */
+ long naxis2, /* I - FITS image NAXIS2 value */
+ long naxis3, /* I - FITS image NAXIS3 value */
+ signed char *array, /* O - array to be filled and returned */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an entire 3-D array of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of the
+ FITS array is not the same as the array being read). Any null
+ values in the array will be set equal to the value of nulval, unless
+ nulval = 0 in which case no null checking will be performed.
+*/
+{
+ long tablerow, nfits, narray, ii, jj;
+ char cdummy;
+ int nullcheck = 1;
+ long inc[] = {1,1,1};
+ long fpixel[] = {1,1,1};
+ long lpixel[3];
+ signed char nullvalue;
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ lpixel[0] = ncols;
+ lpixel[1] = nrows;
+ lpixel[2] = naxis3;
+ nullvalue = nulval; /* set local variable */
+
+ fits_read_compressed_img(fptr, TSBYTE, fpixel, lpixel, inc,
+ nullcheck, &nullvalue, array, NULL, anynul, status);
+ return(*status);
+ }
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+ tablerow=maxvalue(1,group);
+
+ if (ncols == naxis1 && nrows == naxis2) /* arrays have same size? */
+ {
+ /* all the image pixels are contiguous, so read all at once */
+ ffgclsb(fptr, 2, tablerow, 1, naxis1 * naxis2 * naxis3, 1, 1, nulval,
+ array, &cdummy, anynul, status);
+ return(*status);
+ }
+
+ if (ncols < naxis1 || nrows < naxis2)
+ return(*status = BAD_DIMEN);
+
+ nfits = 1; /* next pixel in FITS image to read */
+ narray = 0; /* next pixel in output array to be filled */
+
+ /* loop over naxis3 planes in the data cube */
+ for (jj = 0; jj < naxis3; jj++)
+ {
+ /* loop over the naxis2 rows in the FITS image, */
+ /* reading naxis1 pixels to each row */
+
+ for (ii = 0; ii < naxis2; ii++)
+ {
+ if (ffgclsb(fptr, 2, tablerow, nfits, naxis1, 1, 1, nulval,
+ &array[narray], &cdummy, anynul, status) > 0)
+ return(*status);
+
+ nfits += naxis1;
+ narray += ncols;
+ }
+ narray += (nrows - naxis2) * ncols;
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgsvsb(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of the column to read (1 = 1st) */
+ int naxis, /* I - number of dimensions in the FITS array */
+ long *naxes, /* I - size of each dimension */
+ long *blc, /* I - 'bottom left corner' of the subsection */
+ long *trc, /* I - 'top right corner' of the subsection */
+ long *inc, /* I - increment to be applied in each dimension */
+ signed char nulval, /* I - value to set undefined pixels */
+ signed char *array, /* O - array to be filled and returned */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read a subsection of data values from an image or a table column.
+ This routine is set up to handle a maximum of nine dimensions.
+*/
+{
+ long ii, i0, i1, i2, i3, i4, i5, i6, i7, i8, row, rstr, rstp, rinc;
+ long str[9], stp[9], incr[9], dir[9];
+ long nelem, nultyp, ninc, numcol;
+ OFF_T felem, dsize[10];
+ int hdutype, anyf;
+ char ldummy, msg[FLEN_ERRMSG];
+ int nullcheck = 1;
+ signed char nullvalue;
+
+ if (naxis < 1 || naxis > 9)
+ {
+ sprintf(msg, "NAXIS = %d in call to ffgsvsb is out of range", naxis);
+ ffpmsg(msg);
+ return(*status = BAD_DIMEN);
+ }
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ nullvalue = nulval; /* set local variable */
+
+ fits_read_compressed_img(fptr, TSBYTE, blc, trc, inc,
+ nullcheck, &nullvalue, array, NULL, anynul, status);
+ return(*status);
+ }
+
+/*
+ if this is a primary array, then the input COLNUM parameter should
+ be interpreted as the row number, and we will alway read the image
+ data from column 2 (any group parameters are in column 1).
+*/
+ if (ffghdt(fptr, &hdutype, status) > 0)
+ return(*status);
+
+ if (hdutype == IMAGE_HDU)
+ {
+ /* this is a primary array, or image extension */
+ if (colnum == 0)
+ {
+ rstr = 1;
+ rstp = 1;
+ }
+ else
+ {
+ rstr = colnum;
+ rstp = colnum;
+ }
+ rinc = 1;
+ numcol = 2;
+ }
+ else
+ {
+ /* this is a table, so the row info is in the (naxis+1) elements */
+ rstr = blc[naxis];
+ rstp = trc[naxis];
+ rinc = inc[naxis];
+ numcol = colnum;
+ }
+
+ nultyp = 1;
+ if (anynul)
+ *anynul = FALSE;
+
+ i0 = 0;
+ for (ii = 0; ii < 9; ii++)
+ {
+ str[ii] = 1;
+ stp[ii] = 1;
+ incr[ii] = 1;
+ dsize[ii] = 1;
+ dir[ii] = 1;
+ }
+
+ for (ii = 0; ii < naxis; ii++)
+ {
+ if (trc[ii] < blc[ii])
+ {
+ if (hdutype == IMAGE_HDU)
+ {
+ dir[ii] = -1;
+ }
+ else
+ {
+ sprintf(msg, "ffgsvsb: illegal range specified for axis %ld", ii + 1);
+ ffpmsg(msg);
+ return(*status = BAD_PIX_NUM);
+ }
+ }
+
+ str[ii] = blc[ii];
+ stp[ii] = trc[ii];
+ incr[ii] = inc[ii];
+ dsize[ii + 1] = dsize[ii] * naxes[ii];
+ dsize[ii] = dsize[ii] * dir[ii];
+ }
+ dsize[naxis] = dsize[naxis] * dir[naxis];
+
+ if (naxis == 1 && naxes[0] == 1)
+ {
+ /* This is not a vector column, so read all the rows at once */
+ nelem = (rstp - rstr) / rinc + 1;
+ ninc = rinc;
+ rstp = rstr;
+ }
+ else
+ {
+ /* have to read each row individually, in all dimensions */
+ nelem = (stp[0]*dir[0] - str[0]*dir[0]) / inc[0] + 1;
+ ninc = incr[0] * dir[0];
+ }
+
+ for (row = rstr; row <= rstp; row += rinc)
+ {
+ for (i8 = str[8]*dir[8]; i8 <= stp[8]*dir[8]; i8 += incr[8])
+ {
+ for (i7 = str[7]*dir[7]; i7 <= stp[7]*dir[7]; i7 += incr[7])
+ {
+ for (i6 = str[6]*dir[6]; i6 <= stp[6]*dir[6]; i6 += incr[6])
+ {
+ for (i5 = str[5]*dir[5]; i5 <= stp[5]*dir[5]; i5 += incr[5])
+ {
+ for (i4 = str[4]*dir[4]; i4 <= stp[4]*dir[4]; i4 += incr[4])
+ {
+ for (i3 = str[3]*dir[3]; i3 <= stp[3]*dir[3]; i3 += incr[3])
+ {
+ for (i2 = str[2]*dir[2]; i2 <= stp[2]*dir[2]; i2 += incr[2])
+ {
+ for (i1 = str[1]*dir[1]; i1 <= stp[1]*dir[1]; i1 += incr[1])
+ {
+
+ felem=str[0] + (i1 - dir[1]) * dsize[1] + (i2 - dir[2]) * dsize[2] +
+ (i3 - dir[3]) * dsize[3] + (i4 - dir[4]) * dsize[4] +
+ (i5 - dir[5]) * dsize[5] + (i6 - dir[6]) * dsize[6] +
+ (i7 - dir[7]) * dsize[7] + (i8 - dir[8]) * dsize[8];
+
+ if ( ffgclsb(fptr, numcol, row, felem, nelem, ninc, nultyp,
+ nulval, &array[i0], &ldummy, &anyf, status) > 0)
+ return(*status);
+
+ if (anyf && anynul)
+ *anynul = TRUE;
+
+ i0 += nelem;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgsfsb(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of the column to read (1 = 1st) */
+ int naxis, /* I - number of dimensions in the FITS array */
+ long *naxes, /* I - size of each dimension */
+ long *blc, /* I - 'bottom left corner' of the subsection */
+ long *trc, /* I - 'top right corner' of the subsection */
+ long *inc, /* I - increment to be applied in each dimension */
+ signed char *array, /* O - array to be filled and returned */
+ char *flagval, /* O - set to 1 if corresponding value is null */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read a subsection of data values from an image or a table column.
+ This routine is set up to handle a maximum of nine dimensions.
+*/
+{
+ long ii,i0, i1,i2,i3,i4,i5,i6,i7,i8,row,rstr,rstp,rinc;
+ long str[9],stp[9],incr[9],dsize[10];
+ long felem, nelem, nultyp, ninc, numcol;
+ int hdutype, anyf;
+ signed char nulval = 0;
+ char msg[FLEN_ERRMSG];
+ int nullcheck = 2;
+
+ if (naxis < 1 || naxis > 9)
+ {
+ sprintf(msg, "NAXIS = %d in call to ffgsvsb is out of range", naxis);
+ ffpmsg(msg);
+ return(*status = BAD_DIMEN);
+ }
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ fits_read_compressed_img(fptr, TSBYTE, blc, trc, inc,
+ nullcheck, NULL, array, flagval, anynul, status);
+ return(*status);
+ }
+
+/*
+ if this is a primary array, then the input COLNUM parameter should
+ be interpreted as the row number, and we will alway read the image
+ data from column 2 (any group parameters are in column 1).
+*/
+ if (ffghdt(fptr, &hdutype, status) > 0)
+ return(*status);
+
+ if (hdutype == IMAGE_HDU)
+ {
+ /* this is a primary array, or image extension */
+ if (colnum == 0)
+ {
+ rstr = 1;
+ rstp = 1;
+ }
+ else
+ {
+ rstr = colnum;
+ rstp = colnum;
+ }
+ rinc = 1;
+ numcol = 2;
+ }
+ else
+ {
+ /* this is a table, so the row info is in the (naxis+1) elements */
+ rstr = blc[naxis];
+ rstp = trc[naxis];
+ rinc = inc[naxis];
+ numcol = colnum;
+ }
+
+ nultyp = 2;
+ if (anynul)
+ *anynul = FALSE;
+
+ i0 = 0;
+ for (ii = 0; ii < 9; ii++)
+ {
+ str[ii] = 1;
+ stp[ii] = 1;
+ incr[ii] = 1;
+ dsize[ii] = 1;
+ }
+
+ for (ii = 0; ii < naxis; ii++)
+ {
+ if (trc[ii] < blc[ii])
+ {
+ sprintf(msg, "ffgsvsb: illegal range specified for axis %ld", ii + 1);
+ ffpmsg(msg);
+ return(*status = BAD_PIX_NUM);
+ }
+
+ str[ii] = blc[ii];
+ stp[ii] = trc[ii];
+ incr[ii] = inc[ii];
+ dsize[ii + 1] = dsize[ii] * naxes[ii];
+ }
+
+ if (naxis == 1 && naxes[0] == 1)
+ {
+ /* This is not a vector column, so read all the rows at once */
+ nelem = (rstp - rstr) / rinc + 1;
+ ninc = rinc;
+ rstp = rstr;
+ }
+ else
+ {
+ /* have to read each row individually, in all dimensions */
+ nelem = (stp[0] - str[0]) / inc[0] + 1;
+ ninc = incr[0];
+ }
+
+ for (row = rstr; row <= rstp; row += rinc)
+ {
+ for (i8 = str[8]; i8 <= stp[8]; i8 += incr[8])
+ {
+ for (i7 = str[7]; i7 <= stp[7]; i7 += incr[7])
+ {
+ for (i6 = str[6]; i6 <= stp[6]; i6 += incr[6])
+ {
+ for (i5 = str[5]; i5 <= stp[5]; i5 += incr[5])
+ {
+ for (i4 = str[4]; i4 <= stp[4]; i4 += incr[4])
+ {
+ for (i3 = str[3]; i3 <= stp[3]; i3 += incr[3])
+ {
+ for (i2 = str[2]; i2 <= stp[2]; i2 += incr[2])
+ {
+ for (i1 = str[1]; i1 <= stp[1]; i1 += incr[1])
+ {
+ felem=str[0] + (i1 - 1) * dsize[1] + (i2 - 1) * dsize[2] +
+ (i3 - 1) * dsize[3] + (i4 - 1) * dsize[4] +
+ (i5 - 1) * dsize[5] + (i6 - 1) * dsize[6] +
+ (i7 - 1) * dsize[7] + (i8 - 1) * dsize[8];
+
+ if ( ffgclsb(fptr, numcol, row, felem, nelem, ninc, nultyp,
+ nulval, &array[i0], &flagval[i0], &anyf, status) > 0)
+ return(*status);
+
+ if (anyf && anynul)
+ *anynul = TRUE;
+
+ i0 += nelem;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffggpsb( fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to read (1 = 1st group) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ signed char *array, /* O - array of values that are returned */
+ int *status) /* IO - error status */
+/*
+ Read an array of group parameters from the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being read).
+*/
+{
+ long row;
+ int idummy;
+ char cdummy;
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ row=maxvalue(1,group);
+
+ ffgclsb(fptr, 1, row, firstelem, nelem, 1, 1, 0,
+ array, &cdummy, &idummy, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgcvsb(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to read (1 = 1st col) */
+ long firstrow, /* I - first row to read (1 = 1st row) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ signed char nulval, /* I - value for null pixels */
+ signed char *array, /* O - array of values that are read */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from a column in the current FITS HDU. Automatic
+ datatype conversion will be performed if the datatype of the column does not
+ match the datatype of the array parameter. The output values will be scaled
+ by the FITS TSCALn and TZEROn values if these values have been defined.
+ Any undefined pixels will be set equal to the value of 'nulval' unless
+ nulval = 0 in which case no checks for undefined pixels will be made.
+*/
+{
+ char cdummy;
+
+ ffgclsb(fptr, colnum, firstrow, firstelem, nelem, 1, 1, nulval,
+ array, &cdummy, anynul, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgcfsb(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to read (1 = 1st col) */
+ long firstrow, /* I - first row to read (1 = 1st row) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ signed char *array, /* O - array of values that are read */
+ char *nularray, /* O - array of flags: 1 if null pixel; else 0 */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from a column in the current FITS HDU. Automatic
+ datatype conversion will be performed if the datatype of the column does not
+ match the datatype of the array parameter. The output values will be scaled
+ by the FITS TSCALn and TZEROn values if these values have been defined.
+ Nularray will be set = 1 if the corresponding array pixel is undefined,
+ otherwise nularray will = 0.
+*/
+{
+ signed char dummy = 0;
+
+ ffgclsb(fptr, colnum, firstrow, firstelem, nelem, 1, 2, dummy,
+ array, nularray, anynul, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgclsb(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to read (1 = 1st col) */
+ long firstrow, /* I - first row to read (1 = 1st row) */
+ OFF_T firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ long elemincre, /* I - pixel increment; e.g., 2 = every other */
+ int nultyp, /* I - null value handling code: */
+ /* 1: set undefined pixels = nulval */
+ /* 2: set nularray=1 for undefined pixels */
+ signed char nulval, /* I - value for null pixels if nultyp = 1 */
+ signed char *array, /* O - array of values that are read */
+ char *nularray, /* O - array of flags = 1 if nultyp = 2 */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from a column in the current FITS HDU.
+ The column number may refer to a real column in an ASCII or binary table,
+ or it may refer be a virtual column in a 1 or more grouped FITS primary
+ array or image extension. FITSIO treats a primary array as a binary table
+ with 2 vector columns: the first column contains the group parameters (often
+ with length = 0) and the second column contains the array of image pixels.
+ Each row of the table represents a group in the case of multigroup FITS
+ images.
+
+ The output array of values will be converted from the datatype of the column
+ and will be scaled by the FITS TSCALn and TZEROn values if necessary.
+*/
+{
+ double scale, zero, power = 1.;
+ int tcode, maxelem, hdutype, xcode, decimals;
+ long twidth, incre, rownum, remain, next, ntodo;
+ long ii, rowincre, tnull, xwidth;
+ int nulcheck, readcheck = 0;
+ OFF_T repeat, startpos, elemnum, readptr, rowlen;
+ char tform[20];
+ char message[81];
+ char snull[20]; /* the FITS null value if reading from ASCII table */
+
+ double cbuff[DBUFFSIZE / sizeof(double)]; /* align cbuff on word boundary */
+ void *buffer;
+
+ union u_tag {
+ char charval;
+ signed char scharval;
+ } u;
+
+ if (*status > 0 || nelem == 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ buffer = cbuff;
+
+ if (anynul)
+ *anynul = 0;
+
+ if (nultyp == 2)
+ memset(nularray, 0, nelem); /* initialize nullarray */
+
+ /*---------------------------------------------------*/
+ /* Check input and get parameters about the column: */
+ /*---------------------------------------------------*/
+ if (elemincre < 0)
+ readcheck = -1; /* don't do range checking in this case */
+
+ ffgcpr( fptr, colnum, firstrow, firstelem, nelem, readcheck, &scale, &zero,
+ tform, &twidth, &tcode, &maxelem, &startpos, &elemnum, &incre,
+ &repeat, &rowlen, &hdutype, &tnull, snull, status);
+
+ /* special case: read column of T/F logicals */
+ if (tcode == TLOGICAL && elemincre == 1)
+ {
+ u.scharval = nulval;
+ ffgcll(fptr, colnum, firstrow, firstelem, nelem, nultyp,
+ u.charval, (char *) array, nularray, anynul, status);
+
+ return(*status);
+ }
+
+ if (strchr(tform,'A') != NULL)
+ {
+ if (*status == BAD_ELEM_NUM)
+ {
+ /* ignore this error message */
+ *status = 0;
+ ffcmsg(); /* clear error stack */
+ }
+
+ /* interpret a 'A' ASCII column as a 'B' byte column ('8A' == '8B') */
+ /* This is an undocumented 'feature' in CFITSIO */
+
+ /* we have to reset some of the values returned by ffgcpr */
+
+ tcode = TBYTE;
+ incre = 1; /* each element is 1 byte wide */
+ repeat = twidth; /* total no. of chars in the col */
+ twidth = 1; /* width of each element */
+ scale = 1.0; /* no scaling */
+ zero = 0.0;
+ tnull = NULL_UNDEFINED; /* don't test for nulls */
+ maxelem = DBUFFSIZE;
+ }
+
+ if (*status > 0)
+ return(*status);
+
+ incre *= elemincre; /* multiply incre to just get every nth pixel */
+
+ if (tcode == TSTRING && hdutype == ASCII_TBL) /* setup for ASCII tables */
+ {
+ /* get the number of implied decimal places if no explicit decmal point */
+ ffasfm(tform, &xcode, &xwidth, &decimals, status);
+ for(ii = 0; ii < decimals; ii++)
+ power *= 10.;
+ }
+ /*------------------------------------------------------------------*/
+ /* Decide whether to check for null values in the input FITS file: */
+ /*------------------------------------------------------------------*/
+ nulcheck = nultyp; /* by default, check for null values in the FITS file */
+
+ if (nultyp == 1 && nulval == 0)
+ nulcheck = 0; /* calling routine does not want to check for nulls */
+
+ else if (tcode%10 == 1 && /* if reading an integer column, and */
+ tnull == NULL_UNDEFINED) /* if a null value is not defined, */
+ nulcheck = 0; /* then do not check for null values. */
+
+ else if (tcode == TSHORT && (tnull > SHRT_MAX || tnull < SHRT_MIN) )
+ nulcheck = 0; /* Impossible null value */
+
+ else if (tcode == TBYTE && (tnull > 255 || tnull < 0) )
+ nulcheck = 0; /* Impossible null value */
+
+ else if (tcode == TSTRING && snull[0] == ASCII_NULL_UNDEFINED)
+ nulcheck = 0;
+
+ /*---------------------------------------------------------------------*/
+ /* Now read the pixels from the FITS column. If the column does not */
+ /* have the same datatype as the output array, then we have to read */
+ /* the raw values into a temporary buffer (of limited size). In */
+ /* the case of a vector colum read only 1 vector of values at a time */
+ /* then skip to the next row if more values need to be read. */
+ /* After reading the raw values, then call the fffXXYY routine to (1) */
+ /* test for undefined values, (2) convert the datatype if necessary, */
+ /* and (3) scale the values by the FITS TSCALn and TZEROn linear */
+ /* scaling parameters. */
+ /*---------------------------------------------------------------------*/
+ remain = nelem; /* remaining number of values to read */
+ next = 0; /* next element in array to be read */
+ rownum = 0; /* row number, relative to firstrow */
+
+ while (remain)
+ {
+ /* limit the number of pixels to read at one time to the number that
+ will fit in the buffer or to the number of pixels that remain in
+ the current vector, which ever is smaller.
+ */
+ ntodo = minvalue(remain, maxelem);
+ if (elemincre >= 0)
+ {
+ ntodo = minvalue(ntodo, ((repeat - elemnum - 1)/elemincre +1));
+ }
+ else
+ {
+ ntodo = minvalue(ntodo, (elemnum/(-elemincre) +1));
+ }
+
+ readptr = startpos + ((OFF_T)rownum * rowlen) + (elemnum * (incre / elemincre));
+
+ switch (tcode)
+ {
+ case (TBYTE):
+ ffgi1b(fptr, readptr, ntodo, incre, (unsigned char *) &array[next], status);
+ fffi1s1((unsigned char *)&array[next], ntodo, scale, zero,
+ nulcheck, (unsigned char) tnull, nulval, &nularray[next],
+ anynul, &array[next], status);
+ break;
+ case (TSHORT):
+ ffgi2b(fptr, readptr, ntodo, incre, (short *) buffer, status);
+ fffi2s1((short *) buffer, ntodo, scale, zero, nulcheck,
+ (short) tnull, nulval, &nularray[next], anynul,
+ &array[next], status);
+ break;
+ case (TLONG):
+ ffgi4b(fptr, readptr, ntodo, incre, (INT32BIT *) buffer,
+ status);
+ fffi4s1((INT32BIT *) buffer, ntodo, scale, zero, nulcheck,
+ (INT32BIT) tnull, nulval, &nularray[next], anynul,
+ &array[next], status);
+ break;
+ case (TLONGLONG):
+ ffgi8b(fptr, readptr, ntodo, incre, (long *) buffer, status);
+ fffi8s1( (LONGLONG *) buffer, ntodo, scale, zero,
+ nulcheck, (long) tnull, nulval, &nularray[next],
+ anynul, &array[next], status);
+ break;
+ case (TFLOAT):
+ ffgr4b(fptr, readptr, ntodo, incre, (float *) buffer, status);
+ fffr4s1((float *) buffer, ntodo, scale, zero, nulcheck,
+ nulval, &nularray[next], anynul,
+ &array[next], status);
+ break;
+ case (TDOUBLE):
+ ffgr8b(fptr, readptr, ntodo, incre, (double *) buffer, status);
+ fffr8s1((double *) buffer, ntodo, scale, zero, nulcheck,
+ nulval, &nularray[next], anynul,
+ &array[next], status);
+ break;
+ case (TSTRING):
+ ffmbyt(fptr, readptr, REPORT_EOF, status);
+
+ if (incre == twidth) /* contiguous bytes */
+ ffgbyt(fptr, ntodo * twidth, buffer, status);
+ else
+ ffgbytoff(fptr, twidth, ntodo, incre - twidth, buffer,
+ status);
+
+ /* interpret the string as an ASCII formated number */
+ fffstrs1((char *) buffer, ntodo, scale, zero, twidth, power,
+ nulcheck, snull, nulval, &nularray[next], anynul,
+ &array[next], status);
+ break;
+
+ default: /* error trap for invalid column format */
+ sprintf(message,
+ "Cannot read bytes from column %d which has format %s",
+ colnum, tform);
+ ffpmsg(message);
+ if (hdutype == ASCII_TBL)
+ return(*status = BAD_ATABLE_FORMAT);
+ else
+ return(*status = BAD_BTABLE_FORMAT);
+
+ } /* End of switch block */
+
+ /*-------------------------*/
+ /* Check for fatal error */
+ /*-------------------------*/
+ if (*status > 0) /* test for error during previous read operation */
+ {
+ if (hdutype > 0)
+ sprintf(message,
+ "Error reading elements %ld thru %ld from column %d (ffgclsb).",
+ next+1, next+ntodo, colnum);
+ else
+ sprintf(message,
+ "Error reading elements %ld thru %ld from image (ffgclsb).",
+ next+1, next+ntodo);
+
+ ffpmsg(message);
+ return(*status);
+ }
+
+ /*--------------------------------------------*/
+ /* increment the counters for the next loop */
+ /*--------------------------------------------*/
+ remain -= ntodo;
+ if (remain)
+ {
+ next += ntodo;
+ elemnum = elemnum + (ntodo * elemincre);
+
+ if (elemnum >= repeat) /* completed a row; start on later row */
+ {
+ rowincre = elemnum / repeat;
+ rownum += rowincre;
+ elemnum = elemnum - (rowincre * repeat);
+ }
+ else if (elemnum < 0) /* completed a row; start on a previous row */
+ {
+ rowincre = (-elemnum - 1) / repeat + 1;
+ rownum -= rowincre;
+ elemnum = (rowincre * repeat) + elemnum;
+ }
+ }
+ } /* End of main while Loop */
+
+
+ /*--------------------------------*/
+ /* check for numerical overflow */
+ /*--------------------------------*/
+ if (*status == OVERFLOW_ERR)
+ {
+ ffpmsg(
+ "Numerical overflow during type conversion while reading FITS data.");
+ *status = NUM_OVERFLOW;
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffi1s1(unsigned char *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ unsigned char tnull, /* I - value of FITS TNULLn keyword if any */
+ signed char nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ signed char *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to tnull. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == -128.)
+ {
+ /* Instead of subtracting 128, it is more efficient */
+ /* to just flip the sign bit with the XOR operator */
+
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = ( *(signed char *) &input[ii] ) ^ 0x80;
+ }
+ else if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] > 127)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 127;
+ }
+ else
+ output[ii] = (signed char) input[ii]; /* copy input */
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DSCHAR_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = -128;
+ }
+ else if (dvalue > DSCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 127;
+ }
+ else
+ output[ii] = (signed char) dvalue;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ if (scale == 1. && zero == -128.)
+ {
+ /* Instead of subtracting 128, it is more efficient */
+ /* to just flip the sign bit with the XOR operator */
+
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ output[ii] = ( *(signed char *) &input[ii] ) ^ 0x80;
+ }
+ }
+ else if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ output[ii] = (signed char) input[ii];
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DSCHAR_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = -128;
+ }
+ else if (dvalue > DSCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 127;
+ }
+ else
+ output[ii] = (signed char) dvalue;
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffi2s1(short *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ short tnull, /* I - value of FITS TNULLn keyword if any */
+ signed char nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ signed char *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to tnull. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] < -128)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = -128;
+ }
+ else if (input[ii] > 127)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 127;
+ }
+ else
+ output[ii] = (signed char) input[ii];
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DSCHAR_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = -128;
+ }
+ else if (dvalue > DSCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 127;
+ }
+ else
+ output[ii] = (signed char) dvalue;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+
+ else
+ {
+ if (input[ii] < -128)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = -128;
+ }
+ else if (input[ii] > 127)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 127;
+ }
+ else
+ output[ii] = (signed char) input[ii];
+ }
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DSCHAR_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = -128;
+ }
+ else if (dvalue > DSCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 127;
+ }
+ else
+ output[ii] = (signed char) dvalue;
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffi4s1(INT32BIT *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ INT32BIT tnull, /* I - value of FITS TNULLn keyword if any */
+ signed char nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ signed char *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to tnull. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] < -128)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = -128;
+ }
+ else if (input[ii] > 127)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 127;
+ }
+ else
+ output[ii] = (signed char) input[ii];
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DSCHAR_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = -128;
+ }
+ else if (dvalue > DSCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 127;
+ }
+ else
+ output[ii] = (signed char) dvalue;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ if (input[ii] < -128)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = -128;
+ }
+ else if (input[ii] > 127)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 127;
+ }
+ else
+ output[ii] = (signed char) input[ii];
+ }
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DSCHAR_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = -128;
+ }
+ else if (dvalue > DSCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 127;
+ }
+ else
+ output[ii] = (signed char) dvalue;
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffi8s1(LONGLONG *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ long tnull, /* I - value of FITS TNULLn keyword if any */
+ signed char nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ signed char *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to tnull. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+#if (LONGSIZE == 32) && (! defined HAVE_LONGLONG)
+
+ /* This block of code is only used in cases where there is */
+ /* no native 8-byte integer support. We have to interpret */
+ /* the corresponding pair of 4-byte integers which are */
+ /* are equivalent to the 8-byte integer. */
+
+ long ii,jj, kk;
+ double dvalue;
+ unsigned long *uinput;
+
+ uinput = (unsigned long *) input;
+
+#if BYTESWAPPED /* jj points to the most significant part of the 8-byte int */
+ jj = 1;
+ kk = 0;
+#else
+ jj = 0;
+ kk = 1;
+#endif
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++, jj += 2, kk += 2)
+ {
+ if (uinput[jj] & 0x80000000) /* negative number */
+ dvalue = (uinput[jj] ^ 0xffffffff) * -4294967296. -
+ (uinput[kk] ^ 0xffffffff) - 1.;
+ else /* positive number */
+ dvalue = uinput[jj] * 4294967296. + uinput[kk];
+
+ if (dvalue < DSCHAR_MIN )
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = -128;
+ }
+ else if (dvalue > DSCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 127;
+ }
+ else
+ output[ii] = (signed char) dvalue;
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++, jj += 2, kk += 2)
+ {
+ if (uinput[jj] & 0x80000000) /* negative number */
+ dvalue = ((uinput[jj] ^ 0xffffffff) * -4294967296. -
+ (uinput[kk] ^ 0xffffffff) - 1.) * scale + zero;
+ else /* positive number */
+ dvalue = (uinput[jj] * 4294967296. + uinput[kk])
+ * scale + zero;
+
+ if (dvalue < DSCHAR_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = -128;
+ }
+ else if (dvalue > DSCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 127;
+ }
+ else
+ output[ii] = (signed char) dvalue;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++, jj += 2, kk += 2)
+ {
+ if (uinput[jj] & 0x80000000) /* negative number */
+ dvalue = (uinput[jj] ^ 0xffffffff) * -4294967296. -
+ (uinput[kk] ^ 0xffffffff) - 1.;
+ else /* positive number */
+ dvalue = uinput[jj] * 4294967296. + uinput[kk];
+
+ if (dvalue == (double) tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ if (dvalue < DSCHAR_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = -128;
+ }
+ else if (dvalue > DSCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 127;
+ }
+ else
+ output[ii] = (signed char) dvalue;
+ }
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++, jj += 2, kk += 2)
+ {
+ if (uinput[jj] & 0x80000000) /* negative number */
+ dvalue = (uinput[jj] ^ 0xffffffff) * -4294967296. -
+ (uinput[kk] ^ 0xffffffff) - 1.;
+ else /* positive number */
+ dvalue = uinput[jj] * 4294967296. + uinput[kk];
+
+ if (dvalue == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ dvalue = dvalue * scale + zero;
+
+ if (dvalue < DSCHAR_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = -128;
+ }
+ else if (dvalue > DSCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 127;
+ }
+ else
+ output[ii] = (signed char) dvalue;
+ }
+ }
+ }
+ }
+
+#else
+
+ /* this block works on machines which support an 8-byte integer type */
+
+ long ii;
+ double dvalue;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] < -128)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = -128;
+ }
+ else if (input[ii] > 127)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 127;
+ }
+ else
+ output[ii] = (signed char) input[ii];
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DSCHAR_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = -128;
+ }
+ else if (dvalue > DSCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 127;
+ }
+ else
+ output[ii] = (signed char) dvalue;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ if (input[ii] < -128)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = -128;
+ }
+ else if (input[ii] > 127)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 127;
+ }
+ else
+ output[ii] = (signed char) input[ii];
+ }
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DSCHAR_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = -128;
+ }
+ else if (dvalue > DSCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 127;
+ }
+ else
+ output[ii] = (signed char) dvalue;
+ }
+ }
+ }
+ }
+
+#endif
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffr4s1(float *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ signed char nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ signed char *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to NaN. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ long ii;
+ double dvalue;
+ short *sptr, iret;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] < DSCHAR_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = -128;
+ }
+ else if (input[ii] > DSCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 127;
+ }
+ else
+ output[ii] = (signed char) input[ii];
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DSCHAR_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = -128;
+ }
+ else if (dvalue > DSCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 127;
+ }
+ else
+ output[ii] = (signed char) dvalue;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ sptr = (short *) input;
+
+#if BYTESWAPPED && MACHINE != VAXVMS && MACHINE != ALPHAVMS
+ sptr++; /* point to MSBs */
+#endif
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++, sptr += 2)
+ {
+ /* use redundant boolean logic in following statement */
+ /* to suppress irritating Borland compiler warning message */
+ if (0 != (iret = fnan(*sptr) ) ) /* test for NaN or underflow */
+ {
+ if (iret == 1) /* is it a NaN? */
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else /* it's an underflow */
+ output[ii] = 0;
+ }
+ else
+ {
+ if (input[ii] < DSCHAR_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = -128;
+ }
+ else if (input[ii] > DSCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 127;
+ }
+ else
+ output[ii] = (signed char) input[ii];
+ }
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++, sptr += 2)
+ {
+ if (0 != (iret = fnan(*sptr) ) ) /* test for NaN or underflow */
+ {
+ if (iret == 1) /* is it a NaN? */
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else /* it's an underflow */
+ {
+ if (zero < DSCHAR_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = -128;
+ }
+ else if (zero > DSCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 127;
+ }
+ else
+ output[ii] = (signed char) zero;
+ }
+ }
+ else
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DSCHAR_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = -128;
+ }
+ else if (dvalue > DSCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 127;
+ }
+ else
+ output[ii] = (signed char) dvalue;
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffr8s1(double *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ signed char nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ signed char *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to NaN. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ long ii;
+ double dvalue;
+ short *sptr, iret;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] < DSCHAR_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = -128;
+ }
+ else if (input[ii] > DSCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 127;
+ }
+ else
+ output[ii] = (signed char) input[ii];
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DSCHAR_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = -128;
+ }
+ else if (dvalue > DSCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 127;
+ }
+ else
+ output[ii] = (signed char) dvalue;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ sptr = (short *) input;
+
+#if BYTESWAPPED && MACHINE != VAXVMS && MACHINE != ALPHAVMS
+ sptr += 3; /* point to MSBs */
+#endif
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++, sptr += 4)
+ {
+ if (0 != (iret = dnan(*sptr)) ) /* test for NaN or underflow */
+ {
+ if (iret == 1) /* is it a NaN? */
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else /* it's an underflow */
+ output[ii] = 0;
+ }
+ else
+ {
+ if (input[ii] < DSCHAR_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = -128;
+ }
+ else if (input[ii] > DSCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 127;
+ }
+ else
+ output[ii] = (signed char) input[ii];
+ }
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++, sptr += 4)
+ {
+ if (0 != (iret = dnan(*sptr)) ) /* test for NaN or underflow */
+ {
+ if (iret == 1) /* is it a NaN? */
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else /* it's an underflow */
+ {
+ if (zero < DSCHAR_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = -128;
+ }
+ else if (zero > DSCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 127;
+ }
+ else
+ output[ii] = (signed char) zero;
+ }
+ }
+ else
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DSCHAR_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = -128;
+ }
+ else if (dvalue > DSCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 127;
+ }
+ else
+ output[ii] = (signed char) dvalue;
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffstrs1(char *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ long twidth, /* I - width of each substring of chars */
+ double implipower, /* I - power of 10 of implied decimal */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ char *snull, /* I - value of FITS null string, if any */
+ signed char nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ signed char *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file. Check
+ for null values and do scaling if required. The nullcheck code value
+ determines how any null values in the input array are treated. A null
+ value is an input pixel that is equal to snull. If nullcheck= 0, then
+ no special checking for nulls is performed. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ int nullen;
+ long ii;
+ double dvalue;
+ char *cstring, message[81];
+ char *cptr, *tpos;
+ char tempstore, chrzero = '0';
+ double val, power;
+ int exponent, sign, esign, decpt;
+
+ nullen = strlen(snull);
+ cptr = input; /* pointer to start of input string */
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ cstring = cptr;
+ /* temporarily insert a null terminator at end of the string */
+ tpos = cptr + twidth;
+ tempstore = *tpos;
+ *tpos = 0;
+
+ /* check if null value is defined, and if the */
+ /* column string is identical to the null string */
+ if (snull[0] != ASCII_NULL_UNDEFINED &&
+ !strncmp(snull, cptr, nullen) )
+ {
+ if (nullcheck)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ cptr += twidth;
+ }
+ else
+ {
+ /* value is not the null value, so decode it */
+ /* remove any embedded blank characters from the string */
+
+ decpt = 0;
+ sign = 1;
+ val = 0.;
+ power = 1.;
+ exponent = 0;
+ esign = 1;
+
+ while (*cptr == ' ') /* skip leading blanks */
+ cptr++;
+
+ if (*cptr == '-' || *cptr == '+') /* check for leading sign */
+ {
+ if (*cptr == '-')
+ sign = -1;
+
+ cptr++;
+
+ while (*cptr == ' ') /* skip blanks between sign and value */
+ cptr++;
+ }
+
+ while (*cptr >= '0' && *cptr <= '9')
+ {
+ val = val * 10. + *cptr - chrzero; /* accumulate the value */
+ cptr++;
+
+ while (*cptr == ' ') /* skip embedded blanks in the value */
+ cptr++;
+ }
+
+ if (*cptr == '.') /* check for decimal point */
+ {
+ decpt = 1;
+ cptr++;
+ while (*cptr == ' ') /* skip any blanks */
+ cptr++;
+
+ while (*cptr >= '0' && *cptr <= '9')
+ {
+ val = val * 10. + *cptr - chrzero; /* accumulate the value */
+ power = power * 10.;
+ cptr++;
+
+ while (*cptr == ' ') /* skip embedded blanks in the value */
+ cptr++;
+ }
+ }
+
+ if (*cptr == 'E' || *cptr == 'D') /* check for exponent */
+ {
+ cptr++;
+ while (*cptr == ' ') /* skip blanks */
+ cptr++;
+
+ if (*cptr == '-' || *cptr == '+') /* check for exponent sign */
+ {
+ if (*cptr == '-')
+ esign = -1;
+
+ cptr++;
+
+ while (*cptr == ' ') /* skip blanks between sign and exp */
+ cptr++;
+ }
+
+ while (*cptr >= '0' && *cptr <= '9')
+ {
+ exponent = exponent * 10 + *cptr - chrzero; /* accumulate exp */
+ cptr++;
+
+ while (*cptr == ' ') /* skip embedded blanks */
+ cptr++;
+ }
+ }
+
+ if (*cptr != 0) /* should end up at the null terminator */
+ {
+ sprintf(message, "Cannot read number from ASCII table");
+ ffpmsg(message);
+ sprintf(message, "Column field = %s.", cstring);
+ ffpmsg(message);
+ /* restore the char that was overwritten by the null */
+ *tpos = tempstore;
+ return(*status = BAD_C2D);
+ }
+
+ if (!decpt) /* if no explicit decimal, use implied */
+ power = implipower;
+
+ dvalue = (sign * val / power) * pow(10., (double) (esign * exponent));
+
+ dvalue = dvalue * scale + zero; /* apply the scaling */
+
+ if (dvalue < DSCHAR_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = -128;
+ }
+ else if (dvalue > DSCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 127;
+ }
+ else
+ output[ii] = (signed char) dvalue;
+ }
+ /* restore the char that was overwritten by the null */
+ *tpos = tempstore;
+ }
+ return(*status);
+}
diff --git a/pkg/tbtables/cfitsio/getcolui.c b/pkg/tbtables/cfitsio/getcolui.c
new file mode 100644
index 00000000..7852aa4c
--- /dev/null
+++ b/pkg/tbtables/cfitsio/getcolui.c
@@ -0,0 +1,2050 @@
+/* This file, getcolui.c, contains routines that read data elements from */
+/* a FITS image or table, with unsigned short datatype. */
+
+/* The FITSIO software was written by William Pence at the High Energy */
+/* Astrophysic Science Archive Research Center (HEASARC) at the NASA */
+/* Goddard Space Flight Center. */
+
+#include <math.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include "fitsio2.h"
+
+/*--------------------------------------------------------------------------*/
+int ffgpvui( fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to read (1 = 1st group) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ unsigned short nulval, /* I - value for undefined pixels */
+ unsigned short *array, /* O - array of values that are returned */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being read).
+ Undefined elements will be set equal to NULVAL, unless NULVAL=0
+ in which case no checking for undefined values will be performed.
+ ANYNUL is returned with a value of .true. if any pixels are undefined.
+*/
+{
+ long row;
+ char cdummy;
+ int nullcheck = 1;
+ unsigned short nullvalue;
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+ nullvalue = nulval; /* set local variable */
+
+ fits_read_compressed_pixels(fptr, TUSHORT, firstelem, nelem,
+ nullcheck, &nullvalue, array, NULL, anynul, status);
+ return(*status);
+ }
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ row=maxvalue(1,group);
+
+ ffgclui(fptr, 2, row, firstelem, nelem, 1, 1, nulval,
+ array, &cdummy, anynul, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgpfui( fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to read (1 = 1st group) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ unsigned short *array, /* O - array of values that are returned */
+ char *nularray, /* O - array of null pixel flags */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being read).
+ Any undefined pixels in the returned array will be set = 0 and the
+ corresponding nularray value will be set = 1.
+ ANYNUL is returned with a value of .true. if any pixels are undefined.
+*/
+{
+ long row;
+ int nullcheck = 2;
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ fits_read_compressed_pixels(fptr, TUSHORT, firstelem, nelem,
+ nullcheck, NULL, array, nularray, anynul, status);
+ return(*status);
+ }
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ row=maxvalue(1,group);
+
+ ffgclui(fptr, 2, row, firstelem, nelem, 1, 2, 0,
+ array, nularray, anynul, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffg2dui(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to read (1 = 1st group) */
+ unsigned short nulval, /* set undefined pixels equal to this */
+ long ncols, /* I - number of pixels in each row of array */
+ long naxis1, /* I - FITS image NAXIS1 value */
+ long naxis2, /* I - FITS image NAXIS2 value */
+ unsigned short *array, /* O - array to be filled and returned */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an entire 2-D array of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of the
+ FITS array is not the same as the array being read). Any null
+ values in the array will be set equal to the value of nulval, unless
+ nulval = 0 in which case no null checking will be performed.
+*/
+{
+ /* call the 3D reading routine, with the 3rd dimension = 1 */
+
+ ffg3dui(fptr, group, nulval, ncols, naxis2, naxis1, naxis2, 1, array,
+ anynul, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffg3dui(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to read (1 = 1st group) */
+ unsigned short nulval, /* set undefined pixels equal to this */
+ long ncols, /* I - number of pixels in each row of array */
+ long nrows, /* I - number of rows in each plane of array */
+ long naxis1, /* I - FITS image NAXIS1 value */
+ long naxis2, /* I - FITS image NAXIS2 value */
+ long naxis3, /* I - FITS image NAXIS3 value */
+ unsigned short *array, /* O - array to be filled and returned */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an entire 3-D array of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of the
+ FITS array is not the same as the array being read). Any null
+ values in the array will be set equal to the value of nulval, unless
+ nulval = 0 in which case no null checking will be performed.
+*/
+{
+ long tablerow, nfits, narray, ii, jj;
+ char cdummy;
+ int nullcheck = 1;
+ long inc[] = {1,1,1};
+ long fpixel[] = {1,1,1};
+ long lpixel[3];
+ unsigned short nullvalue;
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ lpixel[0] = ncols;
+ lpixel[1] = nrows;
+ lpixel[2] = naxis3;
+ nullvalue = nulval; /* set local variable */
+
+ fits_read_compressed_img(fptr, TUSHORT, fpixel, lpixel, inc,
+ nullcheck, &nullvalue, array, NULL, anynul, status);
+ return(*status);
+ }
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+ tablerow=maxvalue(1,group);
+
+ if (ncols == naxis1 && nrows == naxis2) /* arrays have same size? */
+ {
+ /* all the image pixels are contiguous, so read all at once */
+ ffgclui(fptr, 2, tablerow, 1, naxis1 * naxis2 * naxis3, 1, 1, nulval,
+ array, &cdummy, anynul, status);
+ return(*status);
+ }
+
+ if (ncols < naxis1 || nrows < naxis2)
+ return(*status = BAD_DIMEN);
+
+ nfits = 1; /* next pixel in FITS image to read */
+ narray = 0; /* next pixel in output array to be filled */
+
+ /* loop over naxis3 planes in the data cube */
+ for (jj = 0; jj < naxis3; jj++)
+ {
+ /* loop over the naxis2 rows in the FITS image, */
+ /* reading naxis1 pixels to each row */
+
+ for (ii = 0; ii < naxis2; ii++)
+ {
+ if (ffgclui(fptr, 2, tablerow, nfits, naxis1, 1, 1, nulval,
+ &array[narray], &cdummy, anynul, status) > 0)
+ return(*status);
+
+ nfits += naxis1;
+ narray += ncols;
+ }
+ narray += (nrows - naxis2) * ncols;
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgsvui(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of the column to read (1 = 1st) */
+ int naxis, /* I - number of dimensions in the FITS array */
+ long *naxes, /* I - size of each dimension */
+ long *blc, /* I - 'bottom left corner' of the subsection */
+ long *trc, /* I - 'top right corner' of the subsection */
+ long *inc, /* I - increment to be applied in each dimension */
+ unsigned short nulval, /* I - value to set undefined pixels */
+ unsigned short *array, /* O - array to be filled and returned */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read a subsection of data values from an image or a table column.
+ This routine is set up to handle a maximum of nine dimensions.
+*/
+{
+ long ii,i0, i1,i2,i3,i4,i5,i6,i7,i8,row,rstr,rstp,rinc;
+ long str[9],stp[9],incr[9];
+ long nelem, nultyp, ninc, numcol;
+ OFF_T felem, dsize[10];
+ int hdutype, anyf;
+ char ldummy, msg[FLEN_ERRMSG];
+ int nullcheck = 1;
+ unsigned short nullvalue;
+
+ if (naxis < 1 || naxis > 9)
+ {
+ sprintf(msg, "NAXIS = %d in call to ffgsvui is out of range", naxis);
+ ffpmsg(msg);
+ return(*status = BAD_DIMEN);
+ }
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ nullvalue = nulval; /* set local variable */
+
+ fits_read_compressed_img(fptr, TUSHORT, blc, trc, inc,
+ nullcheck, &nullvalue, array, NULL, anynul, status);
+ return(*status);
+ }
+
+/*
+ if this is a primary array, then the input COLNUM parameter should
+ be interpreted as the row number, and we will alway read the image
+ data from column 2 (any group parameters are in column 1).
+*/
+ if (ffghdt(fptr, &hdutype, status) > 0)
+ return(*status);
+
+ if (hdutype == IMAGE_HDU)
+ {
+ /* this is a primary array, or image extension */
+ if (colnum == 0)
+ {
+ rstr = 1;
+ rstp = 1;
+ }
+ else
+ {
+ rstr = colnum;
+ rstp = colnum;
+ }
+ rinc = 1;
+ numcol = 2;
+ }
+ else
+ {
+ /* this is a table, so the row info is in the (naxis+1) elements */
+ rstr = blc[naxis];
+ rstp = trc[naxis];
+ rinc = inc[naxis];
+ numcol = colnum;
+ }
+
+ nultyp = 1;
+ if (anynul)
+ *anynul = FALSE;
+
+ i0 = 0;
+ for (ii = 0; ii < 9; ii++)
+ {
+ str[ii] = 1;
+ stp[ii] = 1;
+ incr[ii] = 1;
+ dsize[ii] = 1;
+ }
+
+ for (ii = 0; ii < naxis; ii++)
+ {
+ if (trc[ii] < blc[ii])
+ {
+ sprintf(msg, "ffgsvui: illegal range specified for axis %ld", ii + 1);
+ ffpmsg(msg);
+ return(*status = BAD_PIX_NUM);
+ }
+
+ str[ii] = blc[ii];
+ stp[ii] = trc[ii];
+ incr[ii] = inc[ii];
+ dsize[ii + 1] = dsize[ii] * naxes[ii];
+ }
+
+ if (naxis == 1 && naxes[0] == 1)
+ {
+ /* This is not a vector column, so read all the rows at once */
+ nelem = (rstp - rstr) / rinc + 1;
+ ninc = rinc;
+ rstp = rstr;
+ }
+ else
+ {
+ /* have to read each row individually, in all dimensions */
+ nelem = (stp[0] - str[0]) / inc[0] + 1;
+ ninc = incr[0];
+ }
+
+ for (row = rstr; row <= rstp; row += rinc)
+ {
+ for (i8 = str[8]; i8 <= stp[8]; i8 += incr[8])
+ {
+ for (i7 = str[7]; i7 <= stp[7]; i7 += incr[7])
+ {
+ for (i6 = str[6]; i6 <= stp[6]; i6 += incr[6])
+ {
+ for (i5 = str[5]; i5 <= stp[5]; i5 += incr[5])
+ {
+ for (i4 = str[4]; i4 <= stp[4]; i4 += incr[4])
+ {
+ for (i3 = str[3]; i3 <= stp[3]; i3 += incr[3])
+ {
+ for (i2 = str[2]; i2 <= stp[2]; i2 += incr[2])
+ {
+ for (i1 = str[1]; i1 <= stp[1]; i1 += incr[1])
+ {
+ felem=str[0] + (i1 - 1) * dsize[1] + (i2 - 1) * dsize[2] +
+ (i3 - 1) * dsize[3] + (i4 - 1) * dsize[4] +
+ (i5 - 1) * dsize[5] + (i6 - 1) * dsize[6] +
+ (i7 - 1) * dsize[7] + (i8 - 1) * dsize[8];
+ if ( ffgclui(fptr, numcol, row, felem, nelem, ninc, nultyp,
+ nulval, &array[i0], &ldummy, &anyf, status) > 0)
+ return(*status);
+
+ if (anyf && anynul)
+ *anynul = TRUE;
+
+ i0 += nelem;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgsfui(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of the column to read (1 = 1st) */
+ int naxis, /* I - number of dimensions in the FITS array */
+ long *naxes, /* I - size of each dimension */
+ long *blc, /* I - 'bottom left corner' of the subsection */
+ long *trc, /* I - 'top right corner' of the subsection */
+ long *inc, /* I - increment to be applied in each dimension */
+ unsigned short *array, /* O - array to be filled and returned */
+ char *flagval, /* O - set to 1 if corresponding value is null */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read a subsection of data values from an image or a table column.
+ This routine is set up to handle a maximum of nine dimensions.
+*/
+{
+ long ii,i0, i1,i2,i3,i4,i5,i6,i7,i8,row,rstr,rstp,rinc;
+ long str[9],stp[9],incr[9],dsize[10];
+ long felem, nelem, nultyp, ninc, numcol;
+ int hdutype, anyf;
+ unsigned short nulval = 0;
+ char msg[FLEN_ERRMSG];
+ int nullcheck = 2;
+
+ if (naxis < 1 || naxis > 9)
+ {
+ sprintf(msg, "NAXIS = %d in call to ffgsvi is out of range", naxis);
+ ffpmsg(msg);
+ return(*status = BAD_DIMEN);
+ }
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ fits_read_compressed_img(fptr, TUSHORT, blc, trc, inc,
+ nullcheck, NULL, array, flagval, anynul, status);
+ return(*status);
+ }
+
+/*
+ if this is a primary array, then the input COLNUM parameter should
+ be interpreted as the row number, and we will alway read the image
+ data from column 2 (any group parameters are in column 1).
+*/
+ if (ffghdt(fptr, &hdutype, status) > 0)
+ return(*status);
+
+ if (hdutype == IMAGE_HDU)
+ {
+ /* this is a primary array, or image extension */
+ if (colnum == 0)
+ {
+ rstr = 1;
+ rstp = 1;
+ }
+ else
+ {
+ rstr = colnum;
+ rstp = colnum;
+ }
+ rinc = 1;
+ numcol = 2;
+ }
+ else
+ {
+ /* this is a table, so the row info is in the (naxis+1) elements */
+ rstr = blc[naxis];
+ rstp = trc[naxis];
+ rinc = inc[naxis];
+ numcol = colnum;
+ }
+
+ nultyp = 2;
+ if (anynul)
+ *anynul = FALSE;
+
+ i0 = 0;
+ for (ii = 0; ii < 9; ii++)
+ {
+ str[ii] = 1;
+ stp[ii] = 1;
+ incr[ii] = 1;
+ dsize[ii] = 1;
+ }
+
+ for (ii = 0; ii < naxis; ii++)
+ {
+ if (trc[ii] < blc[ii])
+ {
+ sprintf(msg, "ffgsvi: illegal range specified for axis %ld", ii + 1);
+ ffpmsg(msg);
+ return(*status = BAD_PIX_NUM);
+ }
+
+ str[ii] = blc[ii];
+ stp[ii] = trc[ii];
+ incr[ii] = inc[ii];
+ dsize[ii + 1] = dsize[ii] * naxes[ii];
+ }
+
+ if (naxis == 1 && naxes[0] == 1)
+ {
+ /* This is not a vector column, so read all the rows at once */
+ nelem = (rstp - rstr) / rinc + 1;
+ ninc = rinc;
+ rstp = rstr;
+ }
+ else
+ {
+ /* have to read each row individually, in all dimensions */
+ nelem = (stp[0] - str[0]) / inc[0] + 1;
+ ninc = incr[0];
+ }
+
+ for (row = rstr; row <= rstp; row += rinc)
+ {
+ for (i8 = str[8]; i8 <= stp[8]; i8 += incr[8])
+ {
+ for (i7 = str[7]; i7 <= stp[7]; i7 += incr[7])
+ {
+ for (i6 = str[6]; i6 <= stp[6]; i6 += incr[6])
+ {
+ for (i5 = str[5]; i5 <= stp[5]; i5 += incr[5])
+ {
+ for (i4 = str[4]; i4 <= stp[4]; i4 += incr[4])
+ {
+ for (i3 = str[3]; i3 <= stp[3]; i3 += incr[3])
+ {
+ for (i2 = str[2]; i2 <= stp[2]; i2 += incr[2])
+ {
+ for (i1 = str[1]; i1 <= stp[1]; i1 += incr[1])
+ {
+ felem=str[0] + (i1 - 1) * dsize[1] + (i2 - 1) * dsize[2] +
+ (i3 - 1) * dsize[3] + (i4 - 1) * dsize[4] +
+ (i5 - 1) * dsize[5] + (i6 - 1) * dsize[6] +
+ (i7 - 1) * dsize[7] + (i8 - 1) * dsize[8];
+
+ if ( ffgclui(fptr, numcol, row, felem, nelem, ninc, nultyp,
+ nulval, &array[i0], &flagval[i0], &anyf, status) > 0)
+ return(*status);
+
+ if (anyf && anynul)
+ *anynul = TRUE;
+
+ i0 += nelem;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffggpui( fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to read (1 = 1st group) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ unsigned short *array, /* O - array of values that are returned */
+ int *status) /* IO - error status */
+/*
+ Read an array of group parameters from the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being read).
+*/
+{
+ long row;
+ int idummy;
+ char cdummy;
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ row=maxvalue(1,group);
+
+ ffgclui(fptr, 1, row, firstelem, nelem, 1, 1, 0,
+ array, &cdummy, &idummy, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgcvui(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to read (1 = 1st col) */
+ long firstrow, /* I - first row to read (1 = 1st row) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ unsigned short nulval, /* I - value for null pixels */
+ unsigned short *array, /* O - array of values that are read */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from a column in the current FITS HDU. Automatic
+ datatype conversion will be performed if the datatype of the column does not
+ match the datatype of the array parameter. The output values will be scaled
+ by the FITS TSCALn and TZEROn values if these values have been defined.
+ Any undefined pixels will be set equal to the value of 'nulval' unless
+ nulval = 0 in which case no checks for undefined pixels will be made.
+*/
+{
+ char cdummy;
+
+ ffgclui(fptr, colnum, firstrow, firstelem, nelem, 1, 1, nulval,
+ array, &cdummy, anynul, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgcfui(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to read (1 = 1st col) */
+ long firstrow, /* I - first row to read (1 = 1st row) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ unsigned short *array, /* O - array of values that are read */
+ char *nularray, /* O - array of flags: 1 if null pixel; else 0 */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from a column in the current FITS HDU. Automatic
+ datatype conversion will be performed if the datatype of the column does not
+ match the datatype of the array parameter. The output values will be scaled
+ by the FITS TSCALn and TZEROn values if these values have been defined.
+ Nularray will be set = 1 if the corresponding array pixel is undefined,
+ otherwise nularray will = 0.
+*/
+{
+ unsigned short dummy = 0;
+
+ ffgclui(fptr, colnum, firstrow, firstelem, nelem, 1, 2, dummy,
+ array, nularray, anynul, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgclui( fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to read (1 = 1st col) */
+ long firstrow, /* I - first row to read (1 = 1st row) */
+ OFF_T firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ long elemincre, /* I - pixel increment; e.g., 2 = every other */
+ int nultyp, /* I - null value handling code: */
+ /* 1: set undefined pixels = nulval */
+ /* 2: set nularray=1 for undefined pixels */
+ unsigned short nulval, /* I - value for null pixels if nultyp = 1 */
+ unsigned short *array, /* O - array of values that are read */
+ char *nularray, /* O - array of flags = 1 if nultyp = 2 */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from a column in the current FITS HDU.
+ The column number may refer to a real column in an ASCII or binary table,
+ or it may refer be a virtual column in a 1 or more grouped FITS primary
+ array or image extension. FITSIO treats a primary array as a binary table
+ with 2 vector columns: the first column contains the group parameters (often
+ with length = 0) and the second column contains the array of image pixels.
+ Each row of the table represents a group in the case of multigroup FITS
+ images.
+
+ The output array of values will be converted from the datatype of the column
+ and will be scaled by the FITS TSCALn and TZEROn values if necessary.
+*/
+{
+ double scale, zero, power = 1.;
+ int tcode, maxelem, hdutype, xcode, decimals;
+ long twidth, incre, rownum, remain, next, ntodo;
+ long ii, rowincre, tnull, xwidth;
+ int nulcheck;
+ OFF_T repeat, startpos, elemnum, readptr, rowlen;
+ char tform[20];
+ char message[81];
+ char snull[20]; /* the FITS null value if reading from ASCII table */
+
+ double cbuff[DBUFFSIZE / sizeof(double)]; /* align cbuff on word boundary */
+ void *buffer;
+
+ if (*status > 0 || nelem == 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ buffer = cbuff;
+
+ if (anynul)
+ *anynul = 0;
+
+ if (nultyp == 2)
+ memset(nularray, 0, nelem); /* initialize nullarray */
+
+ /*---------------------------------------------------*/
+ /* Check input and get parameters about the column: */
+ /*---------------------------------------------------*/
+ if ( ffgcpr( fptr, colnum, firstrow, firstelem, nelem, 0, &scale, &zero,
+ tform, &twidth, &tcode, &maxelem, &startpos, &elemnum, &incre,
+ &repeat, &rowlen, &hdutype, &tnull, snull, status) > 0 )
+ return(*status);
+
+ incre *= elemincre; /* multiply incre to just get every nth pixel */
+
+ if (tcode == TSTRING) /* setup for ASCII tables */
+ {
+ /* get the number of implied decimal places if no explicit decmal point */
+ ffasfm(tform, &xcode, &xwidth, &decimals, status);
+ for(ii = 0; ii < decimals; ii++)
+ power *= 10.;
+ }
+ /*------------------------------------------------------------------*/
+ /* Decide whether to check for null values in the input FITS file: */
+ /*------------------------------------------------------------------*/
+ nulcheck = nultyp; /* by default check for null values in the FITS file */
+
+ if (nultyp == 1 && nulval == 0)
+ nulcheck = 0; /* calling routine does not want to check for nulls */
+
+ else if (tcode%10 == 1 && /* if reading an integer column, and */
+ tnull == NULL_UNDEFINED) /* if a null value is not defined, */
+ nulcheck = 0; /* then do not check for null values. */
+
+ else if (tcode == TSHORT && (tnull > SHRT_MAX || tnull < SHRT_MIN) )
+ nulcheck = 0; /* Impossible null value */
+
+ else if (tcode == TBYTE && (tnull > 255 || tnull < 0) )
+ nulcheck = 0; /* Impossible null value */
+
+ else if (tcode == TSTRING && snull[0] == ASCII_NULL_UNDEFINED)
+ nulcheck = 0;
+
+ /*----------------------------------------------------------------------*/
+ /* If FITS column and output data array have same datatype, then we do */
+ /* not need to use a temporary buffer to store intermediate datatype. */
+ /*----------------------------------------------------------------------*/
+ if (tcode == TSHORT) /* Special Case: */
+ { /* no type convertion required, so read */
+ maxelem = nelem; /* data directly into output buffer. */
+ }
+
+ /*---------------------------------------------------------------------*/
+ /* Now read the pixels from the FITS column. If the column does not */
+ /* have the same datatype as the output array, then we have to read */
+ /* the raw values into a temporary buffer (of limited size). In */
+ /* the case of a vector colum read only 1 vector of values at a time */
+ /* then skip to the next row if more values need to be read. */
+ /* After reading the raw values, then call the fffXXYY routine to (1) */
+ /* test for undefined values, (2) convert the datatype if necessary, */
+ /* and (3) scale the values by the FITS TSCALn and TZEROn linear */
+ /* scaling parameters. */
+ /*---------------------------------------------------------------------*/
+ remain = nelem; /* remaining number of values to read */
+ next = 0; /* next element in array to be read */
+ rownum = 0; /* row number, relative to firstrow */
+
+ while (remain)
+ {
+ /* limit the number of pixels to read at one time to the number that
+ will fit in the buffer or to the number of pixels that remain in
+ the current vector, which ever is smaller.
+ */
+ ntodo = minvalue(remain, maxelem);
+ ntodo = minvalue(ntodo, ((repeat - elemnum - 1)/elemincre +1));
+
+ readptr = startpos + ((OFF_T)rownum * rowlen) + (elemnum * (incre / elemincre));
+
+ switch (tcode)
+ {
+ case (TSHORT):
+ ffgi2b(fptr, readptr, ntodo, incre,
+ (short *) &array[next], status);
+ fffi2u2((short *) &array[next], ntodo, scale,
+ zero, nulcheck, (short) tnull, nulval, &nularray[next],
+ anynul, &array[next], status);
+ break;
+ case (TLONGLONG):
+
+ ffgi8b(fptr, readptr, ntodo, incre, (long *) buffer, status);
+ fffi8u2( (LONGLONG *) buffer, ntodo, scale, zero,
+ nulcheck, (long) tnull, nulval, &nularray[next],
+ anynul, &array[next], status);
+ break;
+ case (TBYTE):
+ ffgi1b(fptr, readptr, ntodo, incre, (unsigned char *) buffer,
+ status);
+ fffi1u2((unsigned char *) buffer, ntodo, scale, zero, nulcheck,
+ (unsigned char) tnull, nulval, &nularray[next], anynul,
+ &array[next], status);
+ break;
+ case (TLONG):
+ ffgi4b(fptr, readptr, ntodo, incre, (INT32BIT *) buffer,
+ status);
+ fffi4u2((INT32BIT *) buffer, ntodo, scale, zero, nulcheck,
+ (INT32BIT) tnull, nulval, &nularray[next], anynul,
+ &array[next], status);
+ break;
+ case (TFLOAT):
+ ffgr4b(fptr, readptr, ntodo, incre, (float *) buffer, status);
+ fffr4u2((float *) buffer, ntodo, scale, zero, nulcheck,
+ nulval, &nularray[next], anynul,
+ &array[next], status);
+ break;
+ case (TDOUBLE):
+ ffgr8b(fptr, readptr, ntodo, incre, (double *) buffer, status);
+ fffr8u2((double *) buffer, ntodo, scale, zero, nulcheck,
+ nulval, &nularray[next], anynul,
+ &array[next], status);
+ break;
+ case (TSTRING):
+ ffmbyt(fptr, readptr, REPORT_EOF, status);
+
+ if (incre == twidth) /* contiguous bytes */
+ ffgbyt(fptr, ntodo * twidth, buffer, status);
+ else
+ ffgbytoff(fptr, twidth, ntodo, incre - twidth, buffer,
+ status);
+
+ fffstru2((char *) buffer, ntodo, scale, zero, twidth, power,
+ nulcheck, snull, nulval, &nularray[next], anynul,
+ &array[next], status);
+ break;
+
+ default: /* error trap for invalid column format */
+ sprintf(message,
+ "Cannot read numbers from column %d which has format %s",
+ colnum, tform);
+ ffpmsg(message);
+ if (hdutype == ASCII_TBL)
+ return(*status = BAD_ATABLE_FORMAT);
+ else
+ return(*status = BAD_BTABLE_FORMAT);
+
+ } /* End of switch block */
+
+ /*-------------------------*/
+ /* Check for fatal error */
+ /*-------------------------*/
+ if (*status > 0) /* test for error during previous read operation */
+ {
+ if (hdutype > 0)
+ sprintf(message,
+ "Error reading elements %ld thru %ld from column %d (ffgclui).",
+ next+1, next+ntodo, colnum);
+ else
+ sprintf(message,
+ "Error reading elements %ld thru %ld from image (ffgclui).",
+ next+1, next+ntodo);
+
+ ffpmsg(message);
+ return(*status);
+ }
+
+ /*--------------------------------------------*/
+ /* increment the counters for the next loop */
+ /*--------------------------------------------*/
+ remain -= ntodo;
+ if (remain)
+ {
+ next += ntodo;
+ elemnum = elemnum + (ntodo * elemincre);
+
+ if (elemnum >= repeat) /* completed a row; start on later row */
+ {
+ rowincre = elemnum / repeat;
+ rownum += rowincre;
+ elemnum = elemnum - (rowincre * repeat);
+ }
+ }
+ } /* End of main while Loop */
+
+
+ /*--------------------------------*/
+ /* check for numerical overflow */
+ /*--------------------------------*/
+ if (*status == OVERFLOW_ERR)
+ {
+ ffpmsg(
+ "Numerical overflow during type conversion while reading FITS data.");
+ *status = NUM_OVERFLOW;
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffi1u2(unsigned char *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ unsigned char tnull, /* I - value of FITS TNULLn keyword if any */
+ unsigned short nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ unsigned short *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to tnull. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = (unsigned short) input[ii]; /* copy input */
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DUSHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DUSHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = USHRT_MAX;
+ }
+ else
+ output[ii] = (unsigned short) dvalue;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ output[ii] = (unsigned short) input[ii];
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DUSHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DUSHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = USHRT_MAX;
+ }
+ else
+ output[ii] = (unsigned short) dvalue;
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffi2u2(short *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ short tnull, /* I - value of FITS TNULLn keyword if any */
+ unsigned short nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ unsigned short *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to tnull. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 32768.)
+ {
+ /* Instead of adding 32768, it is more efficient */
+ /* to just flip the sign bit with the XOR operator */
+
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = ( *(unsigned short *) &input[ii] ) ^ 0x8000;
+ }
+ else if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] < 0)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else
+ output[ii] = (unsigned short) input[ii]; /* copy input */
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DUSHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DUSHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = USHRT_MAX;
+ }
+ else
+ output[ii] = (unsigned short) dvalue;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ if (scale == 1. && zero == 32768.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ output[ii] = ( *(unsigned short *) &input[ii] ) ^ 0x8000;
+ }
+ }
+ else if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else if (input[ii] < 0)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else
+ output[ii] = (unsigned short) input[ii]; /* copy input */
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DUSHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DUSHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = USHRT_MAX;
+ }
+ else
+ output[ii] = (unsigned short) dvalue;
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffi4u2(INT32BIT *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ INT32BIT tnull, /* I - value of FITS TNULLn keyword if any */
+ unsigned short nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ unsigned short *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to tnull. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] < 0)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (input[ii] > USHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = USHRT_MAX;
+ }
+ else
+ output[ii] = (unsigned short) input[ii];
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DUSHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DUSHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = USHRT_MAX;
+ }
+ else
+ output[ii] = (unsigned short) dvalue;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ if (input[ii] < 0)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (input[ii] > USHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = USHRT_MAX;
+ }
+ else
+ output[ii] = (unsigned short) input[ii];
+ }
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DUSHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DUSHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = USHRT_MAX;
+ }
+ else
+ output[ii] = (unsigned short) dvalue;
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffi8u2(LONGLONG *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ long tnull, /* I - value of FITS TNULLn keyword if any */
+ unsigned short nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ unsigned short *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to tnull. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+#if (LONGSIZE == 32) && (! defined HAVE_LONGLONG)
+
+ /* This block of code is only used in cases where there is */
+ /* no native 8-byte integer support. We have to interpret */
+ /* the corresponding pair of 4-byte integers which are */
+ /* are equivalent to the 8-byte integer. */
+
+ long ii,jj,kk;
+ double dvalue;
+ unsigned long *uinput;
+
+ uinput = (unsigned long *) input;
+
+#if BYTESWAPPED /* jj points to the most significant part of the 8-byte int */
+ jj = 1;
+ kk = 0;
+#else
+ jj = 0;
+ kk = 1;
+#endif
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++, jj += 2, kk += 2)
+ {
+ if (uinput[jj] & 0x80000000) /* negative number */
+ dvalue = (uinput[jj] ^ 0xffffffff) * -4294967296. -
+ (uinput[kk] ^ 0xffffffff) - 1.;
+ else /* positive number */
+ dvalue = uinput[jj] * 4294967296. + uinput[kk];
+
+ if (dvalue < DUSHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DUSHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = USHRT_MAX;
+ }
+ else
+ output[ii] = (unsigned short) dvalue;
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++, jj += 2, kk += 2)
+ {
+ if (uinput[jj] & 0x80000000) /* negative number */
+ dvalue = ((uinput[jj] ^ 0xffffffff) * -4294967296. -
+ (uinput[kk] ^ 0xffffffff) - 1.) * scale + zero;
+ else /* positive number */
+ dvalue = (uinput[jj] * 4294967296. + uinput[kk])
+ * scale + zero;
+
+ if (dvalue < DUSHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DUSHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = USHRT_MAX;
+ }
+ else
+ output[ii] = (unsigned short) dvalue;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++, jj += 2, kk += 2)
+ {
+ if (uinput[jj] & 0x80000000) /* negative number */
+ dvalue = (uinput[jj] ^ 0xffffffff) * -4294967296. -
+ (uinput[kk] ^ 0xffffffff) - 1.;
+ else /* positive number */
+ dvalue = uinput[jj] * 4294967296. + uinput[kk];
+
+ if (dvalue == (double) tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ if (dvalue < DUSHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DUSHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = USHRT_MAX;
+ }
+ else
+ output[ii] = (unsigned short) dvalue;
+ }
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++, jj += 2, kk += 2)
+ {
+ if (uinput[jj] & 0x80000000) /* negative number */
+ dvalue = (uinput[jj] ^ 0xffffffff) * -4294967296. -
+ (uinput[kk] ^ 0xffffffff) - 1.;
+ else /* positive number */
+ dvalue = uinput[jj] * 4294967296. + uinput[kk];
+
+ if (dvalue == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ dvalue = dvalue * scale + zero;
+
+ if (dvalue < DUSHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DUSHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = USHRT_MAX;
+ }
+ else
+ output[ii] = (unsigned short) dvalue;
+ }
+ }
+ }
+ }
+
+#else
+
+ /* this block works on machines which support an 8-byte integer type */
+
+ long ii;
+ double dvalue;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] < 0)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (input[ii] > USHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = USHRT_MAX;
+ }
+ else
+ output[ii] = (unsigned short) input[ii];
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DUSHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DUSHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = USHRT_MAX;
+ }
+ else
+ output[ii] = (unsigned short) dvalue;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ if (input[ii] < 0)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (input[ii] > USHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = USHRT_MAX;
+ }
+ else
+ output[ii] = (unsigned short) input[ii];
+ }
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DUSHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DUSHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = USHRT_MAX;
+ }
+ else
+ output[ii] = (unsigned short) dvalue;
+ }
+ }
+ }
+ }
+
+#endif
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffr4u2(float *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ unsigned short nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ unsigned short *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to NaN. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ long ii;
+ double dvalue;
+ short *sptr, iret;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] < DUSHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (input[ii] > DUSHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = USHRT_MAX;
+ }
+ else
+ output[ii] = (unsigned short) input[ii];
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DUSHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DUSHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = USHRT_MAX;
+ }
+ else
+ output[ii] = (unsigned short) dvalue;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ sptr = (short *) input;
+
+#if BYTESWAPPED && MACHINE != VAXVMS && MACHINE != ALPHAVMS
+ sptr++; /* point to MSBs */
+#endif
+
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++, sptr += 2)
+ {
+ if (0 != (iret = fnan(*sptr) ) ) /* test for NaN or underflow */
+ {
+ if (iret == 1) /* is it a NaN? */
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else /* it's an underflow */
+ output[ii] = 0;
+ }
+ else
+ {
+ if (input[ii] < DUSHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (input[ii] > DUSHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = USHRT_MAX;
+ }
+ else
+ output[ii] = (unsigned short) input[ii];
+ }
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++, sptr += 2)
+ {
+ if (0 != (iret = fnan(*sptr) ) ) /* test for NaN or underflow */
+ {
+ if (iret == 1) /* is it a NaN? */
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else /* it's an underflow */
+ {
+ if (zero < DUSHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (zero > DUSHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = USHRT_MAX;
+ }
+ else
+ output[ii] = (unsigned short) zero;
+ }
+ }
+ else
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DUSHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DUSHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = USHRT_MAX;
+ }
+ else
+ output[ii] = (unsigned short) dvalue;
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffr8u2(double *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ unsigned short nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ unsigned short *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to NaN. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ long ii;
+ double dvalue;
+ short *sptr, iret;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] < DUSHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (input[ii] > DUSHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = USHRT_MAX;
+ }
+ else
+ output[ii] = (unsigned short) input[ii];
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DUSHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DUSHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = USHRT_MAX;
+ }
+ else
+ output[ii] = (unsigned short) dvalue;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ sptr = (short *) input;
+
+#if BYTESWAPPED && MACHINE != VAXVMS && MACHINE != ALPHAVMS
+ sptr += 3; /* point to MSBs */
+#endif
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++, sptr += 4)
+ {
+ if (0 != (iret = dnan(*sptr)) ) /* test for NaN or underflow */
+ {
+ if (iret == 1) /* is it a NaN? */
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else /* it's an underflow */
+ output[ii] = 0;
+ }
+ else
+ {
+ if (input[ii] < DUSHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (input[ii] > DUSHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = USHRT_MAX;
+ }
+ else
+ output[ii] = (unsigned short) input[ii];
+ }
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++, sptr += 4)
+ {
+ if (0 != (iret = dnan(*sptr)) ) /* test for NaN or underflow */
+ {
+ if (iret == 1) /* is it a NaN? */
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else /* it's an underflow */
+ {
+ if (zero < DUSHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (zero > DUSHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = USHRT_MAX;
+ }
+ else
+ output[ii] = (unsigned short) zero;
+ }
+ }
+ else
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DUSHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DUSHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = USHRT_MAX;
+ }
+ else
+ output[ii] = (unsigned short) dvalue;
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffstru2(char *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ long twidth, /* I - width of each substring of chars */
+ double implipower, /* I - power of 10 of implied decimal */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ char *snull, /* I - value of FITS null string, if any */
+ unsigned short nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ unsigned short *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file. Check
+ for null values and do scaling if required. The nullcheck code value
+ determines how any null values in the input array are treated. A null
+ value is an input pixel that is equal to snull. If nullcheck= 0, then
+ no special checking for nulls is performed. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ int nullen;
+ long ii;
+ double dvalue;
+ char *cstring, message[81];
+ char *cptr, *tpos;
+ char tempstore, chrzero = '0';
+ double val, power;
+ int exponent, sign, esign, decpt;
+
+ nullen = strlen(snull);
+ cptr = input; /* pointer to start of input string */
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ cstring = cptr;
+ /* temporarily insert a null terminator at end of the string */
+ tpos = cptr + twidth;
+ tempstore = *tpos;
+ *tpos = 0;
+
+ /* check if null value is defined, and if the */
+ /* column string is identical to the null string */
+ if (snull[0] != ASCII_NULL_UNDEFINED &&
+ !strncmp(snull, cptr, nullen) )
+ {
+ if (nullcheck)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ cptr += twidth;
+ }
+ else
+ {
+ /* value is not the null value, so decode it */
+ /* remove any embedded blank characters from the string */
+
+ decpt = 0;
+ sign = 1;
+ val = 0.;
+ power = 1.;
+ exponent = 0;
+ esign = 1;
+
+ while (*cptr == ' ') /* skip leading blanks */
+ cptr++;
+
+ if (*cptr == '-' || *cptr == '+') /* check for leading sign */
+ {
+ if (*cptr == '-')
+ sign = -1;
+
+ cptr++;
+
+ while (*cptr == ' ') /* skip blanks between sign and value */
+ cptr++;
+ }
+
+ while (*cptr >= '0' && *cptr <= '9')
+ {
+ val = val * 10. + *cptr - chrzero; /* accumulate the value */
+ cptr++;
+
+ while (*cptr == ' ') /* skip embedded blanks in the value */
+ cptr++;
+ }
+
+ if (*cptr == '.') /* check for decimal point */
+ {
+ decpt = 1; /* set flag to show there was a decimal point */
+ cptr++;
+ while (*cptr == ' ') /* skip any blanks */
+ cptr++;
+
+ while (*cptr >= '0' && *cptr <= '9')
+ {
+ val = val * 10. + *cptr - chrzero; /* accumulate the value */
+ power = power * 10.;
+ cptr++;
+
+ while (*cptr == ' ') /* skip embedded blanks in the value */
+ cptr++;
+ }
+ }
+
+ if (*cptr == 'E' || *cptr == 'D') /* check for exponent */
+ {
+ cptr++;
+ while (*cptr == ' ') /* skip blanks */
+ cptr++;
+
+ if (*cptr == '-' || *cptr == '+') /* check for exponent sign */
+ {
+ if (*cptr == '-')
+ esign = -1;
+
+ cptr++;
+
+ while (*cptr == ' ') /* skip blanks between sign and exp */
+ cptr++;
+ }
+
+ while (*cptr >= '0' && *cptr <= '9')
+ {
+ exponent = exponent * 10 + *cptr - chrzero; /* accumulate exp */
+ cptr++;
+
+ while (*cptr == ' ') /* skip embedded blanks */
+ cptr++;
+ }
+ }
+
+ if (*cptr != 0) /* should end up at the null terminator */
+ {
+ sprintf(message, "Cannot read number from ASCII table");
+ ffpmsg(message);
+ sprintf(message, "Column field = %s.", cstring);
+ ffpmsg(message);
+ /* restore the char that was overwritten by the null */
+ *tpos = tempstore;
+ return(*status = BAD_C2D);
+ }
+
+ if (!decpt) /* if no explicit decimal, use implied */
+ power = implipower;
+
+ dvalue = (sign * val / power) * pow(10., (double) (esign * exponent));
+
+ dvalue = dvalue * scale + zero; /* apply the scaling */
+
+ if (dvalue < DUSHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DUSHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = USHRT_MAX;
+ }
+ else
+ output[ii] = (unsigned short) dvalue;
+ }
+ /* restore the char that was overwritten by the null */
+ *tpos = tempstore;
+ }
+ return(*status);
+}
diff --git a/pkg/tbtables/cfitsio/getcoluj.c b/pkg/tbtables/cfitsio/getcoluj.c
new file mode 100644
index 00000000..5cdf486c
--- /dev/null
+++ b/pkg/tbtables/cfitsio/getcoluj.c
@@ -0,0 +1,2044 @@
+/* This file, getcoluj.c, contains routines that read data elements from */
+/* a FITS image or table, with unsigned long data type. */
+
+/* The FITSIO software was written by William Pence at the High Energy */
+/* Astrophysic Science Archive Research Center (HEASARC) at the NASA */
+/* Goddard Space Flight Center. */
+
+#include <math.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include "fitsio2.h"
+
+/*--------------------------------------------------------------------------*/
+int ffgpvuj(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to read (1 = 1st group) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ unsigned long nulval, /* I - value for undefined pixels */
+ unsigned long *array, /* O - array of values that are returned */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being read).
+ Undefined elements will be set equal to NULVAL, unless NULVAL=0
+ in which case no checking for undefined values will be performed.
+ ANYNUL is returned with a value of .true. if any pixels are undefined.
+*/
+{
+ long row;
+ char cdummy;
+ int nullcheck = 1;
+ unsigned long nullvalue;
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+ nullvalue = nulval; /* set local variable */
+
+ fits_read_compressed_pixels(fptr, TULONG, firstelem, nelem,
+ nullcheck, &nullvalue, array, NULL, anynul, status);
+ return(*status);
+ }
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ row=maxvalue(1,group);
+
+ ffgcluj(fptr, 2, row, firstelem, nelem, 1, 1, nulval,
+ array, &cdummy, anynul, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgpfuj(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to read (1 = 1st group) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ unsigned long *array, /* O - array of values that are returned */
+ char *nularray, /* O - array of null pixel flags */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being read).
+ Any undefined pixels in the returned array will be set = 0 and the
+ corresponding nularray value will be set = 1.
+ ANYNUL is returned with a value of .true. if any pixels are undefined.
+*/
+{
+ long row;
+ int nullcheck = 2;
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ fits_read_compressed_pixels(fptr, TULONG, firstelem, nelem,
+ nullcheck, NULL, array, nularray, anynul, status);
+ return(*status);
+ }
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ row=maxvalue(1,group);
+
+ ffgcluj(fptr, 2, row, firstelem, nelem, 1, 2, 0L,
+ array, nularray, anynul, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffg2duj(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to read (1 = 1st group) */
+ unsigned long nulval, /* set undefined pixels equal to this */
+ long ncols, /* I - number of pixels in each row of array */
+ long naxis1, /* I - FITS image NAXIS1 value */
+ long naxis2, /* I - FITS image NAXIS2 value */
+ unsigned long *array, /* O - array to be filled and returned */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an entire 2-D array of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of the
+ FITS array is not the same as the array being read). Any null
+ values in the array will be set equal to the value of nulval, unless
+ nulval = 0 in which case no null checking will be performed.
+*/
+{
+ /* call the 3D reading routine, with the 3rd dimension = 1 */
+
+ ffg3duj(fptr, group, nulval, ncols, naxis2, naxis1, naxis2, 1, array,
+ anynul, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffg3duj(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to read (1 = 1st group) */
+ unsigned long nulval, /* set undefined pixels equal to this */
+ long ncols, /* I - number of pixels in each row of array */
+ long nrows, /* I - number of rows in each plane of array */
+ long naxis1, /* I - FITS image NAXIS1 value */
+ long naxis2, /* I - FITS image NAXIS2 value */
+ long naxis3, /* I - FITS image NAXIS3 value */
+ unsigned long *array, /* O - array to be filled and returned */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an entire 3-D array of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of the
+ FITS array is not the same as the array being read). Any null
+ values in the array will be set equal to the value of nulval, unless
+ nulval = 0 in which case no null checking will be performed.
+*/
+{
+ long tablerow, nfits, narray, ii, jj;
+ char cdummy;
+ int nullcheck = 1;
+ long inc[] = {1,1,1};
+ long fpixel[] = {1,1,1};
+ long lpixel[3];
+ unsigned long nullvalue;
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ lpixel[0] = ncols;
+ lpixel[1] = nrows;
+ lpixel[2] = naxis3;
+ nullvalue = nulval; /* set local variable */
+
+ fits_read_compressed_img(fptr, TULONG, fpixel, lpixel, inc,
+ nullcheck, &nullvalue, array, NULL, anynul, status);
+ return(*status);
+ }
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+ tablerow=maxvalue(1,group);
+
+ if (ncols == naxis1 && nrows == naxis2) /* arrays have same size? */
+ {
+ /* all the image pixels are contiguous, so read all at once */
+ ffgcluj(fptr, 2, tablerow, 1, naxis1 * naxis2 * naxis3, 1, 1, nulval,
+ array, &cdummy, anynul, status);
+ return(*status);
+ }
+
+ if (ncols < naxis1 || nrows < naxis2)
+ return(*status = BAD_DIMEN);
+
+ nfits = 1; /* next pixel in FITS image to read */
+ narray = 0; /* next pixel in output array to be filled */
+
+ /* loop over naxis3 planes in the data cube */
+ for (jj = 0; jj < naxis3; jj++)
+ {
+ /* loop over the naxis2 rows in the FITS image, */
+ /* reading naxis1 pixels to each row */
+
+ for (ii = 0; ii < naxis2; ii++)
+ {
+ if (ffgcluj(fptr, 2, tablerow, nfits, naxis1, 1, 1, nulval,
+ &array[narray], &cdummy, anynul, status) > 0)
+ return(*status);
+
+ nfits += naxis1;
+ narray += ncols;
+ }
+ narray += (nrows - naxis2) * ncols;
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgsvuj(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of the column to read (1 = 1st) */
+ int naxis, /* I - number of dimensions in the FITS array */
+ long *naxes, /* I - size of each dimension */
+ long *blc, /* I - 'bottom left corner' of the subsection */
+ long *trc, /* I - 'top right corner' of the subsection */
+ long *inc, /* I - increment to be applied in each dimension */
+ unsigned long nulval, /* I - value to set undefined pixels */
+ unsigned long *array, /* O - array to be filled and returned */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read a subsection of data values from an image or a table column.
+ This routine is set up to handle a maximum of nine dimensions.
+*/
+{
+ long ii,i0, i1,i2,i3,i4,i5,i6,i7,i8,row,rstr,rstp,rinc;
+ long str[9],stp[9],incr[9];
+ long nelem, nultyp, ninc, numcol;
+ OFF_T felem, dsize[10];
+ int hdutype, anyf;
+ char ldummy, msg[FLEN_ERRMSG];
+ int nullcheck = 1;
+ unsigned long nullvalue;
+
+ if (naxis < 1 || naxis > 9)
+ {
+ sprintf(msg, "NAXIS = %d in call to ffgsvuj is out of range", naxis);
+ ffpmsg(msg);
+ return(*status = BAD_DIMEN);
+ }
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ nullvalue = nulval; /* set local variable */
+
+ fits_read_compressed_img(fptr, TULONG, blc, trc, inc,
+ nullcheck, &nullvalue, array, NULL, anynul, status);
+ return(*status);
+ }
+
+/*
+ if this is a primary array, then the input COLNUM parameter should
+ be interpreted as the row number, and we will alway read the image
+ data from column 2 (any group parameters are in column 1).
+*/
+ if (ffghdt(fptr, &hdutype, status) > 0)
+ return(*status);
+
+ if (hdutype == IMAGE_HDU)
+ {
+ /* this is a primary array, or image extension */
+ if (colnum == 0)
+ {
+ rstr = 1;
+ rstp = 1;
+ }
+ else
+ {
+ rstr = colnum;
+ rstp = colnum;
+ }
+ rinc = 1;
+ numcol = 2;
+ }
+ else
+ {
+ /* this is a table, so the row info is in the (naxis+1) elements */
+ rstr = blc[naxis];
+ rstp = trc[naxis];
+ rinc = inc[naxis];
+ numcol = colnum;
+ }
+
+ nultyp = 1;
+ if (anynul)
+ *anynul = FALSE;
+
+ i0 = 0;
+ for (ii = 0; ii < 9; ii++)
+ {
+ str[ii] = 1;
+ stp[ii] = 1;
+ incr[ii] = 1;
+ dsize[ii] = 1;
+ }
+
+ for (ii = 0; ii < naxis; ii++)
+ {
+ if (trc[ii] < blc[ii])
+ {
+ sprintf(msg, "ffgsvuj: illegal range specified for axis %ld", ii + 1);
+ ffpmsg(msg);
+ return(*status = BAD_PIX_NUM);
+ }
+
+ str[ii] = blc[ii];
+ stp[ii] = trc[ii];
+ incr[ii] = inc[ii];
+ dsize[ii + 1] = dsize[ii] * naxes[ii];
+ }
+
+ if (naxis == 1 && naxes[0] == 1)
+ {
+ /* This is not a vector column, so read all the rows at once */
+ nelem = (rstp - rstr) / rinc + 1;
+ ninc = rinc;
+ rstp = rstr;
+ }
+ else
+ {
+ /* have to read each row individually, in all dimensions */
+ nelem = (stp[0] - str[0]) / inc[0] + 1;
+ ninc = incr[0];
+ }
+
+ for (row = rstr; row <= rstp; row += rinc)
+ {
+ for (i8 = str[8]; i8 <= stp[8]; i8 += incr[8])
+ {
+ for (i7 = str[7]; i7 <= stp[7]; i7 += incr[7])
+ {
+ for (i6 = str[6]; i6 <= stp[6]; i6 += incr[6])
+ {
+ for (i5 = str[5]; i5 <= stp[5]; i5 += incr[5])
+ {
+ for (i4 = str[4]; i4 <= stp[4]; i4 += incr[4])
+ {
+ for (i3 = str[3]; i3 <= stp[3]; i3 += incr[3])
+ {
+ for (i2 = str[2]; i2 <= stp[2]; i2 += incr[2])
+ {
+ for (i1 = str[1]; i1 <= stp[1]; i1 += incr[1])
+ {
+ felem=str[0] + (i1 - 1) * dsize[1] + (i2 - 1) * dsize[2] +
+ (i3 - 1) * dsize[3] + (i4 - 1) * dsize[4] +
+ (i5 - 1) * dsize[5] + (i6 - 1) * dsize[6] +
+ (i7 - 1) * dsize[7] + (i8 - 1) * dsize[8];
+
+ if ( ffgcluj(fptr, numcol, row, felem, nelem, ninc, nultyp,
+ nulval, &array[i0], &ldummy, &anyf, status) > 0)
+ return(*status);
+
+ if (anyf && anynul)
+ *anynul = TRUE;
+
+ i0 += nelem;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgsfuj(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of the column to read (1 = 1st) */
+ int naxis, /* I - number of dimensions in the FITS array */
+ long *naxes, /* I - size of each dimension */
+ long *blc, /* I - 'bottom left corner' of the subsection */
+ long *trc, /* I - 'top right corner' of the subsection */
+ long *inc, /* I - increment to be applied in each dimension */
+ unsigned long *array, /* O - array to be filled and returned */
+ char *flagval, /* O - set to 1 if corresponding value is null */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read a subsection of data values from an image or a table column.
+ This routine is set up to handle a maximum of nine dimensions.
+*/
+{
+ long ii,i0, i1,i2,i3,i4,i5,i6,i7,i8,row,rstr,rstp,rinc;
+ long str[9],stp[9],incr[9],dsize[10];
+ long felem, nelem, nultyp, ninc, numcol;
+ unsigned long nulval = 0;
+ int hdutype, anyf;
+ char msg[FLEN_ERRMSG];
+ int nullcheck = 2;
+
+ if (naxis < 1 || naxis > 9)
+ {
+ sprintf(msg, "NAXIS = %d in call to ffgsvj is out of range", naxis);
+ ffpmsg(msg);
+ return(*status = BAD_DIMEN);
+ }
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ fits_read_compressed_img(fptr, TULONG, blc, trc, inc,
+ nullcheck, NULL, array, flagval, anynul, status);
+ return(*status);
+ }
+
+/*
+ if this is a primary array, then the input COLNUM parameter should
+ be interpreted as the row number, and we will alway read the image
+ data from column 2 (any group parameters are in column 1).
+*/
+ if (ffghdt(fptr, &hdutype, status) > 0)
+ return(*status);
+
+ if (hdutype == IMAGE_HDU)
+ {
+ /* this is a primary array, or image extension */
+ if (colnum == 0)
+ {
+ rstr = 1;
+ rstp = 1;
+ }
+ else
+ {
+ rstr = colnum;
+ rstp = colnum;
+ }
+ rinc = 1;
+ numcol = 2;
+ }
+ else
+ {
+ /* this is a table, so the row info is in the (naxis+1) elements */
+ rstr = blc[naxis];
+ rstp = trc[naxis];
+ rinc = inc[naxis];
+ numcol = colnum;
+ }
+
+ nultyp = 2;
+ if (anynul)
+ *anynul = FALSE;
+
+ i0 = 0;
+ for (ii = 0; ii < 9; ii++)
+ {
+ str[ii] = 1;
+ stp[ii] = 1;
+ incr[ii] = 1;
+ dsize[ii] = 1;
+ }
+
+ for (ii = 0; ii < naxis; ii++)
+ {
+ if (trc[ii] < blc[ii])
+ {
+ sprintf(msg, "ffgsvj: illegal range specified for axis %ld", ii + 1);
+ ffpmsg(msg);
+ return(*status = BAD_PIX_NUM);
+ }
+
+ str[ii] = blc[ii];
+ stp[ii] = trc[ii];
+ incr[ii] = inc[ii];
+ dsize[ii + 1] = dsize[ii] * naxes[ii];
+ }
+
+ if (naxis == 1 && naxes[0] == 1)
+ {
+ /* This is not a vector column, so read all the rows at once */
+ nelem = (rstp - rstr) / rinc + 1;
+ ninc = rinc;
+ rstp = rstr;
+ }
+ else
+ {
+ /* have to read each row individually, in all dimensions */
+ nelem = (stp[0] - str[0]) / inc[0] + 1;
+ ninc = incr[0];
+ }
+
+ for (row = rstr; row <= rstp; row += rinc)
+ {
+ for (i8 = str[8]; i8 <= stp[8]; i8 += incr[8])
+ {
+ for (i7 = str[7]; i7 <= stp[7]; i7 += incr[7])
+ {
+ for (i6 = str[6]; i6 <= stp[6]; i6 += incr[6])
+ {
+ for (i5 = str[5]; i5 <= stp[5]; i5 += incr[5])
+ {
+ for (i4 = str[4]; i4 <= stp[4]; i4 += incr[4])
+ {
+ for (i3 = str[3]; i3 <= stp[3]; i3 += incr[3])
+ {
+ for (i2 = str[2]; i2 <= stp[2]; i2 += incr[2])
+ {
+ for (i1 = str[1]; i1 <= stp[1]; i1 += incr[1])
+ {
+ felem=str[0] + (i1 - 1) * dsize[1] + (i2 - 1) * dsize[2] +
+ (i3 - 1) * dsize[3] + (i4 - 1) * dsize[4] +
+ (i5 - 1) * dsize[5] + (i6 - 1) * dsize[6] +
+ (i7 - 1) * dsize[7] + (i8 - 1) * dsize[8];
+
+ if ( ffgcluj(fptr, numcol, row, felem, nelem, ninc, nultyp,
+ nulval, &array[i0], &flagval[i0], &anyf, status) > 0)
+ return(*status);
+
+ if (anyf && anynul)
+ *anynul = TRUE;
+
+ i0 += nelem;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffggpuj(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to read (1 = 1st group) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ unsigned long *array, /* O - array of values that are returned */
+ int *status) /* IO - error status */
+/*
+ Read an array of group parameters from the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being read).
+*/
+{
+ long row;
+ int idummy;
+ char cdummy;
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ row=maxvalue(1,group);
+
+ ffgcluj(fptr, 1, row, firstelem, nelem, 1, 1, 0L,
+ array, &cdummy, &idummy, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgcvuj(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to read (1 = 1st col) */
+ long firstrow, /* I - first row to read (1 = 1st row) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ unsigned long nulval, /* I - value for null pixels */
+ unsigned long *array, /* O - array of values that are read */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from a column in the current FITS HDU. Automatic
+ datatype conversion will be performed if the datatype of the column does not
+ match the datatype of the array parameter. The output values will be scaled
+ by the FITS TSCALn and TZEROn values if these values have been defined.
+ Any undefined pixels will be set equal to the value of 'nulval' unless
+ nulval = 0 in which case no checks for undefined pixels will be made.
+*/
+{
+ char cdummy;
+
+ ffgcluj(fptr, colnum, firstrow, firstelem, nelem, 1, 1, nulval,
+ array, &cdummy, anynul, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgcfuj(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to read (1 = 1st col) */
+ long firstrow, /* I - first row to read (1 = 1st row) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ unsigned long *array, /* O - array of values that are read */
+ char *nularray, /* O - array of flags: 1 if null pixel; else 0 */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from a column in the current FITS HDU. Automatic
+ datatype conversion will be performed if the datatype of the column does not
+ match the datatype of the array parameter. The output values will be scaled
+ by the FITS TSCALn and TZEROn values if these values have been defined.
+ Nularray will be set = 1 if the corresponding array pixel is undefined,
+ otherwise nularray will = 0.
+*/
+{
+ unsigned long dummy = 0;
+
+ ffgcluj(fptr, colnum, firstrow, firstelem, nelem, 1, 2, dummy,
+ array, nularray, anynul, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgcluj(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to read (1 = 1st col) */
+ long firstrow, /* I - first row to read (1 = 1st row) */
+ OFF_T firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ long elemincre, /* I - pixel increment; e.g., 2 = every other */
+ int nultyp, /* I - null value handling code: */
+ /* 1: set undefined pixels = nulval */
+ /* 2: set nularray=1 for undefined pixels */
+ unsigned long nulval, /* I - value for null pixels if nultyp = 1 */
+ unsigned long *array, /* O - array of values that are read */
+ char *nularray, /* O - array of flags = 1 if nultyp = 2 */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from a column in the current FITS HDU.
+ The column number may refer to a real column in an ASCII or binary table,
+ or it may refer be a virtual column in a 1 or more grouped FITS primary
+ array or image extension. FITSIO treats a primary array as a binary table
+ with 2 vector columns: the first column contains the group parameters (often
+ with length = 0) and the second column contains the array of image pixels.
+ Each row of the table represents a group in the case of multigroup FITS
+ images.
+
+ The output array of values will be converted from the datatype of the column
+ and will be scaled by the FITS TSCALn and TZEROn values if necessary.
+*/
+{
+ double scale, zero, power = 1.;
+ int tcode, maxelem, hdutype, xcode, decimals;
+ long twidth, incre, rownum, remain, next, ntodo;
+ long ii, rowincre, tnull, xwidth;
+ int nulcheck;
+ OFF_T repeat, startpos, elemnum, readptr, rowlen;
+ char tform[20];
+ char message[81];
+ char snull[20]; /* the FITS null value if reading from ASCII table */
+
+ double cbuff[DBUFFSIZE / sizeof(double)]; /* align cbuff on word boundary */
+ void *buffer;
+
+ if (*status > 0 || nelem == 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ buffer = cbuff;
+
+ if (anynul)
+ *anynul = 0;
+
+ if (nultyp == 2)
+ memset(nularray, 0, nelem); /* initialize nullarray */
+
+ /*---------------------------------------------------*/
+ /* Check input and get parameters about the column: */
+ /*---------------------------------------------------*/
+ if ( ffgcpr( fptr, colnum, firstrow, firstelem, nelem, 0, &scale, &zero,
+ tform, &twidth, &tcode, &maxelem, &startpos, &elemnum, &incre,
+ &repeat, &rowlen, &hdutype, &tnull, snull, status) > 0 )
+ return(*status);
+
+ incre *= elemincre; /* multiply incre to just get every nth pixel */
+
+ if (tcode == TSTRING) /* setup for ASCII tables */
+ {
+ /* get the number of implied decimal places if no explicit decmal point */
+ ffasfm(tform, &xcode, &xwidth, &decimals, status);
+ for(ii = 0; ii < decimals; ii++)
+ power *= 10.;
+ }
+ /*------------------------------------------------------------------*/
+ /* Decide whether to check for null values in the input FITS file: */
+ /*------------------------------------------------------------------*/
+ nulcheck = nultyp; /* by default check for null values in the FITS file */
+
+ if (nultyp == 1 && nulval == 0)
+ nulcheck = 0; /* calling routine does not want to check for nulls */
+
+ else if (tcode%10 == 1 && /* if reading an integer column, and */
+ tnull == NULL_UNDEFINED) /* if a null value is not defined, */
+ nulcheck = 0; /* then do not check for null values. */
+
+ else if (tcode == TSHORT && (tnull > SHRT_MAX || tnull < SHRT_MIN) )
+ nulcheck = 0; /* Impossible null value */
+
+ else if (tcode == TBYTE && (tnull > 255 || tnull < 0) )
+ nulcheck = 0; /* Impossible null value */
+
+ else if (tcode == TSTRING && snull[0] == ASCII_NULL_UNDEFINED)
+ nulcheck = 0;
+
+ /*----------------------------------------------------------------------*/
+ /* If FITS column and output data array have same datatype, then we do */
+ /* not need to use a temporary buffer to store intermediate datatype. */
+ /*----------------------------------------------------------------------*/
+ if (tcode == TLONG) /* Special Case: */
+ { /* no type convertion required, so read */
+ maxelem = nelem; /* data directly into output buffer. */
+ }
+
+ /*---------------------------------------------------------------------*/
+ /* Now read the pixels from the FITS column. If the column does not */
+ /* have the same datatype as the output array, then we have to read */
+ /* the raw values into a temporary buffer (of limited size). In */
+ /* the case of a vector colum read only 1 vector of values at a time */
+ /* then skip to the next row if more values need to be read. */
+ /* After reading the raw values, then call the fffXXYY routine to (1) */
+ /* test for undefined values, (2) convert the datatype if necessary, */
+ /* and (3) scale the values by the FITS TSCALn and TZEROn linear */
+ /* scaling parameters. */
+ /*---------------------------------------------------------------------*/
+ remain = nelem; /* remaining number of values to read */
+ next = 0; /* next element in array to be read */
+ rownum = 0; /* row number, relative to firstrow */
+
+ while (remain)
+ {
+ /* limit the number of pixels to read at one time to the number that
+ will fit in the buffer or to the number of pixels that remain in
+ the current vector, which ever is smaller.
+ */
+ ntodo = minvalue(remain, maxelem);
+ ntodo = minvalue(ntodo, ((repeat - elemnum - 1)/elemincre +1));
+
+ readptr = startpos + ((OFF_T)rownum * rowlen) + (elemnum * (incre / elemincre));
+
+ switch (tcode)
+ {
+ case (TLONG):
+ ffgi4b(fptr, readptr, ntodo, incre, (INT32BIT *) &array[next],
+ status);
+ fffi4u4((INT32BIT *) &array[next], ntodo, scale, zero,
+ nulcheck, (INT32BIT) tnull, nulval, &nularray[next],
+ anynul, &array[next], status);
+ break;
+ case (TLONGLONG):
+
+ ffgi8b(fptr, readptr, ntodo, incre, (long *) buffer, status);
+ fffi8u4( (LONGLONG *) buffer, ntodo, scale, zero,
+ nulcheck, (long) tnull, nulval, &nularray[next],
+ anynul, &array[next], status);
+ break;
+ case (TBYTE):
+ ffgi1b(fptr, readptr, ntodo, incre, (unsigned char *) buffer,
+ status);
+ fffi1u4((unsigned char *) buffer, ntodo, scale, zero, nulcheck,
+ (unsigned char) tnull, nulval, &nularray[next], anynul,
+ &array[next], status);
+ break;
+ case (TSHORT):
+ ffgi2b(fptr, readptr, ntodo, incre, (short *) buffer, status);
+ fffi2u4((short *) buffer, ntodo, scale, zero, nulcheck,
+ (short) tnull, nulval, &nularray[next], anynul,
+ &array[next], status);
+ break;
+ case (TFLOAT):
+ ffgr4b(fptr, readptr, ntodo, incre, (float *) buffer, status);
+ fffr4u4((float *) buffer, ntodo, scale, zero, nulcheck,
+ nulval, &nularray[next], anynul,
+ &array[next], status);
+ break;
+ case (TDOUBLE):
+ ffgr8b(fptr, readptr, ntodo, incre, (double *) buffer, status);
+ fffr8u4((double *) buffer, ntodo, scale, zero, nulcheck,
+ nulval, &nularray[next], anynul,
+ &array[next], status);
+ break;
+ case (TSTRING):
+ ffmbyt(fptr, readptr, REPORT_EOF, status);
+
+ if (incre == twidth) /* contiguous bytes */
+ ffgbyt(fptr, ntodo * twidth, buffer, status);
+ else
+ ffgbytoff(fptr, twidth, ntodo, incre - twidth, buffer,
+ status);
+
+ fffstru4((char *) buffer, ntodo, scale, zero, twidth, power,
+ nulcheck, snull, nulval, &nularray[next], anynul,
+ &array[next], status);
+ break;
+
+ default: /* error trap for invalid column format */
+ sprintf(message,
+ "Cannot read numbers from column %d which has format %s",
+ colnum, tform);
+ ffpmsg(message);
+ if (hdutype == ASCII_TBL)
+ return(*status = BAD_ATABLE_FORMAT);
+ else
+ return(*status = BAD_BTABLE_FORMAT);
+
+ } /* End of switch block */
+
+ /*-------------------------*/
+ /* Check for fatal error */
+ /*-------------------------*/
+ if (*status > 0) /* test for error during previous read operation */
+ {
+ if (hdutype > 0)
+ sprintf(message,
+ "Error reading elements %ld thru %ld from column %d (ffgcluj).",
+ next+1, next+ntodo, colnum);
+ else
+ sprintf(message,
+ "Error reading elements %ld thru %ld from image (ffgcluj).",
+ next+1, next+ntodo);
+
+ ffpmsg(message);
+ return(*status);
+ }
+
+ /*--------------------------------------------*/
+ /* increment the counters for the next loop */
+ /*--------------------------------------------*/
+ remain -= ntodo;
+ if (remain)
+ {
+ next += ntodo;
+ elemnum = elemnum + (ntodo * elemincre);
+
+ if (elemnum >= repeat) /* completed a row; start on later row */
+ {
+ rowincre = elemnum / repeat;
+ rownum += rowincre;
+ elemnum = elemnum - (rowincre * repeat);
+ }
+ }
+ } /* End of main while Loop */
+
+
+ /*--------------------------------*/
+ /* check for numerical overflow */
+ /*--------------------------------*/
+ if (*status == OVERFLOW_ERR)
+ {
+ ffpmsg(
+ "Numerical overflow during type conversion while reading FITS data.");
+ *status = NUM_OVERFLOW;
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffi1u4(unsigned char *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ unsigned char tnull, /* I - value of FITS TNULLn keyword if any */
+ unsigned long nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ unsigned long *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to tnull. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = (unsigned long) input[ii]; /* copy input */
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DULONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DULONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = ULONG_MAX;
+ }
+ else
+ output[ii] = (unsigned long) dvalue;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ output[ii] = (unsigned long) input[ii];
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DULONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DULONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = ULONG_MAX;
+ }
+ else
+ output[ii] = (unsigned long) dvalue;
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffi2u4(short *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ short tnull, /* I - value of FITS TNULLn keyword if any */
+ unsigned long nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ unsigned long *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to tnull. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] < 0)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else
+ output[ii] = (unsigned long) input[ii];
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DULONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DULONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = ULONG_MAX;
+ }
+ else
+ output[ii] = (unsigned long) dvalue;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ if (input[ii] < 0)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else
+ output[ii] = (unsigned long) input[ii];
+ }
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DULONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DULONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = ULONG_MAX;
+ }
+ else
+ output[ii] = (unsigned long) dvalue;
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffi4u4(INT32BIT *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ INT32BIT tnull, /* I - value of FITS TNULLn keyword if any */
+ unsigned long nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ unsigned long *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to tnull. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+
+ Process the array of data in reverse order, to handle the case where
+ the input data is 4-bytes and the output is 8-bytes and the conversion
+ is being done in place in the same array.
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 2147483648.)
+ {
+ /* Instead of adding 2147483648, it is more efficient */
+ /* to just flip the sign bit with the XOR operator */
+
+ for (ii = ntodo - 1; ii >= 0; ii--)
+ output[ii] = ( *(unsigned int *) &input[ii] ) ^ 0x80000000;
+ }
+ else if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = ntodo - 1; ii >= 0; ii--)
+ {
+ if (input[ii] < 0)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else
+ output[ii] = (unsigned long) input[ii]; /* copy input */
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = ntodo - 1; ii >= 0; ii--)
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DULONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DULONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = ULONG_MAX;
+ }
+ else
+ output[ii] = (unsigned long) dvalue;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ if (scale == 1. && zero == 2147483648.)
+ {
+ for (ii = ntodo - 1; ii >= 0; ii--)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ output[ii] = ( *(unsigned int *) &input[ii] ) ^ 0x80000000;
+ }
+ }
+ else if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = ntodo - 1; ii >= 0; ii--)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else if (input[ii] < 0)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else
+ output[ii] = (unsigned long) input[ii]; /* copy input */
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = ntodo - 1; ii >= 0; ii--)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DULONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DULONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = ULONG_MAX;
+ }
+ else
+ output[ii] = (unsigned long) dvalue;
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffi8u4(LONGLONG *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ long tnull, /* I - value of FITS TNULLn keyword if any */
+ unsigned long nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ unsigned long *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to tnull. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+#if (LONGSIZE == 32) && (! defined HAVE_LONGLONG)
+
+ /* This block of code is only used in cases where there is */
+ /* no native 8-byte integer support. We have to interpret */
+ /* the corresponding pair of 4-byte integers which are */
+ /* are equivalent to the 8-byte integer. */
+
+ long ii,jj,kk;
+ double dvalue;
+ unsigned long *uinput;
+
+ uinput = (unsigned long *) input;
+
+#if BYTESWAPPED /* jj points to the most significant part of the 8-byte int */
+ jj = 1;
+ kk = 0;
+#else
+ jj = 0;
+ kk = 1;
+#endif
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++, jj += 2, kk =+ 2)
+ {
+ if (uinput[jj] & 0x80000000) /* negative number */
+ dvalue = (uinput[jj] ^ 0xffffffff) * -4294967296. -
+ (uinput[kk] ^ 0xffffffff) - 1.;
+ else /* positive number */
+ dvalue = uinput[jj] * 4294967296. + uinput[kk];
+
+ if (dvalue < DULONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DULONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = ULONG_MAX;
+ }
+ else
+ output[ii] = (unsigned long) dvalue;
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++, jj += 2, kk += 2)
+ {
+ if (uinput[jj] & 0x80000000) /* negative number */
+ dvalue = ((uinput[jj] ^ 0xffffffff) * -4294967296. -
+ (uinput[kk] ^ 0xffffffff) - 1.) * scale + zero;
+ else /* positive number */
+ dvalue = (uinput[jj] * 4294967296. + uinput[kk])
+ * scale + zero;
+
+ if (dvalue < DULONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DULONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = ULONG_MAX;
+ }
+ else
+ output[ii] = (unsigned long) dvalue;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++, jj += 2, kk += 2)
+ {
+ if (uinput[jj] & 0x80000000) /* negative number */
+ dvalue = (uinput[jj] ^ 0xffffffff) * -4294967296. -
+ (uinput[kk] ^ 0xffffffff) - 1.;
+ else /* positive number */
+ dvalue = uinput[jj] * 4294967296. + uinput[kk];
+
+ if (dvalue == (double) tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ if (dvalue < DULONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DULONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = ULONG_MAX;
+ }
+ else
+ output[ii] = (unsigned long) dvalue;
+ }
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++, jj += 2, kk += 2)
+ {
+ if (uinput[jj] & 0x80000000) /* negative number */
+ dvalue = (uinput[jj] ^ 0xffffffff) * -4294967296. -
+ (uinput[kk] ^ 0xffffffff) - 1.;
+ else /* positive number */
+ dvalue = uinput[jj] * 4294967296. + uinput[kk];
+
+ if (dvalue == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ dvalue = dvalue * scale + zero;
+
+ if (dvalue < DULONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DULONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = ULONG_MAX;
+ }
+ else
+ output[ii] = (unsigned long) dvalue;
+ }
+ }
+ }
+ }
+
+#else
+
+ /* this block works on machines which support an 8-byte integer type */
+
+ long ii;
+ double dvalue;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] < 0)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (input[ii] > ULONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = ULONG_MAX;
+ }
+ else
+ output[ii] = (unsigned long) input[ii];
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DULONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DULONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = ULONG_MAX;
+ }
+ else
+ output[ii] = (unsigned long) dvalue;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ if (input[ii] < 0)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (input[ii] > ULONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = ULONG_MAX;
+ }
+ else
+ output[ii] = (unsigned long) input[ii];
+ }
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DULONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DULONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = ULONG_MAX;
+ }
+ else
+ output[ii] = (unsigned long) dvalue;
+ }
+ }
+ }
+ }
+
+#endif
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffr4u4(float *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ unsigned long nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ unsigned long *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to NaN. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ long ii;
+ double dvalue;
+ short *sptr, iret;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] < DULONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (input[ii] > DULONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = ULONG_MAX;
+ }
+ else
+ output[ii] = (unsigned long) input[ii];
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DULONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DULONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = ULONG_MAX;
+ }
+ else
+ output[ii] = (unsigned long) dvalue;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ sptr = (short *) input;
+
+#if BYTESWAPPED && MACHINE != VAXVMS && MACHINE != ALPHAVMS
+ sptr++; /* point to MSBs */
+#endif
+
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++, sptr += 2)
+ {
+ if (0 != (iret = fnan(*sptr) ) ) /* test for NaN or underflow */
+ {
+ if (iret == 1) /* is it a NaN? */
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else /* it's an underflow */
+ output[ii] = 0;
+ }
+ else
+ {
+ if (input[ii] < DULONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (input[ii] > DULONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = ULONG_MAX;
+ }
+ else
+ output[ii] = (unsigned long) input[ii];
+ }
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++, sptr += 2)
+ {
+ if (0 != (iret = fnan(*sptr) ) ) /* test for NaN or underflow */
+ {
+ if (iret == 1) /* is it a NaN? */
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else /* it's an underflow */
+ {
+ if (zero < DULONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (zero > DULONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = ULONG_MAX;
+ }
+ else
+ output[ii] = (unsigned long) zero;
+ }
+ }
+ else
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DULONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DULONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = ULONG_MAX;
+ }
+ else
+ output[ii] = (unsigned long) dvalue;
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffr8u4(double *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ unsigned long nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ unsigned long *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to NaN. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ long ii;
+ double dvalue;
+ short *sptr, iret;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] < DULONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (input[ii] > DULONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = ULONG_MAX;
+ }
+ else
+ output[ii] = (unsigned long) input[ii];
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DULONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DULONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = ULONG_MAX;
+ }
+ else
+ output[ii] = (unsigned long) dvalue;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ sptr = (short *) input;
+
+#if BYTESWAPPED && MACHINE != VAXVMS && MACHINE != ALPHAVMS
+ sptr += 3; /* point to MSBs */
+#endif
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++, sptr += 4)
+ {
+ if (0 != (iret = dnan(*sptr)) ) /* test for NaN or underflow */
+ {
+ if (iret == 1) /* is it a NaN? */
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else /* it's an underflow */
+ output[ii] = 0;
+ }
+ else
+ {
+ if (input[ii] < DULONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (input[ii] > DULONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = ULONG_MAX;
+ }
+ else
+ output[ii] = (unsigned long) input[ii];
+ }
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++, sptr += 4)
+ {
+ if (0 != (iret = dnan(*sptr)) ) /* test for NaN or underflow */
+ {
+ if (iret == 1) /* is it a NaN? */
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else /* it's an underflow */
+ {
+ if (zero < DULONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (zero > DULONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = ULONG_MAX;
+ }
+ else
+ output[ii] = (unsigned long) zero;
+ }
+ }
+ else
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DULONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DULONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = ULONG_MAX;
+ }
+ else
+ output[ii] = (unsigned long) dvalue;
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffstru4(char *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ long twidth, /* I - width of each substring of chars */
+ double implipower, /* I - power of 10 of implied decimal */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ char *snull, /* I - value of FITS null string, if any */
+ unsigned long nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ unsigned long *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file. Check
+ for null values and do scaling if required. The nullcheck code value
+ determines how any null values in the input array are treated. A null
+ value is an input pixel that is equal to snull. If nullcheck= 0, then
+ no special checking for nulls is performed. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ int nullen;
+ long ii;
+ double dvalue;
+ char *cstring, message[81];
+ char *cptr, *tpos;
+ char tempstore, chrzero = '0';
+ double val, power;
+ int exponent, sign, esign, decpt;
+
+ nullen = strlen(snull);
+ cptr = input; /* pointer to start of input string */
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ cstring = cptr;
+ /* temporarily insert a null terminator at end of the string */
+ tpos = cptr + twidth;
+ tempstore = *tpos;
+ *tpos = 0;
+
+ /* check if null value is defined, and if the */
+ /* column string is identical to the null string */
+ if (snull[0] != ASCII_NULL_UNDEFINED &&
+ !strncmp(snull, cptr, nullen) )
+ {
+ if (nullcheck)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ cptr += twidth;
+ }
+ else
+ {
+ /* value is not the null value, so decode it */
+ /* remove any embedded blank characters from the string */
+
+ decpt = 0;
+ sign = 1;
+ val = 0.;
+ power = 1.;
+ exponent = 0;
+ esign = 1;
+
+ while (*cptr == ' ') /* skip leading blanks */
+ cptr++;
+
+ if (*cptr == '-' || *cptr == '+') /* check for leading sign */
+ {
+ if (*cptr == '-')
+ sign = -1;
+
+ cptr++;
+
+ while (*cptr == ' ') /* skip blanks between sign and value */
+ cptr++;
+ }
+
+ while (*cptr >= '0' && *cptr <= '9')
+ {
+ val = val * 10. + *cptr - chrzero; /* accumulate the value */
+ cptr++;
+
+ while (*cptr == ' ') /* skip embedded blanks in the value */
+ cptr++;
+ }
+
+ if (*cptr == '.') /* check for decimal point */
+ {
+ decpt = 1; /* set flag to show there was a decimal point */
+ cptr++;
+ while (*cptr == ' ') /* skip any blanks */
+ cptr++;
+
+ while (*cptr >= '0' && *cptr <= '9')
+ {
+ val = val * 10. + *cptr - chrzero; /* accumulate the value */
+ power = power * 10.;
+ cptr++;
+
+ while (*cptr == ' ') /* skip embedded blanks in the value */
+ cptr++;
+ }
+ }
+
+ if (*cptr == 'E' || *cptr == 'D') /* check for exponent */
+ {
+ cptr++;
+ while (*cptr == ' ') /* skip blanks */
+ cptr++;
+
+ if (*cptr == '-' || *cptr == '+') /* check for exponent sign */
+ {
+ if (*cptr == '-')
+ esign = -1;
+
+ cptr++;
+
+ while (*cptr == ' ') /* skip blanks between sign and exp */
+ cptr++;
+ }
+
+ while (*cptr >= '0' && *cptr <= '9')
+ {
+ exponent = exponent * 10 + *cptr - chrzero; /* accumulate exp */
+ cptr++;
+
+ while (*cptr == ' ') /* skip embedded blanks */
+ cptr++;
+ }
+ }
+
+ if (*cptr != 0) /* should end up at the null terminator */
+ {
+ sprintf(message, "Cannot read number from ASCII table");
+ ffpmsg(message);
+ sprintf(message, "Column field = %s.", cstring);
+ ffpmsg(message);
+ /* restore the char that was overwritten by the null */
+ *tpos = tempstore;
+ return(*status = BAD_C2D);
+ }
+
+ if (!decpt) /* if no explicit decimal, use implied */
+ power = implipower;
+
+ dvalue = (sign * val / power) * pow(10., (double) (esign * exponent));
+
+ dvalue = dvalue * scale + zero; /* apply the scaling */
+
+ if (dvalue < DULONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DULONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = ULONG_MAX;
+ }
+ else
+ output[ii] = (unsigned long) dvalue;
+ }
+ /* restore the char that was overwritten by the null */
+ *tpos = tempstore;
+ }
+ return(*status);
+}
diff --git a/pkg/tbtables/cfitsio/getcoluk.c b/pkg/tbtables/cfitsio/getcoluk.c
new file mode 100644
index 00000000..fdbe5395
--- /dev/null
+++ b/pkg/tbtables/cfitsio/getcoluk.c
@@ -0,0 +1,2059 @@
+/* This file, getcolk.c, contains routines that read data elements from */
+/* a FITS image or table, with 'unsigned int' data type. */
+
+/* The FITSIO software was written by William Pence at the High Energy */
+/* Astrophysic Science Archive Research Center (HEASARC) at the NASA */
+/* Goddard Space Flight Center. */
+
+#include <math.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include "fitsio2.h"
+
+/*--------------------------------------------------------------------------*/
+int ffgpvuk( fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to read (1 = 1st group) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ unsigned int nulval, /* I - value for undefined pixels */
+ unsigned int *array, /* O - array of values that are returned */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being read).
+ Undefined elements will be set equal to NULVAL, unless NULVAL=0
+ in which case no checking for undefined values will be performed.
+ ANYNUL is returned with a value of .true. if any pixels are undefined.
+*/
+{
+ long row;
+ char cdummy;
+ int nullcheck = 1;
+ unsigned int nullvalue;
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+ nullvalue = nulval; /* set local variable */
+
+ fits_read_compressed_pixels(fptr, TUINT, firstelem, nelem,
+ nullcheck, &nullvalue, array, NULL, anynul, status);
+ return(*status);
+ }
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ row=maxvalue(1,group);
+
+ ffgcluk(fptr, 2, row, firstelem, nelem, 1, 1, nulval,
+ array, &cdummy, anynul, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgpfuk(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to read (1 = 1st group) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ unsigned int *array, /* O - array of values that are returned */
+ char *nularray, /* O - array of null pixel flags */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being read).
+ Any undefined pixels in the returned array will be set = 0 and the
+ corresponding nularray value will be set = 1.
+ ANYNUL is returned with a value of .true. if any pixels are undefined.
+*/
+{
+ long row;
+ int nullcheck = 2;
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ fits_read_compressed_pixels(fptr, TUINT, firstelem, nelem,
+ nullcheck, NULL, array, nularray, anynul, status);
+ return(*status);
+ }
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ row=maxvalue(1,group);
+
+ ffgcluk(fptr, 2, row, firstelem, nelem, 1, 2, 0L,
+ array, nularray, anynul, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffg2duk(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to read (1 = 1st group) */
+ unsigned int nulval, /* set undefined pixels equal to this */
+ long ncols, /* I - number of pixels in each row of array */
+ long naxis1, /* I - FITS image NAXIS1 value */
+ long naxis2, /* I - FITS image NAXIS2 value */
+ unsigned int *array, /* O - array to be filled and returned */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an entire 2-D array of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of the
+ FITS array is not the same as the array being read). Any null
+ values in the array will be set equal to the value of nulval, unless
+ nulval = 0 in which case no null checking will be performed.
+*/
+{
+ /* call the 3D reading routine, with the 3rd dimension = 1 */
+
+ ffg3duk(fptr, group, nulval, ncols, naxis2, naxis1, naxis2, 1, array,
+ anynul, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffg3duk(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to read (1 = 1st group) */
+ unsigned int nulval, /* set undefined pixels equal to this */
+ long ncols, /* I - number of pixels in each row of array */
+ long nrows, /* I - number of rows in each plane of array */
+ long naxis1, /* I - FITS image NAXIS1 value */
+ long naxis2, /* I - FITS image NAXIS2 value */
+ long naxis3, /* I - FITS image NAXIS3 value */
+ unsigned int *array, /* O - array to be filled and returned */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an entire 3-D array of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of the
+ FITS array is not the same as the array being read). Any null
+ values in the array will be set equal to the value of nulval, unless
+ nulval = 0 in which case no null checking will be performed.
+*/
+{
+ long tablerow, nfits, narray, ii, jj;
+ char cdummy;
+ int nullcheck = 1;
+ long inc[] = {1,1,1};
+ long fpixel[] = {1,1,1};
+ long lpixel[3];
+ unsigned int nullvalue;
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ lpixel[0] = ncols;
+ lpixel[1] = nrows;
+ lpixel[2] = naxis3;
+ nullvalue = nulval; /* set local variable */
+
+ fits_read_compressed_img(fptr, TUINT, fpixel, lpixel, inc,
+ nullcheck, &nullvalue, array, NULL, anynul, status);
+ return(*status);
+ }
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+ tablerow=maxvalue(1,group);
+
+ if (ncols == naxis1 && nrows == naxis2) /* arrays have same size? */
+ {
+ /* all the image pixels are contiguous, so read all at once */
+ ffgcluk(fptr, 2, tablerow, 1, naxis1 * naxis2 * naxis3, 1, 1, nulval,
+ array, &cdummy, anynul, status);
+ return(*status);
+ }
+
+ if (ncols < naxis1 || nrows < naxis2)
+ return(*status = BAD_DIMEN);
+
+ nfits = 1; /* next pixel in FITS image to read */
+ narray = 0; /* next pixel in output array to be filled */
+
+ /* loop over naxis3 planes in the data cube */
+ for (jj = 0; jj < naxis3; jj++)
+ {
+ /* loop over the naxis2 rows in the FITS image, */
+ /* reading naxis1 pixels to each row */
+
+ for (ii = 0; ii < naxis2; ii++)
+ {
+ if (ffgcluk(fptr, 2, tablerow, nfits, naxis1, 1, 1, nulval,
+ &array[narray], &cdummy, anynul, status) > 0)
+ return(*status);
+
+ nfits += naxis1;
+ narray += ncols;
+ }
+ narray += (nrows - naxis2) * ncols;
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgsvuk(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of the column to read (1 = 1st) */
+ int naxis, /* I - number of dimensions in the FITS array */
+ long *naxes, /* I - size of each dimension */
+ long *blc, /* I - 'bottom left corner' of the subsection */
+ long *trc, /* I - 'top right corner' of the subsection */
+ long *inc, /* I - increment to be applied in each dimension */
+ unsigned int nulval, /* I - value to set undefined pixels */
+ unsigned int *array, /* O - array to be filled and returned */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read a subsection of data values from an image or a table column.
+ This routine is set up to handle a maximum of nine dimensions.
+*/
+{
+ long ii,i0, i1,i2,i3,i4,i5,i6,i7,i8,row,rstr,rstp,rinc;
+ long str[9],stp[9],incr[9];
+ long nelem, nultyp, ninc, numcol;
+ OFF_T felem, dsize[10];
+ int hdutype, anyf;
+ char ldummy, msg[FLEN_ERRMSG];
+ int nullcheck = 1;
+ unsigned int nullvalue;
+
+ if (naxis < 1 || naxis > 9)
+ {
+ sprintf(msg, "NAXIS = %d in call to ffgsvuk is out of range", naxis);
+ ffpmsg(msg);
+ return(*status = BAD_DIMEN);
+ }
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ nullvalue = nulval; /* set local variable */
+
+ fits_read_compressed_img(fptr, TUINT, blc, trc, inc,
+ nullcheck, &nullvalue, array, NULL, anynul, status);
+ return(*status);
+ }
+
+/*
+ if this is a primary array, then the input COLNUM parameter should
+ be interpreted as the row number, and we will alway read the image
+ data from column 2 (any group parameters are in column 1).
+*/
+ if (ffghdt(fptr, &hdutype, status) > 0)
+ return(*status);
+
+ if (hdutype == IMAGE_HDU)
+ {
+ /* this is a primary array, or image extension */
+ if (colnum == 0)
+ {
+ rstr = 1;
+ rstp = 1;
+ }
+ else
+ {
+ rstr = colnum;
+ rstp = colnum;
+ }
+ rinc = 1;
+ numcol = 2;
+ }
+ else
+ {
+ /* this is a table, so the row info is in the (naxis+1) elements */
+ rstr = blc[naxis];
+ rstp = trc[naxis];
+ rinc = inc[naxis];
+ numcol = colnum;
+ }
+
+ nultyp = 1;
+ if (anynul)
+ *anynul = FALSE;
+
+ i0 = 0;
+ for (ii = 0; ii < 9; ii++)
+ {
+ str[ii] = 1;
+ stp[ii] = 1;
+ incr[ii] = 1;
+ dsize[ii] = 1;
+ }
+
+ for (ii = 0; ii < naxis; ii++)
+ {
+ if (trc[ii] < blc[ii])
+ {
+ sprintf(msg, "ffgsvuk: illegal range specified for axis %ld", ii + 1);
+ ffpmsg(msg);
+ return(*status = BAD_PIX_NUM);
+ }
+
+ str[ii] = blc[ii];
+ stp[ii] = trc[ii];
+ incr[ii] = inc[ii];
+ dsize[ii + 1] = dsize[ii] * naxes[ii];
+ }
+
+ if (naxis == 1 && naxes[0] == 1)
+ {
+ /* This is not a vector column, so read all the rows at once */
+ nelem = (rstp - rstr) / rinc + 1;
+ ninc = rinc;
+ rstp = rstr;
+ }
+ else
+ {
+ /* have to read each row individually, in all dimensions */
+ nelem = (stp[0] - str[0]) / inc[0] + 1;
+ ninc = incr[0];
+ }
+
+ for (row = rstr; row <= rstp; row += rinc)
+ {
+ for (i8 = str[8]; i8 <= stp[8]; i8 += incr[8])
+ {
+ for (i7 = str[7]; i7 <= stp[7]; i7 += incr[7])
+ {
+ for (i6 = str[6]; i6 <= stp[6]; i6 += incr[6])
+ {
+ for (i5 = str[5]; i5 <= stp[5]; i5 += incr[5])
+ {
+ for (i4 = str[4]; i4 <= stp[4]; i4 += incr[4])
+ {
+ for (i3 = str[3]; i3 <= stp[3]; i3 += incr[3])
+ {
+ for (i2 = str[2]; i2 <= stp[2]; i2 += incr[2])
+ {
+ for (i1 = str[1]; i1 <= stp[1]; i1 += incr[1])
+ {
+ felem=str[0] + (i1 - 1) * dsize[1] + (i2 - 1) * dsize[2] +
+ (i3 - 1) * dsize[3] + (i4 - 1) * dsize[4] +
+ (i5 - 1) * dsize[5] + (i6 - 1) * dsize[6] +
+ (i7 - 1) * dsize[7] + (i8 - 1) * dsize[8];
+
+ if ( ffgcluk(fptr, numcol, row, felem, nelem, ninc, nultyp,
+ nulval, &array[i0], &ldummy, &anyf, status) > 0)
+ return(*status);
+
+ if (anyf && anynul)
+ *anynul = TRUE;
+
+ i0 += nelem;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgsfuk(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of the column to read (1 = 1st) */
+ int naxis, /* I - number of dimensions in the FITS array */
+ long *naxes, /* I - size of each dimension */
+ long *blc, /* I - 'bottom left corner' of the subsection */
+ long *trc, /* I - 'top right corner' of the subsection */
+ long *inc, /* I - increment to be applied in each dimension */
+ unsigned int *array, /* O - array to be filled and returned */
+ char *flagval, /* O - set to 1 if corresponding value is null */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read a subsection of data values from an image or a table column.
+ This routine is set up to handle a maximum of nine dimensions.
+*/
+{
+ long ii,i0, i1,i2,i3,i4,i5,i6,i7,i8,row,rstr,rstp,rinc;
+ long str[9],stp[9],incr[9],dsize[10];
+ long felem, nelem, nultyp, ninc, numcol;
+ long nulval = 0;
+ int hdutype, anyf;
+ char msg[FLEN_ERRMSG];
+ int nullcheck = 2;
+
+ if (naxis < 1 || naxis > 9)
+ {
+ sprintf(msg, "NAXIS = %d in call to ffgsvj is out of range", naxis);
+ ffpmsg(msg);
+ return(*status = BAD_DIMEN);
+ }
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ fits_read_compressed_img(fptr, TUINT, blc, trc, inc,
+ nullcheck, NULL, array, flagval, anynul, status);
+ return(*status);
+ }
+
+/*
+ if this is a primary array, then the input COLNUM parameter should
+ be interpreted as the row number, and we will alway read the image
+ data from column 2 (any group parameters are in column 1).
+*/
+ if (ffghdt(fptr, &hdutype, status) > 0)
+ return(*status);
+
+ if (hdutype == IMAGE_HDU)
+ {
+ /* this is a primary array, or image extension */
+ if (colnum == 0)
+ {
+ rstr = 1;
+ rstp = 1;
+ }
+ else
+ {
+ rstr = colnum;
+ rstp = colnum;
+ }
+ rinc = 1;
+ numcol = 2;
+ }
+ else
+ {
+ /* this is a table, so the row info is in the (naxis+1) elements */
+ rstr = blc[naxis];
+ rstp = trc[naxis];
+ rinc = inc[naxis];
+ numcol = colnum;
+ }
+
+ nultyp = 2;
+ if (anynul)
+ *anynul = FALSE;
+
+ i0 = 0;
+ for (ii = 0; ii < 9; ii++)
+ {
+ str[ii] = 1;
+ stp[ii] = 1;
+ incr[ii] = 1;
+ dsize[ii] = 1;
+ }
+
+ for (ii = 0; ii < naxis; ii++)
+ {
+ if (trc[ii] < blc[ii])
+ {
+ sprintf(msg, "ffgsvj: illegal range specified for axis %ld", ii + 1);
+ ffpmsg(msg);
+ return(*status = BAD_PIX_NUM);
+ }
+
+ str[ii] = blc[ii];
+ stp[ii] = trc[ii];
+ incr[ii] = inc[ii];
+ dsize[ii + 1] = dsize[ii] * naxes[ii];
+ }
+
+ if (naxis == 1 && naxes[0] == 1)
+ {
+ /* This is not a vector column, so read all the rows at once */
+ nelem = (rstp - rstr) / rinc + 1;
+ ninc = rinc;
+ rstp = rstr;
+ }
+ else
+ {
+ /* have to read each row individually, in all dimensions */
+ nelem = (stp[0] - str[0]) / inc[0] + 1;
+ ninc = incr[0];
+ }
+
+ for (row = rstr; row <= rstp; row += rinc)
+ {
+ for (i8 = str[8]; i8 <= stp[8]; i8 += incr[8])
+ {
+ for (i7 = str[7]; i7 <= stp[7]; i7 += incr[7])
+ {
+ for (i6 = str[6]; i6 <= stp[6]; i6 += incr[6])
+ {
+ for (i5 = str[5]; i5 <= stp[5]; i5 += incr[5])
+ {
+ for (i4 = str[4]; i4 <= stp[4]; i4 += incr[4])
+ {
+ for (i3 = str[3]; i3 <= stp[3]; i3 += incr[3])
+ {
+ for (i2 = str[2]; i2 <= stp[2]; i2 += incr[2])
+ {
+ for (i1 = str[1]; i1 <= stp[1]; i1 += incr[1])
+ {
+ felem=str[0] + (i1 - 1) * dsize[1] + (i2 - 1) * dsize[2] +
+ (i3 - 1) * dsize[3] + (i4 - 1) * dsize[4] +
+ (i5 - 1) * dsize[5] + (i6 - 1) * dsize[6] +
+ (i7 - 1) * dsize[7] + (i8 - 1) * dsize[8];
+
+ if ( ffgcluk(fptr, numcol, row, felem, nelem, ninc, nultyp,
+ nulval, &array[i0], &flagval[i0], &anyf, status) > 0)
+ return(*status);
+
+ if (anyf && anynul)
+ *anynul = TRUE;
+
+ i0 += nelem;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffggpuk( fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to read (1 = 1st group) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ unsigned int *array, /* O - array of values that are returned */
+ int *status) /* IO - error status */
+/*
+ Read an array of group parameters from the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being read).
+*/
+{
+ long row;
+ int idummy;
+ char cdummy;
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ row=maxvalue(1,group);
+
+ ffgcluk(fptr, 1, row, firstelem, nelem, 1, 1, 0L,
+ array, &cdummy, &idummy, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgcvuk(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to read (1 = 1st col) */
+ long firstrow, /* I - first row to read (1 = 1st row) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ unsigned int nulval, /* I - value for null pixels */
+ unsigned int *array, /* O - array of values that are read */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from a column in the current FITS HDU. Automatic
+ datatype conversion will be performed if the datatype of the column does not
+ match the datatype of the array parameter. The output values will be scaled
+ by the FITS TSCALn and TZEROn values if these values have been defined.
+ Any undefined pixels will be set equal to the value of 'nulval' unless
+ nulval = 0 in which case no checks for undefined pixels will be made.
+*/
+{
+ char cdummy;
+
+ ffgcluk(fptr, colnum, firstrow, firstelem, nelem, 1, 1, nulval,
+ array, &cdummy, anynul, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgcfuk(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to read (1 = 1st col) */
+ long firstrow, /* I - first row to read (1 = 1st row) */
+ long firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ unsigned int *array, /* O - array of values that are read */
+ char *nularray, /* O - array of flags: 1 if null pixel; else 0 */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from a column in the current FITS HDU. Automatic
+ datatype conversion will be performed if the datatype of the column does not
+ match the datatype of the array parameter. The output values will be scaled
+ by the FITS TSCALn and TZEROn values if these values have been defined.
+ Nularray will be set = 1 if the corresponding array pixel is undefined,
+ otherwise nularray will = 0.
+*/
+{
+ int dummy = 0;
+
+ ffgcluk(fptr, colnum, firstrow, firstelem, nelem, 1, 2, dummy,
+ array, nularray, anynul, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgcluk( fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to read (1 = 1st col) */
+ long firstrow, /* I - first row to read (1 = 1st row) */
+ OFF_T firstelem, /* I - first vector element to read (1 = 1st) */
+ long nelem, /* I - number of values to read */
+ long elemincre, /* I - pixel increment; e.g., 2 = every other */
+ int nultyp, /* I - null value handling code: */
+ /* 1: set undefined pixels = nulval */
+ /* 2: set nularray=1 for undefined pixels */
+ unsigned int nulval, /* I - value for null pixels if nultyp = 1 */
+ unsigned int *array, /* O - array of values that are read */
+ char *nularray, /* O - array of flags = 1 if nultyp = 2 */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read an array of values from a column in the current FITS HDU.
+ The column number may refer to a real column in an ASCII or binary table,
+ or it may refer be a virtual column in a 1 or more grouped FITS primary
+ array or image extension. FITSIO treats a primary array as a binary table
+ with 2 vector columns: the first column contains the group parameters (often
+ with length = 0) and the second column contains the array of image pixels.
+ Each row of the table represents a group in the case of multigroup FITS
+ images.
+
+ The output array of values will be converted from the datatype of the column
+ and will be scaled by the FITS TSCALn and TZEROn values if necessary.
+*/
+{
+ double scale, zero, power = 1.;
+ int tcode, maxelem, hdutype, xcode, decimals;
+ long twidth, incre, rownum, remain, next, ntodo;
+ long ii, rowincre, tnull, xwidth;
+ int nulcheck;
+ OFF_T repeat, startpos, elemnum, readptr, rowlen;
+ char tform[20];
+ char message[81];
+ char snull[20]; /* the FITS null value if reading from ASCII table */
+
+ double cbuff[DBUFFSIZE / sizeof(double)]; /* align cbuff on word boundary */
+ void *buffer;
+
+ if (*status > 0 || nelem == 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ /* call the 'short' or 'long' version of this routine, if possible */
+ if (sizeof(int) == sizeof(short))
+ ffgclui(fptr, colnum, firstrow, firstelem, nelem, elemincre, nultyp,
+ (unsigned short) nulval, (unsigned short *) array, nularray, anynul,
+ status);
+ else if (sizeof(int) == sizeof(long))
+ ffgcluj(fptr, colnum, firstrow, firstelem, nelem, elemincre, nultyp,
+ (unsigned long) nulval, (unsigned long *) array, nularray, anynul,
+ status);
+ else
+ {
+ /*
+ This is a special case: sizeof(int) is not equal to sizeof(short) or
+ sizeof(long). This occurs on Alpha OSF systems where short = 2 bytes,
+ int = 4 bytes, and long = 8 bytes.
+ */
+
+ buffer = cbuff;
+
+ if (anynul)
+ *anynul = 0;
+
+ if (nultyp == 2)
+ memset(nularray, 0, nelem); /* initialize nullarray */
+
+ /*---------------------------------------------------*/
+ /* Check input and get parameters about the column: */
+ /*---------------------------------------------------*/
+ if ( ffgcpr( fptr, colnum, firstrow, firstelem, nelem, 0, &scale, &zero,
+ tform, &twidth, &tcode, &maxelem, &startpos, &elemnum, &incre,
+ &repeat, &rowlen, &hdutype, &tnull, snull, status) > 0 )
+ return(*status);
+
+ incre *= elemincre; /* multiply incre to just get every nth pixel */
+
+ if (tcode == TSTRING) /* setup for ASCII tables */
+ {
+ /* get the number of implied decimal places if no explicit decmal point */
+ ffasfm(tform, &xcode, &xwidth, &decimals, status);
+ for(ii = 0; ii < decimals; ii++)
+ power *= 10.;
+ }
+ /*------------------------------------------------------------------*/
+ /* Decide whether to check for null values in the input FITS file: */
+ /*------------------------------------------------------------------*/
+ nulcheck = nultyp; /* by default check for null values in the FITS file */
+
+ if (nultyp == 1 && nulval == 0)
+ nulcheck = 0; /* calling routine does not want to check for nulls */
+
+ else if (tcode%10 == 1 && /* if reading an integer column, and */
+ tnull == NULL_UNDEFINED) /* if a null value is not defined, */
+ nulcheck = 0; /* then do not check for null values. */
+
+ else if (tcode == TSHORT && (tnull > SHRT_MAX || tnull < SHRT_MIN) )
+ nulcheck = 0; /* Impossible null value */
+
+ else if (tcode == TBYTE && (tnull > 255 || tnull < 0) )
+ nulcheck = 0; /* Impossible null value */
+
+ else if (tcode == TSTRING && snull[0] == ASCII_NULL_UNDEFINED)
+ nulcheck = 0;
+
+ /*----------------------------------------------------------------------*/
+ /* If FITS column and output data array have same datatype, then we do */
+ /* not need to use a temporary buffer to store intermediate datatype. */
+ /*----------------------------------------------------------------------*/
+ if (tcode == TLONG) /* Special Case: */
+ { /* data are 4-bytes long, so read */
+ maxelem = nelem; /* data directly into output buffer. */
+ }
+
+ /*---------------------------------------------------------------------*/
+ /* Now read the pixels from the FITS column. If the column does not */
+ /* have the same datatype as the output array, then we have to read */
+ /* the raw values into a temporary buffer (of limited size). In */
+ /* the case of a vector colum read only 1 vector of values at a time */
+ /* then skip to the next row if more values need to be read. */
+ /* After reading the raw values, then call the fffXXYY routine to (1) */
+ /* test for undefined values, (2) convert the datatype if necessary, */
+ /* and (3) scale the values by the FITS TSCALn and TZEROn linear */
+ /* scaling parameters. */
+ /*---------------------------------------------------------------------*/
+ remain = nelem; /* remaining number of values to read */
+ next = 0; /* next element in array to be read */
+ rownum = 0; /* row number, relative to firstrow */
+
+ while (remain)
+ {
+ /* limit the number of pixels to read at one time to the number that
+ will fit in the buffer or to the number of pixels that remain in
+ the current vector, which ever is smaller.
+ */
+ ntodo = minvalue(remain, maxelem);
+ ntodo = minvalue(ntodo, ((repeat - elemnum - 1)/elemincre +1));
+
+ readptr = startpos + ((OFF_T)rownum * rowlen) + (elemnum * (incre / elemincre));
+
+ switch (tcode)
+ {
+ case (TLONG):
+ ffgi4b(fptr, readptr, ntodo, incre, (INT32BIT *) &array[next],
+ status);
+ fffi4uint((INT32BIT *) &array[next], ntodo, scale, zero,
+ nulcheck, (INT32BIT) tnull, nulval, &nularray[next],
+ anynul, &array[next], status);
+ break;
+ case (TLONGLONG):
+
+ ffgi8b(fptr, readptr, ntodo, incre, (long *) buffer, status);
+ fffi8uint( (LONGLONG *) buffer, ntodo, scale, zero,
+ nulcheck, (long) tnull, nulval, &nularray[next],
+ anynul, &array[next], status);
+ break;
+ case (TBYTE):
+ ffgi1b(fptr, readptr, ntodo, incre, (unsigned char *) buffer,
+ status);
+ fffi1uint((unsigned char *) buffer, ntodo, scale, zero,nulcheck,
+ (unsigned char) tnull, nulval, &nularray[next], anynul,
+ &array[next], status);
+ break;
+ case (TSHORT):
+ ffgi2b(fptr, readptr, ntodo, incre, (short *) buffer, status);
+ fffi2uint((short *) buffer, ntodo, scale, zero, nulcheck,
+ (short) tnull, nulval, &nularray[next], anynul,
+ &array[next], status);
+ break;
+ case (TFLOAT):
+ ffgr4b(fptr, readptr, ntodo, incre, (float *) buffer, status);
+ fffr4uint((float *) buffer, ntodo, scale, zero, nulcheck,
+ nulval, &nularray[next], anynul,
+ &array[next], status);
+ break;
+ case (TDOUBLE):
+ ffgr8b(fptr, readptr, ntodo, incre, (double *) buffer, status);
+ fffr8uint((double *) buffer, ntodo, scale, zero, nulcheck,
+ nulval, &nularray[next], anynul,
+ &array[next], status);
+ break;
+ case (TSTRING):
+ ffmbyt(fptr, readptr, REPORT_EOF, status);
+
+ if (incre == twidth) /* contiguous bytes */
+ ffgbyt(fptr, ntodo * twidth, buffer, status);
+ else
+ ffgbytoff(fptr, twidth, ntodo, incre - twidth, buffer,
+ status);
+
+ fffstruint((char *) buffer, ntodo, scale, zero, twidth, power,
+ nulcheck, snull, nulval, &nularray[next], anynul,
+ &array[next], status);
+ break;
+
+ default: /* error trap for invalid column format */
+ sprintf(message,
+ "Cannot read numbers from column %d which has format %s",
+ colnum, tform);
+ ffpmsg(message);
+ if (hdutype == ASCII_TBL)
+ return(*status = BAD_ATABLE_FORMAT);
+ else
+ return(*status = BAD_BTABLE_FORMAT);
+
+ } /* End of switch block */
+
+ /*-------------------------*/
+ /* Check for fatal error */
+ /*-------------------------*/
+ if (*status > 0) /* test for error during previous read operation */
+ {
+ if (hdutype > 0)
+ sprintf(message,
+ "Error reading elements %ld thru %ld from column %d (ffgcluk).",
+ next+1, next+ntodo, colnum);
+ else
+ sprintf(message,
+ "Error reading elements %ld thru %ld from image (ffgcluk).",
+ next+1, next+ntodo);
+
+ ffpmsg(message);
+ return(*status);
+ }
+
+ /*--------------------------------------------*/
+ /* increment the counters for the next loop */
+ /*--------------------------------------------*/
+ remain -= ntodo;
+ if (remain)
+ {
+ next += ntodo;
+ elemnum = elemnum + (ntodo * elemincre);
+
+ if (elemnum >= repeat) /* completed a row; start on later row */
+ {
+ rowincre = elemnum / repeat;
+ rownum += rowincre;
+ elemnum = elemnum - (rowincre * repeat);
+ }
+ }
+ } /* End of main while Loop */
+
+
+ /*--------------------------------*/
+ /* check for numerical overflow */
+ /*--------------------------------*/
+ if (*status == OVERFLOW_ERR)
+ {
+ ffpmsg(
+ "Numerical overflow during type conversion while reading FITS data.");
+ *status = NUM_OVERFLOW;
+ }
+
+ } /* end of DEC Alpha special case */
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffi1uint(unsigned char *input,/* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ unsigned char tnull, /* I - value of FITS TNULLn keyword if any */
+ unsigned int nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ unsigned int *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to tnull. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = (unsigned int) input[ii]; /* copy input */
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DUINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DUINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UINT_MAX;
+ }
+ else
+ output[ii] = (unsigned int) dvalue;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ output[ii] = (unsigned int) input[ii];
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DUINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DUINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UINT_MAX;
+ }
+ else
+ output[ii] = (unsigned int) dvalue;
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffi2uint(short *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ short tnull, /* I - value of FITS TNULLn keyword if any */
+ unsigned int nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ unsigned int *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to tnull. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] < 0)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else
+ output[ii] = (unsigned int) input[ii];
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DUINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DUINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UINT_MAX;
+ }
+ else
+ output[ii] = (unsigned int) dvalue;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ if (input[ii] < 0)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else
+ output[ii] = (unsigned int) input[ii];
+ }
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DUINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DUINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UINT_MAX;
+ }
+ else
+ output[ii] = (unsigned int) dvalue;
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffi4uint(INT32BIT *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ INT32BIT tnull, /* I - value of FITS TNULLn keyword if any */
+ unsigned int nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ unsigned int *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to tnull. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 2147483648.)
+ {
+ /* Instead of adding 2147483648, it is more efficient */
+ /* to just flip the sign bit with the XOR operator */
+
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = ( *(unsigned int *) &input[ii] ) ^ 0x80000000;
+ }
+ else if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] < 0)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else
+ output[ii] = (unsigned int) input[ii]; /* copy to output */
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DUINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DUINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UINT_MAX;
+ }
+ else
+ output[ii] = (unsigned int) dvalue;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ if (scale == 1. && zero == 2147483648.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ output[ii] = ( *(unsigned int *) &input[ii] ) ^ 0x80000000;
+ }
+ }
+ else if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else if (input[ii] < 0)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else
+ output[ii] = (unsigned int) input[ii];
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DUINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DUINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UINT_MAX;
+ }
+ else
+ output[ii] = (unsigned int) dvalue;
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffi8uint(LONGLONG *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ long tnull, /* I - value of FITS TNULLn keyword if any */
+ unsigned int nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ unsigned int *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to tnull. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+#if (LONGSIZE == 32) && (! defined HAVE_LONGLONG)
+
+ /* This block of code is only used in cases where there is */
+ /* no native 8-byte integer support. We have to interpret */
+ /* the corresponding pair of 4-byte integers which are */
+ /* are equivalent to the 8-byte integer. */
+
+ long ii,jj,kk;
+ double dvalue;
+ unsigned long *uinput;
+
+ uinput = (unsigned long *) input;
+
+#if BYTESWAPPED /* jj points to the most significant part of the 8-byte int */
+ jj = 1;
+ kk = 0;
+#else
+ jj = 0;
+ kk = 1;
+#endif
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++, jj += 2, kk += 2)
+ {
+ if (uinput[jj] & 0x80000000) /* negative number */
+ dvalue = (uinput[jj] ^ 0xffffffff) * -4294967296. -
+ (uinput[kk] ^ 0xffffffff) - 1.;
+ else /* positive number */
+ dvalue = uinput[jj] * 4294967296. + uinput[kk];
+
+ if (dvalue < DUINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DUINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UINT_MAX;
+ }
+ else
+ output[ii] = (unsigned int) dvalue;
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++, jj += 2, kk += 2)
+ {
+ if (uinput[jj] & 0x80000000) /* negative number */
+ dvalue = ((uinput[jj] ^ 0xffffffff) * -4294967296. -
+ (uinput[kk] ^ 0xffffffff) - 1.) * scale + zero;
+ else /* positive number */
+ dvalue = (uinput[jj] * 4294967296. + uinput[kk])
+ * scale + zero;
+
+ if (dvalue < DUINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DUINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UINT_MAX;
+ }
+ else
+ output[ii] = (unsigned int) dvalue;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++, jj += 2, kk += 2)
+ {
+ if (uinput[jj] & 0x80000000) /* negative number */
+ dvalue = (uinput[jj] ^ 0xffffffff) * -4294967296. -
+ (uinput[kk] ^ 0xffffffff) - 1.;
+ else /* positive number */
+ dvalue = uinput[jj] * 4294967296. + uinput[kk];
+
+ if (dvalue == (double) tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ if (dvalue < DUINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DUINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UINT_MAX;
+ }
+ else
+ output[ii] = (unsigned int) dvalue;
+ }
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++, jj += 2, kk += 2)
+ {
+ if (uinput[jj] & 0x80000000) /* negative number */
+ dvalue = (uinput[jj] ^ 0xffffffff) * -4294967296. -
+ (uinput[kk] ^ 0xffffffff) - 1.;
+ else /* positive number */
+ dvalue = uinput[jj] * 4294967296. + uinput[kk];
+
+ if (dvalue == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ dvalue = dvalue * scale + zero;
+
+ if (dvalue < DUINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DUINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UINT_MAX;
+ }
+ else
+ output[ii] = (unsigned int) dvalue;
+ }
+ }
+ }
+ }
+
+#else
+
+ /* this block works on machines which support an 8-byte integer type */
+
+ long ii;
+ double dvalue;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] < 0)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (input[ii] > UINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UINT_MAX;
+ }
+ else
+ output[ii] = (unsigned int) input[ii];
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DUINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DUINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UINT_MAX;
+ }
+ else
+ output[ii] = (unsigned int) dvalue;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ if (input[ii] < 0)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (input[ii] > UINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UINT_MAX;
+ }
+ else
+ output[ii] = (unsigned int) input[ii];
+ }
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] == tnull)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DUINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DUINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UINT_MAX;
+ }
+ else
+ output[ii] = (unsigned int) dvalue;
+ }
+ }
+ }
+ }
+
+#endif
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffr4uint(float *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ unsigned int nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ unsigned int *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to NaN. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ long ii;
+ double dvalue;
+ short *sptr, iret;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] < DUINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (input[ii] > DUINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UINT_MAX;
+ }
+ else
+ output[ii] = (unsigned int) input[ii];
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DUINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DUINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UINT_MAX;
+ }
+ else
+ output[ii] = (unsigned int) dvalue;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ sptr = (short *) input;
+
+#if BYTESWAPPED && MACHINE != VAXVMS && MACHINE != ALPHAVMS
+ sptr++; /* point to MSBs */
+#endif
+
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++, sptr += 2)
+ {
+ if (0 != (iret = fnan(*sptr) ) ) /* test for NaN or underflow */
+ {
+ if (iret == 1) /* is it a NaN? */
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else /* it's an underflow */
+ output[ii] = 0;
+ }
+ else
+ {
+ if (input[ii] < DUINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (input[ii] > DUINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UINT_MAX;
+ }
+ else
+ output[ii] = (unsigned int) input[ii];
+ }
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++, sptr += 2)
+ {
+ if (0 != (iret = fnan(*sptr) ) ) /* test for NaN or underflow */
+ {
+ if (iret == 1) /* is it a NaN? */
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else /* it's an underflow */
+ {
+ if (zero < DUINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (zero > DUINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UINT_MAX;
+ }
+ else
+ output[ii] = (unsigned int) zero;
+ }
+ }
+ else
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DUINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DUINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UINT_MAX;
+ }
+ else
+ output[ii] = (unsigned int) dvalue;
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffr8uint(double *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ unsigned int nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ unsigned int *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file.
+ Check for null values and do datatype conversion and scaling if required.
+ The nullcheck code value determines how any null values in the input array
+ are treated. A null value is an input pixel that is equal to NaN. If
+ nullcheck = 0, then no checking for nulls is performed and any null values
+ will be transformed just like any other pixel. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ long ii;
+ double dvalue;
+ short *sptr, iret;
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] < DUINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (input[ii] > DUINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UINT_MAX;
+ }
+ else
+ output[ii] = (unsigned int) input[ii];
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DUINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DUINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UINT_MAX;
+ }
+ else
+ output[ii] = (unsigned int) dvalue;
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ sptr = (short *) input;
+
+#if BYTESWAPPED && MACHINE != VAXVMS && MACHINE != ALPHAVMS
+ sptr += 3; /* point to MSBs */
+#endif
+ if (scale == 1. && zero == 0.) /* no scaling */
+ {
+ for (ii = 0; ii < ntodo; ii++, sptr += 4)
+ {
+ if (0 != (iret = dnan(*sptr)) ) /* test for NaN or underflow */
+ {
+ if (iret == 1) /* is it a NaN? */
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else /* it's an underflow */
+ output[ii] = 0;
+ }
+ else
+ {
+ if (input[ii] < DUINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (input[ii] > DUINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UINT_MAX;
+ }
+ else
+ output[ii] = (unsigned int) input[ii];
+ }
+ }
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++, sptr += 4)
+ {
+ if (0 != (iret = dnan(*sptr)) ) /* test for NaN or underflow */
+ {
+ if (iret == 1) /* is it a NaN? */
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ else /* it's an underflow */
+ {
+ if (zero < DUINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (zero > DUINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UINT_MAX;
+ }
+ else
+ output[ii] = (unsigned int) zero;
+ }
+ }
+ else
+ {
+ dvalue = input[ii] * scale + zero;
+
+ if (dvalue < DUINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DUINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UINT_MAX;
+ }
+ else
+ output[ii] = (unsigned int) dvalue;
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fffstruint(char *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ long twidth, /* I - width of each substring of chars */
+ double implipower, /* I - power of 10 of implied decimal */
+ int nullcheck, /* I - null checking code; 0 = don't check */
+ /* 1:set null pixels = nullval */
+ /* 2: if null pixel, set nullarray = 1 */
+ char *snull, /* I - value of FITS null string, if any */
+ unsigned int nullval, /* I - set null pixels, if nullcheck = 1 */
+ char *nullarray, /* I - bad pixel array, if nullcheck = 2 */
+ int *anynull, /* O - set to 1 if any pixels are null */
+ unsigned int *output, /* O - array of converted pixels */
+ int *status) /* IO - error status */
+/*
+ Copy input to output following reading of the input from a FITS file. Check
+ for null values and do scaling if required. The nullcheck code value
+ determines how any null values in the input array are treated. A null
+ value is an input pixel that is equal to snull. If nullcheck= 0, then
+ no special checking for nulls is performed. If nullcheck = 1, then the
+ output pixel will be set = nullval if the corresponding input pixel is null.
+ If nullcheck = 2, then if the pixel is null then the corresponding value of
+ nullarray will be set to 1; the value of nullarray for non-null pixels
+ will = 0. The anynull parameter will be set = 1 if any of the returned
+ pixels are null, otherwise anynull will be returned with a value = 0;
+*/
+{
+ int nullen;
+ long ii;
+ double dvalue;
+ char *cstring, message[81];
+ char *cptr, *tpos;
+ char tempstore, chrzero = '0';
+ double val, power;
+ int exponent, sign, esign, decpt;
+
+ nullen = strlen(snull);
+ cptr = input; /* pointer to start of input string */
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ cstring = cptr;
+ /* temporarily insert a null terminator at end of the string */
+ tpos = cptr + twidth;
+ tempstore = *tpos;
+ *tpos = 0;
+
+ /* check if null value is defined, and if the */
+ /* column string is identical to the null string */
+ if (snull[0] != ASCII_NULL_UNDEFINED &&
+ !strncmp(snull, cptr, nullen) )
+ {
+ if (nullcheck)
+ {
+ *anynull = 1;
+ if (nullcheck == 1)
+ output[ii] = nullval;
+ else
+ nullarray[ii] = 1;
+ }
+ cptr += twidth;
+ }
+ else
+ {
+ /* value is not the null value, so decode it */
+ /* remove any embedded blank characters from the string */
+
+ decpt = 0;
+ sign = 1;
+ val = 0.;
+ power = 1.;
+ exponent = 0;
+ esign = 1;
+
+ while (*cptr == ' ') /* skip leading blanks */
+ cptr++;
+
+ if (*cptr == '-' || *cptr == '+') /* check for leading sign */
+ {
+ if (*cptr == '-')
+ sign = -1;
+
+ cptr++;
+
+ while (*cptr == ' ') /* skip blanks between sign and value */
+ cptr++;
+ }
+
+ while (*cptr >= '0' && *cptr <= '9')
+ {
+ val = val * 10. + *cptr - chrzero; /* accumulate the value */
+ cptr++;
+
+ while (*cptr == ' ') /* skip embedded blanks in the value */
+ cptr++;
+ }
+
+ if (*cptr == '.') /* check for decimal point */
+ {
+ decpt = 1; /* set flag to show there was a decimal point */
+ cptr++;
+ while (*cptr == ' ') /* skip any blanks */
+ cptr++;
+
+ while (*cptr >= '0' && *cptr <= '9')
+ {
+ val = val * 10. + *cptr - chrzero; /* accumulate the value */
+ power = power * 10.;
+ cptr++;
+
+ while (*cptr == ' ') /* skip embedded blanks in the value */
+ cptr++;
+ }
+ }
+
+ if (*cptr == 'E' || *cptr == 'D') /* check for exponent */
+ {
+ cptr++;
+ while (*cptr == ' ') /* skip blanks */
+ cptr++;
+
+ if (*cptr == '-' || *cptr == '+') /* check for exponent sign */
+ {
+ if (*cptr == '-')
+ esign = -1;
+
+ cptr++;
+
+ while (*cptr == ' ') /* skip blanks between sign and exp */
+ cptr++;
+ }
+
+ while (*cptr >= '0' && *cptr <= '9')
+ {
+ exponent = exponent * 10 + *cptr - chrzero; /* accumulate exp */
+ cptr++;
+
+ while (*cptr == ' ') /* skip embedded blanks */
+ cptr++;
+ }
+ }
+
+ if (*cptr != 0) /* should end up at the null terminator */
+ {
+ sprintf(message, "Cannot read number from ASCII table");
+ ffpmsg(message);
+ sprintf(message, "Column field = %s.", cstring);
+ ffpmsg(message);
+ /* restore the char that was overwritten by the null */
+ *tpos = tempstore;
+ return(*status = BAD_C2D);
+ }
+
+ if (!decpt) /* if no explicit decimal, use implied */
+ power = implipower;
+
+ dvalue = (sign * val / power) * pow(10., (double) (esign * exponent));
+
+ dvalue = dvalue * scale + zero; /* apply the scaling */
+
+ if (dvalue < DUINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DUINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UINT_MAX;
+ }
+ else
+ output[ii] = (long) dvalue;
+ }
+ /* restore the char that was overwritten by the null */
+ *tpos = tempstore;
+ }
+ return(*status);
+}
diff --git a/pkg/tbtables/cfitsio/getkey.c b/pkg/tbtables/cfitsio/getkey.c
new file mode 100644
index 00000000..698eb55c
--- /dev/null
+++ b/pkg/tbtables/cfitsio/getkey.c
@@ -0,0 +1,2544 @@
+/* This file, getkey.c, contains routines that read keywords from */
+/* a FITS header. */
+
+/* The FITSIO software was written by William Pence at the High Energy */
+/* Astrophysic Science Archive Research Center (HEASARC) at the NASA */
+/* Goddard Space Flight Center. */
+
+#include <string.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <ctype.h>
+/* stddef.h is apparently needed to define size_t */
+#include <stddef.h>
+#include "fitsio2.h"
+
+/*--------------------------------------------------------------------------*/
+int ffghsp(fitsfile *fptr, /* I - FITS file pointer */
+ int *nexist, /* O - number of existing keywords in header */
+ int *nmore, /* O - how many more keywords will fit */
+ int *status) /* IO - error status */
+/*
+ returns the number of existing keywords (not counting the END keyword)
+ and the number of more keyword that will fit in the current header
+ without having to insert more FITS blocks.
+*/
+{
+ if (*status > 0)
+ return(*status);
+
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+
+ *nexist = ( ((fptr->Fptr)->headend) -
+ ((fptr->Fptr)->headstart[(fptr->Fptr)->curhdu]) ) / 80;
+
+ if ((fptr->Fptr)->datastart == DATA_UNDEFINED)
+ {
+ if (nmore)
+ *nmore = -1; /* data not written yet, so room for any keywords */
+ }
+ else
+ {
+ /* calculate space available between the data and the END card */
+ if (nmore)
+ *nmore = ((fptr->Fptr)->datastart - (fptr->Fptr)->headend) / 80 - 1;
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffghps(fitsfile *fptr, /* I - FITS file pointer */
+ int *nexist, /* O - number of existing keywords in header */
+ int *position, /* O - position of next keyword to be read */
+ int *status) /* IO - error status */
+/*
+ return the number of existing keywords and the position of the next
+ keyword that will be read.
+*/
+{
+ if (*status > 0)
+ return(*status);
+
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+
+ *nexist = ( ((fptr->Fptr)->headend) - ((fptr->Fptr)->headstart[(fptr->Fptr)->curhdu]) ) / 80;
+ *position = ( ((fptr->Fptr)->nextkey) - ((fptr->Fptr)->headstart[(fptr->Fptr)->curhdu]) ) / 80 + 1;
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffnchk(fitsfile *fptr, /* I - FITS file pointer */
+ int *status) /* IO - error status */
+/*
+ function returns the position of the first null character (ASCII 0), if
+ any, in the current header. Null characters are illegal, but the other
+ CFITSIO routines that read the header will not detect this error, because
+ the null gets interpreted as a normal end of string character.
+*/
+{
+ long ii, nblock;
+ OFF_T bytepos;
+ int length, nullpos;
+ char block[2881];
+
+ if (*status > 0)
+ return(*status);
+
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+
+ if ((fptr->Fptr)->datastart == DATA_UNDEFINED)
+ {
+ return(0); /* Don't check a file that is just being created. */
+ /* It cannot contain nulls since CFITSIO wrote it. */
+ }
+ else
+ {
+ /* calculate number of blocks in the header */
+ nblock = ( (fptr->Fptr)->datastart -
+ (fptr->Fptr)->headstart[(fptr->Fptr)->curhdu] ) / 2880;
+ }
+
+ bytepos = (fptr->Fptr)->headstart[(fptr->Fptr)->curhdu];
+ ffmbyt(fptr, bytepos, REPORT_EOF, status); /* move to read pos. */
+
+ block[2880] = '\0';
+ for (ii = 0; ii < nblock; ii++)
+ {
+ if (ffgbyt(fptr, 2880, block, status) > 0)
+ return(0); /* read error of some sort */
+
+ length = strlen(block);
+ if (length != 2880)
+ {
+ nullpos = (ii * 2880) + length + 1;
+ return(nullpos);
+ }
+ }
+
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int ffmaky(fitsfile *fptr, /* I - FITS file pointer */
+ int nrec, /* I - one-based keyword number to move to */
+ int *status) /* IO - error status */
+{
+/*
+ move pointer to the specified absolute keyword position. E.g. this keyword
+ will then be read by the next call to ffgnky.
+*/
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+
+ (fptr->Fptr)->nextkey = (fptr->Fptr)->headstart[(fptr->Fptr)->curhdu] + ( (nrec - 1) * 80);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffmrky(fitsfile *fptr, /* I - FITS file pointer */
+ int nmove, /* I - relative number of keywords to move */
+ int *status) /* IO - error status */
+{
+/*
+ move pointer to the specified keyword position relative to the current
+ position. E.g. this keyword will then be read by the next call to ffgnky.
+*/
+
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+
+ (fptr->Fptr)->nextkey += (nmove * 80);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgnky(fitsfile *fptr, /* I - FITS file pointer */
+ char *card, /* O - card string */
+ int *status) /* IO - error status */
+/*
+ read the next keyword from the header - used internally by cfitsio
+*/
+{
+ int jj, nrec;
+ OFF_T bytepos, endhead;
+ char message[FLEN_ERRMSG];
+
+ if (*status > 0)
+ return(*status);
+
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+
+ card[0] = '\0'; /* make sure card is terminated, even affer read error */
+
+/*
+ Check that nextkey points to a legal keyword position. Note that headend
+ is the current end of the header, i.e., the position where a new keyword
+ would be appended, however, if there are more than 1 FITS block worth of
+ blank keywords at the end of the header (36 keywords per 2880 byte block)
+ then the actual physical END card must be located at a starting position
+ which is just 2880 bytes prior to the start of the data unit.
+*/
+
+ bytepos = (fptr->Fptr)->nextkey;
+ endhead = maxvalue( ((fptr->Fptr)->headend), ((fptr->Fptr)->datastart - 2880) );
+
+ /* nextkey must be < endhead and > than headstart */
+ if (bytepos > endhead ||
+ bytepos < (fptr->Fptr)->headstart[(fptr->Fptr)->curhdu] )
+ {
+ nrec=(bytepos - (fptr->Fptr)->headstart[(fptr->Fptr)->curhdu]) / 80 + 1;
+ sprintf(message, "Cannot get keyword number %d. It does not exist.",
+ nrec);
+ ffpmsg(message);
+ return(*status = KEY_OUT_BOUNDS);
+ }
+
+ ffmbyt(fptr, bytepos, REPORT_EOF, status); /* move to read pos. */
+
+ card[80] = '\0'; /* make sure card is terminate, even if ffgbyt fails */
+
+ if (ffgbyt(fptr, 80, card, status) <= 0)
+ {
+ (fptr->Fptr)->nextkey += 80; /* increment pointer to next keyword */
+
+ /* strip off trailing blanks with terminated string */
+ jj = 79;
+ while (jj >= 0 && card[jj] == ' ')
+ jj--;
+
+ card[jj + 1] = '\0';
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgnxk( fitsfile *fptr, /* I - FITS file pointer */
+ char **inclist, /* I - list of included keyword names */
+ int ninc, /* I - number of names in inclist */
+ char **exclist, /* I - list of excluded keyword names */
+ int nexc, /* I - number of names in exclist */
+ char *card, /* O - first matching keyword */
+ int *status) /* IO - error status */
+/*
+ Return the next keyword that matches one of the names in inclist
+ but does not match any of the names in exclist. The search
+ goes from the current position to the end of the header, only.
+ Wild card characters may be used in the name lists ('*', '?' and '#').
+*/
+{
+ int casesn, match, exact, namelen;
+ long ii, jj;
+ char keybuf[FLEN_CARD], keyname[FLEN_KEYWORD];
+
+ card[0] = '\0';
+ if (*status > 0)
+ return(*status);
+
+ casesn = FALSE;
+
+ /* get next card, and return with an error if hit end of header */
+ while( ffgcrd(fptr, "*", keybuf, status) <= 0)
+ {
+ ffgknm(keybuf, keyname, &namelen, status); /* get the keyword name */
+
+ /* does keyword match any names in the include list? */
+ for (ii = 0; ii < ninc; ii++)
+ {
+ ffcmps(inclist[ii], keyname, casesn, &match, &exact);
+ if (match)
+ {
+ /* does keyword match any names in the exclusion list? */
+ jj = -1;
+ while ( ++jj < nexc )
+ {
+ ffcmps(exclist[jj], keyname, casesn, &match, &exact);
+ if (match)
+ break;
+ }
+
+ if (jj >= nexc)
+ {
+ /* not in exclusion list, so return this keyword */
+ strcat(card, keybuf);
+ return(*status);
+ }
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgky( fitsfile *fptr, /* I - FITS file pointer */
+ int datatype, /* I - datatype of the value */
+ char *keyname, /* I - name of keyword to read */
+ void *value, /* O - keyword value */
+ char *comm, /* O - keyword comment */
+ int *status) /* IO - error status */
+/*
+ Read (get) the keyword value and comment from the FITS header.
+ Reads a keyword value with the datatype specified by the 2nd argument.
+*/
+{
+ long longval;
+ double doubleval;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ if (datatype == TSTRING)
+ {
+ ffgkys(fptr, keyname, (char *) value, comm, status);
+ }
+ else if (datatype == TBYTE)
+ {
+ if (ffgkyj(fptr, keyname, &longval, comm, status) <= 0)
+ {
+ if (longval > UCHAR_MAX || longval < 0)
+ *status = NUM_OVERFLOW;
+ else
+ *(unsigned char *) value = longval;
+ }
+ }
+ else if (datatype == TSBYTE)
+ {
+ if (ffgkyj(fptr, keyname, &longval, comm, status) <= 0)
+ {
+ if (longval > 127 || longval < -128)
+ *status = NUM_OVERFLOW;
+ else
+ *(signed char *) value = longval;
+ }
+ }
+ else if (datatype == TUSHORT)
+ {
+ if (ffgkyj(fptr, keyname, &longval, comm, status) <= 0)
+ {
+ if (longval > USHRT_MAX || longval < 0)
+ *status = NUM_OVERFLOW;
+ else
+ *(unsigned short *) value = longval;
+ }
+ }
+ else if (datatype == TSHORT)
+ {
+ if (ffgkyj(fptr, keyname, &longval, comm, status) <= 0)
+ {
+ if (longval > SHRT_MAX || longval < SHRT_MIN)
+ *status = NUM_OVERFLOW;
+ else
+ *(short *) value = longval;
+ }
+ }
+ else if (datatype == TUINT)
+ {
+ if (ffgkyj(fptr, keyname, &longval, comm, status) <= 0)
+ {
+ if (longval > (long) UINT_MAX || longval < 0)
+ *status = NUM_OVERFLOW;
+ else
+ *(unsigned int *) value = longval;
+ }
+ }
+ else if (datatype == TINT)
+ {
+ if (ffgkyj(fptr, keyname, &longval, comm, status) <= 0)
+ {
+ if (longval > INT_MAX || longval < INT_MIN)
+ *status = NUM_OVERFLOW;
+ else
+ *(int *) value = longval;
+ }
+ }
+ else if (datatype == TLOGICAL)
+ {
+ ffgkyl(fptr, keyname, (int *) value, comm, status);
+ }
+ else if (datatype == TULONG)
+ {
+ if (ffgkyd(fptr, keyname, &doubleval, comm, status) <= 0)
+ {
+ if (doubleval > (double) ULONG_MAX || doubleval < 0)
+ *status = NUM_OVERFLOW;
+ else
+ *(unsigned long *) value = doubleval;
+ }
+ }
+ else if (datatype == TLONG)
+ {
+ ffgkyj(fptr, keyname, (long *) value, comm, status);
+ }
+ else if (datatype == TFLOAT)
+ {
+ ffgkye(fptr, keyname, (float *) value, comm, status);
+ }
+ else if (datatype == TDOUBLE)
+ {
+ ffgkyd(fptr, keyname, (double *) value, comm, status);
+ }
+ else if (datatype == TCOMPLEX)
+ {
+ ffgkyc(fptr, keyname, (float *) value, comm, status);
+ }
+ else if (datatype == TDBLCOMPLEX)
+ {
+ ffgkym(fptr, keyname, (double *) value, comm, status);
+ }
+ else
+ *status = BAD_DATATYPE;
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgkey( fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - name of keyword to read */
+ char *keyval, /* O - keyword value */
+ char *comm, /* O - keyword comment */
+ int *status) /* IO - error status */
+/*
+ Read (get) the named keyword, returning the keyword value and comment.
+ The value is just the literal string of characters in the value field
+ of the keyword. In the case of a string valued keyword, the returned
+ value includes the leading and closing quote characters. The value may be
+ up to 70 characters long, and the comment may be up to 72 characters long.
+ If the keyword has no value (no equal sign in column 9) then a null value
+ is returned.
+*/
+{
+ char card[FLEN_CARD];
+
+ keyval[0] = '\0';
+ if (comm)
+ comm[0] = '\0';
+
+ if (*status > 0)
+ return(*status);
+
+ if (ffgcrd(fptr, keyname, card, status) > 0) /* get the 80-byte card */
+ return(*status);
+
+ ffpsvc(card, keyval, comm, status); /* parse the value and comment */
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgrec( fitsfile *fptr, /* I - FITS file pointer */
+ int nrec, /* I - number of keyword to read */
+ char *card, /* O - keyword card */
+ int *status) /* IO - error status */
+/*
+ Read (get) the nrec-th keyword, returning the entire keyword card up to
+ 80 characters long. The first keyword in the header has nrec = 1, not 0.
+ The returned card value is null terminated with any trailing blank
+ characters removed. If nrec = 0, then this routine simply moves the
+ current header pointer to the top of the header.
+*/
+{
+ if (*status > 0)
+ return(*status);
+
+ if (nrec == 0)
+ {
+ ffmaky(fptr, 1, status); /* simply move to beginning of header */
+ card[0] = '\0'; /* and return null card */
+ }
+ else if (nrec > 0)
+ {
+ ffmaky(fptr, nrec, status);
+ ffgnky(fptr, card, status);
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgcrd( fitsfile *fptr, /* I - FITS file pointer */
+ char *name, /* I - name of keyword to read */
+ char *card, /* O - keyword card */
+ int *status) /* IO - error status */
+/*
+ Read (get) the named keyword, returning the entire keyword card up to
+ 80 characters long. The first keyword in the header has nrec = 1, not 0.
+ The returned card value is null terminated with any trailing blank
+ characters removed.
+
+ If the input name contains wild cards ('?' matches any single char
+ and '*' matches any sequence of chars, # matches any string of decimal
+ digits) then the search ends once the end of header is reached and does
+ not automatically resume from the top of the header.
+*/
+{
+ int nkeys, nextkey, ntodo, namelen, namelen_limit, namelenminus1, cardlen;
+ int ii = 0, jj, kk, wild, match, exact, hier = 0;
+ char keyname[FLEN_KEYWORD], cardname[FLEN_KEYWORD];
+ char *ptr1, *ptr2, *gotstar;
+
+ if (*status > 0)
+ return(*status);
+
+ *keyname = '\0';
+
+ while (name[ii] == ' ') /* skip leading blanks in name */
+ ii++;
+
+ strncat(keyname, &name[ii], FLEN_KEYWORD - 1);
+
+ namelen = strlen(keyname);
+
+ while (namelen > 0 && keyname[namelen - 1] == ' ')
+ namelen--; /* ignore trailing blanks in name */
+
+ keyname[namelen] = '\0'; /* terminate the name */
+
+ for (ii=0; ii < namelen; ii++)
+ keyname[ii] = toupper(keyname[ii]); /* make upper case */
+
+ if (FSTRNCMP("HIERARCH", keyname, 8) == 0)
+ {
+ if (namelen == 8)
+ {
+ /* special case: just looking for any HIERARCH keyword */
+ hier = 1;
+ }
+ else
+ {
+ /* ignore the leading HIERARCH and look for the 'real' name */
+ /* starting with first non-blank character following HIERARCH */
+ ptr1 = keyname;
+ ptr2 = &keyname[8];
+
+ while(*ptr2 == ' ')
+ ptr2++;
+
+ namelen = 0;
+ while(*ptr2)
+ {
+ *ptr1 = *ptr2;
+ ptr1++;
+ ptr2++;
+ namelen++;
+ }
+ *ptr1 = '\0';
+ }
+ }
+
+ /* does input name contain wild card chars? ('?', '*', or '#') */
+ /* wild cards are currently not supported with HIERARCH keywords */
+
+ namelen_limit = namelen;
+ gotstar = 0;
+ if (namelen < 9 &&
+ (strchr(keyname,'?') || (gotstar = strchr(keyname,'*')) ||
+ strchr(keyname,'#')) )
+ {
+ wild = 1;
+
+ /* if we found a '*' wild card in the name, there might be */
+ /* more than one. Support up to 2 '*' in the template. */
+ /* Thus we need to compare keywords whose names have at least */
+ /* namelen - 2 characters. */
+ if (gotstar)
+ namelen_limit -= 2;
+ }
+ else
+ wild = 0;
+
+ ffghps(fptr, &nkeys, &nextkey, status); /* get no. keywords and position */
+
+ namelenminus1 = maxvalue(namelen - 1, 1);
+ ntodo = nkeys - nextkey + 1; /* first, read from next keyword to end */
+ for (jj=0; jj < 2; jj++)
+ {
+ for (kk = 0; kk < ntodo; kk++)
+ {
+ ffgnky(fptr, card, status); /* get next keyword */
+
+ if (hier)
+ {
+ if (FSTRNCMP("HIERARCH", card, 8) == 0)
+ return(*status); /* found a HIERARCH keyword */
+ }
+ else
+ {
+ ffgknm(card, cardname, &cardlen, status); /* get the keyword name */
+
+ if (cardlen >= namelen_limit) /* can't match if card < name */
+ {
+ /* if there are no wild cards, lengths must be the same */
+ if (!( !wild && cardlen != namelen) )
+ {
+ for (ii=0; ii < cardlen; ii++)
+ {
+ /* make sure keyword is in uppercase */
+ if (cardname[ii] > 96)
+ {
+ /* This assumes the ASCII character set in which */
+ /* upper case characters start at ASCII(97) */
+ /* Timing tests showed that this is 20% faster */
+ /* than calling the isupper function. */
+
+ cardname[ii] = toupper(cardname[ii]); /* make upper case */
+ }
+ }
+
+ if (wild)
+ {
+ ffcmps(keyname, cardname, 1, &match, &exact);
+ if (match)
+ return(*status); /* found a matching keyword */
+ }
+ else if (keyname[namelenminus1] == cardname[namelenminus1])
+ {
+ /* test the last character of the keyword name first, on */
+ /* the theory that it is less likely to match then the first */
+ /* character since many keywords begin with 'T', for example */
+
+ if (FSTRNCMP(keyname, cardname, namelenminus1) == 0)
+ {
+ return(*status); /* found the matching keyword */
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (wild || jj == 1)
+ break; /* stop at end of header if template contains wildcards */
+
+ ffmaky(fptr, 1, status); /* reset pointer to beginning of header */
+ ntodo = nextkey - 1; /* number of keyword to read */
+ }
+
+ return(*status = KEY_NO_EXIST); /* couldn't find the keyword */
+}
+/*--------------------------------------------------------------------------*/
+int ffgknm( char *card, /* I - keyword card */
+ char *name, /* O - name of the keyword */
+ int *length, /* O - length of the keyword name */
+ int *status) /* IO - error status */
+
+/*
+ Return the name of the keyword, and the name length. This supports the
+ ESO HIERARCH convention where keyword names may be > 8 characters long.
+*/
+{
+ char *ptr1, *ptr2;
+ int ii;
+
+ *name = '\0';
+ *length = 0;
+
+ /* support for ESO HIERARCH keywords; find the '=' */
+ if (FSTRNCMP(card, "HIERARCH ", 9) == 0)
+ {
+ ptr2 = strchr(card, '=');
+
+ if (!ptr2) /* no value indicator ??? */
+ {
+ /* this probably indicates an error, so just return FITS name */
+ strcat(name, "HIERARCH");
+ *length = 8;
+ return(*status);
+ }
+
+ /* find the start and end of the HIERARCH name */
+ ptr1 = &card[9];
+ while (*ptr1 == ' ') /* skip spaces */
+ ptr1++;
+
+ strncat(name, ptr1, ptr2 - ptr1);
+ ii = ptr2 - ptr1;
+
+ while (ii > 0 && name[ii - 1] == ' ') /* remove trailing spaces */
+ ii--;
+
+ name[ii] = '\0';
+ *length = ii;
+ }
+ else
+ {
+ for (ii = 0; ii < 8; ii++)
+ {
+ /* look for string terminator, or a blank */
+ if (*(card+ii) != ' ' && *(card+ii) !='\0')
+ {
+ *(name+ii) = *(card+ii);
+ }
+ else
+ {
+ name[ii] = '\0';
+ *length = ii;
+ return(*status);
+ }
+ }
+
+ /* if we got here, keyword is 8 characters long */
+ name[8] = '\0';
+ *length = 8;
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgunt( fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - name of keyword to read */
+ char *unit, /* O - keyword units */
+ int *status) /* IO - error status */
+/*
+ Read (get) the units string from the comment field of the existing
+ keyword. This routine uses a local FITS convention (not defined in the
+ official FITS standard) in which the units are enclosed in
+ square brackets following the '/' comment field delimiter, e.g.:
+
+ KEYWORD = 12 / [kpc] comment string goes here
+*/
+{
+ char valstring[FLEN_VALUE];
+ char comm[FLEN_COMMENT];
+ char *loc;
+
+ if (*status > 0)
+ return(*status);
+
+ ffgkey(fptr, keyname, valstring, comm, status); /* read the keyword */
+
+ if (comm[0] == '[')
+ {
+ loc = strchr(comm, ']'); /* find the closing bracket */
+ if (loc)
+ *loc = '\0'; /* terminate the string */
+
+ strcpy(unit, &comm[1]); /* copy the string */
+ }
+ else
+ unit[0] = '\0';
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgkys( fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - name of keyword to read */
+ char *value, /* O - keyword value */
+ char *comm, /* O - keyword comment */
+ int *status) /* IO - error status */
+/*
+ Get KeYword with a String value:
+ Read (get) a simple string valued keyword. The returned value may be up to
+ 68 chars long ( + 1 null terminator char). The routine does not support the
+ HEASARC convention for continuing long string values over multiple keywords.
+ The ffgkls routine may be used to read long continued strings. The returned
+ comment string may be up to 69 characters long (including null terminator).
+*/
+{
+ char valstring[FLEN_VALUE];
+
+ if (*status > 0)
+ return(*status);
+
+ ffgkey(fptr, keyname, valstring, comm, status); /* read the keyword */
+ value[0] = '\0';
+ ffc2s(valstring, value, status); /* remove quotes from string */
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgkls( fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - name of keyword to read */
+ char **value, /* O - pointer to keyword value */
+ char *comm, /* O - keyword comment */
+ int *status) /* IO - error status */
+/*
+ Get Keyword with possible Long String value:
+ Read (get) the named keyword, returning the value and comment.
+ The returned value string may be arbitrarily long (by using the HEASARC
+ convention for continuing long string values over multiple keywords) so
+ this routine allocates the required memory for the returned string value.
+ It is up to the calling routine to free the memory once it is finished
+ with the value string. The returned comment string may be up to 69
+ characters long.
+*/
+{
+ char valstring[FLEN_VALUE];
+ int contin;
+ size_t len;
+
+ if (*status > 0)
+ return(*status);
+
+ *value = NULL; /* initialize a null pointer in case of error */
+
+ ffgkey(fptr, keyname, valstring, comm, status); /* read the keyword */
+
+ if (*status > 0)
+ return(*status);
+
+ if (!valstring[0]) /* null value string? */
+ {
+ *value = (char *) malloc(1); /* allocate and return a null string */
+ **value = '\0';
+ }
+ else
+ {
+ /* allocate space, plus 1 for null */
+ *value = (char *) malloc(strlen(valstring) + 1);
+
+ ffc2s(valstring, *value, status); /* convert string to value */
+ len = strlen(*value);
+
+ /* If last character is a & then value may be continued on next keyword */
+ contin = 1;
+ while (contin)
+ {
+ if (len && *(*value+len-1) == '&') /* is last char an anpersand? */
+ {
+ ffgcnt(fptr, valstring, status);
+ if (*valstring) /* a null valstring indicates no continuation */
+ {
+ *(*value+len-1) = '\0'; /* erase the trailing & char */
+ len += strlen(valstring) - 1;
+ *value = (char *) realloc(*value, len + 1); /* increase size */
+ strcat(*value, valstring); /* append the continued chars */
+ }
+ else
+ contin = 0;
+ }
+ else
+ contin = 0;
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgcnt( fitsfile *fptr, /* I - FITS file pointer */
+ char *value, /* O - continued string value */
+ int *status) /* IO - error status */
+/*
+ Attempt to read the next keyword, returning the string value
+ if it is a continuation of the previous string keyword value.
+ This uses the HEASARC convention for continuing long string values
+ over multiple keywords. Each continued string is terminated with a
+ backslash character, and the continuation follows on the next keyword
+ which must have the name CONTINUE without an equal sign in column 9
+ of the card. If the next card is not a continuation, then the returned
+ value string will be null.
+*/
+{
+ int tstatus;
+ char card[FLEN_CARD], strval[FLEN_VALUE], comm[FLEN_COMMENT];
+
+ if (*status > 0)
+ return(*status);
+
+ tstatus = 0;
+ value[0] = '\0';
+
+ if (ffgnky(fptr, card, &tstatus) > 0) /* read next keyword */
+ return(*status); /* hit end of header */
+
+ if (strncmp(card, "CONTINUE ", 10) == 0) /* a continuation card? */
+ {
+ strncpy(card, "D2345678= ", 10); /* overwrite a dummy keyword name */
+ ffpsvc(card, strval, comm, &tstatus); /* get the string value */
+ ffc2s(strval, value, &tstatus); /* remove the surrounding quotes */
+
+ if (tstatus) /* return null if error status was returned */
+ value[0] = '\0';
+ }
+ else
+ ffmrky(fptr, -1, status); /* reset the keyword pointer */
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgkyl( fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - name of keyword to read */
+ int *value, /* O - keyword value */
+ char *comm, /* O - keyword comment */
+ int *status) /* IO - error status */
+/*
+ Read (get) the named keyword, returning the value and comment.
+ The returned value = 1 if the keyword is true, else = 0 if false.
+ The comment may be up to 69 characters long.
+*/
+{
+ char valstring[FLEN_VALUE];
+
+ if (*status > 0)
+ return(*status);
+
+ ffgkey(fptr, keyname, valstring, comm, status); /* read the keyword */
+ ffc2l(valstring, value, status); /* convert string to value */
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgkyj( fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - name of keyword to read */
+ long *value, /* O - keyword value */
+ char *comm, /* O - keyword comment */
+ int *status) /* IO - error status */
+/*
+ Read (get) the named keyword, returning the value and comment.
+ The value will be implicitly converted to a (long) integer if it not
+ already of this datatype. The comment may be up to 69 characters long.
+*/
+{
+ char valstring[FLEN_VALUE];
+
+ if (*status > 0)
+ return(*status);
+
+ ffgkey(fptr, keyname, valstring, comm, status); /* read the keyword */
+ ffc2i(valstring, value, status); /* convert string to value */
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgkye( fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - name of keyword to read */
+ float *value, /* O - keyword value */
+ char *comm, /* O - keyword comment */
+ int *status) /* IO - error status */
+/*
+ Read (get) the named keyword, returning the value and comment.
+ The value will be implicitly converted to a float if it not
+ already of this datatype. The comment may be up to 69 characters long.
+*/
+{
+ char valstring[FLEN_VALUE];
+
+ if (*status > 0)
+ return(*status);
+
+ ffgkey(fptr, keyname, valstring, comm, status); /* read the keyword */
+ ffc2r(valstring, value, status); /* convert string to value */
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgkyd( fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - name of keyword to read */
+ double *value, /* O - keyword value */
+ char *comm, /* O - keyword comment */
+ int *status) /* IO - error status */
+/*
+ Read (get) the named keyword, returning the value and comment.
+ The value will be implicitly converted to a double if it not
+ already of this datatype. The comment may be up to 69 characters long.
+*/
+{
+ char valstring[FLEN_VALUE];
+
+ if (*status > 0)
+ return(*status);
+
+ ffgkey(fptr, keyname, valstring, comm, status); /* read the keyword */
+ ffc2d(valstring, value, status); /* convert string to value */
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgkyc( fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - name of keyword to read */
+ float *value, /* O - keyword value (real,imag) */
+ char *comm, /* O - keyword comment */
+ int *status) /* IO - error status */
+/*
+ Read (get) the named keyword, returning the value and comment.
+ The keyword must have a complex value. No implicit data conversion
+ will be performed.
+*/
+{
+ char valstring[FLEN_VALUE], message[81];
+ int len;
+
+ if (*status > 0)
+ return(*status);
+
+ ffgkey(fptr, keyname, valstring, comm, status); /* read the keyword */
+
+ if (valstring[0] != '(' ) /* test that this is a complex keyword */
+ {
+ sprintf(message, "keyword %s does not have a complex value (ffgkyc):",
+ keyname);
+ ffpmsg(message);
+ ffpmsg(valstring);
+ return(*status = BAD_C2F);
+ }
+
+ valstring[0] = ' '; /* delete the opening parenthesis */
+ len = strcspn(valstring, ")" );
+ valstring[len] = '\0'; /* delete the closing parenthesis */
+
+ len = strcspn(valstring, ",");
+ valstring[len] = '\0';
+
+ ffc2r(valstring, &value[0], status); /* convert the real part */
+ ffc2r(&valstring[len + 1], &value[1], status); /* convert imag. part */
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgkym( fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - name of keyword to read */
+ double *value, /* O - keyword value (real,imag) */
+ char *comm, /* O - keyword comment */
+ int *status) /* IO - error status */
+/*
+ Read (get) the named keyword, returning the value and comment.
+ The keyword must have a complex value. No implicit data conversion
+ will be performed.
+*/
+{
+ char valstring[FLEN_VALUE], message[81];
+ int len;
+
+ if (*status > 0)
+ return(*status);
+
+ ffgkey(fptr, keyname, valstring, comm, status); /* read the keyword */
+
+ if (valstring[0] != '(' ) /* test that this is a complex keyword */
+ {
+ sprintf(message, "keyword %s does not have a complex value (ffgkym):",
+ keyname);
+ ffpmsg(message);
+ ffpmsg(valstring);
+ return(*status = BAD_C2D);
+ }
+
+ valstring[0] = ' '; /* delete the opening parenthesis */
+ len = strcspn(valstring, ")" );
+ valstring[len] = '\0'; /* delete the closing parenthesis */
+
+ len = strcspn(valstring, ",");
+ valstring[len] = '\0';
+
+ ffc2d(valstring, &value[0], status); /* convert the real part */
+ ffc2d(&valstring[len + 1], &value[1], status); /* convert the imag. part */
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgkyt( fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - name of keyword to read */
+ long *ivalue, /* O - integer part of keyword value */
+ double *fraction, /* O - fractional part of keyword value */
+ char *comm, /* O - keyword comment */
+ int *status) /* IO - error status */
+/*
+ Read (get) the named keyword, returning the value and comment.
+ The integer and fractional parts of the value are returned in separate
+ variables, to allow more numerical precision to be passed. This
+ effectively passes a 'triple' precision value, with a 4-byte integer
+ and an 8-byte fraction. The comment may be up to 69 characters long.
+*/
+{
+ char valstring[FLEN_VALUE];
+ char *loc;
+
+ if (*status > 0)
+ return(*status);
+
+ ffgkey(fptr, keyname, valstring, comm, status); /* read the keyword */
+
+ /* read the entire value string as a double, to get the integer part */
+ ffc2d(valstring, fraction, status);
+
+ *ivalue = (long) *fraction;
+
+ *fraction = *fraction - *ivalue;
+
+ /* see if we need to read the fractional part again with more precision */
+ /* look for decimal point, without an exponential E or D character */
+
+ loc = strchr(valstring, '.');
+ if (loc)
+ {
+ if (!strchr(valstring, 'E') && !strchr(valstring, 'D'))
+ ffc2d(loc, fraction, status);
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgkyn( fitsfile *fptr, /* I - FITS file pointer */
+ int nkey, /* I - number of the keyword to read */
+ char *keyname, /* O - name of the keyword */
+ char *value, /* O - keyword value */
+ char *comm, /* O - keyword comment */
+ int *status) /* IO - error status */
+/*
+ Read (get) the nkey-th keyword returning the keyword name, value and comment.
+ The value is just the literal string of characters in the value field
+ of the keyword. In the case of a string valued keyword, the returned
+ value includes the leading and closing quote characters. The value may be
+ up to 70 characters long, and the comment may be up to 72 characters long.
+ If the keyword has no value (no equal sign in column 9) then a null value
+ is returned. If comm = NULL, then do not return the comment string.
+*/
+{
+ char card[FLEN_CARD], sbuff[FLEN_CARD];
+ int namelen;
+
+ keyname[0] = '\0';
+ value[0] = '\0';
+ if (comm)
+ comm[0] = '\0';
+
+ if (*status > 0)
+ return(*status);
+
+ if (ffgrec(fptr, nkey, card, status) > 0 ) /* get the 80-byte card */
+ return(*status);
+
+ ffgknm(card, keyname, &namelen, status); /* get the keyword name */
+
+ if (ffpsvc(card, value, comm, status) > 0) /* parse value and comment */
+ return(*status);
+
+ if (fftrec(keyname, status) > 0) /* test keyword name; catches no END */
+ {
+ sprintf(sbuff,"Name of keyword no. %d contains illegal character(s): %s",
+ nkey, keyname);
+ ffpmsg(sbuff);
+
+ if (nkey % 36 == 0) /* test if at beginning of 36-card FITS record */
+ ffpmsg(" (This may indicate a missing END keyword).");
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgkns( fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - root name of keywords to read */
+ int nstart, /* I - starting index number */
+ int nmax, /* I - maximum number of keywords to return */
+ char *value[], /* O - array of pointers to keyword values */
+ int *nfound, /* O - number of values that were returned */
+ int *status) /* IO - error status */
+/*
+ Read (get) an indexed array of keywords with index numbers between
+ NSTART and (NSTART + NMAX -1) inclusive.
+ This routine does NOT support the HEASARC long string convention.
+*/
+{
+ int nend, lenroot, ii, nkeys, mkeys, tstatus, undefinedval;
+ long ival;
+ char keyroot[FLEN_KEYWORD], keyindex[8], card[FLEN_CARD];
+ char svalue[FLEN_VALUE], comm[FLEN_COMMENT];
+
+ if (*status > 0)
+ return(*status);
+
+ *nfound = 0;
+ nend = nstart + nmax - 1;
+
+ keyroot[0] = '\0';
+ strncat(keyroot, keyname, 8);
+
+ lenroot = strlen(keyroot);
+ if (lenroot == 0 || lenroot > 7) /* root must be 1 - 7 chars long */
+ return(*status);
+
+ for (ii=0; ii < lenroot; ii++) /* make sure upper case */
+ keyroot[ii] = toupper(keyroot[ii]);
+
+ ffghps(fptr, &nkeys, &mkeys, status); /* get the number of keywords */
+
+ undefinedval = FALSE;
+ for (ii=3; ii <= nkeys; ii++)
+ {
+ if (ffgrec(fptr, ii, card, status) > 0) /* get next keyword */
+ return(*status);
+
+ if (strncmp(keyroot, card, lenroot) == 0) /* see if keyword matches */
+ {
+ keyindex[0] = '\0';
+ strncat(keyindex, &card[lenroot], 8-lenroot); /* copy suffix */
+
+ tstatus = 0;
+ if (ffc2ii(keyindex, &ival, &tstatus) <= 0) /* test suffix */
+ {
+ if (ival <= nend && ival >= nstart)
+ {
+ ffpsvc(card, svalue, comm, status); /* parse the value */
+ ffc2s(svalue, value[ival-nstart], status); /* convert */
+ if (ival - nstart + 1 > *nfound)
+ *nfound = ival - nstart + 1; /* max found */
+
+ if (*status == VALUE_UNDEFINED)
+ {
+ undefinedval = TRUE;
+ *status = 0; /* reset status to read remaining values */
+ }
+ }
+ }
+ }
+ }
+ if (undefinedval && (*status <= 0) )
+ *status = VALUE_UNDEFINED; /* report at least 1 value undefined */
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgknl( fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - root name of keywords to read */
+ int nstart, /* I - starting index number */
+ int nmax, /* I - maximum number of keywords to return */
+ int *value, /* O - array of keyword values */
+ int *nfound, /* O - number of values that were returned */
+ int *status) /* IO - error status */
+/*
+ Read (get) an indexed array of keywords with index numbers between
+ NSTART and (NSTART + NMAX -1) inclusive.
+ The returned value = 1 if the keyword is true, else = 0 if false.
+*/
+{
+ int nend, lenroot, ii, nkeys, mkeys, tstatus, undefinedval;
+ long ival;
+ char keyroot[FLEN_KEYWORD], keyindex[8], card[FLEN_CARD];
+ char svalue[FLEN_VALUE], comm[FLEN_COMMENT];
+
+ if (*status > 0)
+ return(*status);
+
+ *nfound = 0;
+ nend = nstart + nmax - 1;
+
+ keyroot[0] = '\0';
+ strncat(keyroot, keyname, 8);
+
+ lenroot = strlen(keyroot);
+ if (lenroot == 0 || lenroot > 7) /* root must be 1 - 7 chars long */
+ return(*status);
+
+ for (ii=0; ii < lenroot; ii++) /* make sure upper case */
+ keyroot[ii] = toupper(keyroot[ii]);
+
+ ffghps(fptr, &nkeys, &mkeys, status); /* get the number of keywords */
+
+ ffmaky(fptr, 3, status); /* move to 3rd keyword (skip 1st 2 keywords) */
+
+ undefinedval = FALSE;
+ for (ii=3; ii <= nkeys; ii++)
+ {
+ if (ffgnky(fptr, card, status) > 0) /* get next keyword */
+ return(*status);
+
+ if (strncmp(keyroot, card, lenroot) == 0) /* see if keyword matches */
+ {
+ keyindex[0] = '\0';
+ strncat(keyindex, &card[lenroot], 8-lenroot); /* copy suffix */
+
+ tstatus = 0;
+ if (ffc2ii(keyindex, &ival, &tstatus) <= 0) /* test suffix */
+ {
+ if (ival <= nend && ival >= nstart)
+ {
+ ffpsvc(card, svalue, comm, status); /* parse the value */
+ ffc2l(svalue, &value[ival-nstart], status); /* convert*/
+ if (ival - nstart + 1 > *nfound)
+ *nfound = ival - nstart + 1; /* max found */
+
+ if (*status == VALUE_UNDEFINED)
+ {
+ undefinedval = TRUE;
+ *status = 0; /* reset status to read remaining values */
+ }
+ }
+ }
+ }
+ }
+ if (undefinedval && (*status <= 0) )
+ *status = VALUE_UNDEFINED; /* report at least 1 value undefined */
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgknj( fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - root name of keywords to read */
+ int nstart, /* I - starting index number */
+ int nmax, /* I - maximum number of keywords to return */
+ long *value, /* O - array of keyword values */
+ int *nfound, /* O - number of values that were returned */
+ int *status) /* IO - error status */
+/*
+ Read (get) an indexed array of keywords with index numbers between
+ NSTART and (NSTART + NMAX -1) inclusive.
+*/
+{
+ int nend, lenroot, ii, nkeys, mkeys, tstatus, undefinedval;
+ long ival;
+ char keyroot[FLEN_KEYWORD], keyindex[8], card[FLEN_CARD];
+ char svalue[FLEN_VALUE], comm[FLEN_COMMENT];
+
+ if (*status > 0)
+ return(*status);
+
+ *nfound = 0;
+ nend = nstart + nmax - 1;
+
+ keyroot[0] = '\0';
+ strncat(keyroot, keyname, 8);
+
+ lenroot = strlen(keyroot);
+ if (lenroot == 0 || lenroot > 7) /* root must be 1 - 7 chars long */
+ return(*status);
+
+ for (ii=0; ii < lenroot; ii++) /* make sure upper case */
+ keyroot[ii] = toupper(keyroot[ii]);
+
+ ffghps(fptr, &nkeys, &mkeys, status); /* get the number of keywords */
+
+ ffmaky(fptr, 3, status); /* move to 3rd keyword (skip 1st 2 keywords) */
+
+ undefinedval = FALSE;
+ for (ii=3; ii <= nkeys; ii++)
+ {
+ if (ffgnky(fptr, card, status) > 0) /* get next keyword */
+ return(*status);
+
+ if (strncmp(keyroot, card, lenroot) == 0) /* see if keyword matches */
+ {
+ keyindex[0] = '\0';
+ strncat(keyindex, &card[lenroot], 8-lenroot); /* copy suffix */
+
+ tstatus = 0;
+ if (ffc2ii(keyindex, &ival, &tstatus) <= 0) /* test suffix */
+ {
+ if (ival <= nend && ival >= nstart)
+ {
+ ffpsvc(card, svalue, comm, status); /* parse the value */
+ ffc2i(svalue, &value[ival-nstart], status); /* convert */
+ if (ival - nstart + 1 > *nfound)
+ *nfound = ival - nstart + 1; /* max found */
+
+ if (*status == VALUE_UNDEFINED)
+ {
+ undefinedval = TRUE;
+ *status = 0; /* reset status to read remaining values */
+ }
+ }
+ }
+ }
+ }
+ if (undefinedval && (*status <= 0) )
+ *status = VALUE_UNDEFINED; /* report at least 1 value undefined */
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgkne( fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - root name of keywords to read */
+ int nstart, /* I - starting index number */
+ int nmax, /* I - maximum number of keywords to return */
+ float *value, /* O - array of keyword values */
+ int *nfound, /* O - number of values that were returned */
+ int *status) /* IO - error status */
+/*
+ Read (get) an indexed array of keywords with index numbers between
+ NSTART and (NSTART + NMAX -1) inclusive.
+*/
+{
+ int nend, lenroot, ii, nkeys, mkeys, tstatus, undefinedval;
+ long ival;
+ char keyroot[FLEN_KEYWORD], keyindex[8], card[FLEN_CARD];
+ char svalue[FLEN_VALUE], comm[FLEN_COMMENT];
+
+ if (*status > 0)
+ return(*status);
+
+ *nfound = 0;
+ nend = nstart + nmax - 1;
+
+ keyroot[0] = '\0';
+ strncat(keyroot, keyname, 8);
+
+ lenroot = strlen(keyroot);
+ if (lenroot == 0 || lenroot > 7) /* root must be 1 - 7 chars long */
+ return(*status);
+
+ for (ii=0; ii < lenroot; ii++) /* make sure upper case */
+ keyroot[ii] = toupper(keyroot[ii]);
+
+ ffghps(fptr, &nkeys, &mkeys, status); /* get the number of keywords */
+
+ ffmaky(fptr, 3, status); /* move to 3rd keyword (skip 1st 2 keywords) */
+
+ undefinedval = FALSE;
+ for (ii=3; ii <= nkeys; ii++)
+ {
+ if (ffgnky(fptr, card, status) > 0) /* get next keyword */
+ return(*status);
+
+ if (strncmp(keyroot, card, lenroot) == 0) /* see if keyword matches */
+ {
+ keyindex[0] = '\0';
+ strncat(keyindex, &card[lenroot], 8-lenroot); /* copy suffix */
+
+ tstatus = 0;
+ if (ffc2ii(keyindex, &ival, &tstatus) <= 0) /* test suffix */
+ {
+ if (ival <= nend && ival >= nstart)
+ {
+ ffpsvc(card, svalue, comm, status); /* parse the value */
+ ffc2r(svalue, &value[ival-nstart], status); /* convert */
+ if (ival - nstart + 1 > *nfound)
+ *nfound = ival - nstart + 1; /* max found */
+
+ if (*status == VALUE_UNDEFINED)
+ {
+ undefinedval = TRUE;
+ *status = 0; /* reset status to read remaining values */
+ }
+ }
+ }
+ }
+ }
+ if (undefinedval && (*status <= 0) )
+ *status = VALUE_UNDEFINED; /* report at least 1 value undefined */
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgknd( fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - root name of keywords to read */
+ int nstart, /* I - starting index number */
+ int nmax, /* I - maximum number of keywords to return */
+ double *value, /* O - array of keyword values */
+ int *nfound, /* O - number of values that were returned */
+ int *status) /* IO - error status */
+/*
+ Read (get) an indexed array of keywords with index numbers between
+ NSTART and (NSTART + NMAX -1) inclusive.
+*/
+{
+ int nend, lenroot, ii, nkeys, mkeys, tstatus, undefinedval;
+ long ival;
+ char keyroot[FLEN_KEYWORD], keyindex[8], card[FLEN_CARD];
+ char svalue[FLEN_VALUE], comm[FLEN_COMMENT];
+
+ if (*status > 0)
+ return(*status);
+
+ *nfound = 0;
+ nend = nstart + nmax - 1;
+
+ keyroot[0] = '\0';
+ strncat(keyroot, keyname, 8);
+
+ lenroot = strlen(keyroot);
+ if (lenroot == 0 || lenroot > 7) /* root must be 1 - 7 chars long */
+ return(*status);
+
+ for (ii=0; ii < lenroot; ii++) /* make sure upper case */
+ keyroot[ii] = toupper(keyroot[ii]);
+
+ ffghps(fptr, &nkeys, &mkeys, status); /* get the number of keywords */
+
+ ffmaky(fptr, 3, status); /* move to 3rd keyword (skip 1st 2 keywords) */
+
+ undefinedval = FALSE;
+ for (ii=3; ii <= nkeys; ii++)
+ {
+ if (ffgnky(fptr, card, status) > 0) /* get next keyword */
+ return(*status);
+
+ if (strncmp(keyroot, card, lenroot) == 0) /* see if keyword matches */
+ {
+ keyindex[0] = '\0';
+ strncat(keyindex, &card[lenroot], 8-lenroot); /* copy suffix */
+
+ tstatus = 0;
+ if (ffc2ii(keyindex, &ival, &tstatus) <= 0) /* test suffix */
+ {
+ if (ival <= nend && ival >= nstart) /* is index within range? */
+ {
+ ffpsvc(card, svalue, comm, status); /* parse the value */
+ ffc2d(svalue, &value[ival-nstart], status); /* convert */
+ if (ival - nstart + 1 > *nfound)
+ *nfound = ival - nstart + 1; /* max found */
+
+ if (*status == VALUE_UNDEFINED)
+ {
+ undefinedval = TRUE;
+ *status = 0; /* reset status to read remaining values */
+ }
+ }
+ }
+ }
+ }
+ if (undefinedval && (*status <= 0) )
+ *status = VALUE_UNDEFINED; /* report at least 1 value undefined */
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgtdm(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of the column to read */
+ int maxdim, /* I - maximum no. of dimensions to read; */
+ int *naxis, /* O - number of axes in the data array */
+ long naxes[], /* O - length of each data axis */
+ int *status) /* IO - error status */
+/*
+ read and parse the TDIMnnn keyword to get the dimensionality of a column
+*/
+{
+ int tstatus = 0;
+ char keyname[FLEN_KEYWORD], tdimstr[FLEN_VALUE];
+
+ if (*status > 0)
+ return(*status);
+
+ ffkeyn("TDIM", colnum, keyname, status); /* construct keyword name */
+
+ ffgkys(fptr, keyname, tdimstr, NULL, &tstatus); /* try reading keyword */
+
+ ffdtdm(fptr, tdimstr, colnum, maxdim,naxis, naxes, status); /* decode it */
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffdtdm(fitsfile *fptr, /* I - FITS file pointer */
+ char *tdimstr, /* I - TDIMn keyword value string. e.g. (10,10) */
+ int colnum, /* I - number of the column */
+ int maxdim, /* I - maximum no. of dimensions to read; */
+ int *naxis, /* O - number of axes in the data array */
+ long naxes[], /* O - length of each data axis */
+ int *status) /* IO - error status */
+/*
+ decode the TDIMnnn keyword to get the dimensionality of a column.
+ Check that the value is legal and consistent with the TFORM value.
+*/
+{
+ long dimsize, totalpix = 1;
+ char *loc, *lastloc, message[81];
+ tcolumn *colptr;
+
+ if (*status > 0)
+ return(*status);
+
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+
+ if (colnum < 1 || colnum > (fptr->Fptr)->tfield)
+ return(*status = BAD_COL_NUM);
+
+ colptr = (fptr->Fptr)->tableptr; /* set pointer to the first column */
+ colptr += (colnum - 1); /* increment to the correct column */
+
+ if (!tdimstr[0]) /* TDIMn keyword doesn't exist? */
+ {
+ *naxis = 1; /* default = 1 dimensional */
+ if (maxdim > 0)
+ naxes[0] = (long) colptr->trepeat; /* default length = repeat */
+ }
+ else
+ {
+ *naxis = 0;
+
+ loc = strchr(tdimstr, '(' ); /* find the opening quote */
+ if (!loc)
+ {
+ sprintf(message, "Illegal TDIM keyword value: %s", tdimstr);
+ return(*status = BAD_TDIM);
+ }
+
+ while (loc)
+ {
+ loc++;
+ dimsize = strtol(loc, &loc, 10); /* read size of next dimension */
+ if (*naxis < maxdim)
+ naxes[*naxis] = dimsize;
+
+ if (dimsize < 0)
+ {
+ ffpmsg("one or more TDIM values are less than 0 (ffdtdm)");
+ ffpmsg(tdimstr);
+ return(*status = BAD_TDIM);
+ }
+
+ totalpix *= dimsize;
+ (*naxis)++;
+ lastloc = loc;
+ loc = strchr(loc, ','); /* look for comma before next dimension */
+ }
+
+ loc = strchr(lastloc, ')' ); /* check for the closing quote */
+ if (!loc)
+ {
+ sprintf(message, "Illegal TDIM keyword value: %s", tdimstr);
+ return(*status = BAD_TDIM);
+ }
+
+ if ((long) colptr->trepeat != totalpix)
+ {
+ sprintf(message,
+ "column vector length, %ld, does not equal TDIMn array size, %ld",
+ (long) colptr->trepeat, totalpix);
+ ffpmsg(message);
+ ffpmsg(tdimstr);
+ return(*status = BAD_TDIM);
+ }
+ }
+ return(*status);
+}
+
+/*--------------------------------------------------------------------------*/
+int ffghpr(fitsfile *fptr, /* I - FITS file pointer */
+ int maxdim, /* I - maximum no. of dimensions to read; */
+ int *simple, /* O - does file conform to FITS standard? 1/0 */
+ int *bitpix, /* O - number of bits per data value pixel */
+ int *naxis, /* O - number of axes in the data array */
+ long naxes[], /* O - length of each data axis */
+ long *pcount, /* O - number of group parameters (usually 0) */
+ long *gcount, /* O - number of random groups (usually 1 or 0) */
+ int *extend, /* O - may FITS file haave extensions? */
+ int *status) /* IO - error status */
+/*
+ Get keywords from the Header of the PRimary array:
+ Check that the keywords conform to the FITS standard and return the
+ parameters which determine the size and structure of the primary array
+ or IMAGE extension.
+*/
+{
+ int idummy;
+ long ldummy;
+ double ddummy;
+
+ ffgphd(fptr, maxdim, simple, bitpix, naxis, naxes, pcount, gcount, extend,
+ &ddummy, &ddummy, &ldummy, &idummy, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffghtb(fitsfile *fptr, /* I - FITS file pointer */
+ int maxfield, /* I - maximum no. of columns to read; */
+ long *naxis1, /* O - length of table row in bytes */
+ long *naxis2, /* O - number of rows in the table */
+ int *tfields, /* O - number of columns in the table */
+ char **ttype, /* O - name of each column */
+ long *tbcol, /* O - byte offset in row to each column */
+ char **tform, /* O - value of TFORMn keyword for each column */
+ char **tunit, /* O - value of TUNITn keyword for each column */
+ char *extnm, /* O - value of EXTNAME keyword, if any */
+ int *status) /* IO - error status */
+/*
+ Get keywords from the Header of the ASCII TaBle:
+ Check that the keywords conform to the FITS standard and return the
+ parameters which describe the table.
+*/
+{
+ int ii, maxf, nfound, tstatus;
+ long pcount, fields;
+ char name[FLEN_KEYWORD], value[FLEN_VALUE], comm[FLEN_COMMENT];
+ char xtension[FLEN_VALUE], message[81];
+
+ if (*status > 0)
+ return(*status);
+
+ /* read the first keyword of the extension */
+ ffgkyn(fptr, 1, name, value, comm, status);
+
+ if (!strcmp(name, "XTENSION"))
+ {
+ if (ffc2s(value, xtension, status) > 0) /* get the value string */
+ {
+ ffpmsg("Bad value string for XTENSION keyword:");
+ ffpmsg(value);
+ return(*status);
+ }
+
+ /* allow the quoted string value to begin in any column and */
+ /* allow any number of trailing blanks before the closing quote */
+ if ( (value[0] != '\'') || /* first char must be a quote */
+ ( strcmp(xtension, "TABLE") ) )
+ {
+ sprintf(message,
+ "This is not a TABLE extension: %s", value);
+ ffpmsg(message);
+ return(*status = NOT_ATABLE);
+ }
+ }
+
+ else /* error: 1st keyword of extension != XTENSION */
+ {
+ sprintf(message,
+ "First keyword of the extension is not XTENSION: %s", name);
+ ffpmsg(message);
+ return(*status = NO_XTENSION);
+ }
+
+ if (ffgttb(fptr, naxis1, naxis2, &pcount, &fields, status) > 0)
+ return(*status);
+
+ if (pcount != 0)
+ {
+ sprintf(message, "PCOUNT = %ld is illegal in ASCII table; must = 0",
+ pcount);
+ ffpmsg(message);
+ return(*status = BAD_PCOUNT);
+ }
+
+ if (tfields)
+ *tfields = fields;
+
+ if (maxfield < 0)
+ maxf = fields;
+ else
+ maxf = minvalue(maxfield, fields);
+
+ if (maxf > 0)
+ {
+ for (ii = 0; ii < maxf; ii++)
+ { /* initialize optional keyword values */
+ if (ttype)
+ *ttype[ii] = '\0';
+
+ if (tunit)
+ *tunit[ii] = '\0';
+ }
+
+
+ if (ttype)
+ ffgkns(fptr, "TTYPE", 1, maxf, ttype, &nfound, status);
+
+ if (tunit)
+ ffgkns(fptr, "TUNIT", 1, maxf, tunit, &nfound, status);
+
+ if (*status > 0)
+ return(*status);
+
+ if (tbcol)
+ {
+ ffgknj(fptr, "TBCOL", 1, maxf, tbcol, &nfound, status);
+
+ if (*status > 0 || nfound != maxf)
+ {
+ ffpmsg(
+ "Required TBCOL keyword(s) not found in ASCII table header (ffghtb).");
+ return(*status = NO_TBCOL);
+ }
+ }
+
+ if (tform)
+ {
+ ffgkns(fptr, "TFORM", 1, maxf, tform, &nfound, status);
+
+ if (*status > 0 || nfound != maxf)
+ {
+ ffpmsg(
+ "Required TFORM keyword(s) not found in ASCII table header (ffghtb).");
+ return(*status = NO_TFORM);
+ }
+ }
+ }
+
+ if (extnm)
+ {
+ extnm[0] = '\0';
+
+ tstatus = *status;
+ ffgkys(fptr, "EXTNAME", extnm, comm, status);
+
+ if (*status == KEY_NO_EXIST)
+ *status = tstatus; /* keyword not required, so ignore error */
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffghbn(fitsfile *fptr, /* I - FITS file pointer */
+ int maxfield, /* I - maximum no. of columns to read; */
+ long *naxis2, /* O - number of rows in the table */
+ int *tfields, /* O - number of columns in the table */
+ char **ttype, /* O - name of each column */
+ char **tform, /* O - TFORMn value for each column */
+ char **tunit, /* O - TUNITn value for each column */
+ char *extnm, /* O - value of EXTNAME keyword, if any */
+ long *pcount, /* O - value of PCOUNT keyword */
+ int *status) /* IO - error status */
+/*
+ Get keywords from the Header of the BiNary table:
+ Check that the keywords conform to the FITS standard and return the
+ parameters which describe the table.
+*/
+{
+ int ii, maxf, nfound, tstatus;
+ long naxis1, fields;
+ char name[FLEN_KEYWORD], value[FLEN_VALUE], comm[FLEN_COMMENT];
+ char xtension[FLEN_VALUE], message[81];
+
+ if (*status > 0)
+ return(*status);
+
+ /* read the first keyword of the extension */
+ ffgkyn(fptr, 1, name, value, comm, status);
+
+ if (!strcmp(name, "XTENSION"))
+ {
+ if (ffc2s(value, xtension, status) > 0) /* get the value string */
+ {
+ ffpmsg("Bad value string for XTENSION keyword:");
+ ffpmsg(value);
+ return(*status);
+ }
+
+ /* allow the quoted string value to begin in any column and */
+ /* allow any number of trailing blanks before the closing quote */
+ if ( (value[0] != '\'') || /* first char must be a quote */
+ ( strcmp(xtension, "BINTABLE") &&
+ strcmp(xtension, "A3DTABLE") &&
+ strcmp(xtension, "3DTABLE")
+ ) )
+ {
+ sprintf(message,
+ "This is not a BINTABLE extension: %s", value);
+ ffpmsg(message);
+ return(*status = NOT_BTABLE);
+ }
+ }
+
+ else /* error: 1st keyword of extension != XTENSION */
+ {
+ sprintf(message,
+ "First keyword of the extension is not XTENSION: %s", name);
+ ffpmsg(message);
+ return(*status = NO_XTENSION);
+ }
+
+ if (ffgttb(fptr, &naxis1, naxis2, pcount, &fields, status) > 0)
+ return(*status);
+
+ if (tfields)
+ *tfields = fields;
+
+ if (maxfield < 0)
+ maxf = fields;
+ else
+ maxf = minvalue(maxfield, fields);
+
+ if (maxf > 0)
+ {
+ for (ii = 0; ii < maxf; ii++)
+ { /* initialize optional keyword values */
+ if (ttype)
+ *ttype[ii] = '\0';
+
+ if (tunit)
+ *tunit[ii] = '\0';
+ }
+
+ if (ttype)
+ ffgkns(fptr, "TTYPE", 1, maxf, ttype, &nfound, status);
+
+ if (tunit)
+ ffgkns(fptr, "TUNIT", 1, maxf, tunit, &nfound, status);
+
+ if (*status > 0)
+ return(*status);
+
+ if (tform)
+ {
+ ffgkns(fptr, "TFORM", 1, maxf, tform, &nfound, status);
+
+ if (*status > 0 || nfound != maxf)
+ {
+ ffpmsg(
+ "Required TFORM keyword(s) not found in binary table header (ffghbn).");
+ return(*status = NO_TFORM);
+ }
+ }
+ }
+
+ if (extnm)
+ {
+ extnm[0] = '\0';
+
+ tstatus = *status;
+ ffgkys(fptr, "EXTNAME", extnm, comm, status);
+
+ if (*status == KEY_NO_EXIST)
+ *status = tstatus; /* keyword not required, so ignore error */
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgphd(fitsfile *fptr, /* I - FITS file pointer */
+ int maxdim, /* I - maximum no. of dimensions to read; */
+ int *simple, /* O - does file conform to FITS standard? 1/0 */
+ int *bitpix, /* O - number of bits per data value pixel */
+ int *naxis, /* O - number of axes in the data array */
+ long naxes[], /* O - length of each data axis */
+ long *pcount, /* O - number of group parameters (usually 0) */
+ long *gcount, /* O - number of random groups (usually 1 or 0) */
+ int *extend, /* O - may FITS file haave extensions? */
+ double *bscale, /* O - array pixel linear scaling factor */
+ double *bzero, /* O - array pixel linear scaling zero point */
+ long *blank, /* O - value used to represent undefined pixels */
+ int *nspace, /* O - number of blank keywords prior to END */
+ int *status) /* IO - error status */
+{
+/*
+ Get the Primary HeaDer parameters. Check that the keywords conform to
+ the FITS standard and return the parameters which determine the size and
+ structure of the primary array or IMAGE extension.
+*/
+ int unknown, found_end, tstatus, ii, nextkey, namelen;
+ long longbitpix, longnaxis, axislen;
+ char message[FLEN_ERRMSG], keyword[FLEN_KEYWORD];
+ char card[FLEN_CARD];
+ char name[FLEN_KEYWORD], value[FLEN_VALUE], comm[FLEN_COMMENT];
+ char xtension[FLEN_VALUE];
+
+ if (*status > 0)
+ return(*status);
+
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+
+ if (simple)
+ *simple = 1;
+
+ unknown = 0;
+
+ /*--------------------------------------------------------------------*/
+ /* Get 1st keyword of HDU and test whether it is SIMPLE or XTENSION */
+ /*--------------------------------------------------------------------*/
+ ffgkyn(fptr, 1, name, value, comm, status);
+
+ if ((fptr->Fptr)->curhdu == 0) /* Is this the beginning of the FITS file? */
+ {
+ if (!strcmp(name, "SIMPLE"))
+ {
+ if (value[0] == 'F')
+ {
+ if (simple)
+ *simple=0; /* not a simple FITS file */
+ }
+ else if (value[0] != 'T')
+ return(*status = BAD_SIMPLE);
+ }
+
+ else
+ {
+ sprintf(message,
+ "First keyword of the file is not SIMPLE: %s", name);
+ ffpmsg(message);
+ return(*status = NO_SIMPLE);
+ }
+ }
+
+ else /* not beginning of the file, so presumably an IMAGE extension */
+ { /* or it could be a compressed image in a binary table */
+
+ if (!strcmp(name, "XTENSION"))
+ {
+ if (ffc2s(value, xtension, status) > 0) /* get the value string */
+ {
+ ffpmsg("Bad value string for XTENSION keyword:");
+ ffpmsg(value);
+ return(*status);
+ }
+
+ /* allow the quoted string value to begin in any column and */
+ /* allow any number of trailing blanks before the closing quote */
+ if ( (value[0] != '\'') || /* first char must be a quote */
+ ( strcmp(xtension, "IMAGE") &&
+ strcmp(xtension, "IUEIMAGE") ) )
+ {
+ unknown = 1; /* unknown type of extension; press on anyway */
+ sprintf(message,
+ "This is not an IMAGE extension: %s", value);
+ ffpmsg(message);
+ }
+ }
+
+ else /* error: 1st keyword of extension != XTENSION */
+ {
+ sprintf(message,
+ "First keyword of the extension is not XTENSION: %s", name);
+ ffpmsg(message);
+ return(*status = NO_XTENSION);
+ }
+ }
+
+ if (unknown && (fptr->Fptr)->compressimg)
+ {
+ /* this is a compressed image, so read ZBITPIX, ZNAXIS keywords */
+ unknown = 0; /* reset flag */
+ ffxmsg(3, message); /* clear previous spurious error message */
+
+ if (bitpix)
+ {
+ ffgidt(fptr, bitpix, status); /* get bitpix value */
+
+ if (*status > 0)
+ {
+ ffpmsg("Error reading BITPIX value of compressed image");
+ return(*status);
+ }
+ }
+
+ if (naxis)
+ {
+ ffgidm(fptr, naxis, status); /* get NAXIS value */
+
+ if (*status > 0)
+ {
+ ffpmsg("Error reading NAXIS value of compressed image");
+ return(*status);
+ }
+ }
+
+ if (naxes)
+ {
+ ffgisz(fptr, maxdim, naxes, status); /* get NAXISn value */
+
+ if (*status > 0)
+ {
+ ffpmsg("Error reading NAXISn values of compressed image");
+ return(*status);
+ }
+ }
+
+ nextkey = 9; /* skip required table keywords in the following search */
+ }
+ else
+ {
+
+ /*----------------------------------------------------------------*/
+ /* Get 2nd keyword; test whether it is BITPIX with legal value */
+ /*----------------------------------------------------------------*/
+ ffgkyn(fptr, 2, name, value, comm, status); /* BITPIX = 2nd keyword */
+
+ if (strcmp(name, "BITPIX"))
+ {
+ sprintf(message,
+ "Second keyword of the extension is not BITPIX: %s", name);
+ ffpmsg(message);
+ return(*status = NO_BITPIX);
+ }
+
+ if (ffc2ii(value, &longbitpix, status) > 0)
+ {
+ sprintf(message,
+ "Value of BITPIX keyword is not an integer: %s", value);
+ ffpmsg(message);
+ return(*status = BAD_BITPIX);
+ }
+ else if (longbitpix != BYTE_IMG && longbitpix != SHORT_IMG &&
+ longbitpix != LONG_IMG && longbitpix != LONGLONG_IMG &&
+ longbitpix != FLOAT_IMG && longbitpix != DOUBLE_IMG)
+ {
+ sprintf(message,
+ "Illegal value for BITPIX keyword: %s", value);
+ ffpmsg(message);
+ return(*status = BAD_BITPIX);
+ }
+ if (bitpix)
+ *bitpix = longbitpix; /* do explicit type conversion */
+
+ /*---------------------------------------------------------------*/
+ /* Get 3rd keyword; test whether it is NAXIS with legal value */
+ /*---------------------------------------------------------------*/
+ ffgtkn(fptr, 3, "NAXIS", &longnaxis, status);
+
+ if (*status == BAD_ORDER)
+ return(*status = NO_NAXIS);
+ else if (*status == NOT_POS_INT || longnaxis > 999)
+ {
+ sprintf(message,"NAXIS = %ld is illegal", longnaxis);
+ ffpmsg(message);
+ return(*status = BAD_NAXIS);
+ }
+ else
+ if (naxis)
+ *naxis = longnaxis; /* do explicit type conversion */
+
+ /*---------------------------------------------------------*/
+ /* Get the next NAXISn keywords and test for legal values */
+ /*---------------------------------------------------------*/
+ for (ii=0, nextkey=4; ii < longnaxis; ii++, nextkey++)
+ {
+ ffkeyn("NAXIS", ii+1, keyword, status);
+ ffgtkn(fptr, 4+ii, keyword, &axislen, status);
+
+ if (*status == BAD_ORDER)
+ return(*status = NO_NAXES);
+ else if (*status == NOT_POS_INT)
+ return(*status = BAD_NAXES);
+ else if (ii < maxdim)
+ if (naxes)
+ naxes[ii] = axislen;
+ }
+ }
+
+ /*---------------------------------------------------------*/
+ /* now look for other keywords of interest: */
+ /* BSCALE, BZERO, BLANK, PCOUNT, GCOUNT, EXTEND, and END */
+ /*---------------------------------------------------------*/
+
+ /* initialize default values in case keyword is not present */
+ if (bscale)
+ *bscale = 1.0;
+ if (bzero)
+ *bzero = 0.0;
+ if (pcount)
+ *pcount = 0;
+ if (gcount)
+ *gcount = 1;
+ if (extend)
+ *extend = 0;
+ if (blank)
+ *blank = NULL_UNDEFINED; /* no default null value for BITPIX=8,16,32 */
+
+ *nspace = 0;
+ found_end = 0;
+ tstatus = *status;
+
+ for (; !found_end; nextkey++)
+ {
+ /* get next keyword */
+ /* don't use ffgkyn here because it trys to parse the card to read */
+ /* the value string, thus failing to read the file just because of */
+ /* minor syntax errors in optional keywords. */
+
+ if (ffgrec(fptr, nextkey, card, status) > 0 ) /* get the 80-byte card */
+ {
+ if (*status == KEY_OUT_BOUNDS)
+ {
+ found_end = 1; /* simply hit the end of the header */
+ *status = tstatus; /* reset error status */
+ }
+ else
+ {
+ ffpmsg("Failed to find the END keyword in header (ffgphd).");
+ }
+ }
+ else /* got the next keyword without error */
+ {
+ ffgknm(card, name, &namelen, status); /* get the keyword name */
+
+ if (fftrec(name, status) > 0) /* test keyword name; catches no END */
+ {
+ sprintf(message,
+ "Name of keyword no. %d contains illegal character(s): %s",
+ nextkey, name);
+ ffpmsg(message);
+
+ if (nextkey % 36 == 0) /* test if at beginning of 36-card record */
+ ffpmsg(" (This may indicate a missing END keyword).");
+ }
+
+ if (!strcmp(name, "BSCALE") && bscale)
+ {
+ *nspace = 0; /* reset count of blank keywords */
+ ffpsvc(card, value, comm, status); /* parse value and comment */
+
+ if (ffc2dd(value, bscale, status) > 0) /* convert to double */
+ {
+ /* reset error status and continue, but still issue warning */
+ *status = tstatus;
+ *bscale = 1.0;
+
+ sprintf(message,
+ "Error reading BSCALE keyword value as a double: %s", value);
+ ffpmsg(message);
+ }
+ }
+
+ else if (!strcmp(name, "BZERO") && bzero)
+ {
+ *nspace = 0; /* reset count of blank keywords */
+ ffpsvc(card, value, comm, status); /* parse value and comment */
+
+ if (ffc2dd(value, bzero, status) > 0) /* convert to double */
+ {
+ /* reset error status and continue, but still issue warning */
+ *status = tstatus;
+ *bzero = 0.0;
+
+ sprintf(message,
+ "Error reading BZERO keyword value as a double: %s", value);
+ ffpmsg(message);
+ }
+ }
+
+ else if (!strcmp(name, "BLANK") && blank)
+ {
+ *nspace = 0; /* reset count of blank keywords */
+ ffpsvc(card, value, comm, status); /* parse value and comment */
+
+ if (ffc2ii(value, blank, status) > 0) /* convert to long */
+ {
+ /* reset error status and continue, but still issue warning */
+ *status = tstatus;
+ *blank = NULL_UNDEFINED;
+
+ sprintf(message,
+ "Error reading BLANK keyword value as an integer: %s", value);
+ ffpmsg(message);
+ }
+ }
+
+ else if (!strcmp(name, "PCOUNT") && pcount)
+ {
+ *nspace = 0; /* reset count of blank keywords */
+ ffpsvc(card, value, comm, status); /* parse value and comment */
+
+ if (ffc2ii(value, pcount, status) > 0) /* convert to long */
+ {
+ sprintf(message,
+ "Error reading PCOUNT keyword value as an integer: %s", value);
+ ffpmsg(message);
+ }
+ }
+
+ else if (!strcmp(name, "GCOUNT") && gcount)
+ {
+ *nspace = 0; /* reset count of blank keywords */
+ ffpsvc(card, value, comm, status); /* parse value and comment */
+
+ if (ffc2ii(value, gcount, status) > 0) /* convert to long */
+ {
+ sprintf(message,
+ "Error reading GCOUNT keyword value as an integer: %s", value);
+ ffpmsg(message);
+ }
+ }
+
+ else if (!strcmp(name, "EXTEND") && extend)
+ {
+ *nspace = 0; /* reset count of blank keywords */
+ ffpsvc(card, value, comm, status); /* parse value and comment */
+
+ if (ffc2ll(value, extend, status) > 0) /* convert to logical */
+ {
+ /* reset error status and continue, but still issue warning */
+ *status = tstatus;
+ *extend = 0;
+
+ sprintf(message,
+ "Error reading EXTEND keyword value as a logical: %s", value);
+ ffpmsg(message);
+ }
+ }
+
+ else if (!strcmp(name, "END"))
+ found_end = 1;
+
+ else if (!card[0] )
+ *nspace = *nspace + 1; /* this is a blank card in the header */
+
+ else
+ *nspace = 0; /* reset count of blank keywords immediately
+ before the END keyword to zero */
+ }
+
+ if (*status > 0) /* exit on error after writing error message */
+ {
+ if ((fptr->Fptr)->curhdu == 0)
+ ffpmsg(
+ "Failed to read the required primary array header keywords.");
+ else
+ ffpmsg(
+ "Failed to read the required image extension header keywords.");
+
+ return(*status);
+ }
+ }
+
+ if (unknown)
+ *status = NOT_IMAGE;
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgttb(fitsfile *fptr, /* I - FITS file pointer*/
+ long *rowlen, /* O - length of a table row, in bytes */
+ long *nrows, /* O - number of rows in the table */
+ long *pcount, /* O - value of PCOUNT keyword */
+ long *tfields, /* O - number of fields in the table */
+ int *status) /* IO - error status */
+{
+/*
+ Get and Test TaBle;
+ Test that this is a legal ASCII or binary table and get some keyword values.
+ We assume that the calling routine has already tested the 1st keyword
+ of the extension to ensure that this is really a table extension.
+*/
+ if (*status > 0)
+ return(*status);
+
+ if (fftkyn(fptr, 2, "BITPIX", "8", status) == BAD_ORDER) /* 2nd keyword */
+ return(*status = NO_BITPIX); /* keyword not BITPIX */
+ else if (*status == NOT_POS_INT)
+ return(*status = BAD_BITPIX); /* value != 8 */
+
+ if (fftkyn(fptr, 3, "NAXIS", "2", status) == BAD_ORDER) /* 3rd keyword */
+ return(*status = NO_NAXIS); /* keyword not NAXIS */
+ else if (*status == NOT_POS_INT)
+ return(*status = BAD_NAXIS); /* value != 2 */
+
+ if (ffgtkn(fptr, 4, "NAXIS1", rowlen, status) == BAD_ORDER) /* 4th key */
+ return(*status = NO_NAXES); /* keyword not NAXIS1 */
+ else if (*status == NOT_POS_INT)
+ return(*status == BAD_NAXES); /* bad NAXIS1 value */
+
+ if (ffgtkn(fptr, 5, "NAXIS2", nrows, status) == BAD_ORDER) /* 5th key */
+ return(*status = NO_NAXES); /* keyword not NAXIS2 */
+ else if (*status == NOT_POS_INT)
+ return(*status == BAD_NAXES); /* bad NAXIS2 value */
+
+ if (ffgtkn(fptr, 6, "PCOUNT", pcount, status) == BAD_ORDER) /* 6th key */
+ return(*status = NO_PCOUNT); /* keyword not PCOUNT */
+ else if (*status == NOT_POS_INT)
+ return(*status = BAD_PCOUNT); /* bad PCOUNT value */
+
+ if (fftkyn(fptr, 7, "GCOUNT", "1", status) == BAD_ORDER) /* 7th keyword */
+ return(*status = NO_GCOUNT); /* keyword not GCOUNT */
+ else if (*status == NOT_POS_INT)
+ return(*status = BAD_GCOUNT); /* value != 1 */
+
+ if (ffgtkn(fptr, 8, "TFIELDS", tfields, status) == BAD_ORDER) /* 8th key*/
+ return(*status = NO_TFIELDS); /* keyword not TFIELDS */
+ else if (*status == NOT_POS_INT || *tfields > 999)
+ return(*status == BAD_TFIELDS); /* bad TFIELDS value */
+
+
+ if (*status > 0)
+ ffpmsg(
+ "Error reading required keywords in the table header (FTGTTB).");
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgtkn(fitsfile *fptr, /* I - FITS file pointer */
+ int numkey, /* I - number of the keyword to read */
+ char *name, /* I - expected name of the keyword */
+ long *value, /* O - integer value of the keyword */
+ int *status) /* IO - error status */
+{
+/*
+ test that keyword number NUMKEY has the expected name and get the
+ integer value of the keyword. Return an error if the keyword
+ name does not match the input name, or if the value of the
+ keyword is not a positive integer.
+*/
+ char keyname[FLEN_KEYWORD], valuestring[FLEN_VALUE];
+ char comm[FLEN_COMMENT], message[FLEN_ERRMSG];
+
+ if (*status > 0)
+ return(*status);
+
+ keyname[0] = '\0';
+ valuestring[0] = '\0';
+
+ if (ffgkyn(fptr, numkey, keyname, valuestring, comm, status) <= 0)
+ {
+ if (strcmp(keyname, name) )
+ *status = BAD_ORDER; /* incorrect keyword name */
+
+ else
+ {
+ ffc2ii(valuestring, value, status); /* convert to integer */
+
+ if (*status > 0 || *value < 0 )
+ *status = NOT_POS_INT;
+ }
+
+ if (*status > 0)
+ {
+ sprintf(message,
+ "ffgtkn found unexpected keyword or value for keyword no. %d.",
+ numkey);
+ ffpmsg(message);
+
+ sprintf(message,
+ " Expected positive integer keyword %s, but instead", name);
+ ffpmsg(message);
+
+ sprintf(message,
+ " found keyword %s with value %s", keyname, valuestring);
+ ffpmsg(message);
+ }
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fftkyn(fitsfile *fptr, /* I - FITS file pointer */
+ int numkey, /* I - number of the keyword to read */
+ char *name, /* I - expected name of the keyword */
+ char *value, /* I - expected value of the keyword */
+ int *status) /* IO - error status */
+{
+/*
+ test that keyword number NUMKEY has the expected name and the
+ expected value string.
+*/
+ char keyname[FLEN_KEYWORD], valuestring[FLEN_VALUE];
+ char comm[FLEN_COMMENT], message[FLEN_ERRMSG];
+
+ if (*status > 0)
+ return(*status);
+
+ keyname[0] = '\0';
+ valuestring[0] = '\0';
+
+ if (ffgkyn(fptr, numkey, keyname, valuestring, comm, status) <= 0)
+ {
+ if (strcmp(keyname, name) )
+ *status = BAD_ORDER; /* incorrect keyword name */
+
+ if (strcmp(value, valuestring) )
+ *status = NOT_POS_INT; /* incorrect keyword value */
+ }
+
+ if (*status > 0)
+ {
+ sprintf(message,
+ "fftkyn found unexpected keyword or value for keyword no. %d.",
+ numkey);
+ ffpmsg(message);
+
+ sprintf(message,
+ " Expected keyword %s with value %s, but", name, value);
+ ffpmsg(message);
+
+ sprintf(message,
+ " found keyword %s with value %s", keyname, valuestring);
+ ffpmsg(message);
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffh2st(fitsfile *fptr, /* I - FITS file pointer */
+ char **header, /* O - returned header string */
+ int *status) /* IO - error status */
+
+/*
+ read header keywords into a long string of chars. This routine allocates
+ memory for the string, so the calling routine must eventually free the
+ memory when it is not needed any more.
+*/
+{
+ int nkeys;
+ long nrec;
+ OFF_T headstart;
+
+ if (*status > 0)
+ return(*status);
+
+ /* get number of keywords in the header (doesn't include END) */
+ if (ffghsp(fptr, &nkeys, NULL, status) > 0)
+ return(*status);
+
+ nrec = (nkeys / 36 + 1);
+
+ /* allocate memory for all the keywords (multiple of 2880 bytes) */
+ *header = (char *) calloc ( nrec * 2880 + 1, 1);
+ if (!(*header))
+ {
+ *status = MEMORY_ALLOCATION;
+ ffpmsg("failed to allocate memory to hold all the header keywords");
+ return(*status);
+ }
+
+ ffghof(fptr, &headstart, NULL, NULL, status); /* get header address */
+ ffmbyt(fptr, headstart, REPORT_EOF, status); /* move to header */
+ ffgbyt(fptr, nrec * 2880, *header, status); /* copy header */
+ *(*header + (nrec * 2880)) = '\0';
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffhdr2str( fitsfile *fptr, /* I - FITS file pointer */
+ int exclude_comm, /* I - if TRUE, exclude commentary keywords */
+ char **exclist, /* I - list of excluded keyword names */
+ int nexc, /* I - number of names in exclist */
+ char **header, /* O - returned header string */
+ int *nkeys, /* O - returned number of 80-char keywords */
+ int *status) /* IO - error status */
+/*
+ read header keywords into a long string of chars. This routine allocates
+ memory for the string, so the calling routine must eventually free the
+ memory when it is not needed any more. If exclude_comm is TRUE, then all
+ the COMMENT, HISTORY, and <blank> keywords will be excluded from the output
+ string of keywords. Any other list of keywords to be excluded may be
+ specified with the exclist parameter.
+*/
+{
+ int casesn, match, exact, totkeys;
+ long ii, jj;
+ char keybuf[162], keyname[FLEN_KEYWORD], *headptr;
+
+ *nkeys = 0;
+
+ if (*status > 0)
+ return(*status);
+
+ /* get number of keywords in the header (doesn't include END) */
+ if (ffghsp(fptr, &totkeys, NULL, status) > 0)
+ return(*status);
+
+ /* allocate memory for all the keywords (multiple of 2880 bytes) */
+ *header = (char *) calloc ( (totkeys + 1) * 80 + 1, 1);
+ if (!(*header))
+ {
+ *status = MEMORY_ALLOCATION;
+ ffpmsg("failed to allocate memory to hold all the header keywords");
+ return(*status);
+ }
+
+ headptr = *header;
+ casesn = FALSE;
+
+ /* read every keyword */
+ for (ii = 1; ii <= totkeys; ii++)
+ {
+ ffgrec(fptr, ii, keybuf, status);
+ /* pad record with blanks so that it is at least 80 chars long */
+ strcat(keybuf,
+ " ");
+
+ keyname[0] = '\0';
+ strncat(keyname, keybuf, 8); /* copy the keyword name */
+
+ if (exclude_comm)
+ {
+ if (!FSTRCMP("COMMENT ", keyname) ||
+ !FSTRCMP("HISTORY ", keyname) ||
+ !FSTRCMP(" ", keyname) )
+ continue; /* skip this commentary keyword */
+ }
+
+ /* does keyword match any names in the exclusion list? */
+ for (jj = 0; jj < nexc; jj++ )
+ {
+ ffcmps(exclist[jj], keyname, casesn, &match, &exact);
+ if (match)
+ break;
+ }
+
+ if (jj == nexc)
+ {
+ /* not in exclusion list, add this keyword to the string */
+ strcpy(headptr, keybuf);
+ headptr += 80;
+ (*nkeys)++;
+ }
+ }
+
+ /* add the END keyword */
+ strcpy(headptr,
+ "END ");
+ headptr += 80;
+ (*nkeys)++;
+
+ *headptr = '\0'; /* terminate the header string */
+ realloc(*header, (*nkeys *80) + 1); /* minimize the allocated memory */
+
+ return(*status);
+}
diff --git a/pkg/tbtables/cfitsio/group.c b/pkg/tbtables/cfitsio/group.c
new file mode 100644
index 00000000..9b5a481d
--- /dev/null
+++ b/pkg/tbtables/cfitsio/group.c
@@ -0,0 +1,6418 @@
+/* This file, group.c, contains the grouping convention suport routines. */
+
+/* The FITSIO software was written by William Pence at the High Energy */
+/* Astrophysic Science Archive Research Center (HEASARC) at the NASA */
+/* Goddard Space Flight Center. */
+/* */
+/* The group.c module of CFITSIO was written by Donald G. Jennings of */
+/* the INTEGRAL Science Data Centre (ISDC) under NASA contract task */
+/* 66002J6. The above copyright laws apply. Copyright guidelines of The */
+/* University of Geneva might also apply. */
+
+/* The following routines are designed to create, read, and manipulate */
+/* FITS Grouping Tables as defined in the FITS Grouping Convention paper */
+/* by Jennings, Pence, Folk and Schlesinger. The development of the */
+/* grouping structure was partially funded under the NASA AISRP Program. */
+
+#include "fitsio2.h"
+#include "group.h"
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define HEX_ESCAPE '%'
+
+/*---------------------------------------------------------------------------
+ Change record:
+
+D. Jennings, 18/06/98, version 1.0 of group module delivered to B. Pence for
+ integration into CFITSIO 2.005
+
+D. Jennings, 17/11/98, fixed bug in ffgtcpr(). Now use fits_find_nextkey()
+ correctly and insert auxiliary keyword records
+ directly before the TTYPE1 keyword in the copied
+ group table.
+
+D. Jennings, 22/01/99, ffgmop() now looks for relative file paths when
+ the MEMBER_LOCATION information is given in a
+ grouping table.
+
+D. Jennings, 01/02/99, ffgtop() now looks for relatve file paths when
+ the GRPLCn keyword value is supplied in the member
+ HDU header.
+
+D. Jennings, 01/02/99, ffgtam() now trys to construct relative file paths
+ from the member's file to the group table's file
+ (and visa versa) when both the member's file and
+ group table file are of access type FILE://.
+
+D. Jennings, 05/05/99, removed the ffgtcn() function; made obsolete by
+ fits_get_url().
+
+D. Jennings, 05/05/99, updated entire module to handle partial URLs and
+ absolute URLs more robustly. Host dependent directory
+ paths are now converted to true URLs before being
+ read from/written to grouping tables.
+
+D. Jennings, 05/05/99, added the following new functions (note, none of these
+ are directly callable by the application)
+
+ int fits_path2url()
+ int fits_url2path()
+ int fits_get_cwd()
+ int fits_get_url()
+ int fits_clean_url()
+ int fits_relurl2url()
+ int fits_encode_url()
+ int fits_unencode_url()
+ int fits_is_url_absolute()
+
+-----------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+int ffgtcr(fitsfile *fptr, /* FITS file pointer */
+ char *grpname, /* name of the grouping table */
+ int grouptype, /* code specifying the type of
+ grouping table information:
+ GT_ID_ALL_URI 0 ==> defualt (all columns)
+ GT_ID_REF 1 ==> ID by reference
+ GT_ID_POS 2 ==> ID by position
+ GT_ID_ALL 3 ==> ID by ref. and position
+ GT_ID_REF_URI 11 ==> (1) + URI info
+ GT_ID_POS_URI 12 ==> (2) + URI info */
+ int *status )/* return status code */
+
+/*
+ create a grouping table at the end of the current FITS file. This
+ function makes the last HDU in the file the CHDU, then calls the
+ fits_insert_group() function to actually create the new grouping table.
+*/
+
+{
+ int hdutype;
+ int hdunum;
+
+
+ if(*status != 0) return(*status);
+
+
+ *status = fits_get_num_hdus(fptr,&hdunum,status);
+
+ /* If hdunum is 0 then we are at the beginning of the file and
+ we actually haven't closed the first header yet, so don't do
+ anything more */
+
+ if (0 != hdunum) {
+
+ *status = fits_movabs_hdu(fptr,hdunum,&hdutype,status);
+ }
+
+ /* Now, the whole point of the above two fits_ calls was to get to
+ the end of file. Let's ignore errors at this point and keep
+ going since any error is likely to mean that we are already at the
+ EOF, or the file is fatally corrupted. If we are at the EOF then
+ the next fits_ call will be ok. If it's corrupted then the
+ next call will fail, but that's not big deal at this point.
+ */
+
+ if (0 != *status ) *status = 0;
+
+ *status = fits_insert_group(fptr,grpname,grouptype,status);
+
+ return(*status);
+}
+
+/*---------------------------------------------------------------------------*/
+int ffgtis(fitsfile *fptr, /* FITS file pointer */
+ char *grpname, /* name of the grouping table */
+ int grouptype, /* code specifying the type of
+ grouping table information:
+ GT_ID_ALL_URI 0 ==> defualt (all columns)
+ GT_ID_REF 1 ==> ID by reference
+ GT_ID_POS 2 ==> ID by position
+ GT_ID_ALL 3 ==> ID by ref. and position
+ GT_ID_REF_URI 11 ==> (1) + URI info
+ GT_ID_POS_URI 12 ==> (2) + URI info */
+ int *status) /* return status code */
+
+/*
+ insert a grouping table just after the current HDU of the current FITS file.
+ This is the same as fits_create_group() only it allows the user to select
+ the place within the FITS file to add the grouping table.
+*/
+
+{
+
+ int tfields = 0;
+ int hdunum = 0;
+ int hdutype = 0;
+ int extver = 0;
+ int i;
+
+ long pcount = 0;
+
+ char *ttype[6];
+ char *tform[6];
+
+ char ttypeBuff[102];
+ char tformBuff[54];
+
+ char extname[] = "GROUPING";
+ char keyword[FLEN_KEYWORD];
+ char keyvalue[FLEN_VALUE];
+ char comment[FLEN_COMMENT];
+
+ do
+ {
+
+ /* set up the ttype and tform character buffers */
+
+ for(i = 0; i < 6; ++i)
+ {
+ ttype[i] = ttypeBuff+(i*17);
+ tform[i] = tformBuff+(i*9);
+ }
+
+ /* define the columns required according to the grouptype parameter */
+
+ *status = ffgtdc(grouptype,0,0,0,0,0,0,ttype,tform,&tfields,status);
+
+ /* create the grouping table using the columns defined above */
+
+ *status = fits_insert_btbl(fptr,0,tfields,ttype,tform,NULL,
+ NULL,pcount,status);
+
+ if(*status != 0) continue;
+
+ /*
+ retrieve the hdu position of the new grouping table for
+ future use
+ */
+
+ fits_get_hdu_num(fptr,&hdunum);
+
+ /*
+ add the EXTNAME and EXTVER keywords to the HDU just after the
+ TFIELDS keyword; for now the EXTVER value is set to 0, it will be
+ set to the correct value later on
+ */
+
+ fits_read_keyword(fptr,"TFIELDS",keyvalue,comment,status);
+
+ fits_insert_key_str(fptr,"EXTNAME",extname,
+ "HDU contains a Grouping Table",status);
+ fits_insert_key_lng(fptr,"EXTVER",0,"Grouping Table vers. (this file)",
+ status);
+
+ /*
+ if the grpname parameter value was defined (Non NULL and non zero
+ length) then add the GRPNAME keyword and value
+ */
+
+ if(grpname != NULL && strlen(grpname) > 0)
+ fits_insert_key_str(fptr,"GRPNAME",grpname,"Grouping Table name",
+ status);
+
+ /*
+ add the TNULL keywords and values for each integer column defined;
+ integer null values are zero (0) for the MEMBER_POSITION and
+ MEMBER_VERSION columns.
+ */
+
+ for(i = 0; i < tfields && *status == 0; ++i)
+ {
+ if(strcasecmp(ttype[i],"MEMBER_POSITION") == 0 ||
+ strcasecmp(ttype[i],"MEMBER_VERSION") == 0)
+ {
+ sprintf(keyword,"TFORM%d",i+1);
+ *status = fits_read_key_str(fptr,keyword,keyvalue,comment,
+ status);
+
+ sprintf(keyword,"TNULL%d",i+1);
+
+ *status = fits_insert_key_lng(fptr,keyword,0,"Column Null Value",
+ status);
+ }
+ }
+
+ /*
+ determine the correct EXTVER value for the new grouping table
+ by finding the highest numbered grouping table EXTVER value
+ the currently exists
+ */
+
+ for(extver = 1;
+ (fits_movnam_hdu(fptr,ANY_HDU,"GROUPING",extver,status)) == 0;
+ ++extver);
+
+ if(*status == BAD_HDU_NUM) *status = 0;
+
+ /*
+ move back to the new grouping table HDU and update the EXTVER
+ keyword value
+ */
+
+ fits_movabs_hdu(fptr,hdunum,&hdutype,status);
+
+ fits_modify_key_lng(fptr,"EXTVER",extver,"&",status);
+
+ }while(0);
+
+
+ return(*status);
+}
+
+/*---------------------------------------------------------------------------*/
+int ffgtch(fitsfile *gfptr, /* FITS pointer to group */
+ int grouptype, /* code specifying the type of
+ grouping table information:
+ GT_ID_ALL_URI 0 ==> defualt (all columns)
+ GT_ID_REF 1 ==> ID by reference
+ GT_ID_POS 2 ==> ID by position
+ GT_ID_ALL 3 ==> ID by ref. and position
+ GT_ID_REF_URI 11 ==> (1) + URI info
+ GT_ID_POS_URI 12 ==> (2) + URI info */
+ int *status) /* return status code */
+
+
+/*
+ Change the grouping table structure of the grouping table pointed to by
+ gfptr. The grouptype code specifies the new structure of the table. This
+ operation only adds or removes grouping table columns, it does not add
+ or delete group members (i.e., table rows). If the grouping table already
+ has the desired structure then no operations are performed and function
+ simply returns with a (0) success status code. If the requested structure
+ change creates new grouping table columns, then the column values for all
+ existing members will be filled with the appropriate null values.
+*/
+
+{
+ int xtensionCol, extnameCol, extverCol, positionCol, locationCol, uriCol;
+ int ncols = 0;
+ int colnum = 0;
+ int nrows = 0;
+ int grptype = 0;
+ int i,j;
+
+ long intNull = 0;
+ long tfields = 0;
+
+ char *tform[6];
+ char *ttype[6];
+
+ unsigned char charNull[1] = {'\0'};
+
+ char ttypeBuff[102];
+ char tformBuff[54];
+
+ char keyword[FLEN_KEYWORD];
+ char keyvalue[FLEN_VALUE];
+ char comment[FLEN_COMMENT];
+
+
+ if(*status != 0) return(*status);
+
+ do
+ {
+ /* set up the ttype and tform character buffers */
+
+ for(i = 0; i < 6; ++i)
+ {
+ ttype[i] = ttypeBuff+(i*17);
+ tform[i] = tformBuff+(i*9);
+ }
+
+ /* retrieve positions of all Grouping table reserved columns */
+
+ *status = ffgtgc(gfptr,&xtensionCol,&extnameCol,&extverCol,&positionCol,
+ &locationCol,&uriCol,&grptype,status);
+
+ if(*status != 0) continue;
+
+ /* determine the total number of grouping table columns */
+
+ *status = fits_read_key_lng(gfptr,"TFIELDS",&tfields,comment,status);
+
+ /* define grouping table columns to be added to the configuration */
+
+ *status = ffgtdc(grouptype,xtensionCol,extnameCol,extverCol,positionCol,
+ locationCol,uriCol,ttype,tform,&ncols,status);
+
+ /*
+ delete any grouping tables columns that exist but do not belong to
+ new desired configuration; note that we delete before creating new
+ columns for (file size) efficiency reasons
+ */
+
+ switch(grouptype)
+ {
+
+ case GT_ID_ALL_URI:
+
+ /* no columns to be deleted in this case */
+
+ break;
+
+ case GT_ID_REF:
+
+ if(positionCol != 0)
+ {
+ *status = fits_delete_col(gfptr,positionCol,status);
+ --tfields;
+ if(uriCol > positionCol) --uriCol;
+ if(locationCol > positionCol) --locationCol;
+ }
+ if(uriCol != 0)
+ {
+ *status = fits_delete_col(gfptr,uriCol,status);
+ --tfields;
+ if(locationCol > uriCol) --locationCol;
+ }
+ if(locationCol != 0)
+ *status = fits_delete_col(gfptr,locationCol,status);
+
+ break;
+
+ case GT_ID_POS:
+
+ if(xtensionCol != 0)
+ {
+ *status = fits_delete_col(gfptr,xtensionCol,status);
+ --tfields;
+ if(extnameCol > xtensionCol) --extnameCol;
+ if(extverCol > xtensionCol) --extverCol;
+ if(uriCol > xtensionCol) --uriCol;
+ if(locationCol > xtensionCol) --locationCol;
+ }
+ if(extnameCol != 0)
+ {
+ *status = fits_delete_col(gfptr,extnameCol,status);
+ --tfields;
+ if(extverCol > extnameCol) --extverCol;
+ if(uriCol > extnameCol) --uriCol;
+ if(locationCol > extnameCol) --locationCol;
+ }
+ if(extverCol != 0)
+ {
+ *status = fits_delete_col(gfptr,extverCol,status);
+ --tfields;
+ if(uriCol > extverCol) --uriCol;
+ if(locationCol > extverCol) --locationCol;
+ }
+ if(uriCol != 0)
+ {
+ *status = fits_delete_col(gfptr,uriCol,status);
+ --tfields;
+ if(locationCol > uriCol) --locationCol;
+ }
+ if(locationCol != 0)
+ {
+ *status = fits_delete_col(gfptr,locationCol,status);
+ --tfields;
+ }
+
+ break;
+
+ case GT_ID_ALL:
+
+ if(uriCol != 0)
+ {
+ *status = fits_delete_col(gfptr,uriCol,status);
+ --tfields;
+ if(locationCol > uriCol) --locationCol;
+ }
+ if(locationCol != 0)
+ {
+ *status = fits_delete_col(gfptr,locationCol,status);
+ --tfields;
+ }
+
+ break;
+
+ case GT_ID_REF_URI:
+
+ if(positionCol != 0)
+ {
+ *status = fits_delete_col(gfptr,positionCol,status);
+ --tfields;
+ }
+
+ break;
+
+ case GT_ID_POS_URI:
+
+ if(xtensionCol != 0)
+ {
+ *status = fits_delete_col(gfptr,xtensionCol,status);
+ --tfields;
+ if(extnameCol > xtensionCol) --extnameCol;
+ if(extverCol > xtensionCol) --extverCol;
+ }
+ if(extnameCol != 0)
+ {
+ *status = fits_delete_col(gfptr,extnameCol,status);
+ --tfields;
+ if(extverCol > extnameCol) --extverCol;
+ }
+ if(extverCol != 0)
+ {
+ *status = fits_delete_col(gfptr,extverCol,status);
+ --tfields;
+ }
+
+ break;
+
+ default:
+
+ *status = BAD_OPTION;
+ ffpmsg("Invalid value for grouptype parameter specified (ffgtch)");
+ break;
+
+ }
+
+ /*
+ add all the new grouping table columns that were not there
+ previously but are called for by the grouptype parameter
+ */
+
+ for(i = 0; i < ncols && *status == 0; ++i)
+ *status = fits_insert_col(gfptr,tfields+i+1,ttype[i],tform[i],status);
+
+ /*
+ add the TNULL keywords and values for each new integer column defined;
+ integer null values are zero (0) for the MEMBER_POSITION and
+ MEMBER_VERSION columns. Insert a null ("/0") into each new string
+ column defined: MEMBER_XTENSION, MEMBER_NAME, MEMBER_URI_TYPE and
+ MEMBER_LOCATION. Note that by convention a null string is the
+ TNULL value for character fields so no TNULL is required.
+ */
+
+ for(i = 0; i < ncols && *status == 0; ++i)
+ {
+ if(strcasecmp(ttype[i],"MEMBER_POSITION") == 0 ||
+ strcasecmp(ttype[i],"MEMBER_VERSION") == 0)
+ {
+ /* col contains int data; set TNULL and insert 0 for each col */
+
+ *status = fits_get_colnum(gfptr,CASESEN,ttype[i],&colnum,
+ status);
+
+ sprintf(keyword,"TFORM%d",colnum);
+
+ *status = fits_read_key_str(gfptr,keyword,keyvalue,comment,
+ status);
+
+ sprintf(keyword,"TNULL%d",colnum);
+
+ *status = fits_insert_key_lng(gfptr,keyword,0,
+ "Column Null Value",status);
+
+ for(j = 1; j <= nrows && *status == 0; ++j)
+ *status = fits_write_col_lng(gfptr,colnum,j,1,1,&intNull,
+ status);
+ }
+ else if(strcasecmp(ttype[i],"MEMBER_XTENSION") == 0 ||
+ strcasecmp(ttype[i],"MEMBER_NAME") == 0 ||
+ strcasecmp(ttype[i],"MEMBER_URI_TYPE") == 0 ||
+ strcasecmp(ttype[i],"MEMBER_LOCATION") == 0)
+ {
+
+ /* new col contains character data; insert NULLs into each col */
+
+ *status = fits_get_colnum(gfptr,CASESEN,ttype[i],&colnum,
+ status);
+
+ for(j = 1; j <= nrows && *status == 0; ++j)
+ /* WILL THIS WORK FOR VAR LENTH CHAR COLS??????*/
+ *status = fits_write_col_byt(gfptr,colnum,j,1,1,charNull,
+ status);
+ }
+ }
+
+ }while(0);
+
+ return(*status);
+}
+
+/*---------------------------------------------------------------------------*/
+int ffgtrm(fitsfile *gfptr, /* FITS file pointer to group */
+ int rmopt, /* code specifying if member
+ elements are to be deleted:
+ OPT_RM_GPT ==> remove only group table
+ OPT_RM_ALL ==> recursively remove members
+ and their members (if groups) */
+ int *status) /* return status code */
+
+/*
+ remove a grouping table, and optionally all its members. Any groups
+ containing the grouping table are updated, and all members (if not
+ deleted) have their GRPIDn and GRPLCn keywords updated accordingly.
+ If the (deleted) members are members of another grouping table then those
+ tables are also updated. The CHDU of the FITS file pointed to by gfptr must
+ be positioned to the grouping table to be deleted.
+*/
+
+{
+ int hdutype;
+
+ long i;
+ long nmembers = 0;
+
+ HDUtracker HDU;
+
+
+ if(*status != 0) return(*status);
+
+ /*
+ remove the grouping table depending upon the rmopt parameter
+ */
+
+ switch(rmopt)
+ {
+
+ case OPT_RM_GPT:
+
+ /*
+ for this option, the grouping table is deleted, but the member
+ HDUs remain; in this case we only have to remove each member from
+ the grouping table by calling fits_remove_member() with the
+ OPT_RM_ENTRY option
+ */
+
+ /* get the number of members contained by this table */
+
+ *status = fits_get_num_members(gfptr,&nmembers,status);
+
+ /* loop over all grouping table members and remove them */
+
+ for(i = nmembers; i > 0 && *status == 0; --i)
+ *status = fits_remove_member(gfptr,i,OPT_RM_ENTRY,status);
+
+ break;
+
+ case OPT_RM_ALL:
+
+ /*
+ for this option the entire Group is deleted -- this includes all
+ members and their members (if grouping tables themselves). Call
+ the recursive form of this function to perform the removal.
+ */
+
+ /* add the current grouping table to the HDUtracker struct */
+
+ HDU.nHDU = 0;
+
+ *status = fftsad(gfptr,&HDU,NULL,NULL);
+
+ /* call the recursive group remove function */
+
+ *status = ffgtrmr(gfptr,&HDU,status);
+
+ /* free the memory allocated to the HDUtracker struct */
+
+ for(i = 0; i < HDU.nHDU; ++i)
+ {
+ free(HDU.filename[i]);
+ free(HDU.newFilename[i]);
+ }
+
+ break;
+
+ default:
+
+ *status = BAD_OPTION;
+ ffpmsg("Invalid value for the rmopt parameter specified (ffgtrm)");
+ break;
+
+ }
+
+ /*
+ if all went well then unlink and delete the grouping table HDU
+ */
+
+ *status = ffgmul(gfptr,0,status);
+
+ *status = fits_delete_hdu(gfptr,&hdutype,status);
+
+ return(*status);
+}
+
+/*---------------------------------------------------------------------------*/
+int ffgtcp(fitsfile *infptr, /* input FITS file pointer */
+ fitsfile *outfptr, /* output FITS file pointer */
+ int cpopt, /* code specifying copy options:
+ OPT_GCP_GPT (0) ==> copy only grouping table
+ OPT_GCP_ALL (2) ==> recusrively copy members
+ and their members (if
+ groups) */
+ int *status) /* return status code */
+
+/*
+ copy a grouping table, and optionally all its members, to a new FITS file.
+ If the cpopt is set to OPT_GCP_GPT (copy grouping table only) then the
+ existing members have their GRPIDn and GRPLCn keywords updated to reflect
+ the existance of the new group, since they now belong to another group. If
+ cpopt is set to OPT_GCP_ALL (copy grouping table and members recursively)
+ then the original members are not updated; the new grouping table is
+ modified to include only the copied member HDUs and not the original members.
+
+ Note that the recursive version of this function, ffgtcpr(), is called
+ to perform the group table copy. In the case of cpopt == OPT_GCP_GPT
+ ffgtcpr() does not actually use recursion.
+*/
+
+{
+ int i;
+
+ HDUtracker HDU;
+
+
+ if(*status != 0) return(*status);
+
+ /* make sure infptr and outfptr are not the same pointer */
+
+ if(infptr == outfptr) *status = IDENTICAL_POINTERS;
+ else
+ {
+
+ /* initialize the HDUtracker struct */
+
+ HDU.nHDU = 0;
+
+ *status = fftsad(infptr,&HDU,NULL,NULL);
+
+ /*
+ call the recursive form of this function to copy the grouping table.
+ If the cpopt is OPT_GCP_GPT then there is actually no recursion
+ performed
+ */
+
+ *status = ffgtcpr(infptr,outfptr,cpopt,&HDU,status);
+
+ /* free memory allocated for the HDUtracker struct */
+
+ for(i = 0; i < HDU.nHDU; ++i)
+ {
+ free(HDU.filename[i]);
+ free(HDU.newFilename[i]);
+ }
+ }
+
+ return(*status);
+}
+
+/*---------------------------------------------------------------------------*/
+int ffgtmg(fitsfile *infptr, /* FITS file ptr to source grouping table */
+ fitsfile *outfptr, /* FITS file ptr to target grouping table */
+ int mgopt, /* code specifying merge options:
+ OPT_MRG_COPY (0) ==> copy members to target
+ group, leaving source
+ group in place
+ OPT_MRG_MOV (1) ==> move members to target
+ group, source group is
+ deleted after merge */
+ int *status) /* return status code */
+
+
+/*
+ merge two grouping tables by combining their members into a single table.
+ The source grouping table must be the CHDU of the fitsfile pointed to by
+ infptr, and the target grouping table must be the CHDU of the fitsfile to by
+ outfptr. All members of the source grouping table shall be copied to the
+ target grouping table. If the mgopt parameter is OPT_MRG_COPY then the source
+ grouping table continues to exist after the merge. If the mgopt parameter
+ is OPT_MRG_MOV then the source grouping table is deleted after the merge,
+ and all member HDUs are updated accordingly.
+*/
+{
+ long i ;
+ long nmembers = 0;
+
+ fitsfile *tmpfptr = NULL;
+
+
+ if(*status != 0) return(*status);
+
+ do
+ {
+
+ *status = fits_get_num_members(infptr,&nmembers,status);
+
+ for(i = 1; i <= nmembers && *status == 0; ++i)
+ {
+ *status = fits_open_member(infptr,i,&tmpfptr,status);
+ *status = fits_add_group_member(outfptr,tmpfptr,0,status);
+
+ if(*status == HDU_ALREADY_MEMBER) *status = 0;
+
+ if(tmpfptr != NULL)
+ {
+ fits_close_file(tmpfptr,status);
+ tmpfptr = NULL;
+ }
+ }
+
+ if(*status != 0) continue;
+
+ if(mgopt == OPT_MRG_MOV)
+ *status = fits_remove_group(infptr,OPT_RM_GPT,status);
+
+ }while(0);
+
+ if(tmpfptr != NULL)
+ {
+ fits_close_file(tmpfptr,status);
+ }
+
+ return(*status);
+}
+
+/*---------------------------------------------------------------------------*/
+int ffgtcm(fitsfile *gfptr, /* FITS file pointer to grouping table */
+ int cmopt, /* code specifying compact options
+ OPT_CMT_MBR (1) ==> compact only direct
+ members (if groups)
+ OPT_CMT_MBR_DEL (11) ==> (1) + delete all
+ compacted groups */
+ int *status) /* return status code */
+
+/*
+ "Compact" a group pointed to by the FITS file pointer gfptr. This
+ is achieved by flattening the tree structure of a group and its
+ (grouping table) members. All members HDUs of a grouping table which is
+ itself a member of the grouping table gfptr are added to gfptr. Optionally,
+ the grouping tables which are "compacted" are deleted. If the grouping
+ table contains no members that are themselves grouping tables then this
+ function performs a NOOP.
+*/
+
+{
+ long i;
+ long nmembers = 0;
+
+ char keyvalue[FLEN_VALUE];
+ char comment[FLEN_COMMENT];
+
+ fitsfile *mfptr = NULL;
+
+
+ if(*status != 0) return(*status);
+
+ do
+ {
+ if(cmopt != OPT_CMT_MBR && cmopt != OPT_CMT_MBR_DEL)
+ {
+ *status = BAD_OPTION;
+ ffpmsg("Invalid value for cmopt parameter specified (ffgtcm)");
+ continue;
+ }
+
+ /* reteive the number of grouping table members */
+
+ *status = fits_get_num_members(gfptr,&nmembers,status);
+
+ /*
+ loop over all the grouping table members; if the member is a
+ grouping table then merge its members with the parent grouping
+ table
+ */
+
+ for(i = 1; i <= nmembers && *status == 0; ++i)
+ {
+ *status = fits_open_member(gfptr,i,&mfptr,status);
+
+ if(*status != 0) continue;
+
+ *status = fits_read_key_str(mfptr,"EXTNAME",keyvalue,comment,status);
+
+ /* if no EXTNAME keyword then cannot be a grouping table */
+
+ if(*status == KEY_NO_EXIST)
+ {
+ *status = 0;
+ continue;
+ }
+ prepare_keyvalue(keyvalue);
+
+ if(*status != 0) continue;
+
+ /* if EXTNAME == "GROUPING" then process member as grouping table */
+
+ if(strcasecmp(keyvalue,"GROUPING") == 0)
+ {
+ /* merge the member (grouping table) into the grouping table */
+
+ *status = fits_merge_groups(mfptr,gfptr,OPT_MRG_COPY,status);
+
+ *status = fits_close_file(mfptr,status);
+ mfptr = NULL;
+
+ /*
+ remove the member from the grouping table now that all of
+ its members have been transferred; if cmopt is set to
+ OPT_CMT_MBR_DEL then remove and delete the member
+ */
+
+ if(cmopt == OPT_CMT_MBR)
+ *status = fits_remove_member(gfptr,i,OPT_RM_ENTRY,status);
+ else
+ *status = fits_remove_member(gfptr,i,OPT_RM_MBR,status);
+ }
+ else
+ {
+ /* not a grouping table; just close the opened member */
+
+ *status = fits_close_file(mfptr,status);
+ mfptr = NULL;
+ }
+ }
+
+ }while(0);
+
+ return(*status);
+}
+
+/*--------------------------------------------------------------------------*/
+int ffgtvf(fitsfile *gfptr, /* FITS file pointer to group */
+ long *firstfailed, /* Member ID (if positive) of first failed
+ member HDU verify check or GRPID index
+ (if negitive) of first failed group
+ link verify check. */
+ int *status) /* return status code */
+
+/*
+ check the integrity of a grouping table to make sure that all group members
+ are accessible and all the links to other grouping tables are valid. The
+ firstfailed parameter returns the member ID of the first member HDU to fail
+ verification if positive or the first group link to fail if negative;
+ otherwise firstfailed contains a return value of 0.
+*/
+
+{
+ long i;
+ long nmembers = 0;
+ long ngroups = 0;
+
+ char errstr[FLEN_VALUE];
+
+ fitsfile *fptr = NULL;
+
+
+ if(*status != 0) return(*status);
+
+ *firstfailed = 0;
+
+ do
+ {
+ /*
+ attempt to open all the members of the grouping table. We stop
+ at the first member which cannot be opened (which implies that it
+ cannot be located)
+ */
+
+ *status = fits_get_num_members(gfptr,&nmembers,status);
+
+ for(i = 1; i <= nmembers && *status == 0; ++i)
+ {
+ *status = fits_open_member(gfptr,i,&fptr,status);
+ fits_close_file(fptr,status);
+ }
+
+ /*
+ if the status is non-zero from the above loop then record the
+ member index that caused the error
+ */
+
+ if(*status != 0)
+ {
+ *firstfailed = i;
+ sprintf(errstr,"Group table verify failed for member %ld (ffgtvf)",
+ i);
+ ffpmsg(errstr);
+ continue;
+ }
+
+ /*
+ attempt to open all the groups linked to this grouping table. We stop
+ at the first group which cannot be opened (which implies that it
+ cannot be located)
+ */
+
+ *status = fits_get_num_groups(gfptr,&ngroups,status);
+
+ for(i = 1; i <= ngroups && *status == 0; ++i)
+ {
+ *status = fits_open_group(gfptr,i,&fptr,status);
+ fits_close_file(fptr,status);
+ }
+
+ /*
+ if the status from the above loop is non-zero, then record the
+ GRPIDn index of the group that caused the failure
+ */
+
+ if(*status != 0)
+ {
+ *firstfailed = -1*i;
+ sprintf(errstr,
+ "Group table verify failed for GRPID index %ld (ffgtvf)",i);
+ ffpmsg(errstr);
+ continue;
+ }
+
+ }while(0);
+
+ return(*status);
+}
+
+/*---------------------------------------------------------------------------*/
+int ffgtop(fitsfile *mfptr, /* FITS file pointer to the member HDU */
+ int grpid, /* group ID (GRPIDn index) within member HDU */
+ fitsfile **gfptr, /* FITS file pointer to grouping table HDU */
+ int *status) /* return status code */
+
+/*
+ open the grouping table that contains the member HDU. The member HDU must
+ be the CHDU of the FITS file pointed to by mfptr, and the grouping table
+ is identified by the Nth index number of the GRPIDn keywords specified in
+ the member HDU's header. The fitsfile gfptr pointer is positioned with the
+ appropriate FITS file with the grouping table as the CHDU. If the group
+ grouping table resides in a file other than the member then an attempt
+ is first made to open the file readwrite, and failing that readonly.
+
+ Note that it is possible for the GRPIDn/GRPLCn keywords in a member
+ header to be non-continuous, e.g., GRPID1, GRPID2, GRPID5, GRPID6. In
+ such cases, the grpid index value specified in the function call shall
+ identify the (grpid)th GRPID value. In the above example, if grpid == 3,
+ then the group specified by GRPID5 would be opened.
+*/
+{
+ int i;
+ int found;
+
+ long ngroups = 0;
+ long grpExtver = 0;
+
+ char keyword[FLEN_KEYWORD];
+ char keyvalue[FLEN_FILENAME];
+ char *tkeyvalue;
+ char location[FLEN_FILENAME];
+ char location1[FLEN_FILENAME];
+ char location2[FLEN_FILENAME];
+ char comment[FLEN_COMMENT];
+
+ char *url[2];
+
+
+ if(*status != 0) return(*status);
+
+ do
+ {
+ /* set the grouping table pointer to NULL for error checking later */
+
+ *gfptr = NULL;
+
+ /*
+ make sure that the group ID requested is valid ==> cannot be
+ larger than the number of GRPIDn keywords in the member HDU header
+ */
+
+ *status = fits_get_num_groups(mfptr,&ngroups,status);
+
+ if(grpid > ngroups)
+ {
+ *status = BAD_GROUP_ID;
+ sprintf(comment,
+ "GRPID index %d larger total GRPID keywords %ld (ffgtop)",
+ grpid,ngroups);
+ ffpmsg(comment);
+ continue;
+ }
+
+ /*
+ find the (grpid)th group that the member HDU belongs to and read
+ the value of the GRPID(grpid) keyword; fits_get_num_groups()
+ automatically re-enumerates the GRPIDn/GRPLCn keywords to fill in
+ any gaps
+ */
+
+ sprintf(keyword,"GRPID%d",grpid);
+
+ *status = fits_read_key_lng(mfptr,keyword,&grpExtver,comment,status);
+
+ if(*status != 0) continue;
+
+ /*
+ if the value of the GRPIDn keyword is positive then the member is
+ in the same FITS file as the grouping table and we only have to
+ reopen the current FITS file. Else the member and grouping table
+ HDUs reside in different files and another FITS file must be opened
+ as specified by the corresponding GRPLCn keyword
+
+ The DO WHILE loop only executes once and is used to control the
+ file opening logic.
+ */
+
+ do
+ {
+ if(grpExtver > 0)
+ {
+ /*
+ the member resides in the same file as the grouping
+ table, so just reopen the grouping table file
+ */
+
+ *status = fits_reopen_file(mfptr,gfptr,status);
+ continue;
+ }
+
+ else if(grpExtver == 0)
+ {
+ /* a GRPIDn value of zero (0) is undefined */
+
+ *status = BAD_GROUP_ID;
+ sprintf(comment,"Invalid value of %ld for GRPID%d (ffgtop)",
+ grpExtver,grpid);
+ ffpmsg(comment);
+ continue;
+ }
+
+ /*
+ The GRPLCn keyword value is negative, which implies that
+ the grouping table must reside in another FITS file;
+ search for the corresponding GRPLCn keyword
+ */
+
+ /* set the grpExtver value positive */
+
+ grpExtver = -1*grpExtver;
+
+ /* read the GRPLCn keyword value */
+
+ sprintf(keyword,"GRPLC%d",grpid);
+ /* SPR 1738 */
+ *status = fits_read_key_longstr(mfptr,keyword,&tkeyvalue,comment,
+ status);
+ if (0 == *status) {
+ strcpy(keyvalue,tkeyvalue);
+ free(tkeyvalue);
+ }
+
+
+ /* if the GRPLCn keyword was not found then there is a problem */
+
+ if(*status == KEY_NO_EXIST)
+ {
+ *status = BAD_GROUP_ID;
+
+ sprintf(comment,"Cannot find GRPLC%d keyword (ffgtop)",
+ grpid);
+ ffpmsg(comment);
+
+ continue;
+ }
+
+ prepare_keyvalue(keyvalue);
+
+ /*
+ if the GRPLCn keyword value specifies an absolute URL then
+ try to open the file; we cannot attempt any relative URL
+ or host-dependent file path reconstruction
+ */
+
+ if(fits_is_url_absolute(keyvalue))
+ {
+ ffpmsg("Try to open group table file as absolute URL (ffgtop)");
+
+ *status = fits_open_file(gfptr,keyvalue,READWRITE,status);
+
+ /* if the open was successful then continue */
+
+ if(*status == 0) continue;
+
+ /* if READWRITE failed then try opening it READONLY */
+
+ ffpmsg("OK, try open group table file as READONLY (ffgtop)");
+
+ *status = 0;
+ *status = fits_open_file(gfptr,keyvalue,READONLY,status);
+
+ /* continue regardless of the outcome */
+
+ continue;
+ }
+
+ /*
+ see if the URL gives a file path that is absolute on the
+ host machine
+ */
+
+ *status = fits_url2path(keyvalue,location1,status);
+
+ *status = fits_open_file(gfptr,location1,READWRITE,status);
+
+ /* if the file opened then continue */
+
+ if(*status == 0) continue;
+
+ /* if READWRITE failed then try opening it READONLY */
+
+ ffpmsg("OK, try open group table file as READONLY (ffgtop)");
+
+ *status = 0;
+ *status = fits_open_file(gfptr,location1,READONLY,status);
+
+ /* if the file opened then continue */
+
+ if(*status == 0) continue;
+
+ /*
+ the grouping table location given by GRPLCn must specify a
+ relative URL. We assume that this URL is relative to the
+ member HDU's FITS file. Try to construct a full URL location
+ for the grouping table's FITS file and then open it
+ */
+
+ *status = 0;
+
+ /* retrieve the URL information for the member HDU's file */
+
+ url[0] = location1; url[1] = location2;
+
+ *status = fits_get_url(mfptr,url[0],url[1],NULL,NULL,NULL,status);
+
+ /*
+ It is possible that the member HDU file has an initial
+ URL it was opened with and a real URL that the file actually
+ exists at (e.g., an HTTP accessed file copied to a local
+ file). For each possible URL try to construct a
+ */
+
+ for(i = 0, found = 0, *gfptr = NULL; i < 2 && !found; ++i)
+ {
+
+ /* the url string could be empty */
+
+ if(*url[i] == 0) continue;
+
+ /*
+ create a full URL from the partial and the member
+ HDU file URL
+ */
+
+ *status = fits_relurl2url(url[i],keyvalue,location,status);
+
+ /* if an error occured then contniue */
+
+ if(*status != 0)
+ {
+ *status = 0;
+ continue;
+ }
+
+ /*
+ if the location does not specify an access method
+ then turn it into a host dependent path
+ */
+
+ if(! fits_is_url_absolute(location))
+ {
+ *status = fits_url2path(location,url[i],status);
+ strcpy(location,url[i]);
+ }
+
+ /* try to open the grouping table file READWRITE */
+
+ *status = fits_open_file(gfptr,location,READWRITE,status);
+
+ if(*status != 0)
+ {
+ /* try to open the grouping table file READONLY */
+
+ ffpmsg("opening file as READWRITE failed (ffgtop)");
+ ffpmsg("OK, try to open file as READONLY (ffgtop)");
+ *status = 0;
+ *status = fits_open_file(gfptr,location,READONLY,status);
+ }
+
+ /* either set the found flag or reset the status flag */
+
+ if(*status == 0)
+ found = 1;
+ else
+ *status = 0;
+ }
+
+ }while(0); /* end of file opening loop */
+
+ /* if an error occured with the file opening then exit */
+
+ if(*status != 0) continue;
+
+ if(*gfptr == NULL)
+ {
+ ffpmsg("Cannot open or find grouping table FITS file (ffgtop)");
+ *status = GROUP_NOT_FOUND;
+ continue;
+ }
+
+ /* search for the grouping table in its FITS file */
+
+ *status = fits_movnam_hdu(*gfptr,ANY_HDU,"GROUPING",(int)grpExtver,
+ status);
+
+ if(*status != 0) *status = GROUP_NOT_FOUND;
+
+ }while(0);
+
+ if(*status != 0 && *gfptr != NULL)
+ {
+ fits_close_file(*gfptr,status);
+ *gfptr = NULL;
+ }
+
+ return(*status);
+}
+/*---------------------------------------------------------------------------*/
+int ffgtam(fitsfile *gfptr, /* FITS file pointer to grouping table HDU */
+ fitsfile *mfptr, /* FITS file pointer to member HDU */
+ int hdupos, /* member HDU position IF in the same file as
+ the grouping table AND mfptr == NULL */
+ int *status) /* return status code */
+
+/*
+ add a member HDU to an existing grouping table. The fitsfile pointer gfptr
+ must be positioned with the grouping table as the CHDU. The member HDU
+ may either be identifed with the fitsfile *mfptr (which must be positioned
+ to the member HDU) or the hdupos parameter (the HDU number of the member
+ HDU) if both reside in the same FITS file. The hdupos value is only used
+ if the mfptr parameter has a value of NULL (0). The new member HDU shall
+ have the appropriate GRPIDn and GRPLCn keywords created in its header.
+
+ Note that if the member HDU to be added to the grouping table is already
+ a member of the group then it will not be added a sceond time.
+*/
+
+{
+ int xtensionCol,extnameCol,extverCol,positionCol,locationCol,uriCol;
+ int memberPosition = 0;
+ int grptype = 0;
+ int hdutype = 0;
+ int useLocation = 0;
+ int nkeys = 6;
+ int found;
+ int i;
+
+ int memberIOstate;
+ int groupIOstate;
+ int iomode;
+
+ long memberExtver = 0;
+ long groupExtver = 0;
+ long memberID = 0;
+ long nmembers = 0;
+ long ngroups = 0;
+ long grpid = 0;
+
+ char memberAccess1[FLEN_VALUE];
+ char memberAccess2[FLEN_VALUE];
+ char memberFileName[FLEN_FILENAME];
+ char memberLocation[FLEN_FILENAME];
+ char grplc[FLEN_FILENAME];
+ char *tgrplc;
+ char memberHDUtype[FLEN_VALUE];
+ char memberExtname[FLEN_VALUE];
+ char memberURI[] = "URL";
+
+ char groupAccess1[FLEN_VALUE];
+ char groupAccess2[FLEN_VALUE];
+ char groupFileName[FLEN_FILENAME];
+ char groupLocation[FLEN_FILENAME];
+
+ char cwd[FLEN_FILENAME];
+
+ char *keys[] = {"GRPNAME","EXTVER","EXTNAME","TFIELDS","GCOUNT","EXTEND"};
+ char *tmpPtr[1];
+
+ char keyword[FLEN_KEYWORD];
+ char card[FLEN_CARD];
+
+ unsigned char charNull[] = {'\0'};
+
+ fitsfile *tmpfptr = NULL;
+
+ int parentStatus = 0;
+
+ if(*status != 0) return(*status);
+
+ do
+ {
+ /*
+ make sure the grouping table can be modified before proceeding
+ */
+
+ fits_file_mode(gfptr,&iomode,status);
+
+ if(iomode != READWRITE)
+ {
+ ffpmsg("cannot modify grouping table (ffgtam)");
+ *status = BAD_GROUP_ATTACH;
+ continue;
+ }
+
+ /*
+ if the calling function supplied the HDU position of the member
+ HDU instead of fitsfile pointer then get a fitsfile pointer
+ */
+
+ if(mfptr == NULL)
+ {
+ *status = fits_reopen_file(gfptr,&tmpfptr,status);
+ *status = fits_movabs_hdu(tmpfptr,hdupos,&hdutype,status);
+
+ if(*status != 0) continue;
+ }
+ else
+ tmpfptr = mfptr;
+
+ /*
+ determine all the information about the member HDU that will
+ be needed later; note that we establish the default values for
+ all information values that are not explicitly found
+ */
+
+ *status = fits_read_key_str(tmpfptr,"XTENSION",memberHDUtype,card,
+ status);
+
+ if(*status == KEY_NO_EXIST)
+ {
+ strcpy(memberHDUtype,"PRIMARY");
+ *status = 0;
+ }
+ prepare_keyvalue(memberHDUtype);
+
+ *status = fits_read_key_lng(tmpfptr,"EXTVER",&memberExtver,card,status);
+
+ if(*status == KEY_NO_EXIST)
+ {
+ memberExtver = 1;
+ *status = 0;
+ }
+
+ *status = fits_read_key_str(tmpfptr,"EXTNAME",memberExtname,card,
+ status);
+
+ if(*status == KEY_NO_EXIST)
+ {
+ memberExtname[0] = 0;
+ *status = 0;
+ }
+ prepare_keyvalue(memberExtname);
+
+ fits_get_hdu_num(tmpfptr,&memberPosition);
+
+ /*
+ Determine if the member HDU's FITS file location needs to be
+ taken into account when building its grouping table reference
+
+ If the member location needs to be used (==> grouping table and member
+ HDU reside in different files) then create an appropriate URL for
+ the member HDU's file and grouping table's file. Note that the logic
+ for this is rather complicated
+ */
+
+ /* SPR 3463, don't do this
+ if(tmpfptr->Fptr == gfptr->Fptr)
+ { */
+ /*
+ member HDU and grouping table reside in the same file, no need
+ to use the location information */
+
+ /* printf ("same file\n");
+
+ useLocation = 0;
+ memberIOstate = 1;
+ *memberFileName = 0;
+ }
+ else
+ { */
+ /*
+ the member HDU and grouping table FITS file location information
+ must be used.
+
+ First determine the correct driver and file name for the group
+ table and member HDU files. If either are disk files then
+ construct an absolute file path for them. Finally, if both are
+ disk files construct relative file paths from the group(member)
+ file to the member(group) file.
+
+ */
+
+ /* set the USELOCATION flag to true */
+
+ useLocation = 1;
+
+ /*
+ get the location, access type and iostate (RO, RW) of the
+ member HDU file
+ */
+
+ *status = fits_get_url(tmpfptr,memberFileName,memberLocation,
+ memberAccess1,memberAccess2,&memberIOstate,
+ status);
+
+ /*
+ if the memberFileName string is empty then use the values of
+ the memberLocation string. This corresponds to a file where
+ the "real" file is a temporary memory file, and we must assume
+ the the application really wants the original file to be the
+ group member
+ */
+
+ if(strlen(memberFileName) == 0)
+ {
+ strcpy(memberFileName,memberLocation);
+ strcpy(memberAccess1,memberAccess2);
+ }
+
+ /*
+ get the location, access type and iostate (RO, RW) of the
+ grouping table file
+ */
+
+ *status = fits_get_url(gfptr,groupFileName,groupLocation,
+ groupAccess1,groupAccess2,&groupIOstate,
+ status);
+
+ if(*status != 0) continue;
+
+ /*
+ the grouping table file must be writable to continue
+ */
+
+ if(groupIOstate == 0)
+ {
+ ffpmsg("cannot modify grouping table (ffgtam)");
+ *status = BAD_GROUP_ATTACH;
+ continue;
+ }
+
+ /*
+ determine how to construct the resulting URLs for the member and
+ group files
+ */
+
+ if(strcasecmp(groupAccess1,"file://") &&
+ strcasecmp(memberAccess1,"file://"))
+ {
+ *cwd = 0;
+ /*
+ nothing to do in this case; both the member and group files
+ must be of an access type that already gives valid URLs;
+ i.e., URLs that we can pass directly to the file drivers
+ */
+ }
+ else
+ {
+ /*
+ retrieve the Current Working Directory as a Unix-like
+ URL standard string
+ */
+
+ *status = fits_get_cwd(cwd,status);
+
+ /*
+ create full file path for the member HDU FITS file URL
+ if it is of access type file://
+ */
+
+ if(strcasecmp(memberAccess1,"file://") == 0)
+ {
+ if(*memberFileName == '/')
+ {
+ strcpy(memberLocation,memberFileName);
+ }
+ else
+ {
+ strcpy(memberLocation,cwd);
+ strcat(memberLocation,"/");
+ strcat(memberLocation,memberFileName);
+ }
+
+ *status = fits_clean_url(memberLocation,memberFileName,
+ status);
+ }
+
+ /*
+ create full file path for the grouping table HDU FITS file URL
+ if it is of access type file://
+ */
+
+ if(strcasecmp(groupAccess1,"file://") == 0)
+ {
+ if(*groupFileName == '/')
+ {
+ strcpy(groupLocation,groupFileName);
+ }
+ else
+ {
+ strcpy(groupLocation,cwd);
+ strcat(groupLocation,"/");
+ strcat(groupLocation,groupFileName);
+ }
+
+ *status = fits_clean_url(groupLocation,groupFileName,status);
+ }
+
+ /*
+ if both the member and group files are disk files then
+ create a relative path (relative URL) strings with
+ respect to the grouping table's file and the grouping table's
+ file with respect to the member HDU's file
+ */
+
+ if(strcasecmp(groupAccess1,"file://") == 0 &&
+ strcasecmp(memberAccess1,"file://") == 0)
+ {
+ fits_url2relurl(memberFileName,groupFileName,
+ groupLocation,status);
+ fits_url2relurl(groupFileName,memberFileName,
+ memberLocation,status);
+
+ /*
+ copy the resulting partial URL strings to the
+ memberFileName and groupFileName variables for latter
+ use in the function
+ */
+
+ strcpy(memberFileName,memberLocation);
+ strcpy(groupFileName,groupLocation);
+ }
+ }
+ /* beo done */
+ /* } */
+
+
+ /* retrieve the grouping table's EXTVER value */
+
+ *status = fits_read_key_lng(gfptr,"EXTVER",&groupExtver,card,status);
+
+ /*
+ if useLocation is true then make the group EXTVER value negative
+ for the subsequent GRPIDn/GRPLCn matching
+ */
+ /* SPR 3463 change test */
+ if(tmpfptr->Fptr != gfptr->Fptr) groupExtver = -1*groupExtver;
+
+ /* retrieve the number of group members */
+
+ *status = fits_get_num_members(gfptr,&nmembers,status);
+
+ do {
+
+ /*
+ make sure the member HDU is not already an entry in the
+ grouping table before adding it
+ */
+
+ *status = ffgmf(gfptr,memberHDUtype,memberExtname,memberExtver,
+ memberPosition,memberFileName,&memberID,status);
+
+ if(*status == MEMBER_NOT_FOUND) *status = 0;
+ else if(*status == 0)
+ {
+ parentStatus = HDU_ALREADY_MEMBER;
+ ffpmsg("Specified HDU is already a member of the Grouping table (ffgtam)");
+ continue;
+ }
+ else continue;
+
+ /*
+ if the member HDU is not already recorded in the grouping table
+ then add it
+ */
+
+ /* add a new row to the grouping table */
+
+ *status = fits_insert_rows(gfptr,nmembers,1,status);
+ ++nmembers;
+
+ /* retrieve the grouping table column IDs and structure type */
+
+ *status = ffgtgc(gfptr,&xtensionCol,&extnameCol,&extverCol,&positionCol,
+ &locationCol,&uriCol,&grptype,status);
+
+ /* fill in the member HDU data in the new grouping table row */
+
+ *tmpPtr = memberHDUtype;
+
+ if(xtensionCol != 0)
+ fits_write_col_str(gfptr,xtensionCol,nmembers,1,1,tmpPtr,status);
+
+ *tmpPtr = memberExtname;
+
+ if(extnameCol != 0)
+ {
+ if(strlen(memberExtname) != 0)
+ fits_write_col_str(gfptr,extnameCol,nmembers,1,1,tmpPtr,status);
+ else
+ /* WILL THIS WORK FOR VAR LENTH CHAR COLS??????*/
+ fits_write_col_byt(gfptr,extnameCol,nmembers,1,1,charNull,status);
+ }
+
+ if(extverCol != 0)
+ fits_write_col_lng(gfptr,extverCol,nmembers,1,1,&memberExtver,
+ status);
+
+ if(positionCol != 0)
+ fits_write_col_int(gfptr,positionCol,nmembers,1,1,
+ &memberPosition,status);
+
+ *tmpPtr = memberFileName;
+
+ if(locationCol != 0)
+ {
+ /* Change the test for SPR 3463 */
+ if(tmpfptr->Fptr != gfptr->Fptr)
+ fits_write_col_str(gfptr,locationCol,nmembers,1,1,tmpPtr,status);
+ else
+ /* WILL THIS WORK FOR VAR LENTH CHAR COLS??????*/
+ fits_write_col_byt(gfptr,locationCol,nmembers,1,1,charNull,status);
+ }
+
+ *tmpPtr = memberURI;
+
+ if(uriCol != 0)
+ {
+
+ /* Change the test for SPR 3463 */
+
+ if(tmpfptr->Fptr != gfptr->Fptr)
+ fits_write_col_str(gfptr,uriCol,nmembers,1,1,tmpPtr,status);
+ else
+ /* WILL THIS WORK FOR VAR LENTH CHAR COLS??????*/
+ fits_write_col_byt(gfptr,uriCol,nmembers,1,1,charNull,status);
+ }
+ } while(0);
+
+ if(0 != *status) continue;
+ /*
+ add GRPIDn/GRPLCn keywords to the member HDU header to link
+ it to the grouing table if the they do not already exist and
+ the member file is RW
+ */
+
+ fits_file_mode(tmpfptr,&iomode,status);
+
+ if(memberIOstate == 0 || iomode != READWRITE)
+ {
+ ffpmsg("cannot add GRPID/LC keywords to member HDU: (ffgtam)");
+ ffpmsg(memberFileName);
+ continue;
+ }
+
+ *status = fits_get_num_groups(tmpfptr,&ngroups,status);
+
+ /*
+ look for the GRPID/LC keywords in the member HDU; if the keywords
+ for the back-link to the grouping table already exist then no
+ need to add them again
+ */
+
+ for(i = 1, found = 0; i <= ngroups && !found && *status == 0; ++i)
+ {
+ sprintf(keyword,"GRPID%d",(int)ngroups);
+ *status = fits_read_key_lng(tmpfptr,keyword,&grpid,card,status);
+
+ if(grpid == groupExtver)
+ {
+ if(grpid < 0)
+ {
+
+ /* have to make sure the GRPLCn keyword matches too */
+
+ sprintf(keyword,"GRPLC%d",(int)ngroups);
+ /* SPR 1738 */
+ *status = fits_read_key_longstr(mfptr,keyword,&tgrplc,card,
+ status);
+ if (0 == *status) {
+ strcpy(grplc,tgrplc);
+ free(tgrplc);
+ }
+
+ /*
+ always compare files using absolute paths
+ the presence of a non-empty cwd indicates
+ that the file names may require conversion
+ to absolute paths
+ */
+
+ if(0 < strlen(cwd)) {
+ /* temp buffer for use in assembling abs. path(s) */
+ char tmp[FLEN_FILENAME];
+
+ /* make grplc absolute if necessary */
+ if(!fits_is_url_absolute(grplc)) {
+ fits_path2url(grplc,groupLocation,status);
+
+ if(groupLocation[0] != '/')
+ {
+ strcpy(tmp, cwd);
+ strcat(tmp,"/");
+ strcat(tmp,groupLocation);
+ fits_clean_url(tmp,grplc,status);
+ }
+ }
+
+ /* make groupFileName absolute if necessary */
+ if(!fits_is_url_absolute(groupFileName)) {
+ fits_path2url(groupFileName,groupLocation,status);
+
+ if(groupLocation[0] != '/')
+ {
+ strcpy(tmp, cwd);
+ strcat(tmp,"/");
+ strcat(tmp,groupLocation);
+ /*
+ note: use groupLocation (which is not used
+ below this block), to store the absolute
+ file name instead of using groupFileName.
+ The latter may be needed unaltered if the
+ GRPLC is written below
+ */
+
+ fits_clean_url(tmp,groupLocation,status);
+ }
+ }
+ }
+ /*
+ see if the grplc value and the group file name match
+ */
+
+ if(strcmp(grplc,groupLocation) == 0) found = 1;
+ }
+ else
+ {
+ /* the match is found with GRPIDn alone */
+ found = 1;
+ }
+ }
+ }
+
+ /*
+ if FOUND is true then no need to continue
+ */
+
+ if(found)
+ {
+ ffpmsg("HDU already has GRPID/LC keywords for group table (ffgtam)");
+ continue;
+ }
+
+ /*
+ add the GRPID/LC keywords to the member header for this grouping
+ table
+
+ If NGROUPS == 0 then we must position the header pointer to the
+ record where we want to insert the GRPID/LC keywords (the pointer
+ is already correctly positioned if the above search loop activiated)
+ */
+
+ if(ngroups == 0)
+ {
+ /*
+ no GRPIDn/GRPLCn keywords currently exist in header so try
+ to position the header pointer to a desirable position
+ */
+
+ for(i = 0, *status = KEY_NO_EXIST;
+ i < nkeys && *status == KEY_NO_EXIST; ++i)
+ {
+ *status = 0;
+ *status = fits_read_card(tmpfptr,keys[i],card,status);
+ }
+
+ /* all else fails: move write pointer to end of header */
+
+ if(*status == KEY_NO_EXIST)
+ {
+ *status = 0;
+ fits_get_hdrspace(tmpfptr,&nkeys,&i,status);
+ ffgrec(tmpfptr,nkeys,card,status);
+ }
+
+ /* any other error status then abort */
+
+ if(*status != 0) continue;
+ }
+
+ /*
+ now that the header pointer is positioned for the GRPID/LC
+ keyword insertion increment the number of group links counter for
+ the member HDU
+ */
+
+ ++ngroups;
+
+ /*
+ if the member HDU and grouping table reside in the same FITS file
+ then there is no need to add a GRPLCn keyword
+ */
+ /* SPR 3463 change test */
+ if(tmpfptr->Fptr == gfptr->Fptr)
+ {
+ /* add the GRPIDn keyword only */
+
+ sprintf(keyword,"GRPID%d",(int)ngroups);
+ fits_insert_key_lng(tmpfptr,keyword,groupExtver,
+ "EXTVER of Group containing this HDU",status);
+ }
+ else
+ {
+ /* add the GRPIDn and GRPLCn keywords */
+
+ sprintf(keyword,"GRPID%d",(int)ngroups);
+ fits_insert_key_lng(tmpfptr,keyword,groupExtver,
+ "EXTVER of Group containing this HDU",status);
+
+ sprintf(keyword,"GRPLC%d",(int)ngroups);
+ /* SPR 1738 */
+ fits_insert_key_longstr(tmpfptr,keyword,groupFileName,
+ "URL of file containing Group",status);
+ fits_write_key_longwarn(tmpfptr,status);
+
+ }
+
+ }while(0);
+
+ /* close the tmpfptr pointer if it was opened in this function */
+
+ if(mfptr == NULL)
+ {
+ *status = fits_close_file(tmpfptr,status);
+ }
+
+ *status = 0 == *status ? parentStatus : *status;
+
+ return(*status);
+}
+
+/*---------------------------------------------------------------------------*/
+int ffgtnm(fitsfile *gfptr, /* FITS file pointer to grouping table */
+ long *nmembers, /* member count of the groping table */
+ int *status) /* return status code */
+
+/*
+ return the number of member HDUs in a grouping table. The fitsfile pointer
+ gfptr must be positioned with the grouping table as the CHDU. The number
+ of grouping table member HDUs is just the NAXIS2 value of the grouping
+ table.
+*/
+
+{
+ char keyvalue[FLEN_VALUE];
+ char comment[FLEN_COMMENT];
+
+
+ if(*status != 0) return(*status);
+
+ *status = fits_read_keyword(gfptr,"EXTNAME",keyvalue,comment,status);
+
+ if(*status == KEY_NO_EXIST)
+ *status = NOT_GROUP_TABLE;
+ else
+ {
+ prepare_keyvalue(keyvalue);
+
+ if(strcasecmp(keyvalue,"GROUPING") != 0)
+ {
+ *status = NOT_GROUP_TABLE;
+ ffpmsg("Specified HDU is not a Grouping table (ffgtnm)");
+ }
+
+ *status = fits_read_key_lng(gfptr,"NAXIS2",nmembers,comment,status);
+ }
+
+ return(*status);
+}
+
+/*--------------------------------------------------------------------------*/
+int ffgmng(fitsfile *mfptr, /* FITS file pointer to member HDU */
+ long *ngroups, /* total number of groups linked to HDU */
+ int *status) /* return status code */
+
+/*
+ return the number of groups to which a HDU belongs, as defined by the number
+ of GRPIDn/GRPLCn keyword records that appear in the HDU header. The
+ fitsfile pointer mfptr must be positioned with the member HDU as the CHDU.
+ Each time this function is called, the indicies of the GRPIDn/GRPLCn
+ keywords are checked to make sure they are continuous (ie no gaps) and
+ are re-enumerated to eliminate gaps if gaps are found to be present.
+*/
+
+{
+ int offset;
+ int index;
+ int newIndex;
+ int i;
+
+ long grpid;
+
+ char *inclist[] = {"GRPID#"};
+ char keyword[FLEN_KEYWORD];
+ char newKeyword[FLEN_KEYWORD];
+ char card[FLEN_CARD];
+ char comment[FLEN_COMMENT];
+ char *tkeyvalue;
+
+ if(*status != 0) return(*status);
+
+ *ngroups = 0;
+
+ /* reset the member HDU keyword counter to the beginning */
+
+ *status = ffgrec(mfptr,0,card,status);
+
+ /*
+ search for the number of GRPIDn keywords in the member HDU header
+ and count them with the ngroups variable
+ */
+
+ while(*status == 0)
+ {
+ /* read the next GRPIDn keyword in the series */
+
+ *status = fits_find_nextkey(mfptr,inclist,1,NULL,0,card,status);
+
+ if(*status != 0) continue;
+
+ ++(*ngroups);
+ }
+
+ if(*status == KEY_NO_EXIST) *status = 0;
+
+ /*
+ read each GRPIDn/GRPLCn keyword and adjust their index values so that
+ there are no gaps in the index count
+ */
+
+ for(index = 1, offset = 0, i = 1; i <= *ngroups && *status == 0; ++index)
+ {
+ sprintf(keyword,"GRPID%d",index);
+
+ /* try to read the next GRPIDn keyword in the series */
+
+ *status = fits_read_key_lng(mfptr,keyword,&grpid,card,status);
+
+ /* if not found then increment the offset counter and continue */
+
+ if(*status == KEY_NO_EXIST)
+ {
+ *status = 0;
+ ++offset;
+ }
+ else
+ {
+ /*
+ increment the number_keys_found counter and see if the index
+ of the keyword needs to be updated
+ */
+
+ ++i;
+
+ if(offset > 0)
+ {
+ /* compute the new index for the GRPIDn/GRPLCn keywords */
+ newIndex = index - offset;
+
+ /* update the GRPIDn keyword index */
+
+ sprintf(newKeyword,"GRPID%d",newIndex);
+ fits_modify_name(mfptr,keyword,newKeyword,status);
+
+ /* If present, update the GRPLCn keyword index */
+
+ sprintf(keyword,"GRPLC%d",index);
+ sprintf(newKeyword,"GRPLC%d",newIndex);
+ /* SPR 1738 */
+ *status = fits_read_key_longstr(mfptr,keyword,&tkeyvalue,comment,
+ status);
+ if (0 == *status) {
+ fits_delete_key(mfptr,keyword,status);
+ fits_insert_key_longstr(mfptr,newKeyword,tkeyvalue,comment,status);
+ fits_write_key_longwarn(mfptr,status);
+ free(tkeyvalue);
+ }
+
+
+ if(*status == KEY_NO_EXIST) *status = 0;
+ }
+ }
+ }
+
+ return(*status);
+}
+
+/*---------------------------------------------------------------------------*/
+int ffgmop(fitsfile *gfptr, /* FITS file pointer to grouping table */
+ long member, /* member ID (row num) within grouping table */
+ fitsfile **mfptr, /* FITS file pointer to member HDU */
+ int *status) /* return status code */
+
+/*
+ open a grouping table member, returning a pointer to the member's FITS file
+ with the CHDU set to the member HDU. The grouping table must be the CHDU of
+ the FITS file pointed to by gfptr. The member to open is identified by its
+ row number within the grouping table (first row/member == 1).
+
+ If the member resides in a FITS file different from the grouping
+ table the member file is first opened readwrite and if this fails then
+ it is opened readonly. For access type of FILE:// the member file is
+ searched for assuming (1) an absolute path is given, (2) a path relative
+ to the CWD is given, and (3) a path relative to the grouping table file
+ but not relative to the CWD is given. If all of these fail then the
+ error FILE_NOT_FOUND is returned.
+*/
+
+{
+ int xtensionCol,extnameCol,extverCol,positionCol,locationCol,uriCol;
+ int grptype,hdutype;
+ int dummy;
+
+ long hdupos = 0;
+ long extver = 0;
+
+ char xtension[FLEN_VALUE];
+ char extname[FLEN_VALUE];
+ char uri[FLEN_VALUE];
+ char grpLocation1[FLEN_FILENAME];
+ char grpLocation2[FLEN_FILENAME];
+ char mbrLocation1[FLEN_FILENAME];
+ char mbrLocation2[FLEN_FILENAME];
+ char mbrLocation3[FLEN_FILENAME];
+ char cwd[FLEN_FILENAME];
+ char card[FLEN_CARD];
+ char nstr[] = {'\0'};
+ char *tmpPtr[1];
+
+
+ if(*status != 0) return(*status);
+
+ do
+ {
+ /*
+ retrieve the Grouping Convention reserved column positions within
+ the grouping table
+ */
+
+ *status = ffgtgc(gfptr,&xtensionCol,&extnameCol,&extverCol,&positionCol,
+ &locationCol,&uriCol,&grptype,status);
+
+ if(*status != 0) continue;
+
+ /*
+ extract the member information from grouping table
+ */
+
+ tmpPtr[0] = xtension;
+
+ if(xtensionCol != 0)
+ {
+
+ *status = fits_read_col_str(gfptr,xtensionCol,member,1,1,nstr,
+ tmpPtr,&dummy,status);
+
+ /* convert the xtension string to a hdutype code */
+
+ if(strcasecmp(xtension,"PRIMARY") == 0) hdutype = IMAGE_HDU;
+ else if(strcasecmp(xtension,"IMAGE") == 0) hdutype = IMAGE_HDU;
+ else if(strcasecmp(xtension,"TABLE") == 0) hdutype = ASCII_TBL;
+ else if(strcasecmp(xtension,"BINTABLE") == 0) hdutype = BINARY_TBL;
+ else hdutype = ANY_HDU;
+ }
+
+ tmpPtr[0] = extname;
+
+ if(extnameCol != 0)
+ *status = fits_read_col_str(gfptr,extnameCol,member,1,1,nstr,
+ tmpPtr,&dummy,status);
+
+ if(extverCol != 0)
+ *status = fits_read_col_lng(gfptr,extverCol,member,1,1,0,
+ (long*)&extver,&dummy,status);
+
+ if(positionCol != 0)
+ *status = fits_read_col_lng(gfptr,positionCol,member,1,1,0,
+ (long*)&hdupos,&dummy,status);
+
+ tmpPtr[0] = mbrLocation1;
+
+ if(locationCol != 0)
+ *status = fits_read_col_str(gfptr,locationCol,member,1,1,nstr,
+ tmpPtr,&dummy,status);
+ tmpPtr[0] = uri;
+
+ if(uriCol != 0)
+ *status = fits_read_col_str(gfptr,uriCol,member,1,1,nstr,
+ tmpPtr,&dummy,status);
+
+ if(*status != 0) continue;
+
+ /*
+ decide what FITS file the member HDU resides in and open the file
+ using the fitsfile* pointer mfptr; note that this logic is rather
+ complicated and is based primiarly upon if a URL specifier is given
+ for the member file in the grouping table
+ */
+
+ switch(grptype)
+ {
+
+ case GT_ID_POS:
+ case GT_ID_REF:
+ case GT_ID_ALL:
+
+ /*
+ no location information is given so we must assume that the
+ member HDU resides in the same FITS file as the grouping table;
+ if the grouping table was incorrectly constructed then this
+ assumption will be false, but there is nothing to be done about
+ it at this point
+ */
+
+ *status = fits_reopen_file(gfptr,mfptr,status);
+
+ break;
+
+ case GT_ID_REF_URI:
+ case GT_ID_POS_URI:
+ case GT_ID_ALL_URI:
+
+ /*
+ The member location column exists. Determine if the member
+ resides in the same file as the grouping table or in a
+ separate file; open the member file in either case
+ */
+
+ if(strlen(mbrLocation1) == 0)
+ {
+ /*
+ since no location information was given we must assume
+ that the member is in the same FITS file as the grouping
+ table
+ */
+
+ *status = fits_reopen_file(gfptr,mfptr,status);
+ }
+ else
+ {
+ /*
+ make sure the location specifiation is "URL"; we cannot
+ decode any other URI types at this time
+ */
+
+ if(strcasecmp(uri,"URL") != 0)
+ {
+ *status = FILE_NOT_OPENED;
+ sprintf(card,
+ "Cannot open member HDU file with URI type %s (ffgmop)",
+ uri);
+ ffpmsg(card);
+
+ continue;
+ }
+
+ /*
+ The location string for the member is not NULL, so it
+ does not necessially reside in the same FITS file as the
+ grouping table.
+
+ Three cases are attempted for opening the member's file
+ in the following order:
+
+ 1. The URL given for the member's file is absolute (i.e.,
+ access method supplied); try to open the member
+
+ 2. The URL given for the member's file is not absolute but
+ is an absolute file path; try to open the member as a file
+ after the file path is converted to a host-dependent form
+
+ 3. The URL given for the member's file is not absolute
+ and is given as a relative path to the location of the
+ grouping table's file. Create an absolute URL using the
+ grouping table's file URL and try to open the member.
+
+ If all three cases fail then an error is returned. In each
+ case the file is first opened in read/write mode and failing
+ that readonly mode.
+
+ The following DO loop is only used as a mechanism to break
+ (continue) when the proper file opening method is found
+ */
+
+ do
+ {
+ /*
+ CASE 1:
+
+ See if the member URL is absolute (i.e., includes a
+ access directive) and if so open the file
+ */
+
+ if(fits_is_url_absolute(mbrLocation1))
+ {
+ /*
+ the URL must specify an access method, which
+ implies that its an absolute reference
+
+ regardless of the access method, pass the whole
+ URL to the open function for processing
+ */
+
+ ffpmsg("member URL is absolute, try open R/W (ffgmop)");
+
+ *status = fits_open_file(mfptr,mbrLocation1,READWRITE,
+ status);
+
+ if(*status == 0) continue;
+
+ *status = 0;
+
+ /*
+ now try to open file using full URL specs in
+ readonly mode
+ */
+
+ ffpmsg("OK, now try to open read-only (ffgmop)");
+
+ *status = fits_open_file(mfptr,mbrLocation1,READONLY,
+ status);
+
+ /* break from DO loop regardless of status */
+
+ continue;
+ }
+
+ /*
+ CASE 2:
+
+ If we got this far then the member URL location
+ has no access type ==> FILE:// Try to open the member
+ file using the URL as is, i.e., assume that it is given
+ as absolute, if it starts with a '/' character
+ */
+
+ ffpmsg("Member URL is of type FILE (ffgmop)");
+
+ if(*mbrLocation1 == '/')
+ {
+ ffpmsg("Member URL specifies abs file path (ffgmop)");
+
+ /*
+ convert the URL path to a host dependent path
+ */
+
+ *status = fits_url2path(mbrLocation1,mbrLocation2,
+ status);
+
+ ffpmsg("Try to open member URL in R/W mode (ffgmop)");
+
+ *status = fits_open_file(mfptr,mbrLocation2,READWRITE,
+ status);
+
+ if(*status == 0) continue;
+
+ *status = 0;
+
+ /*
+ now try to open file using the URL as an absolute
+ path in readonly mode
+ */
+
+ ffpmsg("OK, now try to open read-only (ffgmop)");
+
+ *status = fits_open_file(mfptr,mbrLocation2,READONLY,
+ status);
+
+ /* break from the Do loop regardless of the status */
+
+ continue;
+ }
+
+ /*
+ CASE 3:
+
+ If we got this far then the URL does not specify an
+ absoulte file path or URL with access method. Since
+ the path to the group table's file is (obviously) valid
+ for the CWD, create a full location string for the
+ member HDU using the grouping table URL as a basis
+
+ The only problem is that the grouping table file might
+ have two URLs, the original one used to open it and
+ the one that points to the real file being accessed
+ (i.e., a file accessed via HTTP but transferred to a
+ local disk file). Have to attempt to build a URL to
+ the member HDU file using both of these URLs if
+ defined.
+ */
+
+ ffpmsg("Try to open member file as relative URL (ffgmop)");
+
+ /* get the URL information for the grouping table file */
+
+ *status = fits_get_url(gfptr,grpLocation1,grpLocation2,
+ NULL,NULL,NULL,status);
+
+ /*
+ if the "real" grouping table file URL is defined then
+ build a full url for the member HDU file using it
+ and try to open the member HDU file
+ */
+
+ if(*grpLocation1)
+ {
+ /* make sure the group location is absolute */
+
+ if(! fits_is_url_absolute(grpLocation1) &&
+ *grpLocation1 != '/')
+ {
+ fits_get_cwd(cwd,status);
+ strcat(cwd,"/");
+ strcat(cwd,grpLocation1);
+ strcpy(grpLocation1,cwd);
+ }
+
+ /* create a full URL for the member HDU file */
+
+ *status = fits_relurl2url(grpLocation1,mbrLocation1,
+ mbrLocation2,status);
+
+ if(*status != 0) continue;
+
+ /*
+ if the URL does not have an access method given then
+ translate it into a host dependent file path
+ */
+
+ if(! fits_is_url_absolute(mbrLocation2))
+ {
+ *status = fits_url2path(mbrLocation2,mbrLocation3,
+ status);
+ strcpy(mbrLocation2,mbrLocation3);
+ }
+
+ /* try to open the member file READWRITE */
+
+ *status = fits_open_file(mfptr,mbrLocation2,READWRITE,
+ status);
+
+ if(*status == 0) continue;
+
+ *status = 0;
+
+ /* now try to open in readonly mode */
+
+ ffpmsg("now try to open file as READONLY (ffgmop)");
+
+ *status = fits_open_file(mfptr,mbrLocation2,READONLY,
+ status);
+
+ if(*status == 0) continue;
+
+ *status = 0;
+ }
+
+ /*
+ if we got this far then either the "real" grouping table
+ file URL was not defined or all attempts to open the
+ resulting member HDU file URL failed.
+
+ if the "original" grouping table file URL is defined then
+ build a full url for the member HDU file using it
+ and try to open the member HDU file
+ */
+
+ if(*grpLocation2)
+ {
+ /* make sure the group location is absolute */
+
+ if(! fits_is_url_absolute(grpLocation2) &&
+ *grpLocation2 != '/')
+ {
+ fits_get_cwd(cwd,status);
+ strcat(cwd,"/");
+ strcat(cwd,grpLocation2);
+ strcpy(grpLocation2,cwd);
+ }
+
+ /* create an absolute URL for the member HDU file */
+
+ *status = fits_relurl2url(grpLocation2,mbrLocation1,
+ mbrLocation2,status);
+ if(*status != 0) continue;
+
+ /*
+ if the URL does not have an access method given then
+ translate it into a host dependent file path
+ */
+
+ if(! fits_is_url_absolute(mbrLocation2))
+ {
+ *status = fits_url2path(mbrLocation2,mbrLocation3,
+ status);
+ strcpy(mbrLocation2,mbrLocation3);
+ }
+
+ /* try to open the member file READWRITE */
+
+ *status = fits_open_file(mfptr,mbrLocation2,READWRITE,
+ status);
+
+ if(*status == 0) continue;
+
+ *status = 0;
+
+ /* now try to open in readonly mode */
+
+ ffpmsg("now try to open file as READONLY (ffgmop)");
+
+ *status = fits_open_file(mfptr,mbrLocation2,READONLY,
+ status);
+
+ if(*status == 0) continue;
+
+ *status = 0;
+ }
+
+ /*
+ if we got this far then the member HDU file could not
+ be opened using any method. Log the error.
+ */
+
+ ffpmsg("Cannot open member HDU FITS file (ffgmop)");
+ *status = MEMBER_NOT_FOUND;
+
+ }while(0);
+ }
+
+ break;
+
+ default:
+
+ /* no default action */
+
+ break;
+ }
+
+ if(*status != 0) continue;
+
+ /*
+ attempt to locate the member HDU within its FITS file as determined
+ and opened above
+ */
+
+ switch(grptype)
+ {
+
+ case GT_ID_POS:
+ case GT_ID_POS_URI:
+
+ /*
+ try to find the member hdu in the the FITS file pointed to
+ by mfptr based upon its HDU posistion value. Note that is
+ impossible to verify if the HDU is actually the correct HDU due
+ to a lack of information.
+ */
+
+ *status = fits_movabs_hdu(*mfptr,(int)hdupos,&hdutype,status);
+
+ break;
+
+ case GT_ID_REF:
+ case GT_ID_REF_URI:
+
+ /*
+ try to find the member hdu in the FITS file pointed to
+ by mfptr based upon its XTENSION, EXTNAME and EXTVER keyword
+ values
+ */
+
+ *status = fits_movnam_hdu(*mfptr,hdutype,extname,extver,status);
+
+ if(*status == BAD_HDU_NUM)
+ {
+ *status = MEMBER_NOT_FOUND;
+ ffpmsg("Cannot find specified member HDU (ffgmop)");
+ }
+
+ /*
+ if the above function returned without error then the
+ mfptr is pointed to the member HDU
+ */
+
+ break;
+
+ case GT_ID_ALL:
+ case GT_ID_ALL_URI:
+
+ /*
+ if the member entry has reference information then use it
+ (ID by reference is safer than ID by position) else use
+ the position information
+ */
+
+ if(strlen(xtension) > 0 && strlen(extname) > 0 && extver > 0)
+ {
+ /* valid reference info exists so use it */
+
+ /* try to find the member hdu in the grouping table's file */
+
+ *status = fits_movnam_hdu(*mfptr,hdutype,extname,extver,status);
+
+ if(*status == BAD_HDU_NUM)
+ {
+ *status = MEMBER_NOT_FOUND;
+ ffpmsg("Cannot find specified member HDU (ffgmop)");
+ }
+ }
+ else
+ {
+ *status = fits_movabs_hdu(*mfptr,(int)hdupos,&hdutype,
+ status);
+ if(*status == END_OF_FILE) *status = MEMBER_NOT_FOUND;
+ }
+
+ /*
+ if the above function returned without error then the
+ mfptr is pointed to the member HDU
+ */
+
+ break;
+
+ default:
+
+ /* no default action */
+
+ break;
+ }
+
+ }while(0);
+
+ if(*status != 0 && *mfptr != NULL)
+ {
+ fits_close_file(*mfptr,status);
+ }
+
+ return(*status);
+}
+
+/*---------------------------------------------------------------------------*/
+int ffgmcp(fitsfile *gfptr, /* FITS file pointer to group */
+ fitsfile *mfptr, /* FITS file pointer to new member
+ FITS file */
+ long member, /* member ID (row num) within grouping table */
+ int cpopt, /* code specifying copy options:
+ OPT_MCP_ADD (0) ==> add copied member to the
+ grouping table
+ OPT_MCP_NADD (1) ==> do not add member copy to
+ the grouping table
+ OPT_MCP_REPL (2) ==> replace current member
+ entry with member copy */
+ int *status) /* return status code */
+
+/*
+ copy a member HDU of a grouping table to a new FITS file. The grouping table
+ must be the CHDU of the FITS file pointed to by gfptr. The copy of the
+ group member shall be appended to the end of the FITS file pointed to by
+ mfptr. If the cpopt parameter is set to OPT_MCP_ADD then the copy of the
+ member is added to the grouping table as a new member, if OPT_MCP_NADD
+ then the copied member is not added to the grouping table, and if
+ OPT_MCP_REPL then the copied member is used to replace the original member.
+ The copied member HDU also has its EXTVER value updated so that its
+ combination of XTENSION, EXTNAME and EXVTER is unique within its new
+ FITS file.
+*/
+
+{
+ int numkeys = 0;
+ int keypos = 0;
+ int hdunum = 0;
+ int hdutype = 0;
+ int i;
+
+ char *incList[] = {"GRPID#","GRPLC#"};
+ char extname[FLEN_VALUE];
+ char card[FLEN_CARD];
+ char comment[FLEN_COMMENT];
+ char keyname[FLEN_CARD];
+ char value[FLEN_CARD];
+
+ fitsfile *tmpfptr = NULL;
+
+
+ if(*status != 0) return(*status);
+
+ do
+ {
+ /* open the member HDU to be copied */
+
+ *status = fits_open_member(gfptr,member,&tmpfptr,status);
+
+ if(*status != 0) continue;
+
+ /*
+ if the member is a grouping table then copy it with a call to
+ fits_copy_group() using the "copy only the grouping table" option
+
+ if it is not a grouping table then copy the hdu with fits_copy_hdu()
+ remove all GRPIDn and GRPLCn keywords, and update the EXTVER keyword
+ value
+ */
+
+ /* get the member HDU's EXTNAME value */
+
+ *status = fits_read_key_str(tmpfptr,"EXTNAME",extname,comment,status);
+
+ /* if no EXTNAME value was found then set the extname to a null string */
+
+ if(*status == KEY_NO_EXIST)
+ {
+ extname[0] = 0;
+ *status = 0;
+ }
+ else if(*status != 0) continue;
+
+ prepare_keyvalue(extname);
+
+ /* if a grouping table then copy with fits_copy_group() */
+
+ if(strcasecmp(extname,"GROUPING") == 0)
+ *status = fits_copy_group(tmpfptr,mfptr,OPT_GCP_GPT,status);
+ else
+ {
+ /* copy the non-grouping table HDU the conventional way */
+
+ *status = fits_copy_hdu(tmpfptr,mfptr,0,status);
+
+ ffgrec(mfptr,0,card,status);
+
+ /* delete all the GRPIDn and GRPLCn keywords in the copied HDU */
+
+ while(*status == 0)
+ {
+ *status = fits_find_nextkey(mfptr,incList,2,NULL,0,card,status);
+ *status = fits_get_hdrpos(mfptr,&numkeys,&keypos,status);
+ /* SPR 1738 */
+ *status = fits_read_keyn(mfptr,keypos-1,keyname,value,
+ comment,status);
+ *status = fits_read_record(mfptr,keypos-1,card,status);
+ *status = fits_delete_key(mfptr,keyname,status);
+ }
+
+ if(*status == KEY_NO_EXIST) *status = 0;
+ if(*status != 0) continue;
+ }
+
+ /*
+ if the member HDU does not have an EXTNAME keyword then add one
+ with a default value
+ */
+
+ if(strlen(extname) == 0)
+ {
+ if(fits_get_hdu_num(tmpfptr,&hdunum) == 1)
+ {
+ strcpy(extname,"PRIMARY");
+ *status = fits_write_key_str(mfptr,"EXTNAME",extname,
+ "HDU was Formerly a Primary Array",
+ status);
+ }
+ else
+ {
+ strcpy(extname,"DEFAULT");
+ *status = fits_write_key_str(mfptr,"EXTNAME",extname,
+ "default EXTNAME set by CFITSIO",
+ status);
+ }
+ }
+
+ /*
+ update the member HDU's EXTVER value (add it if not present)
+ */
+
+ fits_get_hdu_num(mfptr,&hdunum);
+ fits_get_hdu_type(mfptr,&hdutype,status);
+
+ /* set the EXTVER value to 0 for now */
+
+ *status = fits_modify_key_lng(mfptr,"EXTVER",0,NULL,status);
+
+ /* if the EXTVER keyword was not found then add it */
+
+ if(*status == KEY_NO_EXIST)
+ {
+ *status = 0;
+ *status = fits_read_key_str(mfptr,"EXTNAME",extname,comment,
+ status);
+ *status = fits_insert_key_lng(mfptr,"EXTVER",0,
+ "Extension version ID",status);
+ }
+
+ if(*status != 0) continue;
+
+ /* find the first available EXTVER value for the copied HDU */
+
+ for(i = 1; fits_movnam_hdu(mfptr,hdutype,extname,i,status) == 0; ++i);
+
+ *status = 0;
+
+ fits_movabs_hdu(mfptr,hdunum,&hdutype,status);
+
+ /* reset the copied member HDUs EXTVER value */
+
+ *status = fits_modify_key_lng(mfptr,"EXTVER",(long)i,NULL,status);
+
+ /*
+ perform member copy operations that are dependent upon the cpopt
+ parameter value
+ */
+
+ switch(cpopt)
+ {
+ case OPT_MCP_ADD:
+
+ /*
+ add the copied member to the grouping table, leaving the
+ entry for the original member in place
+ */
+
+ *status = fits_add_group_member(gfptr,mfptr,0,status);
+
+ break;
+
+ case OPT_MCP_NADD:
+
+ /*
+ nothing to do for this copy option
+ */
+
+ break;
+
+ case OPT_MCP_REPL:
+
+ /*
+ remove the original member from the grouping table and add the
+ copied member in its place
+ */
+
+ *status = fits_remove_member(gfptr,member,OPT_RM_ENTRY,status);
+ *status = fits_add_group_member(gfptr,mfptr,0,status);
+
+ break;
+
+ default:
+
+ *status = BAD_OPTION;
+ ffpmsg("Invalid value specified for the cmopt parameter (ffgmcp)");
+
+ break;
+ }
+
+ }while(0);
+
+ if(tmpfptr != NULL)
+ {
+ fits_close_file(tmpfptr,status);
+ }
+
+ return(*status);
+}
+
+/*---------------------------------------------------------------------------*/
+int ffgmtf(fitsfile *infptr, /* FITS file pointer to source grouping table */
+ fitsfile *outfptr, /* FITS file pointer to target grouping table */
+ long member, /* member ID within source grouping table */
+ int tfopt, /* code specifying transfer opts:
+ OPT_MCP_ADD (0) ==> copy member to dest.
+ OPT_MCP_MOV (3) ==> move member to dest. */
+ int *status) /* return status code */
+
+/*
+ transfer a group member from one grouping table to another. The source
+ grouping table must be the CHDU of the fitsfile pointed to by infptr, and
+ the destination grouping table must be the CHDU of the fitsfile to by
+ outfptr. If the tfopt parameter is OPT_MCP_ADD then the member is made a
+ member of the target group and remains a member of the source group. If
+ the tfopt parameter is OPT_MCP_MOV then the member is deleted from the
+ source group after the transfer to the destination group. The member to be
+ transfered is identified by its row number within the source grouping table.
+*/
+
+{
+ fitsfile *mfptr = NULL;
+
+
+ if(*status != 0) return(*status);
+
+ if(tfopt != OPT_MCP_MOV && tfopt != OPT_MCP_ADD)
+ {
+ *status = BAD_OPTION;
+ ffpmsg("Invalid value specified for the tfopt parameter (ffgmtf)");
+ }
+ else
+ {
+ /* open the member of infptr to be transfered */
+
+ *status = fits_open_member(infptr,member,&mfptr,status);
+
+ /* add the member to the outfptr grouping table */
+
+ *status = fits_add_group_member(outfptr,mfptr,0,status);
+
+ /* close the member HDU */
+
+ *status = fits_close_file(mfptr,status);
+
+ /*
+ if the tfopt is "move member" then remove it from the infptr
+ grouping table
+ */
+
+ if(tfopt == OPT_MCP_MOV)
+ *status = fits_remove_member(infptr,member,OPT_RM_ENTRY,status);
+ }
+
+ return(*status);
+}
+
+/*---------------------------------------------------------------------------*/
+int ffgmrm(fitsfile *gfptr, /* FITS file pointer to group table */
+ long member, /* member ID (row num) in the group */
+ int rmopt, /* code specifying the delete option:
+ OPT_RM_ENTRY ==> delete the member entry
+ OPT_RM_MBR ==> delete entry and member HDU */
+ int *status) /* return status code */
+
+/*
+ remove a member HDU from a grouping table. The fitsfile pointer gfptr must
+ be positioned with the grouping table as the CHDU, and the member to
+ delete is identified by its row number in the table (first member == 1).
+ The rmopt parameter determines if the member entry is deleted from the
+ grouping table (in which case GRPIDn and GRPLCn keywords in the member
+ HDU's header shall be updated accordingly) or if the member HDU shall
+ itself be removed from its FITS file.
+*/
+
+{
+ int found = 0;
+ int hdutype = 0;
+ int index = 0;
+ int iomode = 0;
+
+ long i;
+ long ngroups = 0;
+ long nmembers = 0;
+ long groupExtver = 0;
+ long grpid = 0;
+
+ char grpLocation1[FLEN_FILENAME];
+ char grpLocation2[FLEN_FILENAME];
+ char grpLocation3[FLEN_FILENAME];
+ char cwd[FLEN_FILENAME];
+ char keyword[FLEN_KEYWORD];
+ /* SPR 1738 This can now be longer */
+ char grplc[FLEN_FILENAME];
+ char *tgrplc;
+ char keyvalue[FLEN_VALUE];
+ char card[FLEN_CARD];
+ char *editLocation;
+
+ fitsfile *mfptr = NULL;
+
+
+ if(*status != 0) return(*status);
+
+ do
+ {
+ /*
+ make sure the grouping table can be modified before proceeding
+ */
+
+ fits_file_mode(gfptr,&iomode,status);
+
+ if(iomode != READWRITE)
+ {
+ ffpmsg("cannot modify grouping table (ffgtam)");
+ *status = BAD_GROUP_DETACH;
+ continue;
+ }
+
+ /* open the group member to be deleted and get its IOstatus*/
+
+ *status = fits_open_member(gfptr,member,&mfptr,status);
+ *status = fits_file_mode(mfptr,&iomode,status);
+
+ /*
+ if the member HDU is to be deleted then call fits_unlink_member()
+ to remove it from all groups to which it belongs (including
+ this one) and then delete it. Note that if the member is a
+ grouping table then we have to recursively call fits_remove_member()
+ for each member of the member before we delete the member itself.
+ */
+
+ if(rmopt == OPT_RM_MBR)
+ {
+ /* cannot delete a PHDU */
+ if(fits_get_hdu_num(mfptr,&hdutype) == 1)
+ {
+ *status = BAD_HDU_NUM;
+ continue;
+ }
+
+ /* determine if the member HDU is itself a grouping table */
+
+ *status = fits_read_key_str(mfptr,"EXTNAME",keyvalue,card,status);
+
+ /* if no EXTNAME is found then the HDU cannot be a grouping table */
+
+ if(*status == KEY_NO_EXIST)
+ {
+ keyvalue[0] = 0;
+ *status = 0;
+ }
+ prepare_keyvalue(keyvalue);
+
+ /* Any other error is a reason to abort */
+
+ if(*status != 0) continue;
+
+ /* if the EXTNAME == GROUPING then the member is a grouping table */
+
+ if(strcasecmp(keyvalue,"GROUPING") == 0)
+ {
+ /* remove each of the grouping table members */
+
+ *status = fits_get_num_members(mfptr,&nmembers,status);
+
+ for(i = nmembers; i > 0 && *status == 0; --i)
+ *status = fits_remove_member(mfptr,i,OPT_RM_ENTRY,status);
+
+ if(*status != 0) continue;
+ }
+
+ /* unlink the member HDU from all groups that contain it */
+
+ *status = ffgmul(mfptr,0,status);
+
+ if(*status != 0) continue;
+
+ /* reset the grouping table HDU struct */
+
+ fits_set_hdustruc(gfptr,status);
+
+ /* delete the member HDU */
+
+ if(iomode != READONLY)
+ *status = fits_delete_hdu(mfptr,&hdutype,status);
+ }
+ else if(rmopt == OPT_RM_ENTRY)
+ {
+ /*
+ The member HDU is only to be removed as an entry from this
+ grouping table. Actions are (1) find the GRPIDn/GRPLCn
+ keywords that link the member to the grouping table, (2)
+ remove the GRPIDn/GRPLCn keyword from the member HDU header
+ and (3) remove the member entry from the grouping table
+ */
+
+ /*
+ there is no need to seach for and remove the GRPIDn/GRPLCn
+ keywords from the member HDU if it has not been opened
+ in READWRITE mode
+ */
+
+ if(iomode == READWRITE)
+ {
+ /*
+ determine the group EXTVER value of the grouping table; if
+ the member HDU and grouping table HDU do not reside in the
+ same file then set the groupExtver value to its negative
+ */
+
+ *status = fits_read_key_lng(gfptr,"EXTVER",&groupExtver,card,
+ status);
+ if(mfptr->Fptr != gfptr->Fptr) groupExtver = -1*groupExtver;
+
+ /*
+ retrieve the URLs for the grouping table; note that it is
+ possible that the grouping table file has two URLs, the
+ one used to open it and the "real" one pointing to the
+ actual file being accessed
+ */
+
+ *status = fits_get_url(gfptr,grpLocation1,grpLocation2,NULL,
+ NULL,NULL,status);
+
+ if(*status != 0) continue;
+
+ /*
+ if either of the group location strings specify a relative
+ file path then convert them into absolute file paths
+ */
+
+ *status = fits_get_cwd(cwd,status);
+
+ if(*grpLocation1 != 0 && *grpLocation1 != '/' &&
+ !fits_is_url_absolute(grpLocation1))
+ {
+ strcpy(grpLocation3,cwd);
+ strcat(grpLocation3,"/");
+ strcat(grpLocation3,grpLocation1);
+ fits_clean_url(grpLocation3,grpLocation1,status);
+ }
+
+ if(*grpLocation2 != 0 && *grpLocation2 != '/' &&
+ !fits_is_url_absolute(grpLocation2))
+ {
+ strcpy(grpLocation3,cwd);
+ strcat(grpLocation3,"/");
+ strcat(grpLocation3,grpLocation2);
+ fits_clean_url(grpLocation3,grpLocation2,status);
+ }
+
+ /*
+ determine the number of groups to which the member HDU
+ belongs
+ */
+
+ *status = fits_get_num_groups(mfptr,&ngroups,status);
+
+ /* reset the HDU keyword position counter to the beginning */
+
+ *status = ffgrec(mfptr,0,card,status);
+
+ /*
+ loop over all the GRPIDn keywords in the member HDU header
+ and find the appropriate GRPIDn and GRPLCn keywords that
+ identify it as belonging to the group
+ */
+
+ for(index = 1, found = 0; index <= ngroups && *status == 0 &&
+ !found; ++index)
+ {
+ /* read the next GRPIDn keyword in the series */
+
+ sprintf(keyword,"GRPID%d",index);
+
+ *status = fits_read_key_lng(mfptr,keyword,&grpid,card,
+ status);
+ if(*status != 0) continue;
+
+ /*
+ grpid value == group EXTVER value then we could have a
+ match
+ */
+
+ if(grpid == groupExtver && grpid > 0)
+ {
+ /*
+ if GRPID is positive then its a match because
+ both the member HDU and grouping table HDU reside
+ in the same FITS file
+ */
+
+ found = index;
+ }
+ else if(grpid == groupExtver && grpid < 0)
+ {
+ /*
+ have to look at the GRPLCn value to determine a
+ match because the member HDU and grouping table
+ HDU reside in different FITS files
+ */
+
+ sprintf(keyword,"GRPLC%d",index);
+
+ /* SPR 1738 */
+ *status = fits_read_key_longstr(mfptr,keyword,&tgrplc,
+ card, status);
+ if (0 == *status) {
+ strcpy(grplc,tgrplc);
+ free(tgrplc);
+ }
+
+ if(*status == KEY_NO_EXIST)
+ {
+ /*
+ no GRPLCn keyword value found ==> grouping
+ convention not followed; nothing we can do
+ about it, so just continue
+ */
+
+ sprintf(card,"No GRPLC%d found for GRPID%d",
+ index,index);
+ ffpmsg(card);
+ *status = 0;
+ continue;
+ }
+ else if (*status != 0) continue;
+
+ /* construct the URL for the GRPLCn value */
+
+ prepare_keyvalue(grplc);
+
+ /*
+ if the grplc value specifies a relative path then
+ turn it into a absolute file path for comparison
+ purposes
+ */
+
+ if(*grplc != 0 && !fits_is_url_absolute(grplc) &&
+ *grplc != '/')
+ {
+ /* No, wrong,
+ strcpy(grpLocation3,cwd);
+ should be */
+ *status = fits_file_name(mfptr,grpLocation3,status);
+ /* Remove everything after the last / */
+ if (NULL != (editLocation = strrchr(grpLocation3,'/'))) {
+ *editLocation = '\0';
+ }
+
+ strcat(grpLocation3,"/");
+ strcat(grpLocation3,grplc);
+ *status = fits_clean_url(grpLocation3,grplc,
+ status);
+ }
+
+ /*
+ if the absolute value of GRPIDn is equal to the
+ EXTVER value of the grouping table and (one of the
+ possible two) grouping table file URL matches the
+ GRPLCn keyword value then we hava a match
+ */
+
+ if(strcmp(grplc,grpLocation1) == 0 ||
+ strcmp(grplc,grpLocation2) == 0)
+ found = index;
+ }
+ }
+
+ /*
+ if found == 0 (false) after the above search then we assume
+ that it is due to an inpromper updating of the GRPIDn and
+ GRPLCn keywords in the member header ==> nothing to delete
+ in the header. Else delete the GRPLCn and GRPIDn keywords
+ that identify the member HDU with the group HDU and
+ re-enumerate the remaining GRPIDn and GRPLCn keywords
+ */
+
+ if(found != 0)
+ {
+ sprintf(keyword,"GRPID%d",found);
+ *status = fits_delete_key(mfptr,keyword,status);
+
+ sprintf(keyword,"GRPLC%d",found);
+ *status = fits_delete_key(mfptr,keyword,status);
+
+ *status = 0;
+
+ /* call fits_get_num_groups() to re-enumerate the GRPIDn */
+
+ *status = fits_get_num_groups(mfptr,&ngroups,status);
+ }
+ }
+
+ /*
+ finally, remove the member entry from the current grouping table
+ pointed to by gfptr
+ */
+
+ *status = fits_delete_rows(gfptr,member,1,status);
+ }
+ else
+ {
+ *status = BAD_OPTION;
+ ffpmsg("Invalid value specified for the rmopt parameter (ffgmrm)");
+ }
+
+ }while(0);
+
+ if(mfptr != NULL)
+ {
+ fits_close_file(mfptr,status);
+ }
+
+ return(*status);
+}
+
+/*---------------------------------------------------------------------------
+ Grouping Table support functions
+ ---------------------------------------------------------------------------*/
+int ffgtgc(fitsfile *gfptr, /* pointer to the grouping table */
+ int *xtensionCol, /* column ID of the MEMBER_XTENSION column */
+ int *extnameCol, /* column ID of the MEMBER_NAME column */
+ int *extverCol, /* column ID of the MEMBER_VERSION column */
+ int *positionCol, /* column ID of the MEMBER_POSITION column */
+ int *locationCol, /* column ID of the MEMBER_LOCATION column */
+ int *uriCol, /* column ID of the MEMBER_URI_TYPE column */
+ int *grptype, /* group structure type code specifying the
+ grouping table columns that are defined:
+ GT_ID_ALL_URI (0) ==> all columns defined
+ GT_ID_REF (1) ==> reference cols only
+ GT_ID_POS (2) ==> position col only
+ GT_ID_ALL (3) ==> ref & pos cols
+ GT_ID_REF_URI (11) ==> ref & loc cols
+ GT_ID_POS_URI (12) ==> pos & loc cols */
+ int *status) /* return status code */
+/*
+ examine the grouping table pointed to by gfptr and determine the column
+ index ID of each possible grouping column. If a column is not found then
+ an index of 0 is returned. the grptype parameter returns the structure
+ of the grouping table ==> what columns are defined.
+*/
+
+{
+
+ char keyvalue[FLEN_VALUE];
+ char comment[FLEN_COMMENT];
+
+
+ if(*status != 0) return(*status);
+
+ do
+ {
+ /*
+ if the HDU does not have an extname of "GROUPING" then it is not
+ a grouping table
+ */
+
+ *status = fits_read_key_str(gfptr,"EXTNAME",keyvalue,comment,status);
+
+ if(*status == KEY_NO_EXIST)
+ {
+ *status = NOT_GROUP_TABLE;
+ ffpmsg("Specified HDU is not a Grouping Table (ffgtgc)");
+ }
+ if(*status != 0) continue;
+
+ prepare_keyvalue(keyvalue);
+
+ if(strcasecmp(keyvalue,"GROUPING") != 0)
+ {
+ *status = NOT_GROUP_TABLE;
+ continue;
+ }
+
+ /*
+ search for the MEMBER_XTENSION, MEMBER_NAME, MEMBER_VERSION,
+ MEMBER_POSITION, MEMBER_LOCATION and MEMBER_URI_TYPE columns
+ and determine their column index ID
+ */
+
+ *status = fits_get_colnum(gfptr,CASESEN,"MEMBER_XTENSION",xtensionCol,
+ status);
+
+ if(*status == COL_NOT_FOUND)
+ {
+ *status = 0;
+ *xtensionCol = 0;
+ }
+
+ if(*status != 0) continue;
+
+ *status = fits_get_colnum(gfptr,CASESEN,"MEMBER_NAME",extnameCol,status);
+
+ if(*status == COL_NOT_FOUND)
+ {
+ *status = 0;
+ *extnameCol = 0;
+ }
+
+ if(*status != 0) continue;
+
+ *status = fits_get_colnum(gfptr,CASESEN,"MEMBER_VERSION",extverCol,
+ status);
+
+ if(*status == COL_NOT_FOUND)
+ {
+ *status = 0;
+ *extverCol = 0;
+ }
+
+ if(*status != 0) continue;
+
+ *status = fits_get_colnum(gfptr,CASESEN,"MEMBER_POSITION",positionCol,
+ status);
+
+ if(*status == COL_NOT_FOUND)
+ {
+ *status = 0;
+ *positionCol = 0;
+ }
+
+ if(*status != 0) continue;
+
+ *status = fits_get_colnum(gfptr,CASESEN,"MEMBER_LOCATION",locationCol,
+ status);
+
+ if(*status == COL_NOT_FOUND)
+ {
+ *status = 0;
+ *locationCol = 0;
+ }
+
+ if(*status != 0) continue;
+
+ *status = fits_get_colnum(gfptr,CASESEN,"MEMBER_URI_TYPE",uriCol,
+ status);
+
+ if(*status == COL_NOT_FOUND)
+ {
+ *status = 0;
+ *uriCol = 0;
+ }
+
+ if(*status != 0) continue;
+
+ /*
+ determine the type of grouping table structure used by this
+ grouping table and record it in the grptype parameter
+ */
+
+ if(*xtensionCol && *extnameCol && *extverCol && *positionCol &&
+ *locationCol && *uriCol)
+ *grptype = GT_ID_ALL_URI;
+
+ else if(*xtensionCol && *extnameCol && *extverCol &&
+ *locationCol && *uriCol)
+ *grptype = GT_ID_REF_URI;
+
+ else if(*xtensionCol && *extnameCol && *extverCol && *positionCol)
+ *grptype = GT_ID_ALL;
+
+ else if(*xtensionCol && *extnameCol && *extverCol)
+ *grptype = GT_ID_REF;
+
+ else if(*positionCol && *locationCol && *uriCol)
+ *grptype = GT_ID_POS_URI;
+
+ else if(*positionCol)
+ *grptype = GT_ID_POS;
+
+ else
+ *status = NOT_GROUP_TABLE;
+
+ }while(0);
+
+ /*
+ if the table contained more than one column with a reserved name then
+ this cannot be considered a vailid grouping table
+ */
+
+ if(*status == COL_NOT_UNIQUE)
+ {
+ *status = NOT_GROUP_TABLE;
+ ffpmsg("Specified HDU has multipule Group table cols defined (ffgtgc)");
+ }
+
+ return(*status);
+}
+
+/*****************************************************************************/
+int ffgtdc(int grouptype, /* code specifying the type of
+ grouping table information:
+ GT_ID_ALL_URI 0 ==> defualt (all columns)
+ GT_ID_REF 1 ==> ID by reference
+ GT_ID_POS 2 ==> ID by position
+ GT_ID_ALL 3 ==> ID by ref. and position
+ GT_ID_REF_URI 11 ==> (1) + URI info
+ GT_ID_POS_URI 12 ==> (2) + URI info */
+ int xtensioncol, /* does MEMBER_XTENSION already exist? */
+ int extnamecol, /* does MEMBER_NAME aleady exist? */
+ int extvercol, /* does MEMBER_VERSION already exist? */
+ int positioncol, /* does MEMBER_POSITION already exist? */
+ int locationcol, /* does MEMBER_LOCATION already exist? */
+ int uricol, /* does MEMBER_URI_TYPE aleardy exist? */
+ char *ttype[], /* array of grouping table column TTYPE names
+ to define (if *col var false) */
+ char *tform[], /* array of grouping table column TFORM values
+ to define (if*col variable false) */
+ int *ncols, /* number of TTYPE and TFORM values returned */
+ int *status) /* return status code */
+
+/*
+ create the TTYPE and TFORM values for the grouping table according to the
+ value of the grouptype parameter and the values of the *col flags. The
+ resulting TTYPE and TFORM are returned in ttype[] and tform[] respectively.
+ The number of TTYPE and TFORMs returned is given by ncols. Both the TTYPE[]
+ and TTFORM[] arrays must contain enough pre-allocated strings to hold
+ the returned information.
+*/
+
+{
+
+ int i = 0;
+
+ char xtension[] = "MEMBER_XTENSION";
+ char xtenTform[] = "8A";
+
+ char name[] = "MEMBER_NAME";
+ char nameTform[] = "32A";
+
+ char version[] = "MEMBER_VERSION";
+ char verTform[] = "1J";
+
+ char position[] = "MEMBER_POSITION";
+ char posTform[] = "1J";
+
+ char URI[] = "MEMBER_URI_TYPE";
+ char URITform[] = "3A";
+
+ char location[] = "MEMBER_LOCATION";
+ /* SPR 01720, move from 160A to 256A */
+ char locTform[] = "256A";
+
+
+ if(*status != 0) return(*status);
+
+ switch(grouptype)
+ {
+
+ case GT_ID_ALL_URI:
+
+ if(xtensioncol == 0)
+ {
+ strcpy(ttype[i],xtension);
+ strcpy(tform[i],xtenTform);
+ ++i;
+ }
+ if(extnamecol == 0)
+ {
+ strcpy(ttype[i],name);
+ strcpy(tform[i],nameTform);
+ ++i;
+ }
+ if(extvercol == 0)
+ {
+ strcpy(ttype[i],version);
+ strcpy(tform[i],verTform);
+ ++i;
+ }
+ if(positioncol == 0)
+ {
+ strcpy(ttype[i],position);
+ strcpy(tform[i],posTform);
+ ++i;
+ }
+ if(locationcol == 0)
+ {
+ strcpy(ttype[i],location);
+ strcpy(tform[i],locTform);
+ ++i;
+ }
+ if(uricol == 0)
+ {
+ strcpy(ttype[i],URI);
+ strcpy(tform[i],URITform);
+ ++i;
+ }
+ break;
+
+ case GT_ID_REF:
+
+ if(xtensioncol == 0)
+ {
+ strcpy(ttype[i],xtension);
+ strcpy(tform[i],xtenTform);
+ ++i;
+ }
+ if(extnamecol == 0)
+ {
+ strcpy(ttype[i],name);
+ strcpy(tform[i],nameTform);
+ ++i;
+ }
+ if(extvercol == 0)
+ {
+ strcpy(ttype[i],version);
+ strcpy(tform[i],verTform);
+ ++i;
+ }
+ break;
+
+ case GT_ID_POS:
+
+ if(positioncol == 0)
+ {
+ strcpy(ttype[i],position);
+ strcpy(tform[i],posTform);
+ ++i;
+ }
+ break;
+
+ case GT_ID_ALL:
+
+ if(xtensioncol == 0)
+ {
+ strcpy(ttype[i],xtension);
+ strcpy(tform[i],xtenTform);
+ ++i;
+ }
+ if(extnamecol == 0)
+ {
+ strcpy(ttype[i],name);
+ strcpy(tform[i],nameTform);
+ ++i;
+ }
+ if(extvercol == 0)
+ {
+ strcpy(ttype[i],version);
+ strcpy(tform[i],verTform);
+ ++i;
+ }
+ if(positioncol == 0)
+ {
+ strcpy(ttype[i],position);
+ strcpy(tform[i], posTform);
+ ++i;
+ }
+
+ break;
+
+ case GT_ID_REF_URI:
+
+ if(xtensioncol == 0)
+ {
+ strcpy(ttype[i],xtension);
+ strcpy(tform[i],xtenTform);
+ ++i;
+ }
+ if(extnamecol == 0)
+ {
+ strcpy(ttype[i],name);
+ strcpy(tform[i],nameTform);
+ ++i;
+ }
+ if(extvercol == 0)
+ {
+ strcpy(ttype[i],version);
+ strcpy(tform[i],verTform);
+ ++i;
+ }
+ if(locationcol == 0)
+ {
+ strcpy(ttype[i],location);
+ strcpy(tform[i],locTform);
+ ++i;
+ }
+ if(uricol == 0)
+ {
+ strcpy(ttype[i],URI);
+ strcpy(tform[i],URITform);
+ ++i;
+ }
+ break;
+
+ case GT_ID_POS_URI:
+
+ if(positioncol == 0)
+ {
+ strcpy(ttype[i],position);
+ strcpy(tform[i],posTform);
+ ++i;
+ }
+ if(locationcol == 0)
+ {
+ strcpy(ttype[i],location);
+ strcpy(tform[i],locTform);
+ ++i;
+ }
+ if(uricol == 0)
+ {
+ strcpy(ttype[i],URI);
+ strcpy(tform[i],URITform);
+ ++i;
+ }
+ break;
+
+ default:
+
+ *status = BAD_OPTION;
+ ffpmsg("Invalid value specified for the grouptype parameter (ffgtdc)");
+
+ break;
+
+ }
+
+ *ncols = i;
+
+ return(*status);
+}
+
+/*****************************************************************************/
+int ffgmul(fitsfile *mfptr, /* pointer to the grouping table member HDU */
+ int rmopt, /* 0 ==> leave GRPIDn/GRPLCn keywords,
+ 1 ==> remove GRPIDn/GRPLCn keywords */
+ int *status) /* return status code */
+
+/*
+ examine all the GRPIDn and GRPLCn keywords in the member HDUs header
+ and remove the member from the grouping tables referenced; This
+ effectively "unlinks" the member from all of its groups. The rmopt
+ specifies if the GRPIDn/GRPLCn keywords are to be removed from the
+ member HDUs header after the unlinking.
+*/
+
+{
+ int memberPosition = 0;
+ int iomode;
+
+ long index = 0;
+ long ngroups = 0;
+ long memberExtver = 0;
+ long memberID = 0;
+
+ char mbrLocation1[FLEN_FILENAME];
+ char mbrLocation2[FLEN_FILENAME];
+ char memberHDUtype[FLEN_VALUE];
+ char memberExtname[FLEN_VALUE];
+ char keyword[FLEN_KEYWORD];
+ char card[FLEN_CARD];
+
+ fitsfile *gfptr = NULL;
+
+
+ if(*status != 0) return(*status);
+
+ do
+ {
+ /*
+ determine location parameters of the member HDU; note that
+ default values are supplied if the expected keywords are not
+ found
+ */
+
+ *status = fits_read_key_str(mfptr,"XTENSION",memberHDUtype,card,status);
+
+ if(*status == KEY_NO_EXIST)
+ {
+ strcpy(memberHDUtype,"PRIMARY");
+ *status = 0;
+ }
+ prepare_keyvalue(memberHDUtype);
+
+ *status = fits_read_key_lng(mfptr,"EXTVER",&memberExtver,card,status);
+
+ if(*status == KEY_NO_EXIST)
+ {
+ memberExtver = 1;
+ *status = 0;
+ }
+
+ *status = fits_read_key_str(mfptr,"EXTNAME",memberExtname,card,status);
+
+ if(*status == KEY_NO_EXIST)
+ {
+ memberExtname[0] = 0;
+ *status = 0;
+ }
+ prepare_keyvalue(memberExtname);
+
+ fits_get_hdu_num(mfptr,&memberPosition);
+
+ *status = fits_get_url(mfptr,mbrLocation1,mbrLocation2,NULL,NULL,
+ NULL,status);
+
+ if(*status != 0) continue;
+
+ /*
+ open each grouping table linked to this HDU and remove the member
+ from the grouping tables
+ */
+
+ *status = fits_get_num_groups(mfptr,&ngroups,status);
+
+ /* loop over each group linked to the member HDU */
+
+ for(index = 1; index <= ngroups && *status == 0; ++index)
+ {
+ /* open the (index)th group linked to the member HDU */
+
+ *status = fits_open_group(mfptr,index,&gfptr,status);
+
+ /* if the group could not be opened then just skip it */
+
+ if(*status != 0)
+ {
+ *status = 0;
+ sprintf(card,"Cannot open the %dth group table (ffgmul)",
+ (int)index);
+ ffpmsg(card);
+ continue;
+ }
+
+ /*
+ make sure the grouping table can be modified before proceeding
+ */
+
+ fits_file_mode(gfptr,&iomode,status);
+
+ if(iomode != READWRITE)
+ {
+ sprintf(card,"The %dth group cannot be modified (ffgtam)",
+ (int)index);
+ ffpmsg(card);
+ continue;
+ }
+
+ /*
+ try to find the member's row within the grouping table; first
+ try using the member HDU file's "real" URL string then try
+ using its originally opened URL string if either string exist
+ */
+
+ memberID = 0;
+
+ if(strlen(mbrLocation1) != 0)
+ {
+ *status = ffgmf(gfptr,memberHDUtype,memberExtname,memberExtver,
+ memberPosition,mbrLocation1,&memberID,status);
+ }
+
+ if(*status == MEMBER_NOT_FOUND && strlen(mbrLocation2) != 0)
+ {
+ *status = 0;
+ *status = ffgmf(gfptr,memberHDUtype,memberExtname,memberExtver,
+ memberPosition,mbrLocation2,&memberID,status);
+ }
+
+ /* if the member was found then delete it from the grouping table */
+
+ if(*status == 0)
+ *status = fits_delete_rows(gfptr,memberID,1,status);
+
+ /*
+ continue the loop over all member groups even if an error
+ was generated
+ */
+
+ if(*status == MEMBER_NOT_FOUND)
+ {
+ ffpmsg("cannot locate member's entry in group table (ffgmul)");
+ }
+ *status = 0;
+
+ /*
+ close the file pointed to by gfptr if it is non NULL to
+ prepare for the next loop iterration
+ */
+
+ if(gfptr != NULL)
+ {
+ fits_close_file(gfptr,status);
+ gfptr = NULL;
+ }
+ }
+
+ if(*status != 0) continue;
+
+ /*
+ if rmopt is non-zero then find and delete the GRPIDn/GRPLCn
+ keywords from the member HDU header
+ */
+
+ if(rmopt != 0)
+ {
+ fits_file_mode(mfptr,&iomode,status);
+
+ if(iomode == READONLY)
+ {
+ ffpmsg("Cannot modify member HDU, opened READONLY (ffgmul)");
+ continue;
+ }
+
+ /* delete all the GRPIDn/GRPLCn keywords */
+
+ for(index = 1; index <= ngroups && *status == 0; ++index)
+ {
+ sprintf(keyword,"GRPID%d",(int)index);
+ fits_delete_key(mfptr,keyword,status);
+
+ sprintf(keyword,"GRPLC%d",(int)index);
+ fits_delete_key(mfptr,keyword,status);
+
+ if(*status == KEY_NO_EXIST) *status = 0;
+ }
+ }
+ }while(0);
+
+ /* make sure the gfptr has been closed */
+
+ if(gfptr != NULL)
+ {
+ fits_close_file(gfptr,status);
+ }
+
+return(*status);
+}
+
+/*--------------------------------------------------------------------------*/
+int ffgmf(fitsfile *gfptr, /* pointer to grouping table HDU to search */
+ char *xtension, /* XTENSION value for member HDU */
+ char *extname, /* EXTNAME value for member HDU */
+ int extver, /* EXTVER value for member HDU */
+ int position, /* HDU position value for member HDU */
+ char *location, /* FITS file location value for member HDU */
+ long *member, /* member HDU ID within group table (if found) */
+ int *status) /* return status code */
+
+/*
+ try to find the entry for the member HDU defined by the xtension, extname,
+ extver, position, and location parameters within the grouping table
+ pointed to by gfptr. If the member HDU is found then its ID (row number)
+ within the grouping table is returned in the member variable; if not
+ found then member is returned with a value of 0 and the status return
+ code will be set to MEMBER_NOT_FOUND.
+
+ Note that the member HDU postion information is used to obtain a member
+ match only if the grouping table type is GT_ID_POS_URI or GT_ID_POS. This
+ is because the position information can become invalid much more
+ easily then the reference information for a group member.
+*/
+
+{
+ int xtensionCol,extnameCol,extverCol,positionCol,locationCol,uriCol;
+ int mposition = 0;
+ int grptype;
+ int dummy;
+ int i;
+
+ long nmembers = 0;
+ long mextver = 0;
+
+ char charBuff1[FLEN_FILENAME];
+ char charBuff2[FLEN_FILENAME];
+ char tmpLocation[FLEN_FILENAME];
+ char mbrLocation1[FLEN_FILENAME];
+ char mbrLocation2[FLEN_FILENAME];
+ char mbrLocation3[FLEN_FILENAME];
+ char grpLocation1[FLEN_FILENAME];
+ char grpLocation2[FLEN_FILENAME];
+ char cwd[FLEN_FILENAME];
+
+ char nstr[] = {'\0'};
+ char *tmpPtr[2];
+
+ if(*status != 0) return(*status);
+
+ *member = 0;
+
+ tmpPtr[0] = charBuff1;
+ tmpPtr[1] = charBuff2;
+
+
+ if(*status != 0) return(*status);
+
+ /*
+ if the passed LOCATION value is not an absolute URL then turn it
+ into an absolute path
+ */
+
+ if(location == NULL)
+ {
+ *tmpLocation = 0;
+ }
+
+ else if(*location == 0)
+ {
+ *tmpLocation = 0;
+ }
+
+ else if(!fits_is_url_absolute(location))
+ {
+ fits_path2url(location,tmpLocation,status);
+
+ if(*tmpLocation != '/')
+ {
+ fits_get_cwd(cwd,status);
+ strcat(cwd,"/");
+ strcat(cwd,tmpLocation);
+ fits_clean_url(cwd,tmpLocation,status);
+ }
+ }
+
+ else
+ strcpy(tmpLocation,location);
+
+ /*
+ retrieve the Grouping Convention reserved column positions within
+ the grouping table
+ */
+
+ *status = ffgtgc(gfptr,&xtensionCol,&extnameCol,&extverCol,&positionCol,
+ &locationCol,&uriCol,&grptype,status);
+
+ /* retrieve the number of group members */
+
+ *status = fits_get_num_members(gfptr,&nmembers,status);
+
+ /*
+ loop over all grouping table rows until the member HDU is found
+ */
+
+ for(i = 1; i <= nmembers && *member == 0 && *status == 0; ++i)
+ {
+ if(xtensionCol != 0)
+ {
+ fits_read_col_str(gfptr,xtensionCol,i,1,1,nstr,tmpPtr,&dummy,status);
+ if(strcasecmp(tmpPtr[0],xtension) != 0) continue;
+ }
+
+ if(extnameCol != 0)
+ {
+ fits_read_col_str(gfptr,extnameCol,i,1,1,nstr,tmpPtr,&dummy,status);
+ if(strcasecmp(tmpPtr[0],extname) != 0) continue;
+ }
+
+ if(extverCol != 0)
+ {
+ fits_read_col_lng(gfptr,extverCol,i,1,1,0,
+ (long*)&mextver,&dummy,status);
+ if(extver != mextver) continue;
+ }
+
+ /* note we only use postionCol if we have to */
+
+ if(positionCol != 0 &&
+ (grptype == GT_ID_POS || grptype == GT_ID_POS_URI))
+ {
+ fits_read_col_int(gfptr,positionCol,i,1,1,0,
+ &mposition,&dummy,status);
+ if(position != mposition) continue;
+ }
+
+ /*
+ if no location string was passed to the function then assume that
+ the calling application does not wish to use it as a comparision
+ critera ==> if we got this far then we have a match
+ */
+
+ if(location == NULL)
+ {
+ ffpmsg("NULL Location string given ==> ingore location (ffgmf)");
+ *member = i;
+ continue;
+ }
+
+ /*
+ if the grouping table MEMBER_LOCATION column exists then read the
+ location URL for the member, else set the location string to
+ a zero-length string for subsequent comparisions
+ */
+
+ if(locationCol != 0)
+ {
+ fits_read_col_str(gfptr,locationCol,i,1,1,nstr,tmpPtr,&dummy,status);
+ strcpy(mbrLocation1,tmpPtr[0]);
+ *mbrLocation2 = 0;
+ }
+ else
+ *mbrLocation1 = 0;
+
+ /*
+ if the member location string from the grouping table is zero
+ length (either implicitly or explicitly) then assume that the
+ member HDU is in the same file as the grouping table HDU; retrieve
+ the possible URL values of the grouping table HDU file
+ */
+
+ if(*mbrLocation1 == 0)
+ {
+ /* retrieve the possible URLs of the grouping table file */
+ *status = fits_get_url(gfptr,mbrLocation1,mbrLocation2,NULL,NULL,
+ NULL,status);
+
+ /* if non-NULL, make sure the first URL is absolute or a full path */
+ if(*mbrLocation1 != 0 && !fits_is_url_absolute(mbrLocation1) &&
+ *mbrLocation1 != '/')
+ {
+ fits_get_cwd(cwd,status);
+ strcat(cwd,"/");
+ strcat(cwd,mbrLocation1);
+ fits_clean_url(cwd,mbrLocation1,status);
+ }
+
+ /* if non-NULL, make sure the first URL is absolute or a full path */
+ if(*mbrLocation2 != 0 && !fits_is_url_absolute(mbrLocation2) &&
+ *mbrLocation2 != '/')
+ {
+ fits_get_cwd(cwd,status);
+ strcat(cwd,"/");
+ strcat(cwd,mbrLocation2);
+ fits_clean_url(cwd,mbrLocation2,status);
+ }
+ }
+
+ /*
+ if the member location was specified, then make sure that it is
+ either an absolute URL or specifies a full path
+ */
+
+ else if(!fits_is_url_absolute(mbrLocation1) && *mbrLocation1 != '/')
+ {
+ strcpy(mbrLocation2,mbrLocation1);
+
+ /* get the possible URLs for the grouping table file */
+ *status = fits_get_url(gfptr,grpLocation1,grpLocation2,NULL,NULL,
+ NULL,status);
+
+ if(*grpLocation1 != 0)
+ {
+ /* make sure the first grouping table URL is absolute */
+ if(!fits_is_url_absolute(grpLocation1) && *grpLocation1 != '/')
+ {
+ fits_get_cwd(cwd,status);
+ strcat(cwd,"/");
+ strcat(cwd,grpLocation1);
+ fits_clean_url(cwd,grpLocation1,status);
+ }
+
+ /* create an absoute URL for the member */
+
+ fits_relurl2url(grpLocation1,mbrLocation1,mbrLocation3,status);
+
+ /*
+ if URL construction succeeded then copy it to the
+ first location string; else set the location string to
+ empty
+ */
+
+ if(*status == 0)
+ {
+ strcpy(mbrLocation1,mbrLocation3);
+ }
+
+ else if(*status == URL_PARSE_ERROR)
+ {
+ *status = 0;
+ *mbrLocation1 = 0;
+ }
+ }
+ else
+ *mbrLocation1 = 0;
+
+ if(*grpLocation2 != 0)
+ {
+ /* make sure the second grouping table URL is absolute */
+ if(!fits_is_url_absolute(grpLocation2) && *grpLocation2 != '/')
+ {
+ fits_get_cwd(cwd,status);
+ strcat(cwd,"/");
+ strcat(cwd,grpLocation2);
+ fits_clean_url(cwd,grpLocation2,status);
+ }
+
+ /* create an absolute URL for the member */
+
+ fits_relurl2url(grpLocation2,mbrLocation2,mbrLocation3,status);
+
+ /*
+ if URL construction succeeded then copy it to the
+ second location string; else set the location string to
+ empty
+ */
+
+ if(*status == 0)
+ {
+ strcpy(mbrLocation2,mbrLocation3);
+ }
+
+ else if(*status == URL_PARSE_ERROR)
+ {
+ *status = 0;
+ *mbrLocation2 = 0;
+ }
+ }
+ else
+ *mbrLocation2 = 0;
+ }
+
+ /*
+ compare the passed member HDU file location string with the
+ (possibly two) member location strings to see if there is a match
+ */
+
+ if(strcmp(mbrLocation1,tmpLocation) != 0 &&
+ strcmp(mbrLocation2,tmpLocation) != 0 ) continue;
+
+ /* if we made it this far then a match to the member HDU was found */
+
+ *member = i;
+ }
+
+ /* if a match was not found then set the return status code */
+
+ if(*member == 0 && *status == 0)
+ {
+ *status = MEMBER_NOT_FOUND;
+ ffpmsg("Cannot find specified member HDU (ffgmf)");
+ }
+
+ return(*status);
+}
+
+/*--------------------------------------------------------------------------
+ Recursive Group Functions
+ --------------------------------------------------------------------------*/
+int ffgtrmr(fitsfile *gfptr, /* FITS file pointer to group */
+ HDUtracker *HDU, /* list of processed HDUs */
+ int *status) /* return status code */
+
+/*
+ recursively remove a grouping table and all its members. Each member of
+ the grouping table pointed to by gfptr it processed. If the member is itself
+ a grouping table then ffgtrmr() is recursively called to process all
+ of its members. The HDUtracker struct *HDU is used to make sure a member
+ is not processed twice, thus avoiding an infinite loop (e.g., a grouping
+ table contains itself as a member).
+*/
+
+{
+ int i;
+ int hdutype;
+
+ long nmembers = 0;
+
+ char keyvalue[FLEN_VALUE];
+ char comment[FLEN_COMMENT];
+
+ fitsfile *mfptr = NULL;
+
+
+ if(*status != 0) return(*status);
+
+ /* get the number of members contained by this grouping table */
+
+ *status = fits_get_num_members(gfptr,&nmembers,status);
+
+ /* loop over all group members and delete them */
+
+ for(i = nmembers; i > 0 && *status == 0; --i)
+ {
+ /* open the member HDU */
+
+ *status = fits_open_member(gfptr,i,&mfptr,status);
+
+ /* if the member cannot be opened then just skip it and continue */
+
+ if(*status == MEMBER_NOT_FOUND)
+ {
+ *status = 0;
+ continue;
+ }
+
+ /* Any other error is a reason to abort */
+
+ if(*status != 0) continue;
+
+ /* add the member HDU to the HDUtracker struct */
+
+ *status = fftsad(mfptr,HDU,NULL,NULL);
+
+ /* status == HDU_ALREADY_TRACKED ==> HDU has already been processed */
+
+ if(*status == HDU_ALREADY_TRACKED)
+ {
+ *status = 0;
+ fits_close_file(mfptr,status);
+ continue;
+ }
+ else if(*status != 0) continue;
+
+ /* determine if the member HDU is itself a grouping table */
+
+ *status = fits_read_key_str(mfptr,"EXTNAME",keyvalue,comment,status);
+
+ /* if no EXTNAME is found then the HDU cannot be a grouping table */
+
+ if(*status == KEY_NO_EXIST)
+ {
+ *status = 0;
+ keyvalue[0] = 0;
+ }
+ prepare_keyvalue(keyvalue);
+
+ /* Any other error is a reason to abort */
+
+ if(*status != 0) continue;
+
+ /*
+ if the EXTNAME == GROUPING then the member is a grouping table
+ and we must call ffgtrmr() to process its members
+ */
+
+ if(strcasecmp(keyvalue,"GROUPING") == 0)
+ *status = ffgtrmr(mfptr,HDU,status);
+
+ /*
+ unlink all the grouping tables that contain this HDU as a member
+ and then delete the HDU (if not a PHDU)
+ */
+
+ if(fits_get_hdu_num(mfptr,&hdutype) == 1)
+ *status = ffgmul(mfptr,1,status);
+ else
+ {
+ *status = ffgmul(mfptr,0,status);
+ *status = fits_delete_hdu(mfptr,&hdutype,status);
+ }
+
+ /* close the fitsfile pointer */
+
+ fits_close_file(mfptr,status);
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgtcpr(fitsfile *infptr, /* input FITS file pointer */
+ fitsfile *outfptr, /* output FITS file pointer */
+ int cpopt, /* code specifying copy options:
+ OPT_GCP_GPT (0) ==> cp only grouping table
+ OPT_GCP_ALL (2) ==> recusrively copy
+ members and their members (if groups) */
+ HDUtracker *HDU, /* list of already copied HDUs */
+ int *status) /* return status code */
+
+/*
+ copy a Group to a new FITS file. If the cpopt parameter is set to
+ OPT_GCP_GPT (copy grouping table only) then the existing members have their
+ GRPIDn and GRPLCn keywords updated to reflect the existance of the new group,
+ since they now belong to another group. If cpopt is set to OPT_GCP_ALL
+ (copy grouping table and members recursively) then the original members are
+ not updated; the new grouping table is modified to include only the copied
+ member HDUs and not the original members.
+
+ Note that this function is recursive. When copt is OPT_GCP_ALL it will call
+ itself whenever a member HDU of the current grouping table is itself a
+ grouping table (i.e., EXTNAME = 'GROUPING').
+*/
+
+{
+
+ int i;
+ int nexclude = 8;
+ int hdutype = 0;
+ int groupHDUnum = 0;
+ int numkeys = 0;
+ int keypos = 0;
+ int startSearch = 0;
+ int newPosition = 0;
+
+ long nmembers = 0;
+ long tfields = 0;
+ long newTfields = 0;
+
+ char keyword[FLEN_KEYWORD];
+ char keyvalue[FLEN_VALUE];
+ char card[FLEN_CARD];
+ char comment[FLEN_CARD];
+ char *tkeyvalue;
+
+ char *includeList[] = {"*"};
+ char *excludeList[] = {"EXTNAME","EXTVER","GRPNAME","GRPID#","GRPLC#",
+ "THEAP","TDIM#","T????#"};
+
+ fitsfile *mfptr = NULL;
+
+
+ if(*status != 0) return(*status);
+
+ do
+ {
+ /*
+ create a new grouping table in the FITS file pointed to by outptr
+ */
+
+ *status = fits_get_num_members(infptr,&nmembers,status);
+
+ *status = fits_read_key_str(infptr,"GRPNAME",keyvalue,card,status);
+
+ if(*status == KEY_NO_EXIST)
+ {
+ keyvalue[0] = 0;
+ *status = 0;
+ }
+ prepare_keyvalue(keyvalue);
+
+ *status = fits_create_group(outfptr,keyvalue,GT_ID_ALL_URI,status);
+
+ /* save the new grouping table's HDU position for future use */
+
+ fits_get_hdu_num(outfptr,&groupHDUnum);
+
+ /* update the HDUtracker struct with the grouping table's new position */
+
+ *status = fftsud(infptr,HDU,groupHDUnum,NULL);
+
+ /*
+ Now populate the copied grouping table depending upon the
+ copy option parameter value
+ */
+
+ switch(cpopt)
+ {
+
+ /*
+ for the "copy grouping table only" option we only have to
+ add the members of the original grouping table to the new
+ grouping table
+ */
+
+ case OPT_GCP_GPT:
+
+ for(i = 1; i <= nmembers && *status == 0; ++i)
+ {
+ *status = fits_open_member(infptr,i,&mfptr,status);
+ *status = fits_add_group_member(outfptr,mfptr,0,status);
+
+ fits_close_file(mfptr,status);
+ mfptr = NULL;
+ }
+
+ break;
+
+ case OPT_GCP_ALL:
+
+ /*
+ for the "copy the entire group" option
+ */
+
+ /* loop over all the grouping table members */
+
+ for(i = 1; i <= nmembers && *status == 0; ++i)
+ {
+ /* open the ith member */
+
+ *status = fits_open_member(infptr,i,&mfptr,status);
+
+ if(*status != 0) continue;
+
+ /* add it to the HDUtracker struct */
+
+ *status = fftsad(mfptr,HDU,&newPosition,NULL);
+
+ /* if already copied then just add the member to the group */
+
+ if(*status == HDU_ALREADY_TRACKED)
+ {
+ *status = 0;
+ *status = fits_add_group_member(outfptr,NULL,newPosition,
+ status);
+ fits_close_file(mfptr,status);
+ mfptr = NULL;
+ continue;
+ }
+ else if(*status != 0) continue;
+
+ /* see if the member is a grouping table */
+
+ *status = fits_read_key_str(mfptr,"EXTNAME",keyvalue,card,
+ status);
+
+ if(*status == KEY_NO_EXIST)
+ {
+ keyvalue[0] = 0;
+ *status = 0;
+ }
+ prepare_keyvalue(keyvalue);
+
+ /*
+ if the member is a grouping table then copy it and all of
+ its members using ffgtcpr(), else copy it using
+ fits_copy_member(); the outptr will point to the newly
+ copied member upon return from both functions
+ */
+
+ if(strcasecmp(keyvalue,"GROUPING") == 0)
+ *status = ffgtcpr(mfptr,outfptr,OPT_GCP_ALL,HDU,status);
+ else
+ *status = fits_copy_member(infptr,outfptr,i,OPT_MCP_NADD,
+ status);
+
+ /* retrieve the position of the newly copied member */
+
+ fits_get_hdu_num(outfptr,&newPosition);
+
+ /* update the HDUtracker struct with member's new position */
+
+ if(strcasecmp(keyvalue,"GROUPING") != 0)
+ *status = fftsud(mfptr,HDU,newPosition,NULL);
+
+ /* move the outfptr back to the copied grouping table HDU */
+
+ *status = fits_movabs_hdu(outfptr,groupHDUnum,&hdutype,status);
+
+ /* add the copied member HDU to the copied grouping table */
+
+ *status = fits_add_group_member(outfptr,NULL,newPosition,status);
+
+ /* close the mfptr pointer */
+
+ fits_close_file(mfptr,status);
+ mfptr = NULL;
+ }
+
+ break;
+
+ default:
+
+ *status = BAD_OPTION;
+ ffpmsg("Invalid value specified for cmopt parameter (ffgtcpr)");
+ break;
+ }
+
+ if(*status != 0) continue;
+
+ /*
+ reposition the outfptr to the grouping table so that the grouping
+ table is the CHDU upon return to the calling function
+ */
+
+ fits_movabs_hdu(outfptr,groupHDUnum,&hdutype,status);
+
+ /*
+ copy all auxiliary keyword records from the original grouping table
+ to the new grouping table; they are copied in their original order
+ and inserted just before the TTYPE1 keyword record
+ */
+
+ *status = fits_read_card(outfptr,"TTYPE1",card,status);
+ *status = fits_get_hdrpos(outfptr,&numkeys,&keypos,status);
+ --keypos;
+
+ startSearch = 8;
+
+ while(*status == 0)
+ {
+ ffgrec(infptr,startSearch,card,status);
+
+ *status = fits_find_nextkey(infptr,includeList,1,excludeList,
+ nexclude,card,status);
+
+ *status = fits_get_hdrpos(infptr,&numkeys,&startSearch,status);
+
+ --startSearch;
+ /* SPR 1738 */
+ if (strncmp(card,"GRPLC",5)) {
+ /* Not going to be a long string so we're ok */
+ *status = fits_insert_record(outfptr,keypos,card,status);
+ } else {
+ /* We could have a long string */
+ *status = fits_read_record(infptr,startSearch,card,status);
+ card[9] = '\0';
+ *status = fits_read_key_longstr(infptr,card,&tkeyvalue,comment,
+ status);
+ if (0 == *status) {
+ fits_insert_key_longstr(outfptr,card,tkeyvalue,comment,status);
+ fits_write_key_longwarn(outfptr,status);
+ free(tkeyvalue);
+ }
+ }
+
+ ++keypos;
+ }
+
+
+ if(*status == KEY_NO_EXIST)
+ *status = 0;
+ else if(*status != 0) continue;
+
+ /*
+ search all the columns of the original grouping table and copy
+ those to the new grouping table that were not part of the grouping
+ convention. Note that is legal to have additional columns in a
+ grouping table. Also note that the order of the columns may
+ not be the same in the original and copied grouping table.
+ */
+
+ /* retrieve the number of columns in the original and new group tables */
+
+ *status = fits_read_key_lng(infptr,"TFIELDS",&tfields,card,status);
+ *status = fits_read_key_lng(outfptr,"TFIELDS",&newTfields,card,status);
+
+ for(i = 1; i <= tfields; ++i)
+ {
+ sprintf(keyword,"TTYPE%d",i);
+ *status = fits_read_key_str(infptr,keyword,keyvalue,card,status);
+
+ if(*status == KEY_NO_EXIST)
+ {
+ *status = 0;
+ keyvalue[0] = 0;
+ }
+ prepare_keyvalue(keyvalue);
+
+ if(strcasecmp(keyvalue,"MEMBER_XTENSION") != 0 &&
+ strcasecmp(keyvalue,"MEMBER_NAME") != 0 &&
+ strcasecmp(keyvalue,"MEMBER_VERSION") != 0 &&
+ strcasecmp(keyvalue,"MEMBER_POSITION") != 0 &&
+ strcasecmp(keyvalue,"MEMBER_LOCATION") != 0 &&
+ strcasecmp(keyvalue,"MEMBER_URI_TYPE") != 0 )
+ {
+ *status = fits_copy_col(infptr,outfptr,i,newTfields,1,status);
+ ++newTfields;
+ }
+ }
+
+ }while(0);
+
+ if(mfptr != NULL)
+ {
+ fits_close_file(mfptr,status);
+ }
+
+ return(*status);
+}
+
+/*--------------------------------------------------------------------------
+ HDUtracker struct manipulation functions
+ --------------------------------------------------------------------------*/
+int fftsad(fitsfile *mfptr, /* pointer to an member HDU */
+ HDUtracker *HDU, /* pointer to an HDU tracker struct */
+ int *newPosition, /* new HDU position of the member HDU */
+ char *newFileName) /* file containing member HDU */
+
+/*
+ add an HDU to the HDUtracker struct pointed to by HDU. The HDU is only
+ added if it does not already reside in the HDUtracker. If it already
+ resides in the HDUtracker then the new HDU postion and file name are
+ returned in newPosition and newFileName (if != NULL)
+*/
+
+{
+ int i;
+ int hdunum;
+ int status = 0;
+
+ char filename1[FLEN_FILENAME];
+ char filename2[FLEN_FILENAME];
+
+ do
+ {
+ /* retrieve the HDU's position within the FITS file */
+
+ fits_get_hdu_num(mfptr,&hdunum);
+
+ /* retrieve the HDU's file name */
+
+ status = fits_file_name(mfptr,filename1,&status);
+
+ /* parse the file name and construct the "standard" URL for it */
+
+ status = ffrtnm(filename1,filename2,&status);
+
+ /*
+ examine all the existing HDUs in the HDUtracker an see if this HDU
+ has already been registered
+ */
+
+ for(i = 0;
+ i < HDU->nHDU && !(HDU->position[i] == hdunum
+ && strcmp(HDU->filename[i],filename2) == 0);
+ ++i);
+
+ if(i != HDU->nHDU)
+ {
+ status = HDU_ALREADY_TRACKED;
+ if(newPosition != NULL) *newPosition = HDU->newPosition[i];
+ if(newFileName != NULL) strcpy(newFileName,HDU->newFilename[i]);
+ continue;
+ }
+
+ if(HDU->nHDU == MAX_HDU_TRACKER)
+ {
+ status = TOO_MANY_HDUS_TRACKED;
+ continue;
+ }
+
+ HDU->filename[i] = (char*) malloc(FLEN_FILENAME * sizeof(char));
+
+ if(HDU->filename[i] == NULL)
+ {
+ status = MEMORY_ALLOCATION;
+ continue;
+ }
+
+ HDU->newFilename[i] = (char*) malloc(FLEN_FILENAME * sizeof(char));
+
+ if(HDU->newFilename[i] == NULL)
+ {
+ status = MEMORY_ALLOCATION;
+ free(HDU->filename[i]);
+ continue;
+ }
+
+ HDU->position[i] = hdunum;
+ HDU->newPosition[i] = hdunum;
+
+ strcpy(HDU->filename[i],filename2);
+ strcpy(HDU->newFilename[i],filename2);
+
+ ++(HDU->nHDU);
+
+ }while(0);
+
+ return(status);
+}
+/*--------------------------------------------------------------------------*/
+int fftsud(fitsfile *mfptr, /* pointer to an member HDU */
+ HDUtracker *HDU, /* pointer to an HDU tracker struct */
+ int newPosition, /* new HDU position of the member HDU */
+ char *newFileName) /* file containing member HDU */
+
+/*
+ update the HDU information in the HDUtracker struct pointed to by HDU. The
+ HDU to update is pointed to by mfptr. If non-zero, the value of newPosition
+ is used to update the HDU->newPosition[] value for the mfptr, and if
+ non-NULL the newFileName value is used to update the HDU->newFilename[]
+ value for mfptr.
+*/
+
+{
+ int i;
+ int hdunum;
+ int status = 0;
+
+ char filename1[FLEN_FILENAME];
+ char filename2[FLEN_FILENAME];
+
+
+ /* retrieve the HDU's position within the FITS file */
+
+ fits_get_hdu_num(mfptr,&hdunum);
+
+ /* retrieve the HDU's file name */
+
+ status = fits_file_name(mfptr,filename1,&status);
+
+ /* parse the file name and construct the "standard" URL for it */
+
+ status = ffrtnm(filename1,filename2,&status);
+
+ /*
+ examine all the existing HDUs in the HDUtracker an see if this HDU
+ has already been registered
+ */
+
+ for(i = 0; i < HDU->nHDU &&
+ !(HDU->position[i] == hdunum && strcmp(HDU->filename[i],filename2) == 0);
+ ++i);
+
+ /* if previously registered then change newPosition and newFileName */
+
+ if(i != HDU->nHDU)
+ {
+ if(newPosition != 0) HDU->newPosition[i] = newPosition;
+ if(newFileName != NULL)
+ {
+ strcpy(HDU->newFilename[i],newFileName);
+ }
+ }
+ else
+ status = MEMBER_NOT_FOUND;
+
+ return(status);
+}
+
+/*---------------------------------------------------------------------------*/
+
+void prepare_keyvalue(char *keyvalue) /* string containing keyword value */
+
+/*
+ strip off all single quote characters "'" and blank spaces from a keyword
+ value retrieved via fits_read_key*() routines
+
+ this is necessary so that a standard comparision of keyword values may
+ be made
+*/
+
+{
+
+ int i;
+ int length;
+
+ /*
+ strip off any leading or trailing single quotes (`) and (') from
+ the keyword value
+ */
+
+ length = strlen(keyvalue) - 1;
+
+ if(keyvalue[0] == '\'' && keyvalue[length] == '\'')
+ {
+ for(i = 0; i < length - 1; ++i) keyvalue[i] = keyvalue[i+1];
+ keyvalue[length-1] = 0;
+ }
+
+ /*
+ strip off any trailing blanks from the keyword value; note that if the
+ keyvalue consists of nothing but blanks then no blanks are stripped
+ */
+
+ length = strlen(keyvalue) - 1;
+
+ for(i = 0; i < length && keyvalue[i] == ' '; ++i);
+
+ if(i != length)
+ {
+ for(i = length; i >= 0 && keyvalue[i] == ' '; --i) keyvalue[i] = '\0';
+ }
+}
+
+/*---------------------------------------------------------------------------
+ Host dependent directory path to/from URL functions
+ --------------------------------------------------------------------------*/
+int fits_path2url(char *inpath, /* input file path string */
+ char *outpath, /* output file path string */
+ int *status)
+ /*
+ convert a file path into its Unix-style equivelent for URL
+ purposes. Note that this process is platform dependent. This
+ function supports Unix, MSDOS/WIN32, VMS and Macintosh platforms.
+ The plaform dependant code is conditionally compiled depending upon
+ the setting of the appropriate C preprocessor macros.
+ */
+{
+ char buff[FLEN_FILENAME];
+
+#if defined(WINNT) || defined(__WINNT__)
+
+ /*
+ Microsoft Windows NT case. We assume input file paths of the form:
+
+ //disk/path/filename
+
+ All path segments may be null, so that a single file name is the
+ simplist case.
+
+ The leading "//" becomes a single "/" if present. If no "//" is present,
+ then make sure the resulting URL path is relative, i.e., does not
+ begin with a "/". In other words, the only way that an absolute URL
+ file path may be generated is if the drive specification is given.
+ */
+
+ if(*status > 0) return(*status);
+
+ if(inpath[0] == '/')
+ {
+ strcpy(buff,inpath+1);
+ }
+ else
+ {
+ strcpy(buff,inpath);
+ }
+
+#elif defined(MSDOS) || defined(__WIN32__) || defined(WIN32)
+
+ /*
+ MSDOS or Microsoft windows/NT case. The assumed form of the
+ input path is:
+
+ disk:\path\filename
+
+ All path segments may be null, so that a single file name is the
+ simplist case.
+
+ All back-slashes '\' become slashes '/'; if the path starts with a
+ string of the form "X:" then it is replaced with "/X/"
+ */
+
+ int i,j,k;
+ int size;
+ if(*status > 0) return(*status);
+
+ for(i = 0, j = 0, size = strlen(inpath), buff[0] = 0;
+ i < size; j = strlen(buff))
+ {
+ switch(inpath[i])
+ {
+
+ case ':':
+
+ /*
+ must be a disk desiginator; add a slash '/' at the start of
+ outpath to designate that the path is absolute, then change
+ the colon ':' to a slash '/'
+ */
+
+ for(k = j; k >= 0; --k) buff[k+1] = buff[k];
+ buff[0] = '/';
+ strcat(buff,"/");
+ ++i;
+
+ break;
+
+ case '\\':
+
+ /* just replace the '\' with a '/' IF its not the first character */
+
+ if(i != 0 && buff[(j == 0 ? 0 : j-1)] != '/')
+ {
+ buff[j] = '/';
+ buff[j+1] = 0;
+ }
+
+ ++i;
+
+ break;
+
+ default:
+
+ /* copy the character from inpath to buff as is */
+
+ buff[j] = inpath[i];
+ buff[j+1] = 0;
+ ++i;
+
+ break;
+ }
+ }
+
+#elif defined(VMS) || defined(vms) || defined(__vms)
+
+ /*
+ VMS case. Assumed format of the input path is:
+
+ node::disk:[path]filename.ext;version
+
+ Any part of the file path may be missing, so that in the simplist
+ case a single file name/extension is given.
+
+ all brackets "[", "]" and dots "." become "/"; dashes "-" become "..",
+ all single colons ":" become ":/", all double colons "::" become
+ "FILE://"
+ */
+
+ int i,j,k;
+ int done;
+ int size;
+
+ if(*status > 0) return(*status);
+
+ /* see if inpath contains a directory specification */
+
+ if(strchr(inpath,']') == NULL)
+ done = 1;
+ else
+ done = 0;
+
+ for(i = 0, j = 0, size = strlen(inpath), buff[0] = 0;
+ i < size && j < FLEN_FILENAME - 8; j = strlen(buff))
+ {
+ switch(inpath[i])
+ {
+
+ case ':':
+
+ /*
+ must be a logical/symbol separator or (in the case of a double
+ colon "::") machine node separator
+ */
+
+ if(inpath[i+1] == ':')
+ {
+ /* insert a "FILE://" at the start of buff ==> machine given */
+
+ for(k = j; k >= 0; --k) buff[k+7] = buff[k];
+ strncpy(buff,"FILE://",7);
+ i += 2;
+ }
+ else if(strstr(buff,"FILE://") == NULL)
+ {
+ /* insert a "/" at the start of buff ==> absolute path */
+
+ for(k = j; k >= 0; --k) buff[k+1] = buff[k];
+ buff[0] = '/';
+ ++i;
+ }
+ else
+ ++i;
+
+ /* a colon always ==> path separator */
+
+ strcat(buff,"/");
+
+ break;
+
+ case ']':
+
+ /* end of directory spec, file name spec begins after this */
+
+ done = 1;
+
+ buff[j] = '/';
+ buff[j+1] = 0;
+ ++i;
+
+ break;
+
+ case '[':
+
+ /*
+ begin directory specification; add a '/' only if the last char
+ is not '/'
+ */
+
+ if(i != 0 && buff[(j == 0 ? 0 : j-1)] != '/')
+ {
+ buff[j] = '/';
+ buff[j+1] = 0;
+ }
+
+ ++i;
+
+ break;
+
+ case '.':
+
+ /*
+ directory segment separator or file name/extension separator;
+ we decide which by looking at the value of done
+ */
+
+ if(!done)
+ {
+ /* must be a directory segment separator */
+ if(inpath[i-1] == '[')
+ {
+ strcat(buff,"./");
+ ++j;
+ }
+ else
+ buff[j] = '/';
+ }
+ else
+ /* must be a filename/extension separator */
+ buff[j] = '.';
+
+ buff[j+1] = 0;
+
+ ++i;
+
+ break;
+
+ case '-':
+
+ /*
+ a dash is the same as ".." in Unix speak, but lets make sure
+ that its not part of the file name first!
+ */
+
+ if(!done)
+ /* must be part of the directory path specification */
+ strcat(buff,"..");
+ else
+ {
+ /* the dash is part of the filename, so just copy it as is */
+ buff[j] = '-';
+ buff[j+1] = 0;
+ }
+
+ ++i;
+
+ break;
+
+ default:
+
+ /* nothing special, just copy the character as is */
+
+ buff[j] = inpath[i];
+ buff[j+1] = 0;
+
+ ++i;
+
+ break;
+
+ }
+ }
+
+ if(j > FLEN_FILENAME - 8)
+ {
+ *status = URL_PARSE_ERROR;
+ ffpmsg("resulting path to URL conversion too big (fits_path2url)");
+ }
+
+#elif defined(macintosh)
+
+ /*
+ MacOS case. The assumed form of the input path is:
+
+ disk:path:filename
+
+ It is assumed that all paths are absolute with disk and path specified,
+ unless no colons ":" are supplied with the string ==> a single file name
+ only. All colons ":" become slashes "/", and if one or more colon is
+ encountered then the path is specified as absolute.
+ */
+
+ int i,j,k;
+ int firstColon;
+ int size;
+
+ if(*status > 0) return(*status);
+
+ for(i = 0, j = 0, firstColon = 1, size = strlen(inpath), buff[0] = 0;
+ i < size; j = strlen(buff))
+ {
+ switch(inpath[i])
+ {
+
+ case ':':
+
+ /*
+ colons imply path separators. If its the first colon encountered
+ then assume that its the disk designator and add a slash to the
+ beginning of the buff string
+ */
+
+ if(firstColon)
+ {
+ firstColon = 0;
+
+ for(k = j; k >= 0; --k) buff[k+1] = buff[k];
+ buff[0] = '/';
+ }
+
+ /* all colons become slashes */
+
+ strcat(buff,"/");
+
+ ++i;
+
+ break;
+
+ default:
+
+ /* copy the character from inpath to buff as is */
+
+ buff[j] = inpath[i];
+ buff[j+1] = 0;
+
+ ++i;
+
+ break;
+ }
+ }
+
+#else
+
+ /*
+ Default Unix case.
+
+ Nothing special to do here except to remove the double or more // and
+ replace them with single /
+ */
+
+ int ii = 0;
+ int jj = 0;
+
+ if(*status > 0) return(*status);
+
+ while (inpath[ii]) {
+ if (inpath[ii] == '/' && inpath[ii+1] == '/') {
+ /* do nothing */
+ } else {
+ buff[jj] = inpath[ii];
+ jj++;
+ }
+ ii++;
+ }
+ buff[jj] = '\0';
+ /* printf("buff is %s\ninpath is %s\n",buff,inpath); */
+ /* strcpy(buff,inpath); */
+
+#endif
+
+ /*
+ encode all "unsafe" and "reserved" URL characters
+ */
+
+ *status = fits_encode_url(buff,outpath,status);
+
+ return(*status);
+}
+
+/*---------------------------------------------------------------------------*/
+int fits_url2path(char *inpath, /* input file path string */
+ char *outpath, /* output file path string */
+ int *status)
+ /*
+ convert a Unix-style URL into a platform dependent directory path.
+ Note that this process is platform dependent. This
+ function supports Unix, MSDOS/WIN32, VMS and Macintosh platforms. Each
+ platform dependent code segment is conditionally compiled depending
+ upon the setting of the appropriate C preprocesser macros.
+ */
+{
+ char buff[FLEN_FILENAME];
+ int absolute;
+
+#if defined(MSDOS) || defined(__WIN32__) || defined(WIN32)
+ char *tmpStr;
+#elif defined(VMS) || defined(vms) || defined(__vms)
+ int i;
+ char *tmpStr;
+#elif defined(macintosh)
+ char *tmpStr;
+#endif
+
+ if(*status != 0) return(*status);
+
+ /*
+ make a copy of the inpath so that we can manipulate it
+ */
+
+ strcpy(buff,inpath);
+
+ /*
+ convert any encoded characters to their unencoded values
+ */
+
+ *status = fits_unencode_url(inpath,buff,status);
+
+ /*
+ see if the URL is given as absolute w.r.t. the "local" file system
+ */
+
+ if(buff[0] == '/')
+ absolute = 1;
+ else
+ absolute = 0;
+
+#if defined(WINNT) || defined(__WINNT__)
+
+ /*
+ Microsoft Windows NT case. We create output paths of the form
+
+ //disk/path/filename
+
+ All path segments but the last may be null, so that a single file name
+ is the simplist case.
+ */
+
+ if(absolute)
+ {
+ strcpy(outpath,"/");
+ strcat(outpath,buff);
+ }
+ else
+ {
+ strcpy(outpath,buff);
+ }
+
+#elif defined(MSDOS) || defined(__WIN32__) || defined(WIN32)
+
+ /*
+ MSDOS or Microsoft windows/NT case. The output path will be of the
+ form
+
+ disk:\path\filename
+
+ All path segments but the last may be null, so that a single file name
+ is the simplist case.
+ */
+
+ /*
+ separate the URL into tokens at each slash '/' and process until
+ all tokens have been examined
+ */
+
+ for(tmpStr = strtok(buff,"/"), outpath[0] = 0;
+ tmpStr != NULL; tmpStr = strtok(NULL,"/"))
+ {
+ strcat(outpath,tmpStr);
+
+ /*
+ if the absolute flag is set then process the token as a disk
+ specification; else just process it as a directory path or filename
+ */
+
+ if(absolute)
+ {
+ strcat(outpath,":\\");
+ absolute = 0;
+ }
+ else
+ strcat(outpath,"\\");
+ }
+
+ /* remove the last "\" from the outpath, it does not belong there */
+
+ outpath[strlen(outpath)-1] = 0;
+
+#elif defined(VMS) || defined(vms) || defined(__vms)
+
+ /*
+ VMS case. The output path will be of the form:
+
+ node::disk:[path]filename.ext;version
+
+ Any part of the file path may be missing execpt filename.ext, so that in
+ the simplist case a single file name/extension is given.
+
+ if the path is specified as relative starting with "./" then the first
+ part of the VMS path is "[.". If the path is relative and does not start
+ with "./" (e.g., "a/b/c") then the VMS path is constructed as
+ "[a.b.c]"
+ */
+
+ /*
+ separate the URL into tokens at each slash '/' and process until
+ all tokens have been examined
+ */
+
+ for(tmpStr = strtok(buff,"/"), outpath[0] = 0;
+ tmpStr != NULL; tmpStr = strtok(NULL,"/"))
+ {
+
+ if(strcasecmp(tmpStr,"FILE:") == 0)
+ {
+ /* the next token should contain the DECnet machine name */
+
+ tmpStr = strtok(NULL,"/");
+ if(tmpStr == NULL) continue;
+
+ strcat(outpath,tmpStr);
+ strcat(outpath,"::");
+
+ /* set the absolute flag to true for the next token */
+ absolute = 1;
+ }
+
+ else if(strcmp(tmpStr,"..") == 0)
+ {
+ /* replace all Unix-like ".." with VMS "-" */
+
+ if(strlen(outpath) == 0) strcat(outpath,"[");
+ strcat(outpath,"-.");
+ }
+
+ else if(strcmp(tmpStr,".") == 0 && strlen(outpath) == 0)
+ {
+ /*
+ must indicate a relative path specifier
+ */
+
+ strcat(outpath,"[.");
+ }
+
+ else if(strchr(tmpStr,'.') != NULL)
+ {
+ /*
+ must be up to the file name; turn the last "." path separator
+ into a "]" and then add the file name to the outpath
+ */
+
+ i = strlen(outpath);
+ if(i > 0 && outpath[i-1] == '.') outpath[i-1] = ']';
+
+ strcat(outpath,tmpStr);
+ }
+
+ else
+ {
+ /*
+ process the token as a a directory path segement
+ */
+
+ if(absolute)
+ {
+ /* treat the token as a disk specifier */
+ absolute = 0;
+ strcat(outpath,tmpStr);
+ strcat(outpath,":[");
+ }
+ else if(strlen(outpath) == 0)
+ {
+ /* treat the token as the first directory path specifier */
+ strcat(outpath,"[");
+ strcat(outpath,tmpStr);
+ strcat(outpath,".");
+ }
+ else
+ {
+ /* treat the token as an imtermediate path specifier */
+ strcat(outpath,tmpStr);
+ strcat(outpath,".");
+ }
+ }
+ }
+
+#elif defined(macintosh)
+
+ /*
+ MacOS case. The output path will be of the form
+
+ disk:path:filename
+
+ All path segments but the last may be null, so that a single file name
+ is the simplist case.
+ */
+
+ /*
+ separate the URL into tokens at each slash '/' and process until
+ all tokens have been examined
+ */
+
+ for(tmpStr = strtok(buff,"/"), outpath[0] = 0;
+ tmpStr != NULL; tmpStr = strtok(NULL,"/"))
+ {
+ strcat(outpath,tmpStr);
+ strcat(outpath,":");
+ }
+
+ /* remove the last ":" from the outpath, it does not belong there */
+
+ outpath[strlen(outpath)-1] = 0;
+
+#else
+
+ /*
+ Default Unix case.
+
+ Nothing special to do here
+ */
+
+ strcpy(outpath,buff);
+
+#endif
+
+ return(*status);
+}
+
+/****************************************************************************/
+int fits_get_cwd(char *cwd, /* IO current working directory string */
+ int *status)
+ /*
+ retrieve the string containing the current working directory absolute
+ path in Unix-like URL standard notation. It is assumed that the CWD
+ string has a size of at least FLEN_FILENAME.
+
+ Note that this process is platform dependent. This
+ function supports Unix, MSDOS/WIN32, VMS and Macintosh platforms. Each
+ platform dependent code segment is conditionally compiled depending
+ upon the setting of the appropriate C preprocesser macros.
+ */
+{
+
+ char buff[FLEN_FILENAME];
+
+
+ if(*status != 0) return(*status);
+
+#if defined(macintosh)
+
+ /*
+ MacOS case. Currently unknown !!!!
+ */
+
+ *buff = 0;
+
+#else
+ /*
+ Good old getcwd() seems to work with all other platforms
+ */
+
+ getcwd(buff,FLEN_FILENAME);
+
+#endif
+
+ /*
+ convert the cwd string to a URL standard path string
+ */
+
+ fits_path2url(buff,cwd,status);
+
+ return(*status);
+}
+
+/*---------------------------------------------------------------------------*/
+int fits_get_url(fitsfile *fptr, /* I ptr to FITS file to evaluate */
+ char *realURL, /* O URL of real FITS file */
+ char *startURL, /* O URL of starting FITS file */
+ char *realAccess, /* O true access method of FITS file */
+ char *startAccess,/* O "official" access of FITS file */
+ int *iostate, /* O can this file be modified? */
+ int *status)
+/*
+ For grouping convention purposes, determine the URL of the FITS file
+ associated with the fitsfile pointer fptr. The true access type (file://,
+ mem://, shmem://, root://), starting "official" access type, and iostate
+ (0 ==> readonly, 1 ==> readwrite) are also returned.
+
+ It is assumed that the url string has enough room to hold the resulting
+ URL, and the the accessType string has enough room to hold the access type.
+*/
+{
+ int i;
+ int tmpIOstate = 0;
+
+ char infile[FLEN_FILENAME];
+ char outfile[FLEN_FILENAME];
+ char tmpStr1[FLEN_FILENAME];
+ char tmpStr2[FLEN_FILENAME];
+ char tmpStr3[FLEN_FILENAME];
+ char tmpStr4[FLEN_FILENAME];
+ char *tmpPtr;
+
+
+ if(*status != 0) return(*status);
+
+ do
+ {
+ /*
+ retrieve the member HDU's file name as opened by ffopen()
+ and parse it into its constitutent pieces; get the currently
+ active driver token too
+ */
+
+ *tmpStr1 = *tmpStr2 = *tmpStr3 = *tmpStr4 = 0;
+
+ *status = fits_file_name(fptr,tmpStr1,status);
+
+ *status = ffiurl(tmpStr1,NULL,infile,outfile,NULL,tmpStr2,tmpStr3,
+ tmpStr4,status);
+
+ if((*tmpStr2) || (*tmpStr3) || (*tmpStr4)) tmpIOstate = -1;
+
+ *status = ffurlt(fptr,tmpStr3,status);
+
+ strcpy(tmpStr4,tmpStr3);
+
+ *status = ffrtnm(tmpStr1,tmpStr2,status);
+ strcpy(tmpStr1,tmpStr2);
+
+ /*
+ for grouping convention purposes (only) determine the URL of the
+ actual FITS file being used for the given fptr, its true access
+ type (file://, mem://, shmem://, root://) and its iostate (0 ==>
+ read only, 1 ==> readwrite)
+ */
+
+ /*
+ The first set of access types are "simple" in that they do not
+ use any redirection to temporary memory or outfiles
+ */
+
+ /* standard disk file driver is in use */
+
+ if(strcasecmp(tmpStr3,"file://") == 0)
+ {
+ tmpIOstate = 1;
+
+ if(strlen(outfile)) strcpy(tmpStr1,outfile);
+ else *tmpStr2 = 0;
+
+ /*
+ make sure no FILE:// specifier is given in the tmpStr1
+ or tmpStr2 strings; the convention calls for local files
+ to have no access specification
+ */
+
+ if((tmpPtr = strstr(tmpStr1,"://")) != NULL)
+ {
+ strcpy(infile,tmpPtr+3);
+ strcpy(tmpStr1,infile);
+ }
+
+ if((tmpPtr = strstr(tmpStr2,"://")) != NULL)
+ {
+ strcpy(infile,tmpPtr+3);
+ strcpy(tmpStr2,infile);
+ }
+ }
+
+ /* file stored in conventional memory */
+
+ else if(strcasecmp(tmpStr3,"mem://") == 0)
+ {
+ if(tmpIOstate < 0)
+ {
+ /* file is a temp mem file only */
+ ffpmsg("cannot make URL from temp MEM:// file (fits_get_url)");
+ *status = URL_PARSE_ERROR;
+ }
+ else
+ {
+ /* file is a "perminate" mem file for this process */
+ tmpIOstate = 1;
+ *tmpStr2 = 0;
+ }
+ }
+
+ /* file stored in conventional memory */
+
+ else if(strcasecmp(tmpStr3,"memkeep://") == 0)
+ {
+ strcpy(tmpStr3,"mem://");
+ *tmpStr4 = 0;
+ *tmpStr2 = 0;
+ tmpIOstate = 1;
+ }
+
+ /* file residing in shared memory */
+
+ else if(strcasecmp(tmpStr3,"shmem://") == 0)
+ {
+ *tmpStr4 = 0;
+ *tmpStr2 = 0;
+ tmpIOstate = 1;
+ }
+
+ /* file accessed via the ROOT network protocol */
+
+ else if(strcasecmp(tmpStr3,"root://") == 0)
+ {
+ *tmpStr4 = 0;
+ *tmpStr2 = 0;
+ tmpIOstate = 1;
+ }
+
+ /*
+ the next set of access types redirect the contents of the original
+ file to an special outfile because the original could not be
+ directly modified (i.e., resides on the network, was compressed).
+ In these cases the URL string takes on the value of the OUTFILE,
+ the access type becomes file://, and the iostate is set to 1 (can
+ read/write to the file).
+ */
+
+ /* compressed file uncompressed and written to disk */
+
+ else if(strcasecmp(tmpStr3,"compressfile://") == 0)
+ {
+ strcpy(tmpStr1,outfile);
+ strcpy(tmpStr2,infile);
+ strcpy(tmpStr3,"file://");
+ strcpy(tmpStr4,"file://");
+ tmpIOstate = 1;
+ }
+
+ /* HTTP accessed file written locally to disk */
+
+ else if(strcasecmp(tmpStr3,"httpfile://") == 0)
+ {
+ strcpy(tmpStr1,outfile);
+ strcpy(tmpStr3,"file://");
+ strcpy(tmpStr4,"http://");
+ tmpIOstate = 1;
+ }
+
+ /* FTP accessd file written locally to disk */
+
+ else if(strcasecmp(tmpStr3,"ftpfile://") == 0)
+ {
+ strcpy(tmpStr1,outfile);
+ strcpy(tmpStr3,"file://");
+ strcpy(tmpStr4,"ftp://");
+ tmpIOstate = 1;
+ }
+
+ /* file from STDIN written to disk */
+
+ else if(strcasecmp(tmpStr3,"stdinfile://") == 0)
+ {
+ strcpy(tmpStr1,outfile);
+ strcpy(tmpStr3,"file://");
+ strcpy(tmpStr4,"stdin://");
+ tmpIOstate = 1;
+ }
+
+ /*
+ the following access types use memory resident files as temporary
+ storage; they cannot be modified or be made group members for
+ grouping conventions purposes, but their original files can be.
+ Thus, their tmpStr3s are reset to mem://, their iostate
+ values are set to 0 (for no-modification), and their URL string
+ values remain set to their original values
+ */
+
+ /* compressed disk file uncompressed into memory */
+
+ else if(strcasecmp(tmpStr3,"compress://") == 0)
+ {
+ *tmpStr1 = 0;
+ strcpy(tmpStr2,infile);
+ strcpy(tmpStr3,"mem://");
+ strcpy(tmpStr4,"file://");
+ tmpIOstate = 0;
+ }
+
+ /* HTTP accessed file transferred into memory */
+
+ else if(strcasecmp(tmpStr3,"http://") == 0)
+ {
+ *tmpStr1 = 0;
+ strcpy(tmpStr3,"mem://");
+ strcpy(tmpStr4,"http://");
+ tmpIOstate = 0;
+ }
+
+ /* HTTP accessed compressed file transferred into memory */
+
+ else if(strcasecmp(tmpStr3,"httpcompress://") == 0)
+ {
+ *tmpStr1 = 0;
+ strcpy(tmpStr3,"mem://");
+ strcpy(tmpStr4,"http://");
+ tmpIOstate = 0;
+ }
+
+ /* FTP accessed file transferred into memory */
+
+ else if(strcasecmp(tmpStr3,"ftp://") == 0)
+ {
+ *tmpStr1 = 0;
+ strcpy(tmpStr3,"mem://");
+ strcpy(tmpStr4,"ftp://");
+ tmpIOstate = 0;
+ }
+
+ /* FTP accessed compressed file transferred into memory */
+
+ else if(strcasecmp(tmpStr3,"ftpcompress://") == 0)
+ {
+ *tmpStr1 = 0;
+ strcpy(tmpStr3,"mem://");
+ strcpy(tmpStr4,"ftp://");
+ tmpIOstate = 0;
+ }
+
+ /*
+ The last set of access types cannot be used to make a meaningful URL
+ strings from; thus an error is generated
+ */
+
+ else if(strcasecmp(tmpStr3,"stdin://") == 0)
+ {
+ *status = URL_PARSE_ERROR;
+ ffpmsg("cannot make vaild URL from stdin:// (fits_get_url)");
+ *tmpStr1 = *tmpStr2 = 0;
+ }
+
+ else if(strcasecmp(tmpStr3,"stdout://") == 0)
+ {
+ *status = URL_PARSE_ERROR;
+ ffpmsg("cannot make vaild URL from stdout:// (fits_get_url)");
+ *tmpStr1 = *tmpStr2 = 0;
+ }
+
+ else if(strcasecmp(tmpStr3,"irafmem://") == 0)
+ {
+ *status = URL_PARSE_ERROR;
+ ffpmsg("cannot make vaild URL from irafmem:// (fits_get_url)");
+ *tmpStr1 = *tmpStr2 = 0;
+ }
+
+ if(*status != 0) continue;
+
+ /*
+ assign values to the calling parameters if they are non-NULL
+ */
+
+ if(realURL != NULL)
+ {
+ if(strlen(tmpStr1) == 0)
+ *realURL = 0;
+ else
+ {
+ if((tmpPtr = strstr(tmpStr1,"://")) != NULL)
+ {
+ tmpPtr += 3;
+ i = (long)tmpPtr - (long)tmpStr1;
+ strncpy(realURL,tmpStr1,i);
+ }
+ else
+ {
+ tmpPtr = tmpStr1;
+ i = 0;
+ }
+
+ *status = fits_path2url(tmpPtr,realURL+i,status);
+ }
+ }
+
+ if(startURL != NULL)
+ {
+ if(strlen(tmpStr2) == 0)
+ *startURL = 0;
+ else
+ {
+ if((tmpPtr = strstr(tmpStr2,"://")) != NULL)
+ {
+ tmpPtr += 3;
+ i = (long)tmpPtr - (long)tmpStr2;
+ strncpy(startURL,tmpStr2,i);
+ }
+ else
+ {
+ tmpPtr = tmpStr2;
+ i = 0;
+ }
+
+ *status = fits_path2url(tmpPtr,startURL+i,status);
+ }
+ }
+
+ if(realAccess != NULL) strcpy(realAccess,tmpStr3);
+ if(startAccess != NULL) strcpy(startAccess,tmpStr4);
+ if(iostate != NULL) *iostate = tmpIOstate;
+
+ }while(0);
+
+ return(*status);
+}
+
+/*--------------------------------------------------------------------------
+ URL parse support functions
+ --------------------------------------------------------------------------*/
+
+/* simple push/pop/shift/unshift string stack for use by fits_clean_url */
+typedef char* grp_stack_data; /* type of data held by grp_stack */
+
+typedef struct grp_stack_item_struct {
+ grp_stack_data data; /* value of this stack item */
+ struct grp_stack_item_struct* next; /* next stack item */
+ struct grp_stack_item_struct* prev; /* previous stack item */
+} grp_stack_item;
+
+typedef struct grp_stack_struct {
+ size_t stack_size; /* number of items on stack */
+ grp_stack_item* top; /* top item */
+} grp_stack;
+
+static char* grp_stack_default = NULL; /* initial value for new instances
+ of grp_stack_data */
+
+/* the following functions implement the group string stack grp_stack */
+static void delete_grp_stack(grp_stack** mystack);
+static grp_stack_item* grp_stack_append(
+ grp_stack_item* last, grp_stack_data data
+);
+static grp_stack_data grp_stack_remove(grp_stack_item* last);
+static grp_stack* new_grp_stack(void);
+static grp_stack_data pop_grp_stack(grp_stack* mystack);
+static void push_grp_stack(grp_stack* mystack, grp_stack_data data);
+static grp_stack_data shift_grp_stack(grp_stack* mystack);
+/* static void unshift_grp_stack(grp_stack* mystack, grp_stack_data data); */
+
+int fits_clean_url(char *inURL, /* I input URL string */
+ char *outURL, /* O output URL string */
+ int *status)
+/*
+ clean the URL by eliminating any ".." or "." specifiers in the inURL
+ string, and write the output to the outURL string.
+
+ Note that this function must have a valid Unix-style URL as input; platform
+ dependent path strings are not allowed.
+ */
+{
+ grp_stack* mystack; /* stack to hold pieces of URL */
+ char* tmp;
+
+ if(*status) return *status;
+
+ mystack = new_grp_stack();
+ *outURL = 0;
+
+ do {
+ /* handle URL scheme and domain if they exist */
+ tmp = strstr(inURL, "://");
+ if(tmp) {
+ /* there is a URL scheme, so look for the end of the domain too */
+ tmp = strchr(tmp + 3, '/');
+ if(tmp) {
+ /* tmp is now the end of the domain, so
+ * copy URL scheme and domain as is, and terminate by hand */
+ size_t string_size = (size_t) (tmp - inURL);
+ strncpy(outURL, inURL, string_size);
+ outURL[string_size] = 0;
+
+ /* now advance the input pointer to just after the domain and go on */
+ inURL = tmp;
+ } else {
+ /* '/' was not found, which means there are no path-like
+ * portions, so copy whole inURL to outURL and we're done */
+ strcpy(outURL, inURL);
+ continue; /* while(0) */
+ }
+ }
+
+ /* explicitly copy a leading / (absolute path) */
+ if('/' == *inURL) strcat(outURL, "/");
+
+ /* now clean the remainder of the inURL. push URL segments onto
+ * stack, dealing with .. and . as we go */
+ tmp = strtok(inURL, "/"); /* finds first / */
+ while(tmp) {
+ if(!strcmp(tmp, "..")) {
+ /* discard previous URL segment, if there was one. if not,
+ * add the .. to the stack if this is *not* an absolute path
+ * (for absolute paths, leading .. has no effect, so skip it) */
+ if(0 < mystack->stack_size) pop_grp_stack(mystack);
+ else if('/' != *inURL) push_grp_stack(mystack, tmp);
+ } else {
+ /* always just skip ., but otherwise add segment to stack */
+ if(strcmp(tmp, ".")) push_grp_stack(mystack, tmp);
+ }
+ tmp = strtok(NULL, "/"); /* get the next segment */
+ }
+
+ /* stack now has pieces of cleaned URL, so just catenate them
+ * onto output string until stack is empty */
+ while(0 < mystack->stack_size) {
+ tmp = shift_grp_stack(mystack);
+ strcat(outURL, tmp);
+ strcat(outURL, "/");
+ }
+ outURL[strlen(outURL) - 1] = 0; /* blank out trailing / */
+ } while(0);
+ delete_grp_stack(&mystack);
+ return *status;
+}
+
+/* free all stack contents using pop_grp_stack before freeing the
+ * grp_stack itself */
+static void delete_grp_stack(grp_stack** mystack) {
+ if(!mystack || !*mystack) return;
+ while((*mystack)->stack_size) pop_grp_stack(*mystack);
+ free(*mystack);
+ *mystack = NULL;
+}
+
+/* append an item to the stack, handling the special case of the first
+ * item appended */
+static grp_stack_item* grp_stack_append(
+ grp_stack_item* last, grp_stack_data data
+) {
+ /* first create a new stack item, and copy data to it */
+ grp_stack_item* new_item = (grp_stack_item*) malloc(sizeof(grp_stack_item));
+ new_item->data = data;
+ if(last) {
+ /* attach this item between the "last" item and its "next" item */
+ new_item->next = last->next;
+ new_item->prev = last;
+ last->next->prev = new_item;
+ last->next = new_item;
+ } else {
+ /* stack is empty, so "next" and "previous" both point back to it */
+ new_item->next = new_item;
+ new_item->prev = new_item;
+ }
+ return new_item;
+}
+
+/* remove an item from the stack, handling the special case of the last
+ * item removed */
+static grp_stack_data grp_stack_remove(grp_stack_item* last) {
+ grp_stack_data retval = last->data;
+ last->prev->next = last->next;
+ last->next->prev = last->prev;
+ free(last);
+ return retval;
+}
+
+/* create new stack dynamically, and give it valid initial values */
+static grp_stack* new_grp_stack(void) {
+ grp_stack* retval = (grp_stack*) malloc(sizeof(grp_stack));
+ if(retval) {
+ retval->stack_size = 0;
+ retval->top = NULL;
+ }
+ return retval;
+}
+
+/* return the value at the top of the stack and remove it, updating
+ * stack_size. top->prev becomes the new "top" */
+static grp_stack_data pop_grp_stack(grp_stack* mystack) {
+ grp_stack_data retval = grp_stack_default;
+ if(mystack && mystack->top) {
+ grp_stack_item* newtop = mystack->top->prev;
+ retval = grp_stack_remove(mystack->top);
+ mystack->top = newtop;
+ if(0 == --mystack->stack_size) mystack->top = NULL;
+ }
+ return retval;
+}
+
+/* add to the stack after the top element. the added element becomes
+ * the new "top" */
+static void push_grp_stack(grp_stack* mystack, grp_stack_data data) {
+ if(!mystack) return;
+ mystack->top = grp_stack_append(mystack->top, data);
+ ++mystack->stack_size;
+ return;
+}
+
+/* return the value at the bottom of the stack and remove it, updating
+ * stack_size. "top" pointer is unaffected */
+static grp_stack_data shift_grp_stack(grp_stack* mystack) {
+ grp_stack_data retval = grp_stack_default;
+ if(mystack && mystack->top) {
+ retval = grp_stack_remove(mystack->top->next); /* top->next == bottom */
+ if(0 == --mystack->stack_size) mystack->top = NULL;
+ }
+ return retval;
+}
+
+/* add to the stack after the top element. "top" is unaffected, except
+ * in the special case of an initially empty stack */
+/* static void unshift_grp_stack(grp_stack* mystack, grp_stack_data data) {
+ if(!mystack) return;
+ if(mystack->top) grp_stack_append(mystack->top, data);
+ else mystack->top = grp_stack_append(NULL, data);
+ ++mystack->stack_size;
+ return;
+ } */
+
+/*--------------------------------------------------------------------------*/
+int fits_url2relurl(char *refURL, /* I reference URL string */
+ char *absURL, /* I absoulute URL string to process */
+ char *relURL, /* O resulting relative URL string */
+ int *status)
+/*
+ create a relative URL to the file referenced by absURL with respect to the
+ reference URL refURL. The relative URL is returned in relURL.
+
+ Both refURL and absURL must be absolute URL strings; i.e. either begin
+ with an access method specification "XXX://" or with a '/' character
+ signifiying that they are absolute file paths.
+
+ Note that it is possible to make a relative URL from two input URLs
+ (absURL and refURL) that are not compatable. This function does not
+ check to see if the resulting relative URL makes any sence. For instance,
+ it is impossible to make a relative URL from the following two inputs:
+
+ absURL = ftp://a.b.c.com/x/y/z/foo.fits
+ refURL = /a/b/c/ttt.fits
+
+ The resulting relURL will be:
+
+ ../../../ftp://a.b.c.com/x/y/z/foo.fits
+
+ Which is syntically correct but meaningless. The problem is that a file
+ with an access method of ftp:// cannot be expressed a a relative URL to
+ a local disk file.
+*/
+
+{
+ int i,j;
+ int refcount,abscount;
+ int refsize,abssize;
+ int done;
+
+
+ if(*status != 0) return(*status);
+
+ do
+ {
+ /*
+ refURL and absURL must be absolute to process
+ */
+
+ if(!(fits_is_url_absolute(refURL) || *refURL == '/') ||
+ !(fits_is_url_absolute(absURL) || *absURL == '/'))
+ {
+ *status = URL_PARSE_ERROR;
+ ffpmsg("Cannot make rel. URL from non abs. URLs (fits_url2relurl)");
+ continue;
+ }
+
+ /* determine the size of the refURL and absURL strings */
+
+ refsize = strlen(refURL);
+ abssize = strlen(absURL);
+
+ /* process the two URL strings and build the relative URL between them */
+
+
+ for(done = 0, refcount = 0, abscount = 0;
+ !done && refcount < refsize && abscount < abssize;
+ ++refcount, ++abscount)
+ {
+ for(; abscount < abssize && absURL[abscount] == '/'; ++abscount);
+ for(; refcount < refsize && refURL[refcount] == '/'; ++refcount);
+
+ /* find the next path segment in absURL */
+ for(i = abscount; absURL[i] != '/' && i < abssize; ++i);
+
+ /* find the next path segment in refURL */
+ for(j = refcount; refURL[j] != '/' && j < refsize; ++j);
+
+ /* do the two path segments match? */
+ if(i == j &&
+ strncmp(absURL+abscount, refURL+refcount,i-refcount) == 0)
+ {
+ /* they match, so ignore them and continue */
+ abscount = i; refcount = j;
+ continue;
+ }
+
+ /* we found a difference in the paths in refURL and absURL */
+
+ /* initialize the relative URL string */
+ relURL[0] = 0;
+
+ /*
+ for every path segment remaining in the refURL string, append
+ a "../" path segment to the relataive URL relURL
+ */
+
+ for(j = refcount; j < refsize; ++j)
+ if(refURL[j] == '/') strcat(relURL,"../");
+
+ /* copy all remaining characters of absURL to the output relURL */
+
+ strcat(relURL,absURL+abscount);
+
+ /* we are done building the relative URL */
+ done = 1;
+ }
+
+ }while(0);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fits_relurl2url(char *refURL, /* I reference URL string */
+ char *relURL, /* I relative URL string to process */
+ char *absURL, /* O absolute URL string */
+ int *status)
+/*
+ create an absolute URL from a relative url and a reference URL. The
+ reference URL is given by the FITS file pointed to by fptr.
+
+ The construction of the absolute URL from the partial and reference URl
+ is performed using the rules set forth in:
+
+ http://www.w3.org/Addressing/URL/URL_TOC.html
+ and
+ http://www.w3.org/Addressing/URL/4_3_Partial.html
+
+ Note that the relative URL string relURL must conform to the Unix-like
+ URL syntax; host dependent partial URL strings are not allowed.
+*/
+{
+ int i;
+
+ char tmpStr[FLEN_FILENAME];
+
+ char *tmpStr1, *tmpStr2;
+
+
+ if(*status != 0) return(*status);
+
+ do
+ {
+
+ /*
+ make a copy of the reference URL string refURL for parsing purposes
+ */
+
+ strcpy(tmpStr,refURL);
+
+ /*
+ if the reference file has an access method of mem:// or shmem://
+ then we cannot use it as the basis of an absolute URL construction
+ for a partial URL
+ */
+
+ if(strncasecmp(tmpStr,"MEM:",4) == 0 ||
+ strncasecmp(tmpStr,"SHMEM:",6) == 0)
+ {
+ ffpmsg("ref URL has access mem:// or shmem:// (fits_relurl2url)");
+ ffpmsg(" cannot construct full URL from a partial URL and ");
+ ffpmsg(" MEM/SHMEM base URL");
+ *status = URL_PARSE_ERROR;
+ continue;
+ }
+
+ if(relURL[0] != '/')
+ {
+ /*
+ just append the relative URL string to the reference URL
+ string (minus the reference URL file name) to form the
+ absolute URL string
+ */
+
+ tmpStr1 = strrchr(tmpStr,'/');
+
+ if(tmpStr1 != NULL) tmpStr1[1] = 0;
+ else tmpStr[0] = 0;
+
+ strcat(tmpStr,relURL);
+ }
+ else
+ {
+ /*
+ have to parse the refURL string for the first occurnace of the
+ same number of '/' characters as contained in the beginning of
+ location that is not followed by a greater number of consective
+ '/' charaters (yes, that is a confusing statement); this is the
+ location in the refURL string where the relURL string is to
+ be appended to form the new absolute URL string
+ */
+
+ /*
+ first, build up a slash pattern string that has one more
+ slash in it than the starting slash pattern of the
+ relURL string
+ */
+
+ strcpy(absURL,"/");
+
+ for(i = 0; relURL[i] == '/'; ++i) strcat(absURL,"/");
+
+ /*
+ loop over the refURL string until the slash pattern stored
+ in absURL is no longer found
+ */
+
+ for(tmpStr1 = tmpStr, i = strlen(absURL);
+ (tmpStr2 = strstr(tmpStr1,absURL)) != NULL;
+ tmpStr1 = tmpStr2 + i);
+
+ /* reduce the slash pattern string by one slash */
+
+ absURL[i-1] = 0;
+
+ /*
+ search for the slash pattern in the remaining portion
+ of the refURL string
+ */
+
+ tmpStr2 = strstr(tmpStr1,absURL);
+
+ /* if no slash pattern match was found */
+
+ if(tmpStr2 == NULL)
+ {
+ /* just strip off the file name from the refURL */
+
+ tmpStr2 = strrchr(tmpStr1,'/');
+
+ if(tmpStr2 != NULL) tmpStr2[0] = 0;
+ else tmpStr[0] = 0;
+ }
+ else
+ {
+ /* set a string terminator at the slash pattern match */
+
+ *tmpStr2 = 0;
+ }
+
+ /*
+ conatenate the relURL string to the refURL string to form
+ the absURL
+ */
+
+ strcat(tmpStr,relURL);
+ }
+
+ /*
+ normalize the absURL by removing any ".." or "." specifiers
+ in the string
+ */
+
+ *status = fits_clean_url(tmpStr,absURL,status);
+
+ }while(0);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fits_encode_url(char *inpath, /* I URL to be encoded */
+ char *outpath, /* O output encoded URL */
+ int *status)
+ /*
+ encode all URL "unsafe" and "reserved" characters using the "%XX"
+ convention, where XX stand for the two hexidecimal digits of the
+ encode character's ASCII code.
+
+ Note that the output path is at least as large as, if not larger than
+ the input path, so that OUTPATH should be passed to this function
+ with room for growth. If not a runtime error could result. It is
+ assumed that OUTPATH has been allocated with enough room to hold
+ the resulting encoded URL.
+
+ This function was adopted from code in the libwww.a library available
+ via the W3 consortium <URL: http://www.w3.org>
+ */
+{
+ unsigned char a;
+
+ char *p;
+ char *q;
+ char *hex = "0123456789ABCDEF";
+
+unsigned const char isAcceptable[96] =
+{/* 0x0 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xA 0xB 0xC 0xD 0xE 0xF */
+
+ 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xF,0xE,0x0,0xF,0xF,0xC,
+ /* 2x !"#$%&'()*+,-./ */
+ 0xF,0xF,0xF,0xF,0xF,0xF,0xF,0xF,0xF,0xF,0x8,0x0,0x0,0x0,0x0,0x0,
+ /* 3x 0123456789:;<=>? */
+ 0xF,0xF,0xF,0xF,0xF,0xF,0xF,0xF,0xF,0xF,0xF,0xF,0xF,0xF,0xF,0xF,
+ /* 4x @ABCDEFGHIJKLMNO */
+ 0xF,0xF,0xF,0xF,0xF,0xF,0xF,0xF,0xF,0xF,0xF,0x0,0x0,0x0,0x0,0xF,
+ /* 5X PQRSTUVWXYZ[\]^_ */
+ 0x0,0xF,0xF,0xF,0xF,0xF,0xF,0xF,0xF,0xF,0xF,0xF,0xF,0xF,0xF,0xF,
+ /* 6x `abcdefghijklmno */
+ 0xF,0xF,0xF,0xF,0xF,0xF,0xF,0xF,0xF,0xF,0xF,0x0,0x0,0x0,0x0,0x0
+ /* 7X pqrstuvwxyz{\}~DEL */
+};
+
+ if(*status != 0) return(*status);
+
+ /* loop over all characters in inpath until '\0' is encountered */
+
+ for(q = outpath, p = inpath; *p; p++)
+ {
+ a = (unsigned char)*p;
+
+ /* if the charcter requires encoding then process it */
+
+ if(!( a>=32 && a<128 && (isAcceptable[a-32])))
+ {
+ /* add a '%' character to the outpath */
+ *q++ = HEX_ESCAPE;
+ /* add the most significant ASCII code hex value */
+ *q++ = hex[a >> 4];
+ /* add the least significant ASCII code hex value */
+ *q++ = hex[a & 15];
+ }
+ /* else just copy the character as is */
+ else *q++ = *p;
+ }
+
+ /* null terminate the outpath string */
+
+ *q++ = 0;
+
+ return(*status);
+}
+
+/*---------------------------------------------------------------------------*/
+int fits_unencode_url(char *inpath, /* I input URL with encoding */
+ char *outpath, /* O unencoded URL */
+ int *status)
+ /*
+ unencode all URL "unsafe" and "reserved" characters to their actual
+ ASCII representation. All tokens of the form "%XX" where XX is the
+ hexidecimal code for an ASCII character, are searched for and
+ translated into the actuall ASCII character (so three chars become
+ 1 char).
+
+ It is assumed that OUTPATH has enough room to hold the unencoded
+ URL.
+
+ This function was adopted from code in the libwww.a library available
+ via the W3 consortium <URL: http://www.w3.org>
+ */
+
+{
+ char *p;
+ char *q;
+ char c;
+
+ if(*status != 0) return(*status);
+
+ p = inpath;
+ q = outpath;
+
+ /*
+ loop over all characters in the inpath looking for the '%' escape
+ character; if found the process the escape sequence
+ */
+
+ while(*p != 0)
+ {
+ /*
+ if the character is '%' then unencode the sequence, else
+ just copy the character from inpath to outpath
+ */
+
+ if (*p == HEX_ESCAPE)
+ {
+ if((c = *(++p)) != 0)
+ {
+ *q = (
+ (c >= '0' && c <= '9') ?
+ (c - '0') : ((c >= 'A' && c <= 'F') ?
+ (c - 'A' + 10) : (c - 'a' + 10))
+ )*16;
+
+ if((c = *(++p)) != 0)
+ {
+ *q = *q + (
+ (c >= '0' && c <= '9') ?
+ (c - '0') : ((c >= 'A' && c <= 'F') ?
+ (c - 'A' + 10) : (c - 'a' + 10))
+ );
+ p++, q++;
+ }
+ }
+ }
+ else
+ *q++ = *p++;
+ }
+
+ /* terminate the outpath */
+ *q = 0;
+
+ return(*status);
+}
+/*---------------------------------------------------------------------------*/
+
+int fits_is_url_absolute(char *url)
+/*
+ Return a True (1) or False (0) value indicating whether or not the passed
+ URL string contains an access method specifier or not. Note that this is
+ a boolean function and it neither reads nor returns the standard error
+ status parameter
+*/
+{
+ char *tmpStr1, *tmpStr2;
+
+ char reserved[] = {':',';','/','?','@','&','=','+','$',','};
+
+ /*
+ The rule for determing if an URL is relative or absolute is that it (1)
+ must have a colon ":" and (2) that the colon must appear before any other
+ reserved URL character in the URL string. We first see if a colon exists,
+ get its position in the string, and then check to see if any of the other
+ reserved characters exists and if their position in the string is greater
+ than that of the colons.
+ */
+
+ if( (tmpStr1 = strchr(url,reserved[0])) != NULL &&
+ ((tmpStr2 = strchr(url,reserved[1])) == NULL || tmpStr2 > tmpStr1) &&
+ ((tmpStr2 = strchr(url,reserved[2])) == NULL || tmpStr2 > tmpStr1) &&
+ ((tmpStr2 = strchr(url,reserved[3])) == NULL || tmpStr2 > tmpStr1) &&
+ ((tmpStr2 = strchr(url,reserved[4])) == NULL || tmpStr2 > tmpStr1) &&
+ ((tmpStr2 = strchr(url,reserved[5])) == NULL || tmpStr2 > tmpStr1) &&
+ ((tmpStr2 = strchr(url,reserved[6])) == NULL || tmpStr2 > tmpStr1) &&
+ ((tmpStr2 = strchr(url,reserved[7])) == NULL || tmpStr2 > tmpStr1) &&
+ ((tmpStr2 = strchr(url,reserved[8])) == NULL || tmpStr2 > tmpStr1) &&
+ ((tmpStr2 = strchr(url,reserved[9])) == NULL || tmpStr2 > tmpStr1) )
+ {
+ return(1);
+ }
+ else
+ {
+ return(0);
+ }
+}
diff --git a/pkg/tbtables/cfitsio/group.h b/pkg/tbtables/cfitsio/group.h
new file mode 100644
index 00000000..f7aae5b1
--- /dev/null
+++ b/pkg/tbtables/cfitsio/group.h
@@ -0,0 +1,65 @@
+#define MAX_HDU_TRACKER 1000
+
+typedef struct _HDUtracker HDUtracker;
+
+struct _HDUtracker
+{
+ int nHDU;
+
+ char *filename[MAX_HDU_TRACKER];
+ int position[MAX_HDU_TRACKER];
+
+ char *newFilename[MAX_HDU_TRACKER];
+ int newPosition[MAX_HDU_TRACKER];
+};
+
+/* functions used internally in the grouping convention module */
+
+int ffgtdc(int grouptype, int xtensioncol, int extnamecol, int extvercol,
+ int positioncol, int locationcol, int uricol, char *ttype[],
+ char *tform[], int *ncols, int *status);
+
+int ffgtgc(fitsfile *gfptr, int *xtensionCol, int *extnameCol, int *extverCol,
+ int *positionCol, int *locationCol, int *uriCol, int *grptype,
+ int *status);
+
+int ffgmul(fitsfile *mfptr, int rmopt, int *status);
+
+int ffgmf(fitsfile *gfptr, char *xtension, char *extname, int extver,
+ int position, char *location, long *member, int *status);
+
+int ffgtrmr(fitsfile *gfptr, HDUtracker *HDU, int *status);
+
+int ffgtcpr(fitsfile *infptr, fitsfile *outfptr, int cpopt, HDUtracker *HDU,
+ int *status);
+
+int fftsad(fitsfile *mfptr, HDUtracker *HDU, int *newPosition,
+ char *newFileName);
+
+int fftsud(fitsfile *mfptr, HDUtracker *HDU, int newPosition,
+ char *newFileName);
+
+void prepare_keyvalue(char *keyvalue);
+
+int fits_path2url(char *inpath, char *outpath, int *status);
+
+int fits_url2path(char *inpath, char *outpath, int *status);
+
+int fits_get_cwd(char *cwd, int *status);
+
+int fits_get_url(fitsfile *fptr, char *realURL, char *startURL,
+ char *realAccess, char *startAccess, int *iostate,
+ int *status);
+
+int fits_clean_url(char *inURL, char *outURL, int *status);
+
+int fits_relurl2url(char *refURL, char *relURL, char *absURL, int *status);
+
+int fits_url2relurl(char *refURL, char *absURL, char *relURL, int *status);
+
+int fits_encode_url(char *inpath, char *outpath, int *status);
+
+int fits_unencode_url(char *inpath, char *outpath, int *status);
+
+int fits_is_url_absolute(char *url);
+
diff --git a/pkg/tbtables/cfitsio/grparser.c b/pkg/tbtables/cfitsio/grparser.c
new file mode 100644
index 00000000..d21c098a
--- /dev/null
+++ b/pkg/tbtables/cfitsio/grparser.c
@@ -0,0 +1,1365 @@
+/* T E M P L A T E P A R S E R
+ =============================
+
+ by Jerzy.Borkowski@obs.unige.ch
+
+ Integral Science Data Center
+ ch. d'Ecogia 16
+ 1290 Versoix
+ Switzerland
+
+14-Oct-98: initial release
+16-Oct-98: code cleanup, #include <string.h> included, now gcc -Wall prints no
+ warnings during compilation. Bugfix: now one can specify additional
+ columns in group HDU. Autoindexing also works in this situation
+ (colunms are number from 7 however).
+17-Oct-98: bugfix: complex keywords were incorrectly written (was TCOMPLEX should
+ be TDBLCOMPLEX).
+20-Oct-98: bugfix: parser was writing EXTNAME twice, when first HDU in template is
+ defined with XTENSION IMAGE then parser creates now dummy PHDU,
+ SIMPLE T is now allowed only at most once and in first HDU only.
+ WARNING: one should not define EXTNAME keyword for GROUP HDUs, as
+ they have them already defined by parser (EXTNAME = GROUPING).
+ Parser accepts EXTNAME oin GROUP HDU definition, but in this
+ case multiple EXTNAME keywords will present in HDU header.
+23-Oct-98: bugfix: unnecessary space was written to FITS file for blank
+ keywords.
+24-Oct-98: syntax change: empty lines and lines with only whitespaces are
+ written to FITS files as blank keywords (if inside group/hdu
+ definition). Previously lines had to have at least 8 spaces.
+ Please note, that due to pecularities of CFITSIO if the
+ last keyword(s) defined for given HDU are blank keywords
+ consisting of only 80 spaces, then (some of) those keywords
+ may be silently deleted by CFITSIO.
+13-Nov-98: bugfix: parser was writing GRPNAME twice. Parser still creates
+ GRPNAME keywords for GROUP HDU's which do not specify them.
+ However, values (of form DEFAULT_GROUP_XXX) are assigned
+ not necessarily in order HDUs appear in template file, but
+ rather in order parser completes their creation in FITS
+ file. Also, when including files, if fopen fails, parser
+ tries to open file with a name = directory_of_top_level
+ file + name of file to be included, as long as name
+ of file to be included does not specify absolute pathname.
+16-Nov-98: bugfix to bugfix from 13-Nov-98
+19-Nov-98: EXTVER keyword is now automatically assigned value by parser.
+17-Dev-98: 2 new things added: 1st: CFITSIO_INCLUDE_FILES environment
+ variable can contain a colon separated list of directories
+ to look for when looking for template include files (and master
+ template also). 2nd: it is now possible to append template
+ to nonempty FITS. file. fitsfile *ff no longer needs to point
+ to an empty FITS file with 0 HDUs in it. All data written by
+ parser will simple be appended at the end of file.
+22-Jan-99: changes to parser: when in append mode parser initially scans all
+ existing HDUs to built a list of already used EXTNAME/EXTVERs
+22-Jan-99: Bruce O'Neel, bugfix : TLONG should always reference long type
+ variable on OSF/Alpha and on 64-bit archs in general
+20-Jun-2002 Wm Pence, added support for the HIERARCH keyword convention in
+ which keyword names can effectively be longer than 8 characters.
+ Example:
+ HIERARCH LongKeywordName = 'value' / comment
+30-Jan-2003 Wm Pence, bugfix: ngp_read_xtension was testing for "ASCIITABLE"
+ instead of "TABLE" as the XTENSION value of an ASCII table,
+ and it did not allow for optional trailing spaces in the
+ "IMAGE" or "TABLE" string.
+16-Dec-2003 James Peachey: ngp_keyword_all_write was modified to apply
+ comments from the template file to the output file in
+ the case of reserved keywords (e.g. tform#, ttype# etcetera).
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef sparc
+#include <malloc.h>
+#include <memory.h>
+#endif
+
+#include <string.h>
+#include "fitsio.h"
+#include "grparser.h"
+
+NGP_RAW_LINE ngp_curline = { NULL, NULL, NULL, NGP_TTYPE_UNKNOWN, NULL, NGP_FORMAT_OK, 0 };
+NGP_RAW_LINE ngp_prevline = { NULL, NULL, NULL, NGP_TTYPE_UNKNOWN, NULL, NGP_FORMAT_OK, 0 };
+
+int ngp_inclevel = 0; /* number of included files, 1 - means mean file */
+int ngp_grplevel = 0; /* group nesting level, 0 - means no grouping */
+
+FILE *ngp_fp[NGP_MAX_INCLUDE]; /* stack of included file handles */
+int ngp_keyidx = NGP_TOKEN_UNKNOWN; /* index of token in current line */
+NGP_TOKEN ngp_linkey; /* keyword after line analyze */
+
+char ngp_master_dir[NGP_MAX_FNAME]; /* directory of top level include file */
+
+NGP_TKDEF ngp_tkdef[] = /* tokens recognized by parser */
+ { { "\\INCLUDE", NGP_TOKEN_INCLUDE },
+ { "\\GROUP", NGP_TOKEN_GROUP },
+ { "\\END", NGP_TOKEN_END },
+ { "XTENSION", NGP_TOKEN_XTENSION },
+ { "SIMPLE", NGP_TOKEN_SIMPLE },
+ { NULL, NGP_TOKEN_UNKNOWN }
+ };
+
+int master_grp_idx = 1; /* current unnamed group in object */
+
+int ngp_extver_tab_size = 0;
+NGP_EXTVER_TAB *ngp_extver_tab = NULL;
+
+
+int ngp_get_extver(char *extname, int *version)
+ { NGP_EXTVER_TAB *p;
+ char *p2;
+ int i;
+
+ if ((NULL == extname) || (NULL == version)) return(NGP_BAD_ARG);
+ if ((NULL == ngp_extver_tab) && (ngp_extver_tab_size > 0)) return(NGP_BAD_ARG);
+ if ((NULL != ngp_extver_tab) && (ngp_extver_tab_size <= 0)) return(NGP_BAD_ARG);
+
+ for (i=0; i<ngp_extver_tab_size; i++)
+ { if (0 == strcmp(extname, ngp_extver_tab[i].extname))
+ { *version = (++ngp_extver_tab[i].version);
+ return(NGP_OK);
+ }
+ }
+
+ if (NULL == ngp_extver_tab)
+ { p = (NGP_EXTVER_TAB *)ngp_alloc(sizeof(NGP_EXTVER_TAB)); }
+ else
+ { p = (NGP_EXTVER_TAB *)ngp_realloc(ngp_extver_tab, (ngp_extver_tab_size + 1) * sizeof(NGP_EXTVER_TAB)); }
+
+ if (NULL == p) return(NGP_NO_MEMORY);
+
+ p2 = ngp_alloc(strlen(extname) + 1);
+ if (NULL == p2)
+ { ngp_free(p);
+ return(NGP_NO_MEMORY);
+ }
+
+ strcpy(p2, extname);
+ ngp_extver_tab = p;
+ ngp_extver_tab[ngp_extver_tab_size].extname = p2;
+ *version = ngp_extver_tab[ngp_extver_tab_size].version = 1;
+
+ ngp_extver_tab_size++;
+
+ return(NGP_OK);
+ }
+
+int ngp_set_extver(char *extname, int version)
+ { NGP_EXTVER_TAB *p;
+ char *p2;
+ int i;
+
+ if (NULL == extname) return(NGP_BAD_ARG);
+ if ((NULL == ngp_extver_tab) && (ngp_extver_tab_size > 0)) return(NGP_BAD_ARG);
+ if ((NULL != ngp_extver_tab) && (ngp_extver_tab_size <= 0)) return(NGP_BAD_ARG);
+
+ for (i=0; i<ngp_extver_tab_size; i++)
+ { if (0 == strcmp(extname, ngp_extver_tab[i].extname))
+ { if (version > ngp_extver_tab[i].version) ngp_extver_tab[i].version = version;
+ return(NGP_OK);
+ }
+ }
+
+ if (NULL == ngp_extver_tab)
+ { p = (NGP_EXTVER_TAB *)ngp_alloc(sizeof(NGP_EXTVER_TAB)); }
+ else
+ { p = (NGP_EXTVER_TAB *)ngp_realloc(ngp_extver_tab, (ngp_extver_tab_size + 1) * sizeof(NGP_EXTVER_TAB)); }
+
+ if (NULL == p) return(NGP_NO_MEMORY);
+
+ p2 = ngp_alloc(strlen(extname) + 1);
+ if (NULL == p2)
+ { ngp_free(p);
+ return(NGP_NO_MEMORY);
+ }
+
+ strcpy(p2, extname);
+ ngp_extver_tab = p;
+ ngp_extver_tab[ngp_extver_tab_size].extname = p2;
+ ngp_extver_tab[ngp_extver_tab_size].version = version;
+
+ ngp_extver_tab_size++;
+
+ return(NGP_OK);
+ }
+
+
+int ngp_delete_extver_tab(void)
+ { int i;
+
+ if ((NULL == ngp_extver_tab) && (ngp_extver_tab_size > 0)) return(NGP_BAD_ARG);
+ if ((NULL != ngp_extver_tab) && (ngp_extver_tab_size <= 0)) return(NGP_BAD_ARG);
+ if ((NULL == ngp_extver_tab) && (0 == ngp_extver_tab_size)) return(NGP_OK);
+
+ for (i=0; i<ngp_extver_tab_size; i++)
+ { if (NULL != ngp_extver_tab[i].extname)
+ { ngp_free(ngp_extver_tab[i].extname);
+ ngp_extver_tab[i].extname = NULL;
+ }
+ ngp_extver_tab[i].version = 0;
+ }
+ ngp_free(ngp_extver_tab);
+ ngp_extver_tab = NULL;
+ ngp_extver_tab_size = 0;
+ return(NGP_OK);
+ }
+
+ /* compare strings, case does not matter */
+
+int ngp_strcasecmp(char *p1, char *p2)
+ { char c1, c2;
+
+ for (;;)
+ {
+ c1 = *p1;
+ if ((c1 >= 'a') && (c1 <= 'z')) c1 += ('A' - 'a');
+
+ c2 = *p2;
+ if ((c2 >= 'a') && (c2 <= 'z')) c2 += ('A' - 'a');
+
+ if (c1 < c2) return(-1);
+ if (c1 > c2) return(1);
+ if (0 == c1) return(0);
+ p1++;
+ p2++;
+ }
+ }
+
+int ngp_strcasencmp(char *p1, char *p2, int n)
+ { char c1, c2;
+ int ii;
+
+ for (ii=0;ii<n;ii++)
+ {
+ c1 = *p1;
+ if ((c1 >= 'a') && (c1 <= 'z')) c1 += ('A' - 'a');
+
+ c2 = *p2;
+ if ((c2 >= 'a') && (c2 <= 'z')) c2 += ('A' - 'a');
+
+ if (c1 < c2) return(-1);
+ if (c1 > c2) return(1);
+ if (0 == c1) return(0);
+ p1++;
+ p2++;
+ }
+ return(0);
+ }
+
+ /* read one line from file */
+
+int ngp_line_from_file(FILE *fp, char **p)
+ { int c, r, llen, allocsize, alen;
+ char *p2;
+
+ if (NULL == fp) return(NGP_NUL_PTR); /* check for stupid args */
+ if (NULL == p) return(NGP_NUL_PTR); /* more foolproof checks */
+
+ r = NGP_OK; /* initialize stuff, reset err code */
+ llen = 0; /* 0 characters read so far */
+ *p = (char *)ngp_alloc(1); /* preallocate 1 byte */
+ allocsize = 1; /* signal that we have allocated 1 byte */
+ if (NULL == *p) return(NGP_NO_MEMORY); /* if this failed, system is in dire straits */
+
+ for (;;)
+ { c = getc(fp); /* get next character */
+ if (EOF == c) /* EOF signalled ? */
+ {
+ if (ferror(fp)) r = NGP_READ_ERR; /* was it real error or simply EOF ? */
+ if (0 == llen) return(NGP_EOF); /* signal EOF only if 0 characters read so far */
+ break;
+ }
+ if ('\n' == c) break; /* end of line character ? */
+
+ llen++; /* we have new character, make room for it */
+ alen = ((llen + NGP_ALLOCCHUNK) / NGP_ALLOCCHUNK) * NGP_ALLOCCHUNK;
+ if (alen > allocsize)
+ { p2 = (char *)ngp_realloc(*p, alen); /* realloc buffer, if there is need */
+ if (NULL == p2)
+ { r = NGP_NO_MEMORY;
+ break;
+ }
+ *p = p2;
+ allocsize = alen;
+ }
+ (*p)[llen - 1] = c; /* copy character to buffer */
+ }
+
+ llen++; /* place for terminating \0 */
+ if (llen != allocsize)
+ { p2 = (char *)ngp_realloc(*p, llen);
+ if (NULL == p2) r = NGP_NO_MEMORY;
+ else
+ { *p = p2;
+ (*p)[llen - 1] = 0; /* copy \0 to buffer */
+ }
+ }
+ else
+ { (*p)[llen - 1] = 0; /* necessary when line read was empty */
+ }
+
+ if ((NGP_EOF != r) && (NGP_OK != r)) /* in case of errors free resources */
+ { ngp_free(*p);
+ *p = NULL;
+ }
+
+ return(r); /* return status code */
+ }
+
+ /* free current line structure */
+
+int ngp_free_line(void)
+ {
+ if (NULL != ngp_curline.line)
+ { ngp_free(ngp_curline.line);
+ ngp_curline.line = NULL;
+ ngp_curline.name = NULL;
+ ngp_curline.value = NULL;
+ ngp_curline.comment = NULL;
+ ngp_curline.type = NGP_TTYPE_UNKNOWN;
+ ngp_curline.format = NGP_FORMAT_OK;
+ ngp_curline.flags = 0;
+ }
+ return(NGP_OK);
+ }
+
+ /* free cached line structure */
+
+int ngp_free_prevline(void)
+ {
+ if (NULL != ngp_prevline.line)
+ { ngp_free(ngp_prevline.line);
+ ngp_prevline.line = NULL;
+ ngp_prevline.name = NULL;
+ ngp_prevline.value = NULL;
+ ngp_prevline.comment = NULL;
+ ngp_prevline.type = NGP_TTYPE_UNKNOWN;
+ ngp_prevline.format = NGP_FORMAT_OK;
+ ngp_prevline.flags = 0;
+ }
+ return(NGP_OK);
+ }
+
+ /* read one line */
+
+int ngp_read_line_buffered(FILE *fp)
+ {
+ ngp_free_line(); /* first free current line (if any) */
+
+ if (NULL != ngp_prevline.line) /* if cached, return cached line */
+ { ngp_curline = ngp_prevline;
+ ngp_prevline.line = NULL;
+ ngp_prevline.name = NULL;
+ ngp_prevline.value = NULL;
+ ngp_prevline.comment = NULL;
+ ngp_prevline.type = NGP_TTYPE_UNKNOWN;
+ ngp_prevline.format = NGP_FORMAT_OK;
+ ngp_prevline.flags = 0;
+ ngp_curline.flags = NGP_LINE_REREAD;
+ return(NGP_OK);
+ }
+
+ ngp_curline.flags = 0; /* if not cached really read line from file */
+ return(ngp_line_from_file(fp, &(ngp_curline.line)));
+ }
+
+ /* unread line */
+
+int ngp_unread_line(void)
+ {
+ if (NULL == ngp_curline.line) /* nothing to unread */
+ return(NGP_EMPTY_CURLINE);
+
+ if (NULL != ngp_prevline.line) /* we cannot unread line twice */
+ return(NGP_UNREAD_QUEUE_FULL);
+
+ ngp_prevline = ngp_curline;
+ ngp_curline.line = NULL;
+ return(NGP_OK);
+ }
+
+ /* a first guess line decomposition */
+
+int ngp_extract_tokens(NGP_RAW_LINE *cl)
+ { char *p, *s;
+ int cl_flags, i;
+
+ p = cl->line; /* start from beginning of line */
+ if (NULL == p) return(NGP_NUL_PTR);
+
+ cl->name = cl->value = cl->comment = NULL;
+ cl->type = NGP_TTYPE_UNKNOWN;
+ cl->format = NGP_FORMAT_OK;
+
+ cl_flags = 0;
+
+ for (i=0;; i++) /* if 8 spaces at beginning then line is comment */
+ { if ((0 == *p) || ('\n' == *p))
+ { /* if line has only blanks -> write blank keyword */
+ cl->line[0] = 0; /* create empty name (0 length string) */
+ cl->comment = cl->name = cl->line;
+ cl->type = NGP_TTYPE_RAW; /* signal write unformatted to FITS file */
+ return(NGP_OK);
+ }
+ if ((' ' != *p) && ('\t' != *p)) break;
+ if (i >= 7)
+ {
+ cl->comment = p + 1;
+ for (s = cl->comment;; s++) /* filter out any EOS characters in comment */
+ { if ('\n' == *s) *s = 0;
+ if (0 == *s) break;
+ }
+ cl->line[0] = 0; /* create empty name (0 length string) */
+ cl->name = cl->line;
+ cl->type = NGP_TTYPE_RAW;
+ return(NGP_OK);
+ }
+ p++;
+ }
+
+ cl->name = p;
+
+ for (;;) /* we need to find 1st whitespace */
+ { if ((0 == *p) || ('\n' == *p))
+ { *p = 0;
+ break;
+ }
+
+ /*
+ from Richard Mathar, 2002-05-03, add 10 lines:
+ if upper/lowercase HIERARCH followed also by an equal sign...
+ */
+ if( strncasecmp("HIERARCH",p,strlen("HIERARCH")) == 0 )
+ {
+ char * const eqsi=strchr(p,'=') ;
+ if( eqsi )
+ {
+ cl_flags |= NGP_FOUND_EQUAL_SIGN ;
+ p=eqsi ;
+ break ;
+ }
+ }
+
+ if ((' ' == *p) || ('\t' == *p)) break;
+ if ('=' == *p)
+ { cl_flags |= NGP_FOUND_EQUAL_SIGN;
+ break;
+ }
+
+ p++;
+ }
+
+ if (*p) *(p++) = 0; /* found end of keyname so terminate string with zero */
+
+ if ((!ngp_strcasecmp("HISTORY", cl->name))
+ || (!ngp_strcasecmp("COMMENT", cl->name))
+ || (!ngp_strcasecmp("CONTINUE", cl->name)))
+ { cl->comment = p;
+ for (s = cl->comment;; s++) /* filter out any EOS characters in comment */
+ { if ('\n' == *s) *s = 0;
+ if (0 == *s) break;
+ }
+ cl->type = NGP_TTYPE_RAW;
+ return(NGP_OK);
+ }
+
+ if (!ngp_strcasecmp("\\INCLUDE", cl->name))
+ {
+ for (;; p++) if ((' ' != *p) && ('\t' != *p)) break; /* skip whitespace */
+
+ cl->value = p;
+ for (s = cl->value;; s++) /* filter out any EOS characters */
+ { if ('\n' == *s) *s = 0;
+ if (0 == *s) break;
+ }
+ cl->type = NGP_TTYPE_UNKNOWN;
+ return(NGP_OK);
+ }
+
+ for (;; p++)
+ { if ((0 == *p) || ('\n' == *p)) return(NGP_OK); /* test if at end of string */
+ if ((' ' == *p) || ('\t' == *p)) continue; /* skip whitespace */
+ if (cl_flags & NGP_FOUND_EQUAL_SIGN) break;
+ if ('=' != *p) break; /* ignore initial equal sign */
+ cl_flags |= NGP_FOUND_EQUAL_SIGN;
+ }
+
+ if ('/' == *p) /* no value specified, comment only */
+ { p++;
+ if ((' ' == *p) || ('\t' == *p)) p++;
+ cl->comment = p;
+ for (s = cl->comment;; s++) /* filter out any EOS characters in comment */
+ { if ('\n' == *s) *s = 0;
+ if (0 == *s) break;
+ }
+ return(NGP_OK);
+ }
+
+ if ('\'' == *p) /* we have found string within quotes */
+ { cl->value = s = ++p; /* set pointer to beginning of that string */
+ cl->type = NGP_TTYPE_STRING; /* signal that it is of string type */
+
+ for (;;) /* analyze it */
+ { if ((0 == *p) || ('\n' == *p)) /* end of line -> end of string */
+ { *s = 0; return(NGP_OK); }
+
+ if ('\'' == *p) /* we have found doublequote */
+ { if ((0 == p[1]) || ('\n' == p[1]))/* doublequote is the last character in line */
+ { *s = 0; return(NGP_OK); }
+ if (('\t' == p[1]) || (' ' == p[1])) /* duoblequote was string terminator */
+ { *s = 0; p++; break; }
+ if ('\'' == p[1]) p++; /* doublequote is inside string, convert "" -> " */
+ }
+
+ *(s++) = *(p++); /* compact string in place, necess. by "" -> " conversion */
+ }
+ }
+ else /* regular token */
+ {
+ cl->value = p; /* set pointer to token */
+ cl->type = NGP_TTYPE_UNKNOWN; /* we dont know type at the moment */
+ for (;; p++) /* we need to find 1st whitespace */
+ { if ((0 == *p) || ('\n' == *p))
+ { *p = 0; return(NGP_OK); }
+ if ((' ' == *p) || ('\t' == *p)) break;
+ }
+ if (*p) *(p++) = 0; /* found so terminate string with zero */
+ }
+
+ for (;; p++)
+ { if ((0 == *p) || ('\n' == *p)) return(NGP_OK); /* test if at end of string */
+ if ((' ' != *p) && ('\t' != *p)) break; /* skip whitespace */
+ }
+
+ if ('/' == *p) /* no value specified, comment only */
+ { p++;
+ if ((' ' == *p) || ('\t' == *p)) p++;
+ cl->comment = p;
+ for (s = cl->comment;; s++) /* filter out any EOS characters in comment */
+ { if ('\n' == *s) *s = 0;
+ if (0 == *s) break;
+ }
+ return(NGP_OK);
+ }
+
+ cl->format = NGP_FORMAT_ERROR;
+ return(NGP_OK); /* too many tokens ... */
+ }
+
+/* try to open include file. If open fails and fname
+ does not specify absolute pathname, try to open fname
+ in any directory specified in CFITSIO_INCLUDE_FILES
+ environment variable. Finally try to open fname
+ relative to ngp_master_dir, which is directory of top
+ level include file
+*/
+
+int ngp_include_file(char *fname) /* try to open include file */
+ { char *p, *p2, *cp, *envar, envfiles[NGP_MAX_ENVFILES];
+
+ if (NULL == fname) return(NGP_NUL_PTR);
+
+ if (ngp_inclevel >= NGP_MAX_INCLUDE) /* too many include files */
+ return(NGP_INC_NESTING);
+
+ if (NULL == (ngp_fp[ngp_inclevel] = fopen(fname, "r")))
+ { /* if simple open failed .. */
+ envar = getenv("CFITSIO_INCLUDE_FILES"); /* scan env. variable, and retry to open */
+
+ if (NULL != envar) /* is env. variable defined ? */
+ { strncpy(envfiles, envar, NGP_MAX_ENVFILES - 1);
+ envfiles[NGP_MAX_ENVFILES - 1] = 0; /* copy search path to local variable, env. is fragile */
+
+ for (p2 = strtok(envfiles, ":"); NULL != p2; p2 = strtok(NULL, ":"))
+ {
+ cp = (char *)ngp_alloc(strlen(fname) + strlen(p2) + 2);
+ if (NULL == cp) return(NGP_NO_MEMORY);
+
+ strcpy(cp, p2);
+#ifdef MSDOS
+ strcat(cp, "\\"); /* abs. pathname for MSDOS */
+
+#else
+ strcat(cp, "/"); /* and for unix */
+#endif
+ strcat(cp, fname);
+
+ ngp_fp[ngp_inclevel] = fopen(cp, "r");
+ ngp_free(cp);
+
+ if (NULL != ngp_fp[ngp_inclevel]) break;
+ }
+ }
+
+ if (NULL == ngp_fp[ngp_inclevel]) /* finally try to open relative to top level */
+ {
+#ifdef MSDOS
+ if ('\\' == fname[0]) return(NGP_ERR_FOPEN); /* abs. pathname for MSDOS, does not support C:\\PATH */
+#else
+ if ('/' == fname[0]) return(NGP_ERR_FOPEN); /* and for unix */
+#endif
+ if (0 == ngp_master_dir[0]) return(NGP_ERR_FOPEN);
+
+ p = ngp_alloc(strlen(fname) + strlen(ngp_master_dir) + 1);
+ if (NULL == p) return(NGP_NO_MEMORY);
+
+ strcpy(p, ngp_master_dir); /* construct composite pathname */
+ strcat(p, fname); /* comp = master + fname */
+
+ ngp_fp[ngp_inclevel] = fopen(p, "r");/* try to open composite */
+ ngp_free(p); /* we don't need buffer anymore */
+
+ if (NULL == ngp_fp[ngp_inclevel])
+ return(NGP_ERR_FOPEN); /* fail if error */
+ }
+ }
+
+ ngp_inclevel++;
+ return(NGP_OK);
+ }
+
+
+/* read line in the intelligent way. All \INCLUDE directives are handled,
+ empty and comment line skipped. If this function returns NGP_OK, than
+ decomposed line (name, type, value in proper type and comment) are
+ stored in ngp_linkey structure. ignore_blank_lines parameter is zero
+ when parser is inside GROUP or HDU definition. Nonzero otherwise.
+*/
+
+int ngp_read_line(int ignore_blank_lines)
+ { int r, nc;
+ unsigned k;
+
+ if (ngp_inclevel <= 0) /* do some sanity checking first */
+ { ngp_keyidx = NGP_TOKEN_EOF; /* no parents, so report error */
+ return(NGP_OK);
+ }
+ if (ngp_inclevel > NGP_MAX_INCLUDE) return(NGP_INC_NESTING);
+ if (NULL == ngp_fp[ngp_inclevel - 1]) return(NGP_NUL_PTR);
+
+ for (;;)
+ { switch (r = ngp_read_line_buffered(ngp_fp[ngp_inclevel - 1]))
+ { case NGP_EOF:
+ ngp_inclevel--; /* end of file, revert to parent */
+ if (ngp_fp[ngp_inclevel]) /* we can close old file */
+ fclose(ngp_fp[ngp_inclevel]);
+
+ ngp_fp[ngp_inclevel] = NULL;
+ if (ngp_inclevel <= 0)
+ { ngp_keyidx = NGP_TOKEN_EOF; /* no parents, so report error */
+ return(NGP_OK);
+ }
+ continue;
+
+ case NGP_OK:
+ if (ngp_curline.flags & NGP_LINE_REREAD) return(r);
+ break;
+ default:
+ return(r);
+ }
+
+ switch (ngp_curline.line[0])
+ { case 0: if (0 == ignore_blank_lines) break; /* ignore empty lines if told so */
+ case '#': continue; /* ignore comment lines */
+ }
+
+ r = ngp_extract_tokens(&ngp_curline); /* analyse line, extract tokens and comment */
+ if (NGP_OK != r) return(r);
+
+ if (NULL == ngp_curline.name) continue; /* skip lines consisting only of whitespaces */
+
+ for (k = 0; k < strlen(ngp_curline.name); k++)
+ { if ((ngp_curline.name[k] >= 'a') && (ngp_curline.name[k] <= 'z'))
+ ngp_curline.name[k] += 'A' - 'a'; /* force keyword to be upper case */
+ if (k == 7) break; /* only first 8 chars are required to be upper case */
+ }
+
+ for (k=0;; k++) /* find index of keyword in keyword table */
+ { if (NGP_TOKEN_UNKNOWN == ngp_tkdef[k].code) break;
+ if (0 == strcmp(ngp_curline.name, ngp_tkdef[k].name)) break;
+ }
+
+ ngp_keyidx = ngp_tkdef[k].code; /* save this index, grammar parser will need this */
+
+ if (NGP_TOKEN_INCLUDE == ngp_keyidx) /* if this is \INCLUDE keyword, try to include file */
+ { if (NGP_OK != (r = ngp_include_file(ngp_curline.value))) return(r);
+ continue; /* and read next line */
+ }
+
+ ngp_linkey.type = NGP_TTYPE_UNKNOWN; /* now, get the keyword type, it's a long story ... */
+
+ if (NULL != ngp_curline.value) /* if no value given signal it */
+ { if (NGP_TTYPE_STRING == ngp_curline.type) /* string type test */
+ { ngp_linkey.type = NGP_TTYPE_STRING;
+ ngp_linkey.value.s = ngp_curline.value;
+ }
+ if (NGP_TTYPE_UNKNOWN == ngp_linkey.type) /* bool type test */
+ { if ((!ngp_strcasecmp("T", ngp_curline.value)) || (!ngp_strcasecmp("F", ngp_curline.value)))
+ { ngp_linkey.type = NGP_TTYPE_BOOL;
+ ngp_linkey.value.b = (ngp_strcasecmp("T", ngp_curline.value) ? 0 : 1);
+ }
+ }
+ if (NGP_TTYPE_UNKNOWN == ngp_linkey.type) /* complex type test */
+ { if (2 == sscanf(ngp_curline.value, "(%lg,%lg)%n", &(ngp_linkey.value.c.re), &(ngp_linkey.value.c.im), &nc))
+ { if ((' ' == ngp_curline.value[nc]) || ('\t' == ngp_curline.value[nc])
+ || ('\n' == ngp_curline.value[nc]) || (0 == ngp_curline.value[nc]))
+ { ngp_linkey.type = NGP_TTYPE_COMPLEX;
+ }
+ }
+ }
+ if (NGP_TTYPE_UNKNOWN == ngp_linkey.type) /* real type test */
+ { if (strchr(ngp_curline.value, '.') && (1 == sscanf(ngp_curline.value, "%lg%n", &(ngp_linkey.value.d), &nc)))
+ { if ((' ' == ngp_curline.value[nc]) || ('\t' == ngp_curline.value[nc])
+ || ('\n' == ngp_curline.value[nc]) || (0 == ngp_curline.value[nc]))
+ { ngp_linkey.type = NGP_TTYPE_REAL;
+ }
+ }
+ }
+ if (NGP_TTYPE_UNKNOWN == ngp_linkey.type) /* integer type test */
+ { if (1 == sscanf(ngp_curline.value, "%d%n", &(ngp_linkey.value.i), &nc))
+ { if ((' ' == ngp_curline.value[nc]) || ('\t' == ngp_curline.value[nc])
+ || ('\n' == ngp_curline.value[nc]) || (0 == ngp_curline.value[nc]))
+ { ngp_linkey.type = NGP_TTYPE_INT;
+ }
+ }
+ }
+ if (NGP_TTYPE_UNKNOWN == ngp_linkey.type) /* force string type */
+ { ngp_linkey.type = NGP_TTYPE_STRING;
+ ngp_linkey.value.s = ngp_curline.value;
+ }
+ }
+ else
+ { if (NGP_TTYPE_RAW == ngp_curline.type) ngp_linkey.type = NGP_TTYPE_RAW;
+ else ngp_linkey.type = NGP_TTYPE_NULL;
+ }
+
+ if (NULL != ngp_curline.comment)
+ { strncpy(ngp_linkey.comment, ngp_curline.comment, NGP_MAX_COMMENT); /* store comment */
+ ngp_linkey.comment[NGP_MAX_COMMENT - 1] = 0;
+ }
+ else
+ { ngp_linkey.comment[0] = 0;
+ }
+
+ strncpy(ngp_linkey.name, ngp_curline.name, NGP_MAX_NAME); /* and keyword's name */
+ ngp_linkey.name[NGP_MAX_NAME - 1] = 0;
+
+ if (strlen(ngp_linkey.name) > FLEN_KEYWORD) /* WDP: 20-Jun-2002: mod to support HIERARCH */
+ {
+ return(NGP_BAD_ARG); /* cfitsio does not allow names > 8 chars */
+ }
+
+ return(NGP_OK); /* we have valid non empty line, so return success */
+ }
+ }
+
+ /* check whether keyword can be written as is */
+
+int ngp_keyword_is_write(NGP_TOKEN *ngp_tok)
+ { int i, j, r, l, spc;
+ /* indexed variables not to write */
+
+ static char *nm[] = { "NAXIS", "TFORM", "TTYPE", NULL } ;
+
+ /* non indexed variables not allowed to write */
+
+ static char *nmni[] = { "SIMPLE", "XTENSION", "BITPIX", "NAXIS", "PCOUNT",
+ "GCOUNT", "TFIELDS", "THEAP", "EXTEND", "EXTVER",
+ NULL } ;
+
+ if (NULL == ngp_tok) return(NGP_NUL_PTR);
+ r = NGP_OK;
+
+ for (j = 0; ; j++) /* first check non indexed */
+ { if (NULL == nmni[j]) break;
+ if (0 == strcmp(nmni[j], ngp_tok->name)) return(NGP_BAD_ARG);
+ }
+
+ for (j = 0; ; j++) /* now check indexed */
+ { if (NULL == nm[j]) return(NGP_OK);
+ l = strlen(nm[j]);
+ if ((l < 1) || (l > 5)) continue;
+ if (0 == strncmp(nm[j], ngp_tok->name, l)) break;
+ }
+
+ if ((ngp_tok->name[l] < '1') || (ngp_tok->name[l] > '9')) return(NGP_OK);
+ spc = 0;
+ for (i = l + 1; i < 8; i++)
+ { if (spc) { if (' ' != ngp_tok->name[i]) return(NGP_OK); }
+ else
+ { if ((ngp_tok->name[i] >= '0') || (ngp_tok->name[i] <= '9')) continue;
+ if (' ' == ngp_tok->name[i]) { spc = 1; continue; }
+ if (0 == ngp_tok->name[i]) break;
+ return(NGP_OK);
+ }
+ }
+ return(NGP_BAD_ARG);
+ }
+
+ /* write (almost) all keywords from given HDU to disk */
+
+int ngp_keyword_all_write(NGP_HDU *ngph, fitsfile *ffp, int mode)
+ { int i, r, ib;
+ char buf[200];
+ long l;
+
+
+ if (NULL == ngph) return(NGP_NUL_PTR);
+ if (NULL == ffp) return(NGP_NUL_PTR);
+ r = NGP_OK;
+
+ for (i=0; i<ngph->tokcnt; i++)
+ { r = ngp_keyword_is_write(&(ngph->tok[i]));
+ if ((NGP_REALLY_ALL & mode) || (NGP_OK == r))
+ { switch (ngph->tok[i].type)
+ { case NGP_TTYPE_BOOL:
+ ib = ngph->tok[i].value.b;
+ fits_write_key(ffp, TLOGICAL, ngph->tok[i].name, &ib, ngph->tok[i].comment, &r);
+ break;
+ case NGP_TTYPE_STRING:
+ fits_write_key_longstr(ffp, ngph->tok[i].name, ngph->tok[i].value.s, ngph->tok[i].comment, &r);
+ break;
+ case NGP_TTYPE_INT:
+ l = ngph->tok[i].value.i; /* bugfix - 22-Jan-99, BO - nonalignment of OSF/Alpha */
+ fits_write_key(ffp, TLONG, ngph->tok[i].name, &l, ngph->tok[i].comment, &r);
+ break;
+ case NGP_TTYPE_REAL:
+ fits_write_key(ffp, TDOUBLE, ngph->tok[i].name, &(ngph->tok[i].value.d), ngph->tok[i].comment, &r);
+ break;
+ case NGP_TTYPE_COMPLEX:
+ fits_write_key(ffp, TDBLCOMPLEX, ngph->tok[i].name, &(ngph->tok[i].value.c), ngph->tok[i].comment, &r);
+ break;
+ case NGP_TTYPE_NULL:
+ fits_write_key_null(ffp, ngph->tok[i].name, ngph->tok[i].comment, &r);
+ break;
+ case NGP_TTYPE_RAW:
+ if (0 == strcmp("HISTORY", ngph->tok[i].name))
+ { fits_write_history(ffp, ngph->tok[i].comment, &r);
+ break;
+ }
+ if (0 == strcmp("COMMENT", ngph->tok[i].name))
+ { fits_write_comment(ffp, ngph->tok[i].comment, &r);
+ break;
+ }
+ sprintf(buf, "%-8.8s%s", ngph->tok[i].name, ngph->tok[i].comment);
+ fits_write_record(ffp, buf, &r);
+ break;
+ }
+ }
+ else if (NGP_BAD_ARG == r) /* enhancement 10 dec 2003, James Peachey: template comments replace defaults */
+ { r = NGP_OK; /* update comments of special keywords like TFORM */
+ if (ngph->tok[i].comment && *ngph->tok[i].comment) /* do not update with a blank comment */
+ { fits_modify_comment(ffp, ngph->tok[i].name, ngph->tok[i].comment, &r);
+ }
+ }
+ else /* other problem, typically a blank token */
+ { r = NGP_OK; /* skip this token, but continue */
+ }
+ if (r) return(r);
+ }
+
+ fits_set_hdustruc(ffp, &r); /* resync cfitsio */
+ return(r);
+ }
+
+ /* init HDU structure */
+
+int ngp_hdu_init(NGP_HDU *ngph)
+ { if (NULL == ngph) return(NGP_NUL_PTR);
+ ngph->tok = NULL;
+ ngph->tokcnt = 0;
+ return(NGP_OK);
+ }
+
+ /* clear HDU structure */
+
+int ngp_hdu_clear(NGP_HDU *ngph)
+ { int i;
+
+ if (NULL == ngph) return(NGP_NUL_PTR);
+
+ for (i=0; i<ngph->tokcnt; i++)
+ { if (NGP_TTYPE_STRING == ngph->tok[i].type)
+ if (NULL != ngph->tok[i].value.s)
+ { ngp_free(ngph->tok[i].value.s);
+ ngph->tok[i].value.s = NULL;
+ }
+ }
+
+ if (NULL != ngph->tok) ngp_free(ngph->tok);
+
+ ngph->tok = NULL;
+ ngph->tokcnt = 0;
+
+ return(NGP_OK);
+ }
+
+ /* insert new token to HDU structure */
+
+int ngp_hdu_insert_token(NGP_HDU *ngph, NGP_TOKEN *newtok)
+ { NGP_TOKEN *tkp;
+
+ if (NULL == ngph) return(NGP_NUL_PTR);
+ if (NULL == newtok) return(NGP_NUL_PTR);
+
+ if (0 == ngph->tokcnt)
+ tkp = (NGP_TOKEN *)ngp_alloc((ngph->tokcnt + 1) * sizeof(NGP_TOKEN));
+ else
+ tkp = (NGP_TOKEN *)ngp_realloc(ngph->tok, (ngph->tokcnt + 1) * sizeof(NGP_TOKEN));
+
+ if (NULL == tkp) return(NGP_NO_MEMORY);
+
+ ngph->tok = tkp;
+ ngph->tok[ngph->tokcnt] = *newtok;
+
+ if (NGP_TTYPE_STRING == newtok->type)
+ { if (NULL != newtok->value.s)
+ { ngph->tok[ngph->tokcnt].value.s = (char *)ngp_alloc(1 + strlen(newtok->value.s));
+ if (NULL == ngph->tok[ngph->tokcnt].value.s) return(NGP_NO_MEMORY);
+ strcpy(ngph->tok[ngph->tokcnt].value.s, newtok->value.s);
+ }
+ }
+
+ ngph->tokcnt++;
+ return(NGP_OK);
+ }
+
+
+int ngp_append_columns(fitsfile *ff, NGP_HDU *ngph, int aftercol)
+ { int r, i, j, exitflg, ngph_i;
+ char *my_tform, *my_ttype;
+ char ngph_ctmp;
+
+
+ if (NULL == ff) return(NGP_NUL_PTR);
+ if (NULL == ngph) return(NGP_NUL_PTR);
+ if (0 == ngph->tokcnt) return(NGP_OK); /* nothing to do ! */
+
+ r = NGP_OK;
+ exitflg = 0;
+
+ for (j=aftercol; j<NGP_MAX_ARRAY_DIM; j++) /* 0 for table, 6 for group */
+ {
+ my_tform = NULL;
+ my_ttype = "";
+
+ for (i=0; ; i++)
+ { if (1 == sscanf(ngph->tok[i].name, "TFORM%d%c", &ngph_i, &ngph_ctmp))
+ { if ((NGP_TTYPE_STRING == ngph->tok[i].type) && (ngph_i == (j + 1)))
+ { my_tform = ngph->tok[i].value.s;
+ }
+ }
+ else if (1 == sscanf(ngph->tok[i].name, "TTYPE%d%c", &ngph_i, &ngph_ctmp))
+ { if ((NGP_TTYPE_STRING == ngph->tok[i].type) && (ngph_i == (j + 1)))
+ { my_ttype = ngph->tok[i].value.s;
+ }
+ }
+
+ if ((NULL != my_tform) && (my_ttype[0])) break;
+
+ if (i < (ngph->tokcnt - 1)) continue;
+ exitflg = 1;
+ break;
+ }
+ if ((NGP_OK == r) && (NULL != my_tform))
+ fits_insert_col(ff, j + 1, my_ttype, my_tform, &r);
+
+ if ((NGP_OK != r) || exitflg) break;
+ }
+ return(r);
+ }
+
+ /* read complete HDU */
+
+int ngp_read_xtension(fitsfile *ff, int parent_hn, int simple_mode)
+ { int r, exflg, l, my_hn, tmp0, incrementor_index, i, j;
+ int ngph_dim, ngph_bitpix, ngph_node_type, my_version;
+ char incrementor_name[NGP_MAX_STRING], ngph_ctmp;
+ char *ngph_extname = 0;
+ long ngph_size[NGP_MAX_ARRAY_DIM];
+ NGP_HDU ngph;
+ long lv;
+
+ incrementor_name[0] = 0; /* signal no keyword+'#' found yet */
+ incrementor_index = 0;
+
+ if (NGP_OK != (r = ngp_hdu_init(&ngph))) return(r);
+
+ if (NGP_OK != (r = ngp_read_line(0))) return(r); /* EOF always means error here */
+ switch (NGP_XTENSION_SIMPLE & simple_mode)
+ {
+ case 0: if (NGP_TOKEN_XTENSION != ngp_keyidx) return(NGP_TOKEN_NOT_EXPECT);
+ break;
+ default: if (NGP_TOKEN_SIMPLE != ngp_keyidx) return(NGP_TOKEN_NOT_EXPECT);
+ break;
+ }
+
+ if (NGP_OK != (r = ngp_hdu_insert_token(&ngph, &ngp_linkey))) return(r);
+
+ for (;;)
+ { if (NGP_OK != (r = ngp_read_line(0))) return(r); /* EOF always means error here */
+ exflg = 0;
+ switch (ngp_keyidx)
+ {
+ case NGP_TOKEN_SIMPLE:
+ r = NGP_TOKEN_NOT_EXPECT;
+ break;
+
+ case NGP_TOKEN_END:
+ case NGP_TOKEN_XTENSION:
+ case NGP_TOKEN_GROUP:
+ r = ngp_unread_line(); /* WARNING - not break here .... */
+ case NGP_TOKEN_EOF:
+ exflg = 1;
+ break;
+
+ default: l = strlen(ngp_linkey.name);
+ if ((l >= 2) && (l <= 6))
+ { if ('#' == ngp_linkey.name[l - 1])
+ { if (0 == incrementor_name[0])
+ { memcpy(incrementor_name, ngp_linkey.name, l - 1);
+ incrementor_name[l - 1] = 0;
+ }
+ if (((l - 1) == (int)strlen(incrementor_name)) && (0 == memcmp(incrementor_name, ngp_linkey.name, l - 1)))
+ { incrementor_index++;
+ }
+ sprintf(ngp_linkey.name + l - 1, "%d", incrementor_index);
+ }
+ }
+ r = ngp_hdu_insert_token(&ngph, &ngp_linkey);
+ break;
+ }
+ if ((NGP_OK != r) || exflg) break;
+ }
+
+ if (NGP_OK == r)
+ { /* we should scan keywords, and calculate HDU's */
+ /* structure ourselves .... */
+
+ ngph_node_type = NGP_NODE_INVALID; /* init variables */
+ ngph_bitpix = 0;
+ ngph_extname = NULL;
+ for (i=0; i<NGP_MAX_ARRAY_DIM; i++) ngph_size[i] = 0;
+ ngph_dim = 0;
+
+ for (i=0; i<ngph.tokcnt; i++)
+ { if (!strcmp("XTENSION", ngph.tok[i].name))
+ { if (NGP_TTYPE_STRING == ngph.tok[i].type)
+ { if (!ngp_strcasencmp("BINTABLE", ngph.tok[i].value.s,8)) ngph_node_type = NGP_NODE_BTABLE;
+ if (!ngp_strcasencmp("TABLE", ngph.tok[i].value.s,5)) ngph_node_type = NGP_NODE_ATABLE;
+ if (!ngp_strcasencmp("IMAGE", ngph.tok[i].value.s,5)) ngph_node_type = NGP_NODE_IMAGE;
+ }
+ }
+ else if (!strcmp("SIMPLE", ngph.tok[i].name))
+ { if (NGP_TTYPE_BOOL == ngph.tok[i].type)
+ { if (ngph.tok[i].value.b) ngph_node_type = NGP_NODE_IMAGE;
+ }
+ }
+ else if (!strcmp("BITPIX", ngph.tok[i].name))
+ { if (NGP_TTYPE_INT == ngph.tok[i].type) ngph_bitpix = ngph.tok[i].value.i;
+ }
+ else if (!strcmp("NAXIS", ngph.tok[i].name))
+ { if (NGP_TTYPE_INT == ngph.tok[i].type) ngph_dim = ngph.tok[i].value.i;
+ }
+ else if (!strcmp("EXTNAME", ngph.tok[i].name)) /* assign EXTNAME, I hope struct does not move */
+ { if (NGP_TTYPE_STRING == ngph.tok[i].type) ngph_extname = ngph.tok[i].value.s;
+ }
+ else if (1 == sscanf(ngph.tok[i].name, "NAXIS%d%c", &j, &ngph_ctmp))
+ { if (NGP_TTYPE_INT == ngph.tok[i].type)
+ if ((j>=1) && (j <= NGP_MAX_ARRAY_DIM))
+ { ngph_size[j - 1] = ngph.tok[i].value.i;
+ }
+ }
+ }
+
+ switch (ngph_node_type)
+ { case NGP_NODE_IMAGE:
+ if (NGP_XTENSION_FIRST == ((NGP_XTENSION_FIRST | NGP_XTENSION_SIMPLE) & simple_mode))
+ { /* if caller signals that this is 1st HDU in file */
+ /* and it is IMAGE defined with XTENSION, then we */
+ /* need create dummy Primary HDU */
+ fits_create_img(ff, 16, 0, NULL, &r);
+ }
+ /* create image */
+ fits_create_img(ff, ngph_bitpix, ngph_dim, ngph_size, &r);
+
+ /* update keywords */
+ if (NGP_OK == r) r = ngp_keyword_all_write(&ngph, ff, NGP_NON_SYSTEM_ONLY);
+ break;
+
+ case NGP_NODE_ATABLE:
+ case NGP_NODE_BTABLE:
+ /* create table, 0 rows and 0 columns for the moment */
+ fits_create_tbl(ff, ((NGP_NODE_ATABLE == ngph_node_type)
+ ? ASCII_TBL : BINARY_TBL),
+ 0, 0, NULL, NULL, NULL, NULL, &r);
+ if (NGP_OK != r) break;
+
+ /* add columns ... */
+ r = ngp_append_columns(ff, &ngph, 0);
+ if (NGP_OK != r) break;
+
+ /* add remaining keywords */
+ r = ngp_keyword_all_write(&ngph, ff, NGP_NON_SYSTEM_ONLY);
+ if (NGP_OK != r) break;
+
+ /* if requested add rows */
+ if (ngph_size[1] > 0) fits_insert_rows(ff, 0, ngph_size[1], &r);
+ break;
+
+ default: r = NGP_BAD_ARG;
+ break;
+ }
+
+ }
+
+ if ((NGP_OK == r) && (NULL != ngph_extname))
+ { r = ngp_get_extver(ngph_extname, &my_version); /* write correct ext version number */
+ lv = my_version; /* bugfix - 22-Jan-99, BO - nonalignment of OSF/Alpha */
+ fits_write_key(ff, TLONG, "EXTVER", &lv, "auto assigned by template parser", &r);
+ }
+
+ if (NGP_OK == r)
+ { if (parent_hn > 0)
+ { fits_get_hdu_num(ff, &my_hn);
+ fits_movabs_hdu(ff, parent_hn, &tmp0, &r); /* link us to parent */
+ fits_add_group_member(ff, NULL, my_hn, &r);
+ fits_movabs_hdu(ff, my_hn, &tmp0, &r);
+ if (NGP_OK != r) return(r);
+ }
+ }
+
+ if (NGP_OK != r) /* in case of error - delete hdu */
+ { tmp0 = 0;
+ fits_delete_hdu(ff, NULL, &tmp0);
+ }
+
+ ngp_hdu_clear(&ngph);
+ return(r);
+ }
+
+ /* read complete GROUP */
+
+int ngp_read_group(fitsfile *ff, char *grpname, int parent_hn)
+ { int r, exitflg, l, my_hn, tmp0, incrementor_index;
+ char grnm[NGP_MAX_STRING]; /* keyword holding group name */
+ char incrementor_name[NGP_MAX_STRING];
+ NGP_HDU ngph;
+
+ incrementor_name[0] = 0; /* signal no keyword+'#' found yet */
+ incrementor_index = 6; /* first 6 cols are used by group */
+
+ ngp_grplevel++;
+ if (NGP_OK != (r = ngp_hdu_init(&ngph))) return(r);
+
+ r = NGP_OK;
+ if (NGP_OK != (r = fits_create_group(ff, grpname, GT_ID_ALL_URI, &r))) return(r);
+ fits_get_hdu_num(ff, &my_hn);
+ if (parent_hn > 0)
+ { fits_movabs_hdu(ff, parent_hn, &tmp0, &r); /* link us to parent */
+ fits_add_group_member(ff, NULL, my_hn, &r);
+ fits_movabs_hdu(ff, my_hn, &tmp0, &r);
+ if (NGP_OK != r) return(r);
+ }
+
+ for (exitflg = 0; 0 == exitflg;)
+ { if (NGP_OK != (r = ngp_read_line(0))) break; /* EOF always means error here */
+ switch (ngp_keyidx)
+ {
+ case NGP_TOKEN_SIMPLE:
+ case NGP_TOKEN_EOF:
+ r = NGP_TOKEN_NOT_EXPECT;
+ break;
+
+ case NGP_TOKEN_END:
+ ngp_grplevel--;
+ exitflg = 1;
+ break;
+
+ case NGP_TOKEN_GROUP:
+ if (NGP_TTYPE_STRING == ngp_linkey.type)
+ { strncpy(grnm, ngp_linkey.value.s, NGP_MAX_STRING);
+ }
+ else
+ { sprintf(grnm, "DEFAULT_GROUP_%d", master_grp_idx++);
+ }
+ grnm[NGP_MAX_STRING - 1] = 0;
+ r = ngp_read_group(ff, grnm, my_hn);
+ break; /* we can have many subsequent GROUP defs */
+
+ case NGP_TOKEN_XTENSION:
+ r = ngp_unread_line();
+ if (NGP_OK != r) break;
+ r = ngp_read_xtension(ff, my_hn, 0);
+ break; /* we can have many subsequent HDU defs */
+
+ default: l = strlen(ngp_linkey.name);
+ if ((l >= 2) && (l <= 6))
+ { if ('#' == ngp_linkey.name[l - 1])
+ { if (0 == incrementor_name[0])
+ { memcpy(incrementor_name, ngp_linkey.name, l - 1);
+ incrementor_name[l - 1] = 0;
+ }
+ if (((l - 1) == (int)strlen(incrementor_name)) && (0 == memcmp(incrementor_name, ngp_linkey.name, l - 1)))
+ { incrementor_index++;
+ }
+ sprintf(ngp_linkey.name + l - 1, "%d", incrementor_index);
+ }
+ }
+ r = ngp_hdu_insert_token(&ngph, &ngp_linkey);
+ break; /* here we can add keyword */
+ }
+ if (NGP_OK != r) break;
+ }
+
+ fits_movabs_hdu(ff, my_hn, &tmp0, &r); /* back to our HDU */
+
+ if (NGP_OK == r) /* create additional columns, if requested */
+ r = ngp_append_columns(ff, &ngph, 6);
+
+ if (NGP_OK == r) /* and write keywords */
+ r = ngp_keyword_all_write(&ngph, ff, NGP_NON_SYSTEM_ONLY);
+
+ if (NGP_OK != r) /* delete group in case of error */
+ { tmp0 = 0;
+ fits_remove_group(ff, OPT_RM_GPT, &tmp0);
+ }
+
+ ngp_hdu_clear(&ngph); /* we are done with this HDU, so delete it */
+ return(r);
+ }
+
+ /* top level API functions */
+
+/* read whole template. ff should point to the opened empty fits file. */
+
+int fits_execute_template(fitsfile *ff, char *ngp_template, int *status)
+ { int r, exit_flg, first_extension, i, my_hn, tmp0, keys_exist, more_keys, used_ver;
+ char grnm[NGP_MAX_STRING], used_name[NGP_MAX_STRING];
+ long luv;
+
+ if (NULL == status) return(NGP_NUL_PTR);
+ if (NGP_OK != *status) return(*status);
+
+ if ((NULL == ff) || (NULL == ngp_template))
+ { *status = NGP_NUL_PTR;
+ return(*status);
+ }
+
+ ngp_inclevel = 0; /* initialize things, not all should be zero */
+ ngp_grplevel = 0;
+ master_grp_idx = 1;
+ exit_flg = 0;
+ ngp_master_dir[0] = 0; /* this should be before 1st call to ngp_include_file */
+ first_extension = 1; /* we need to create PHDU */
+
+ if (NGP_OK != (r = ngp_delete_extver_tab()))
+ { *status = r;
+ return(r);
+ }
+
+ fits_get_hdu_num(ff, &my_hn); /* our HDU position */
+ if (my_hn <= 1) /* check whether we really need to create PHDU */
+ { fits_movabs_hdu(ff, 1, &tmp0, status);
+ fits_get_hdrspace(ff, &keys_exist, &more_keys, status);
+ fits_movabs_hdu(ff, my_hn, &tmp0, status);
+ if (NGP_OK != *status) return(*status); /* error here means file is corrupted */
+ if (keys_exist > 0) first_extension = 0; /* if keywords exist assume PHDU already exist */
+ }
+ else
+ { first_extension = 0; /* PHDU (followed by 1+ extensions) exist */
+
+ for (i = 2; i<= my_hn; i++)
+ { *status = NGP_OK;
+ fits_movabs_hdu(ff, 1, &tmp0, status);
+ if (NGP_OK != *status) break;
+
+ fits_read_key(ff, TSTRING, "EXTNAME", used_name, NULL, status);
+ if (NGP_OK != *status) continue;
+
+ fits_read_key(ff, TLONG, "EXTVER", &luv, NULL, status);
+ used_ver = luv; /* bugfix - 22-Jan-99, BO - nonalignment of OSF/Alpha */
+ if (VALUE_UNDEFINED == *status)
+ { used_ver = 1;
+ *status = NGP_OK;
+ }
+
+ if (NGP_OK == *status) *status = ngp_set_extver(used_name, used_ver);
+ }
+
+ fits_movabs_hdu(ff, my_hn, &tmp0, status);
+ }
+ if (NGP_OK != *status) return(*status);
+
+ if (NGP_OK != (*status = ngp_include_file(ngp_template))) return(*status);
+
+ for (i = strlen(ngp_template) - 1; i >= 0; i--) /* strlen is > 0, otherwise fopen failed */
+ {
+#ifdef MSDOS
+ if ('\\' == ngp_template[i]) break;
+#else
+ if ('/' == ngp_template[i]) break;
+#endif
+ }
+
+ i++;
+ if (i > (NGP_MAX_FNAME - 1)) i = NGP_MAX_FNAME - 1;
+
+ if (i > 0)
+ { memcpy(ngp_master_dir, ngp_template, i);
+ ngp_master_dir[i] = 0;
+ }
+
+
+ for (;;)
+ { if (NGP_OK != (r = ngp_read_line(1))) break; /* EOF always means error here */
+ switch (ngp_keyidx)
+ {
+ case NGP_TOKEN_SIMPLE:
+ if (0 == first_extension) /* simple only allowed in first HDU */
+ { r = NGP_TOKEN_NOT_EXPECT;
+ break;
+ }
+ if (NGP_OK != (r = ngp_unread_line())) break;
+ r = ngp_read_xtension(ff, 0, NGP_XTENSION_SIMPLE | NGP_XTENSION_FIRST);
+ first_extension = 0;
+ break;
+
+ case NGP_TOKEN_XTENSION:
+ if (NGP_OK != (r = ngp_unread_line())) break;
+ r = ngp_read_xtension(ff, 0, (first_extension ? NGP_XTENSION_FIRST : 0));
+ first_extension = 0;
+ break;
+
+ case NGP_TOKEN_GROUP:
+ if (NGP_TTYPE_STRING == ngp_linkey.type)
+ { strncpy(grnm, ngp_linkey.value.s, NGP_MAX_STRING); }
+ else
+ { sprintf(grnm, "DEFAULT_GROUP_%d", master_grp_idx++); }
+ grnm[NGP_MAX_STRING - 1] = 0;
+ r = ngp_read_group(ff, grnm, 0);
+ first_extension = 0;
+ break;
+
+ case NGP_TOKEN_EOF:
+ exit_flg = 1;
+ break;
+
+ default: r = NGP_TOKEN_NOT_EXPECT;
+ break;
+ }
+ if (exit_flg || (NGP_OK != r)) break;
+ }
+
+/* all top level HDUs up to faulty one are left intact in case of i/o error. It is up
+ to the caller to call fits_close_file or fits_delete_file when this function returns
+ error. */
+
+ ngp_free_line(); /* deallocate last line (if any) */
+ ngp_free_prevline(); /* deallocate cached line (if any) */
+ ngp_delete_extver_tab(); /* delete extver table (if present), error ignored */
+
+ *status = r;
+ return(r);
+ }
diff --git a/pkg/tbtables/cfitsio/grparser.h b/pkg/tbtables/cfitsio/grparser.h
new file mode 100644
index 00000000..56bdea03
--- /dev/null
+++ b/pkg/tbtables/cfitsio/grparser.h
@@ -0,0 +1,185 @@
+/* T E M P L A T E P A R S E R H E A D E R F I L E
+ =====================================================
+
+ by Jerzy.Borkowski@obs.unige.ch
+
+ Integral Science Data Center
+ ch. d'Ecogia 16
+ 1290 Versoix
+ Switzerland
+
+14-Oct-98: initial release
+16-Oct-98: reference to fitsio.h removed, also removed strings after #endif
+ directives to make gcc -Wall not to complain
+20-Oct-98: added declarations NGP_XTENSION_SIMPLE and NGP_XTENSION_FIRST
+24-Oct-98: prototype of ngp_read_line() function updated.
+22-Jan-99: prototype for ngp_set_extver() function added.
+20-Jun-2002 Wm Pence, added support for the HIERARCH keyword convention
+ (changed NGP_MAX_NAME from (20) to FLEN_KEYWORD)
+*/
+
+#ifndef GRPARSER_H_INCLUDED
+#define GRPARSER_H_INCLUDED
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ /* error codes - now defined in fitsio.h */
+
+ /* common constants definitions */
+
+#define NGP_ALLOCCHUNK (1000)
+#define NGP_MAX_INCLUDE (10) /* include file nesting limit */
+#define NGP_MAX_COMMENT (80) /* max size for comment */
+#define NGP_MAX_NAME FLEN_KEYWORD /* max size for KEYWORD (FITS limits it to 8 chars) */
+ /* except HIERARCH can have longer effective keyword names */
+#define NGP_MAX_STRING (80) /* max size for various strings */
+#define NGP_MAX_ARRAY_DIM (999) /* max. number of dimensions in array */
+#define NGP_MAX_FNAME (1000) /* max size of combined path+fname */
+#define NGP_MAX_ENVFILES (10000) /* max size of CFITSIO_INCLUDE_FILES env. variable */
+
+#define NGP_TOKEN_UNKNOWN (-1) /* token type unknown */
+#define NGP_TOKEN_INCLUDE (0) /* \INCLUDE token */
+#define NGP_TOKEN_GROUP (1) /* \GROUP token */
+#define NGP_TOKEN_END (2) /* \END token */
+#define NGP_TOKEN_XTENSION (3) /* XTENSION token */
+#define NGP_TOKEN_SIMPLE (4) /* SIMPLE token */
+#define NGP_TOKEN_EOF (5) /* End Of File pseudo token */
+
+#define NGP_TTYPE_UNKNOWN (0) /* undef (yet) token type - invalid to print/write to disk */
+#define NGP_TTYPE_BOOL (1) /* boolean, it is 'T' or 'F' */
+#define NGP_TTYPE_STRING (2) /* something withing "" or starting with letter */
+#define NGP_TTYPE_INT (3) /* starting with digit and not with '.' */
+#define NGP_TTYPE_REAL (4) /* digits + '.' */
+#define NGP_TTYPE_COMPLEX (5) /* 2 reals, separated with ',' */
+#define NGP_TTYPE_NULL (6) /* NULL token, format is : NAME = / comment */
+#define NGP_TTYPE_RAW (7) /* HISTORY/COMMENT/8SPACES + comment string without / */
+
+#define NGP_FOUND_EQUAL_SIGN (1) /* line contains '=' after keyword name */
+
+#define NGP_FORMAT_OK (0) /* line format OK */
+#define NGP_FORMAT_ERROR (1) /* line format error */
+
+#define NGP_NODE_INVALID (0) /* default node type - invalid (to catch errors) */
+#define NGP_NODE_IMAGE (1) /* IMAGE type */
+#define NGP_NODE_ATABLE (2) /* ASCII table type */
+#define NGP_NODE_BTABLE (3) /* BINARY table type */
+
+#define NGP_NON_SYSTEM_ONLY (0) /* save all keywords except NAXIS,BITPIX,etc.. */
+#define NGP_REALLY_ALL (1) /* save really all keywords */
+
+#define NGP_XTENSION_SIMPLE (1) /* HDU defined with SIMPLE T */
+#define NGP_XTENSION_FIRST (2) /* this is first extension in template */
+
+#define NGP_LINE_REREAD (1) /* reread line */
+
+#define NGP_BITPIX_INVALID (-12345) /* default BITPIX (to catch errors) */
+
+ /* common macro definitions */
+
+#ifdef NGP_PARSER_DEBUG_MALLOC
+
+#define ngp_alloc(x) dal_malloc(x)
+#define ngp_free(x) dal_free(x)
+#define ngp_realloc(x,y) dal_realloc(x,y)
+
+#else
+
+#define ngp_alloc(x) malloc(x)
+#define ngp_free(x) free(x)
+#define ngp_realloc(x,y) realloc(x,y)
+
+#endif
+
+ /* type definitions */
+
+typedef struct NGP_RAW_LINE_STRUCT
+ { char *line;
+ char *name;
+ char *value;
+ int type;
+ char *comment;
+ int format;
+ int flags;
+ } NGP_RAW_LINE;
+
+
+typedef union NGP_TOKVAL_UNION
+ { char *s; /* space allocated separately, be careful !!! */
+ char b;
+ int i;
+ double d;
+ struct NGP_COMPLEX_STRUCT
+ { double re;
+ double im;
+ } c; /* complex value */
+ } NGP_TOKVAL;
+
+
+typedef struct NGP_TOKEN_STRUCT
+ { int type;
+ char name[NGP_MAX_NAME];
+ NGP_TOKVAL value;
+ char comment[NGP_MAX_COMMENT];
+ } NGP_TOKEN;
+
+
+typedef struct NGP_HDU_STRUCT
+ { int tokcnt;
+ NGP_TOKEN *tok;
+ } NGP_HDU;
+
+
+typedef struct NGP_TKDEF_STRUCT
+ { char *name;
+ int code;
+ } NGP_TKDEF;
+
+
+typedef struct NGP_EXTVER_TAB_STRUCT
+ { char *extname;
+ int version;
+ } NGP_EXTVER_TAB;
+
+
+ /* globally visible variables declarations */
+
+extern NGP_RAW_LINE ngp_curline;
+extern NGP_RAW_LINE ngp_prevline;
+
+extern int ngp_extver_tab_size;
+extern NGP_EXTVER_TAB *ngp_extver_tab;
+
+
+ /* globally visible functions declarations */
+
+int ngp_get_extver(char *extname, int *version);
+int ngp_set_extver(char *extname, int version);
+int ngp_delete_extver_tab(void);
+int ngp_strcasecmp(char *p1, char *p2);
+int ngp_strcasencmp(char *p1, char *p2, int n);
+int ngp_line_from_file(FILE *fp, char **p);
+int ngp_free_line(void);
+int ngp_free_prevline(void);
+int ngp_read_line_buffered(FILE *fp);
+int ngp_unread_line(void);
+int ngp_extract_tokens(NGP_RAW_LINE *cl);
+int ngp_include_file(char *fname);
+int ngp_read_line(int ignore_blank_lines);
+int ngp_keyword_is_write(NGP_TOKEN *ngp_tok);
+int ngp_keyword_all_write(NGP_HDU *ngph, fitsfile *ffp, int mode);
+int ngp_hdu_init(NGP_HDU *ngph);
+int ngp_hdu_clear(NGP_HDU *ngph);
+int ngp_hdu_insert_token(NGP_HDU *ngph, NGP_TOKEN *newtok);
+int ngp_append_columns(fitsfile *ff, NGP_HDU *ngph, int aftercol);
+int ngp_read_xtension(fitsfile *ff, int parent_hn, int simple_mode);
+int ngp_read_group(fitsfile *ff, char *grpname, int parent_hn);
+
+ /* top level API function - now defined in fitsio.h */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/pkg/tbtables/cfitsio/histo.c b/pkg/tbtables/cfitsio/histo.c
new file mode 100644
index 00000000..525f50fd
--- /dev/null
+++ b/pkg/tbtables/cfitsio/histo.c
@@ -0,0 +1,1300 @@
+/* Globally defined histogram parameters */
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+#include <stdlib.h>
+#include "fitsio2.h"
+
+typedef struct { /* Structure holding all the histogramming information */
+ union { /* the iterator work functions (ffwritehist, ffcalchist) */
+ char *b; /* need to do their job... passed via *userPointer. */
+ short *i;
+ int *j;
+ float *r;
+ double *d;
+ } hist;
+
+ fitsfile *tblptr;
+
+ int haxis, hcolnum[4], himagetype;
+ long haxis1, haxis2, haxis3, haxis4;
+ float amin1, amin2, amin3, amin4;
+ float maxbin1, maxbin2, maxbin3, maxbin4;
+ float binsize1, binsize2, binsize3, binsize4;
+ int wtrecip, wtcolnum;
+ float weight;
+ char *rowselector;
+
+} histType;
+
+/*--------------------------------------------------------------------------*/
+int ffbins(char *binspec, /* I - binning specification */
+ int *imagetype, /* O - image type, TINT or TSHORT */
+ int *histaxis, /* O - no. of axes in the histogram */
+ char colname[4][FLEN_VALUE], /* column name for axis */
+ double *minin, /* minimum value for each axis */
+ double *maxin, /* maximum value for each axis */
+ double *binsizein, /* size of bins on each axis */
+ char minname[4][FLEN_VALUE], /* keyword name for min */
+ char maxname[4][FLEN_VALUE], /* keyword name for max */
+ char binname[4][FLEN_VALUE], /* keyword name for binsize */
+ double *wt, /* weighting factor */
+ char *wtname, /* keyword or column name for weight */
+ int *recip, /* the reciprocal of the weight? */
+ int *status)
+{
+/*
+ Parse the input binning specification string, returning the binning
+ parameters. Supports up to 4 dimensions. The binspec string has
+ one of these forms:
+
+ bin binsize - 2D histogram with binsize on each axis
+ bin xcol - 1D histogram on column xcol
+ bin (xcol, ycol) = binsize - 2D histogram with binsize on each axis
+ bin x=min:max:size, y=min:max:size, z..., t...
+ bin x=:max, y=::size
+ bin x=size, y=min::size
+
+ most other reasonable combinations are supported.
+*/
+ int ii, slen, defaulttype;
+ char *ptr, tmpname[30], *file_expr = NULL;
+ double dummy;
+
+ if (*status > 0)
+ return(*status);
+
+ /* set the default values */
+ *histaxis = 2;
+ *imagetype = TINT;
+ defaulttype = 1;
+ *wt = 1.;
+ *recip = 0;
+ *wtname = '\0';
+
+ /* set default values */
+ for (ii = 0; ii < 4; ii++)
+ {
+ *colname[ii] = '\0';
+ *minname[ii] = '\0';
+ *maxname[ii] = '\0';
+ *binname[ii] = '\0';
+ minin[ii] = DOUBLENULLVALUE; /* undefined values */
+ maxin[ii] = DOUBLENULLVALUE;
+ binsizein[ii] = DOUBLENULLVALUE;
+ }
+
+ ptr = binspec + 3; /* skip over 'bin' */
+
+ if (*ptr == 'i' ) /* bini */
+ {
+ *imagetype = TSHORT;
+ defaulttype = 0;
+ ptr++;
+ }
+ else if (*ptr == 'j' ) /* binj; same as default */
+ {
+ defaulttype = 0;
+ ptr ++;
+ }
+ else if (*ptr == 'r' ) /* binr */
+ {
+ *imagetype = TFLOAT;
+ defaulttype = 0;
+ ptr ++;
+ }
+ else if (*ptr == 'd' ) /* bind */
+ {
+ *imagetype = TDOUBLE;
+ defaulttype = 0;
+ ptr ++;
+ }
+ else if (*ptr == 'b' ) /* binb */
+ {
+ *imagetype = TBYTE;
+ defaulttype = 0;
+ ptr ++;
+ }
+
+ if (*ptr == '\0') /* use all defaults for other parameters */
+ return(*status);
+ else if (*ptr != ' ') /* must be at least one blank */
+ {
+ ffpmsg("binning specification syntax error:");
+ ffpmsg(binspec);
+ return(*status = URL_PARSE_ERROR);
+ }
+
+ while (*ptr == ' ') /* skip over blanks */
+ ptr++;
+
+ if (*ptr == '\0') /* no other parameters; use defaults */
+ return(*status);
+
+ /* Check if need to import expression from a file */
+
+ if( *ptr=='@' ) {
+ if( ffimport_file( ptr+1, &file_expr, status ) ) return(*status);
+ ptr = file_expr;
+ while (*ptr == ' ')
+ ptr++; /* skip leading white space... again */
+ }
+
+ if (*ptr == '(' )
+ {
+ /* this must be the opening parenthesis around a list of column */
+ /* names, optionally followed by a '=' and the binning spec. */
+
+ for (ii = 0; ii < 4; ii++)
+ {
+ ptr++; /* skip over the '(', ',', or ' ') */
+ while (*ptr == ' ') /* skip over blanks */
+ ptr++;
+
+ slen = strcspn(ptr, " ,)");
+ strncat(colname[ii], ptr, slen); /* copy 1st column name */
+
+ ptr += slen;
+ while (*ptr == ' ') /* skip over blanks */
+ ptr++;
+
+ if (*ptr == ')' ) /* end of the list of names */
+ {
+ *histaxis = ii + 1;
+ break;
+ }
+ }
+
+ if (ii == 4) /* too many names in the list , or missing ')' */
+ {
+ ffpmsg(
+ "binning specification has too many column names or is missing closing ')':");
+ ffpmsg(binspec);
+ if( file_expr ) free( file_expr );
+ return(*status = URL_PARSE_ERROR);
+ }
+
+ ptr++; /* skip over the closing parenthesis */
+ while (*ptr == ' ') /* skip over blanks */
+ ptr++;
+
+ if (*ptr == '\0') {
+ if( file_expr ) free( file_expr );
+ return(*status); /* parsed the entire string */
+ }
+
+ else if (*ptr != '=') /* must be an equals sign now*/
+ {
+ ffpmsg("illegal binning specification in URL:");
+ ffpmsg(" an equals sign '=' must follow the column names");
+ ffpmsg(binspec);
+ if( file_expr ) free( file_expr );
+ return(*status = URL_PARSE_ERROR);
+ }
+
+ ptr++; /* skip over the equals sign */
+ while (*ptr == ' ') /* skip over blanks */
+ ptr++;
+
+ /* get the single range specification for all the columns */
+ ffbinr(&ptr, tmpname, minin,
+ maxin, binsizein, minname[0],
+ maxname[0], binname[0], status);
+ if (*status > 0)
+ {
+ ffpmsg("illegal binning specification in URL:");
+ ffpmsg(binspec);
+ if( file_expr ) free( file_expr );
+ return(*status);
+ }
+
+ for (ii = 1; ii < *histaxis; ii++)
+ {
+ minin[ii] = minin[0];
+ maxin[ii] = maxin[0];
+ binsizein[ii] = binsizein[0];
+ strcpy(minname[ii], minname[0]);
+ strcpy(maxname[ii], maxname[0]);
+ strcpy(binname[ii], binname[0]);
+ }
+
+ while (*ptr == ' ') /* skip over blanks */
+ ptr++;
+
+ if (*ptr == ';')
+ goto getweight; /* a weighting factor is specified */
+
+ if (*ptr != '\0') /* must have reached end of string */
+ {
+ ffpmsg("illegal syntax after binning range specification in URL:");
+ ffpmsg(binspec);
+ if( file_expr ) free( file_expr );
+ return(*status = URL_PARSE_ERROR);
+ }
+
+ return(*status);
+ } /* end of case with list of column names in ( ) */
+
+ /* if we've reached this point, then the binning specification */
+ /* must be of the form: XCOL = min:max:binsize, YCOL = ... */
+ /* where the column name followed by '=' are optional. */
+ /* If the column name is not specified, then use the default name */
+
+ for (ii = 0; ii < 4; ii++) /* allow up to 4 histogram dimensions */
+ {
+ ffbinr(&ptr, colname[ii], &minin[ii],
+ &maxin[ii], &binsizein[ii], minname[ii],
+ maxname[ii], binname[ii], status);
+
+ if (*status > 0)
+ {
+ ffpmsg("illegal syntax in binning range specification in URL:");
+ ffpmsg(binspec);
+ if( file_expr ) free( file_expr );
+ return(*status);
+ }
+
+ if (*ptr == '\0' || *ptr == ';')
+ break; /* reached the end of the string */
+
+ if (*ptr == ' ')
+ {
+ while (*ptr == ' ') /* skip over blanks */
+ ptr++;
+
+ if (*ptr == '\0' || *ptr == ';')
+ break; /* reached the end of the string */
+
+ if (*ptr == ',')
+ ptr++; /* comma separates the next column specification */
+ }
+ else if (*ptr == ',')
+ {
+ ptr++; /* comma separates the next column specification */
+ }
+ else
+ {
+ ffpmsg("illegal characters following binning specification in URL:");
+ ffpmsg(binspec);
+ if( file_expr ) free( file_expr );
+ return(*status = URL_PARSE_ERROR);
+ }
+ }
+
+ if (ii == 4)
+ {
+ /* there are yet more characters in the string */
+ ffpmsg("illegal binning specification in URL:");
+ ffpmsg("apparently greater than 4 histogram dimensions");
+ ffpmsg(binspec);
+ return(*status = URL_PARSE_ERROR);
+ }
+ else
+ *histaxis = ii + 1;
+
+ /* special case: if a single number was entered it should be */
+ /* interpreted as the binning factor for the default X and Y axes */
+
+ if (*histaxis == 1 && *colname[0] == '\0' &&
+ minin[0] == DOUBLENULLVALUE && maxin[0] == DOUBLENULLVALUE)
+ {
+ *histaxis = 2;
+ binsizein[1] = binsizein[0];
+ }
+
+getweight:
+ if (*ptr == ';') /* looks like a weighting factor is given */
+ {
+ ptr++;
+
+ while (*ptr == ' ') /* skip over blanks */
+ ptr++;
+
+ recip = 0;
+ if (*ptr == '/')
+ {
+ *recip = 1; /* the reciprocal of the weight is entered */
+ ptr++;
+
+ while (*ptr == ' ') /* skip over blanks */
+ ptr++;
+ }
+
+ /* parse the weight as though it were a binrange. */
+ /* either a column name or a numerical value will be returned */
+
+ ffbinr(&ptr, wtname, &dummy, &dummy, wt, tmpname,
+ tmpname, tmpname, status);
+
+ if (*status > 0)
+ {
+ ffpmsg("illegal binning weight specification in URL:");
+ ffpmsg(binspec);
+ if( file_expr ) free( file_expr );
+ return(*status);
+ }
+
+ /* creat a float datatype histogram by default, if weight */
+ /* factor is not = 1.0 */
+
+ if (defaulttype && *wt != 1.0)
+ *imagetype = TFLOAT;
+ }
+
+ while (*ptr == ' ') /* skip over blanks */
+ ptr++;
+
+ if (*ptr != '\0') /* should have reached the end of string */
+ {
+ ffpmsg("illegal syntax after binning weight specification in URL:");
+ ffpmsg(binspec);
+ *status = URL_PARSE_ERROR;
+ }
+
+ if( file_expr ) free( file_expr );
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffbinr(char **ptr,
+ char *colname,
+ double *minin,
+ double *maxin,
+ double *binsizein,
+ char *minname,
+ char *maxname,
+ char *binname,
+ int *status)
+/*
+ Parse the input binning range specification string, returning
+ the column name, histogram min and max values, and bin size.
+*/
+{
+ int slen, isanumber;
+ char token[FLEN_VALUE];
+
+ if (*status > 0)
+ return(*status);
+
+ slen = fits_get_token(ptr, " ,=:;", token, &isanumber); /* get 1st token */
+
+ if (slen == 0 && (**ptr == '\0' || **ptr == ',' || **ptr == ';') )
+ return(*status); /* a null range string */
+
+ if (!isanumber && **ptr != ':')
+ {
+ /* this looks like the column name */
+
+ if (token[0] == '#' && isdigit((int) token[1]) )
+ {
+ /* omit the leading '#' in the column number */
+ strcpy(colname, token+1);
+ }
+ else
+ strcpy(colname, token);
+
+ while (**ptr == ' ') /* skip over blanks */
+ (*ptr)++;
+
+ if (**ptr != '=')
+ return(*status); /* reached the end */
+
+ (*ptr)++; /* skip over the = sign */
+
+ while (**ptr == ' ') /* skip over blanks */
+ (*ptr)++;
+
+ slen = fits_get_token(ptr, " ,:;", token, &isanumber); /* get token */
+ }
+
+ if (**ptr != ':')
+ {
+ /* this is the first token, and since it is not followed by */
+ /* a ':' this must be the binsize token */
+ if (!isanumber)
+ strcpy(binname, token);
+ else
+ *binsizein = strtod(token, NULL);
+
+ return(*status); /* reached the end */
+ }
+ else
+ {
+ /* the token contains the min value */
+ if (slen)
+ {
+ if (!isanumber)
+ strcpy(minname, token);
+ else
+ *minin = strtod(token, NULL);
+ }
+ }
+
+ (*ptr)++; /* skip the colon between the min and max values */
+ slen = fits_get_token(ptr, " ,:;", token, &isanumber); /* get token */
+
+ /* the token contains the max value */
+ if (slen)
+ {
+ if (!isanumber)
+ strcpy(maxname, token);
+ else
+ *maxin = strtod(token, NULL);
+ }
+
+ if (**ptr != ':')
+ return(*status); /* reached the end; no binsize token */
+
+ (*ptr)++; /* skip the colon between the max and binsize values */
+ slen = fits_get_token(ptr, " ,:;", token, &isanumber); /* get token */
+
+ /* the token contains the binsize value */
+ if (slen)
+ {
+ if (!isanumber)
+ strcpy(binname, token);
+ else
+ *binsizein = strtod(token, NULL);
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffhist(fitsfile **fptr, /* IO - pointer to table with X and Y cols; */
+ /* on output, points to histogram image */
+ char *outfile, /* I - name for the output histogram file */
+ int imagetype, /* I - datatype for image: TINT, TSHORT, etc */
+ int naxis, /* I - number of axes in the histogram image */
+ char colname[4][FLEN_VALUE], /* I - column names */
+ double *minin, /* I - minimum histogram value, for each axis */
+ double *maxin, /* I - maximum histogram value, for each axis */
+ double *binsizein, /* I - bin size along each axis */
+ char minname[4][FLEN_VALUE], /* I - optional keywords for min */
+ char maxname[4][FLEN_VALUE], /* I - optional keywords for max */
+ char binname[4][FLEN_VALUE], /* I - optional keywords for binsize */
+ double weightin, /* I - binning weighting factor */
+ char wtcol[FLEN_VALUE], /* I - optional keyword or col for weight*/
+ int recip, /* I - use reciprocal of the weight? */
+ char *selectrow, /* I - optional array (length = no. of */
+ /* rows in the table). If the element is true */
+ /* then the corresponding row of the table will*/
+ /* be included in the histogram, otherwise the */
+ /* row will be skipped. Ingnored if *selectrow*/
+ /* is equal to NULL. */
+ int *status)
+{
+ int ii, datatype, repeat, imin, imax, ibin, bitpix, tstatus, use_datamax = 0;
+ long haxes[4];
+ fitsfile *histptr;
+ char errmsg[FLEN_ERRMSG], keyname[FLEN_KEYWORD], card[FLEN_CARD];
+ tcolumn *colptr;
+ iteratorCol imagepars[1];
+ int n_cols = 1, nkeys;
+ long offset = 0;
+ long n_per_loop = -1; /* force whole array to be passed at one time */
+ histType histData; /* Structure holding histogram info for iterator */
+
+ float amin[4], amax[4], binsize[4], maxbin[4];
+ float datamin = FLOATNULLVALUE, datamax = FLOATNULLVALUE;
+ char svalue[FLEN_VALUE];
+ double dvalue;
+ char cpref[4][FLEN_VALUE];
+ char *cptr;
+
+ if (*status > 0)
+ return(*status);
+
+ if (naxis > 4)
+ {
+ ffpmsg("histogram has more than 4 dimensions");
+ return(*status = BAD_DIMEN);
+ }
+
+ /* reset position to the correct HDU if necessary */
+ if ((*fptr)->HDUposition != ((*fptr)->Fptr)->curhdu)
+ ffmahd(*fptr, ((*fptr)->HDUposition) + 1, NULL, status);
+
+ histData.tblptr = *fptr;
+ histData.himagetype = imagetype;
+ histData.haxis = naxis;
+ histData.rowselector = selectrow;
+
+ if (imagetype == TBYTE)
+ bitpix = BYTE_IMG;
+ else if (imagetype == TSHORT)
+ bitpix = SHORT_IMG;
+ else if (imagetype == TINT)
+ bitpix = LONG_IMG;
+ else if (imagetype == TFLOAT)
+ bitpix = FLOAT_IMG;
+ else if (imagetype == TDOUBLE)
+ bitpix = DOUBLE_IMG;
+ else
+ return(*status = BAD_DATATYPE);
+
+ /* The CPREF keyword, if it exists, gives the preferred columns. */
+ /* Otherwise, assume "X", "Y", "Z", and "T" */
+
+ tstatus = 0;
+ ffgky(*fptr, TSTRING, "CPREF", cpref[0], NULL, &tstatus);
+
+ if (!tstatus)
+ {
+ /* Preferred column names are given; separate them */
+ cptr = cpref[0];
+
+ /* the first preferred axis... */
+ while (*cptr != ',' && *cptr != '\0')
+ cptr++;
+
+ if (*cptr != '\0')
+ {
+ *cptr = '\0';
+ cptr++;
+ while (*cptr == ' ')
+ cptr++;
+
+ strcpy(cpref[1], cptr);
+ cptr = cpref[1];
+
+ /* the second preferred axis... */
+ while (*cptr != ',' && *cptr != '\0')
+ cptr++;
+
+ if (*cptr != '\0')
+ {
+ *cptr = '\0';
+ cptr++;
+ while (*cptr == ' ')
+ cptr++;
+
+ strcpy(cpref[2], cptr);
+ cptr = cpref[2];
+
+ /* the third preferred axis... */
+ while (*cptr != ',' && *cptr != '\0')
+ cptr++;
+
+ if (*cptr != '\0')
+ {
+ *cptr = '\0';
+ cptr++;
+ while (*cptr == ' ')
+ cptr++;
+
+ strcpy(cpref[3], cptr);
+
+ }
+ }
+ }
+ }
+
+ for (ii = 0; ii < naxis; ii++)
+ {
+
+ /* get the min, max, and binsize values from keywords, if specified */
+
+ if (*minname[ii])
+ {
+ if (ffgky(*fptr, TDOUBLE, minname[ii], &minin[ii], NULL, status) )
+ {
+ ffpmsg("error reading histogramming minimum keyword");
+ ffpmsg(minname[ii]);
+ return(*status);
+ }
+ }
+
+ if (*maxname[ii])
+ {
+ if (ffgky(*fptr, TDOUBLE, maxname[ii], &maxin[ii], NULL, status) )
+ {
+ ffpmsg("error reading histogramming maximum keyword");
+ ffpmsg(maxname[ii]);
+ return(*status);
+ }
+ }
+
+ if (*binname[ii])
+ {
+ if (ffgky(*fptr, TDOUBLE, binname[ii], &binsizein[ii], NULL, status) )
+ {
+ ffpmsg("error reading histogramming binsize keyword");
+ ffpmsg(binname[ii]);
+ return(*status);
+ }
+ }
+
+ if (binsizein[ii] == 0.)
+ {
+ ffpmsg("error: histogram binsize = 0");
+ return(*status = ZERO_SCALE);
+ }
+
+ if (*colname[ii] == '\0')
+ {
+ strcpy(colname[ii], cpref[ii]); /* try using the preferred column */
+ if (*colname[ii] == '\0')
+ {
+ if (ii == 0)
+ strcpy(colname[ii], "X");
+ else if (ii == 1)
+ strcpy(colname[ii], "Y");
+ else if (ii == 2)
+ strcpy(colname[ii], "Z");
+ else if (ii == 3)
+ strcpy(colname[ii], "T");
+ }
+ }
+
+ /* get the column number in the table */
+ if (ffgcno(*fptr, CASEINSEN, colname[ii], histData.hcolnum+ii, status)
+ > 0)
+ {
+ strcpy(errmsg, "column for histogram axis doesn't exist: ");
+ strcat(errmsg, colname[ii]);
+ ffpmsg(errmsg);
+ return(*status);
+ }
+
+ colptr = ((*fptr)->Fptr)->tableptr;
+ colptr += (histData.hcolnum[ii] - 1);
+
+ repeat = colptr->trepeat; /* vector repeat factor of the column */
+ if (repeat > 1)
+ {
+ strcpy(errmsg, "Can't bin a vector column: ");
+ strcat(errmsg, colname[ii]);
+ ffpmsg(errmsg);
+ return(*status = BAD_DATATYPE);
+ }
+
+ /* get the datatype of the column */
+ fits_get_coltype(*fptr, histData.hcolnum[ii], &datatype,
+ NULL, NULL, status);
+
+ if (datatype < 0 || datatype == TSTRING)
+ {
+ strcpy(errmsg, "Inappropriate datatype; can't bin this column: ");
+ strcat(errmsg, colname[ii]);
+ ffpmsg(errmsg);
+ return(*status = BAD_DATATYPE);
+ }
+
+ /* use TLMINn and TLMAXn keyword values if min and max were not given */
+ /* else use actual data min and max if TLMINn and TLMAXn don't exist */
+
+ if (minin[ii] == DOUBLENULLVALUE)
+ {
+ ffkeyn("TLMIN", histData.hcolnum[ii], keyname, status);
+ if (ffgky(*fptr, TFLOAT, keyname, amin+ii, NULL, status) > 0)
+ {
+ /* use actual data minimum value for the histogram minimum */
+ *status = 0;
+ if (fits_get_col_minmax(*fptr, histData.hcolnum[ii], amin+ii, &datamax, status) > 0)
+ {
+ strcpy(errmsg, "Error calculating datamin and datamax for column: ");
+ strcat(errmsg, colname[ii]);
+ ffpmsg(errmsg);
+ return(*status);
+ }
+ }
+ }
+ else
+ {
+ amin[ii] = minin[ii];
+ }
+
+ if (maxin[ii] == DOUBLENULLVALUE)
+ {
+ ffkeyn("TLMAX", histData.hcolnum[ii], keyname, status);
+ if (ffgky(*fptr, TFLOAT, keyname, &amax[ii], NULL, status) > 0)
+ {
+ *status = 0;
+ if(datamax != FLOATNULLVALUE) /* already computed max value */
+ {
+ amax[ii] = datamax;
+ }
+ else
+ {
+ /* use actual data maximum value for the histogram maximum */
+ if (fits_get_col_minmax(*fptr, histData.hcolnum[ii], &datamin, &amax[ii], status) > 0)
+ {
+ strcpy(errmsg, "Error calculating datamin and datamax for column: ");
+ strcat(errmsg, colname[ii]);
+ ffpmsg(errmsg);
+ return(*status);
+ }
+ }
+ }
+ use_datamax = 1; /* flag that the max was determined by the data values */
+ /* and not specifically set by the calling program */
+ }
+ else
+ {
+ amax[ii] = maxin[ii];
+ }
+
+ /* use TDBINn keyword or else 1 if bin size is not given */
+ if (binsizein[ii] == DOUBLENULLVALUE)
+ {
+ tstatus = 0;
+ ffkeyn("TDBIN", histData.hcolnum[ii], keyname, &tstatus);
+
+ if (ffgky(*fptr, TDOUBLE, keyname, binsizein + ii, NULL, &tstatus) > 0)
+ {
+ /* make at least 10 bins */
+ binsizein[ii] = (amax[ii] - amin[ii]) / 10. ;
+ if (binsizein[ii] > 1.)
+ binsizein[ii] = 1.; /* use default bin size */
+ }
+ }
+
+ if ( (amin[ii] > amax[ii] && binsizein[ii] > 0. ) ||
+ (amin[ii] < amax[ii] && binsizein[ii] < 0. ) )
+ binsize[ii] = -binsizein[ii]; /* reverse the sign of binsize */
+ else
+ binsize[ii] = binsizein[ii]; /* binsize has the correct sign */
+
+ ibin = binsize[ii];
+ imin = amin[ii];
+ imax = amax[ii];
+
+ /* Determine the range and number of bins in the histogram. This */
+ /* depends on whether the input columns are integer or floats, so */
+ /* treat each case separately. */
+
+ if (datatype <= TLONG && (float) imin == amin[ii] &&
+ (float) imax == amax[ii] &&
+ (float) ibin == binsize[ii] )
+ {
+ /* This is an integer column and integer limits were entered. */
+ /* Shift the lower and upper histogramming limits by 0.5, so that */
+ /* the values fall in the center of the bin, not on the edge. */
+
+ haxes[ii] = (imax - imin) / ibin + 1; /* last bin may only */
+ /* be partially full */
+ maxbin[ii] = haxes[ii] + 1.; /* add 1. instead of .5 to avoid roundoff */
+
+ if (amin[ii] < amax[ii])
+ {
+ amin[ii] = amin[ii] - 0.5;
+ amax[ii] = amax[ii] + 0.5;
+ }
+ else
+ {
+ amin[ii] = amin[ii] + 0.5;
+ amax[ii] = amax[ii] - 0.5;
+ }
+ }
+ else if (use_datamax)
+ {
+ /* Either the column datatype and/or the limits are floating point, */
+ /* and the histogram limits are being defined by the min and max */
+ /* values of the array. Add 1 to the number of histogram bins to */
+ /* make sure that pixels that are equal to the maximum or are */
+ /* in the last partial bin are included. */
+
+ maxbin[ii] = (amax[ii] - amin[ii]) / binsize[ii];
+ haxes[ii] = maxbin[ii] + 1;
+ }
+ else
+ {
+ /* float datatype column and/or limits, and the maximum value to */
+ /* include in the histogram is specified by the calling program. */
+ /* The lower limit is inclusive, but upper limit is exclusive */
+ maxbin[ii] = (amax[ii] - amin[ii]) / binsize[ii];
+ haxes[ii] = maxbin[ii];
+
+ if (amin[ii] < amax[ii])
+ {
+ if (amin[ii] + (haxes[ii] * binsize[ii]) < amax[ii])
+ haxes[ii]++; /* need to include another partial bin */
+ }
+ else
+ {
+ if (amin[ii] + (haxes[ii] * binsize[ii]) > amax[ii])
+ haxes[ii]++; /* need to include another partial bin */
+ }
+ }
+ }
+
+ /* get the histogramming weighting factor */
+ if (*wtcol)
+ {
+ /* first, look for a keyword with the weight value */
+ if (ffgky(*fptr, TFLOAT, wtcol, &histData.weight, NULL, status) )
+ {
+ /* not a keyword, so look for column with this name */
+ *status = 0;
+
+ /* get the column number in the table */
+ if (ffgcno(*fptr, CASEINSEN, wtcol, &histData.wtcolnum, status) > 0)
+ {
+ ffpmsg(
+ "keyword or column for histogram weights doesn't exist: ");
+ ffpmsg(wtcol);
+ return(*status);
+ }
+
+ histData.weight = FLOATNULLVALUE;
+ }
+ }
+ else
+ histData.weight = (float) weightin;
+
+ if (histData.weight <= 0. && histData.weight != FLOATNULLVALUE)
+ {
+ ffpmsg("Illegal histogramming weighting factor <= 0.");
+ return(*status = URL_PARSE_ERROR);
+ }
+
+ if (recip && histData.weight != FLOATNULLVALUE)
+ /* take reciprocal of weight */
+ histData.weight = 1.0 / histData.weight;
+
+ histData.wtrecip = recip;
+
+ /* size of histogram is now known, so create temp output file */
+ if (ffinit(&histptr, outfile, status) > 0)
+ {
+ ffpmsg("failed to create temp output file for histogram");
+ return(*status);
+ }
+
+ if (ffcrim(histptr, bitpix, histData.haxis, haxes, status) > 0)
+ {
+ ffpmsg("failed to create primary array histogram in temp file");
+ ffclos(histptr, status);
+ return(*status);
+ }
+
+ /* copy all non-structural keywords from the table to the image */
+ fits_get_hdrspace(*fptr, &nkeys, NULL, status);
+ for (ii = 1; ii <= nkeys; ii++)
+ {
+ fits_read_record(*fptr, ii, card, status);
+ if (fits_get_keyclass(card) >= 120)
+ fits_write_record(histptr, card, status);
+ }
+
+ /* Set global variables with histogram parameter values. */
+ /* Use separate scalar variables rather than arrays because */
+ /* it is more efficient when computing the histogram. */
+
+ histData.amin1 = amin[0];
+ histData.maxbin1 = maxbin[0];
+ histData.binsize1 = binsize[0];
+ histData.haxis1 = haxes[0];
+
+ if (histData.haxis > 1)
+ {
+ histData.amin2 = amin[1];
+ histData.maxbin2 = maxbin[1];
+ histData.binsize2 = binsize[1];
+ histData.haxis2 = haxes[1];
+
+ if (histData.haxis > 2)
+ {
+ histData.amin3 = amin[2];
+ histData.maxbin3 = maxbin[2];
+ histData.binsize3 = binsize[2];
+ histData.haxis3 = haxes[2];
+
+ if (histData.haxis > 3)
+ {
+ histData.amin4 = amin[3];
+ histData.maxbin4 = maxbin[3];
+ histData.binsize4 = binsize[3];
+ histData.haxis4 = haxes[3];
+ }
+ }
+ }
+
+ /* define parameters of image for the iterator function */
+ fits_iter_set_file(imagepars, histptr); /* pointer to image */
+ fits_iter_set_datatype(imagepars, imagetype); /* image datatype */
+ fits_iter_set_iotype(imagepars, OutputCol); /* image is output */
+
+ /* call the iterator function to write out the histogram image */
+ if (fits_iterate_data(n_cols, imagepars, offset, n_per_loop,
+ ffwritehisto, (void*)&histData, status) )
+ return(*status);
+
+ /* write the World Coordinate System (WCS) keywords */
+ /* create default values if WCS keywords are not present in the table */
+ for (ii = 0; ii < histData.haxis; ii++)
+ {
+ /* CTYPEn */
+ tstatus = 0;
+ ffkeyn("TCTYP", histData.hcolnum[ii], keyname, &tstatus);
+ ffgky(*fptr, TSTRING, keyname, svalue, NULL, &tstatus);
+ if (tstatus)
+ { /* just use column name as the type */
+ tstatus = 0;
+ ffkeyn("TTYPE", histData.hcolnum[ii], keyname, &tstatus);
+ ffgky(*fptr, TSTRING, keyname, svalue, NULL, &tstatus);
+ }
+
+ if (!tstatus)
+ {
+ ffkeyn("CTYPE", ii + 1, keyname, &tstatus);
+ ffpky(histptr, TSTRING, keyname, svalue, "Coordinate Type", &tstatus);
+ }
+ else
+ tstatus = 0;
+
+ /* CUNITn */
+ ffkeyn("TCUNI", histData.hcolnum[ii], keyname, &tstatus);
+ ffgky(*fptr, TSTRING, keyname, svalue, NULL, &tstatus);
+ if (tstatus)
+ { /* use the column units */
+ tstatus = 0;
+ ffkeyn("TUNIT", histData.hcolnum[ii], keyname, &tstatus);
+ ffgky(*fptr, TSTRING, keyname, svalue, NULL, &tstatus);
+ }
+
+ if (!tstatus)
+ {
+ ffkeyn("CUNIT", ii + 1, keyname, &tstatus);
+ ffpky(histptr, TSTRING, keyname, svalue, "Coordinate Units", &tstatus);
+ }
+ else
+ tstatus = 0;
+
+ /* CRPIXn - Reference Pixel */
+ ffkeyn("TCRPX", histData.hcolnum[ii], keyname, &tstatus);
+ ffgky(*fptr, TDOUBLE, keyname, &dvalue, NULL, &tstatus);
+ if (tstatus)
+ {
+ dvalue = 1.0; /* choose first pixel in new image as ref. pix. */
+ tstatus = 0;
+ }
+ else
+ {
+ /* calculate locate of the ref. pix. in the new image */
+ dvalue = (dvalue - amin[ii]) / binsize[ii] + .5;
+ }
+
+ ffkeyn("CRPIX", ii + 1, keyname, &tstatus);
+ ffpky(histptr, TDOUBLE, keyname, &dvalue, "Reference Pixel", &tstatus);
+
+ /* CRVALn - Value at the location of the reference pixel */
+ ffkeyn("TCRVL", histData.hcolnum[ii], keyname, &tstatus);
+ ffgky(*fptr, TDOUBLE, keyname, &dvalue, NULL, &tstatus);
+ if (tstatus)
+ {
+ /* calculate value at ref. pix. location (at center of 1st pixel) */
+ dvalue = amin[ii] + binsize[ii]/2.;
+ tstatus = 0;
+ }
+
+ ffkeyn("CRVAL", ii + 1, keyname, &tstatus);
+ ffpky(histptr, TDOUBLE, keyname, &dvalue, "Reference Value", &tstatus);
+
+ /* CDELTn - unit size of pixels */
+ ffkeyn("TCDLT", histData.hcolnum[ii], keyname, &tstatus);
+ ffgky(*fptr, TDOUBLE, keyname, &dvalue, NULL, &tstatus);
+ if (tstatus)
+ {
+ dvalue = 1.0; /* use default pixel size */
+ tstatus = 0;
+ }
+
+ dvalue = dvalue * binsize[ii];
+ ffkeyn("CDELT", ii + 1, keyname, &tstatus);
+ ffpky(histptr, TDOUBLE, keyname, &dvalue, "Pixel size", &tstatus);
+
+ /* CROTAn - Rotation angle (degrees CCW) */
+ /* There should only be a CROTA2 keyword, and only for 2+ D images */
+ if (ii == 1)
+ {
+ ffkeyn("TCROT", histData.hcolnum[ii], keyname, &tstatus);
+ ffgky(*fptr, TDOUBLE, keyname, &dvalue, NULL, &tstatus);
+ if (!tstatus && dvalue != 0.) /* only write keyword if angle != 0 */
+ {
+ ffkeyn("CROTA", ii + 1, keyname, &tstatus);
+ ffpky(histptr, TDOUBLE, keyname, &dvalue,
+ "Rotation angle", &tstatus);
+ }
+ else
+ {
+ /* didn't find CROTA for the 2nd axis, so look for one */
+ /* on the first axis */
+ tstatus = 0;
+ ffkeyn("TCROT", histData.hcolnum[0], keyname, &tstatus);
+ ffgky(*fptr, TDOUBLE, keyname, &dvalue, NULL, &tstatus);
+ if (!tstatus && dvalue != 0.) /* only write keyword if angle != 0 */
+ {
+ dvalue *= -1.; /* negate the value, because mirror image */
+ ffkeyn("CROTA", ii + 1, keyname, &tstatus);
+ ffpky(histptr, TDOUBLE, keyname, &dvalue,
+ "Rotation angle", &tstatus);
+ }
+ }
+ }
+ }
+
+ /* finally, close the original file and return ptr to the new image */
+ ffclos(*fptr, status);
+ *fptr = histptr;
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fits_get_col_minmax(fitsfile *fptr, int colnum, float *datamin,
+ float *datamax, int *status)
+/*
+ Simple utility routine to compute the min and max value in a column
+*/
+{
+ int anynul;
+ long nrows, ntodo, firstrow, ii;
+ float array[1000], nulval;
+
+ ffgky(fptr, TLONG, "NAXIS2", &nrows, NULL, status); /* no. of rows */
+
+ firstrow = 1;
+ nulval = FLOATNULLVALUE;
+ *datamin = 9.0E36F;
+ *datamax = -9.0E36F;
+
+ while(nrows)
+ {
+ ntodo = minvalue(nrows, 100);
+ ffgcv(fptr, TFLOAT, colnum, firstrow, 1, ntodo, &nulval, array,
+ &anynul, status);
+
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (array[ii] != nulval)
+ {
+ *datamin = minvalue(*datamin, array[ii]);
+ *datamax = maxvalue(*datamax, array[ii]);
+ }
+ }
+
+ nrows -= ntodo;
+ firstrow += ntodo;
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffwritehisto(long totaln, long pixoffset, long firstn, long nvalues,
+ int narrays, iteratorCol *imagepars, void *userPointer)
+/*
+ Interator work function that writes out the histogram.
+ The histogram values are calculated by another work function, ffcalchisto.
+ This work function only gets called once, and totaln = nvalues.
+*/
+{
+ iteratorCol colpars[5];
+ int ii, status = 0, ncols;
+ long rows_per_loop = 0, offset = 0;
+ histType *histData;
+
+ histData = (histType *)userPointer;
+
+ /* store pointer to the histogram array, and initialize to zero */
+
+ switch( histData->himagetype ) {
+ case TBYTE:
+ histData->hist.b = (char * ) fits_iter_get_array(imagepars);
+ break;
+ case TSHORT:
+ histData->hist.i = (short * ) fits_iter_get_array(imagepars);
+ break;
+ case TINT:
+ histData->hist.j = (int * ) fits_iter_get_array(imagepars);
+ break;
+ case TFLOAT:
+ histData->hist.r = (float * ) fits_iter_get_array(imagepars);
+ break;
+ case TDOUBLE:
+ histData->hist.d = (double *) fits_iter_get_array(imagepars);
+ break;
+ }
+
+ /* set the column parameters for the iterator function */
+ for (ii = 0; ii < histData->haxis; ii++)
+ {
+ fits_iter_set_by_num(&colpars[ii], histData->tblptr,
+ histData->hcolnum[ii], TFLOAT, InputCol);
+ }
+ ncols = histData->haxis;
+
+ if (histData->weight == FLOATNULLVALUE)
+ {
+ fits_iter_set_by_num(&colpars[histData->haxis], histData->tblptr,
+ histData->wtcolnum, TFLOAT, InputCol);
+ ncols = histData->haxis + 1;
+ }
+
+ /* call iterator function to calc the histogram pixel values */
+ fits_iterate_data(ncols, colpars, offset, rows_per_loop,
+ ffcalchist, (void*)histData, &status);
+
+ return(status);
+}
+/*--------------------------------------------------------------------------*/
+int ffcalchist(long totalrows, long offset, long firstrow, long nrows,
+ int ncols, iteratorCol *colpars, void *userPointer)
+/*
+ Interator work function that calculates values for the 2D histogram.
+*/
+{
+ long ii, ipix, iaxisbin;
+ float pix, axisbin;
+ static float *col1, *col2, *col3, *col4; /* static to preserve values */
+ static float *wtcol;
+ static long incr2, incr3, incr4;
+ static histType histData;
+ static char *rowselect;
+
+ /* Initialization procedures: execute on the first call */
+ if (firstrow == 1)
+ {
+
+ /* Copy input histogram data to static local variable so we */
+ /* don't have to constantly dereference it. */
+
+ histData = *(histType*)userPointer;
+ rowselect = histData.rowselector;
+
+ /* assign the input array pointers to local pointers */
+ col1 = (float *) fits_iter_get_array(&colpars[0]);
+ if (histData.haxis > 1)
+ {
+ col2 = (float *) fits_iter_get_array(&colpars[1]);
+ incr2 = histData.haxis1;
+
+ if (histData.haxis > 2)
+ {
+ col3 = (float *) fits_iter_get_array(&colpars[2]);
+ incr3 = incr2 * histData.haxis2;
+
+ if (histData.haxis > 3)
+ {
+ col4 = (float *) fits_iter_get_array(&colpars[3]);
+ incr4 = incr3 * histData.haxis3;
+ }
+ }
+ }
+
+ if (ncols > histData.haxis) /* then weights are give in a column */
+ {
+ wtcol = (float *) fits_iter_get_array(&colpars[histData.haxis]);
+ }
+ } /* end of Initialization procedures */
+
+ /* Main loop: increment the histogram at position of each event */
+ for (ii = 1; ii <= nrows; ii++)
+ {
+ if (rowselect) /* if a row selector array is supplied... */
+ {
+ if (*rowselect)
+ {
+ rowselect++; /* this row is included in the histogram */
+ }
+ else
+ {
+ rowselect++; /* this row is excluded from the histogram */
+ continue;
+ }
+ }
+
+ if (col1[ii] == FLOATNULLVALUE) /* test for null value */
+ continue;
+
+ pix = (col1[ii] - histData.amin1) / histData.binsize1;
+ ipix = (long) (pix + 1.); /* add 1 because the 1st pixel is the null value */
+
+ /* test if bin is within range */
+ if (ipix < 1 || ipix > histData.haxis1 || pix > histData.maxbin1)
+ continue;
+
+ if (histData.haxis > 1)
+ {
+ if (col2[ii] == FLOATNULLVALUE)
+ continue;
+
+ axisbin = (col2[ii] - histData.amin2) / histData.binsize2;
+ iaxisbin = axisbin;
+
+ if (axisbin < 0. || iaxisbin >= histData.haxis2 || axisbin > histData.maxbin2)
+ continue;
+
+ ipix += (iaxisbin * incr2);
+
+ if (histData.haxis > 2)
+ {
+ if (col3[ii] == FLOATNULLVALUE)
+ continue;
+
+ axisbin = (col3[ii] - histData.amin3) / histData.binsize3;
+ iaxisbin = axisbin;
+ if (axisbin < 0. || iaxisbin >= histData.haxis3 || axisbin > histData.maxbin3)
+ continue;
+
+ ipix += (iaxisbin * incr3);
+
+ if (histData.haxis > 3)
+ {
+ if (col4[ii] == FLOATNULLVALUE)
+ continue;
+
+ axisbin = (col4[ii] - histData.amin4) / histData.binsize4;
+ iaxisbin = axisbin;
+ if (axisbin < 0. || iaxisbin >= histData.haxis4 || axisbin > histData.maxbin4)
+ continue;
+
+ ipix += (iaxisbin * incr4);
+
+ } /* end of haxis > 3 case */
+ } /* end of haxis > 2 case */
+ } /* end of haxis > 1 case */
+
+ /* increment the histogram pixel */
+ if (histData.weight != FLOATNULLVALUE) /* constant weight factor */
+ {
+ if (histData.himagetype == TINT)
+ histData.hist.j[ipix] += histData.weight;
+ else if (histData.himagetype == TSHORT)
+ histData.hist.i[ipix] += histData.weight;
+ else if (histData.himagetype == TFLOAT)
+ histData.hist.r[ipix] += histData.weight;
+ else if (histData.himagetype == TDOUBLE)
+ histData.hist.d[ipix] += histData.weight;
+ else if (histData.himagetype == TBYTE)
+ histData.hist.b[ipix] += histData.weight;
+ }
+ else if (histData.wtrecip) /* use reciprocal of the weight */
+ {
+ if (histData.himagetype == TINT)
+ histData.hist.j[ipix] += 1./wtcol[ii];
+ else if (histData.himagetype == TSHORT)
+ histData.hist.i[ipix] += 1./wtcol[ii];
+ else if (histData.himagetype == TFLOAT)
+ histData.hist.r[ipix] += 1./wtcol[ii];
+ else if (histData.himagetype == TDOUBLE)
+ histData.hist.d[ipix] += 1./wtcol[ii];
+ else if (histData.himagetype == TBYTE)
+ histData.hist.b[ipix] += 1./wtcol[ii];
+ }
+ else /* no weights */
+ {
+ if (histData.himagetype == TINT)
+ histData.hist.j[ipix] += wtcol[ii];
+ else if (histData.himagetype == TSHORT)
+ histData.hist.i[ipix] += wtcol[ii];
+ else if (histData.himagetype == TFLOAT)
+ histData.hist.r[ipix] += wtcol[ii];
+ else if (histData.himagetype == TDOUBLE)
+ histData.hist.d[ipix] += wtcol[ii];
+ else if (histData.himagetype == TBYTE)
+ histData.hist.b[ipix] += wtcol[ii];
+ }
+
+ } /* end of main loop over all rows */
+
+ return(0);
+}
+
diff --git a/pkg/tbtables/cfitsio/imcompress.c b/pkg/tbtables/cfitsio/imcompress.c
new file mode 100644
index 00000000..fbc3842c
--- /dev/null
+++ b/pkg/tbtables/cfitsio/imcompress.c
@@ -0,0 +1,2997 @@
+# include <stdio.h>
+# include <stdlib.h>
+# include <string.h>
+# include <math.h>
+# include "fitsio2.h"
+
+/*--------------------------------------------------------------------------*/
+int fits_set_compression_type(fitsfile *fptr, /* I - FITS file pointer */
+ int ctype, /* image compression type code; */
+ /* allowed values: RICE_1, GZIP_1, PLIO_1, HCOMPRESS_1 */
+ int *status) /* IO - error status */
+{
+/*
+ This routine specifies the image compression algorithm that should be
+ used when writing a FITS image. The image is divided into tiles, and
+ each tile is compressed and stored in a row of at variable length binary
+ table column.
+*/
+ (fptr->Fptr)->request_compress_type = ctype;
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fits_set_tile_dim(fitsfile *fptr, /* I - FITS file pointer */
+ int ndim, /* number of dimensions in the compressed image */
+ long *dims, /* size of image compression tile in each dimension */
+ /* default tile size = (NAXIS1, 1, 1, ...) */
+ int *status) /* IO - error status */
+{
+/*
+ This routine specifies the size (dimension) of the image
+ compression tiles that should be used when writing a FITS
+ image. The image is divided into tiles, and each tile is compressed
+ and stored in a row of at variable length binary table column.
+*/
+ int ii;
+
+ if (ndim < 0 || ndim > MAX_COMPRESS_DIM)
+ {
+ *status = BAD_DIMEN;
+ return(*status);
+ }
+
+ for (ii = 0; ii < ndim; ii++)
+ {
+ (fptr->Fptr)->request_tilesize[ii] = dims[ii];
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fits_set_noise_bits(fitsfile *fptr, /* I - FITS file pointer */
+ int noisebits, /* noise_bits parameter value */
+ /* (default = 4) */
+ int *status) /* IO - error status */
+{
+/*
+ This routine specifies the value of the noice_bits parameter that
+ should be used when compressing floating point images. The image is
+ divided into tiles, and each tile is compressed and stored in a row
+ of at variable length binary table column.
+*/
+ if (noisebits < 1 || noisebits > 16)
+ {
+ *status = DATA_COMPRESSION_ERR;
+ return(*status);
+ }
+
+ (fptr->Fptr)->request_rice_nbits = noisebits;
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fits_get_compression_type(fitsfile *fptr, /* I - FITS file pointer */
+ int *ctype, /* image compression type code; */
+ /* allowed values: RICE_1, GZIP_1, PLIO_1, HCOMPRESS_1 */
+ int *status) /* IO - error status */
+{
+/*
+ This routine returns the image compression algorithm that should be
+ used when writing a FITS image. The image is divided into tiles, and
+ each tile is compressed and stored in a row of at variable length binary
+ table column.
+*/
+ *ctype = (fptr->Fptr)->request_compress_type;
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fits_get_tile_dim(fitsfile *fptr, /* I - FITS file pointer */
+ int ndim, /* number of dimensions in the compressed image */
+ long *dims, /* size of image compression tile in each dimension */
+ /* default tile size = (NAXIS1, 1, 1, ...) */
+ int *status) /* IO - error status */
+{
+/*
+ This routine returns the size (dimension) of the image
+ compression tiles that should be used when writing a FITS
+ image. The image is divided into tiles, and each tile is compressed
+ and stored in a row of at variable length binary table column.
+*/
+ int ii;
+
+ if (ndim < 0 || ndim > MAX_COMPRESS_DIM)
+ {
+ *status = BAD_DIMEN;
+ return(*status);
+ }
+
+ for (ii = 0; ii < ndim; ii++)
+ {
+ dims[ii] = (fptr->Fptr)->request_tilesize[ii];
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fits_get_noise_bits(fitsfile *fptr, /* I - FITS file pointer */
+ int *noisebits, /* noise_bits parameter value */
+ /* (default = 4) */
+ int *status) /* IO - error status */
+
+{
+/*
+ This routine returns the value of the noice_bits parameter that
+ should be used when compressing floating point images. The image is
+ divided into tiles, and each tile is compressed and stored in a row
+ of at variable length binary table column.
+*/
+
+ *noisebits = (fptr->Fptr)->request_rice_nbits;
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fits_compress_img(fitsfile *infptr, /* pointer to image to be compressed */
+ fitsfile *outfptr, /* empty HDU for output compressed image */
+ int compress_type, /* compression type code */
+ /* RICE_1, HCOMPRESS_1, etc. */
+ long *intilesize, /* size in each dimension of the tiles */
+ /* NULL pointer means tile by rows */
+ int blocksize, /* compression parameter: blocksize */
+ int nbits, /* compression parameter: nbits */
+ int *status) /* IO - error status */
+
+/*
+ This routine initializes the output table, copies all the keywords,
+ and loops through the input image, compressing the data and
+ writing the compressed tiles to the output table.
+*/
+{
+ int ii, bitpix, naxis;
+ long naxes[MAX_COMPRESS_DIM], tilesize[MAX_COMPRESS_DIM];
+
+ if (*status > 0)
+ return(*status);
+
+ /* get datatype and size of input image */
+ if (fits_get_img_param(infptr, MAX_COMPRESS_DIM, &bitpix,
+ &naxis, naxes, status) > 0)
+ return(*status);
+
+ if (naxis < 1 || naxis > MAX_COMPRESS_DIM)
+ {
+ ffpmsg("Image cannot be compressed: NAXIS out of range");
+ return(*status = BAD_NAXIS);
+ }
+
+ /* determine tile size */
+ if (intilesize == NULL) /* caller did not specify tile size? */
+ {
+ /* default case; compress each row of the image separately */
+ tilesize[0] = naxes[0];
+ for (ii = 1; ii < naxis; ii++)
+ {
+ tilesize[ii] = 1;
+ }
+ }
+ else
+ {
+ /* limit max tile size in each dimension to size of dimension */
+ for (ii = 0; ii < naxis; ii++)
+ {
+ tilesize[ii] = minvalue(intilesize[ii], naxes[ii]);
+ }
+ }
+
+ if (blocksize <= 0)
+ blocksize = 32; /* default value */
+
+ if (nbits <= 0)
+ nbits = 4; /* default value */
+
+ /* initialize output table */
+ if (imcomp_init_table(outfptr, compress_type, bitpix, naxis, naxes,
+ tilesize, blocksize, nbits, status) > 0)
+ return (*status);
+
+ /* Copy the image header keywords to the table header. */
+ if (imcomp_copy_imheader(infptr, outfptr, status) > 0)
+ return (*status);
+
+ /* turn off any intensity scaling (defined by BSCALE and BZERO */
+ /* keywords) so that unscaled values will be read by CFITSIO */
+ ffpscl(infptr, 1.0, 0.0, status);
+
+ /* force a rescan of the output file keywords, so that */
+ /* the compression parameters will be copied to the internal */
+ /* fitsfile structure used by CFITSIO */
+ ffrdef(outfptr, status);
+
+ /* Read each image tile, compress, and write to a table row. */
+ imcomp_compress_image (infptr, outfptr, status);
+
+ /* force another rescan of the output file keywords, to */
+ /* update PCOUNT and TFORMn = '1PB(iii)' keyword values. */
+ ffrdef(outfptr, status);
+
+ return (*status);
+}
+/*--------------------------------------------------------------------------*/
+int imcomp_init_table(fitsfile *outfptr,
+ int compress_type,
+ int bitpix,
+ int naxis,
+ long *naxes,
+ long *tiledim,
+ int rice_blocksize,
+ int rice_nbits,
+ int *status)
+
+/*
+ create a BINTABLE extension for the output compressed image.
+*/
+{
+ char keyname[FLEN_KEYWORD], zcmptype[12];
+ int ii, ncols;
+ long nrows, tilesize[9] = {0,1,1,1,1,1,1,1,1};
+ char *ttype[] = {"COMPRESSED_DATA", "UNCOMPRESSED_DATA", "ZSCALE", "ZZERO"};
+ char *tform[4];
+ char tf0[4], tf1[4], tf2[4], tf3[4];
+ char *tunit[] = {"\0", "\0", "\0", "\0" };
+
+ if (*status > 0)
+ return(*status);
+
+ for (ii = 0; ii < naxis; ii++)
+ tilesize[ii] = tiledim[ii]; /* copy input to local variable */
+
+ /* if legal tile dimensions are not defined, use NAXIS1 as the */
+ /* first dimension and 1 for all the higher dimensions */
+
+ if (tilesize[0] <= 0)
+ tilesize[0] = naxes[0];
+
+ for (ii = 1; ii < naxis; ii++)
+ {
+ if (tilesize[ii] <= 0)
+ tilesize[ii] = 1;
+ }
+
+ /* (only used to quantize floating point images) */
+ if (rice_nbits < 1) /* use default value if input is not legal */
+ rice_nbits = 4;
+
+ /* ---- set up array of TFORM strings -------------------------------*/
+ strcpy(tf0, "1PB");
+ strcpy(tf2, "1D");
+ strcpy(tf3, "1D");
+
+ tform[0] = tf0;
+ tform[1] = tf1;
+ tform[2] = tf2;
+ tform[3] = tf3;
+
+ /* calculate number of rows in output table */
+ nrows = 1;
+ for (ii = 0; ii < naxis; ii++)
+ {
+ nrows = nrows * ((naxes[ii] - 1)/ tilesize[ii] + 1);
+ }
+
+ if (bitpix < 0 ) /* floating point image */
+ ncols = 4;
+ else
+ ncols = 1; /* default table has just one 'COMPRESSED_DATA' column */
+
+ if (compress_type == RICE_1)
+ {
+ strcpy(zcmptype, "RICE_1");
+ }
+ else if (compress_type == GZIP_1)
+ {
+ strcpy(zcmptype, "GZIP_1");
+ }
+ else if (compress_type == PLIO_1)
+ {
+ strcpy(zcmptype, "PLIO_1");
+ /* the PLIO compression algorithm outputs short integers, not bytes */
+ strcpy(tform[0], "1PI");
+ }
+ else if (compress_type == HCOMPRESS_1)
+ {
+ strcpy(zcmptype, "HCOMPRESS_1");
+ }
+ else
+ {
+ ffpmsg("unknown compression type (imcomp_init_table)");
+ return(*status = DATA_COMPRESSION_ERR);
+ }
+
+ /* set correct datatype for any tiles that cannot be compressed */
+ if (bitpix == SHORT_IMG)
+ strcpy(tform[1], "1PI");
+ else if (bitpix == LONG_IMG)
+ strcpy(tform[1], "1PJ");
+ else if (bitpix == FLOAT_IMG)
+ strcpy(tform[1], "1PE");
+ else if (bitpix == DOUBLE_IMG)
+ strcpy(tform[1], "1PD");
+
+ /* create the bintable extension to contain the compressed image */
+ ffcrtb(outfptr, BINARY_TBL, nrows, ncols, ttype,
+ tform, tunit, "COMPRESSED_IMAGE", status);
+
+ /* Add standard header keywords. */
+ ffpkyl (outfptr, "ZIMAGE", 1,
+ "extension contains compressed image", status);
+
+ ffpkyj (outfptr, "ZBITPIX", (long) bitpix,
+ "data type of original image", status);
+ ffpkyj (outfptr, "ZNAXIS", (long) naxis,
+ "dimension of original image", status);
+
+ for (ii = 0; ii < naxis; ii++)
+ {
+ sprintf (keyname, "ZNAXIS%d", ii+1);
+ ffpkyj (outfptr, keyname, naxes[ii],
+ "length of original image axis", status);
+ }
+
+ for (ii = 0; ii < naxis; ii++)
+ {
+ sprintf (keyname, "ZTILE%d", ii+1);
+ ffpkyj (outfptr, keyname, tilesize[ii],
+ "size of tiles to be compressed", status);
+ }
+
+ ffpkys (outfptr, "ZCMPTYPE", zcmptype,
+ "compression algorithm", status);
+
+
+ /* write any algorithm-specific keywords */
+ if (compress_type == RICE_1)
+ {
+ ffpkys (outfptr, "ZNAME1", "BLOCKSIZE",
+ "compression block size", status);
+ ffpkyj (outfptr, "ZVAL1", (long) rice_blocksize,
+ "pixels per block", status);
+
+ if (bitpix < 0 ) /* floating point image */
+ {
+ ffpkys (outfptr, "ZNAME2", "NOISEBIT",
+ "floating point quantization level", status);
+
+ ffpkyj (outfptr, "ZVAL2", (long) rice_nbits,
+ "floating point quantization level", status);
+ }
+ }
+ else
+ {
+ if (bitpix < 0 ) /* floating point image */
+ {
+ ffpkys (outfptr, "ZNAME1", "NOISEBIT",
+ "floating point quantization level", status);
+
+ ffpkyj (outfptr, "ZVAL1", (long) rice_nbits,
+ "floating point quantization level", status);
+ }
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int imcomp_calc_max_elem (int comptype, int nx, int blocksize)
+
+/* This function returns the maximum number of bytes in a compressed
+ image line.
+*/
+{
+ if (comptype == RICE_1)
+ {
+ return (sizeof(float) * nx + nx / blocksize + 2 + 4);
+ }
+ else if (comptype == GZIP_1)
+ {
+ /* gzip usually compressed by at least a factor of 2 */
+ /* If this size turns out to be too small, then the gzip */
+ /* compression routine will allocate more space as required */
+
+ return(nx * sizeof(int) / 2);
+ }
+ else
+ return(nx * sizeof(int));
+}
+/*--------------------------------------------------------------------------*/
+int imcomp_compress_image (fitsfile *infptr, fitsfile *outfptr, int *status)
+
+/* This routine does the following:
+ - reads an image one tile at a time
+ - if it is a float or double image, then it quantizes the pixels
+ - compresses the integer pixel values
+ - writes the compressed byte stream to the FITS file.
+
+ If the tile cannot be quantized than the raw float or double values
+ are written to the output table.
+
+*/
+{
+ double *tiledata = 0;
+ int anynul, gotnulls = 0, datatype, tstatus, colnum;
+ long ii, row, nelem, offset;
+ int naxis;
+ long maxtilelen, tilelen, incre[] = {1, 1, 1, 1, 1, 1};
+ long naxes[MAX_COMPRESS_DIM], fpixel[MAX_COMPRESS_DIM];
+ long lpixel[MAX_COMPRESS_DIM], tile[MAX_COMPRESS_DIM];
+ long tilesize[MAX_COMPRESS_DIM];
+ long i0, i1, i2, i3, i4, i5;
+ char card[FLEN_CARD];
+
+ if (*status > 0)
+ return(*status);
+
+ maxtilelen = (outfptr->Fptr)->maxtilelen;
+
+ /* allocate buffer to hold 1 tile of data */
+ if ((outfptr->Fptr)->zbitpix == FLOAT_IMG)
+ {
+ datatype = TFLOAT;
+ tiledata = (double*) calloc (maxtilelen, sizeof (float));
+ }
+ else if ((outfptr->Fptr)->zbitpix == DOUBLE_IMG)
+ {
+ datatype = TDOUBLE;
+ tiledata = (double*) calloc (maxtilelen, sizeof (double));
+ }
+ else
+ {
+ datatype = TINT;
+ tiledata = (double*) calloc (maxtilelen, sizeof (int));
+ }
+
+ if (tiledata == NULL)
+ {
+ ffpmsg("Out of memory. (imcomp_compress_image)");
+ return (*status = MEMORY_ALLOCATION);
+ }
+
+ /* calculate size of tile in each dimension */
+ naxis = (outfptr->Fptr)->zndim;
+ for (ii = 0; ii < MAX_COMPRESS_DIM; ii++)
+ {
+ if (ii < naxis)
+ {
+ naxes[ii] = (outfptr->Fptr)->znaxis[ii];
+ tilesize[ii] = (outfptr->Fptr)->tilesize[ii];
+ }
+ else
+ {
+ naxes[ii] = 1;
+ tilesize[ii] = 1;
+ }
+ }
+ row = 1;
+
+ /* set up big loop over up to 6 dimensions */
+ for (i5 = 1; i5 <= naxes[5]; i5 += tilesize[5])
+ {
+ fpixel[5] = i5;
+ lpixel[5] = minvalue(i5 + tilesize[5] - 1, naxes[5]);
+ tile[5] = lpixel[5] - fpixel[5] + 1;
+ for (i4 = 1; i4 <= naxes[4]; i4 += tilesize[4])
+ {
+ fpixel[4] = i4;
+ lpixel[4] = minvalue(i4 + tilesize[4] - 1, naxes[4]);
+ tile[4] = lpixel[4] - fpixel[4] + 1;
+ for (i3 = 1; i3 <= naxes[3]; i3 += tilesize[3])
+ {
+ fpixel[3] = i3;
+ lpixel[3] = minvalue(i3 + tilesize[3] - 1, naxes[3]);
+ tile[3] = lpixel[3] - fpixel[3] + 1;
+ for (i2 = 1; i2 <= naxes[2]; i2 += tilesize[2])
+ {
+ fpixel[2] = i2;
+ lpixel[2] = minvalue(i2 + tilesize[2] - 1, naxes[2]);
+ tile[2] = lpixel[2] - fpixel[2] + 1;
+ for (i1 = 1; i1 <= naxes[1]; i1 += tilesize[1])
+ {
+ fpixel[1] = i1;
+ lpixel[1] = minvalue(i1 + tilesize[1] - 1, naxes[1]);
+ tile[1] = lpixel[1] - fpixel[1] + 1;
+ for (i0 = 1; i0 <= naxes[0]; i0 += tilesize[0])
+ {
+ fpixel[0] = i0;
+ lpixel[0] = minvalue(i0 + tilesize[0] - 1, naxes[0]);
+ tile[0] = lpixel[0] - fpixel[0] + 1;
+
+ /* number of pixels in this tile */
+ tilelen = tile[0];
+ for (ii = 1; ii < naxis; ii++)
+ {
+ tilelen *= tile[ii];
+ }
+
+ /* read next tile of data from image */
+ if (datatype == TFLOAT)
+ {
+ ffgsve(infptr, 1, naxis, naxes, fpixel, lpixel, incre,
+ FLOATNULLVALUE, (float *) tiledata, &anynul, status);
+ }
+ else if (datatype == TDOUBLE)
+ {
+ ffgsvd(infptr, 1, naxis, naxes, fpixel, lpixel, incre,
+ DOUBLENULLVALUE, tiledata, &anynul, status);
+ }
+ else /* read all integer data types as int */
+ {
+ ffgsvk(infptr, 1, naxis, naxes, fpixel, lpixel, incre,
+ 0, (int *) tiledata, &anynul, status);
+ }
+
+ /* now compress the tile, and write to row of binary table */
+
+ imcomp_compress_tile(outfptr, row, datatype, tiledata, tilelen,
+ status);
+
+ /* set flag if we found any null values */
+ if (anynul)
+ gotnulls = 1;
+
+ /* check for any error in the previous operations */
+ if (*status > 0)
+ {
+ ffpmsg("Error writing compressed image to table");
+ free(tiledata);
+ return (*status);
+ }
+
+ row++;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ free (tiledata); /* finished with this buffer */
+
+ /* insert ZBLANK keyword if necessary */
+ if (gotnulls)
+ {
+ ffgcrd(outfptr, "ZCMPTYPE", card, status);
+ ffikyj(outfptr, "ZBLANK", COMPRESS_NULL_VALUE,
+ "null value in the compressed integer array", status);
+ }
+
+ if (datatype >= TFLOAT )
+ {
+ /* check if any data were written to the UNCOMPRESSED_DATA column */
+ /* If not, then delete that column from the table */
+ for (ii = 1; ii < row; ii++)
+ {
+ ffgdes (outfptr, (outfptr->Fptr)->cn_uncompressed, ii,
+ &nelem, &offset, status);
+ if (nelem)
+ break;
+ }
+
+ if (!nelem)
+ {
+ tstatus = 0;
+ ffgcno(outfptr, CASEINSEN, "UNCOMPRESSED_DATA", &colnum, &tstatus);
+ if (tstatus == 0)
+ {
+ /* make sure table is properly terminated before deleting col */
+ /* (in particular, make sure the '1PB(nnn)' keyword is updated */
+ ffrdef(outfptr, status);
+ ffdcol(outfptr, colnum, status);
+ }
+ }
+ }
+
+ return (*status);
+}
+/*--------------------------------------------------------------------------*/
+int imcomp_compress_tile (fitsfile *outfptr,
+ long row,
+ int datatype,
+ void *tiledata,
+ long tilelen,
+ int *status)
+
+/*
+ This is the main compression routine.
+
+ This routine does the following to the input tile of pixels:
+ - if it is a float or double image, then it quantizes the pixels
+ - compresses the integer pixel values
+ - writes the compressed byte stream to the FITS file.
+
+ If the tile cannot be quantized than the raw float or double values
+ are written to the output table.
+*/
+{
+ int *idata = 0; /* quantized integer data */
+ short *cbuf; /* compressed data */
+ int clen; /* size of cbuf */
+ int flag = 1; /* true if data were quantized */
+ int iminval = 0, imaxval = 0; /* min and max quantized integers */
+ double bscale[1] = {1.}, bzero[1] = {0.}; /* scaling parameters */
+ int nelem = 0; /* number of bytes */
+ size_t gzip_nelem = 0;
+ long ii;
+
+ if (*status > 0)
+ return(*status);
+
+ if (datatype == TINT || datatype == TUINT)
+ {
+ /* POTENTIAL BUG?? When reading unsigned int values they will be */
+ /* interpret them as signed integers? */
+ idata = tiledata;
+ }
+ else
+ {
+ idata = (int*) calloc (tilelen, sizeof (int));
+ if (idata == NULL)
+ {
+ ffpmsg("Out of memory. (imcomp_compress_tile)");
+ return (*status = MEMORY_ALLOCATION);
+ }
+
+ if (datatype == TSHORT)
+ {
+ for (ii = 0; ii < tilelen; ii++)
+ idata[ii] = ((short *)tiledata)[ii];
+ }
+ else if (datatype == TUSHORT)
+ {
+ for (ii = 0; ii < tilelen; ii++)
+ idata[ii] = ((unsigned short *)tiledata)[ii];
+ }
+ else if (datatype == TLONG)
+ {
+ for (ii = 0; ii < tilelen; ii++)
+ idata[ii] = ((long *)tiledata)[ii];
+ }
+ else if (datatype == TBYTE)
+ {
+ for (ii = 0; ii < tilelen; ii++)
+ idata[ii] = ((unsigned char *)tiledata)[ii];
+ }
+ else if (datatype == TSBYTE)
+ {
+ for (ii = 0; ii < tilelen; ii++)
+ idata[ii] = ((signed char *)tiledata)[ii];
+ }
+ else if (datatype == TFLOAT)
+ {
+ /* if the tile-compressed table contains zscale and zzero columns */
+ /* then scale and quantize the input floating point data. */
+ /* Otherwise, just truncate the floats to integers. */
+ if ((outfptr->Fptr)->cn_zscale > 0)
+ {
+ /* quantize the float values into integers */
+ flag = fits_quantize_float ((float *) tiledata, tilelen,
+ FLOATNULLVALUE, (outfptr->Fptr)->rice_nbits, idata,
+ bscale, bzero, &iminval, &imaxval);
+ }
+ else
+ {
+ for (ii = 0; ii < tilelen; ii++)
+ idata[ii] = ((float *)tiledata)[ii];
+ }
+ }
+ else if (datatype == TDOUBLE)
+ {
+ /* if the tile-compressed table contains zscale and zzero columns */
+ /* then scale and quantize the input floating point data. */
+ /* Otherwise, just truncate the floats to integers. */
+ if ((outfptr->Fptr)->cn_zscale > 0)
+ {
+ /* quantize the double values into integers */
+ flag = fits_quantize_double ((double *) tiledata, tilelen,
+ DOUBLENULLVALUE, (outfptr->Fptr)->rice_nbits, idata,
+ bscale, bzero, &iminval, &imaxval);
+ }
+ else
+ {
+ for (ii = 0; ii < tilelen; ii++)
+ idata[ii] = ((double *)tiledata)[ii];
+ }
+ }
+ else
+ {
+ ffpmsg("unsupported datatype for compressing image");
+ free(idata);
+ return(*status = BAD_DATATYPE);
+ }
+ }
+
+ if (flag)
+ {
+ /* allocate buffer for the compressed tile bytes */
+ clen = (outfptr->Fptr)->maxelem;
+ cbuf = (short *) calloc (clen, sizeof (unsigned char));
+ if (cbuf == NULL)
+ {
+ ffpmsg("Out of memory. (imcomp_compress_tile)");
+ if (datatype != TINT && datatype != TUINT)
+ free(idata);
+ return (*status = MEMORY_ALLOCATION);
+ }
+
+ /* Compress the integer data, then write the compressed bytes */
+ if ( (outfptr->Fptr)->compress_type == RICE_1)
+ {
+ nelem = fits_rcomp (idata, tilelen, (unsigned char *) cbuf,
+ clen, (outfptr->Fptr)->rice_blocksize);
+
+ /* Write the compressed byte stream. */
+ ffpclb(outfptr, (outfptr->Fptr)->cn_compressed, row, 1,
+ nelem, (unsigned char *) cbuf, status);
+ }
+ else if ( (outfptr->Fptr)->compress_type == PLIO_1)
+ {
+ if (iminval < 0 || imaxval > 16777215)
+ {
+ /* plio algorithn only supports positive 24 bit ints */
+ ffpmsg("data out of range for PLIO compression (0 - 2**24)");
+ if (datatype != TINT && datatype != TUINT)
+ free(idata);
+ return(*status = DATA_DECOMPRESSION_ERR);
+ }
+
+ nelem = pl_p2li (idata, 1, cbuf, tilelen);
+
+ /* Write the compressed byte stream. */
+ ffpcli(outfptr, (outfptr->Fptr)->cn_compressed, row, 1,
+ nelem, cbuf, status);
+ }
+ else if ( (outfptr->Fptr)->compress_type == GZIP_1)
+ {
+
+#if BYTESWAPPED
+ ffswap4(idata, tilelen); /* reverse order of bytes */
+#endif
+ compress2mem_from_mem((char *) idata, tilelen * sizeof(int),
+ (char **) &cbuf, (size_t *) &clen, realloc,
+ &gzip_nelem, status);
+
+ /* Write the compressed byte stream. */
+ ffpclb(outfptr, (outfptr->Fptr)->cn_compressed, row, 1,
+ gzip_nelem, (unsigned char *) cbuf, status);
+ }
+ else if ( (outfptr->Fptr)->compress_type == HCOMPRESS_1)
+ {
+ /* add support for this compression algorithm here */
+ }
+
+ if (nelem < 0) /* error condition */
+ {
+ if (datatype != TINT && datatype != TUINT)
+ free(idata);
+ free (cbuf);
+ ffpmsg
+ ("error compressing row of the image (imcomp_compress_tile)");
+ return (*status = DATA_COMPRESSION_ERR);
+ }
+
+ if ((outfptr->Fptr)->cn_zscale > 0)
+ {
+ /* write the linear scaling parameters */
+ ffpcld (outfptr, (outfptr->Fptr)->cn_zscale, row, 1, 1,
+ bscale, status);
+ ffpcld (outfptr, (outfptr->Fptr)->cn_zzero, row, 1, 1,
+ bzero, status);
+ }
+
+ free(cbuf); /* finished with this buffer */
+ }
+ else /* floating point data couldn't be quantized */
+ {
+ /* Write the original floating point data. */
+ if (datatype == TFLOAT)
+ {
+ ffpcle (outfptr, (outfptr->Fptr)->cn_uncompressed, row, 1,
+ tilelen, (float *)tiledata, status);
+ }
+ else if (datatype == TDOUBLE)
+ {
+ ffpcld (outfptr, (outfptr->Fptr)->cn_uncompressed, row, 1,
+ tilelen, (double *)tiledata, status);
+ }
+ }
+
+ if (datatype != TINT && datatype != TUINT)
+ free(idata);
+
+ return (*status);
+}
+/*---------------------------------------------------------------------------*/
+int fits_write_compressed_img(fitsfile *fptr, /* I - FITS file pointer */
+ int datatype, /* I - datatype of the array to be written */
+ long *infpixel, /* I - 'bottom left corner' of the subsection */
+ long *inlpixel, /* I - 'top right corner' of the subsection */
+ int nullcheck, /* I - 0 for no null checking */
+ /* 1: pixels that are = nullval will be */
+ /* written with the FITS null pixel value */
+ /* (floating point arrays only) */
+ void *array, /* I - array of values to be written */
+ void *nullval, /* I - undefined pixel value (floating pt only) */
+ int *status) /* IO - error status */
+/*
+ Write a section of a compressed image.
+*/
+{
+ int naxis[MAX_COMPRESS_DIM], tiledim[MAX_COMPRESS_DIM];
+ long tilesize[MAX_COMPRESS_DIM], thistilesize[MAX_COMPRESS_DIM];
+ long ftile[MAX_COMPRESS_DIM], ltile[MAX_COMPRESS_DIM];
+ long tfpixel[MAX_COMPRESS_DIM], tlpixel[MAX_COMPRESS_DIM];
+ long rowdim[MAX_COMPRESS_DIM], offset[MAX_COMPRESS_DIM],ntemp;
+ long fpixel[MAX_COMPRESS_DIM], lpixel[MAX_COMPRESS_DIM];
+ int ii, i5, i4, i3, i2, i1, i0, ndim, irow, pixlen, tilenul;
+ void *buffer;
+ char *bnullarray = 0;
+
+ if (*status > 0)
+ return(*status);
+
+ if (!fits_is_compressed_image(fptr, status) )
+ {
+ ffpmsg("CHDU is not a compressed image (fits_write_compressed_img)");
+ return(*status = DATA_COMPRESSION_ERR);
+ }
+
+ /* reset position to the correct HDU if necessary */
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+
+ /* rescan header if data structure is undefined */
+ else if ((fptr->Fptr)->datastart == DATA_UNDEFINED)
+ if ( ffrdef(fptr, status) > 0)
+ return(*status);
+
+ /* get temporary space for uncompressing one image tile */
+ if (datatype == TSHORT)
+ {
+ buffer = calloc ((fptr->Fptr)->maxtilelen, sizeof (short));
+ pixlen = sizeof(short);
+ }
+ else if (datatype == TINT)
+ {
+ buffer = calloc ((fptr->Fptr)->maxtilelen, sizeof (int));
+ pixlen = sizeof(int);
+ }
+ else if (datatype == TLONG)
+ {
+ buffer = calloc ((fptr->Fptr)->maxtilelen, sizeof (long));
+ pixlen = sizeof(long);
+ }
+ else if (datatype == TFLOAT)
+ {
+ buffer = calloc ((fptr->Fptr)->maxtilelen, sizeof (float));
+ pixlen = sizeof(float);
+ }
+ else if (datatype == TDOUBLE)
+ {
+ buffer = calloc ((fptr->Fptr)->maxtilelen, sizeof (double));
+ pixlen = sizeof(double);
+ }
+ else if (datatype == TUSHORT)
+ {
+ buffer = calloc ((fptr->Fptr)->maxtilelen, sizeof (unsigned short));
+ pixlen = sizeof(short);
+ }
+ else if (datatype == TUINT)
+ {
+ buffer = calloc ((fptr->Fptr)->maxtilelen, sizeof (unsigned int));
+ pixlen = sizeof(int);
+ }
+ else if (datatype == TULONG)
+ {
+ buffer = calloc ((fptr->Fptr)->maxtilelen, sizeof (unsigned long));
+ pixlen = sizeof(long);
+ }
+ else if (datatype == TBYTE || datatype == TSBYTE)
+ {
+ buffer = calloc ((fptr->Fptr)->maxtilelen, sizeof (char));
+ pixlen = 1;
+ }
+ else
+ {
+ ffpmsg("unsupported datatype for compressing image");
+ return(*status = BAD_DATATYPE);
+ }
+
+ if (buffer == NULL)
+ {
+ ffpmsg("Out of memory (fits_write_compress_img)");
+ return (*status = MEMORY_ALLOCATION);
+ }
+
+ /* initialize all the arrays */
+ for (ii = 0; ii < MAX_COMPRESS_DIM; ii++)
+ {
+ naxis[ii] = 1;
+ tiledim[ii] = 1;
+ tilesize[ii] = 1;
+ ftile[ii] = 1;
+ ltile[ii] = 1;
+ rowdim[ii] = 1;
+ }
+
+ ndim = (fptr->Fptr)->zndim;
+ ntemp = 1;
+ for (ii = 0; ii < ndim; ii++)
+ {
+ fpixel[ii] = infpixel[ii];
+ lpixel[ii] = inlpixel[ii];
+
+ /* calc number of tiles in each dimension, and tile containing */
+ /* the first and last pixel we want to read in each dimension */
+ naxis[ii] = (fptr->Fptr)->znaxis[ii];
+ if (fpixel[ii] < 1)
+ {
+ free(buffer);
+ return(*status = BAD_PIX_NUM);
+ }
+
+ tilesize[ii] = (fptr->Fptr)->tilesize[ii];
+ tiledim[ii] = (naxis[ii] - 1) / tilesize[ii] + 1;
+ ftile[ii] = (fpixel[ii] - 1) / tilesize[ii] + 1;
+ ltile[ii] = minvalue((lpixel[ii] - 1) / tilesize[ii] + 1,
+ tiledim[ii]);
+ rowdim[ii] = ntemp; /* total tiles in each dimension */
+ ntemp *= tiledim[ii];
+ }
+
+ /* support up to 6 dimensions for now */
+ /* tfpixel and tlpixel are the first and last image pixels */
+ /* along each dimension of the compression tile */
+ for (i5 = ftile[5]; i5 <= ltile[5]; i5++)
+ {
+ tfpixel[5] = (i5 - 1) * tilesize[5] + 1;
+ tlpixel[5] = minvalue(tfpixel[5] + tilesize[5] - 1,
+ naxis[5]);
+ thistilesize[5] = tlpixel[5] - tfpixel[5] + 1;
+ offset[5] = (i5 - 1) * rowdim[5];
+ for (i4 = ftile[4]; i4 <= ltile[4]; i4++)
+ {
+ tfpixel[4] = (i4 - 1) * tilesize[4] + 1;
+ tlpixel[4] = minvalue(tfpixel[4] + tilesize[4] - 1,
+ naxis[4]);
+ thistilesize[4] = thistilesize[5] * (tlpixel[4] - tfpixel[4] + 1);
+ offset[4] = (i4 - 1) * rowdim[4] + offset[5];
+ for (i3 = ftile[3]; i3 <= ltile[3]; i3++)
+ {
+ tfpixel[3] = (i3 - 1) * tilesize[3] + 1;
+ tlpixel[3] = minvalue(tfpixel[3] + tilesize[3] - 1,
+ naxis[3]);
+ thistilesize[3] = thistilesize[4] * (tlpixel[3] - tfpixel[3] + 1);
+ offset[3] = (i3 - 1) * rowdim[3] + offset[4];
+ for (i2 = ftile[2]; i2 <= ltile[2]; i2++)
+ {
+ tfpixel[2] = (i2 - 1) * tilesize[2] + 1;
+ tlpixel[2] = minvalue(tfpixel[2] + tilesize[2] - 1,
+ naxis[2]);
+ thistilesize[2] = thistilesize[3] * (tlpixel[2] - tfpixel[2] + 1);
+ offset[2] = (i2 - 1) * rowdim[2] + offset[3];
+ for (i1 = ftile[1]; i1 <= ltile[1]; i1++)
+ {
+ tfpixel[1] = (i1 - 1) * tilesize[1] + 1;
+ tlpixel[1] = minvalue(tfpixel[1] + tilesize[1] - 1,
+ naxis[1]);
+ thistilesize[1] = thistilesize[2] * (tlpixel[1] - tfpixel[1] + 1);
+ offset[1] = (i1 - 1) * rowdim[1] + offset[2];
+ for (i0 = ftile[0]; i0 <= ltile[0]; i0++)
+ {
+ tfpixel[0] = (i0 - 1) * tilesize[0] + 1;
+ tlpixel[0] = minvalue(tfpixel[0] + tilesize[0] - 1,
+ naxis[0]);
+ thistilesize[0] = thistilesize[1] * (tlpixel[0] - tfpixel[0] + 1);
+ /* calculate row of table containing this tile */
+ irow = i0 + offset[1];
+
+ /* read and uncompress this row (tile) of the table */
+ /* also do type conversion and undefined pixel substitution */
+ /* at this point */
+
+ imcomp_decompress_tile(fptr, irow, thistilesize[0],
+ datatype, nullcheck, nullval, buffer, bnullarray, &tilenul,
+ status);
+
+ if (*status == NO_COMPRESSED_TILE)
+ {
+ /* tile doesn't exist, so initialize to zero */
+ memset(buffer, 0, pixlen * thistilesize[0]);
+ *status = 0;
+ }
+
+ /* copy the intersecting pixels to this tile from the input */
+ imcomp_merge_overlap(buffer, pixlen, ndim, tfpixel, tlpixel,
+ bnullarray, array, fpixel, lpixel, nullcheck, status);
+
+ /* compress the tile again, and write it back to the FITS file */
+ imcomp_compress_tile (fptr, irow, datatype, buffer,
+ thistilesize[0], status);
+ }
+ }
+ }
+ }
+ }
+ }
+ free(buffer);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fits_write_compressed_pixels(fitsfile *fptr, /* I - FITS file pointer */
+ int datatype, /* I - datatype of the array to be written */
+ OFF_T fpixel, /* I - 'first pixel to write */
+ long npixel, /* I - number of pixels to write */
+ int nullcheck, /* I - 0 for no null checking */
+ /* 1: pixels that are = nullval will be */
+ /* written with the FITS null pixel value */
+ /* (floating point arrays only) */
+ void *array, /* I - array of values to write */
+ void *nullval, /* I - value used to represent undefined pixels*/
+ int *status) /* IO - error status */
+/*
+ Write a consecutive set of pixels to a compressed image. This routine
+ interpretes the n-dimensional image as a long one-dimensional array.
+ This is actually a rather inconvenient way to write compressed images in
+ general, and could be rather inefficient if the requested pixels to be
+ written are located in many different image compression tiles.
+
+ The general strategy used here is to write the requested pixels in blocks
+ that correspond to rectangular image sections.
+*/
+{
+ int naxis, ii, bytesperpixel;
+ long naxes[MAX_COMPRESS_DIM], nread;
+ OFF_T tfirst, tlast, last0, last1, dimsize[MAX_COMPRESS_DIM];
+ long nplane, firstcoord[MAX_COMPRESS_DIM], lastcoord[MAX_COMPRESS_DIM];
+ char *arrayptr;
+
+ if (*status > 0)
+ return(*status);
+
+ arrayptr = (char *) array;
+
+ /* get size of array pixels, in bytes */
+ bytesperpixel = ffpxsz(datatype);
+
+ for (ii = 0; ii < MAX_COMPRESS_DIM; ii++)
+ {
+ naxes[ii] = 1;
+ firstcoord[ii] = 0;
+ lastcoord[ii] = 0;
+ }
+
+ /* determine the dimensions of the image to be read */
+ ffgidm(fptr, &naxis, status);
+ ffgisz(fptr, MAX_COMPRESS_DIM, naxes, status);
+
+ /* calc the cumulative number of pixels in each successive dimension */
+ dimsize[0] = 1;
+ for (ii = 1; ii < MAX_COMPRESS_DIM; ii++)
+ dimsize[ii] = dimsize[ii - 1] * naxes[ii - 1];
+
+ /* determine the coordinate of the first and last pixel in the image */
+ /* Use zero based indexes here */
+ tfirst = fpixel - 1;
+ tlast = tfirst + npixel - 1;
+ for (ii = naxis - 1; ii >= 0; ii--)
+ {
+ firstcoord[ii] = tfirst / dimsize[ii];
+ lastcoord[ii] = tlast / dimsize[ii];
+ tfirst = tfirst - firstcoord[ii] * dimsize[ii];
+ tlast = tlast - lastcoord[ii] * dimsize[ii];
+ }
+
+ /* to simplify things, treat 1-D, 2-D, and 3-D images as separate cases */
+
+ if (naxis == 1)
+ {
+ /* Simple: just write the requested range of pixels */
+
+ firstcoord[0] = firstcoord[0] + 1;
+ lastcoord[0] = lastcoord[0] + 1;
+ fits_write_compressed_img(fptr, datatype, firstcoord, lastcoord,
+ nullcheck, array, nullval, status);
+ return(*status);
+ }
+ else if (naxis == 2)
+ {
+ nplane = 0; /* write 1st (and only) plane of the image */
+
+ fits_write_compressed_img_plane(fptr, datatype, bytesperpixel,
+ nplane, firstcoord, lastcoord, naxes, nullcheck,
+ array, nullval, &nread, status);
+ }
+ else if (naxis == 3)
+ {
+ /* test for special case: writing an integral number of planes */
+ if (firstcoord[0] == 0 && firstcoord[1] == 0 &&
+ lastcoord[0] == naxes[0] - 1 && lastcoord[1] == naxes[1] - 1)
+ {
+ for (ii = 0; ii < MAX_COMPRESS_DIM; ii++)
+ {
+ /* convert from zero base to 1 base */
+ (firstcoord[ii])++;
+ (lastcoord[ii])++;
+ }
+
+ /* we can write the contiguous block of pixels in one go */
+ fits_write_compressed_img(fptr, datatype, firstcoord, lastcoord,
+ nullcheck, array, nullval, status);
+ return(*status);
+ }
+
+ /* save last coordinate in temporary variables */
+ last0 = lastcoord[0];
+ last1 = lastcoord[1];
+
+ if (firstcoord[2] < lastcoord[2])
+ {
+ /* we will write up to the last pixel in all but the last plane */
+ lastcoord[0] = naxes[0] - 1;
+ lastcoord[1] = naxes[1] - 1;
+ }
+
+ /* write one plane of the cube at a time, for simplicity */
+ for (nplane = firstcoord[2]; nplane <= lastcoord[2]; nplane++)
+ {
+ if (nplane == lastcoord[2])
+ {
+ lastcoord[0] = last0;
+ lastcoord[1] = last1;
+ }
+
+ fits_write_compressed_img_plane(fptr, datatype, bytesperpixel,
+ nplane, firstcoord, lastcoord, naxes, nullcheck,
+ arrayptr, nullval, &nread, status);
+
+ /* for all subsequent planes, we start with the first pixel */
+ firstcoord[0] = 0;
+ firstcoord[1] = 0;
+
+ /* increment pointers to next elements to be written */
+ arrayptr = arrayptr + nread * bytesperpixel;
+ }
+ }
+ else
+ {
+ ffpmsg("only 1D, 2D, or 3D images are currently supported");
+ return(*status = DATA_COMPRESSION_ERR);
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fits_write_compressed_img_plane(fitsfile *fptr, /* I - FITS file */
+ int datatype, /* I - datatype of the array to be written */
+ int bytesperpixel, /* I - number of bytes per pixel in array */
+ long nplane, /* I - which plane of the cube to write */
+ long *firstcoord, /* I coordinate of first pixel to write */
+ long *lastcoord, /* I coordinate of last pixel to write */
+ long *naxes, /* I size of each image dimension */
+ int nullcheck, /* I - 0 for no null checking */
+ /* 1: pixels that are = nullval will be */
+ /* written with the FITS null pixel value */
+ /* (floating point arrays only) */
+ void *array, /* I - array of values that are written */
+ void *nullval, /* I - value for undefined pixels */
+ long *nread, /* O - total number of pixels written */
+ int *status) /* IO - error status */
+
+ /*
+ in general we have to write the first partial row of the image,
+ followed by the middle complete rows, followed by the last
+ partial row of the image. If the first or last rows are complete,
+ then write them at the same time as all the middle rows.
+ */
+{
+ /* bottom left coord. and top right coord. */
+ long blc[MAX_COMPRESS_DIM], trc[MAX_COMPRESS_DIM];
+ char *arrayptr;
+
+ *nread = 0;
+
+ arrayptr = (char *) array;
+
+ blc[2] = nplane + 1;
+ trc[2] = nplane + 1;
+
+ if (firstcoord[0] != 0)
+ {
+ /* have to read a partial first row */
+ blc[0] = firstcoord[0] + 1;
+ blc[1] = firstcoord[1] + 1;
+ trc[1] = blc[1];
+ if (lastcoord[1] == firstcoord[1])
+ trc[0] = lastcoord[0] + 1; /* 1st and last pixels in same row */
+ else
+ trc[0] = naxes[0]; /* read entire rest of the row */
+
+ fits_write_compressed_img(fptr, datatype, blc, trc,
+ nullcheck, arrayptr, nullval, status);
+
+ *nread = *nread + trc[0] - blc[0] + 1;
+
+ if (lastcoord[1] == firstcoord[1])
+ {
+ return(*status); /* finished */
+ }
+
+ /* set starting coord to beginning of next line */
+ firstcoord[0] = 0;
+ firstcoord[1] += 1;
+ arrayptr = arrayptr + (trc[0] - blc[0] + 1) * bytesperpixel;
+ }
+
+ /* write contiguous complete rows of the image, if any */
+ blc[0] = 1;
+ blc[1] = firstcoord[1] + 1;
+ trc[0] = naxes[0];
+
+ if (lastcoord[0] + 1 == naxes[0])
+ {
+ /* can write the last complete row, too */
+ trc[1] = lastcoord[1] + 1;
+ }
+ else
+ {
+ /* last row is incomplete; have to read it separately */
+ trc[1] = lastcoord[1];
+ }
+
+ if (trc[1] >= blc[1]) /* must have at least one whole line to read */
+ {
+ fits_write_compressed_img(fptr, datatype, blc, trc,
+ nullcheck, arrayptr, nullval, status);
+
+ *nread = *nread + (trc[1] - blc[1] + 1) * naxes[0];
+
+ if (lastcoord[1] + 1 == trc[1])
+ return(*status); /* finished */
+
+ /* increment pointers for the last partial row */
+ arrayptr = arrayptr + (trc[1] - blc[1] + 1) * naxes[0] * bytesperpixel;
+
+ }
+
+ if (trc[1] == lastcoord[1] + 1)
+ return(*status); /* all done */
+
+ /* set starting and ending coord to last line */
+
+ trc[0] = lastcoord[0] + 1;
+ trc[1] = lastcoord[1] + 1;
+ blc[1] = trc[1];
+
+ fits_write_compressed_img(fptr, datatype, blc, trc,
+ nullcheck, arrayptr, nullval, status);
+
+ *nread = *nread + trc[0] - blc[0] + 1;
+
+ return(*status);
+}
+
+/* ######################################################################## */
+/* ### Image Decompression Routines ### */
+/* ######################################################################## */
+
+/*--------------------------------------------------------------------------*/
+int fits_decompress_img (fitsfile *infptr, /* image (bintable) to uncompress */
+ fitsfile *outfptr, /* empty HDU for output uncompressed image */
+ int *status) /* IO - error status */
+
+/*
+ This routine decompresses the whole image and writes it to the output file.
+*/
+
+{
+ double *data;
+ int ii, datatype = 0, byte_per_pix = 0;
+ int nullcheck, anynul;
+ long fpixel[MAX_COMPRESS_DIM], lpixel[MAX_COMPRESS_DIM];
+ long inc[MAX_COMPRESS_DIM];
+ long imgsize, memsize;
+ float *nulladdr, fnulval;
+ double dnulval;
+
+ if (*status > 0)
+ return(*status);
+
+ if (!fits_is_compressed_image(infptr, status) )
+ {
+ ffpmsg("CHDU is not a compressed image (fits_decompress_img)");
+ return(*status = DATA_DECOMPRESSION_ERR);
+ }
+
+ /* create an empty output image with the correct dimensions */
+ if (ffcrim(outfptr, (infptr->Fptr)->zbitpix, (infptr->Fptr)->zndim,
+ (infptr->Fptr)->znaxis, status) > 0)
+ {
+ ffpmsg("error creating output decompressed image HDU");
+ return (*status);
+ }
+ /* Copy the table header to the image header. */
+ if (imcomp_copy_imheader(infptr, outfptr, status) > 0)
+ {
+ ffpmsg("error copying header of compressed image");
+ return (*status);
+ }
+
+ /* force a rescan of the output header keywords, then reset the scaling */
+ /* in case the BSCALE and BZERO keywords are present, so that the */
+ /* decompressed values won't be scaled when written to the output image */
+ ffrdef(outfptr, status);
+ ffpscl(outfptr, 1.0, 0.0, status);
+ ffpscl(infptr, 1.0, 0.0, status);
+
+ /* initialize; no null checking is needed for integer images */
+ nullcheck = 0;
+ nulladdr = &fnulval;
+
+ /* determine datatype for image */
+ if ((infptr->Fptr)->zbitpix == BYTE_IMG)
+ {
+ datatype = TBYTE;
+ byte_per_pix = 1;
+ }
+ else if ((infptr->Fptr)->zbitpix == SHORT_IMG)
+ {
+ datatype = TSHORT;
+ byte_per_pix = sizeof(short);
+ }
+ else if ((infptr->Fptr)->zbitpix == LONG_IMG)
+ {
+ datatype = TINT;
+ byte_per_pix = sizeof(int);
+ }
+ else if ((infptr->Fptr)->zbitpix == FLOAT_IMG)
+ {
+ /* In the case of float images we must check for NaNs */
+ nullcheck = 1;
+ fnulval = FLOATNULLVALUE;
+ nulladdr = &fnulval;
+ datatype = TFLOAT;
+ byte_per_pix = sizeof(float);
+ }
+ else if ((infptr->Fptr)->zbitpix == DOUBLE_IMG)
+ {
+ /* In the case of double images we must check for NaNs */
+ nullcheck = 1;
+ dnulval = DOUBLENULLVALUE;
+ nulladdr = (float *) &dnulval;
+ datatype = TDOUBLE;
+ byte_per_pix = sizeof(double);
+ }
+
+ /* calculate size of the image (in pixels) */
+ imgsize = 1;
+ for (ii = 0; ii < (infptr->Fptr)->zndim; ii++)
+ {
+ imgsize *= (infptr->Fptr)->znaxis[ii];
+ fpixel[ii] = 1; /* Set first and last pixel to */
+ lpixel[ii] = (infptr->Fptr)->znaxis[ii]; /* include the entire image. */
+ inc[ii] = 1;
+ }
+ /* Calc equivalent number of double pixels same size as whole the image. */
+ /* We use double datatype to force the memory to be aligned properly */
+ memsize = ((imgsize * byte_per_pix) - 1) / sizeof(double) + 1;
+
+ /* allocate memory for the image */
+ data = (double*) calloc (memsize, sizeof(double));
+ if (!data)
+ {
+ ffpmsg("Couldn't allocate memory for the uncompressed image");
+ return(*status = MEMORY_ALLOCATION);
+ }
+
+ /* uncompress the entire image into memory */
+ /* This routine should be enhanced sometime to only need enough */
+ /* memory to uncompress one tile at a time. */
+ fits_read_compressed_img(infptr, datatype, fpixel, lpixel, inc,
+ nullcheck, nulladdr, data, NULL, &anynul, status);
+
+ /* write the image to the output file */
+ if (anynul)
+ fits_write_imgnull(outfptr, datatype, 1, imgsize, data, nulladdr,
+ status);
+ else
+ fits_write_img(outfptr, datatype, 1, imgsize, data, status);
+
+ free(data);
+ return (*status);
+}
+/*---------------------------------------------------------------------------*/
+int fits_read_compressed_img(fitsfile *fptr, /* I - FITS file pointer */
+ int datatype, /* I - datatype of the array to be returned */
+ long *infpixel, /* I - 'bottom left corner' of the subsection */
+ long *inlpixel, /* I - 'top right corner' of the subsection */
+ long *ininc, /* I - increment to be applied in each dimension */
+ int nullcheck, /* I - 0 for no null checking */
+ /* 1: set undefined pixels = nullval */
+ /* 2: set nullarray=1 for undefined pixels */
+ void *nullval, /* I - value for undefined pixels */
+ void *array, /* O - array of values that are returned */
+ char *nullarray, /* O - array of flags = 1 if nullcheck = 2 */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read a section of a compressed image; Note: lpixel may be larger than the
+ size of the uncompressed image. Only the pixels within the image will be
+ returned.
+*/
+{
+ int naxis[MAX_COMPRESS_DIM], tiledim[MAX_COMPRESS_DIM];
+ long tilesize[MAX_COMPRESS_DIM], thistilesize[MAX_COMPRESS_DIM];
+ long ftile[MAX_COMPRESS_DIM], ltile[MAX_COMPRESS_DIM];
+ long tfpixel[MAX_COMPRESS_DIM], tlpixel[MAX_COMPRESS_DIM];
+ long rowdim[MAX_COMPRESS_DIM], offset[MAX_COMPRESS_DIM],ntemp;
+ long fpixel[MAX_COMPRESS_DIM], lpixel[MAX_COMPRESS_DIM];
+ long inc[MAX_COMPRESS_DIM];
+ int ii, i5, i4, i3, i2, i1, i0, ndim, irow, pixlen, tilenul;
+ void *buffer;
+ char *bnullarray = 0;
+
+ if (*status > 0)
+ return(*status);
+
+ if (!fits_is_compressed_image(fptr, status) )
+ {
+ ffpmsg("CHDU is not a compressed image (fits_read_compressed_img)");
+ return(*status = DATA_DECOMPRESSION_ERR);
+ }
+
+ /* get temporary space for uncompressing one image tile */
+ if (datatype == TSHORT)
+ {
+ buffer = calloc ((fptr->Fptr)->maxtilelen, sizeof (short));
+ pixlen = sizeof(short);
+ }
+ else if (datatype == TINT)
+ {
+ buffer = calloc ((fptr->Fptr)->maxtilelen, sizeof (int));
+ pixlen = sizeof(int);
+ }
+ else if (datatype == TLONG)
+ {
+ buffer = calloc ((fptr->Fptr)->maxtilelen, sizeof (long));
+ pixlen = sizeof(long);
+ }
+ else if (datatype == TFLOAT)
+ {
+ buffer = calloc ((fptr->Fptr)->maxtilelen, sizeof (float));
+ pixlen = sizeof(float);
+ }
+ else if (datatype == TDOUBLE)
+ {
+ buffer = calloc ((fptr->Fptr)->maxtilelen, sizeof (double));
+ pixlen = sizeof(double);
+ }
+ else if (datatype == TUSHORT)
+ {
+ buffer = calloc ((fptr->Fptr)->maxtilelen, sizeof (unsigned short));
+ pixlen = sizeof(short);
+ }
+ else if (datatype == TUINT)
+ {
+ buffer = calloc ((fptr->Fptr)->maxtilelen, sizeof (unsigned int));
+ pixlen = sizeof(int);
+ }
+ else if (datatype == TULONG)
+ {
+ buffer = calloc ((fptr->Fptr)->maxtilelen, sizeof (unsigned long));
+ pixlen = sizeof(long);
+ }
+ else if (datatype == TBYTE || datatype == TSBYTE)
+ {
+ buffer = calloc ((fptr->Fptr)->maxtilelen, sizeof (char));
+ pixlen = 1;
+ }
+ else
+ {
+ ffpmsg("unsupported datatype for uncompressing image");
+ return(*status = BAD_DATATYPE);
+ }
+
+ if (buffer == NULL)
+ {
+ ffpmsg("Out of memory (fits_read_compress_img)");
+ return (*status = MEMORY_ALLOCATION);
+ }
+ /* allocate memory for a null flag array, if needed */
+ if (nullcheck == 2)
+ {
+ bnullarray = calloc ((fptr->Fptr)->maxtilelen, sizeof (char));
+
+ if (bnullarray == NULL)
+ {
+ ffpmsg("Out of memory (fits_read_compress_img)");
+ free(buffer);
+ return (*status = MEMORY_ALLOCATION);
+ }
+ }
+
+ /* initialize all the arrays */
+ for (ii = 0; ii < MAX_COMPRESS_DIM; ii++)
+ {
+ naxis[ii] = 1;
+ tiledim[ii] = 1;
+ tilesize[ii] = 1;
+ ftile[ii] = 1;
+ ltile[ii] = 1;
+ rowdim[ii] = 1;
+ }
+
+ ndim = (fptr->Fptr)->zndim;
+ ntemp = 1;
+ for (ii = 0; ii < ndim; ii++)
+ {
+ /* support for mirror-reversed image sections */
+ if (infpixel[ii] <= inlpixel[ii])
+ {
+ fpixel[ii] = infpixel[ii];
+ lpixel[ii] = inlpixel[ii];
+ inc[ii] = ininc[ii];
+ }
+ else
+ {
+ fpixel[ii] = inlpixel[ii];
+ lpixel[ii] = infpixel[ii];
+ inc[ii] = -ininc[ii];
+ }
+
+ /* calc number of tiles in each dimension, and tile containing */
+ /* the first and last pixel we want to read in each dimension */
+ naxis[ii] = (fptr->Fptr)->znaxis[ii];
+ if (fpixel[ii] < 1)
+ {
+ if (nullcheck == 2)
+ {
+ free(bnullarray);
+ }
+ free(buffer);
+ return(*status = BAD_PIX_NUM);
+ }
+
+ tilesize[ii] = (fptr->Fptr)->tilesize[ii];
+ tiledim[ii] = (naxis[ii] - 1) / tilesize[ii] + 1;
+ ftile[ii] = (fpixel[ii] - 1) / tilesize[ii] + 1;
+ ltile[ii] = minvalue((lpixel[ii] - 1) / tilesize[ii] + 1,
+ tiledim[ii]);
+ rowdim[ii] = ntemp; /* total tiles in each dimension */
+ ntemp *= tiledim[ii];
+ }
+
+ *anynul = 0; /* initialize */
+
+ /* support up to 6 dimensions for now */
+ /* tfpixel and tlpixel are the first and last image pixels */
+ /* along each dimension of the compression tile */
+ for (i5 = ftile[5]; i5 <= ltile[5]; i5++)
+ {
+ tfpixel[5] = (i5 - 1) * tilesize[5] + 1;
+ tlpixel[5] = minvalue(tfpixel[5] + tilesize[5] - 1,
+ naxis[5]);
+ thistilesize[5] = tlpixel[5] - tfpixel[5] + 1;
+ offset[5] = (i5 - 1) * rowdim[5];
+ for (i4 = ftile[4]; i4 <= ltile[4]; i4++)
+ {
+ tfpixel[4] = (i4 - 1) * tilesize[4] + 1;
+ tlpixel[4] = minvalue(tfpixel[4] + tilesize[4] - 1,
+ naxis[4]);
+ thistilesize[4] = thistilesize[5] * (tlpixel[4] - tfpixel[4] + 1);
+ offset[4] = (i4 - 1) * rowdim[4] + offset[5];
+ for (i3 = ftile[3]; i3 <= ltile[3]; i3++)
+ {
+ tfpixel[3] = (i3 - 1) * tilesize[3] + 1;
+ tlpixel[3] = minvalue(tfpixel[3] + tilesize[3] - 1,
+ naxis[3]);
+ thistilesize[3] = thistilesize[4] * (tlpixel[3] - tfpixel[3] + 1);
+ offset[3] = (i3 - 1) * rowdim[3] + offset[4];
+ for (i2 = ftile[2]; i2 <= ltile[2]; i2++)
+ {
+ tfpixel[2] = (i2 - 1) * tilesize[2] + 1;
+ tlpixel[2] = minvalue(tfpixel[2] + tilesize[2] - 1,
+ naxis[2]);
+ thistilesize[2] = thistilesize[3] * (tlpixel[2] - tfpixel[2] + 1);
+ offset[2] = (i2 - 1) * rowdim[2] + offset[3];
+ for (i1 = ftile[1]; i1 <= ltile[1]; i1++)
+ {
+ tfpixel[1] = (i1 - 1) * tilesize[1] + 1;
+ tlpixel[1] = minvalue(tfpixel[1] + tilesize[1] - 1,
+ naxis[1]);
+ thistilesize[1] = thistilesize[2] * (tlpixel[1] - tfpixel[1] + 1);
+ offset[1] = (i1 - 1) * rowdim[1] + offset[2];
+ for (i0 = ftile[0]; i0 <= ltile[0]; i0++)
+ {
+ tfpixel[0] = (i0 - 1) * tilesize[0] + 1;
+ tlpixel[0] = minvalue(tfpixel[0] + tilesize[0] - 1,
+ naxis[0]);
+ thistilesize[0] = thistilesize[1] * (tlpixel[0] - tfpixel[0] + 1);
+ /* calculate row of table containing this tile */
+ irow = i0 + offset[1];
+
+ /* read and uncompress this row (tile) of the table */
+ /* also do type conversion and undefined pixel substitution */
+ /* at this point */
+ imcomp_decompress_tile(fptr, irow, thistilesize[0],
+ datatype, nullcheck, nullval, buffer, bnullarray, &tilenul,
+ status);
+
+ if (tilenul && anynul)
+ *anynul = 1; /* there are null pixels */
+
+ /* copy the intersecting pixels from this tile to the output */
+ imcomp_copy_overlap(buffer, pixlen, ndim, tfpixel, tlpixel,
+ bnullarray, array, fpixel, lpixel, inc, nullcheck,
+ nullarray, status);
+ }
+ }
+ }
+ }
+ }
+ }
+ if (nullcheck == 2)
+ {
+ free(bnullarray);
+ }
+ free(buffer);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fits_read_compressed_pixels(fitsfile *fptr, /* I - FITS file pointer */
+ int datatype, /* I - datatype of the array to be returned */
+ OFF_T fpixel, /* I - 'first pixel to read */
+ long npixel, /* I - number of pixels to read */
+ int nullcheck, /* I - 0 for no null checking */
+ /* 1: set undefined pixels = nullval */
+ /* 2: set nullarray=1 for undefined pixels */
+ void *nullval, /* I - value for undefined pixels */
+ void *array, /* O - array of values that are returned */
+ char *nullarray, /* O - array of flags = 1 if nullcheck = 2 */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ int *status) /* IO - error status */
+/*
+ Read a consecutive set of pixels from a compressed image. This routine
+ interpretes the n-dimensional image as a long one-dimensional array.
+ This is actually a rather inconvenient way to read compressed images in
+ general, and could be rather inefficient if the requested pixels to be
+ read are located in many different image compression tiles.
+
+ The general strategy used here is to read the requested pixels in blocks
+ that correspond to rectangular image sections.
+*/
+{
+ int naxis, ii, bytesperpixel, planenul;
+ long naxes[MAX_COMPRESS_DIM], nread;
+ long inc[MAX_COMPRESS_DIM];
+ OFF_T tfirst, tlast, last0, last1, dimsize[MAX_COMPRESS_DIM];
+ long nplane, firstcoord[MAX_COMPRESS_DIM], lastcoord[MAX_COMPRESS_DIM];
+ char *arrayptr, *nullarrayptr;
+
+ if (*status > 0)
+ return(*status);
+
+ arrayptr = (char *) array;
+ nullarrayptr = nullarray;
+
+ /* get size of array pixels, in bytes */
+ bytesperpixel = ffpxsz(datatype);
+
+ for (ii = 0; ii < MAX_COMPRESS_DIM; ii++)
+ {
+ naxes[ii] = 1;
+ firstcoord[ii] = 0;
+ lastcoord[ii] = 0;
+ inc[ii] = 1;
+ }
+
+ /* determine the dimensions of the image to be read */
+ ffgidm(fptr, &naxis, status);
+ ffgisz(fptr, MAX_COMPRESS_DIM, naxes, status);
+
+ /* calc the cumulative number of pixels in each successive dimension */
+ dimsize[0] = 1;
+ for (ii = 1; ii < MAX_COMPRESS_DIM; ii++)
+ dimsize[ii] = dimsize[ii - 1] * naxes[ii - 1];
+
+ /* determine the coordinate of the first and last pixel in the image */
+ /* Use zero based indexes here */
+ tfirst = fpixel - 1;
+ tlast = tfirst + npixel - 1;
+ for (ii = naxis - 1; ii >= 0; ii--)
+ {
+ firstcoord[ii] = tfirst / dimsize[ii];
+ lastcoord[ii] = tlast / dimsize[ii];
+ tfirst = tfirst - firstcoord[ii] * dimsize[ii];
+ tlast = tlast - lastcoord[ii] * dimsize[ii];
+ }
+
+ /* to simplify things, treat 1-D, 2-D, and 3-D images as separate cases */
+
+ if (naxis == 1)
+ {
+ /* Simple: just read the requested range of pixels */
+
+ firstcoord[0] = firstcoord[0] + 1;
+ lastcoord[0] = lastcoord[0] + 1;
+ fits_read_compressed_img(fptr, datatype, firstcoord, lastcoord, inc,
+ nullcheck, nullval, array, nullarray, anynul, status);
+ return(*status);
+ }
+ else if (naxis == 2)
+ {
+ nplane = 0; /* read 1st (and only) plane of the image */
+
+ fits_read_compressed_img_plane(fptr, datatype, bytesperpixel,
+ nplane, firstcoord, lastcoord, inc, naxes, nullcheck, nullval,
+ array, nullarray, anynul, &nread, status);
+ }
+ else if (naxis == 3)
+ {
+ /* test for special case: reading an integral number of planes */
+ if (firstcoord[0] == 0 && firstcoord[1] == 0 &&
+ lastcoord[0] == naxes[0] - 1 && lastcoord[1] == naxes[1] - 1)
+ {
+ for (ii = 0; ii < MAX_COMPRESS_DIM; ii++)
+ {
+ /* convert from zero base to 1 base */
+ (firstcoord[ii])++;
+ (lastcoord[ii])++;
+ }
+
+ /* we can read the contiguous block of pixels in one go */
+ fits_read_compressed_img(fptr, datatype, firstcoord, lastcoord, inc,
+ nullcheck, nullval, array, nullarray, anynul, status);
+
+ return(*status);
+ }
+
+ if (anynul)
+ *anynul = 0; /* initialize */
+
+ /* save last coordinate in temporary variables */
+ last0 = lastcoord[0];
+ last1 = lastcoord[1];
+
+ if (firstcoord[2] < lastcoord[2])
+ {
+ /* we will read up to the last pixel in all but the last plane */
+ lastcoord[0] = naxes[0] - 1;
+ lastcoord[1] = naxes[1] - 1;
+ }
+
+ /* read one plane of the cube at a time, for simplicity */
+ for (nplane = firstcoord[2]; nplane <= lastcoord[2]; nplane++)
+ {
+ if (nplane == lastcoord[2])
+ {
+ lastcoord[0] = last0;
+ lastcoord[1] = last1;
+ }
+
+ fits_read_compressed_img_plane(fptr, datatype, bytesperpixel,
+ nplane, firstcoord, lastcoord, inc, naxes, nullcheck, nullval,
+ arrayptr, nullarrayptr, &planenul, &nread, status);
+
+ if (planenul && anynul)
+ *anynul = 1; /* there are null pixels */
+
+ /* for all subsequent planes, we start with the first pixel */
+ firstcoord[0] = 0;
+ firstcoord[1] = 0;
+
+ /* increment pointers to next elements to be read */
+ arrayptr = arrayptr + nread * bytesperpixel;
+ if (nullarrayptr && (nullcheck == 2) )
+ nullarrayptr = nullarrayptr + nread;
+ }
+ }
+ else
+ {
+ ffpmsg("only 1D, 2D, or 3D images are currently supported");
+ return(*status = DATA_DECOMPRESSION_ERR);
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fits_read_compressed_img_plane(fitsfile *fptr, /* I - FITS file */
+ int datatype, /* I - datatype of the array to be returned */
+ int bytesperpixel, /* I - number of bytes per pixel in array */
+ long nplane, /* I - which plane of the cube to read */
+ long *firstcoord, /* coordinate of first pixel to read */
+ long *lastcoord, /* coordinate of last pixel to read */
+ long *inc, /* increment of pixels to read */
+ long *naxes, /* size of each image dimension */
+ int nullcheck, /* I - 0 for no null checking */
+ /* 1: set undefined pixels = nullval */
+ /* 2: set nullarray=1 for undefined pixels */
+ void *nullval, /* I - value for undefined pixels */
+ void *array, /* O - array of values that are returned */
+ char *nullarray, /* O - array of flags = 1 if nullcheck = 2 */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ long *nread, /* O - total number of pixels read and returned*/
+ int *status) /* IO - error status */
+
+ /*
+ in general we have to read the first partial row of the image,
+ followed by the middle complete rows, followed by the last
+ partial row of the image. If the first or last rows are complete,
+ then read them at the same time as all the middle rows.
+ */
+{
+ /* bottom left coord. and top right coord. */
+ long blc[MAX_COMPRESS_DIM], trc[MAX_COMPRESS_DIM];
+ char *arrayptr, *nullarrayptr;
+ int tnull;
+
+ if (anynul)
+ *anynul = 0;
+
+ *nread = 0;
+
+ arrayptr = (char *) array;
+ nullarrayptr = nullarray;
+
+ blc[2] = nplane + 1;
+ trc[2] = nplane + 1;
+
+ if (firstcoord[0] != 0)
+ {
+ /* have to read a partial first row */
+ blc[0] = firstcoord[0] + 1;
+ blc[1] = firstcoord[1] + 1;
+ trc[1] = blc[1];
+ if (lastcoord[1] == firstcoord[1])
+ trc[0] = lastcoord[0] + 1; /* 1st and last pixels in same row */
+ else
+ trc[0] = naxes[0]; /* read entire rest of the row */
+
+ fits_read_compressed_img(fptr, datatype, blc, trc, inc,
+ nullcheck, nullval, arrayptr, nullarrayptr, &tnull, status);
+
+ *nread = *nread + trc[0] - blc[0] + 1;
+
+ if (tnull && anynul)
+ *anynul = 1; /* there are null pixels */
+
+ if (lastcoord[1] == firstcoord[1])
+ {
+ return(*status); /* finished */
+ }
+
+ /* set starting coord to beginning of next line */
+ firstcoord[0] = 0;
+ firstcoord[1] += 1;
+ arrayptr = arrayptr + (trc[0] - blc[0] + 1) * bytesperpixel;
+ if (nullarrayptr && (nullcheck == 2) )
+ nullarrayptr = nullarrayptr + (trc[0] - blc[0] + 1);
+
+ }
+
+ /* read contiguous complete rows of the image, if any */
+ blc[0] = 1;
+ blc[1] = firstcoord[1] + 1;
+ trc[0] = naxes[0];
+
+ if (lastcoord[0] + 1 == naxes[0])
+ {
+ /* can read the last complete row, too */
+ trc[1] = lastcoord[1] + 1;
+ }
+ else
+ {
+ /* last row is incomplete; have to read it separately */
+ trc[1] = lastcoord[1];
+ }
+
+ if (trc[1] >= blc[1]) /* must have at least one whole line to read */
+ {
+ fits_read_compressed_img(fptr, datatype, blc, trc, inc,
+ nullcheck, nullval, arrayptr, nullarrayptr, &tnull, status);
+
+ *nread = *nread + (trc[1] - blc[1] + 1) * naxes[0];
+
+ if (tnull && anynul)
+ *anynul = 1;
+
+ if (lastcoord[1] + 1 == trc[1])
+ return(*status); /* finished */
+
+ /* increment pointers for the last partial row */
+ arrayptr = arrayptr + (trc[1] - blc[1] + 1) * naxes[0] * bytesperpixel;
+ if (nullarrayptr && (nullcheck == 2) )
+ nullarrayptr = nullarrayptr + (trc[1] - blc[1] + 1) * naxes[0];
+ }
+
+ if (trc[1] == lastcoord[1] + 1)
+ return(*status); /* all done */
+
+ /* set starting and ending coord to last line */
+
+ trc[0] = lastcoord[0] + 1;
+ trc[1] = lastcoord[1] + 1;
+ blc[1] = trc[1];
+
+ fits_read_compressed_img(fptr, datatype, blc, trc, inc,
+ nullcheck, nullval, arrayptr, nullarrayptr, &tnull, status);
+
+ if (tnull)
+ *anynul = 1;
+
+ *nread = *nread + trc[0] - blc[0] + 1;
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int imcomp_get_compressed_image_par(fitsfile *infptr, int *status)
+
+/*
+ This routine reads keywords from a BINTABLE extension containing a
+ compressed image.
+*/
+{
+ char keyword[FLEN_KEYWORD];
+ char value[FLEN_VALUE];
+ int ii, tstatus;
+ long expect_nrows, maxtilelen;
+
+ if (*status > 0)
+ return(*status);
+
+ /* Copy relevant header keyword values to structure */
+ if (ffgky (infptr, TSTRING, "ZCMPTYPE", value, NULL, status) > 0)
+ {
+ ffpmsg("required ZCMPTYPE compression keyword not found in");
+ ffpmsg(" imcomp_get_compressed_image_par");
+ return(*status);
+ }
+
+ (infptr->Fptr)->zcmptype[0] = '\0';
+ strncat((infptr->Fptr)->zcmptype, value, 11);
+
+ if (!FSTRCMP(value, "RICE_1") )
+ (infptr->Fptr)->compress_type = RICE_1;
+ else if (!FSTRCMP(value, "HCOMPRESS_1") )
+ (infptr->Fptr)->compress_type = HCOMPRESS_1;
+ else if (!FSTRCMP(value, "GZIP_1") )
+ (infptr->Fptr)->compress_type = GZIP_1;
+ else if (!FSTRCMP(value, "PLIO_1") )
+ (infptr->Fptr)->compress_type = PLIO_1;
+ else
+ {
+ ffpmsg("Unknown image compression type:");
+ ffpmsg(value);
+ return (*status = DATA_DECOMPRESSION_ERR);
+ }
+
+ if (ffgky (infptr, TINT, "ZBITPIX", &(infptr->Fptr)->zbitpix,
+ NULL, status) > 0)
+ {
+ ffpmsg("required ZBITPIX compression keyword not found");
+ return(*status);
+ }
+
+ if (ffgky (infptr,TINT, "ZNAXIS", &(infptr->Fptr)->zndim, NULL, status) > 0)
+ {
+ ffpmsg("required ZNAXIS compression keyword not found");
+ return(*status);
+ }
+
+ if ((infptr->Fptr)->zndim < 1)
+ {
+ ffpmsg("Compressed image has no data (ZNAXIS < 1)");
+ return (*status = BAD_NAXIS);
+ }
+
+ if ((infptr->Fptr)->zndim > MAX_COMPRESS_DIM)
+ {
+ ffpmsg("Compressed image has too many dimensions");
+ return(*status = BAD_NAXIS);
+ }
+
+ expect_nrows = 1;
+ maxtilelen = 1;
+ for (ii = 0; ii < (infptr->Fptr)->zndim; ii++)
+ {
+ /* get image size */
+ sprintf (keyword, "ZNAXIS%d", ii+1);
+ ffgky (infptr, TLONG,keyword, &(infptr->Fptr)->znaxis[ii],NULL,status);
+
+ if (*status > 0)
+ {
+ ffpmsg("required ZNAXISn compression keyword not found");
+ return(*status);
+ }
+
+ /* get compression tile size */
+ sprintf (keyword, "ZTILE%d", ii+1);
+
+ /* set default tile size in case keywords are not present */
+ if (ii == 0)
+ (infptr->Fptr)->tilesize[0] = (infptr->Fptr)->znaxis[0];
+ else
+ (infptr->Fptr)->tilesize[ii] = 1;
+
+ tstatus = 0;
+ ffgky (infptr, TLONG, keyword, &(infptr->Fptr)->tilesize[ii], NULL,
+ &tstatus);
+
+ expect_nrows *= (((infptr->Fptr)->znaxis[ii] - 1) /
+ (infptr->Fptr)->tilesize[ii]+ 1);
+ maxtilelen *= (infptr->Fptr)->tilesize[ii];
+ }
+
+ /* check number of rows */
+ if (expect_nrows != (infptr->Fptr)->numrows)
+ {
+ ffpmsg(
+ "number of table rows != the number of tiles in compressed image");
+ return (*status = DATA_DECOMPRESSION_ERR);
+ }
+
+ /* read any algorithm specific parameters */
+ if ((infptr->Fptr)->compress_type == RICE_1 )
+ {
+ if (ffgky(infptr, TINT,"ZVAL1", &(infptr->Fptr)->rice_blocksize,
+ NULL, status) > 0)
+ {
+ ffpmsg("required ZVAL1 compression keyword not found");
+ return(*status);
+ }
+
+ if ((infptr->Fptr)->zbitpix < 0)
+ {
+ /* try to read the floating point quantization parameter */
+ tstatus = 0;
+ ffgky(infptr, TINT,"ZVAL2", &(infptr->Fptr)->rice_nbits,
+ NULL, &tstatus);
+ }
+ }
+ else
+ {
+ if ((infptr->Fptr)->zbitpix < 0)
+ {
+ /* try to read the floating point quantization parameter */
+ tstatus = 0;
+ ffgky(infptr, TINT,"ZVAL1", &(infptr->Fptr)->rice_nbits,
+ NULL, &tstatus);
+ }
+ }
+
+ /* store number of pixels in each compression tile, */
+ /* and max size of the compressed tile buffer */
+ (infptr->Fptr)->maxtilelen = maxtilelen;
+
+ (infptr->Fptr)->maxelem =
+ imcomp_calc_max_elem ((infptr->Fptr)->compress_type, maxtilelen,
+ (infptr->Fptr)->rice_blocksize);
+
+ /* Get Column numbers. */
+ if (ffgcno(infptr, CASEINSEN, "COMPRESSED_DATA",
+ &(infptr->Fptr)->cn_compressed, status) > 0)
+ {
+ ffpmsg("couldn't find COMPRESSED_DATA column (fits_get_compressed_img_par)");
+ return(*status = DATA_DECOMPRESSION_ERR);
+ }
+
+ ffpmrk(); /* put mark on message stack; erase any messages after this */
+
+ tstatus = 0;
+ ffgcno(infptr,CASEINSEN, "UNCOMPRESSED_DATA",
+ &(infptr->Fptr)->cn_uncompressed, &tstatus);
+
+ tstatus = 0;
+ if (ffgcno(infptr, CASEINSEN, "ZSCALE", &(infptr->Fptr)->cn_zscale,
+ &tstatus) > 0)
+ {
+ /* CMPSCALE column doesn't exist; see if there is a keyword */
+ tstatus = 0;
+ if (ffgky(infptr, TDOUBLE, "ZSCALE", &(infptr->Fptr)->zscale, NULL,
+ &tstatus) <= 0)
+ (infptr->Fptr)->cn_zscale = -1; /* flag for a constant ZSCALE */
+ }
+
+ tstatus = 0;
+ if (ffgcno(infptr, CASEINSEN, "ZZERO", &(infptr->Fptr)->cn_zzero,
+ &tstatus) > 0)
+ {
+ /* CMPZERO column doesn't exist; see if there is a keyword */
+ tstatus = 0;
+ if (ffgky(infptr, TDOUBLE, "ZZERO", &(infptr->Fptr)->zzero, NULL,
+ &tstatus) <= 0)
+ (infptr->Fptr)->cn_zzero = -1; /* flag for a constant ZZERO */
+ }
+
+ tstatus = 0;
+ if (ffgcno(infptr, CASEINSEN, "ZBLANK", &(infptr->Fptr)->cn_zblank,
+ &tstatus) > 0)
+ {
+ /* CMPZERO column doesn't exist; see if there is a keyword */
+ tstatus = 0;
+ if (ffgky(infptr, TINT, "ZBLANK", &(infptr->Fptr)->zblank, NULL,
+ &tstatus) <= 0)
+ (infptr->Fptr)->cn_zblank = -1; /* flag for a constant ZBLANK */
+ }
+
+ /* read the conventional BSCALE and BZERO scaling keywords, if present */
+ tstatus = 0;
+ if (ffgky (infptr, TDOUBLE, "BSCALE", &(infptr->Fptr)->cn_bscale,
+ NULL, &tstatus) > 0)
+ {
+ (infptr->Fptr)->cn_bscale = 1.0;
+ }
+
+ tstatus = 0;
+ if (ffgky (infptr, TDOUBLE, "BZERO", &(infptr->Fptr)->cn_bzero,
+ NULL, &tstatus) > 0)
+ {
+ (infptr->Fptr)->cn_bzero = 0.0;
+ }
+
+ ffcmrk(); /* clear any spurious error messages, back to the mark */
+ return (*status);
+}
+/*--------------------------------------------------------------------------*/
+int imcomp_copy_imheader(fitsfile *infptr, fitsfile *outfptr, int *status)
+/*
+ This routine reads the header keywords from the input image and
+ copies them to the output image; the manditory structural keywords
+ and the checksum keywords are not copied. If the DATE keyword is copied,
+ then it is updated with the current date and time.
+*/
+{
+ int nkeys, ii, keyclass;
+ char card[FLEN_CARD]; /* a header record */
+
+ if (*status > 0)
+ return(*status);
+
+ ffghsp(infptr, &nkeys, NULL, status); /* get number of keywords in image */
+
+ for (ii = 5; ii <= nkeys; ii++) /* skip the first 4 keywords */
+ {
+ ffgrec(infptr, ii, card, status);
+
+ keyclass = ffgkcl(card); /* Get the type/class of keyword */
+
+ /* don't copy structural keywords or checksum keywords */
+ if ((keyclass <= TYP_CMPRS_KEY) || (keyclass == TYP_CKSUM_KEY))
+ continue;
+
+ if (FSTRNCMP(card, "DATE ", 5) == 0) /* write current date */
+ {
+ ffpdat(outfptr, status);
+ }
+ else if (FSTRNCMP(card, "EXTNAME ", 8) == 0)
+ {
+ /* don't copy default EXTNAME keyword from a compressed image */
+ if (FSTRNCMP(card, "EXTNAME = 'COMPRESSED_IMAGE'", 28))
+ {
+ /* if EXTNAME keyword already exists, overwrite it */
+ /* otherwise append a new EXTNAME keyword */
+ ffucrd(outfptr, "EXTNAME", card, status);
+ }
+ }
+ else
+ {
+ /* just copy the keyword to the output header */
+ ffprec (outfptr, card, status);
+ }
+
+ if (*status > 0)
+ return (*status);
+ }
+ return (*status);
+}
+/*--------------------------------------------------------------------------*/
+int imcomp_decompress_tile (fitsfile *infptr,
+ int nrow, /* I - row of table to read and uncompress */
+ int tilelen, /* I - number of pixels in the tile */
+ int datatype, /* I - datatype to be returned in 'buffer' */
+ int nullcheck, /* I - 0 for no null checking */
+ void *nulval, /* I - value to be used for undefined pixels */
+ void *buffer, /* O - buffer for returned decompressed values */
+ char *bnullarray, /* O - buffer for returned null flags */
+ int *anynul, /* O - any null values returned? */
+ int *status)
+
+/* This routine decompresses one tile of the image */
+{
+ int *idata = 0; /* uncompressed integer data */
+ size_t idatalen, tilebytesize;
+ int ii, tnull; /* value in the data which represents nulls */
+ unsigned char *cbuf = 0; /* compressed data */
+ unsigned char charnull = 0;
+ short *sbuf = 0;
+ short snull = 0;
+ int blocksize;
+ double bscale, bzero, dummy = 0; /* scaling parameters */
+ long nelem = 0, offset = 0; /* number of bytes */
+
+ if (*status > 0)
+ return(*status);
+
+ /* get length of the compressed byte stream */
+ ffgdes (infptr, (infptr->Fptr)->cn_compressed, nrow, &nelem, &offset,
+ status);
+
+ /* EOF error here indicates that this tile has not yet been written */
+ if (*status == END_OF_FILE)
+ return(*status = NO_COMPRESSED_TILE);
+
+ /* **************************************************************** */
+ if (nelem == 0) /* tile was not compressed; read uncompressed data */
+ {
+ if ((infptr->Fptr)->cn_uncompressed < 1 )
+ {
+ return (*status = NO_COMPRESSED_TILE);
+ }
+
+ /* no compressed data, so simply read the uncompressed data */
+ /* directly from the UNCOMPRESSED_DATA column, then return */
+ ffgdes (infptr, (infptr->Fptr)->cn_uncompressed, nrow, &nelem,
+ &offset, status);
+
+ if (nelem == 0 && offset == 0)
+ return (*status = NO_COMPRESSED_TILE);
+
+ if (nullcheck <= 1)
+ fits_read_col(infptr, datatype, (infptr->Fptr)->cn_uncompressed,
+ nrow, 1, nelem, nulval, buffer, anynul, status);
+ else
+ fits_read_colnull(infptr, datatype, (infptr->Fptr)->cn_uncompressed,
+ nrow, 1, nelem, buffer, bnullarray, anynul, status);
+
+ return(*status);
+ }
+
+ /* **************************************************************** */
+
+ if (nullcheck == 2)
+ {
+ for (ii = 0; ii < tilelen; ii++) /* initialize the null array */
+ bnullarray[ii] = 0;
+ }
+
+ if (anynul)
+ *anynul = 0;
+
+ /* get linear scaling and offset values, if they exist */
+ if ((infptr->Fptr)->cn_zscale == 0)
+ {
+ /* set default scaling, if scaling is not defined */
+ bscale = 1.;
+ bzero = 0.;
+ }
+ else if ((infptr->Fptr)->cn_zscale == -1)
+ {
+ bscale = (infptr->Fptr)->zscale;
+ bzero = (infptr->Fptr)->zzero;
+ }
+ else
+ {
+ /* read the linear scale and offset values for this row */
+ ffgcvd (infptr, (infptr->Fptr)->cn_zscale, nrow, 1, 1, 0.,
+ &bscale, NULL, status);
+ ffgcvd (infptr, (infptr->Fptr)->cn_zzero, nrow, 1, 1, 0.,
+ &bzero, NULL, status);
+ if (*status > 0)
+ {
+ ffpmsg("error reading scaling factor and offset for compressed tile");
+ free(idata);
+ free (cbuf);
+ return (*status);
+ }
+ }
+
+ if (bscale == 1.0 && bzero == 0.0 )
+ {
+ /* if no other scaling has been specified, try using the values
+ given by the BSCALE and BZERO keywords, if any */
+
+ bscale = (infptr->Fptr)->cn_bscale;
+ bzero = (infptr->Fptr)->cn_bzero;
+ }
+
+ /* ************************************************************* */
+
+ /* get the value used to represent nulls in the int array */
+ if ((infptr->Fptr)->cn_zblank == 0)
+ {
+ nullcheck = 0; /* no null value; don't check for nulls */
+ }
+ else if ((infptr->Fptr)->cn_zblank == -1)
+ {
+ tnull = (infptr->Fptr)->zblank; /* use the the ZBLANK keyword */
+ }
+ else
+ {
+ /* read the null value for this row */
+ ffgcvk (infptr, (infptr->Fptr)->cn_zblank, nrow, 1, 1, 0.,
+ &tnull, NULL, status);
+ if (*status > 0)
+ {
+ ffpmsg("error reading null value for compressed tile");
+ free(idata);
+ free (cbuf);
+ return (*status);
+ }
+ }
+
+ /* ************************************************************* */
+
+ /* allocate memory for uncompressed integers */
+ idata = (int*) calloc (tilelen, sizeof (int));
+ if (idata == NULL)
+ {
+ ffpmsg("Out of memory for idata. (imcomp_decompress_tile)");
+ return (*status = MEMORY_ALLOCATION);
+ }
+
+ /* ************************************************************* */
+
+ if ((infptr->Fptr)->compress_type == RICE_1)
+ {
+ cbuf = (unsigned char *) calloc (nelem, sizeof (unsigned char));
+ if (cbuf == NULL)
+ {
+ ffpmsg("Out of memory for cbuf. (imcomp_decompress_tile)");
+ free(idata);
+ return (*status = MEMORY_ALLOCATION);
+ }
+
+ /* read array of compressed bytes */
+ if (fits_read_col(infptr, TBYTE, (infptr->Fptr)->cn_compressed, nrow,
+ 1, nelem, &charnull, cbuf, NULL, status) > 0)
+ {
+ ffpmsg("error reading compressed byte stream from binary table");
+ free (cbuf);
+ free(idata);
+ return (*status);
+ }
+
+ /* uncompress the data */
+ blocksize = (infptr->Fptr)->rice_blocksize;
+ if ((*status = fits_rdecomp (cbuf, nelem, (unsigned int *)idata,
+ tilelen, blocksize)))
+ {
+ free (cbuf);
+ free(idata);
+ return (*status);
+ }
+
+ free(cbuf);
+ }
+
+ /* ************************************************************* */
+
+ else if ((infptr->Fptr)->compress_type == PLIO_1)
+ {
+ sbuf = (short *) calloc (nelem, sizeof (short));
+ if (sbuf == NULL)
+ {
+ ffpmsg("Out of memory for sbuf. (imcomp_decompress_tile)");
+ free(idata);
+ return (*status = MEMORY_ALLOCATION);
+ }
+
+ /* read array of compressed bytes */
+ if (fits_read_col(infptr, TSHORT, (infptr->Fptr)->cn_compressed, nrow,
+ 1, nelem, &snull, sbuf, NULL, status) > 0)
+ {
+ ffpmsg("error reading compressed byte stream from binary table");
+ free(idata);
+ free (sbuf);
+ return (*status);
+ }
+
+ pl_l2pi (sbuf, 1, idata, tilelen); /* uncompress the data */
+ free(sbuf);
+ }
+
+ /* ************************************************************* */
+
+ else if ((infptr->Fptr)->compress_type == GZIP_1)
+ {
+ cbuf = (unsigned char *) calloc (nelem, sizeof (unsigned char));
+ if (cbuf == NULL)
+ {
+ ffpmsg("Out of memory for cbuf. (imcomp_decompress_tile)");
+ free(idata);
+ return (*status = MEMORY_ALLOCATION);
+ }
+
+ /* read array of compressed bytes */
+ if (fits_read_col(infptr, TBYTE, (infptr->Fptr)->cn_compressed, nrow,
+ 1, nelem, &charnull, cbuf, NULL, status) > 0)
+ {
+ ffpmsg("error reading compressed byte stream from binary table");
+ free(idata);
+ free (cbuf);
+ return (*status);
+ }
+
+ /* uncompress the data */
+ idatalen = tilelen * sizeof(int);
+ if (uncompress2mem_from_mem ((char *)cbuf, nelem,
+ (char **) &idata, &idatalen, realloc, &tilebytesize, status))
+ {
+ ffpmsg("uncompress2mem_from_mem returned with an error");
+ free(idata);
+ free (cbuf);
+ return (*status);
+ }
+
+#if BYTESWAPPED
+ ffswap4(idata, tilelen); /* reverse order of bytes */
+#endif
+
+ if (idatalen != tilebytesize)
+ {
+ ffpmsg("error: uncompressed tile has wrong size");
+ free(idata);
+ free (cbuf);
+ return (*status = DATA_DECOMPRESSION_ERR);
+ }
+
+ free(cbuf);
+ }
+
+ /* ************************************************************* */
+ else
+ {
+ ffpmsg("unknown compression algorithm");
+ free(idata);
+ return (*status = DATA_DECOMPRESSION_ERR);
+ }
+
+ /* ************************************************************* */
+ /* copy the uncompressed tile data to the output buffer, doing */
+ /* null checking, datatype conversion and linear scaling, if necessary */
+
+
+ if (nulval == 0)
+ nulval = &dummy; /* set address to dummy value */
+
+ if (datatype == TSHORT)
+ {
+ fffi4i2(idata, tilelen, bscale, bzero, nullcheck, tnull,
+ *(short *) nulval, bnullarray, anynul,
+ (short *) buffer, status);
+ }
+ else if (datatype == TINT)
+ {
+ fffi4int(idata, (long) tilelen, bscale, bzero, nullcheck, tnull,
+ *(int *) nulval, bnullarray, anynul,
+ (int *) buffer, status);
+ }
+ else if (datatype == TLONG)
+ {
+ fffi4i4(idata, tilelen, bscale, bzero, nullcheck, tnull,
+ *(long *) nulval, bnullarray, anynul,
+ (long *) buffer, status);
+ }
+ else if (datatype == TFLOAT)
+ {
+ fffi4r4(idata, tilelen, bscale, bzero, nullcheck, tnull,
+ *(float *) nulval, bnullarray, anynul,
+ (float *) buffer, status);
+ }
+ else if (datatype == TDOUBLE)
+ {
+ fffi4r8(idata, tilelen, bscale, bzero, nullcheck, tnull,
+ *(double *) nulval, bnullarray, anynul,
+ (double *) buffer, status);
+ }
+ else if (datatype == TBYTE)
+ {
+ fffi4i1(idata, tilelen, bscale, bzero, nullcheck, tnull,
+ *(unsigned char *) nulval, bnullarray, anynul,
+ (unsigned char *) buffer, status);
+ }
+ else if (datatype == TSBYTE)
+ {
+ fffi4s1(idata, tilelen, bscale, bzero, nullcheck, tnull,
+ *(signed char *) nulval, bnullarray, anynul,
+ (signed char *) buffer, status);
+ }
+ else if (datatype == TUSHORT)
+ {
+ fffi4u2(idata, tilelen, bscale, bzero, nullcheck, tnull,
+ *(unsigned short *) nulval, bnullarray, anynul,
+ (unsigned short *) buffer, status);
+ }
+ else if (datatype == TUINT)
+ {
+ fffi4uint(idata, tilelen, bscale, bzero, nullcheck, tnull,
+ *(unsigned int *) nulval, bnullarray, anynul,
+ (unsigned int *) buffer, status);
+ }
+ else if (datatype == TULONG)
+ {
+ fffi4u4(idata, tilelen, bscale, bzero, nullcheck, tnull,
+ *(unsigned long *) nulval, bnullarray, anynul,
+ (unsigned long *) buffer, status);
+ }
+ else
+ *status = BAD_DATATYPE;
+
+ free(idata);
+
+ return (*status);
+}
+/*--------------------------------------------------------------------------*/
+int imcomp_copy_overlap (
+ char *tile, /* I - multi dimensional array of tile pixels */
+ int pixlen, /* I - number of bytes in each tile or image pixel */
+ int ndim, /* I - number of dimension in the tile and image */
+ long *tfpixel, /* I - first pixel number in each dim. of the tile */
+ long *tlpixel, /* I - last pixel number in each dim. of the tile */
+ char *bnullarray, /* I - array of null flags; used if nullcheck = 2 */
+ char *image, /* O - multi dimensional output image */
+ long *fpixel, /* I - first pixel number in each dim. of the image */
+ long *lpixel, /* I - last pixel number in each dim. of the image */
+ long *ininc, /* I - increment to be applied in each image dimen. */
+ int nullcheck, /* I - 0, 1: do nothing; 2: set nullarray for nulls */
+ char *nullarray,
+ int *status)
+
+/*
+ copy the intersecting pixels from a decompressed tile to the output image.
+ Both the tile and the image must have the same number of dimensions.
+*/
+{
+ long imgdim[MAX_COMPRESS_DIM]; /* product of preceding dimensions in the */
+ /* output image, allowing for inc factor */
+ long tiledim[MAX_COMPRESS_DIM]; /* product of preceding dimensions in the */
+ /* tile, array; inc factor is not relevant */
+ long imgfpix[MAX_COMPRESS_DIM]; /* 1st img pix overlapping tile: 0 base, */
+ /* allowing for inc factor */
+ long imglpix[MAX_COMPRESS_DIM]; /* last img pix overlapping tile 0 base, */
+ /* allowing for inc factor */
+ long tilefpix[MAX_COMPRESS_DIM]; /* 1st tile pix overlapping img 0 base, */
+ /* allowing for inc factor */
+ long inc[MAX_COMPRESS_DIM]; /* local copy of input ininc */
+ long i1, i2, i3, i4; /* offset along each axis of the image */
+ long it1, it2, it3, it4;
+ long im1, im2, im3, im4; /* offset to image pixel, allowing for inc */
+ long ipos, tf, tl;
+ long t2, t3, t4; /* offset along each axis of the tile */
+ long tilepix, imgpix, tilepixbyte, imgpixbyte;
+ int ii, overlap_bytes, overlap_flags;
+
+ if (*status > 0)
+ return(*status);
+
+ for (ii = 0; ii < MAX_COMPRESS_DIM; ii++)
+ {
+ /* set default values for higher dimensions */
+ inc[ii] = 1;
+ imgdim[ii] = 1;
+ tiledim[ii] = 1;
+ imgfpix[ii] = 0;
+ imglpix[ii] = 0;
+ tilefpix[ii] = 0;
+ }
+
+ /* ------------------------------------------------------------ */
+ /* calc amount of overlap in each dimension; if there is zero */
+ /* overlap in any dimension then just return */
+ /* ------------------------------------------------------------ */
+
+ for (ii = 0; ii < ndim; ii++)
+ {
+ if (tlpixel[ii] < fpixel[ii] || tfpixel[ii] > lpixel[ii])
+ return(*status); /* there are no overlapping pixels */
+
+ inc[ii] = ininc[ii];
+
+ /* calc dimensions of the output image section */
+ imgdim[ii] = (lpixel[ii] - fpixel[ii]) / labs(inc[ii]) + 1;
+ if (imgdim[ii] < 1)
+ return(*status = NEG_AXIS);
+
+ /* calc dimensions of the tile */
+ tiledim[ii] = tlpixel[ii] - tfpixel[ii] + 1;
+ if (tiledim[ii] < 1)
+ return(*status = NEG_AXIS);
+
+ if (ii > 0)
+ tiledim[ii] *= tiledim[ii - 1]; /* product of dimensions */
+
+ /* first and last pixels in image that overlap with the tile, 0 base */
+ tf = tfpixel[ii] - 1;
+ tl = tlpixel[ii] - 1;
+
+ /* skip this plane if it falls in the cracks of the subsampled image */
+ while ((tf-(fpixel[ii] - 1)) % labs(inc[ii]))
+ {
+ tf++;
+ if (tf > tl)
+ return(*status); /* no overlapping pixels */
+ }
+
+ while ((tl-(fpixel[ii] - 1)) % labs(inc[ii]))
+ {
+ tl--;
+ if (tf > tl)
+ return(*status); /* no overlapping pixels */
+ }
+ imgfpix[ii] = maxvalue((tf - fpixel[ii] +1) / labs(inc[ii]) , 0);
+ imglpix[ii] = minvalue((tl - fpixel[ii] +1) / labs(inc[ii]) ,
+ imgdim[ii] - 1);
+
+ /* first pixel in the tile that overlaps with the image (0 base) */
+ tilefpix[ii] = maxvalue(fpixel[ii] - tfpixel[ii], 0);
+
+ while ((tfpixel[ii] + tilefpix[ii] - fpixel[ii]) % labs(inc[ii]))
+ {
+ (tilefpix[ii])++;
+ if (tilefpix[ii] >= tiledim[ii])
+ return(*status); /* no overlapping pixels */
+ }
+/*
+printf("ii tfpixel, tlpixel %d %d %d \n",ii, tfpixel[ii], tlpixel[ii]);
+printf("ii, tf, tl, imgfpix,imglpix, tilefpix %d %d %d %d %d %d\n",ii,
+ tf,tl,imgfpix[ii], imglpix[ii],tilefpix[ii]);
+*/
+ if (ii > 0)
+ imgdim[ii] *= imgdim[ii - 1]; /* product of dimensions */
+ }
+
+ /* ---------------------------------------------------------------- */
+ /* calc number of pixels in each row (first dimension) that overlap */
+ /* multiply by pixlen to get number of bytes to copy in each loop */
+ /* ---------------------------------------------------------------- */
+
+ if (inc[0] != 1)
+ overlap_flags = 1; /* can only copy 1 pixel at a time */
+ else
+ overlap_flags = imglpix[0] - imgfpix[0] + 1; /* can copy whole row */
+
+ overlap_bytes = overlap_flags * pixlen;
+
+ /* support up to 5 dimensions for now */
+ for (i4 = 0, it4=0; i4 <= imglpix[4] - imgfpix[4]; i4++, it4++)
+ {
+ /* increment plane if it falls in the cracks of the subsampled image */
+ while (ndim > 4 && (tfpixel[4] + tilefpix[4] - fpixel[4] + it4)
+ % labs(inc[4]) != 0)
+ it4++;
+
+ /* offset to start of hypercube */
+ if (inc[4] > 0)
+ im4 = (i4 + imgfpix[4]) * imgdim[3];
+ else
+ im4 = imgdim[4] - (i4 + 1 + imgfpix[4]) * imgdim[3];
+
+ t4 = (tilefpix[4] + it4) * tiledim[3];
+ for (i3 = 0, it3=0; i3 <= imglpix[3] - imgfpix[3]; i3++, it3++)
+ {
+ /* increment plane if it falls in the cracks of the subsampled image */
+ while (ndim > 3 && (tfpixel[3] + tilefpix[3] - fpixel[3] + it3)
+ % labs(inc[3]) != 0)
+ it3++;
+
+ /* offset to start of cube */
+ if (inc[3] > 0)
+ im3 = (i3 + imgfpix[3]) * imgdim[2] + im4;
+ else
+ im3 = imgdim[3] - (i3 + 1 + imgfpix[3]) * imgdim[2] + im4;
+
+ t3 = (tilefpix[3] + it3) * tiledim[2] + t4;
+
+ /* loop through planes of the image */
+ for (i2 = 0, it2=0; i2 <= imglpix[2] - imgfpix[2]; i2++, it2++)
+ {
+ /* incre plane if it falls in the cracks of the subsampled image */
+ while (ndim > 2 && (tfpixel[2] + tilefpix[2] - fpixel[2] + it2)
+ % labs(inc[2]) != 0)
+ it2++;
+
+ /* offset to start of plane */
+ if (inc[2] > 0)
+ im2 = (i2 + imgfpix[2]) * imgdim[1] + im3;
+ else
+ im2 = imgdim[2] - (i2 + 1 + imgfpix[2]) * imgdim[1] + im3;
+
+ t2 = (tilefpix[2] + it2) * tiledim[1] + t3;
+
+ /* loop through rows of the image */
+ for (i1 = 0, it1=0; i1 <= imglpix[1] - imgfpix[1]; i1++, it1++)
+ {
+ /* incre row if it falls in the cracks of the subsampled image */
+ while (ndim > 1 && (tfpixel[1] + tilefpix[1] - fpixel[1] + it1)
+ % labs(inc[1]) != 0)
+ it1++;
+
+ /* calc position of first pixel in tile to be copied */
+ tilepix = tilefpix[0] + (tilefpix[1] + it1) * tiledim[0] + t2;
+
+ /* offset to start of row */
+ if (inc[1] > 0)
+ im1 = (i1 + imgfpix[1]) * imgdim[0] + im2;
+ else
+ im1 = imgdim[1] - (i1 + 1 + imgfpix[1]) * imgdim[0] + im2;
+/*
+printf("inc = %d %d %d %d\n",inc[0],inc[1],inc[2],inc[3]);
+printf("im1,im2,im3,im4 = %d %d %d %d\n",im1,im2,im3,im4);
+*/
+ /* offset to byte within the row */
+ if (inc[0] > 0)
+ imgpix = imgfpix[0] + im1;
+ else
+ imgpix = imgdim[0] - 1 - imgfpix[0] + im1;
+/*
+printf("tilefpix0,1, imgfpix1, it1, inc1, t2= %d %d %d %d %d %d\n",
+ tilefpix[0],tilefpix[1],imgfpix[1],it1,inc[1], t2);
+printf("i1, it1, tilepix, imgpix %d %d %d %d \n", i1, it1, tilepix, imgpix);
+*/
+ /* loop over pixels along one row of the image */
+ for (ipos = imgfpix[0]; ipos <= imglpix[0]; ipos += overlap_flags)
+ {
+ if (nullcheck == 2)
+ {
+ /* copy overlapping null flags from tile to image */
+ memcpy(nullarray + imgpix, bnullarray + tilepix,
+ overlap_flags);
+ }
+
+ /* convert from image pixel to byte offset */
+ tilepixbyte = tilepix * pixlen;
+ imgpixbyte = imgpix * pixlen;
+/*
+printf(" tilepix, tilepixbyte, imgpix, imgpixbyte= %d %d %d %d\n",
+ tilepix, tilepixbyte, imgpix, imgpixbyte);
+*/
+ /* copy overlapping row of pixels from tile to image */
+ memcpy(image + imgpixbyte, tile + tilepixbyte, overlap_bytes);
+
+ tilepix += (overlap_flags * labs(inc[0]));
+ if (inc[0] > 0)
+ imgpix += overlap_flags;
+ else
+ imgpix -= overlap_flags;
+ }
+ }
+ }
+ }
+ }
+ return(*status);
+}
+
+/*--------------------------------------------------------------------------*/
+int imcomp_merge_overlap (
+ char *tile, /* O - multi dimensional array of tile pixels */
+ int pixlen, /* I - number of bytes in each tile or image pixel */
+ int ndim, /* I - number of dimension in the tile and image */
+ long *tfpixel, /* I - first pixel number in each dim. of the tile */
+ long *tlpixel, /* I - last pixel number in each dim. of the tile */
+ char *bnullarray, /* I - array of null flags; used if nullcheck = 2 */
+ char *image, /* I - multi dimensional output image */
+ long *fpixel, /* I - first pixel number in each dim. of the image */
+ long *lpixel, /* I - last pixel number in each dim. of the image */
+ int nullcheck, /* I - 0, 1: do nothing; 2: set nullarray for nulls */
+ int *status)
+
+/*
+ Similar to imcomp_copy_overlap, except it copies the overlapping pixels from
+ the 'image' to the 'tile'.
+*/
+{
+ long imgdim[MAX_COMPRESS_DIM]; /* product of preceding dimensions in the */
+ /* output image, allowing for inc factor */
+ long tiledim[MAX_COMPRESS_DIM]; /* product of preceding dimensions in the */
+ /* tile, array; inc factor is not relevant */
+ long imgfpix[MAX_COMPRESS_DIM]; /* 1st img pix overlapping tile: 0 base, */
+ /* allowing for inc factor */
+ long imglpix[MAX_COMPRESS_DIM]; /* last img pix overlapping tile 0 base, */
+ /* allowing for inc factor */
+ long tilefpix[MAX_COMPRESS_DIM]; /* 1st tile pix overlapping img 0 base, */
+ /* allowing for inc factor */
+ long inc[MAX_COMPRESS_DIM]; /* local copy of input ininc */
+ long i1, i2, i3, i4; /* offset along each axis of the image */
+ long it1, it2, it3, it4;
+ long im1, im2, im3, im4; /* offset to image pixel, allowing for inc */
+ long ipos, tf, tl;
+ long t2, t3, t4; /* offset along each axis of the tile */
+ long tilepix, imgpix, tilepixbyte, imgpixbyte;
+ int ii, overlap_bytes, overlap_flags;
+
+ if (*status > 0)
+ return(*status);
+
+ for (ii = 0; ii < MAX_COMPRESS_DIM; ii++)
+ {
+ /* set default values for higher dimensions */
+ inc[ii] = 1;
+ imgdim[ii] = 1;
+ tiledim[ii] = 1;
+ imgfpix[ii] = 0;
+ imglpix[ii] = 0;
+ tilefpix[ii] = 0;
+ }
+
+ /* ------------------------------------------------------------ */
+ /* calc amount of overlap in each dimension; if there is zero */
+ /* overlap in any dimension then just return */
+ /* ------------------------------------------------------------ */
+
+ for (ii = 0; ii < ndim; ii++)
+ {
+ if (tlpixel[ii] < fpixel[ii] || tfpixel[ii] > lpixel[ii])
+ return(*status); /* there are no overlapping pixels */
+
+ /* calc dimensions of the output image section */
+ imgdim[ii] = (lpixel[ii] - fpixel[ii]) / labs(inc[ii]) + 1;
+ if (imgdim[ii] < 1)
+ return(*status = NEG_AXIS);
+
+ /* calc dimensions of the tile */
+ tiledim[ii] = tlpixel[ii] - tfpixel[ii] + 1;
+ if (tiledim[ii] < 1)
+ return(*status = NEG_AXIS);
+
+ if (ii > 0)
+ tiledim[ii] *= tiledim[ii - 1]; /* product of dimensions */
+
+ /* first and last pixels in image that overlap with the tile, 0 base */
+ tf = tfpixel[ii] - 1;
+ tl = tlpixel[ii] - 1;
+
+ /* skip this plane if it falls in the cracks of the subsampled image */
+ while ((tf-(fpixel[ii] - 1)) % labs(inc[ii]))
+ {
+ tf++;
+ if (tf > tl)
+ return(*status); /* no overlapping pixels */
+ }
+
+ while ((tl-(fpixel[ii] - 1)) % labs(inc[ii]))
+ {
+ tl--;
+ if (tf > tl)
+ return(*status); /* no overlapping pixels */
+ }
+ imgfpix[ii] = maxvalue((tf - fpixel[ii] +1) / labs(inc[ii]) , 0);
+ imglpix[ii] = minvalue((tl - fpixel[ii] +1) / labs(inc[ii]) ,
+ imgdim[ii] - 1);
+
+ /* first pixel in the tile that overlaps with the image (0 base) */
+ tilefpix[ii] = maxvalue(fpixel[ii] - tfpixel[ii], 0);
+
+ while ((tfpixel[ii] + tilefpix[ii] - fpixel[ii]) % labs(inc[ii]))
+ {
+ (tilefpix[ii])++;
+ if (tilefpix[ii] >= tiledim[ii])
+ return(*status); /* no overlapping pixels */
+ }
+/*
+printf("ii tfpixel, tlpixel %d %d %d \n",ii, tfpixel[ii], tlpixel[ii]);
+printf("ii, tf, tl, imgfpix,imglpix, tilefpix %d %d %d %d %d %d\n",ii,
+ tf,tl,imgfpix[ii], imglpix[ii],tilefpix[ii]);
+*/
+ if (ii > 0)
+ imgdim[ii] *= imgdim[ii - 1]; /* product of dimensions */
+ }
+
+ /* ---------------------------------------------------------------- */
+ /* calc number of pixels in each row (first dimension) that overlap */
+ /* multiply by pixlen to get number of bytes to copy in each loop */
+ /* ---------------------------------------------------------------- */
+
+ if (inc[0] != 1)
+ overlap_flags = 1; /* can only copy 1 pixel at a time */
+ else
+ overlap_flags = imglpix[0] - imgfpix[0] + 1; /* can copy whole row */
+
+ overlap_bytes = overlap_flags * pixlen;
+
+ /* support up to 5 dimensions for now */
+ for (i4 = 0, it4=0; i4 <= imglpix[4] - imgfpix[4]; i4++, it4++)
+ {
+ /* increment plane if it falls in the cracks of the subsampled image */
+ while (ndim > 4 && (tfpixel[4] + tilefpix[4] - fpixel[4] + it4)
+ % labs(inc[4]) != 0)
+ it4++;
+
+ /* offset to start of hypercube */
+ if (inc[4] > 0)
+ im4 = (i4 + imgfpix[4]) * imgdim[3];
+ else
+ im4 = imgdim[4] - (i4 + 1 + imgfpix[4]) * imgdim[3];
+
+ t4 = (tilefpix[4] + it4) * tiledim[3];
+ for (i3 = 0, it3=0; i3 <= imglpix[3] - imgfpix[3]; i3++, it3++)
+ {
+ /* increment plane if it falls in the cracks of the subsampled image */
+ while (ndim > 3 && (tfpixel[3] + tilefpix[3] - fpixel[3] + it3)
+ % labs(inc[3]) != 0)
+ it3++;
+
+ /* offset to start of cube */
+ if (inc[3] > 0)
+ im3 = (i3 + imgfpix[3]) * imgdim[2] + im4;
+ else
+ im3 = imgdim[3] - (i3 + 1 + imgfpix[3]) * imgdim[2] + im4;
+
+ t3 = (tilefpix[3] + it3) * tiledim[2] + t4;
+
+ /* loop through planes of the image */
+ for (i2 = 0, it2=0; i2 <= imglpix[2] - imgfpix[2]; i2++, it2++)
+ {
+ /* incre plane if it falls in the cracks of the subsampled image */
+ while (ndim > 2 && (tfpixel[2] + tilefpix[2] - fpixel[2] + it2)
+ % labs(inc[2]) != 0)
+ it2++;
+
+ /* offset to start of plane */
+ if (inc[2] > 0)
+ im2 = (i2 + imgfpix[2]) * imgdim[1] + im3;
+ else
+ im2 = imgdim[2] - (i2 + 1 + imgfpix[2]) * imgdim[1] + im3;
+
+ t2 = (tilefpix[2] + it2) * tiledim[1] + t3;
+
+ /* loop through rows of the image */
+ for (i1 = 0, it1=0; i1 <= imglpix[1] - imgfpix[1]; i1++, it1++)
+ {
+ /* incre row if it falls in the cracks of the subsampled image */
+ while (ndim > 1 && (tfpixel[1] + tilefpix[1] - fpixel[1] + it1)
+ % labs(inc[1]) != 0)
+ it1++;
+
+ /* calc position of first pixel in tile to be copied */
+ tilepix = tilefpix[0] + (tilefpix[1] + it1) * tiledim[0] + t2;
+
+ /* offset to start of row */
+ if (inc[1] > 0)
+ im1 = (i1 + imgfpix[1]) * imgdim[0] + im2;
+ else
+ im1 = imgdim[1] - (i1 + 1 + imgfpix[1]) * imgdim[0] + im2;
+/*
+printf("inc = %d %d %d %d\n",inc[0],inc[1],inc[2],inc[3]);
+printf("im1,im2,im3,im4 = %d %d %d %d\n",im1,im2,im3,im4);
+*/
+ /* offset to byte within the row */
+ if (inc[0] > 0)
+ imgpix = imgfpix[0] + im1;
+ else
+ imgpix = imgdim[0] - 1 - imgfpix[0] + im1;
+/*
+printf("tilefpix0,1, imgfpix1, it1, inc1, t2= %d %d %d %d %d %d\n",
+ tilefpix[0],tilefpix[1],imgfpix[1],it1,inc[1], t2);
+printf("i1, it1, tilepix, imgpix %d %d %d %d \n", i1, it1, tilepix, imgpix);
+*/
+ /* loop over pixels along one row of the image */
+ for (ipos = imgfpix[0]; ipos <= imglpix[0]; ipos += overlap_flags)
+ {
+ /* convert from image pixel to byte offset */
+ tilepixbyte = tilepix * pixlen;
+ imgpixbyte = imgpix * pixlen;
+/*
+printf(" tilepix, tilepixbyte, imgpix, imgpixbyte= %d %d %d %d\n",
+ tilepix, tilepixbyte, imgpix, imgpixbyte);
+*/
+ /* copy overlapping row of pixels from image to tile */
+ memcpy(tile + tilepixbyte, image + imgpixbyte, overlap_bytes);
+
+ tilepix += (overlap_flags * labs(inc[0]));
+ if (inc[0] > 0)
+ imgpix += overlap_flags;
+ else
+ imgpix -= overlap_flags;
+ }
+ }
+ }
+ }
+ }
+ return(*status);
+}
diff --git a/pkg/tbtables/cfitsio/iraffits.c b/pkg/tbtables/cfitsio/iraffits.c
new file mode 100644
index 00000000..db6940d6
--- /dev/null
+++ b/pkg/tbtables/cfitsio/iraffits.c
@@ -0,0 +1,1975 @@
+/*------------------------------------------------------------------------*/
+/* */
+/* These routines have been modified by William Pence for use by CFITSIO */
+/* The original files were provided by Doug Mink */
+/*------------------------------------------------------------------------*/
+
+/* File imhfile.c
+ * August 6, 1998
+ * By Doug Mink, based on Mike VanHilst's readiraf.c
+
+ * Module: imhfile.c (IRAF .imh image file reading and writing)
+ * Purpose: Read and write IRAF image files (and translate headers)
+ * 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: 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: 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
+
+
+ * 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 <stddef.h> /* stddef.h is apparently needed to define size_t */
+#include <string.h>
+
+#define FILE_NOT_OPENED 104
+
+/* 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_PIXHDR 1024
+#define MAXINT 2147483647 /* Biggest number that can fit in long */
+
+static int isirafswapped(char *irafheader, int offset);
+static int irafgeti4(char *irafheader, int offset);
+static char *irafgetc2(char *irafheader, int offset, int nc);
+static char *irafgetc(char *irafheader, int offset, int nc);
+static char *iraf2str(char *irafstring, int nchar);
+static char *irafrdhead(char *filename, int *lihead);
+static int irafrdimage (char **buffptr, size_t *buffsize,
+ size_t *filesize, int *status);
+static int iraftofits (char *hdrname, char *irafheader, int nbiraf,
+ char **buffptr, size_t *nbfits, size_t *fitssize, int *status);
+static char *same_path(char *pixname, char *hdrname);
+
+static int swaphead=0; /* =1 to swap data bytes of IRAF header values */
+static int swapdata=0; /* =1 to swap bytes in IRAF data pixels */
+
+static void irafswap(int bitpix, char *string, int nbytes);
+static void irafswap2(char *string, int nbytes);
+static void irafswap4(char *string, int nbytes);
+static void irafswap8(char *string, int nbytes);
+static int pix_version (char *irafheader);
+static int irafncmp (char *irafheader, char *teststring, int nc);
+static int machswap(void);
+static int head_version (char *irafheader);
+static int hgeti4(char* hstring, char* keyword, int* val);
+static int hgets(char* hstring, char* keyword, int lstr, char* string);
+static char* hgetc(char* hstring, char* keyword);
+static char* ksearch(char* hstring, char* keyword);
+static char *blsearch (char* hstring, char* keyword);
+static char *strsrch (char* s1, char* s2);
+static char *strnsrch ( char* s1,char* s2,int ls1);
+static void hputi4(char* hstring,char* keyword, int ival);
+static void hputs(char* hstring,char* keyword,char* cval);
+static void hputcom(char* hstring,char* keyword,char* comment);
+static void hputl(char* hstring,char* keyword,int lval);
+static void hputc(char* hstring,char* keyword,char* cval);
+
+int iraf2mem(char *filename, char **buffptr, size_t *buffsize,
+ size_t *filesize, int *status);
+
+void ffpmsg(const char *err_message);
+
+/*--------------------------------------------------------------------------*/
+int iraf2mem(char *filename, /* name of input file */
+ char **buffptr, /* O - memory pointer (initially NULL) */
+ size_t *buffsize, /* O - size of mem buffer, in bytes */
+ size_t *filesize, /* O - size of FITS file, in bytes */
+ int *status) /* IO - error status */
+
+/*
+ Driver routine that reads an IRAF image into memory, also converting
+ it into FITS format.
+*/
+{
+ char *irafheader;
+ int lenirafhead;
+
+ *buffptr = NULL;
+ *buffsize = 0;
+ *filesize = 0;
+
+ /* read IRAF header into dynamically created char array (free it later!) */
+ irafheader = irafrdhead(filename, &lenirafhead);
+
+ if (!irafheader)
+ {
+ return(*status = FILE_NOT_OPENED);
+ }
+
+ /* convert IRAF header to FITS header in memory */
+ iraftofits(filename, irafheader, lenirafhead, buffptr, buffsize, filesize,
+ status);
+
+ /* don't need the IRAF header any more */
+ free(irafheader);
+
+ if (*status > 0)
+ return(*status);
+
+ *filesize = (((*filesize - 1) / 2880 ) + 1 ) * 2880; /* multiple of 2880 */
+
+ /* append the image data onto the FITS header */
+ irafrdimage(buffptr, buffsize, filesize, status);
+
+ return(*status);
+}
+
+/*--------------------------------------------------------------------------*/
+/* Subroutine: irafrdhead (was irafrhead in D. Mink's original code)
+ * Purpose: Open and read the iraf .imh file.
+ * 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.
+ */
+
+static char *irafrdhead (
+ char *filename, /* Name of IRAF header file */
+ int *lihead) /* Length of IRAF image header in bytes (returned) */
+{
+ FILE *fd;
+ int nbr;
+ char *irafheader;
+ char errmsg[81];
+ long nbhead;
+ int nihead;
+
+ *lihead = 0;
+
+ /* open the image header file */
+ fd = fopen (filename, "rb");
+ if (fd == NULL) {
+ ffpmsg("unable to open IRAF header file:");
+ ffpmsg(filename);
+ return (NULL);
+ }
+
+ /* Find size of image header file */
+ if (fseek(fd, 0, 2) != 0) /* move to end of the file */
+ {
+ ffpmsg("IRAFRHEAD: cannot seek in file:");
+ ffpmsg(filename);
+ return(NULL);
+ }
+
+ nbhead = ftell(fd); /* position = size of file */
+ if (nbhead < 0)
+ {
+ ffpmsg("IRAFRHEAD: cannot get pos. in file:");
+ ffpmsg(filename);
+ return(NULL);
+ }
+
+ if (fseek(fd, 0, 0) != 0) /* move back to beginning */
+ {
+ ffpmsg("IRAFRHEAD: cannot seek to beginning of file:");
+ ffpmsg(filename);
+ return(NULL);
+ }
+
+ /* allocate initial sized buffer */
+ nihead = nbhead + 5000;
+ irafheader = (char *) calloc (1, nihead);
+ if (irafheader == NULL) {
+ sprintf(errmsg, "IRAFRHEAD Cannot allocate %d-byte header",
+ nihead);
+ ffpmsg(errmsg);
+ ffpmsg(filename);
+ return (NULL);
+ }
+ *lihead = nihead;
+
+ /* Read IRAF header */
+ nbr = fread (irafheader, 1, nbhead, fd);
+ fclose (fd);
+
+ /* Reject if header less than minimum length */
+ if (nbr < LEN_PIXHDR) {
+ sprintf(errmsg, "IRAFRHEAD header file: %d / %d bytes read.",
+ nbr,LEN_PIXHDR);
+ ffpmsg(errmsg);
+ ffpmsg(filename);
+ free (irafheader);
+ return (NULL);
+ }
+
+ return (irafheader);
+}
+/*--------------------------------------------------------------------------*/
+static int irafrdimage (
+ char **buffptr, /* FITS image header (filled) */
+ size_t *buffsize, /* allocated size of the buffer */
+ size_t *filesize, /* actual size of the FITS file */
+ int *status)
+{
+ FILE *fd;
+ char *bang;
+ int nax, naxis1 = 1, naxis2 = 1, naxis3 = 1, naxis4 = 1, npaxis1, npaxis2;
+ int bitpix, bytepix, i;
+ char *fitsheader, *image;
+ int nbr, nbimage, nbaxis, nbl, nbx, nbdiff;
+ char *pixheader;
+ char *linebuff;
+ int imhver, lpixhead;
+ char pixname[SZ_IM2PIXFILE+1];
+ char errmsg[81];
+ size_t newfilesize;
+
+ fitsheader = *buffptr; /* pointer to start of header */
+ image = fitsheader + *filesize; /* pointer to start of the data */
+
+ /* Convert pixel file name to character string */
+ hgets (fitsheader, "PIXFILE", SZ_IM2PIXFILE, pixname);
+ 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");
+
+ /* Print error message and exit if pixel file is not found */
+ if (!fd) {
+ ffpmsg("IRAFRIMAGE: Cannot open IRAF pixel file:");
+ ffpmsg(pixname);
+ return (*status = FILE_NOT_OPENED);
+ }
+
+ /* Read pixel header */
+ pixheader = (char *) calloc (lpixhead, 1);
+ if (pixheader == NULL) {
+ ffpmsg("IRAFRIMAGE: Cannot alloc memory for pixel header");
+ ffpmsg(pixname);
+ fclose (fd);
+ return (*status = FILE_NOT_OPENED);
+ }
+ nbr = fread (pixheader, 1, lpixhead, fd);
+
+ /* Check size of pixel header */
+ if (nbr < lpixhead) {
+ sprintf(errmsg, "IRAF pixel file: %d / %d bytes read.",
+ nbr,LEN_PIXHDR);
+ ffpmsg(errmsg);
+ free (pixheader);
+ fclose (fd);
+ return (*status = FILE_NOT_OPENED);
+ }
+
+ /* check pixel header magic word */
+ imhver = pix_version (pixheader);
+ if (imhver < 1) {
+ ffpmsg("File not valid IRAF pixel file:");
+ ffpmsg(pixname);
+ free (pixheader);
+ fclose (fd);
+ return (*status = FILE_NOT_OPENED);
+ }
+ free (pixheader);
+
+ /* Find number of bytes to read */
+ hgeti4 (fitsheader,"NAXIS",&nax);
+ hgeti4 (fitsheader,"NAXIS1",&naxis1);
+ hgeti4 (fitsheader,"NPAXIS1",&npaxis1);
+ if (nax > 1) {
+ hgeti4 (fitsheader,"NAXIS2",&naxis2);
+ hgeti4 (fitsheader,"NPAXIS2",&npaxis2);
+ }
+ if (nax > 2)
+ hgeti4 (fitsheader,"NAXIS3",&naxis3);
+ if (nax > 3)
+ hgeti4 (fitsheader,"NAXIS4",&naxis4);
+
+ hgeti4 (fitsheader,"BITPIX",&bitpix);
+ if (bitpix < 0)
+ bytepix = -bitpix / 8;
+ else
+ bytepix = bitpix / 8;
+
+ nbimage = naxis1 * naxis2 * naxis3 * naxis4 * bytepix;
+
+ newfilesize = *filesize + nbimage; /* header + data */
+ newfilesize = (((newfilesize - 1) / 2880 ) + 1 ) * 2880;
+
+ if (newfilesize > *buffsize) /* need to allocate more memory? */
+ {
+ fitsheader = (char *) realloc (*buffptr, newfilesize);
+ if (fitsheader == NULL) {
+ sprintf(errmsg, "IRAFRIMAGE Cannot allocate %d-byte image buffer",
+ (int) (*filesize));
+ ffpmsg(errmsg);
+ ffpmsg(pixname);
+ fclose (fd);
+ return (*status = FILE_NOT_OPENED);
+ }
+ }
+
+ *buffptr = fitsheader;
+ *buffsize = newfilesize;
+
+ image = fitsheader + *filesize;
+ *filesize = newfilesize;
+
+ /* 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;
+ nbx = fseek (fd, nbdiff, SEEK_CUR);
+ linebuff = linebuff + nbaxis;
+ }
+ }
+ fclose (fd);
+
+ /* Check size of image */
+ if (nbr < nbimage) {
+ sprintf(errmsg, "IRAF pixel file: %d / %d bytes read.",
+ nbr,nbimage);
+ ffpmsg(errmsg);
+ ffpmsg(pixname);
+ return (*status = FILE_NOT_OPENED);
+ }
+
+ /* Byte-reverse image, if necessary */
+ if (swapdata)
+ irafswap (bitpix, image, nbimage);
+
+ return (*status);
+}
+/*--------------------------------------------------------------------------*/
+/* Return IRAF image format version number from magic word in IRAF header*/
+
+static int head_version (
+ 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 */
+
+static int pix_version (
+ 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 */
+
+static int irafncmp (
+
+char *irafheader, /* IRAF image header from file */
+char *teststring, /* C character string to compare */
+int nc) /* Number of characters to compate */
+
+{
+ char *line;
+
+ 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 */
+
+static int iraftofits (
+ char *hdrname, /* IRAF header file name (may be path) */
+ char *irafheader, /* IRAF image header */
+ int nbiraf, /* Number of bytes in IRAF header */
+ char **buffptr, /* pointer to the FITS header */
+ size_t *nbfits, /* allocated size of the FITS header buffer */
+ size_t *fitssize, /* Number of bytes in FITS header (returned) */
+ /* = number of bytes to the end of the END keyword */
+ int *status)
+{
+ char *objname; /* object name from FITS file */
+ int lstr, i, j, k, ib, nax, nbits;
+ char *pixname, *newpixname, *bang, *chead;
+ char *fitsheader;
+ int nblock, nlines;
+ char *fhead, *fhead1, *fp, endline[81];
+ char irafchar;
+ char fitsline[81];
+ int pixtype;
+ int imhver, n, imu, pixoff, impixoff, immax, immin, imtime;
+ int imndim, imlen, imphyslen, impixtype;
+ char errmsg[81];
+
+ /* 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) {
+ ffpmsg("File not valid IRAF image header");
+ ffpmsg(hdrname);
+ return(*status = FILE_NOT_OPENED);
+ }
+ 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) {
+ sprintf(errmsg, "IRAF2FITS Cannot allocate %d-byte FITS header",
+ (int) (*nbfits));
+ ffpmsg(hdrname);
+ return (*status = FILE_NOT_OPENED);
+ }
+
+ fhead = fitsheader;
+ *buffptr = fitsheader;
+ (void)strncpy (fitsheader, endline, 80);
+ hputl (fitsheader, "SIMPLE", 1);
+ fhead = fhead + 80;
+
+ /* check if the IRAF file is in big endian (sun) format (= 0) or not. */
+ /* This is done by checking the 4 byte integer in the header that */
+ /* represents the iraf pixel type. This 4-byte word is guaranteed to */
+ /* have the least sig byte != 0 and the most sig byte = 0, so if the */
+ /* first byte of the word != 0, then the file in little endian format */
+ /* like on an Alpha machine. */
+
+ swaphead = isirafswapped(irafheader, impixtype);
+ if (imhver == 1)
+ swapdata = swaphead; /* vers 1 data has same swapness as header */
+ else
+ swapdata = irafgeti4 (irafheader, IM2_SWAPPED);
+
+ /* 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:
+ sprintf(errmsg,"Unsupported IRAF data type: %d", pixtype);
+ ffpmsg(errmsg);
+ ffpmsg(hdrname);
+ return (*status = FILE_NOT_OPENED);
+ }
+ 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]");
+ 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 header filename in header */
+ hputs (fitsheader,"IMHFILE",hdrname);
+ hputcom (fitsheader,"IMHFILE", "IRAF header file name");
+ fhead = fhead + 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 )
+ hputs (fitsheader,"PIXFILE",bang+1);
+ else
+ hputs (fitsheader,"PIXFILE",pixname);
+ free (pixname);
+ hputcom (fitsheader,"PIXFILE", "IRAF .pix pixel file");
+ fhead = fhead + 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;
+
+ /* Save flag as to whether to swap IRAF data for this file and machine */
+ if (swapdata)
+ hputl (fitsheader, "PIXSWAP", 1);
+ else
+ hputl (fitsheader, "PIXSWAP", 0);
+ hputcom (fitsheader,"PIXSWAP", "IRAF pixels, FITS byte orders differ if T");
+ 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 (swaphead == 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);
+ *fitssize = fhead - fitsheader; /* no. of bytes to end of END keyword */
+
+ /* Pad rest of header with spaces */
+ strncpy (endline," ",3);
+ for (fp = fhead; fp < fhead1; fp = fp + 80) {
+ (void)strncpy (fp, endline,80);
+ }
+
+ return (*status);
+}
+
+/*--------------------------------------------------------------------------*/
+/* Put filename and header path together */
+
+static char *same_path (
+
+char *pixname, /* IRAF pixel file pathname */
+char *hdrname) /* IRAF image header file pathname */
+
+{
+ int len;
+ char *newpixname;
+
+ newpixname = (char *) calloc (SZ_IM2PIXFILE, sizeof (char));
+
+ /* 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';
+ (void)strncat (newpixname, &pixname[4], SZ_IM2PIXFILE);
+ }
+
+ /* 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);
+}
+
+/*--------------------------------------------------------------------------*/
+static int isirafswapped (
+
+char *irafheader, /* IRAF image header */
+int offset) /* Number of bytes to skip before number */
+
+ /* check if the IRAF file is in big endian (sun) format (= 0) or not */
+ /* This is done by checking the 4 byte integer in the header that */
+ /* represents the iraf pixel type. This 4-byte word is guaranteed to */
+ /* have the least sig byte != 0 and the most sig byte = 0, so if the */
+ /* first byte of the word != 0, then the file in little endian format */
+ /* like on an Alpha machine. */
+
+{
+ int swapped;
+
+ if (irafheader[offset] != 0)
+ swapped = 1;
+ else
+ swapped = 0;
+
+ return (swapped);
+}
+/*--------------------------------------------------------------------------*/
+static int irafgeti4 (
+
+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 (machswap() != swaphead) {
+ 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 */
+
+static char *irafgetc2 (
+
+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 */
+
+static char *irafgetc (
+
+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) {
+ ffpmsg("IRAFGETC Cannot allocate memory for string variable");
+ 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 */
+
+static char *iraf2str (
+
+char *irafstring, /* IRAF 2-byte/character string */
+int nchar) /* Number of characters in string */
+{
+ char *string;
+ int i, j;
+
+ string = (char *) calloc (nchar+1, 1);
+ if (string == NULL) {
+ ffpmsg("IRAF2STR Cannot allocate memory for string variable");
+ return (NULL);
+ }
+
+ /* the chars are in bytes 1, 3, 5, ... if bigendian format (SUN) */
+ /* else in bytes 0, 2, 4, ... if little endian format (Alpha) */
+
+ if (irafstring[0] != 0)
+ 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);
+}
+
+/*--------------------------------------------------------------------------*/
+/* IRAFSWAP -- Reverse bytes of any type of vector in place */
+
+static void irafswap (
+
+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 (
+
+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 (
+
+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 (
+
+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;
+}
+
+/*--------------------------------------------------------------------------*/
+static int
+machswap (void)
+
+{
+ char *ctest;
+ int itest;
+
+ itest = 1;
+ ctest = (char *)&itest;
+ if (*ctest)
+ return (1);
+ else
+ return (0);
+}
+
+/*--------------------------------------------------------------------------*/
+/* the following routines were originally in hget.c */
+/*--------------------------------------------------------------------------*/
+
+
+static int lhead0 = 0;
+
+/*--------------------------------------------------------------------------*/
+
+/* Extract long value for variable from FITS header string */
+
+static int
+hgeti4 (hstring,keyword,ival)
+
+char *hstring; /* character string containing FITS header information
+ in the format <keyword>= <value> {/ <comment>} */
+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;
+char val[30];
+
+/* Get value and comment from header string */
+ value = hgetc (hstring,keyword);
+
+/* Translate value from ASCII to binary */
+ if (value != NULL) {
+ minint = -MAXINT - 1;
+ strcpy (val, value);
+ dval = atof (val);
+ if (dval+0.001 > MAXINT)
+ *ival = MAXINT;
+ 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 string value for variable from FITS header string */
+
+static int
+hgets (hstring, keyword, lstr, str)
+
+char *hstring; /* character string containing FITS header information
+ in the format <keyword>= <value> {/ <comment>} */
+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 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 character value for variable from FITS header string */
+
+static char *
+hgetc (hstring,keyword0)
+
+char *hstring; /* character string containing FITS header information
+ in the format <keyword>= <value> {/ <comment>} */
+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 keyword[81]; /* large for ESO hierarchical keywords */
+ char line[100];
+ char *vpos, *cpar = NULL;
+ char *q1, *q2 = NULL, *v1, *v2, *c1, *brack1, *brack2;
+ int ipar, i;
+
+ squot[0] = 39;
+ squot[1] = 0;
+ dquot[0] = 34;
+ dquot[1] = 0;
+ lbracket[0] = 91;
+ lbracket[1] = 0;
+ comma[0] = 44;
+ comma[1] = 0;
+ rbracket[0] = 93;
+ rbracket[1] = 0;
+ slash[0] = 47;
+ slash[1] = 0;
+
+/* 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);
+ else if (c1 == NULL)
+ q2 = strsrch (q1+1,squot);
+ else
+ q1 = NULL;
+ }
+ else {
+ q1 = strsrch (line,dquot);
+ if (q1 != NULL) {
+ if (c1 != NULL && q1 < c1)
+ q2 = strsrch (q1+1,dquot);
+ else if (c1 == NULL)
+ q2 = strsrch (q1+1,dquot);
+ else
+ q1 = NULL;
+ }
+ else {
+ q1 = NULL;
+ q2 = line + 10;
+ }
+ }
+
+/* Extract value and remove excess spaces */
+ if (q1 != NULL) {
+ v1 = q1 + 1;;
+ v2 = q2;
+ c1 = strsrch (q2,"/");
+ }
+ else {
+ v1 = strsrch (line,"=") + 1;
+ c1 = strsrch (line,"/");
+ if (c1 != NULL)
+ v2 = c1;
+ else
+ v2 = line + 79;
+ }
+
+/* Ignore leading spaces */
+ while (*v1 == ' ' && v1 < v2) {
+ v1++;
+ }
+
+/* Drop trailing spaces */
+ *v2 = '\0';
+ v2--;
+ while (*v2 == ' ' && v2 > v1) {
+ *v2 = '\0';
+ v2--;
+ }
+
+ 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';
+ ipar = atoi (brack1);
+ if (ipar > 0) {
+ cwhite[0] = ' ';
+ cwhite[1] = '\0';
+ for (i = 1; i <= ipar; i++) {
+ cpar = strtok (v1,cwhite);
+ v1 = NULL;
+ }
+ if (cpar != NULL) {
+ strcpy (cval,cpar);
+ }
+ else
+ value = NULL;
+ }
+ }
+
+ return (value);
+}
+
+
+/*-------------------------------------------------------------------*/
+/* Find beginning of fillable blank line before FITS header keyword line */
+
+static 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 */
+
+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. */
+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. */
+{
+ char *loc, *headnext, *headlast, *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 < 57600 && hstring[lhstr] != 0)
+ lhstr++;
+ }
+ headlast = hstring + lhstr;
+ headnext = hstring;
+ pval = NULL;
+ while (headnext < headlast) {
+ nleft = headlast - headnext;
+ loc = strnsrch (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 if keyword is found at start of FITS header string */
+ if (pval == NULL)
+ return (pval);
+
+ /* Return NULL if found the first keyword in the header */
+ if (pval == hstring)
+ return (NULL);
+
+ /* Find last nonblank line before requested keyword */
+ bval = pval - 80;
+ while (!strncmp (bval," ",8))
+ bval = bval - 80;
+ bval = bval + 80;
+
+ /* Return pointer to calling program if blank lines found */
+ if (bval < pval)
+ return (bval);
+ else
+ return (NULL);
+}
+
+
+/*-------------------------------------------------------------------*/
+/* Find FITS header line containing specified keyword */
+
+static 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 */
+
+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. */
+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. */
+{
+ char *loc, *headnext, *headlast, *pval, *lc, *line;
+ int icol, nextchar, lkey, nleft, lhstr;
+
+ pval = 0;
+
+/* Search header string for variable name */
+ if (lhead0)
+ lhstr = lhead0;
+ else {
+ lhstr = 0;
+ while (lhstr < 57600 && hstring[lhstr] != 0)
+ lhstr++;
+ }
+ headlast = hstring + lhstr;
+ headnext = hstring;
+ pval = NULL;
+ while (headnext < headlast) {
+ nleft = headlast - headnext;
+ loc = strnsrch (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);
+
+}
+
+/*-------------------------------------------------------------------*/
+/* Find string s2 within null-terminated string s1 */
+
+static char *
+strsrch (s1, s2)
+
+char *s1; /* String to search */
+char *s2; /* String to look for */
+
+{
+ int ls1;
+ ls1 = strlen (s1);
+ return (strnsrch (s1, s2, ls1));
+}
+
+/*-------------------------------------------------------------------*/
+/* Find string s2 within string s1 */
+
+static char *
+strnsrch (s1, s2, ls1)
+
+char *s1; /* String to search */
+char *s2; /* String to look for */
+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 (s1);
+
+ /* Only a zero-length string can be found in a zero-length string */
+ if (ls1 ==0)
+ return (NULL);
+
+ cfirst = s2[0];
+ clast = s2[ls2-1];
+ s1e = s1 + ls1 - ls2 + 1;
+ s = 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);
+}
+
+/*-------------------------------------------------------------------*/
+/* the following routines were originally in hget.c */
+/*-------------------------------------------------------------------*/
+/* HPUTI4 - Set int keyword = ival in FITS header string */
+
+static void
+hputi4 (hstring,keyword,ival)
+
+ char *hstring; /* character string containing FITS-style header
+ information in the format
+ <keyword>= <value> {/ <comment>}
+ each entry is padded with spaces to 80 characters */
+
+ char *keyword; /* character string containing the name of the variable
+ to be returned. hput searches for a line beginning
+ with this string, and if there isn't one, creates one.
+ 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 */
+ hputc (hstring,keyword,value);
+
+ /* Return to calling program */
+ return;
+}
+
+/*-------------------------------------------------------------------*/
+
+/* HPUTL - Set keyword = F if lval=0, else T, in FITS header string */
+
+static void
+hputl (hstring, keyword,lval)
+
+char *hstring; /* FITS header */
+char *keyword; /* Keyword name */
+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 */
+ hputc (hstring,keyword,value);
+
+ /* Return to calling program */
+ return;
+}
+
+/*-------------------------------------------------------------------*/
+
+/* HPUTS - Set character string keyword = 'cval' in FITS header string */
+
+static void
+hputs (hstring,keyword,cval)
+
+char *hstring; /* FITS header */
+char *keyword; /* Keyword name */
+char *cval; /* character string containing the value for variable
+ keyword. trailing and leading blanks are removed. */
+{
+ char squot = 39;
+ char value[70];
+ int lcval;
+
+ /* find length of variable string */
+
+ lcval = strlen (cval);
+ if (lcval > 67)
+ lcval = 67;
+
+ /* Put quotes around string */
+ value[0] = squot;
+ strncpy (&value[1],cval,lcval);
+ value[lcval+1] = squot;
+ value[lcval+2] = 0;
+
+ /* Put value into header string */
+ hputc (hstring,keyword,value);
+
+ /* Return to calling program */
+ return;
+}
+
+/*---------------------------------------------------------------------*/
+/* HPUTC - Set character string keyword = value in FITS header string */
+
+static void
+hputc (hstring,keyword,value)
+
+char *hstring;
+char *keyword;
+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 blank[80];
+ char *v, *vp, *v1, *v2, *q1, *q2, *c1, *ve;
+ int lkeyword, lcom, lval, lc, i;
+
+ for (i = 0; i < 80; i++)
+ blank[i] = ' ';
+
+ /* find length of keyword and value */
+ lkeyword = strlen (keyword);
+ lval = strlen (value);
+
+ /* 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");
+ v2 = v1 + 80;
+
+ /* Move END down one line */
+ strncpy (v2, v1, 80);
+
+ /* Insert keyword */
+ strncpy (v1,keyword,7);
+
+ /* Pad with spaces */
+ for (vp = v1+lkeyword; vp < v2; vp++)
+ *vp = ' ';
+
+ /* Insert comment */
+ strncpy (v1+9,value,lval);
+ return;
+ }
+
+ /* 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;
+ v2 = v1 + 80;
+ strncpy (v2, ve, 80);
+ }
+ else
+ v2 = v1 + 80;
+ lcom = 0;
+ newcom[0] = 0;
+ }
+
+ /* Otherwise, extract the entry for this keyword from the header */
+ else {
+ 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);
+ else
+ q2 = line;
+
+ /* extract comment and remove trailing spaces */
+
+ c1 = strchr (q2,'/');
+ if (c1 != NULL) {
+ lcom = 80 - (c1 - line);
+ strncpy (newcom, c1+1, lcom);
+ vp = newcom + lcom - 1;
+ while (vp-- > newcom && *vp == ' ')
+ *vp = 0;
+ lcom = strlen (newcom);
+ }
+ 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 = 78 - lc;
+ vp = v1 + lc + 2; /* Jul 16 1997: was vp = v1 + lc * 2 */
+ *vp = '/';
+ vp = vp + 1;
+ strncpy (vp, newcom, lcom);
+ for (v = vp + lcom; v < v2; v++)
+ *v = ' ';
+ }
+
+ return;
+}
+
+/*-------------------------------------------------------------------*/
+/* HPUTCOM - Set comment for keyword or on line in FITS header string */
+
+static void
+hputcom (hstring,keyword,comment)
+
+ char *hstring;
+ char *keyword;
+ char *comment;
+{
+ char squot;
+ char line[100];
+ int lkeyword, lcom;
+ char *vp, *v1, *v2, *c0 = NULL, *c1, *q1, *q2;
+
+ squot = 39;
+
+/* Find length of variable name */
+ lkeyword = strlen (keyword);
+
+/* 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");
+ v2 = v1 + 80;
+ strncpy (v2, v1, 80);
+
+ /* blank out new line and insert keyword */
+ for (vp = v1; vp < v2; vp++)
+ *vp = ' ';
+ strncpy (v1, keyword, lkeyword);
+ }
+
+/* search header string for variable name */
+ else {
+ v1 = ksearch (hstring,keyword);
+ v2 = v1 + 80;
+
+ /* if parameter is not found, return without doing anything */
+ if (v1 == NULL) {
+ return;
+ }
+
+ /* otherwise, extract entry for this variable from the header */
+ strncpy (line, v1, 80);
+
+ /* check for quoted value */
+ q1 = strchr (line,squot);
+ if (q1 != NULL)
+ q2 = strchr (q1+1,squot);
+ else
+ q2 = NULL;
+
+ if (q2 == NULL || q2-line < 31)
+ c0 = v1 + 31;
+ else
+ c0 = v1 + (q2-line) + 2; /* allan: 1997-09-30, was c0=q2+2 */
+
+ strncpy (c0, "/ ",2);
+ }
+
+/* create new entry */
+ lcom = strlen (comment);
+
+ if (lcom > 0) {
+ c1 = c0 + 2;
+ if (c1+lcom > v2)
+ lcom = v2 - c1;
+ strncpy (c1, comment, lcom);
+ }
+
+}
diff --git a/pkg/tbtables/cfitsio/iter_a.c b/pkg/tbtables/cfitsio/iter_a.c
new file mode 100644
index 00000000..19ea1d1c
--- /dev/null
+++ b/pkg/tbtables/cfitsio/iter_a.c
@@ -0,0 +1,147 @@
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "fitsio.h"
+
+/*
+ This program illustrates how to use the CFITSIO iterator function.
+ It reads and modifies the input 'iter_a.fit' file by computing a
+ value for the 'rate' column as a function of the values in the other
+ 'counts' and 'time' columns.
+*/
+main()
+{
+ extern flux_rate(); /* external work function is passed to the iterator */
+ fitsfile *fptr;
+ iteratorCol cols[3]; /* structure used by the iterator function */
+ int n_cols;
+ long rows_per_loop, offset;
+
+ int status, nkeys, keypos, hdutype, ii, jj;
+ char filename[] = "iter_a.fit"; /* name of rate FITS file */
+
+ status = 0;
+
+ fits_open_file(&fptr, filename, READWRITE, &status); /* open file */
+
+ /* move to the desired binary table extension */
+ if (fits_movnam_hdu(fptr, BINARY_TBL, "RATE", 0, &status) )
+ fits_report_error(stderr, status); /* print out error messages */
+
+ n_cols = 3; /* number of columns */
+
+ /* define input column structure members for the iterator function */
+ fits_iter_set_by_name(&cols[0], fptr, "COUNTS", TLONG, InputCol);
+ fits_iter_set_by_name(&cols[1], fptr, "TIME", TFLOAT, InputCol);
+ fits_iter_set_by_name(&cols[2], fptr, "RATE", TFLOAT, OutputCol);
+
+ rows_per_loop = 0; /* use default optimum number of rows */
+ offset = 0; /* process all the rows */
+
+ /* apply the rate function to each row of the table */
+ printf("Calling iterator function...%d\n", status);
+
+ fits_iterate_data(n_cols, cols, offset, rows_per_loop,
+ flux_rate, 0L, &status);
+
+ fits_close_file(fptr, &status); /* all done */
+
+ if (status)
+ fits_report_error(stderr, status); /* print out error messages */
+
+ return(status);
+}
+/*--------------------------------------------------------------------------*/
+int flux_rate(long totalrows, long offset, long firstrow, long nrows,
+ int ncols, iteratorCol *cols, void *user_strct )
+
+/*
+ Sample iterator function that calculates the output flux 'rate' column
+ by dividing the input 'counts' by the 'time' column.
+ It also applies a constant deadtime correction factor if the 'deadtime'
+ keyword exists. Finally, this creates or updates the 'LIVETIME'
+ keyword with the sum of all the individual integration times.
+*/
+{
+ int ii, status = 0;
+
+ /* declare variables static to preserve their values between calls */
+ static long *counts;
+ static float *interval;
+ static float *rate;
+ static float deadtime, livetime; /* must preserve values between calls */
+
+ /*--------------------------------------------------------*/
+ /* Initialization procedures: execute on the first call */
+ /*--------------------------------------------------------*/
+ if (firstrow == 1)
+ {
+ if (ncols != 3)
+ return(-1); /* number of columns incorrect */
+
+ if (fits_iter_get_datatype(&cols[0]) != TLONG ||
+ fits_iter_get_datatype(&cols[1]) != TFLOAT ||
+ fits_iter_get_datatype(&cols[2]) != TFLOAT )
+ return(-2); /* bad data type */
+
+ /* assign the input pointers to the appropriate arrays and null ptrs*/
+ counts = (long *) fits_iter_get_array(&cols[0]);
+ interval = (float *) fits_iter_get_array(&cols[1]);
+ rate = (float *) fits_iter_get_array(&cols[2]);
+
+ livetime = 0; /* initialize the total integration time */
+
+ /* try to get the deadtime keyword value */
+ fits_read_key(cols[0].fptr, TFLOAT, "DEADTIME", &deadtime, '\0',
+ &status);
+ if (status)
+ {
+ deadtime = 1.0; /* default deadtime if keyword doesn't exist */
+ }
+ else if (deadtime < 0. || deadtime > 1.0)
+ {
+ return(-1); /* bad deadtime value */
+ }
+
+ printf("deadtime = %f\n", deadtime);
+ }
+
+ /*--------------------------------------------*/
+ /* Main loop: process all the rows of data */
+ /*--------------------------------------------*/
+
+ /* NOTE: 1st element of array is the null pixel value! */
+ /* Loop from 1 to nrows, not 0 to nrows - 1. */
+
+ /* this version tests for null values */
+ rate[0] = DOUBLENULLVALUE; /* define the value that represents null */
+
+ for (ii = 1; ii <= nrows; ii++)
+ {
+ if (counts[ii] == counts[0]) /* undefined counts value? */
+ {
+ rate[ii] = DOUBLENULLVALUE;
+ }
+ else if (interval[ii] > 0.)
+ {
+ rate[ii] = counts[ii] / interval[ii] / deadtime;
+ livetime += interval[ii]; /* accumulate total integration time */
+ }
+ else
+ return(-2); /* bad integration time */
+ }
+
+ /*-------------------------------------------------------*/
+ /* Clean up procedures: after processing all the rows */
+ /*-------------------------------------------------------*/
+
+ if (firstrow + nrows - 1 == totalrows)
+ {
+ /* update the LIVETIME keyword value */
+
+ fits_update_key(cols[0].fptr, TFLOAT, "LIVETIME", &livetime,
+ "total integration time", &status);
+ printf("livetime = %f\n", livetime);
+ }
+ return(0); /* return successful status */
+}
diff --git a/pkg/tbtables/cfitsio/iter_a.f b/pkg/tbtables/cfitsio/iter_a.f
new file mode 100644
index 00000000..e6221897
--- /dev/null
+++ b/pkg/tbtables/cfitsio/iter_a.f
@@ -0,0 +1,224 @@
+ program f77iterate_a
+
+ external flux_rate
+ integer ncols
+ parameter (ncols=3)
+ integer units(ncols), colnum(ncols), datatype(ncols)
+ integer iotype(ncols), offset, rows_per_loop, status
+ character*70 colname(ncols)
+ integer iunit, blocksize
+ character*80 fname
+
+C include f77.inc -------------------------------------
+C Codes for FITS extension types
+ integer IMAGE_HDU, ASCII_TBL, BINARY_TBL
+ parameter (
+ & IMAGE_HDU = 0,
+ & ASCII_TBL = 1,
+ & BINARY_TBL = 2 )
+
+C Codes for FITS table data types
+
+ integer TBIT,TBYTE,TLOGICAL,TSTRING,TSHORT,TINT
+ integer TFLOAT,TDOUBLE,TCOMPLEX,TDBLCOMPLEX
+ parameter (
+ & TBIT = 1,
+ & TBYTE = 11,
+ & TLOGICAL = 14,
+ & TSTRING = 16,
+ & TSHORT = 21,
+ & TINT = 31,
+ & TFLOAT = 42,
+ & TDOUBLE = 82,
+ & TCOMPLEX = 83,
+ & TDBLCOMPLEX = 163 )
+
+C Codes for iterator column types
+
+ integer InputCol, InputOutputCol, OutputCol
+ parameter (
+ & InputCol = 0,
+ & InputOutputCol = 1,
+ & OutputCol = 2 )
+C End of f77.inc -------------------------------------
+
+
+ iunit = 15
+
+ units(1) = iunit
+ units(2) = iunit
+ units(3) = iunit
+
+C open the file
+ fname = 'iter_a.fit'
+ call ftopen(iunit,fname,1,blocksize,status)
+
+C move to the HDU containing the rate table
+ call ftmnhd(iunit, BINARY_TBL, 'RATE', 0, status)
+
+C Select iotypes for column data
+ iotype(1) = InputCol
+ iotype(2) = InputCol
+ iotype(3) = OutputCol
+
+C Select desired datatypes for column data
+ datatype(1) = TINT
+ datatype(2) = TFLOAT
+ datatype(3) = TFLOAT
+
+C find the column number corresponding to each column
+ call ftgcno( iunit, 0, 'counts', colnum(1), status )
+ call ftgcno( iunit, 0, 'time', colnum(2), status )
+ call ftgcno( iunit, 0, 'rate', colnum(3), status )
+
+C use default optimum number of rows
+ rows_per_loop = 0
+ offset = 0
+
+C apply the rate function to each row of the table
+ print *, 'Calling iterator function...', status
+
+C although colname is not being used, still need to send a string
+C array in the function
+ call ftiter( ncols, units, colnum, colname, datatype, iotype,
+ & offset, rows_per_loop, flux_rate, 3, status )
+
+ call ftclos(iunit, status)
+ stop
+ end
+
+C***************************************************************************
+C Sample iterator function that calculates the output flux 'rate' column
+C by dividing the input 'counts' by the 'time' column.
+C It also applies a constant deadtime correction factor if the 'deadtime'
+C keyword exists. Finally, this creates or updates the 'LIVETIME'
+C keyword with the sum of all the individual integration times.
+C***************************************************************************
+ subroutine flux_rate(totalrows, offset, firstrow, nrows, ncols,
+ & units, colnum, datatype, iotype, repeat, status, userData,
+ & counts, interval, rate )
+
+ integer totalrows, offset, firstrow, nrows, ncols
+ integer units(ncols), colnum(ncols), datatype(ncols)
+ integer iotype(ncols), repeat(ncols)
+ integer userData
+
+C include f77.inc -------------------------------------
+C Codes for FITS extension types
+ integer IMAGE_HDU, ASCII_TBL, BINARY_TBL
+ parameter (
+ & IMAGE_HDU = 0,
+ & ASCII_TBL = 1,
+ & BINARY_TBL = 2 )
+
+C Codes for FITS table data types
+
+ integer TBIT,TBYTE,TLOGICAL,TSTRING,TSHORT,TINT
+ integer TFLOAT,TDOUBLE,TCOMPLEX,TDBLCOMPLEX
+ parameter (
+ & TBIT = 1,
+ & TBYTE = 11,
+ & TLOGICAL = 14,
+ & TSTRING = 16,
+ & TSHORT = 21,
+ & TINT = 31,
+ & TFLOAT = 42,
+ & TDOUBLE = 82,
+ & TCOMPLEX = 83,
+ & TDBLCOMPLEX = 163 )
+
+C Codes for iterator column types
+
+ integer InputCol, InputOutputCol, OutputCol
+ parameter (
+ & InputCol = 0,
+ & InputOutputCol = 1,
+ & OutputCol = 2 )
+C End of f77.inc -------------------------------------
+
+ integer counts(*)
+ real interval(*),rate(*)
+
+ integer ii, status
+ character*80 comment
+
+C**********************************************************************
+C must preserve these values between calls
+ real deadtime, livetime
+ common /fluxblock/ deadtime, livetime
+C**********************************************************************
+
+ if (status .ne. 0) return
+
+C --------------------------------------------------------
+C Initialization procedures: execute on the first call
+C --------------------------------------------------------
+ if (firstrow .eq. 1) then
+ if (ncols .ne. 3) then
+C wrong number of columns
+ status = -1
+ return
+ endif
+
+ if (datatype(1).ne.TINT .or. datatype(2).ne.TFLOAT .or.
+ & datatype(3).ne.TFLOAT ) then
+C bad data type
+ status = -2
+ return
+ endif
+
+C try to get the deadtime keyword value
+ call ftgkye( units(1), 'DEADTIME', deadtime, comment, status )
+
+ if (status.ne.0) then
+C default deadtime if keyword doesn't exist
+ deadtime = 1.0
+ status = 0
+ elseif (deadtime .lt. 0.0 .or. deadtime .gt. 1.0) then
+C bad deadtime value
+ status = -3
+ return
+ endif
+
+ print *, 'deadtime = ', deadtime
+
+ livetime = 0.0
+ endif
+
+C --------------------------------------------
+C Main loop: process all the rows of data
+C --------------------------------------------
+
+C NOTE: 1st element of array is the null pixel value!
+C Loop over elements 2 to nrows+1, not 1 to nrows.
+
+C this version ignores null values
+
+C set the output null value to zero to ignore nulls */
+ rate(1) = 0.0
+ do 10 ii = 2,nrows+1
+ if ( interval(ii) .gt. 0.0) then
+ rate(ii) = counts(ii) / interval(ii) / deadtime
+ livetime = livetime + interval(ii)
+ else
+C Nonsensical negative time interval
+ status = -3
+ return
+ endif
+ 10 continue
+
+C -------------------------------------------------------
+C Clean up procedures: after processing all the rows
+C -------------------------------------------------------
+
+ if (firstrow + nrows - 1 .eq. totalrows) then
+C update the LIVETIME keyword value
+
+ call ftukye( units(1),'LIVETIME', livetime, 3,
+ & 'total integration time', status )
+ print *,'livetime = ', livetime
+
+ endif
+
+ return
+ end
diff --git a/pkg/tbtables/cfitsio/iter_a.fit b/pkg/tbtables/cfitsio/iter_a.fit
new file mode 100644
index 00000000..543646e3
--- /dev/null
+++ b/pkg/tbtables/cfitsio/iter_a.fit
@@ -0,0 +1,1111 @@
+SIMPLE = T / file does conform to FITS standard BITPIX = 16 / number of bits per data pixel NAXIS = 0 / number of data axes EXTEND = T / FITS dataset may contain extensions COMMENT FITS (Flexible Image Transport System) format defined in Astronomy andCOMMENT Astrophysics Supplement Series v44/p363, v44/p371, v73/p359, v73/p365.COMMENT Contact the NASA Science Office of Standards and Technology for the COMMENT FITS Definition document #100 and other FITS information. HISTORY TASK:FMERGE on file ratefile.fits HISTORY fmerge3.1c at 29/12/97 16:1:37. HISTORY TASK:FMERGE on file m1.fits HISTORY fmerge3.1c at 29/12/97 16:2:30. HISTORY TASK:FMERGE on file m3.fits HISTORY fmerge3.1c at 29/12/97 16:3:38. HISTORY TASK:FMERGE on file m5.fits HISTORY fmerge3.1c at 29/12/97 16:4:15. HISTORY TASK:FMERGE on file m7.fits HISTORY fmerge3.1c at 29/12/97 16:5:1.0 HISTORY TASK:FMERGE on file m9.fits HISTORY fmerge3.1c at 29/12/97 16:6:48. END XTENSION= 'BINTABLE' / binary table extension BITPIX = 8 / 8-bit bytes NAXIS = 2 / 2-dimensional binary table NAXIS1 = 12 / width of table in bytes NAXIS2 = 10000 / number of rows in table PCOUNT = 0 / size of special data area GCOUNT = 1 / one data group (required keyword) TFIELDS = 3 / number of fields in each row TTYPE1 = 'Counts ' / label for field 1 TFORM1 = 'J ' / data format of field: 4-byte INTEGER TTYPE2 = 'Time ' / label for field 2 TFORM2 = 'E ' / data format of field: 4-byte REAL TTYPE3 = 'Rate ' / label for field 3 TFORM3 = 'E ' / data format of field: 4-byte REAL EXTNAME = 'rate ' / name of this binary table extension DEADTIME= 1.0 HISTORY This FITS file was created by the FCREATE task. HISTORY fcreate3.1 at 29/12/97 HISTORY File modified by user 'pence' with fv on 97-12-29T15:45:06 HISTORY File modified by user 'pence' with fv on 97-12-29T15:54:30 LIVETIME= 3.055450E+04 / total integration time HISTORY TASK:FMERGE copied 26924 rows from file ratefile.fits HISTORY TASK:FMERGE appended 26924 rows from file r2.fits HISTORY TASK:FMERGE copied 53848 rows from file m1.fits HISTORY TASK:FMERGE appended 53848 rows from file m2.fits HISTORY TASK:FMERGE copied 107696 rows from file m3.fits HISTORY TASK:FMERGE appended 107696 rows from file m4.fits HISTORY TASK:FMERGE copied 215392 rows from file m5.fits HISTORY TASK:FMERGE appended 215392 rows from file m6.fits HISTORY TASK:FMERGE copied 430784 rows from file m7.fits HISTORY TASK:FMERGE appended 430784 rows from file m8.fits HISTORY TASK:FMERGE copied 861568 rows from file m9.fits HISTORY TASK:FMERGE appended 861568 rows from file m10.fits HISTORY File modified by user 'pence' with fv on 97-12-30T10:44:37 HISTORY File modified by user 'pence' with fv on 97-12-30T10:51:44 HISTORY ftabcopy V4.0a copied columns from ratefile.fits HISTORY ftabcopy V4.0a at 5/1/98 23:10:24 END
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
+?€
diff --git a/pkg/tbtables/cfitsio/iter_b.c b/pkg/tbtables/cfitsio/iter_b.c
new file mode 100644
index 00000000..296f4e16
--- /dev/null
+++ b/pkg/tbtables/cfitsio/iter_b.c
@@ -0,0 +1,114 @@
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "fitsio.h"
+
+/*
+ This program illustrates how to use the CFITSIO iterator function.
+ It simply prints out the values in a character string and a logical
+ type column in a table, and toggles the value in the logical column
+ so that T -> F and F -> T.
+*/
+main()
+{
+ extern str_iter(); /* external work function is passed to the iterator */
+ fitsfile *fptr;
+ iteratorCol cols[2];
+ int n_cols;
+ long rows_per_loop, offset;
+ int status = 0;
+ char filename[] = "iter_b.fit"; /* name of rate FITS file */
+
+ /* open the file and move to the correct extension */
+ fits_open_file(&fptr, filename, READWRITE, &status);
+ fits_movnam_hdu(fptr, BINARY_TBL, "iter_test", 0, &status);
+
+ /* define input column structure members for the iterator function */
+ n_cols = 2; /* number of columns */
+
+ /* define input column structure members for the iterator function */
+ fits_iter_set_by_name(&cols[0], fptr, "Avalue", TSTRING, InputOutputCol);
+ fits_iter_set_by_name(&cols[1], fptr, "Lvalue", TLOGICAL, InputOutputCol);
+
+ rows_per_loop = 0; /* use default optimum number of rows */
+ offset = 0; /* process all the rows */
+
+ /* apply the function to each row of the table */
+ printf("Calling iterator function...%d\n", status);
+
+ fits_iterate_data(n_cols, cols, offset, rows_per_loop,
+ str_iter, 0L, &status);
+
+ fits_close_file(fptr, &status); /* all done */
+
+ if (status)
+ fits_report_error(stderr, status); /* print out error messages */
+
+ return(status);
+}
+/*--------------------------------------------------------------------------*/
+int str_iter(long totalrows, long offset, long firstrow, long nrows,
+ int ncols, iteratorCol *cols, void *user_strct )
+
+/*
+ Sample iterator function.
+*/
+{
+ int ii;
+
+ /* declare variables static to preserve their values between calls */
+ static char **stringvals;
+ static char *logicalvals;
+
+ /*--------------------------------------------------------*/
+ /* Initialization procedures: execute on the first call */
+ /*--------------------------------------------------------*/
+ if (firstrow == 1)
+ {
+ if (ncols != 2)
+ return(-1); /* number of columns incorrect */
+
+ if (fits_iter_get_datatype(&cols[0]) != TSTRING ||
+ fits_iter_get_datatype(&cols[1]) != TLOGICAL )
+ return(-2); /* bad data type */
+
+ /* assign the input pointers to the appropriate arrays */
+ stringvals = (char **) fits_iter_get_array(&cols[0]);
+ logicalvals = (char *) fits_iter_get_array(&cols[1]);
+
+ printf("Total rows, No. rows = %d %d\n",totalrows, nrows);
+ }
+
+ /*------------------------------------------*/
+ /* Main loop: process all the rows of data */
+ /*------------------------------------------*/
+
+ /* NOTE: 1st element of array is the null pixel value! */
+ /* Loop from 1 to nrows, not 0 to nrows - 1. */
+
+ for (ii = 1; ii <= nrows; ii++)
+ {
+ printf("%s %d\n", stringvals[ii], logicalvals[ii]);
+ if (logicalvals[ii])
+ {
+ logicalvals[ii] = FALSE;
+ strcpy(stringvals[ii], "changed to false");
+ }
+ else
+ {
+ logicalvals[ii] = TRUE;
+ strcpy(stringvals[ii], "changed to true");
+ }
+ }
+
+ /*-------------------------------------------------------*/
+ /* Clean up procedures: after processing all the rows */
+ /*-------------------------------------------------------*/
+
+ if (firstrow + nrows - 1 == totalrows)
+ {
+ /* no action required in this case */
+ }
+
+ return(0);
+}
diff --git a/pkg/tbtables/cfitsio/iter_b.f b/pkg/tbtables/cfitsio/iter_b.f
new file mode 100644
index 00000000..7a2a6e7d
--- /dev/null
+++ b/pkg/tbtables/cfitsio/iter_b.f
@@ -0,0 +1,193 @@
+ program f77iterate_b
+
+C external work function is passed to the iterator
+ external str_iter
+
+ integer ncols
+ parameter (ncols=2)
+ integer units(ncols), colnum(ncols), datatype(ncols)
+ integer iotype(ncols), offset, rows_per_loop, status
+ character*70 colname(ncols)
+
+ integer iunit, blocksize
+ character*80 fname
+
+C include f77.inc -------------------------------------
+C Codes for FITS extension types
+ integer IMAGE_HDU, ASCII_TBL, BINARY_TBL
+ parameter (
+ & IMAGE_HDU = 0,
+ & ASCII_TBL = 1,
+ & BINARY_TBL = 2 )
+
+C Codes for FITS table data types
+
+ integer TBIT,TBYTE,TLOGICAL,TSTRING,TSHORT,TINT
+ integer TFLOAT,TDOUBLE,TCOMPLEX,TDBLCOMPLEX
+ parameter (
+ & TBIT = 1,
+ & TBYTE = 11,
+ & TLOGICAL = 14,
+ & TSTRING = 16,
+ & TSHORT = 21,
+ & TINT = 31,
+ & TFLOAT = 42,
+ & TDOUBLE = 82,
+ & TCOMPLEX = 83,
+ & TDBLCOMPLEX = 163 )
+
+C Codes for iterator column types
+
+ integer InputCol, InputOutputCol, OutputCol
+ parameter (
+ & InputCol = 0,
+ & InputOutputCol = 1,
+ & OutputCol = 2 )
+C End of f77.inc -------------------------------------
+
+ status = 0
+
+ fname = 'iter_b.fit'
+ iunit = 15
+
+C both columns are in the same FITS file
+ units(1) = iunit
+ units(2) = iunit
+
+C open the file and move to the correct extension
+ call ftopen(iunit,fname,1,blocksize,status)
+ call ftmnhd(iunit, BINARY_TBL, 'iter_test', 0, status)
+
+C define the desired columns by name
+ colname(1) = 'Avalue'
+ colname(2) = 'Lvalue'
+
+C leave column numbers undefined
+ colnum(1) = 0
+ colnum(2) = 0
+
+C define the desired datatype for each column: TSTRING & TLOGICAL
+ datatype(1) = TSTRING
+ datatype(2) = TLOGICAL
+
+C define whether columns are input, input/output, or output only
+C Both in/out
+ iotype(1) = InputOutputCol
+ iotype(2) = InputOutputCol
+
+C use default optimum number of rows and process all the rows
+ rows_per_loop = 0
+ offset = 0
+
+C apply the function to each row of the table
+ print *,'Calling iterator function...', status
+
+ call ftiter( ncols, units, colnum, colname, datatype, iotype,
+ & offset, rows_per_loop, str_iter, 0, status )
+
+ call ftclos(iunit, status)
+
+C print out error messages if problem
+ if (status.ne.0) call ftrprt('STDERR', status)
+ stop
+ end
+
+C--------------------------------------------------------------------------
+C
+C Sample iterator function.
+C
+C--------------------------------------------------------------------------
+ subroutine str_iter(totalrows, offset, firstrow, nrows, ncols,
+ & units, colnum, datatype, iotype, repeat, status,
+ & userData, stringCol, logicalCol )
+
+ integer totalrows,offset,firstrow,nrows,ncols,status
+ integer units(*),colnum(*),datatype(*),iotype(*),repeat(*)
+ integer userData
+ character*(*) stringCol(*)
+ logical logicalCol(*)
+
+ integer ii
+
+C include f77.inc -------------------------------------
+C Codes for FITS extension types
+ integer IMAGE_HDU, ASCII_TBL, BINARY_TBL
+ parameter (
+ & IMAGE_HDU = 0,
+ & ASCII_TBL = 1,
+ & BINARY_TBL = 2 )
+
+C Codes for FITS table data types
+
+ integer TBIT,TBYTE,TLOGICAL,TSTRING,TSHORT,TINT
+ integer TFLOAT,TDOUBLE,TCOMPLEX,TDBLCOMPLEX
+ parameter (
+ & TBIT = 1,
+ & TBYTE = 11,
+ & TLOGICAL = 14,
+ & TSTRING = 16,
+ & TSHORT = 21,
+ & TINT = 31,
+ & TFLOAT = 42,
+ & TDOUBLE = 82,
+ & TCOMPLEX = 83,
+ & TDBLCOMPLEX = 163 )
+
+C Codes for iterator column types
+
+ integer InputCol, InputOutputCol, OutputCol
+ parameter (
+ & InputCol = 0,
+ & InputOutputCol = 1,
+ & OutputCol = 2 )
+C End of f77.inc -------------------------------------
+
+ if (status .ne. 0) return
+
+C --------------------------------------------------------
+C Initialization procedures: execute on the first call
+C --------------------------------------------------------
+ if (firstrow .eq. 1) then
+ if (ncols .ne. 2) then
+ status = -1
+ return
+ endif
+
+ if (datatype(1).ne.TSTRING .or. datatype(2).ne.TLOGICAL) then
+ status = -2
+ return
+ endif
+
+ print *,'Total rows, No. rows = ',totalrows, nrows
+
+ endif
+
+C -------------------------------------------
+C Main loop: process all the rows of data
+C -------------------------------------------
+
+C NOTE: 1st element of array is the null pixel value!
+C Loop over elements 2 to nrows+1, not 1 to nrows.
+
+ do 10 ii=2,nrows+1
+ print *, stringCol(ii), logicalCol(ii)
+ if( logicalCol(ii) ) then
+ logicalCol(ii) = .false.
+ stringCol(ii) = 'changed to false'
+ else
+ logicalCol(ii) = .true.
+ stringCol(ii) = 'changed to true'
+ endif
+ 10 continue
+
+C -------------------------------------------------------
+C Clean up procedures: after processing all the rows
+C -------------------------------------------------------
+
+ if (firstrow + nrows - 1 .eq. totalrows) then
+C no action required in this case
+ endif
+
+ return
+ end
+
diff --git a/pkg/tbtables/cfitsio/iter_b.fit b/pkg/tbtables/cfitsio/iter_b.fit
new file mode 100644
index 00000000..9b4a086c
--- /dev/null
+++ b/pkg/tbtables/cfitsio/iter_b.fit
Binary files differ
diff --git a/pkg/tbtables/cfitsio/iter_c.c b/pkg/tbtables/cfitsio/iter_c.c
new file mode 100644
index 00000000..bbf97742
--- /dev/null
+++ b/pkg/tbtables/cfitsio/iter_c.c
@@ -0,0 +1,171 @@
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "fitsio.h"
+
+/*
+ This example program illustrates how to use the CFITSIO iterator function.
+
+ This program creates a 2D histogram of the X and Y columns of an event
+ list. The 'main' routine just creates the empty new image, then executes
+ the 'writehisto' work function by calling the CFITSIO iterator function.
+
+ 'writehisto' opens the FITS event list that contains the X and Y columns.
+ It then calls a second work function, calchisto, (by recursively calling
+ the CFITSIO iterator function) which actually computes the 2D histogram.
+*/
+
+/* Globally defined parameters */
+
+long xsize = 480; /* size of the histogram image */
+long ysize = 480;
+long xbinsize = 32;
+long ybinsize = 32;
+
+main()
+{
+ extern writehisto(); /* external work function passed to the iterator */
+ extern long xsize, ysize; /* size of image */
+
+ fitsfile *fptr;
+ iteratorCol cols[1];
+ int n_cols, status = 0;
+ long n_per_loop, offset, naxes[2];
+ char filename[] = "histoimg.fit"; /* name of FITS image */
+
+ remove(filename); /* delete previous version of the file if it exists */
+ fits_create_file(&fptr, filename, &status); /* create new output image */
+
+ naxes[0] = xsize;
+ naxes[1] = ysize;
+ fits_create_img(fptr, LONG_IMG, 2, naxes, &status); /* create primary HDU */
+
+ n_cols = 1; /* number of columns */
+
+ /* define input column structure members for the iterator function */
+ fits_iter_set_by_name(&cols[0], fptr, " ", TLONG, OutputCol);
+
+ n_per_loop = -1; /* force whole array to be passed at one time */
+ offset = 0; /* don't skip over any pixels */
+
+ /* execute the function to create and write the 2D histogram */
+ printf("Calling writehisto iterator work function... %d\n", status);
+
+ fits_iterate_data(n_cols, cols, offset, n_per_loop,
+ writehisto, 0L, &status);
+
+ fits_close_file(fptr, &status); /* all done; close the file */
+
+ if (status)
+ fits_report_error(stderr, status); /* print out error messages */
+ else
+ printf("Program completed successfully.\n");
+
+ return(status);
+}
+/*--------------------------------------------------------------------------*/
+int writehisto(long totaln, long offset, long firstn, long nvalues,
+ int narrays, iteratorCol *histo, void *userPointer)
+/*
+ Iterator work function that writes out the 2D histogram.
+ The histogram values are calculated by another work function, calchisto.
+
+ This routine is executed only once since nvalues was forced to = totaln.
+*/
+{
+ extern calchisto(); /* external function called by the iterator */
+ long *histogram;
+ fitsfile *tblptr;
+ iteratorCol cols[2];
+ int n_cols, status = 0;
+ long rows_per_loop, rowoffset;
+ char filename[] = "iter_c.fit"; /* name of FITS table */
+
+ /* do sanity checking of input values */
+ if (totaln != nvalues)
+ return(-1); /* whole image must be passed at one time */
+
+ if (narrays != 1)
+ return(-2); /* number of images is incorrect */
+
+ if (fits_iter_get_datatype(&histo[0]) != TLONG)
+ return(-3); /* input array has wrong data type */
+
+ /* assign the FITS array pointer to the global histogram pointer */
+ histogram = (long *) fits_iter_get_array(&histo[0]);
+
+ /* open the file and move to the table containing the X and Y columns */
+ fits_open_file(&tblptr, filename, READONLY, &status);
+ fits_movnam_hdu(tblptr, BINARY_TBL, "EVENTS", 0, &status);
+ if (status)
+ return(status);
+
+ n_cols = 2; /* number of columns */
+
+ /* define input column structure members for the iterator function */
+ fits_iter_set_by_name(&cols[0], tblptr, "X", TLONG, InputCol);
+ fits_iter_set_by_name(&cols[1], tblptr, "Y", TLONG, InputCol);
+
+ rows_per_loop = 0; /* take default number of rows per interation */
+ rowoffset = 0;
+
+ /* calculate the histogram */
+ printf("Calling calchisto iterator work function... %d\n", status);
+
+ fits_iterate_data(n_cols, cols, rowoffset, rows_per_loop,
+ calchisto, histogram, &status);
+
+ fits_close_file(tblptr, &status); /* all done */
+ return(status);
+}
+/*--------------------------------------------------------------------------*/
+int calchisto(long totalrows, long offset, long firstrow, long nrows,
+ int ncols, iteratorCol *cols, void *userPointer)
+
+/*
+ Interator work function that calculates values for the 2D histogram.
+*/
+{
+ extern long xsize, ysize, xbinsize, ybinsize;
+ long ii, ihisto, xbin, ybin;
+ static long *xcol, *ycol, *histogram; /* static to preserve values */
+
+ /*--------------------------------------------------------*/
+ /* Initialization procedures: execute on the first call */
+ /*--------------------------------------------------------*/
+ if (firstrow == 1)
+ {
+ /* do sanity checking of input values */
+ if (ncols != 2)
+ return(-3); /* number of arrays is incorrect */
+
+ if (fits_iter_get_datatype(&cols[0]) != TLONG ||
+ fits_iter_get_datatype(&cols[1]) != TLONG)
+ return(-4); /* wrong datatypes */
+
+ /* assign the input array points to the X and Y arrays */
+ xcol = (long *) fits_iter_get_array(&cols[0]);
+ ycol = (long *) fits_iter_get_array(&cols[1]);
+ histogram = (long *) userPointer;
+
+ /* initialize the histogram image pixels = 0 */
+ for (ii = 0; ii <= xsize * ysize; ii++)
+ histogram[ii] = 0L;
+ }
+
+ /*------------------------------------------------------------------*/
+ /* Main loop: increment the 2D histogram at position of each event */
+ /*------------------------------------------------------------------*/
+
+ for (ii = 1; ii <= nrows; ii++)
+ {
+ xbin = xcol[ii] / xbinsize;
+ ybin = ycol[ii] / ybinsize;
+
+ ihisto = ( ybin * xsize ) + xbin + 1;
+ histogram[ihisto]++;
+ }
+
+ return(0);
+}
+
diff --git a/pkg/tbtables/cfitsio/iter_c.f b/pkg/tbtables/cfitsio/iter_c.f
new file mode 100644
index 00000000..f9abeaa8
--- /dev/null
+++ b/pkg/tbtables/cfitsio/iter_c.f
@@ -0,0 +1,347 @@
+ program f77iterate_c
+C
+C This example program illustrates how to use the CFITSIO iterator function.
+C
+C This program creates a 2D histogram of the X and Y columns of an event
+C list. The 'main' routine just creates the empty new image, then executes
+C the 'writehisto' work function by calling the CFITSIO iterator function.
+C
+C 'writehisto' opens the FITS event list that contains the X and Y columns.
+C It then calls a second work function, calchisto, (by recursively calling
+C the CFITSIO iterator function) which actually computes the 2D histogram.
+
+C external work function to be passed to the iterator
+ external writehisto
+
+ integer ncols
+ parameter (ncols=1)
+ integer units(ncols), colnum(ncols), datatype(ncols)
+ integer iotype(ncols), offset, n_per_loop, status
+ character*70 colname(ncols)
+
+ integer naxes(2), ounit, blocksize
+ character*80 fname
+ logical exists
+
+C include f77.inc -------------------------------------
+C Codes for FITS extension types
+ integer IMAGE_HDU, ASCII_TBL, BINARY_TBL
+ parameter (
+ & IMAGE_HDU = 0,
+ & ASCII_TBL = 1,
+ & BINARY_TBL = 2 )
+
+C Codes for FITS table data types
+
+ integer TBIT,TBYTE,TLOGICAL,TSTRING,TSHORT,TINT
+ integer TFLOAT,TDOUBLE,TCOMPLEX,TDBLCOMPLEX
+ parameter (
+ & TBIT = 1,
+ & TBYTE = 11,
+ & TLOGICAL = 14,
+ & TSTRING = 16,
+ & TSHORT = 21,
+ & TINT = 31,
+ & TFLOAT = 42,
+ & TDOUBLE = 82,
+ & TCOMPLEX = 83,
+ & TDBLCOMPLEX = 163 )
+
+C Codes for iterator column types
+
+ integer InputCol, InputOutputCol, OutputCol
+ parameter (
+ & InputCol = 0,
+ & InputOutputCol = 1,
+ & OutputCol = 2 )
+C End of f77.inc -------------------------------------
+
+C**********************************************************************
+C Need to make these variables available to the 2 work functions
+ integer xsize,ysize,xbinsize,ybinsize
+ common /histcomm/ xsize,ysize,xbinsize,ybinsize
+C**********************************************************************
+
+ status = 0
+
+ xsize = 480
+ ysize = 480
+ xbinsize = 32
+ ybinsize = 32
+
+ fname = 'histoimg.fit'
+ ounit = 15
+
+C delete previous version of the file if it exists
+ inquire(file=fname,exist=exists)
+ if( exists ) then
+ open(ounit,file=fname,status='old')
+ close(ounit,status='delete')
+ endif
+ 99 blocksize = 2880
+
+C create new output image
+ call ftinit(ounit,fname,blocksize,status)
+
+ naxes(1) = xsize
+ naxes(2) = ysize
+
+C create primary HDU
+ call ftiimg(ounit,32,2,naxes,status)
+
+ units(1) = ounit
+
+C Define column as TINT and Output
+ datatype(1) = TINT
+ iotype(1) = OutputCol
+
+C force whole array to be passed at one time
+ n_per_loop = -1
+ offset = 0
+
+C execute the function to create and write the 2D histogram
+ print *,'Calling writehisto iterator work function... ',status
+
+ call ftiter( ncols, units, colnum, colname, datatype, iotype,
+ & offset, n_per_loop, writehisto, 0, status )
+
+ call ftclos(ounit, status)
+
+C print out error messages if problem
+ if (status.ne.0) then
+ call ftrprt('STDERR', status)
+ else
+ print *,'Program completed successfully.'
+ endif
+
+ stop
+ end
+
+C--------------------------------------------------------------------------
+C
+C Sample iterator function.
+C
+C Iterator work function that writes out the 2D histogram.
+C The histogram values are calculated by another work function, calchisto.
+C
+C--------------------------------------------------------------------------
+ subroutine writehisto(totaln, offset, firstn, nvalues, narrays,
+ & units_out, colnum_out, datatype_out, iotype_out, repeat,
+ & status, userData, histogram )
+
+ integer totaln,offset,firstn,nvalues,narrays,status
+ integer units_out(narrays),colnum_out(narrays)
+ integer datatype_out(narrays),iotype_out(narrays)
+ integer repeat(narrays)
+ integer histogram(*), userData
+
+ external calchisto
+ integer ncols
+ parameter (ncols=2)
+ integer units(ncols), colnum(ncols), datatype(ncols)
+ integer iotype(ncols), rowoffset, rows_per_loop
+ character*70 colname(ncols)
+
+ integer iunit, blocksize
+ character*80 fname
+
+C include f77.inc -------------------------------------
+C Codes for FITS extension types
+ integer IMAGE_HDU, ASCII_TBL, BINARY_TBL
+ parameter (
+ & IMAGE_HDU = 0,
+ & ASCII_TBL = 1,
+ & BINARY_TBL = 2 )
+
+C Codes for FITS table data types
+
+ integer TBIT,TBYTE,TLOGICAL,TSTRING,TSHORT,TINT
+ integer TFLOAT,TDOUBLE,TCOMPLEX,TDBLCOMPLEX
+ parameter (
+ & TBIT = 1,
+ & TBYTE = 11,
+ & TLOGICAL = 14,
+ & TSTRING = 16,
+ & TSHORT = 21,
+ & TINT = 31,
+ & TFLOAT = 42,
+ & TDOUBLE = 82,
+ & TCOMPLEX = 83,
+ & TDBLCOMPLEX = 163 )
+
+C Codes for iterator column types
+
+ integer InputCol, InputOutputCol, OutputCol
+ parameter (
+ & InputCol = 0,
+ & InputOutputCol = 1,
+ & OutputCol = 2 )
+C End of f77.inc -------------------------------------
+
+C**********************************************************************
+C Need to make these variables available to the 2 work functions
+ integer xsize,ysize,xbinsize,ybinsize
+ common /histcomm/ xsize,ysize,xbinsize,ybinsize
+C**********************************************************************
+
+ if (status .ne. 0) return
+
+C name of FITS table
+ fname = 'iter_c.fit'
+ iunit = 16
+
+C do sanity checking of input values
+ if (totaln .ne. nvalues) then
+C whole image must be passed at one time
+ status = -1
+ return
+ endif
+
+ if (narrays .ne. 1) then
+C number of images is incorrect
+ status = -2
+ return
+ endif
+
+ if (datatype_out(1) .ne. TINT) then
+C input array has wrong data type
+ status = -3
+ return
+ endif
+
+C open the file and move to the table containing the X and Y columns
+ call ftopen(iunit,fname,0,blocksize,status)
+ call ftmnhd(iunit, BINARY_TBL, 'EVENTS', 0, status)
+ if (status) return
+
+C both the columns are in the same FITS file
+ units(1) = iunit
+ units(2) = iunit
+
+C desired datatype for each column: TINT
+ datatype(1) = TINT
+ datatype(2) = TINT
+
+C names of the columns
+ colname(1) = 'X'
+ colname(2) = 'Y'
+
+C leave column numbers undefined
+ colnum(1) = 0
+ colnum(2) = 0
+
+C define whether columns are input, input/output, or output only
+C Both input
+ iotype(1) = InputCol
+ iotype(1) = InputCol
+
+C take default number of rows per iteration
+ rows_per_loop = 0
+ rowoffset = 0
+
+C calculate the histogram
+ print *,'Calling calchisto iterator work function... ', status
+
+ call ftiter( ncols, units, colnum, colname, datatype, iotype,
+ & rowoffset, rows_per_loop, calchisto, histogram, status )
+
+ call ftclos(iunit,status)
+ return
+ end
+
+C--------------------------------------------------------------------------
+C
+C Iterator work function that calculates values for the 2D histogram.
+C
+C--------------------------------------------------------------------------
+ subroutine calchisto(totalrows, offset, firstrow, nrows, ncols,
+ & units, colnum, datatype, iotype, repeat, status,
+ & histogram, xcol, ycol )
+
+ integer totalrows,offset,firstrow,nrows,ncols,status
+ integer units(ncols),colnum(ncols),datatype(ncols)
+ integer iotype(ncols),repeat(ncols)
+ integer histogram(*),xcol(*),ycol(*)
+C include f77.inc -------------------------------------
+C Codes for FITS extension types
+ integer IMAGE_HDU, ASCII_TBL, BINARY_TBL
+ parameter (
+ & IMAGE_HDU = 0,
+ & ASCII_TBL = 1,
+ & BINARY_TBL = 2 )
+
+C Codes for FITS table data types
+
+ integer TBIT,TBYTE,TLOGICAL,TSTRING,TSHORT,TINT
+ integer TFLOAT,TDOUBLE,TCOMPLEX,TDBLCOMPLEX
+ parameter (
+ & TBIT = 1,
+ & TBYTE = 11,
+ & TLOGICAL = 14,
+ & TSTRING = 16,
+ & TSHORT = 21,
+ & TINT = 31,
+ & TFLOAT = 42,
+ & TDOUBLE = 82,
+ & TCOMPLEX = 83,
+ & TDBLCOMPLEX = 163 )
+
+C Codes for iterator column types
+
+ integer InputCol, InputOutputCol, OutputCol
+ parameter (
+ & InputCol = 0,
+ & InputOutputCol = 1,
+ & OutputCol = 2 )
+C End of f77.inc -------------------------------------
+
+ integer ii, ihisto, xbin, ybin
+
+C**********************************************************************
+C Need to make these variables available to the 2 work functions
+ integer xsize,ysize,xbinsize,ybinsize
+ common /histcomm/ xsize,ysize,xbinsize,ybinsize
+C**********************************************************************
+
+ if (status .ne. 0) return
+
+C --------------------------------------------------------
+C Initialization procedures: execute on the first call
+C --------------------------------------------------------
+ if (firstrow .eq. 1) then
+C do sanity checking of input values
+
+ if (ncols .ne. 2) then
+C number of arrays is incorrect
+ status = -4
+ return
+ endif
+
+ if (datatype(1).ne.TINT .or. datatype(2).ne.TINT) then
+C wrong datatypes
+ status = -5
+ return
+ endif
+
+C initialize the histogram image pixels = 0, including null value
+ do 10 ii = 1, xsize * ysize + 1
+ histogram(ii) = 0
+ 10 continue
+
+ endif
+
+C ------------------------------------------------------------------
+C Main loop: increment the 2D histogram at position of each event
+C ------------------------------------------------------------------
+
+ do 20 ii=2,nrows+1
+ xbin = xcol(ii) / xbinsize
+ ybin = ycol(ii) / ybinsize
+
+ ihisto = ( ybin * xsize ) + xbin + 2
+ histogram(ihisto) = histogram(ihisto) + 1
+ 20 continue
+
+ return
+ end
+
diff --git a/pkg/tbtables/cfitsio/iter_c.fit b/pkg/tbtables/cfitsio/iter_c.fit
new file mode 100644
index 00000000..f8576741
--- /dev/null
+++ b/pkg/tbtables/cfitsio/iter_c.fit
@@ -0,0 +1,701 @@
+SIMPLE = T / file does conform to FITS standard BITPIX = 32 / number of bits per data pixel NAXIS = 0 / number of data axes EXTEND = T / FITS dataset may contain extensions COMMENT FITS (Flexible Image Transport System) format defined in Astronomy andCOMMENT Astrophysics Supplement Series v44/p363, v44/p371, v73/p359, v73/p365.COMMENT Contact the NASA Science Office of Standards and Technology for the COMMENT FITS Definition document #100 and other FITS information. END XTENSION= 'BINTABLE' / FITS 3D BINARY TABLE BITPIX = 8 / Binary data NAXIS = 2 / Table is a matrix NAXIS1 = 16 / Width of table in bytes NAXIS2 = 5000 / Number of entries in table PCOUNT = 0 / Random parameter count GCOUNT = 1 / Group count TFIELDS = 5 / Number of fields in each row EXTNAME = 'EVENTS ' / Table name EXTVER = 1 / Version number of table TFORM1 = '1I ' / Data type for field TTYPE1 = 'X ' / Label for field TUNIT1 = ' ' / Physical units for field TFORM2 = '1I ' / Data type for field TTYPE2 = 'Y ' / Label for field TUNIT2 = ' ' / Physical units for field TFORM3 = '1I ' / Data type for field TTYPE3 = 'PHA ' / Label for field TUNIT3 = ' ' / Physical units for field TFORM4 = '1D ' / Data type for field TTYPE4 = 'TIME ' / Label for field TUNIT4 = ' ' / Physical units for field TFORM5 = '1I ' / Data type for field TTYPE5 = 'DY ' / Label for field TUNIT5 = ' ' / Physical units for field TLMIN1 = 1 TLMAX1 = 15360 TLMIN2 = 1 TLMAX2 = 15360 NAXLEN = 2 / Number of QPOE axes AXLEN1 = 15360 / Dim. of qpoe axis 1 AXLEN2 = 15360 / Dim. of qpoe axis 2 TELESCOP= 'ROSAT ' / telescope (mission) name INSTRUME= 'PSPC ' / instrument (detector) name RADECSYS= 'FK5 ' / WCS for this file (e.g. Fk4) EQUINOX = 2.000000E3 / equinox (epoch) for WCS CTYPE1 = 'RA---TAN' / axis type for dim. 1 (e.g. RA---TAN) CTYPE2 = 'DEC--TAN' / axis type for dim. 2 (e.g. DEC--TAN) CRVAL1 = 8.588000E1 / sky coord of 1st axis (deg.) CRVAL2 = 6.926986E1 / sky coord of 2nd axis (deg.) CDELT1 = -1.388889E-4 / x degrees per pixel CDELT2 = 1.388889E-4 / y degrees per pixel CRPIX1 = 7.680000E3 / x pixel of tangent plane direction CRPIX2 = 7.680000E3 / y pixel of tangent plane direction CROTA2 = 0.000000E0 / rotation angle (degrees) MJD-OBS = 4.905444E4 / MJD of start of obs. DATE-OBS= '08/03/93' / date of observation start TIME-OBS= '10:30:32' / time of observation start DATE-END= '11/03/93' / date of observation end TIME-END= '05:02:18' / time of observation end XS-OBSID= 'US800282P.N1 ' / observation ID XS-SEQPI= 'ROTS, DR., ARNOLD,H. ' / XS-SUBIN= 2 / subinstrument id XS-OBSV = 800282 / observer id XS-CNTRY= 'USA ' / country where data was processed XS-FILTR= 0 / filter id: 0=none, 1=PSPC boron XS-MODE = 1 / pointing mode: 1=point,2=slew,3=scan XS-DANG = 0.000000E0 / detector roll angle (degrees) XS-MJDRD= 48043 / integer portion of mjd for SC clock start XS-MJDRF= 8.797453703700740E-1 / fractional portion of mjd for SC clock start XS-EVREF= 0 / day offset from mjdrday to evenr start times XS-TBASE= 0.000000000000000E0 / seconds from s/c clock start to obs start XS-ONTI = 1.476600000000000E4 / on time (seconds) XS-LIVTI= 1.476600000000000E4 / live time (seconds) XS-DTCOR= 1.000000E0 / dead time correction XS-BKDEN= 0.000000E0 / bkgd density cts/arcmin**2 XS-MINLT= 0.000000E0 / min live time factor XS-MAXLT= 0.000000E0 / max live time factor XS-XAOPT= 0.000000E0 / avg. opt. axis x in degrees from tangent planXS-YAOPT= 0.000000E0 / avg. opt. axis y in degrees from tangent planXS-XAOFF= 0.000000E0 / avg x aspect offset (degrees) XS-YAOFF= 0.000000E0 / avg y aspect offset (degrees) XS-RAROT= 0.000000E0 / avg aspect rotation (degrees) XS-XARMS= 0.000000E0 / avg x aspect RMS (arcsec) XS-YARMS= 0.000000E0 / avg y aspect RMS (arcsec) XS-RARMS= 0.000000E0 / avg aspect rotation RMS (degrees) XS-RAPT = 8.588000E1 / nominal right ascension (degrees) XS-DECPT= 6.926986E1 / nominal declination (degrees) XS-XPT = 4096 / target pointing direction (pixels) XS-YPT = 4096 / target pointing direction (pixels) XS-XDET = 8192 / x dimen. of detector XS-YDET = 8192 / y dimen. of detector XS-FOV = 0 / field of view (degrees) XS-INPXX= 2.595021E-4 / original degrees per pixel XS-INPXY= 2.595021E-4 / original degrees per pixel XS-XDOPT= 4.119000E3 / detector opt. axis x in detector pixels XS-YDOPT= 3.929000E3 / detector opt. axis y in detector pixels XS-CHANS= 256 / pha channels TDISP4 = 'I12 ' HISTORY modified by pence on Thu Apr 24 15:04:08 EDT 1997 HISTORY modified by pence on Thu Apr 24 15:07:24 EDT 1997 TDISP5 = 'I4 ' HISTORY modified by pence on Thu Apr 24 16:06:08 EDT 1997 HISTORY File modified by user 'pence' with fv on 97-11-25T14:34:58 HISTORY File modified by user 'pence' with fv on 98-01-12T14:03:09 HISTORY File modified by user 'pence' with fv on 98-02-06T15:18:24 END óµ
+Œ?-a
+A”Ñm~à
+Á ä
+A”ÑrÛ
+A”Ñ{ó@
+e
+î¬é
+Ý
+Ð1°
+A”Ñ’k
+A”Ñ–@
+á(
+A”Ñ«Y€
+Q
+A”ѯ`
+Ô2
+/Õ æ
+A”Ñ´RÀ
+A”ѺG 
+A”ѽt€
+Ù/ú
+A”ѾD`
+A”ѾNÀ
+r
+A”ÑÂ
+$s
+§$_
+A”ÑÎÀà
+Û/Ù
+A”ÑÒà
+A”ÑÔZ
+
+ J
+/û^
+A”ÑæE
+ÛxJ
+A”Ñõ] 
+A”ÑüQ€
+A”Ñÿ¼
+¿¥A
+A”ÑË
+J ]{
+—`
+€
+RÕ
+…;
+A”Ñ!í`
+
+‡ 4`
+Ôû¾
+A”ÑCi€
+_(U
+QJë
+^n
+A”ÑQþ
+*È B
+A”Ñ\÷
+–ªf
+
+A”Ñu•€
+Yª4p
+ë,|
+<
+A”Ñ‹
+A”Ñ£à
+™-ˆ
+A”ÑŸC 
+
+N
+A”Ñ©à
+÷ Ä
+A”ѵØ`
+
+''-
+Ôs í
+œ%L
+1)V
+&bp
+D
+‰,÷
+ž¡
+–#¶
+s€
+Aӄ 
+[
++!E
+Aӄ ,*`
+=
+Ã? N
+A”Ñ :îÀ
+Þ]¼
+Aӄ BG
+_9 ©
+#
+A”Ñ TéÀ
+`
+A”Ñ _–@
+¾0¢ «
+‰
+A”Ñ vÙ
+€
+¾3f?
+A”Ñ |Ÿ€
+(J a
+H
+g(C
+A”Ñ ”Íà
+H"´ 
+A”Ñ £¥à
+
+@
+Q
+•­
+>Ê*
+ú&yµ
+A”Ñ ÆW@
+A”Ñ Ì„`
+
+A”Ñ ìí
+6
+A”Ñ óä@
+ï 'y
+91/Ü
+ù)?/ñ
+Â:1¢
+
+A”Ñ!Í`
+Aӄ! T
+) Š
+A”Ñ!ý
+Aӄ!Y@
+…0‘ S
+Aӄ!-
+
+A”Ñ!1=À
+Ì$$!c
+l],
+Aӄ!7R
+Aӄ!8@
+*5
+A”Ñ!@M€
+A”Ñ!Sz€
+[: µ
+ã&2»
+%Ñ+•
+Aӄ!ji@
+Ÿ 
+A”Ñ!w€
+A”Ñ!yØ`
+Ì·
+
+
+A”Ñ!3À
+»1S
+Ô«"¥
+þ*@(
+A”Ñ!”–@
+A”Ñ!šîà
+A”Ñ!ž¥@
+çææ
+A”Ñ!¡w 
+A”Ñ!¢h`
+
+X–,*
+˜
+A”Ñ!¹ 
+#%0f
+&
+Aӄ!ꉈ
+
+A”Ñ!ÏOÀ
+A”Ñ!ؼà
+R-¦,ž
+A”Ñ!åŒ
+A”Ñ!óΠ
+o7
+A”Ñ!üé 
+A”Ñ!ý<@
+Ô®*¨
+C@
+Ð'
+A”Ñ"  
+Aӄ"@
+Aӄ"%4
+Aӄ"&r`
+A”Ñ"(Ó@
+A”Ñ"8‹@
+à»+œ
+A”Ñ":ª`
+A/(
+çÎÅ
+›¶L
+Aӄ"e@
+
+A”Ñ"u{ 
+A”Ñ"ŠÀ
+„$Ý
+@
+Aӄ"ݬ@
+A”Ñ"Ÿ`
+ëBq
+{ ¶b
+â'à
+if
+A”Ñ"½ÍÀ
+ç%7{
+A”Ñ"ÈEà
+A”Ñ"Ï?À
+}Ë
+Ù
+%)¯ë
+A”Ñ"çä
+A”Ñ"ðÇ@
+A”Ñ"ú
+Ü"ú
+;
+z)/#j
+A”Ñ#]à
+kÀ
+`"¢3è
+Æ)£
+A”Ñ#Å 
+A”Ñ#iÀ
+b^7Ð
+öU4ý
+
+Aӄ#$
+Ê$
+A”Ñ#-ß
+Ý#‘1É
+A”Ñ#1 
+Ò Ù)
+¯& ‚
+
+A”Ñ#>½À
+A”Ñ#BØà
+Òi.
+?á+Æ
+Aӄ#R@
+› ­ §
+A”Ñ#XÍà
+U
+”
+1#o'…
+%Ïé
+A”Ñ#h•à
+Aӄ#tp
+8/
+A”Ñ#‹P@
+A”Ñ#ñ 
+Aӄ#m
+Î'Ë&f
+f Ù
+)¯
+A”Ñ#¢H
+[+º
+A”Ñ#§Ý
+â^À
+A”Ñ#¯ @
+Š
+A”Ñ#½D 
+Ý!ù,å
+Ø£2#
+A”Ñ#Í× 
++++Ç
+A”Ñ#Ïà
+A”Ñ#Ò#
+A”Ñ#Û¦
+Å •(x
+Ö(:$‰
+A”Ñ#íÙ
+6tÛ
+Ë$HÈ
+A”Ñ#öq
+A”Ñ$¢à
+ò
+
+È*!
+A”ÑS¸@
+âí
+A”ÑS¿í`
+
+
+•%¼
+A”ÑSÇÄ
+A”ÑSÍ´
+±Û„
+ Õ6J
+èè6
+™pÇ
+Ã+%i
+A”ÑS÷‡@
+A”ÑSúa
+ûú"³
+c„9
+¿
+€
+A”ÑTX€
+Œ 
+A”ÑT£`
+Ê
+ty
+A”ÑT¨@
+Ü
+Z
+T
+A”ÑT$CÀ
+AӄT'
+{§
+AӄT*u@
+'.‡
+A”ÑT+“`
+AӄT3`
+@$®
+A”ÑTFÌà
+ÿS7¾
+Õ½
+Ñ%5
+ë5a
+A”ÑTW?€
+‹ž
+A”ÑTiä`
+A”ÑTy³
+La1ø
+A”ÑT„o
+A”ÑT‡Ñ@
+é5Sé
+#(¹/s
+AӄTπ`
+c
+Ü9%.
+A”ÑT¨€
+Þ"D
+A”ÑTÂä`
+A”ÑTÍ!
+´+ù
+öw5¹
+A”ÑTê
+A”ÑTíS 
+A”ÑTíò
+A”ÑTð‚@
+j.ZV
+A”ÑTôG@
+A”ÑTõÉ
+A”ÑTýà
+*
+AӄUp
+A”ÑU„
+\_»
+.à
+
+:`
+A”ÑU SÀ
+AӄU@
+†
+A”ÑUŒ
+AӄU`
+V€(À
+a è18
+A”ÑU#±
+A”ÑU(6 
+$ Å
+AӄU2U
+p*> Ï
+A”ÑU<š€
+§-˜
+Q
+A”ÑUCÔ€
+µ,È
+AӄUI[
+×P{
+AӄUVF
+A”ÑU[là
+A”ÑU\å`
+A”ÑU_‡ 
+S
+&éQ
+õ0¯¤
+ïU
+A”ÑUjß 
+í3ã¦
+A”ÑUm4 
+ú-¸
+Œw
++4è'Í
+W&µ
+^ Ñ
+A”ÑUŒ
+È&n
+A”ÑUÍ€
+Ÿ
+A”ÑUý
+¢i
+A”ÑUºÝ`
+1?
+Û ¹0É
+ä.à(p
+w/ˆO
+yÕ0
+ýç
+
+(èR
+Q#M0"
+A”ÑUüæ€
+Õ`
+m ½(
+ü$
+F$œ
+A”ÑV%Dà
+`3P]
+A”ÑV.U 
+‘
+z$œ
+A”ÑV;·
+â-+¸
+AӄV?
+$­
+A”ÑV?×`
+L
+‚
+’
+ã6&²
+AӄVe
+A”ÑVh™
+Q…
+A”ÑVp 
+l‚A
+"I,[
+A”ÑV€ú 
+?
+A”ÑV‰2 
+A”ÑVŒå€
+A”ÑVŽ– 
+A”ÑVÈÀ
+!_
+A”ÑV ”€
+õ ©
+
+{;
+A”ÑVÀS€
+W)[j
+<!T2é
+A”ÑVÆÛ`
+d‰
+¶0Ê 5
+Õòñ
+A”ÑVÓ^@
+É $z
+A”ÑVáÒ@
+ýŒ
+
+~]
+èA
+5
+A”ÑVÿK`
+A”ÑW³ 
+A”ÑW­
+t
+"€
+‰
+AӄWY@
+V"m
+
+”!Ø
+A”ÑW¯@
+A”ÑW @
+F
+A”ÑW*HÀ
+B,kK
+ã$BÖ
+A”ÑWDyà
+)ð
+ÇÍ
+!þ–
+$
+A”ÑWhï 
+
+A”ÑW‡”
+&
+A”ÑWoÀ
+A”ÑWޝ€
+AӄWФ`
+@#
+|
+%
+A”ÑW¥&à
+
+.
+A”ÑW®
+
+[
+A”ÑW¶i
+FÐ
+A”ÑWÀ²`
+A”ÑWÆ]€
++
+™
+].w
+˜
+Ï5±-
+A”ÑWÙU 
+A”ÑWé9
+
+A”ÑWôSà
+îž
+A”ÑX ¨
+A”ÑX p 
+›YJ
+AӄXc
+Ü 
+¼#îs
+4%-Ì
+I.Ú
+
++â
+
+A”ÑX3–`
+AӄXG$`
+©+‚
+AӄXI
+€
+Z)3I
+!(î
+
+A”ÑXR/À
+î
+A”ÑXXÁ
+¾3 
+A”ÑXbAÀ
+Ï(o¶
+A”ÑXx=€
+¿*Î
+¯*!
+A”ÑX„Û`
+
+Ú "
+Š"H
+"
+A”ÑXÏ€
+A”ÑX¡€
+A”ÑX£[€
+R 4ú
+¿Â‹
+‰
+A”ÑXµƒ 
+A”ÑX¼ôà
+A”ÑXÀ,À
+
+ñÿ
+€
+Í
+®ì
+*
+¸*"ª
+
+
+c0
+A”ÑY zÀ
+= 
+Ó€
+M\F
+
+.&£
+þ%™
+
+4 é,ó
+A”ÑYº@
+A”ÑY"™`
+AӄY'
+AӄY'f
+A”ÑY6œ@
+É,Î
+A”ÑYF 
+,­
+A”ÑYT°@
+AӄYV~
+&
+f Ô$‚
+„'_
+AӄYoY`
+A”ÑYrÎ@
+AӄYyd
+A”ÑYyÔà
+A”ÑYœ 
+A”ÑY„×À
+A”ÑY†!à
+A”ÑY‘œ@
+
+AӄYՂ
+A”ÑY•
+AӄYќ@
+L
+A”ÑY˜¼ 
+A”ÑY úà
+A”ÑY¡î
+A”ÑY¦Ÿ@
+j(}
+A”ÑY§9
+A”ÑY®`
+-(
+
+“@-Æ
+
+!
+Å/¯
+A”ÑYÖÞ€
+„
+A”ÑYêÅ
+
+øg
+A”ÑYñïà
+ì†x
+ü6*
+S„ø
+™€
+V°
+Ä@
+@
+A”ÑZÀ
+A”ÑZš
+y,h+
+f!
+[
+ÃHÅ
+d0
+
+3~¿
+
+AӄZ]M
+œ
+Ò&Ç;
+A”ÑZ`ià
+A”ÑZdû
+A”ÑZe« 
+A”ÑZf)à
+A”ÑZr×
+„/áJ
+AӄZw7@
+1
+A”ÑZ…Â@
+Œ%'
+Ñ w
+A”ÑZšà
+Ø)s
+A”ÑZ§‰@
+A”ÑZ¨H`
+A”ÑZ©j 
+A”ÑZª#
+p.b
+A”ÑZ®Š 
+
+Ø7eë
+A”ÑZÄnÀ
diff --git a/pkg/tbtables/cfitsio/listhead.c b/pkg/tbtables/cfitsio/listhead.c
new file mode 100644
index 00000000..a9a62384
--- /dev/null
+++ b/pkg/tbtables/cfitsio/listhead.c
@@ -0,0 +1,62 @@
+#include <string.h>
+#include <stdio.h>
+#include "fitsio.h"
+
+int main(int argc, char *argv[])
+{
+ fitsfile *fptr; /* FITS file pointer, defined in fitsio.h */
+ char card[FLEN_CARD]; /* Standard string lengths defined in fitsio.h */
+ int status = 0, single = 0, hdupos, nkeys, ii;
+
+ if (argc != 2) {
+ printf("Usage: listhead filename[ext] \n");
+ printf("\n");
+ printf("List the FITS header keywords in a single extension, or, if \n");
+ printf("ext is not given, list the keywords in all the extensions. \n");
+ printf("\n");
+ printf("Examples: \n");
+ printf(" listhead file.fits - list every header in the file \n");
+ printf(" listhead file.fits[0] - list primary array header \n");
+ printf(" listhead file.fits[2] - list header of 2nd extension \n");
+ printf(" listhead file.fits+2 - same as above \n");
+ printf(" listhead file.fits[GTI] - list header of GTI extension\n");
+ printf("\n");
+ printf("Note that it may be necessary to enclose the input file\n");
+ printf("name in single quote characters on the Unix command line.\n");
+ return(0);
+ }
+
+ if (!fits_open_file(&fptr, argv[1], READONLY, &status))
+ {
+ fits_get_hdu_num(fptr, &hdupos); /* Get the current HDU position */
+
+ /* List only a single header if a specific extension was given */
+ if (hdupos != 1 || strchr(argv[1], '[')) single = 1;
+
+ for (; !status; hdupos++) /* Main loop through each extension */
+ {
+ fits_get_hdrspace(fptr, &nkeys, NULL, &status); /* get # of keywords */
+
+ printf("Header listing for HDU #%d:\n", hdupos);
+
+ for (ii = 1; ii <= nkeys; ii++) { /* Read and print each keywords */
+
+ if (fits_read_record(fptr, ii, card, &status))break;
+ printf("%s\n", card);
+ }
+ printf("END\n\n"); /* terminate listing with END */
+
+ if (single) break; /* quit if only listing a single header */
+
+ fits_movrel_hdu(fptr, 1, NULL, &status); /* try to move to next HDU */
+ }
+
+ if (status == END_OF_FILE) status = 0; /* Reset after normal error */
+
+ fits_close_file(fptr, &status);
+ }
+
+ if (status) fits_report_error(stderr, status); /* print any error message */
+ return(status);
+}
+
diff --git a/pkg/tbtables/cfitsio/longnam.h b/pkg/tbtables/cfitsio/longnam.h
new file mode 100644
index 00000000..de8c0545
--- /dev/null
+++ b/pkg/tbtables/cfitsio/longnam.h
@@ -0,0 +1,538 @@
+#ifndef _LONGNAME_H
+#define _LONGNAME_H
+
+#define fits_parse_input_url ffiurl
+#define fits_parse_rootname ffrtnm
+#define fits_file_exists ffexist
+#define fits_parse_output_url ffourl
+#define fits_parse_extspec ffexts
+#define fits_parse_extnum ffextn
+#define fits_parse_binspec ffbins
+#define fits_parse_binrange ffbinr
+#define fits_parse_range ffrwrg
+#define fits_open_memfile ffomem
+#define fits_open_file ffopen
+#define fits_open_data ffdopn
+#define fits_open_table fftopn
+#define fits_open_image ffiopn
+#define fits_open_diskfile ffdkopn
+#define fits_reopen_file ffreopen
+#define fits_create_file ffinit
+#define fits_create_diskfile ffdkinit
+#define fits_create_memfile ffimem
+#define fits_create_template fftplt
+#define fits_flush_file ffflus
+#define fits_flush_buffer ffflsh
+#define fits_close_file ffclos
+#define fits_delete_file ffdelt
+#define fits_file_name ffflnm
+#define fits_file_mode ffflmd
+#define fits_url_type ffurlt
+
+#define fits_get_version ffvers
+#define fits_uppercase ffupch
+#define fits_get_errstatus ffgerr
+#define fits_write_errmsg ffpmsg
+#define fits_write_errmark ffpmrk
+#define fits_read_errmsg ffgmsg
+#define fits_clear_errmsg ffcmsg
+#define fits_clear_errmark ffcmrk
+#define fits_report_error ffrprt
+#define fits_compare_str ffcmps
+#define fits_test_keyword fftkey
+#define fits_test_record fftrec
+#define fits_null_check ffnchk
+#define fits_make_keyn ffkeyn
+#define fits_make_nkey ffnkey
+#define fits_get_keyclass ffgkcl
+#define fits_get_keytype ffdtyp
+#define fits_parse_value ffpsvc
+#define fits_get_keyname ffgknm
+#define fits_parse_template ffgthd
+#define fits_ascii_tform ffasfm
+#define fits_binary_tform ffbnfm
+#define fits_get_tbcol ffgabc
+#define fits_get_rowsize ffgrsz
+#define fits_get_col_display_width ffgcdw
+
+#define fits_write_record ffprec
+#define fits_write_key ffpky
+#define fits_write_key_unit ffpunt
+#define fits_write_comment ffpcom
+#define fits_write_history ffphis
+#define fits_write_date ffpdat
+#define fits_get_system_time ffgstm
+#define fits_get_system_date ffgsdt
+#define fits_date2str ffdt2s
+#define fits_time2str fftm2s
+#define fits_str2date ffs2dt
+#define fits_str2time ffs2tm
+#define fits_write_key_longstr ffpkls
+#define fits_write_key_longwarn ffplsw
+#define fits_write_key_null ffpkyu
+#define fits_write_key_str ffpkys
+#define fits_write_key_log ffpkyl
+#define fits_write_key_lng ffpkyj
+#define fits_write_key_fixflt ffpkyf
+#define fits_write_key_flt ffpkye
+#define fits_write_key_fixdbl ffpkyg
+#define fits_write_key_dbl ffpkyd
+#define fits_write_key_fixcmp ffpkfc
+#define fits_write_key_cmp ffpkyc
+#define fits_write_key_fixdblcmp ffpkfm
+#define fits_write_key_dblcmp ffpkym
+#define fits_write_key_triple ffpkyt
+#define fits_write_tdim ffptdm
+#define fits_write_keys_str ffpkns
+#define fits_write_keys_log ffpknl
+#define fits_write_keys_lng ffpknj
+#define fits_write_keys_fixflt ffpknf
+#define fits_write_keys_flt ffpkne
+#define fits_write_keys_fixdbl ffpkng
+#define fits_write_keys_dbl ffpknd
+#define fits_copy_key ffcpky
+#define fits_write_imghdr ffphps
+#define fits_write_grphdr ffphpr
+#define fits_write_atblhdr ffphtb
+#define fits_write_btblhdr ffphbn
+#define fits_write_key_template ffpktp
+
+#define fits_get_hdrspace ffghsp
+#define fits_get_hdrpos ffghps
+#define fits_movabs_key ffmaky
+#define fits_movrel_key ffmrky
+#define fits_find_nextkey ffgnxk
+
+#define fits_read_record ffgrec
+#define fits_read_card ffgcrd
+#define fits_read_key_unit ffgunt
+#define fits_read_keyn ffgkyn
+#define fits_read_key ffgky
+#define fits_read_keyword ffgkey
+#define fits_read_key_str ffgkys
+#define fits_read_key_log ffgkyl
+#define fits_read_key_lng ffgkyj
+#define fits_read_key_flt ffgkye
+#define fits_read_key_dbl ffgkyd
+#define fits_read_key_cmp ffgkyc
+#define fits_read_key_dblcmp ffgkym
+#define fits_read_key_triple ffgkyt
+#define fits_read_key_longstr ffgkls
+#define fits_read_tdim ffgtdm
+#define fits_decode_tdim ffdtdm
+#define fits_read_keys_str ffgkns
+#define fits_read_keys_log ffgknl
+#define fits_read_keys_lng ffgknj
+#define fits_read_keys_flt ffgkne
+#define fits_read_keys_dbl ffgknd
+#define fits_read_imghdr ffghpr
+#define fits_read_atblhdr ffghtb
+#define fits_read_btblhdr ffghbn
+#define fits_hdr2str ffhdr2str
+
+#define fits_update_card ffucrd
+#define fits_update_key ffuky
+#define fits_update_key_null ffukyu
+#define fits_update_key_str ffukys
+#define fits_update_key_longstr ffukls
+#define fits_update_key_log ffukyl
+#define fits_update_key_lng ffukyj
+#define fits_update_key_fixflt ffukyf
+#define fits_update_key_flt ffukye
+#define fits_update_key_fixdbl ffukyg
+#define fits_update_key_dbl ffukyd
+#define fits_update_key_fixcmp ffukfc
+#define fits_update_key_cmp ffukyc
+#define fits_update_key_fixdblcmp ffukfm
+#define fits_update_key_dblcmp ffukym
+
+#define fits_modify_record ffmrec
+#define fits_modify_card ffmcrd
+#define fits_modify_name ffmnam
+#define fits_modify_comment ffmcom
+#define fits_modify_key_null ffmkyu
+#define fits_modify_key_str ffmkys
+#define fits_modify_key_longstr ffmkls
+#define fits_modify_key_log ffmkyl
+#define fits_modify_key_lng ffmkyj
+#define fits_modify_key_fixflt ffmkyf
+#define fits_modify_key_flt ffmkye
+#define fits_modify_key_fixdbl ffmkyg
+#define fits_modify_key_dbl ffmkyd
+#define fits_modify_key_fixcmp ffmkfc
+#define fits_modify_key_cmp ffmkyc
+#define fits_modify_key_fixdblcmp ffmkfm
+#define fits_modify_key_dblcmp ffmkym
+
+#define fits_insert_record ffirec
+#define fits_insert_card ffikey
+#define fits_insert_key_null ffikyu
+#define fits_insert_key_str ffikys
+#define fits_insert_key_longstr ffikls
+#define fits_insert_key_log ffikyl
+#define fits_insert_key_lng ffikyj
+#define fits_insert_key_fixflt ffikyf
+#define fits_insert_key_flt ffikye
+#define fits_insert_key_fixdbl ffikyg
+#define fits_insert_key_dbl ffikyd
+#define fits_insert_key_fixcmp ffikfc
+#define fits_insert_key_cmp ffikyc
+#define fits_insert_key_fixdblcmp ffikfm
+#define fits_insert_key_dblcmp ffikym
+
+#define fits_delete_key ffdkey
+#define fits_delete_record ffdrec
+#define fits_get_hdu_num ffghdn
+#define fits_get_hdu_type ffghdt
+#define fits_get_hduaddr ffghad
+#define fits_get_hduoff ffghof
+
+#define fits_get_img_param ffgipr
+#define fits_get_img_type ffgidt
+#define fits_get_img_equivtype ffgiet
+#define fits_get_img_dim ffgidm
+#define fits_get_img_size ffgisz
+
+#define fits_movabs_hdu ffmahd
+#define fits_movrel_hdu ffmrhd
+#define fits_movnam_hdu ffmnhd
+#define fits_get_num_hdus ffthdu
+#define fits_create_img ffcrim
+#define fits_create_tbl ffcrtb
+#define fits_create_hdu ffcrhd
+#define fits_insert_img ffiimg
+#define fits_insert_atbl ffitab
+#define fits_insert_btbl ffibin
+#define fits_resize_img ffrsim
+#define fits_delete_hdu ffdhdu
+#define fits_copy_hdu ffcopy
+#define fits_copy_file ffcpfl
+#define fits_copy_header ffcphd
+#define fits_copy_data ffcpdt
+
+#define fits_set_hdustruc ffrdef
+#define fits_set_hdrsize ffhdef
+#define fits_write_theap ffpthp
+
+#define fits_encode_chksum ffesum
+#define fits_decode_chksum ffdsum
+#define fits_write_chksum ffpcks
+#define fits_update_chksum ffupck
+#define fits_verify_chksum ffvcks
+#define fits_get_chksum ffgcks
+
+#define fits_set_bscale ffpscl
+#define fits_set_tscale fftscl
+#define fits_set_imgnull ffpnul
+#define fits_set_btblnull fftnul
+#define fits_set_atblnull ffsnul
+
+#define fits_get_colnum ffgcno
+#define fits_get_colname ffgcnn
+#define fits_get_coltype ffgtcl
+#define fits_get_eqcoltype ffeqty
+#define fits_get_num_rows ffgnrw
+#define fits_get_num_cols ffgncl
+#define fits_get_acolparms ffgacl
+#define fits_get_bcolparms ffgbcl
+
+#define fits_iterate_data ffiter
+
+#define fits_read_grppar_byt ffggpb
+#define fits_read_grppar_sbyt ffggpsb
+#define fits_read_grppar_usht ffggpui
+#define fits_read_grppar_ulng ffggpuj
+#define fits_read_grppar_sht ffggpi
+#define fits_read_grppar_lng ffggpj
+#define fits_read_grppar_lnglng ffggpjj
+#define fits_read_grppar_int ffggpk
+#define fits_read_grppar_uint ffggpuk
+#define fits_read_grppar_flt ffggpe
+#define fits_read_grppar_dbl ffggpd
+
+#define fits_read_pix ffgpxv
+#define fits_read_pixnull ffgpxf
+#define fits_read_img ffgpv
+#define fits_read_imgnull ffgpf
+#define fits_read_img_byt ffgpvb
+#define fits_read_img_sbyt ffgpvsb
+#define fits_read_img_usht ffgpvui
+#define fits_read_img_ulng ffgpvuj
+#define fits_read_img_sht ffgpvi
+#define fits_read_img_lng ffgpvj
+#define fits_read_img_lnglng ffgpvjj
+#define fits_read_img_uint ffgpvuk
+#define fits_read_img_int ffgpvk
+#define fits_read_img_flt ffgpve
+#define fits_read_img_dbl ffgpvd
+
+#define fits_read_imgnull_byt ffgpfb
+#define fits_read_imgnull_sbyt ffgpfsb
+#define fits_read_imgnull_usht ffgpfui
+#define fits_read_imgnull_ulng ffgpfuj
+#define fits_read_imgnull_sht ffgpfi
+#define fits_read_imgnull_lng ffgpfj
+#define fits_read_imgnull_lnglng ffgpfjj
+#define fits_read_imgnull_uint ffgpfuk
+#define fits_read_imgnull_int ffgpfk
+#define fits_read_imgnull_flt ffgpfe
+#define fits_read_imgnull_dbl ffgpfd
+
+#define fits_read_2d_byt ffg2db
+#define fits_read_2d_sbyt ffg2dsb
+#define fits_read_2d_usht ffg2dui
+#define fits_read_2d_ulng ffg2duj
+#define fits_read_2d_sht ffg2di
+#define fits_read_2d_lng ffg2dj
+#define fits_read_2d_lnglng ffg2djj
+#define fits_read_2d_uint ffg2duk
+#define fits_read_2d_int ffg2dk
+#define fits_read_2d_flt ffg2de
+#define fits_read_2d_dbl ffg2dd
+
+#define fits_read_3d_byt ffg3db
+#define fits_read_3d_sbyt ffg3dsb
+#define fits_read_3d_usht ffg3dui
+#define fits_read_3d_ulng ffg3duj
+#define fits_read_3d_sht ffg3di
+#define fits_read_3d_lng ffg3dj
+#define fits_read_3d_lnglng ffg3djj
+#define fits_read_3d_uint ffg3duk
+#define fits_read_3d_int ffg3dk
+#define fits_read_3d_flt ffg3de
+#define fits_read_3d_dbl ffg3dd
+
+#define fits_read_subset ffgsv
+#define fits_read_subset_byt ffgsvb
+#define fits_read_subset_sbyt ffgsvsb
+#define fits_read_subset_usht ffgsvui
+#define fits_read_subset_ulng ffgsvuj
+#define fits_read_subset_sht ffgsvi
+#define fits_read_subset_lng ffgsvj
+#define fits_read_subset_lnglng ffgsvjj
+#define fits_read_subset_uint ffgsvuk
+#define fits_read_subset_int ffgsvk
+#define fits_read_subset_flt ffgsve
+#define fits_read_subset_dbl ffgsvd
+
+#define fits_read_subsetnull_byt ffgsfb
+#define fits_read_subsetnull_sbyt ffgsfsb
+#define fits_read_subsetnull_usht ffgsfui
+#define fits_read_subsetnull_ulng ffgsfuj
+#define fits_read_subsetnull_sht ffgsfi
+#define fits_read_subsetnull_lng ffgsfj
+#define fits_read_subsetnull_lnglng ffgsfjj
+#define fits_read_subsetnull_uint ffgsfuk
+#define fits_read_subsetnull_int ffgsfk
+#define fits_read_subsetnull_flt ffgsfe
+#define fits_read_subsetnull_dbl ffgsfd
+
+#define fits_compress_img fits_comp_img
+#define fits_decompress_img fits_decomp_img
+
+#define fits_read_col ffgcv
+#define fits_read_colnull ffgcf
+#define fits_read_col_str ffgcvs
+#define fits_read_col_log ffgcvl
+#define fits_read_col_byt ffgcvb
+#define fits_read_col_sbyt ffgcvsb
+#define fits_read_col_usht ffgcvui
+#define fits_read_col_ulng ffgcvuj
+#define fits_read_col_sht ffgcvi
+#define fits_read_col_lng ffgcvj
+#define fits_read_col_lnglng ffgcvjj
+#define fits_read_col_uint ffgcvuk
+#define fits_read_col_int ffgcvk
+#define fits_read_col_flt ffgcve
+#define fits_read_col_dbl ffgcvd
+#define fits_read_col_cmp ffgcvc
+#define fits_read_col_dblcmp ffgcvm
+#define fits_read_col_bit ffgcx
+#define fits_read_col_bit_usht ffgcxui
+#define fits_read_col_bit_uint ffgcxuk
+
+#define fits_read_colnull_str ffgcfs
+#define fits_read_colnull_log ffgcfl
+#define fits_read_colnull_byt ffgcfb
+#define fits_read_colnull_sbyt ffgcfsb
+#define fits_read_colnull_usht ffgcfui
+#define fits_read_colnull_ulng ffgcfuj
+#define fits_read_colnull_sht ffgcfi
+#define fits_read_colnull_lng ffgcfj
+#define fits_read_colnull_lnglng ffgcfjj
+#define fits_read_colnull_uint ffgcfuk
+#define fits_read_colnull_int ffgcfk
+#define fits_read_colnull_flt ffgcfe
+#define fits_read_colnull_dbl ffgcfd
+#define fits_read_colnull_cmp ffgcfc
+#define fits_read_colnull_dblcmp ffgcfm
+
+#define fits_read_descript ffgdes
+#define fits_read_descripts ffgdess
+#define fits_read_tblbytes ffgtbb
+
+#define fits_write_grppar_byt ffpgpb
+#define fits_write_grppar_sbyt ffpgpsb
+#define fits_write_grppar_usht ffpgpui
+#define fits_write_grppar_ulng ffpgpuj
+#define fits_write_grppar_sht ffpgpi
+#define fits_write_grppar_lng ffpgpj
+#define fits_write_grppar_lnglng ffpgpjj
+#define fits_write_grppar_uint ffpgpuk
+#define fits_write_grppar_int ffpgpk
+#define fits_write_grppar_flt ffpgpe
+#define fits_write_grppar_dbl ffpgpd
+
+#define fits_write_pix ffppx
+#define fits_write_pixnull ffppxn
+#define fits_write_img ffppr
+#define fits_write_img_byt ffpprb
+#define fits_write_img_sbyt ffpprsb
+#define fits_write_img_usht ffpprui
+#define fits_write_img_ulng ffppruj
+#define fits_write_img_sht ffppri
+#define fits_write_img_lng ffpprj
+#define fits_write_img_lnglng ffpprjj
+#define fits_write_img_uint ffppruk
+#define fits_write_img_int ffpprk
+#define fits_write_img_flt ffppre
+#define fits_write_img_dbl ffpprd
+
+#define fits_write_imgnull ffppn
+#define fits_write_imgnull_byt ffppnb
+#define fits_write_imgnull_sbyt ffppnsb
+#define fits_write_imgnull_usht ffppnui
+#define fits_write_imgnull_ulng ffppnuj
+#define fits_write_imgnull_sht ffppni
+#define fits_write_imgnull_lng ffppnj
+#define fits_write_imgnull_lnglng ffppnjj
+#define fits_write_imgnull_uint ffppnuk
+#define fits_write_imgnull_int ffppnk
+#define fits_write_imgnull_flt ffppne
+#define fits_write_imgnull_dbl ffppnd
+
+#define fits_write_img_null ffppru
+#define fits_write_null_img ffpprn
+
+#define fits_write_2d_byt ffp2db
+#define fits_write_2d_sbyt ffp2dsb
+#define fits_write_2d_usht ffp2dui
+#define fits_write_2d_ulng ffp2duj
+#define fits_write_2d_sht ffp2di
+#define fits_write_2d_lng ffp2dj
+#define fits_write_2d_lnglng ffp2djj
+#define fits_write_2d_uint ffp2duk
+#define fits_write_2d_int ffp2dk
+#define fits_write_2d_flt ffp2de
+#define fits_write_2d_dbl ffp2dd
+
+#define fits_write_3d_byt ffp3db
+#define fits_write_3d_sbyt ffp3dsb
+#define fits_write_3d_usht ffp3dui
+#define fits_write_3d_ulng ffp3duj
+#define fits_write_3d_sht ffp3di
+#define fits_write_3d_lng ffp3dj
+#define fits_write_3d_lnglng ffp3djj
+#define fits_write_3d_uint ffp3duk
+#define fits_write_3d_int ffp3dk
+#define fits_write_3d_flt ffp3de
+#define fits_write_3d_dbl ffp3dd
+
+#define fits_write_subset ffpss
+#define fits_write_subset_byt ffpssb
+#define fits_write_subset_sbyt ffpsssb
+#define fits_write_subset_usht ffpssui
+#define fits_write_subset_ulng ffpssuj
+#define fits_write_subset_sht ffpssi
+#define fits_write_subset_lng ffpssj
+#define fits_write_subset_lnglng ffpssjj
+#define fits_write_subset_uint ffpssuk
+#define fits_write_subset_int ffpssk
+#define fits_write_subset_flt ffpsse
+#define fits_write_subset_dbl ffpssd
+
+#define fits_write_col ffpcl
+#define fits_write_col_str ffpcls
+#define fits_write_col_log ffpcll
+#define fits_write_col_byt ffpclb
+#define fits_write_col_sbyt ffpclsb
+#define fits_write_col_usht ffpclui
+#define fits_write_col_ulng ffpcluj
+#define fits_write_col_sht ffpcli
+#define fits_write_col_lng ffpclj
+#define fits_write_col_lnglng ffpcljj
+#define fits_write_col_uint ffpcluk
+#define fits_write_col_int ffpclk
+#define fits_write_col_flt ffpcle
+#define fits_write_col_dbl ffpcld
+#define fits_write_col_cmp ffpclc
+#define fits_write_col_dblcmp ffpclm
+#define fits_write_col_null ffpclu
+#define fits_write_col_bit ffpclx
+
+#define fits_write_colnull ffpcn
+#define fits_write_colnull_str ffpcns
+#define fits_write_colnull_log ffpcnl
+#define fits_write_colnull_byt ffpcnb
+#define fits_write_colnull_sbyt ffpcnsb
+#define fits_write_colnull_usht ffpcnui
+#define fits_write_colnull_ulng ffpcnuj
+#define fits_write_colnull_sht ffpcni
+#define fits_write_colnull_lng ffpcnj
+#define fits_write_colnull_lnglng ffpcnjj
+#define fits_write_colnull_uint ffpcnuk
+#define fits_write_colnull_int ffpcnk
+#define fits_write_colnull_flt ffpcne
+#define fits_write_colnull_dbl ffpcnd
+
+#define fits_write_descript ffpdes
+#define fits_compress_heap ffcmph
+#define fits_test_heap fftheap
+
+#define fits_write_tblbytes ffptbb
+#define fits_insert_rows ffirow
+#define fits_delete_rows ffdrow
+#define fits_delete_rowrange ffdrrg
+#define fits_delete_rowlist ffdrws
+#define fits_insert_col fficol
+#define fits_insert_cols fficls
+#define fits_delete_col ffdcol
+#define fits_copy_col ffcpcl
+#define fits_modify_vector_len ffmvec
+
+#define fits_read_img_coord ffgics
+#define fits_read_tbl_coord ffgtcs
+#define fits_pix_to_world ffwldp
+#define fits_world_to_pix ffxypx
+
+#define fits_get_image_wcs_keys ffgiwcs
+#define fits_get_table_wcs_keys ffgtwcs
+
+#define fits_find_rows fffrow
+#define fits_find_first_row ffffrw
+#define fits_find_rows_cmp fffrwc
+#define fits_select_rows ffsrow
+#define fits_calc_rows ffcrow
+#define fits_calculator ffcalc
+#define fits_calculator_rng ffcalc_rng
+#define fits_test_expr fftexp
+
+#define fits_create_group ffgtcr
+#define fits_insert_group ffgtis
+#define fits_change_group ffgtch
+#define fits_remove_group ffgtrm
+#define fits_copy_group ffgtcp
+#define fits_merge_groups ffgtmg
+#define fits_compact_group ffgtcm
+#define fits_verify_group ffgtvf
+#define fits_open_group ffgtop
+#define fits_add_group_member ffgtam
+#define fits_get_num_members ffgtnm
+
+#define fits_get_num_groups ffgmng
+#define fits_open_member ffgmop
+#define fits_copy_member ffgmcp
+#define fits_transfer_member ffgmtf
+#define fits_remove_member ffgmrm
+
+#endif
diff --git a/pkg/tbtables/cfitsio/make_dfloat.com b/pkg/tbtables/cfitsio/make_dfloat.com
new file mode 100644
index 00000000..eb12ce9a
--- /dev/null
+++ b/pkg/tbtables/cfitsio/make_dfloat.com
@@ -0,0 +1,83 @@
+$ ! Command file to build the CFITSIO library on a VMS systems (VAX or Alpha)
+$ set verify
+$ cc/float=d_float buffers.c
+$ cc/float=d_float cfileio.c
+$ cc/float=d_float checksum.c
+$ cc/float=d_float compress.c
+$ cc/float=d_float drvrfile.c
+$ cc/float=d_float drvrmem.c
+$ ! cc/float=d_float drvrnet.c not currently supported on VMS
+$ ! cc/float=d_float drvsmem.c not currently supported on VMS
+$ cc/float=d_float editcol.c
+$ cc/float=d_float edithdu.c
+$ cc/float=d_float eval_f.c
+$ cc/float=d_float eval_l.c
+$ cc/float=d_float eval_y.c
+$ cc/float=d_float fitscore.c
+$ cc/float=d_float f77_wrap1.c
+$ cc/float=d_float f77_wrap2.c
+$ cc/float=d_float getcol.c
+$ cc/float=d_float getcolb.c
+$ cc/float=d_float getcoli.c
+$ cc/float=d_float getcolj.c
+$ cc/float=d_float getcolui.c
+$ cc/float=d_float getcoluj.c
+$ cc/float=d_float getcoluk.c
+$ cc/float=d_float getcolk.c
+$ cc/float=d_float getcole.c
+$ cc/float=d_float getcold.c
+$ cc/float=d_float getcoll.c
+$ cc/float=d_float getcols.c
+$ cc/float=d_float getkey.c
+$ cc/float=d_float group.c
+$ cc/float=d_float grparser.c
+$ cc/float=d_float histo.c
+$ cc/float=d_float iraffits.c
+$ cc/float=d_float modkey.c
+$ cc/float=d_float putcol.c
+$ cc/float=d_float putcolb.c
+$ cc/float=d_float putcoli.c
+$ cc/float=d_float putcolj.c
+$ cc/float=d_float putcolk.c
+$ cc/float=d_float putcolui.c
+$ cc/float=d_float putcoluj.c
+$ cc/float=d_float putcoluk.c
+$ cc/float=d_float putcole.c
+$ cc/float=d_float putcold.c
+$ cc/float=d_float putcols.c
+$ cc/float=d_float putcoll.c
+$ cc/float=d_float putcolu.c
+$ cc/float=d_float putkey.c
+$ cc/float=d_float region.c
+$ cc/float=d_float scalnull.c
+$ cc/float=d_float swapproc.c
+$ cc/float=d_float wcsutil.c
+$ cc/float=d_float wcssub.c
+$ cc/float=d_float imcompress.c
+$ cc/float=d_float quantize.c
+$ cc/float=d_float ricecomp.c
+$ cc/float=d_float pliocomp.c
+$ lib/create cfitsio buffers,cfileio,checksum,compress,drvrfile,drvrmem
+$ lib/insert cfitsio editcol,edithdu,eval_f,eval_l,eval_y,f77_wrap1,f77_wrap2
+$ lib/insert cfitsio fitscore,getcol,getcolb,getcoli,getcolj,getcolk,getcole
+$ lib/insert cfitsio getcold,getcoll,getcols,getcolui,getcoluj,getcoluk
+$ lib/insert cfitsio getkey,group,grparser,histo,iraffits,modkey,putcol,putcolb
+$ lib/insert cfitsio putcoli,putcolj,putcolk,putcole,putcold,putcolui
+$ lib/insert cfitsio putcoluj,putcoluk,putcols,putcoll,putcolu,putkey,region
+$ lib/insert cfitsio scalnull,swapproc,wcsutil,wcssub
+$ lib/insert cfitsio imcompress,quantize,ricecomp,pliocomp
+$ !
+$ if (F$GETSYI("ARCH_NAME") .eqs. "VAX") then goto VAX
+$ ! add C routine needed on Alpha to do D_FLOAT conversions
+$ cc/float=d_float vmsieee.c
+$ lib/insert cfitsio vmsieee
+$ set noverify
+$ exit
+$ !
+$ VAX:
+$ ! add macro routines not needed on Alpha and only used on VAX
+$ macro vmsieeer.mar
+$ macro vmsieeed.mar
+$ lib/insert cfitsio vmsieeer,vmsieeed
+$ set noverify
+$ exit
diff --git a/pkg/tbtables/cfitsio/make_gfloat.com b/pkg/tbtables/cfitsio/make_gfloat.com
new file mode 100644
index 00000000..b0d07bab
--- /dev/null
+++ b/pkg/tbtables/cfitsio/make_gfloat.com
@@ -0,0 +1,81 @@
+$ ! Command file to build the CFITSIO library on a VMS systems (VAX or Alpha)
+$ ! This uses the default /float=G_FLOAT option on the Alpha
+$ set verify
+$ cc buffers.c
+$ cc cfileio.c
+$ cc checksum.c
+$ cc compress.c
+$ cc drvrfile.c
+$ cc drvrmem.c
+$ ! cc drvrnet.c not currently supported on VMS
+$ ! cc drvsmem.c not currently supported on VMS
+$ cc editcol.c
+$ cc edithdu.c
+$ cc eval_f.c
+$ cc eval_l.c
+$ cc eval_y.c
+$ cc fitscore.c
+$ cc f77_wrap1.c
+$ cc f77_wrap2.c
+$ cc getcol.c
+$ cc getcolb.c
+$ cc getcoli.c
+$ cc getcolj.c
+$ cc getcolui.c
+$ cc getcoluj.c
+$ cc getcoluk.c
+$ cc getcolk.c
+$ cc getcole.c
+$ cc getcold.c
+$ cc getcoll.c
+$ cc getcols.c
+$ cc getkey.c
+$ cc group.c
+$ cc grparser.c
+$ cc histo.c
+$ cc iraffits.c
+$ cc modkey.c
+$ cc putcol.c
+$ cc putcolb.c
+$ cc putcoli.c
+$ cc putcolj.c
+$ cc putcolk.c
+$ cc putcolui.c
+$ cc putcoluj.c
+$ cc putcoluk.c
+$ cc putcole.c
+$ cc putcold.c
+$ cc putcols.c
+$ cc putcoll.c
+$ cc putcolu.c
+$ cc putkey.c
+$ cc region.c
+$ cc scalnull.c
+$ cc swapproc.c
+$ cc wcsutil.c
+$ cc wcssub.c
+$ cc imcompress.c
+$ cc quantize.c
+$ cc ricecomp.c
+$ cc pliocomp.c
+$ lib/create cfitsio buffers,cfileio,checksum,compress,drvrfile,drvrmem
+$ lib/insert cfitsio editcol,edithdu,eval_f,eval_l,eval_y,f77_wrap1,f77_wrap2
+$ lib/insert cfitsio fitscore,getcol,getcolb,getcoli,getcolj,getcolk,getcole
+$ lib/insert cfitsio getcold,getcoll,getcols,getcolui,getcoluj,getcoluk
+$ lib/insert cfitsio getkey,group,grparser,histo,iraffits,modkey,putcol,putcolb
+$ lib/insert cfitsio putcoli,putcolj,putcolk,putcole,putcold,putcolui
+$ lib/insert cfitsio putcoluj,putcoluk,putcols,putcoll,putcolu,putkey,region
+$ lib/insert cfitsio scalnull,swapproc,wcsutil,wcssub
+$ lib/insert cfitsio imcompress,quantize,ricecomp,pliocomp
+$ !
+$ if (F$GETSYI("ARCH_NAME") .eqs. "VAX") then goto VAX
+$ set noverify
+$ exit
+$ !
+$ VAX:
+$ ! add macro routines not needed on Alpha and only used on VAX
+$ macro vmsieeer.mar
+$ macro vmsieeed.mar
+$ lib/insert cfitsio vmsieeer,vmsieeed
+$ set noverify
+$ exit
diff --git a/pkg/tbtables/cfitsio/make_ieee.com b/pkg/tbtables/cfitsio/make_ieee.com
new file mode 100644
index 00000000..f4c5f1d8
--- /dev/null
+++ b/pkg/tbtables/cfitsio/make_ieee.com
@@ -0,0 +1,80 @@
+$ ! Command file to build the CFITSIO library on a VMS systems (VAX or Alpha)
+$ set verify
+$ cc/float=ieee_float buffers.c
+$ cc/float=ieee_float cfileio.c
+$ cc/float=ieee_float checksum.c
+$ cc/float=ieee_float compress.c
+$ cc/float=ieee_float drvrfile.c
+$ cc/float=ieee_float drvrmem.c
+$ ! cc/float=ieee_float drvrnet.c not currently supported on VMS
+$ ! cc/float=ieee_float drvsmem.c not currently supported on VMS
+$ cc/float=ieee_float editcol.c
+$ cc/float=ieee_float edithdu.c
+$ cc/float=ieee_float eval_f.c
+$ cc/float=ieee_float eval_l.c
+$ cc/float=ieee_float eval_y.c
+$ cc/float=ieee_float fitscore.c
+$ cc/float=ieee_float f77_wrap1.c
+$ cc/float=ieee_float f77_wrap2.c
+$ cc/float=ieee_float getcol.c
+$ cc/float=ieee_float getcolb.c
+$ cc/float=ieee_float getcoli.c
+$ cc/float=ieee_float getcolj.c
+$ cc/float=ieee_float getcolui.c
+$ cc/float=ieee_float getcoluj.c
+$ cc/float=ieee_float getcoluk.c
+$ cc/float=ieee_float getcolk.c
+$ cc/float=ieee_float getcole.c
+$ cc/float=ieee_float getcold.c
+$ cc/float=ieee_float getcoll.c
+$ cc/float=ieee_float getcols.c
+$ cc/float=ieee_float getkey.c
+$ cc/float=ieee_float group.c
+$ cc/float=ieee_float grparser.c
+$ cc/float=ieee_float histo.c
+$ cc/float=ieee_float iraffits.c
+$ cc/float=ieee_float modkey.c
+$ cc/float=ieee_float putcol.c
+$ cc/float=ieee_float putcolb.c
+$ cc/float=ieee_float putcoli.c
+$ cc/float=ieee_float putcolj.c
+$ cc/float=ieee_float putcolk.c
+$ cc/float=ieee_float putcolui.c
+$ cc/float=ieee_float putcoluj.c
+$ cc/float=ieee_float putcoluk.c
+$ cc/float=ieee_float putcole.c
+$ cc/float=ieee_float putcold.c
+$ cc/float=ieee_float putcols.c
+$ cc/float=ieee_float putcoll.c
+$ cc/float=ieee_float putcolu.c
+$ cc/float=ieee_float putkey.c
+$ cc/float=ieee_float region.c
+$ cc/float=ieee_float scalnull.c
+$ cc/float=ieee_float swapproc.c
+$ cc/float=ieee_float wcsutil.c
+$ cc/float=ieee_float wcssub.c
+$ cc/float=ieee_float imcompress.c
+$ cc/float=ieee_float quantize.c
+$ cc/float=ieee_float ricecomp.c
+$ cc/float=ieee_float pliocomp.c
+$ lib/create cfitsio buffers,cfileio,checksum,compress,drvrfile,drvrmem
+$ lib/insert cfitsio editcol,edithdu,eval_f,eval_l,eval_y,f77_wrap1,f77_wrap2
+$ lib/insert cfitsio fitscore,getcol,getcolb,getcoli,getcolj,getcolk,getcole
+$ lib/insert cfitsio getcold,getcoll,getcols,getcolui,getcoluj,getcoluk
+$ lib/insert cfitsio getkey,group,grparser,histo,iraffits,modkey,putcol,putcolb
+$ lib/insert cfitsio putcoli,putcolj,putcolk,putcole,putcold,putcolui
+$ lib/insert cfitsio putcoluj,putcoluk,putcols,putcoll,putcolu,putkey,region
+$ lib/insert cfitsio scalnull,swapproc,wcsutil,wcssub
+$ lib/insert cfitsio imcompress,quantize,ricecomp,pliocomp
+$ !
+$ if (F$GETSYI("ARCH_NAME") .eqs. "VAX") then goto VAX
+$ set noverify
+$ exit
+$ !
+$ VAX:
+$ ! add macro routines not needed on Alpha and only used on VAX
+$ macro vmsieeer.mar
+$ macro vmsieeed.mar
+$ lib/insert cfitsio vmsieeer,vmsieeed
+$ set noverify
+$ exit
diff --git a/pkg/tbtables/cfitsio/makefile.bc b/pkg/tbtables/cfitsio/makefile.bc
new file mode 100644
index 00000000..d8fa69ec
--- /dev/null
+++ b/pkg/tbtables/cfitsio/makefile.bc
@@ -0,0 +1,496 @@
+#
+# Borland C++ IDE generated makefile
+# Generated 10/12/99 at 1:24:11 PM
+#
+.AUTODEPEND
+
+
+#
+# Borland C++ tools
+#
+IMPLIB = Implib
+BCC32 = Bcc32 +BccW32.cfg
+BCC32I = Bcc32i +BccW32.cfg
+TLINK32 = TLink32
+ILINK32 = Ilink32
+TLIB = TLib
+BRC32 = Brc32
+TASM32 = Tasm32
+#
+# IDE macros
+#
+
+
+#
+# Options
+#
+IDE_LinkFLAGS32 = -LD:\BC5\LIB
+LinkerLocalOptsAtC32_cfitsiodlib = -Tpd -ap -c
+ResLocalOptsAtC32_cfitsiodlib =
+BLocalOptsAtC32_cfitsiodlib =
+CompInheritOptsAt_cfitsiodlib = -ID:\BC5\INCLUDE -D_RTLDLL -DWIN32;
+LinkerInheritOptsAt_cfitsiodlib = -x
+LinkerOptsAt_cfitsiodlib = $(LinkerLocalOptsAtC32_cfitsiodlib)
+ResOptsAt_cfitsiodlib = $(ResLocalOptsAtC32_cfitsiodlib)
+BOptsAt_cfitsiodlib = $(BLocalOptsAtC32_cfitsiodlib)
+
+#
+# Dependency List
+#
+Dep_cfitsio = \
+ cfitsio.lib
+
+cfitsio : BccW32.cfg $(Dep_cfitsio)
+ echo MakeNode
+
+cfitsio.lib : cfitsio.dll
+ $(IMPLIB) $@ cfitsio.dll
+
+
+Dep_cfitsioddll = \
+ listhead.obj\
+ imcompress.obj\
+ quantize.obj\
+ ricecomp.obj\
+ pliocomp.obj\
+ iraffits.obj\
+ wcsutil.obj\
+ histo.obj\
+ scalnull.obj\
+ region.obj\
+ putkey.obj\
+ putcoluk.obj\
+ putcoluj.obj\
+ putcolui.obj\
+ putcolu.obj\
+ putcols.obj\
+ putcoll.obj\
+ putcolk.obj\
+ putcolj.obj\
+ putcoli.obj\
+ putcole.obj\
+ putcold.obj\
+ putcolb.obj\
+ putcolsb.obj\
+ putcol.obj\
+ modkey.obj\
+ swapproc.obj\
+ getcol.obj\
+ group.obj\
+ getkey.obj\
+ getcoluk.obj\
+ getcoluj.obj\
+ getcolui.obj\
+ getcols.obj\
+ getcoll.obj\
+ getcolk.obj\
+ getcolj.obj\
+ getcoli.obj\
+ getcole.obj\
+ getcold.obj\
+ getcolb.obj\
+ getcolsb.obj\
+ grparser.obj\
+ fitscore.obj\
+ f77_wrap1.obj\
+ f77_wrap2.obj\
+ f77_wrap3.obj\
+ f77_wrap4.obj\
+ eval_y.obj\
+ eval_l.obj\
+ eval_f.obj\
+ edithdu.obj\
+ editcol.obj\
+ drvrmem.obj\
+ drvrfile.obj\
+ compress.obj\
+ checksum.obj\
+ cfileio.obj\
+ buffers.obj
+
+cfitsio.dll : $(Dep_cfitsioddll) cfitsio.def
+ $(ILINK32) @&&|
+ /v $(IDE_LinkFLAGS32) $(LinkerOptsAt_cfitsiodlib) $(LinkerInheritOptsAt_cfitsiodlib) +
+D:\BC5\LIB\c0d32.obj+
+listhead.obj+
+imcompress.obj+
+quantize.obj+
+ricecomp.obj+
+pliocomp.obj+
+iraffits.obj+
+wcsutil.obj+
+histo.obj+
+iraffits.obj+
+scalnull.obj+
+region.obj+
+putkey.obj+
+putcoluk.obj+
+putcoluj.obj+
+putcolui.obj+
+putcolu.obj+
+putcols.obj+
+putcoll.obj+
+putcolk.obj+
+putcolj.obj+
+putcoli.obj+
+putcole.obj+
+putcold.obj+
+putcolb.obj+
+putcolsb.obj+
+putcol.obj+
+modkey.obj+
+swapproc.obj+
+getcol.obj+
+group.obj+
+getkey.obj+
+getcoluk.obj+
+getcoluj.obj+
+getcolui.obj+
+getcols.obj+
+getcoll.obj+
+getcolk.obj+
+getcolj.obj+
+getcoli.obj+
+getcole.obj+
+getcold.obj+
+getcolb.obj+
+getcolsb.obj+
+grparser.obj+
+fitscore.obj+
+f77_wrap1.obj+
+f77_wrap2.obj+
+f77_wrap3.obj+
+f77_wrap4.obj+
+eval_y.obj+
+eval_l.obj+
+eval_f.obj+
+edithdu.obj+
+editcol.obj+
+drvrmem.obj+
+drvrfile.obj+
+compress.obj+
+checksum.obj+
+cfileio.obj+
+buffers.obj
+$<,$*
+D:\BC5\LIB\import32.lib+
+D:\BC5\LIB\cw32i.lib
+cfitsio.def
+
+
+|
+wcsutil.obj : wcsutil.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ wcsutil.c
+|
+iraffits.obj : iraffits.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ iraffits.c
+|
+histo.obj : histo.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ histo.c
+|
+
+scalnull.obj : scalnull.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ scalnull.c
+|
+
+region.obj : region.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ region.c
+|
+
+putkey.obj : putkey.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ putkey.c
+|
+
+putcoluk.obj : putcoluk.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ putcoluk.c
+|
+
+putcoluj.obj : putcoluj.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ putcoluj.c
+|
+
+putcolui.obj : putcolui.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ putcolui.c
+|
+
+putcolu.obj : putcolu.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ putcolu.c
+|
+
+putcols.obj : putcols.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ putcols.c
+|
+
+putcoll.obj : putcoll.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ putcoll.c
+|
+
+putcolk.obj : putcolk.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ putcolk.c
+|
+
+putcolj.obj : putcolj.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ putcolj.c
+|
+
+putcoli.obj : putcoli.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ putcoli.c
+|
+
+putcole.obj : putcole.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ putcole.c
+|
+
+putcold.obj : putcold.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ putcold.c
+|
+
+putcolb.obj : putcolb.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ putcolb.c
+|
+
+putcolsb.obj : putcolsb.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ putcolsb.c
+|
+
+putcol.obj : putcol.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ putcol.c
+|
+
+modkey.obj : modkey.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ modkey.c
+|
+
+swapproc.obj : swapproc.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ swapproc.c
+|
+
+getcol.obj : getcol.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ getcol.c
+|
+
+group.obj : group.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ group.c
+|
+
+getkey.obj : getkey.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ getkey.c
+|
+
+getcoluk.obj : getcoluk.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ getcoluk.c
+|
+
+getcoluj.obj : getcoluj.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ getcoluj.c
+|
+
+getcolui.obj : getcolui.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ getcolui.c
+|
+
+getcols.obj : getcols.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ getcols.c
+|
+
+getcoll.obj : getcoll.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ getcoll.c
+|
+
+getcolk.obj : getcolk.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ getcolk.c
+|
+
+getcolj.obj : getcolj.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ getcolj.c
+|
+
+getcoli.obj : getcoli.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ getcoli.c
+|
+
+getcole.obj : getcole.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ getcole.c
+|
+
+getcold.obj : getcold.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ getcold.c
+|
+
+getcolb.obj : getcolb.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ getcolb.c
+|
+getcolsb.obj : getcolsb.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ getcolsb.c
+|
+
+grparser.obj : grparser.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ grparser.c
+|
+
+fitscore.obj : fitscore.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ fitscore.c
+|
+
+f77_wrap1.obj : f77_wrap1.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ f77_wrap1.c
+|
+
+f77_wrap2.obj : f77_wrap2.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ f77_wrap2.c
+|
+
+f77_wrap3.obj : f77_wrap3.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ f77_wrap3.c
+|
+
+f77_wrap4.obj : f77_wrap4.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ f77_wrap4.c
+|
+
+eval_y.obj : eval_y.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ eval_y.c
+|
+
+eval_l.obj : eval_l.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ eval_l.c
+|
+
+eval_f.obj : eval_f.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ eval_f.c
+|
+
+edithdu.obj : edithdu.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ edithdu.c
+|
+
+editcol.obj : editcol.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ editcol.c
+|
+
+drvrmem.obj : drvrmem.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ drvrmem.c
+|
+
+drvrfile.obj : drvrfile.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ drvrfile.c
+|
+
+compress.obj : compress.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ compress.c
+|
+
+checksum.obj : checksum.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ checksum.c
+|
+
+cfileio.obj : cfileio.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ cfileio.c
+|
+
+listhead.obj : listhead.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ listhead.c
+|
+
+imcompress.obj : imcompress.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ imcompress.c
+|
+
+quantize.obj : quantize.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ quantize.c
+|
+
+ricecomp.obj : ricecomp.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ ricecomp.c
+|
+
+pliocomp.obj : pliocomp.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ pliocomp.c
+|
+
+buffers.obj : buffers.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ buffers.c
+|
+
+windumpexts.exe : windumpexts.c
+ bcc32 windumpexts.c
+
+
+cfitsio.def: windumpexts.exe
+ windumpexts -o cfitsio.def cfitsio.dll @&&|
+ $(Dep_cfitsioddll)
+|
+
+# Compiler configuration file
+BccW32.cfg :
+ Copy &&|
+-w
+-R
+-v
+-WM-
+-vi
+-H
+-H=cfitsio.csm
+-WCD
+| $@
+
+
diff --git a/pkg/tbtables/cfitsio/makefile.os2 b/pkg/tbtables/cfitsio/makefile.os2
new file mode 100644
index 00000000..0d795542
--- /dev/null
+++ b/pkg/tbtables/cfitsio/makefile.os2
@@ -0,0 +1,22 @@
+#
+# To be use with OS/2 and GCC/EMX Compiler.
+# Submitted by Andrea Di Paola (dipaola@coma.mporzio.astro.it)
+# June 1997
+#
+# Makefile for cfitsio library:
+# libcfits.a
+#
+
+CFLAGS= -m486 -O3 -c
+CC=gcc
+
+OBJECTS = buffers.o cfileio.o checksum.o compress.o f77_wrap.o drvrfile.o fitscore.o \
+ getcol.o getcolb.o getcold.o getcole.o getcoli.o getcolj.o \
+ getcolk.o getcoll.o getcols.o getcolui.o getcoluj.o editcol.o \
+ edithdu.o getkey.o modkey.o putcol.o putcolb.o putcold.o putcole.o \
+ putcoli.o putcolj.o putcolk.o putcoll.o putcols.o putcolui.o \
+ putcoluj.o putcolu.o putkey.o scalnull.o swapproc.o wcsutil.o \
+ imcompress.o quantize.o ricecomp.o pliocomp.o
+
+libcfitsio.a: $(OBJECTS)
+ ar rv libcfitsio.a $(OBJECTS)
diff --git a/pkg/tbtables/cfitsio/makefile.vcc b/pkg/tbtables/cfitsio/makefile.vcc
new file mode 100644
index 00000000..42df7ffe
--- /dev/null
+++ b/pkg/tbtables/cfitsio/makefile.vcc
@@ -0,0 +1,691 @@
+# Microsoft Developer Studio Generated NMAKE File, Based on cfitsio.dsp
+!IF "$(CFG)" == ""
+CFG=cfitsio - Win32 Release
+!MESSAGE No configuration specified. Defaulting to cfitsio - Win32 Release.
+!ENDIF
+
+!IF "$(CFG)" != "cfitsio - Win32 Release" && "$(CFG)" != "cfitsio - Win32 Debug"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "cfitsio.mak" CFG="cfitsio - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "cfitsio - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "cfitsio - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+!ERROR An invalid configuration is specified.
+!ENDIF
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "cfitsio - Win32 Release"
+
+OUTDIR=.
+INTDIR=.\Release
+# Begin Custom Macros
+OutDir=.
+# End Custom Macros
+
+ALL : "$(OUTDIR)\cfitsio.dll"
+
+
+CLEAN :
+ -@erase "$(INTDIR)\buffers.obj"
+ -@erase "$(INTDIR)\cfileio.obj"
+ -@erase "$(INTDIR)\checksum.obj"
+ -@erase "$(INTDIR)\compress.obj"
+ -@erase "$(INTDIR)\drvrfile.obj"
+ -@erase "$(INTDIR)\drvrmem.obj"
+ -@erase "$(INTDIR)\editcol.obj"
+ -@erase "$(INTDIR)\edithdu.obj"
+ -@erase "$(INTDIR)\eval_f.obj"
+ -@erase "$(INTDIR)\eval_l.obj"
+ -@erase "$(INTDIR)\eval_y.obj"
+ -@erase "$(INTDIR)\fitscore.obj"
+ -@erase "$(INTDIR)\f77_wrap1.obj"
+ -@erase "$(INTDIR)\f77_wrap2.obj"
+ -@erase "$(INTDIR)\f77_wrap3.obj"
+ -@erase "$(INTDIR)\f77_wrap4.obj"
+ -@erase "$(INTDIR)\getcol.obj"
+ -@erase "$(INTDIR)\getcolb.obj"
+ -@erase "$(INTDIR)\getcolsb.obj"
+ -@erase "$(INTDIR)\getcold.obj"
+ -@erase "$(INTDIR)\getcole.obj"
+ -@erase "$(INTDIR)\getcoli.obj"
+ -@erase "$(INTDIR)\getcolj.obj"
+ -@erase "$(INTDIR)\getcolk.obj"
+ -@erase "$(INTDIR)\getcoll.obj"
+ -@erase "$(INTDIR)\getcols.obj"
+ -@erase "$(INTDIR)\getcolui.obj"
+ -@erase "$(INTDIR)\getcoluj.obj"
+ -@erase "$(INTDIR)\getcoluk.obj"
+ -@erase "$(INTDIR)\getkey.obj"
+ -@erase "$(INTDIR)\group.obj"
+ -@erase "$(INTDIR)\grparser.obj"
+ -@erase "$(INTDIR)\histo.obj"
+ -@erase "$(INTDIR)\iraffits.obj"
+ -@erase "$(INTDIR)\modkey.obj"
+ -@erase "$(INTDIR)\putcol.obj"
+ -@erase "$(INTDIR)\putcolb.obj"
+ -@erase "$(INTDIR)\putcolsb.obj"
+ -@erase "$(INTDIR)\putcold.obj"
+ -@erase "$(INTDIR)\putcole.obj"
+ -@erase "$(INTDIR)\putcoli.obj"
+ -@erase "$(INTDIR)\putcolj.obj"
+ -@erase "$(INTDIR)\putcolk.obj"
+ -@erase "$(INTDIR)\putcoll.obj"
+ -@erase "$(INTDIR)\putcols.obj"
+ -@erase "$(INTDIR)\putcolu.obj"
+ -@erase "$(INTDIR)\putcolui.obj"
+ -@erase "$(INTDIR)\putcoluj.obj"
+ -@erase "$(INTDIR)\putcoluk.obj"
+ -@erase "$(INTDIR)\putkey.obj"
+ -@erase "$(INTDIR)\region.obj"
+ -@erase "$(INTDIR)\scalnull.obj"
+ -@erase "$(INTDIR)\swapproc.obj"
+ -@erase "$(INTDIR)\imcompress.obj"
+ -@erase "$(INTDIR)\ricecomp.obj"
+ -@erase "$(INTDIR)\quantize.obj"
+ -@erase "$(INTDIR)\pliocomp.obj"
+ -@erase "$(INTDIR)\vc60.idb"
+ -@erase "$(INTDIR)\wcssub.obj"
+ -@erase "$(INTDIR)\wcsutil.obj"
+ -@erase "$(OUTDIR)\cfitsio.dll"
+ -@erase "$(OUTDIR)\cfitsio.exp"
+ -@erase "$(OUTDIR)\cfitsio.lib"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+"$(INTDIR)" :
+ if not exist "$(INTDIR)/$(NULL)" mkdir "$(INTDIR)"
+
+CPP_PROJ=/nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "CFITSIO_EXPORTS" /Fp"$(INTDIR)\cfitsio.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
+MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\cfitsio.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /incremental:no /pdb:"$(OUTDIR)\cfitsio.pdb" /machine:I386 /def:".\cfitsio.def" /out:"$(OUTDIR)\cfitsio.dll" /implib:"$(OUTDIR)\cfitsio.lib"
+DEF_FILE= ".\cfitsio.def"
+LINK32_OBJS= \
+ "$(INTDIR)\buffers.obj" \
+ "$(INTDIR)\cfileio.obj" \
+ "$(INTDIR)\checksum.obj" \
+ "$(INTDIR)\compress.obj" \
+ "$(INTDIR)\drvrfile.obj" \
+ "$(INTDIR)\drvrmem.obj" \
+ "$(INTDIR)\editcol.obj" \
+ "$(INTDIR)\edithdu.obj" \
+ "$(INTDIR)\eval_f.obj" \
+ "$(INTDIR)\eval_l.obj" \
+ "$(INTDIR)\eval_y.obj" \
+ "$(INTDIR)\fitscore.obj" \
+ "$(INTDIR)\f77_wrap1.obj" \
+ "$(INTDIR)\f77_wrap2.obj" \
+ "$(INTDIR)\f77_wrap3.obj" \
+ "$(INTDIR)\f77_wrap4.obj" \
+ "$(INTDIR)\getcol.obj" \
+ "$(INTDIR)\getcolb.obj" \
+ "$(INTDIR)\getcolsb.obj" \
+ "$(INTDIR)\getcold.obj" \
+ "$(INTDIR)\getcole.obj" \
+ "$(INTDIR)\getcoli.obj" \
+ "$(INTDIR)\getcolj.obj" \
+ "$(INTDIR)\getcolk.obj" \
+ "$(INTDIR)\getcoll.obj" \
+ "$(INTDIR)\getcols.obj" \
+ "$(INTDIR)\getcolui.obj" \
+ "$(INTDIR)\getcoluj.obj" \
+ "$(INTDIR)\getcoluk.obj" \
+ "$(INTDIR)\getkey.obj" \
+ "$(INTDIR)\group.obj" \
+ "$(INTDIR)\grparser.obj" \
+ "$(INTDIR)\histo.obj" \
+ "$(INTDIR)\iraffits.obj" \
+ "$(INTDIR)\modkey.obj" \
+ "$(INTDIR)\putcol.obj" \
+ "$(INTDIR)\putcolb.obj" \
+ "$(INTDIR)\putcolsb.obj" \
+ "$(INTDIR)\putcold.obj" \
+ "$(INTDIR)\putcole.obj" \
+ "$(INTDIR)\putcoli.obj" \
+ "$(INTDIR)\putcolj.obj" \
+ "$(INTDIR)\putcolk.obj" \
+ "$(INTDIR)\putcoll.obj" \
+ "$(INTDIR)\putcols.obj" \
+ "$(INTDIR)\putcolu.obj" \
+ "$(INTDIR)\putcolui.obj" \
+ "$(INTDIR)\putcoluj.obj" \
+ "$(INTDIR)\putcoluk.obj" \
+ "$(INTDIR)\putkey.obj" \
+ "$(INTDIR)\region.obj" \
+ "$(INTDIR)\scalnull.obj" \
+ "$(INTDIR)\swapproc.obj" \
+ "$(INTDIR)\imcompress.obj" \
+ "$(INTDIR)\ricecomp.obj" \
+ "$(INTDIR)\quantize.obj" \
+ "$(INTDIR)\pliocomp.obj" \
+ "$(INTDIR)\wcssub.obj" \
+ "$(INTDIR)\wcsutil.obj"
+
+"$(OUTDIR)\cfitsio.dll" : $(LINK32_OBJS) WINDUMP
+ windumpexts -o $(DEF_FILE) cfitsio.dll $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ELSEIF "$(CFG)" == "cfitsio - Win32 Debug"
+
+OUTDIR=.
+INTDIR=.\Debug
+# Begin Custom Macros
+OutDir=.
+# End Custom Macros
+
+ALL : "$(OUTDIR)\cfitsio.dll"
+
+
+CLEAN :
+ -@erase "$(INTDIR)\buffers.obj"
+ -@erase "$(INTDIR)\cfileio.obj"
+ -@erase "$(INTDIR)\checksum.obj"
+ -@erase "$(INTDIR)\compress.obj"
+ -@erase "$(INTDIR)\drvrfile.obj"
+ -@erase "$(INTDIR)\drvrmem.obj"
+ -@erase "$(INTDIR)\editcol.obj"
+ -@erase "$(INTDIR)\edithdu.obj"
+ -@erase "$(INTDIR)\eval_f.obj"
+ -@erase "$(INTDIR)\eval_l.obj"
+ -@erase "$(INTDIR)\eval_y.obj"
+ -@erase "$(INTDIR)\fitscore.obj"
+ -@erase "$(INTDIR)\f77_wrap1.obj"
+ -@erase "$(INTDIR)\f77_wrap2.obj"
+ -@erase "$(INTDIR)\f77_wrap3.obj"
+ -@erase "$(INTDIR)\f77_wrap4.obj"
+ -@erase "$(INTDIR)\getcol.obj"
+ -@erase "$(INTDIR)\getcolb.obj"
+ -@erase "$(INTDIR)\getcolsb.obj"
+ -@erase "$(INTDIR)\getcold.obj"
+ -@erase "$(INTDIR)\getcole.obj"
+ -@erase "$(INTDIR)\getcoli.obj"
+ -@erase "$(INTDIR)\getcolj.obj"
+ -@erase "$(INTDIR)\getcolk.obj"
+ -@erase "$(INTDIR)\getcoll.obj"
+ -@erase "$(INTDIR)\getcols.obj"
+ -@erase "$(INTDIR)\getcolui.obj"
+ -@erase "$(INTDIR)\getcoluj.obj"
+ -@erase "$(INTDIR)\getcoluk.obj"
+ -@erase "$(INTDIR)\getkey.obj"
+ -@erase "$(INTDIR)\group.obj"
+ -@erase "$(INTDIR)\grparser.obj"
+ -@erase "$(INTDIR)\histo.obj"
+ -@erase "$(INTDIR)\iraffits.obj"
+ -@erase "$(INTDIR)\modkey.obj"
+ -@erase "$(INTDIR)\putcol.obj"
+ -@erase "$(INTDIR)\putcolb.obj"
+ -@erase "$(INTDIR)\putcolsb.obj"
+ -@erase "$(INTDIR)\putcold.obj"
+ -@erase "$(INTDIR)\putcole.obj"
+ -@erase "$(INTDIR)\putcoli.obj"
+ -@erase "$(INTDIR)\putcolj.obj"
+ -@erase "$(INTDIR)\putcolk.obj"
+ -@erase "$(INTDIR)\putcoll.obj"
+ -@erase "$(INTDIR)\putcols.obj"
+ -@erase "$(INTDIR)\putcolu.obj"
+ -@erase "$(INTDIR)\putcolui.obj"
+ -@erase "$(INTDIR)\putcoluj.obj"
+ -@erase "$(INTDIR)\putcoluk.obj"
+ -@erase "$(INTDIR)\putkey.obj"
+ -@erase "$(INTDIR)\region.obj"
+ -@erase "$(INTDIR)\scalnull.obj"
+ -@erase "$(INTDIR)\swapproc.obj"
+ -@erase "$(INTDIR)\vc60.idb"
+ -@erase "$(INTDIR)\vc60.pdb"
+ -@erase "$(INTDIR)\wcssub.obj"
+ -@erase "$(INTDIR)\wcsutil.obj"
+ -@erase "$(INTDIR)\imcompress.obj"
+ -@erase "$(INTDIR)\ricecomp.obj"
+ -@erase "$(INTDIR)\quantize.obj"
+ -@erase "$(INTDIR)\pliocomp.obj"
+ -@erase "$(OUTDIR)\cfitsio.dll"
+ -@erase "$(OUTDIR)\cfitsio.exp"
+ -@erase "$(OUTDIR)\cfitsio.ilk"
+ -@erase "$(OUTDIR)\cfitsio.lib"
+ -@erase "$(OUTDIR)\cfitsio.pdb"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+"$(INTDIR)" :
+ if not exist "$(INTDIR)/$(NULL)" mkdir "$(INTDIR)"
+
+CPP_PROJ=/nologo /MD /W3 /Gm /GX /ZI /Od /D "__WIN32__" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "CFITSIO_EXPORTS" /Fp"$(INTDIR)\cfitsio.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /GZ /c
+MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\cfitsio.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /incremental:yes /pdb:"$(OUTDIR)\cfitsio.pdb" /debug /machine:I386 /def:".\cfitsio.def" /out:"$(OUTDIR)\cfitsio.dll" /implib:"$(OUTDIR)\cfitsio.lib" /pdbtype:sept
+DEF_FILE= ".\cfitsio.def"
+LINK32_OBJS= \
+ "$(INTDIR)\buffers.obj" \
+ "$(INTDIR)\cfileio.obj" \
+ "$(INTDIR)\checksum.obj" \
+ "$(INTDIR)\compress.obj" \
+ "$(INTDIR)\drvrfile.obj" \
+ "$(INTDIR)\drvrmem.obj" \
+ "$(INTDIR)\editcol.obj" \
+ "$(INTDIR)\edithdu.obj" \
+ "$(INTDIR)\eval_f.obj" \
+ "$(INTDIR)\eval_l.obj" \
+ "$(INTDIR)\eval_y.obj" \
+ "$(INTDIR)\fitscore.obj" \
+ "$(INTDIR)\f77_wrap1.obj" \
+ "$(INTDIR)\f77_wrap2.obj" \
+ "$(INTDIR)\f77_wrap3.obj" \
+ "$(INTDIR)\f77_wrap4.obj" \
+ "$(INTDIR)\getcol.obj" \
+ "$(INTDIR)\getcolb.obj" \
+ "$(INTDIR)\getcolsb.obj" \
+ "$(INTDIR)\getcold.obj" \
+ "$(INTDIR)\getcole.obj" \
+ "$(INTDIR)\getcoli.obj" \
+ "$(INTDIR)\getcolj.obj" \
+ "$(INTDIR)\getcolk.obj" \
+ "$(INTDIR)\getcoll.obj" \
+ "$(INTDIR)\getcols.obj" \
+ "$(INTDIR)\getcolui.obj" \
+ "$(INTDIR)\getcoluj.obj" \
+ "$(INTDIR)\getcoluk.obj" \
+ "$(INTDIR)\getkey.obj" \
+ "$(INTDIR)\group.obj" \
+ "$(INTDIR)\grparser.obj" \
+ "$(INTDIR)\histo.obj" \
+ "$(INTDIR)\iraffits.obj" \
+ "$(INTDIR)\modkey.obj" \
+ "$(INTDIR)\putcol.obj" \
+ "$(INTDIR)\putcolb.obj" \
+ "$(INTDIR)\putcolsb.obj" \
+ "$(INTDIR)\putcold.obj" \
+ "$(INTDIR)\putcole.obj" \
+ "$(INTDIR)\putcoli.obj" \
+ "$(INTDIR)\putcolj.obj" \
+ "$(INTDIR)\putcolk.obj" \
+ "$(INTDIR)\putcoll.obj" \
+ "$(INTDIR)\putcols.obj" \
+ "$(INTDIR)\putcolu.obj" \
+ "$(INTDIR)\putcolui.obj" \
+ "$(INTDIR)\putcoluj.obj" \
+ "$(INTDIR)\putcoluk.obj" \
+ "$(INTDIR)\putkey.obj" \
+ "$(INTDIR)\region.obj" \
+ "$(INTDIR)\scalnull.obj" \
+ "$(INTDIR)\swapproc.obj" \
+ "$(INTDIR)\wcssub.obj" \
+ "$(INTDIR)\wcsutil.obj" \
+ "$(INTDIR)\imcompress.obj" \
+ "$(INTDIR)\ricecomp.obj" \
+ "$(INTDIR)\quantize.obj" \
+ "$(INTDIR)\pliocomp.obj"
+
+
+"$(OUTDIR)\cfitsio.dll" : $(LINK32_OBJS) WINDUMP
+ windumpexts -o $(DEF_FILE) cfitsio.dll $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ENDIF
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+
+!IF "$(NO_EXTERNAL_DEPS)" != "1"
+!IF EXISTS("cfitsio.dep")
+!INCLUDE "cfitsio.dep"
+!ELSE
+!MESSAGE Warning: cannot find "cfitsio.dep"
+!ENDIF
+!ENDIF
+
+
+!IF "$(CFG)" == "cfitsio - Win32 Release" || "$(CFG)" == "cfitsio - Win32 Debug"
+SOURCE=.\buffers.c
+
+"$(INTDIR)\buffers.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\cfileio.c
+
+"$(INTDIR)\cfileio.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\checksum.c
+
+"$(INTDIR)\checksum.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\compress.c
+
+"$(INTDIR)\compress.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\drvrfile.c
+
+"$(INTDIR)\drvrfile.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\drvrmem.c
+
+"$(INTDIR)\drvrmem.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\editcol.c
+
+"$(INTDIR)\editcol.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\edithdu.c
+
+"$(INTDIR)\edithdu.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\eval_f.c
+
+"$(INTDIR)\eval_f.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\eval_l.c
+
+"$(INTDIR)\eval_l.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\eval_y.c
+
+"$(INTDIR)\eval_y.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\fitscore.c
+
+"$(INTDIR)\fitscore.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\f77_wrap1.c
+
+"$(INTDIR)\f77_wrap1.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\f77_wrap2.c
+
+"$(INTDIR)\f77_wrap2.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\f77_wrap3.c
+
+"$(INTDIR)\f77_wrap3.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\f77_wrap4.c
+
+"$(INTDIR)\f77_wrap4.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\getcol.c
+
+"$(INTDIR)\getcol.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\getcolb.c
+
+"$(INTDIR)\getcolb.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\getcolsb.c
+
+"$(INTDIR)\getcolsb.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\getcold.c
+
+"$(INTDIR)\getcold.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\getcole.c
+
+"$(INTDIR)\getcole.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\getcoli.c
+
+"$(INTDIR)\getcoli.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\getcolj.c
+
+"$(INTDIR)\getcolj.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\getcolk.c
+
+"$(INTDIR)\getcolk.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\getcoll.c
+
+"$(INTDIR)\getcoll.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\getcols.c
+
+"$(INTDIR)\getcols.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\getcolui.c
+
+"$(INTDIR)\getcolui.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\getcoluj.c
+
+"$(INTDIR)\getcoluj.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\getcoluk.c
+
+"$(INTDIR)\getcoluk.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\getkey.c
+
+"$(INTDIR)\getkey.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\group.c
+
+"$(INTDIR)\group.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\grparser.c
+
+"$(INTDIR)\grparser.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\histo.c
+
+"$(INTDIR)\histo.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\iraffits.c
+
+"$(INTDIR)\iraffits.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\modkey.c
+
+"$(INTDIR)\modkey.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\putcol.c
+
+"$(INTDIR)\putcol.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\putcolb.c
+
+"$(INTDIR)\putcolb.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\putcolsb.c
+
+"$(INTDIR)\putcolsb.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\putcold.c
+
+"$(INTDIR)\putcold.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\putcole.c
+
+"$(INTDIR)\putcole.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\putcoli.c
+
+"$(INTDIR)\putcoli.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\putcolj.c
+
+"$(INTDIR)\putcolj.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\putcolk.c
+
+"$(INTDIR)\putcolk.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\putcoll.c
+
+"$(INTDIR)\putcoll.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\putcols.c
+
+"$(INTDIR)\putcols.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\putcolu.c
+
+"$(INTDIR)\putcolu.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\putcolui.c
+
+"$(INTDIR)\putcolui.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\putcoluj.c
+
+"$(INTDIR)\putcoluj.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\putcoluk.c
+
+"$(INTDIR)\putcoluk.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\putkey.c
+
+"$(INTDIR)\putkey.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\region.c
+
+"$(INTDIR)\region.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\scalnull.c
+
+"$(INTDIR)\scalnull.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\swapproc.c
+
+"$(INTDIR)\swapproc.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\wcssub.c
+
+"$(INTDIR)\wcssub.obj" : $(SOURCE) "$(INTDIR)"
+
+SOURCE=.\wcsutil.c
+
+"$(INTDIR)\wcsutil.obj" : $(SOURCE) "$(INTDIR)"
+
+SOURCE=imcompress.c
+
+"$(INTDIR)\imcompress.obj" : $(SOURCE) "$(INTDIR)"
+
+SOURCE=ricecomp.c
+
+"$(INTDIR)\ricecomp.obj" : $(SOURCE) "$(INTDIR)"
+
+SOURCE=quantize.c
+
+"$(INTDIR)\quantize.obj" : $(SOURCE) "$(INTDIR)"
+
+SOURCE=pliocomp.c
+
+"$(INTDIR)\pliocomp.obj" : $(SOURCE) "$(INTDIR)"
+
+!ENDIF
+
+$(DEF_FILE):
+
+
+
+WINDUMP:
+ nmake -f winDumpExts.mak
diff --git a/pkg/tbtables/cfitsio/makepc.bat b/pkg/tbtables/cfitsio/makepc.bat
new file mode 100644
index 00000000..fd461853
--- /dev/null
+++ b/pkg/tbtables/cfitsio/makepc.bat
@@ -0,0 +1,69 @@
+rem: this batch file builds the cfitsio library
+rem: using the Borland C++ v4.5 compiler
+rem:
+bcc32 -c buffers.c
+bcc32 -c cfileio.c
+bcc32 -c checksum.c
+bcc32 -c compress.c
+bcc32 -c drvrfile.c
+bcc32 -c drvrmem.c
+bcc32 -c editcol.c
+bcc32 -c edithdu.c
+bcc32 -c eval_l.c
+bcc32 -c eval_y.c
+bcc32 -c eval_f.c
+bcc32 -c fitscore.c
+bcc32 -c getcol.c
+bcc32 -c getcolb.c
+bcc32 -c getcoli.c
+bcc32 -c getcolj.c
+bcc32 -c getcolui.c
+bcc32 -c getcoluj.c
+bcc32 -c getcoluk.c
+bcc32 -c getcolk.c
+bcc32 -c getcole.c
+bcc32 -c getcold.c
+bcc32 -c getcoll.c
+bcc32 -c getcols.c
+bcc32 -c getkey.c
+bcc32 -c group.c
+bcc32 -c grparser.c
+bcc32 -c histo.c
+bcc32 -c iraffits.c
+bcc32 -c modkey.c
+bcc32 -c putcol.c
+bcc32 -c putcolb.c
+bcc32 -c putcoli.c
+bcc32 -c putcolj.c
+bcc32 -c putcolui.c
+bcc32 -c putcoluj.c
+bcc32 -c putcoluk.c
+bcc32 -c putcolk.c
+bcc32 -c putcole.c
+bcc32 -c putcold.c
+bcc32 -c putcols.c
+bcc32 -c putcoll.c
+bcc32 -c putcolu.c
+bcc32 -c putkey.c
+bcc32 -c region.c
+bcc32 -c scalnull.c
+bcc32 -c swapproc.c
+bcc32 -c wcsutil.c
+bcc32 -c wcssub.c
+bcc32 -c imcompress.c
+bcc32 -c quantize.c
+bcc32 -c ricecomp.c
+bcc32 -c pliocomp.c
+del cfitsio.lib
+tlib cfitsio +buffers +cfileio +checksum +compress +drvrfile +drvrmem
+tlib cfitsio +editcol +edithdu +eval_l +eval_y +eval_f +fitscore
+tlib cfitsio +getcol +getcolb +getcoli +getcolj +getcolk +getcoluk
+tlib cfitsio +getcolui +getcoluj +getcole +getcold +getcoll +getcols
+tlib cfitsio +getkey +group +grparser +histo +iraffits +modkey +putkey
+tlib cfitsio +putcol +putcolb +putcoli +putcolj +putcolk +putcole +putcold
+tlib cfitsio +putcoll +putcols +putcolu +putcolui +putcoluj +putcoluk
+tlib cfitsio +region +scalnull +swapproc +wcsutil +wcssub
+tlib cfitsio +imcompress +quantize +ricecomp +pliocomp
+bcc32 -f testprog.c cfitsio.lib
+bcc32 -f cookbook.c cfitsio.lib
+
diff --git a/pkg/tbtables/cfitsio/mkpkg b/pkg/tbtables/cfitsio/mkpkg
new file mode 100644
index 00000000..2bee177f
--- /dev/null
+++ b/pkg/tbtables/cfitsio/mkpkg
@@ -0,0 +1,66 @@
+# CFITSIO -- This IRAF mkpkg file updates the TBTABLES library to include
+# the CFITSIO interface.
+
+libtbtables.a:
+ $set XFLAGS = "-Inolibc $(XFLAGS)"
+ buffers.c fitsio2.h fitsio.h longnam.h drvrsmem.h
+ cfileio.c fitsio2.h fitsio.h longnam.h drvrsmem.h
+ checksum.c fitsio2.h fitsio.h longnam.h drvrsmem.h
+ compress.c
+ drvrfile.c fitsio2.h fitsio.h longnam.h drvrsmem.h
+ drvrmem.c fitsio2.h fitsio.h longnam.h drvrsmem.h
+ editcol.c fitsio2.h fitsio.h longnam.h drvrsmem.h
+ edithdu.c fitsio2.h fitsio.h longnam.h drvrsmem.h
+ eval_f.c eval_defs.h fitsio2.h fitsio.h longnam.h drvrsmem.h \
+ eval_tab.h region.h
+ eval_l.c eval_defs.h fitsio2.h fitsio.h longnam.h drvrsmem.h \
+ eval_tab.h
+ eval_y.c eval_defs.h fitsio2.h fitsio.h longnam.h drvrsmem.h \
+ region.h
+ fitscore.c fitsio2.h fitsio.h longnam.h drvrsmem.h
+ getcol.c fitsio2.h fitsio.h longnam.h drvrsmem.h
+ getcolb.c fitsio2.h fitsio.h longnam.h drvrsmem.h
+ getcold.c fitsio2.h fitsio.h longnam.h drvrsmem.h
+ getcole.c fitsio2.h fitsio.h longnam.h drvrsmem.h
+ getcoli.c fitsio2.h fitsio.h longnam.h drvrsmem.h
+ getcolj.c fitsio2.h fitsio.h longnam.h drvrsmem.h
+ getcolk.c fitsio2.h fitsio.h longnam.h drvrsmem.h
+ getcoll.c fitsio2.h fitsio.h longnam.h drvrsmem.h
+ getcols.c fitsio2.h fitsio.h longnam.h drvrsmem.h
+ getcolsb.c fitsio2.h fitsio.h longnam.h drvrsmem.h
+ getcolui.c fitsio2.h fitsio.h longnam.h drvrsmem.h
+ getcoluj.c fitsio2.h fitsio.h longnam.h drvrsmem.h
+ getcoluk.c fitsio2.h fitsio.h longnam.h drvrsmem.h
+ getkey.c fitsio2.h fitsio.h longnam.h drvrsmem.h
+ group.c fitsio2.h fitsio.h longnam.h drvrsmem.h group.h
+ grparser.c fitsio.h longnam.h grparser.h
+ histo.c fitsio2.h fitsio.h longnam.h drvrsmem.h
+ imcompress.c fitsio2.h fitsio.h longnam.h
+ iraffits.c
+ modkey.c fitsio2.h fitsio.h longnam.h drvrsmem.h
+ pliocomp.c
+ putcol.c fitsio2.h fitsio.h longnam.h drvrsmem.h
+ putcolb.c fitsio2.h fitsio.h longnam.h drvrsmem.h
+ putcold.c fitsio2.h fitsio.h longnam.h drvrsmem.h
+ putcole.c fitsio2.h fitsio.h longnam.h drvrsmem.h
+ putcoli.c fitsio2.h fitsio.h longnam.h drvrsmem.h
+ putcolj.c fitsio2.h fitsio.h longnam.h drvrsmem.h
+ putcolk.c fitsio2.h fitsio.h longnam.h drvrsmem.h
+ putcoll.c fitsio2.h fitsio.h longnam.h drvrsmem.h
+ putcols.c fitsio2.h fitsio.h longnam.h drvrsmem.h
+ putcolsb.c fitsio2.h fitsio.h longnam.h drvrsmem.h
+ putcolu.c fitsio2.h fitsio.h longnam.h drvrsmem.h
+ putcolui.c fitsio2.h fitsio.h longnam.h drvrsmem.h
+ putcoluj.c fitsio2.h fitsio.h longnam.h drvrsmem.h
+ putcoluk.c fitsio2.h fitsio.h longnam.h drvrsmem.h
+ putkey.c fitsio2.h fitsio.h longnam.h drvrsmem.h
+ quantize.c fitsio2.h fitsio.h longnam.h
+ region.c fitsio2.h fitsio.h longnam.h drvrsmem.h region.h
+ ricecomp.c ricecomp.h fitsio2.h fitsio.h longnam.h
+ scalnull.c fitsio2.h fitsio.h longnam.h drvrsmem.h
+ swapproc.c fitsio2.h fitsio.h longnam.h drvrsmem.h
+ wcsutil.c fitsio2.h fitsio.h longnam.h drvrsmem.h
+$ifeq (MACH, _alpha)
+ wcssub.c fitsio2.h fitsio.h longnam.h drvrsmem.h
+$endif
+ ;
diff --git a/pkg/tbtables/cfitsio/modkey.c b/pkg/tbtables/cfitsio/modkey.c
new file mode 100644
index 00000000..b257eb25
--- /dev/null
+++ b/pkg/tbtables/cfitsio/modkey.c
@@ -0,0 +1,1614 @@
+/* This file, modkey.c, contains routines that modify, insert, or update */
+/* keywords in a FITS header. */
+
+/* The FITSIO software was written by William Pence at the High Energy */
+/* Astrophysic Science Archive Research Center (HEASARC) at the NASA */
+/* Goddard Space Flight Center. */
+
+#include <string.h>
+/* stddef.h is apparently needed to define size_t */
+#include <ctype.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include "fitsio2.h"
+/*--------------------------------------------------------------------------*/
+int ffuky( fitsfile *fptr, /* I - FITS file pointer */
+ int datatype, /* I - datatype of the value */
+ char *keyname, /* I - name of keyword to write */
+ void *value, /* I - keyword value */
+ char *comm, /* I - keyword comment */
+ int *status) /* IO - error status */
+/*
+ Update the keyword, value and comment in the FITS header.
+ The datatype is specified by the 2nd argument.
+*/
+{
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ if (datatype == TSTRING)
+ {
+ ffukys(fptr, keyname, (char *) value, comm, status);
+ }
+ else if (datatype == TBYTE)
+ {
+ ffukyj(fptr, keyname, (long) *(unsigned char *) value, comm, status);
+ }
+ else if (datatype == TSBYTE)
+ {
+ ffukyj(fptr, keyname, (long) *(signed char *) value, comm, status);
+ }
+ else if (datatype == TUSHORT)
+ {
+ ffukyj(fptr, keyname, (long) *(unsigned short *) value, comm, status);
+ }
+ else if (datatype == TSHORT)
+ {
+ ffukyj(fptr, keyname, (long) *(short *) value, comm, status);
+ }
+ else if (datatype == TINT)
+ {
+ ffukyj(fptr, keyname, (long) *(int *) value, comm, status);
+ }
+ else if (datatype == TUINT)
+ {
+ ffukyg(fptr, keyname, (double) *(unsigned int *) value, 0,
+ comm, status);
+ }
+ else if (datatype == TLOGICAL)
+ {
+ ffukyl(fptr, keyname, *(int *) value, comm, status);
+ }
+ else if (datatype == TULONG)
+ {
+ ffukyg(fptr, keyname, (double) *(unsigned long *) value, 0,
+ comm, status);
+ }
+ else if (datatype == TLONG)
+ {
+ ffukyj(fptr, keyname, *(long *) value, comm, status);
+ }
+ else if (datatype == TFLOAT)
+ {
+ ffukye(fptr, keyname, *(float *) value, -7, comm, status);
+ }
+ else if (datatype == TDOUBLE)
+ {
+ ffukyd(fptr, keyname, *(double *) value, -15, comm, status);
+ }
+ else if (datatype == TCOMPLEX)
+ {
+ ffukyc(fptr, keyname, (float *) value, -7, comm, status);
+ }
+ else if (datatype == TDBLCOMPLEX)
+ {
+ ffukym(fptr, keyname, (double *) value, -15, comm, status);
+ }
+ else
+ *status = BAD_DATATYPE;
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffukyu(fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - keyword name */
+ char *comm, /* I - keyword comment */
+ int *status) /* IO - error status */
+{
+ int tstatus;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ tstatus = *status;
+
+ if (ffmkyu(fptr, keyname, comm, status) == KEY_NO_EXIST)
+ {
+ *status = tstatus;
+ ffpkyu(fptr, keyname, comm, status);
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffukys(fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - keyword name */
+ char *value, /* I - keyword value */
+ char *comm, /* I - keyword comment */
+ int *status) /* IO - error status */
+{
+ int tstatus;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ tstatus = *status;
+
+ if (ffmkys(fptr, keyname, value, comm, status) == KEY_NO_EXIST)
+ {
+ *status = tstatus;
+ ffpkys(fptr, keyname, value, comm, status);
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffukls(fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - keyword name */
+ char *value, /* I - keyword value */
+ char *comm, /* I - keyword comment */
+ int *status) /* IO - error status */
+{
+ /* update a long string keyword */
+
+ int tstatus;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ tstatus = *status;
+
+ if (ffmkls(fptr, keyname, value, comm, status) == KEY_NO_EXIST)
+ {
+ *status = tstatus;
+ ffpkls(fptr, keyname, value, comm, status);
+ }
+ return(*status);
+}/*--------------------------------------------------------------------------*/
+int ffukyl(fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - keyword name */
+ int value, /* I - keyword value */
+ char *comm, /* I - keyword comment */
+ int *status) /* IO - error status */
+{
+ int tstatus;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ tstatus = *status;
+
+ if (ffmkyl(fptr, keyname, value, comm, status) == KEY_NO_EXIST)
+ {
+ *status = tstatus;
+ ffpkyl(fptr, keyname, value, comm, status);
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffukyj(fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - keyword name */
+ long value, /* I - keyword value */
+ char *comm, /* I - keyword comment */
+ int *status) /* IO - error status */
+{
+ int tstatus;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ tstatus = *status;
+
+ if (ffmkyj(fptr, keyname, value, comm, status) == KEY_NO_EXIST)
+ {
+ *status = tstatus;
+ ffpkyj(fptr, keyname, value, comm, status);
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffukyf(fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - keyword name */
+ float value, /* I - keyword value */
+ int decim, /* I - no of decimals */
+ char *comm, /* I - keyword comment */
+ int *status) /* IO - error status */
+{
+ int tstatus;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ tstatus = *status;
+
+ if (ffmkyf(fptr, keyname, value, decim, comm, status) == KEY_NO_EXIST)
+ {
+ *status = tstatus;
+ ffpkyf(fptr, keyname, value, decim, comm, status);
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffukye(fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - keyword name */
+ float value, /* I - keyword value */
+ int decim, /* I - no of decimals */
+ char *comm, /* I - keyword comment */
+ int *status) /* IO - error status */
+{
+ int tstatus;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ tstatus = *status;
+
+ if (ffmkye(fptr, keyname, value, decim, comm, status) == KEY_NO_EXIST)
+ {
+ *status = tstatus;
+ ffpkye(fptr, keyname, value, decim, comm, status);
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffukyg(fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - keyword name */
+ double value, /* I - keyword value */
+ int decim, /* I - no of decimals */
+ char *comm, /* I - keyword comment */
+ int *status) /* IO - error status */
+{
+ int tstatus;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ tstatus = *status;
+
+ if (ffmkyg(fptr, keyname, value, decim, comm, status) == KEY_NO_EXIST)
+ {
+ *status = tstatus;
+ ffpkyg(fptr, keyname, value, decim, comm, status);
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffukyd(fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - keyword name */
+ double value, /* I - keyword value */
+ int decim, /* I - no of decimals */
+ char *comm, /* I - keyword comment */
+ int *status) /* IO - error status */
+{
+ int tstatus;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ tstatus = *status;
+
+ if (ffmkyd(fptr, keyname, value, decim, comm, status) == KEY_NO_EXIST)
+ {
+ *status = tstatus;
+ ffpkyd(fptr, keyname, value, decim, comm, status);
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffukfc(fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - keyword name */
+ float *value, /* I - keyword value */
+ int decim, /* I - no of decimals */
+ char *comm, /* I - keyword comment */
+ int *status) /* IO - error status */
+{
+ int tstatus;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ tstatus = *status;
+
+ if (ffmkfc(fptr, keyname, value, decim, comm, status) == KEY_NO_EXIST)
+ {
+ *status = tstatus;
+ ffpkfc(fptr, keyname, value, decim, comm, status);
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffukyc(fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - keyword name */
+ float *value, /* I - keyword value */
+ int decim, /* I - no of decimals */
+ char *comm, /* I - keyword comment */
+ int *status) /* IO - error status */
+{
+ int tstatus;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ tstatus = *status;
+
+ if (ffmkyc(fptr, keyname, value, decim, comm, status) == KEY_NO_EXIST)
+ {
+ *status = tstatus;
+ ffpkyc(fptr, keyname, value, decim, comm, status);
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffukfm(fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - keyword name */
+ double *value, /* I - keyword value */
+ int decim, /* I - no of decimals */
+ char *comm, /* I - keyword comment */
+ int *status) /* IO - error status */
+{
+ int tstatus;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ tstatus = *status;
+
+ if (ffmkfm(fptr, keyname, value, decim, comm, status) == KEY_NO_EXIST)
+ {
+ *status = tstatus;
+ ffpkfm(fptr, keyname, value, decim, comm, status);
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffukym(fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - keyword name */
+ double *value, /* I - keyword value */
+ int decim, /* I - no of decimals */
+ char *comm, /* I - keyword comment */
+ int *status) /* IO - error status */
+{
+ int tstatus;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ tstatus = *status;
+
+ if (ffmkym(fptr, keyname, value, decim, comm, status) == KEY_NO_EXIST)
+ {
+ *status = tstatus;
+ ffpkym(fptr, keyname, value, decim, comm, status);
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffucrd(fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - keyword name */
+ char *card, /* I - card string value */
+ int *status) /* IO - error status */
+{
+ int tstatus;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ tstatus = *status;
+
+ if (ffmcrd(fptr, keyname, card, status) == KEY_NO_EXIST)
+ {
+ *status = tstatus;
+ ffprec(fptr, card, status);
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffmrec(fitsfile *fptr, /* I - FITS file pointer */
+ int nkey, /* I - number of the keyword to modify */
+ char *card, /* I - card string value */
+ int *status) /* IO - error status */
+{
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ ffmaky(fptr, nkey+1, status);
+ ffmkey(fptr, card, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffmcrd(fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - keyword name */
+ char *card, /* I - card string value */
+ int *status) /* IO - error status */
+{
+ char tcard[FLEN_CARD];
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ if (ffgcrd(fptr, keyname, tcard, status) > 0)
+ return(*status);
+
+ ffmkey(fptr, card, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffmnam(fitsfile *fptr, /* I - FITS file pointer */
+ char *oldname, /* I - existing keyword name */
+ char *newname, /* I - new name for keyword */
+ int *status) /* IO - error status */
+{
+ char comm[FLEN_COMMENT];
+ char value[FLEN_VALUE];
+ char card[FLEN_CARD];
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ if (ffgkey(fptr, oldname, value, comm, status) > 0)
+ return(*status);
+
+ ffmkky(newname, value, comm, card, status); /* construct the card */
+ ffmkey(fptr, card, status); /* rewrite with new name */
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffmcom(fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - keyword name */
+ char *comm, /* I - keyword comment */
+ int *status) /* IO - error status */
+{
+ char oldcomm[FLEN_COMMENT];
+ char value[FLEN_VALUE];
+ char card[FLEN_CARD];
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ if (ffgkey(fptr, keyname, value, oldcomm, status) > 0)
+ return(*status);
+
+ ffmkky(keyname, value, comm, card, status); /* construct the card */
+ ffmkey(fptr, card, status); /* rewrite with new comment */
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpunt(fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - keyword name */
+ char *unit, /* I - keyword unit string */
+ int *status) /* IO - error status */
+/*
+ Write (put) the units string into the comment field of the existing
+ keyword. This routine uses a local FITS convention (not defined in the
+ official FITS standard) in which the units are enclosed in
+ square brackets following the '/' comment field delimiter, e.g.:
+
+ KEYWORD = 12 / [kpc] comment string goes here
+*/
+{
+ char oldcomm[FLEN_COMMENT];
+ char newcomm[FLEN_COMMENT];
+ char value[FLEN_VALUE];
+ char card[FLEN_CARD];
+ char *loc;
+ size_t len;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ if (ffgkey(fptr, keyname, value, oldcomm, status) > 0)
+ return(*status);
+
+ /* copy the units string to the new comment string if not null */
+ if (*unit)
+ {
+ strcpy(newcomm, "[");
+ strncat(newcomm, unit, 45); /* max allowed length is about 45 chars */
+ strcat(newcomm, "] ");
+ len = strlen(newcomm);
+ len = FLEN_COMMENT - len - 1; /* amount of space left in the field */
+ }
+ else
+ {
+ newcomm[0] = '\0';
+ len = FLEN_COMMENT - 1;
+ }
+
+ if (oldcomm[0] == '[') /* check for existing units field */
+ {
+ loc = strchr(oldcomm, ']'); /* look for the closing bracket */
+ if (loc)
+ {
+ loc++;
+ while (*loc == ' ') /* skip any blank spaces */
+ loc++;
+
+ strncat(newcomm, loc, len); /* concat remainder of comment */
+ }
+ else
+ {
+ strncat(newcomm, oldcomm, len); /* append old comment onto new */
+ }
+ }
+ else
+ {
+ strncat(newcomm, oldcomm, len);
+ }
+
+ ffmkky(keyname, value, newcomm, card, status); /* construct the card */
+ ffmkey(fptr, card, status); /* rewrite with new units string */
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffmkyu(fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - keyword name */
+ char *comm, /* I - keyword comment */
+ int *status) /* IO - error status */
+{
+ char valstring[FLEN_VALUE];
+ char oldcomm[FLEN_COMMENT];
+ char card[FLEN_CARD];
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ if (ffgkey(fptr, keyname, valstring, oldcomm, status) > 0)
+ return(*status); /* get old comment */
+
+ strcpy(valstring," "); /* create a dummy value string */
+
+ if (!comm || comm[0] == '&') /* preserve the current comment string */
+ ffmkky(keyname, valstring, oldcomm, card, status);
+ else
+ ffmkky(keyname, valstring, comm, card, status);
+
+ ffmkey(fptr, card, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffmkys(fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - keyword name */
+ char *value, /* I - keyword value */
+ char *comm, /* I - keyword comment */
+ int *status) /* IO - error status */
+{
+ /* NOTE: This routine does not support long continued strings */
+ /* It will correctly overwrite an existing long continued string, */
+ /* but it will not write a new long string. */
+
+ char oldval[FLEN_VALUE], valstring[FLEN_VALUE];
+ char oldcomm[FLEN_COMMENT];
+ char card[FLEN_CARD];
+ int len, keypos;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ if (ffgkey(fptr, keyname, oldval, oldcomm, status) > 0)
+ return(*status); /* get old comment */
+
+ ffs2c(value, valstring, status); /* convert value to a string */
+
+ if (!comm || comm[0] == '&') /* preserve the current comment string */
+ ffmkky(keyname, valstring, oldcomm, card, status);
+ else
+ ffmkky(keyname, valstring, comm, card, status);
+
+ ffmkey(fptr, card, status); /* overwrite the previous keyword */
+
+ keypos = ((((fptr->Fptr)->nextkey) - ((fptr->Fptr)->headstart[(fptr->Fptr)->curhdu])) / 80) + 1;
+
+ /* check if old string value was continued over multiple keywords */
+ ffc2s(oldval, valstring, status); /* remove quotes and trailing spaces */
+ len = strlen(valstring);
+
+ while (len && valstring[len - 1] == '&') /* ampersand is continuation char */
+ {
+ ffgcnt(fptr, valstring, status);
+ if (*valstring)
+ {
+ ffdrec(fptr, keypos, status); /* delete the continuation */
+ len = strlen(valstring);
+ }
+ else /* a null valstring indicates no continuation */
+ len = 0;
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffmkls( fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - name of keyword to write */
+ char *value, /* I - keyword value */
+ char *incomm, /* I - keyword comment */
+ int *status) /* IO - error status */
+/*
+ Modify the value and optionally the comment of a long string keyword.
+ This routine supports the
+ HEASARC long string convention and can modify arbitrarily long string
+ keyword values. The value is continued over multiple keywords that
+ have the name COMTINUE without an equal sign in column 9 of the card.
+ This routine also supports simple string keywords which are less than
+ 69 characters in length.
+
+ This routine is not very efficient, so it should be used sparingly.
+*/
+{
+ char valstring[FLEN_VALUE];
+ char card[FLEN_CARD];
+ char comm[FLEN_COMMENT];
+ char tstring[FLEN_VALUE], *cptr;
+ char *longval;
+ int next, remain, vlen, nquote, nchar, namelen, contin, tstatus = -1;
+ int nkeys, keypos;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ if (!incomm || incomm[0] == '&') /* preserve the old comment string */
+ {
+ ffghps(fptr, &nkeys, &keypos, status); /* save current position */
+
+ if (ffgkls(fptr, keyname, &longval, comm, status) > 0)
+ return(*status); /* keyword doesn't exist */
+
+ free(longval); /* don't need the old value */
+
+ /* move back to previous position to ensure that we delete */
+ /* the right keyword in case there are more than one keyword */
+ /* with this same name. */
+ ffgrec(fptr, keypos - 1, card, status);
+ }
+ else
+ strcpy(comm, incomm); /* copy the input comment string */
+
+ /* delete the old keyword */
+ if (ffdkey(fptr, keyname, status) > 0)
+ return(*status); /* keyword doesn't exist */
+
+ ffghps(fptr, &nkeys, &keypos, status); /* save current position */
+
+ /* now construct the new keyword, and insert into header */
+ remain = strlen(value); /* number of characters to write out */
+ next = 0; /* pointer to next character to write */
+
+ /* count the number of single quote characters in the string */
+ nquote = 0;
+ cptr = strchr(value, '\''); /* search for quote character */
+
+ while (cptr) /* search for quote character */
+ {
+ nquote++; /* increment no. of quote characters */
+ cptr++; /* increment pointer to next character */
+ cptr = strchr(cptr, '\''); /* search for another quote char */
+ }
+
+ cptr = keyname;
+ while(*cptr == ' ') /* skip over leading spaces in name */
+ cptr++;
+
+ /* determine the number of characters that will fit on the line */
+ /* Note: each quote character is expanded to 2 quotes */
+
+ namelen = strlen(cptr);
+ if (namelen <= 8 && (fftkey(cptr, &tstatus) <= 0) )
+ {
+ /* This a normal 8-character FITS keyword */
+ nchar = 68 - nquote; /* max of 68 chars fit in a FITS string value */
+ }
+ else
+ {
+ /* This a HIERARCH keyword */
+ if (FSTRNCMP(cptr, "HIERARCH ", 9) &&
+ FSTRNCMP(cptr, "hierarch ", 9))
+ nchar = 66 - nquote - namelen;
+ else
+ nchar = 75 - nquote - namelen; /* don't count 'HIERARCH' twice */
+
+ }
+
+ contin = 0;
+ while (remain > 0)
+ {
+ strncpy(tstring, &value[next], nchar); /* copy string to temp buff */
+ tstring[nchar] = '\0';
+ ffs2c(tstring, valstring, status); /* put quotes around the string */
+
+ if (remain > nchar) /* if string is continued, put & as last char */
+ {
+ vlen = strlen(valstring);
+ nchar -= 1; /* outputting one less character now */
+
+ if (valstring[vlen-2] != '\'')
+ valstring[vlen-2] = '&'; /* over write last char with & */
+ else
+ { /* last char was a pair of single quotes, so over write both */
+ valstring[vlen-3] = '&';
+ valstring[vlen-1] = '\0';
+ }
+ }
+
+ if (contin) /* This is a CONTINUEd keyword */
+ {
+ ffmkky("CONTINUE", valstring, comm, card, status); /* make keyword */
+ strncpy(&card[8], " ", 2); /* overwrite the '=' */
+ }
+ else
+ {
+ ffmkky(keyname, valstring, comm, card, status); /* make keyword */
+ }
+
+ ffirec(fptr, keypos, card, status); /* insert the keyword */
+
+ keypos++; /* next insert position */
+ contin = 1;
+ remain -= nchar;
+ next += nchar;
+ nchar = 68 - nquote;
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffmkyl(fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - keyword name */
+ int value, /* I - keyword value */
+ char *comm, /* I - keyword comment */
+ int *status) /* IO - error status */
+{
+ char valstring[FLEN_VALUE];
+ char oldcomm[FLEN_COMMENT];
+ char card[FLEN_CARD];
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ if (ffgkey(fptr, keyname, valstring, oldcomm, status) > 0)
+ return(*status); /* get old comment */
+
+ ffl2c(value, valstring, status); /* convert value to a string */
+
+ if (!comm || comm[0] == '&') /* preserve the current comment string */
+ ffmkky(keyname, valstring, oldcomm, card, status);
+ else
+ ffmkky(keyname, valstring, comm, card, status);
+
+ ffmkey(fptr, card, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffmkyj(fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - keyword name */
+ long value, /* I - keyword value */
+ char *comm, /* I - keyword comment */
+ int *status) /* IO - error status */
+{
+ char valstring[FLEN_VALUE];
+ char oldcomm[FLEN_COMMENT];
+ char card[FLEN_CARD];
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ if (ffgkey(fptr, keyname, valstring, oldcomm, status) > 0)
+ return(*status); /* get old comment */
+
+ ffi2c(value, valstring, status); /* convert value to a string */
+
+ if (!comm || comm[0] == '&') /* preserve the current comment string */
+ ffmkky(keyname, valstring, oldcomm, card, status);
+ else
+ ffmkky(keyname, valstring, comm, card, status);
+
+ ffmkey(fptr, card, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffmkyf(fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - keyword name */
+ float value, /* I - keyword value */
+ int decim, /* I - no of decimals */
+ char *comm, /* I - keyword comment */
+ int *status) /* IO - error status */
+{
+ char valstring[FLEN_VALUE];
+ char oldcomm[FLEN_COMMENT];
+ char card[FLEN_CARD];
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ if (ffgkey(fptr, keyname, valstring, oldcomm, status) > 0)
+ return(*status); /* get old comment */
+
+ ffr2f(value, decim, valstring, status); /* convert value to a string */
+
+ if (!comm || comm[0] == '&') /* preserve the current comment string */
+ ffmkky(keyname, valstring, oldcomm, card, status);
+ else
+ ffmkky(keyname, valstring, comm, card, status);
+
+ ffmkey(fptr, card, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffmkye(fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - keyword name */
+ float value, /* I - keyword value */
+ int decim, /* I - no of decimals */
+ char *comm, /* I - keyword comment */
+ int *status) /* IO - error status */
+{
+ char valstring[FLEN_VALUE];
+ char oldcomm[FLEN_COMMENT];
+ char card[FLEN_CARD];
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ if (ffgkey(fptr, keyname, valstring, oldcomm, status) > 0)
+ return(*status); /* get old comment */
+
+ ffr2e(value, decim, valstring, status); /* convert value to a string */
+
+ if (!comm || comm[0] == '&') /* preserve the current comment string */
+ ffmkky(keyname, valstring, oldcomm, card, status);
+ else
+ ffmkky(keyname, valstring, comm, card, status);
+
+ ffmkey(fptr, card, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffmkyg(fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - keyword name */
+ double value, /* I - keyword value */
+ int decim, /* I - no of decimals */
+ char *comm, /* I - keyword comment */
+ int *status) /* IO - error status */
+{
+ char valstring[FLEN_VALUE];
+ char oldcomm[FLEN_COMMENT];
+ char card[FLEN_CARD];
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ if (ffgkey(fptr, keyname, valstring, oldcomm, status) > 0)
+ return(*status); /* get old comment */
+
+ ffd2f(value, decim, valstring, status); /* convert value to a string */
+
+ if (!comm || comm[0] == '&') /* preserve the current comment string */
+ ffmkky(keyname, valstring, oldcomm, card, status);
+ else
+ ffmkky(keyname, valstring, comm, card, status);
+
+ ffmkey(fptr, card, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffmkyd(fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - keyword name */
+ double value, /* I - keyword value */
+ int decim, /* I - no of decimals */
+ char *comm, /* I - keyword comment */
+ int *status) /* IO - error status */
+{
+ char valstring[FLEN_VALUE];
+ char oldcomm[FLEN_COMMENT];
+ char card[FLEN_CARD];
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ if (ffgkey(fptr, keyname, valstring, oldcomm, status) > 0)
+ return(*status); /* get old comment */
+
+ ffd2e(value, decim, valstring, status); /* convert value to a string */
+
+ if (!comm || comm[0] == '&') /* preserve the current comment string */
+ ffmkky(keyname, valstring, oldcomm, card, status);
+ else
+ ffmkky(keyname, valstring, comm, card, status);
+
+ ffmkey(fptr, card, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffmkfc(fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - keyword name */
+ float *value, /* I - keyword value */
+ int decim, /* I - no of decimals */
+ char *comm, /* I - keyword comment */
+ int *status) /* IO - error status */
+{
+ char valstring[FLEN_VALUE], tmpstring[FLEN_VALUE];
+ char oldcomm[FLEN_COMMENT];
+ char card[FLEN_CARD];
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ if (ffgkey(fptr, keyname, valstring, oldcomm, status) > 0)
+ return(*status); /* get old comment */
+
+ strcpy(valstring, "(" );
+ ffr2f(value[0], decim, tmpstring, status); /* convert to string */
+ strcat(valstring, tmpstring);
+ strcat(valstring, ", ");
+ ffr2f(value[1], decim, tmpstring, status); /* convert to string */
+ strcat(valstring, tmpstring);
+ strcat(valstring, ")");
+
+ if (!comm || comm[0] == '&') /* preserve the current comment string */
+ ffmkky(keyname, valstring, oldcomm, card, status);
+ else
+ ffmkky(keyname, valstring, comm, card, status);
+
+ ffmkey(fptr, card, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffmkyc(fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - keyword name */
+ float *value, /* I - keyword value */
+ int decim, /* I - no of decimals */
+ char *comm, /* I - keyword comment */
+ int *status) /* IO - error status */
+{
+ char valstring[FLEN_VALUE], tmpstring[FLEN_VALUE];
+ char oldcomm[FLEN_COMMENT];
+ char card[FLEN_CARD];
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ if (ffgkey(fptr, keyname, valstring, oldcomm, status) > 0)
+ return(*status); /* get old comment */
+
+ strcpy(valstring, "(" );
+ ffr2e(value[0], decim, tmpstring, status); /* convert to string */
+ strcat(valstring, tmpstring);
+ strcat(valstring, ", ");
+ ffr2e(value[1], decim, tmpstring, status); /* convert to string */
+ strcat(valstring, tmpstring);
+ strcat(valstring, ")");
+
+ if (!comm || comm[0] == '&') /* preserve the current comment string */
+ ffmkky(keyname, valstring, oldcomm, card, status);
+ else
+ ffmkky(keyname, valstring, comm, card, status);
+
+ ffmkey(fptr, card, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffmkfm(fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - keyword name */
+ double *value, /* I - keyword value */
+ int decim, /* I - no of decimals */
+ char *comm, /* I - keyword comment */
+ int *status) /* IO - error status */
+{
+ char valstring[FLEN_VALUE], tmpstring[FLEN_VALUE];
+ char oldcomm[FLEN_COMMENT];
+ char card[FLEN_CARD];
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ if (ffgkey(fptr, keyname, valstring, oldcomm, status) > 0)
+ return(*status); /* get old comment */
+
+ strcpy(valstring, "(" );
+ ffd2f(value[0], decim, tmpstring, status); /* convert to string */
+ strcat(valstring, tmpstring);
+ strcat(valstring, ", ");
+ ffd2f(value[1], decim, tmpstring, status); /* convert to string */
+ strcat(valstring, tmpstring);
+ strcat(valstring, ")");
+
+ if (!comm || comm[0] == '&') /* preserve the current comment string */
+ ffmkky(keyname, valstring, oldcomm, card, status);
+ else
+ ffmkky(keyname, valstring, comm, card, status);
+
+ ffmkey(fptr, card, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffmkym(fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - keyword name */
+ double *value, /* I - keyword value */
+ int decim, /* I - no of decimals */
+ char *comm, /* I - keyword comment */
+ int *status) /* IO - error status */
+{
+ char valstring[FLEN_VALUE], tmpstring[FLEN_VALUE];
+ char oldcomm[FLEN_COMMENT];
+ char card[FLEN_CARD];
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ if (ffgkey(fptr, keyname, valstring, oldcomm, status) > 0)
+ return(*status); /* get old comment */
+
+ strcpy(valstring, "(" );
+ ffd2e(value[0], decim, tmpstring, status); /* convert to string */
+ strcat(valstring, tmpstring);
+ strcat(valstring, ", ");
+ ffd2e(value[1], decim, tmpstring, status); /* convert to string */
+ strcat(valstring, tmpstring);
+ strcat(valstring, ")");
+
+ if (!comm || comm[0] == '&') /* preserve the current comment string */
+ ffmkky(keyname, valstring, oldcomm, card, status);
+ else
+ ffmkky(keyname, valstring, comm, card, status);
+
+ ffmkey(fptr, card, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffikyu(fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - keyword name */
+ char *comm, /* I - keyword comment */
+ int *status) /* IO - error status */
+/*
+ Insert a null-valued keyword and comment into the FITS header.
+*/
+{
+ char valstring[FLEN_VALUE];
+ char card[FLEN_CARD];
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ strcpy(valstring," "); /* create a dummy value string */
+ ffmkky(keyname, valstring, comm, card, status); /* construct the keyword*/
+ ffikey(fptr, card, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffikys(fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - keyword name */
+ char *value, /* I - keyword value */
+ char *comm, /* I - keyword comment */
+ int *status) /* IO - error status */
+{
+ char valstring[FLEN_VALUE];
+ char card[FLEN_CARD];
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ ffs2c(value, valstring, status); /* put quotes around the string */
+ ffmkky(keyname, valstring, comm, card, status); /* construct the keyword*/
+ ffikey(fptr, card, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffikls( fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - name of keyword to write */
+ char *value, /* I - keyword value */
+ char *comm, /* I - keyword comment */
+ int *status) /* IO - error status */
+/*
+ Insert a long string keyword. This routine supports the
+ HEASARC long string convention and can insert arbitrarily long string
+ keyword values. The value is continued over multiple keywords that
+ have the name COMTINUE without an equal sign in column 9 of the card.
+ This routine also supports simple string keywords which are less than
+ 69 characters in length.
+*/
+{
+ char valstring[FLEN_VALUE];
+ char card[FLEN_CARD];
+ char tstring[FLEN_VALUE], *cptr;
+ int next, remain, vlen, nquote, nchar, namelen, contin, tstatus = -1;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ /* construct the new keyword, and insert into header */
+ remain = strlen(value); /* number of characters to write out */
+ next = 0; /* pointer to next character to write */
+
+ /* count the number of single quote characters in the string */
+ nquote = 0;
+ cptr = strchr(value, '\''); /* search for quote character */
+
+ while (cptr) /* search for quote character */
+ {
+ nquote++; /* increment no. of quote characters */
+ cptr++; /* increment pointer to next character */
+ cptr = strchr(cptr, '\''); /* search for another quote char */
+ }
+
+ cptr = keyname;
+ while(*cptr == ' ') /* skip over leading spaces in name */
+ cptr++;
+
+ /* determine the number of characters that will fit on the line */
+ /* Note: each quote character is expanded to 2 quotes */
+
+ namelen = strlen(cptr);
+ if (namelen <= 8 && (fftkey(cptr, &tstatus) <= 0) )
+ {
+ /* This a normal 8-character FITS keyword */
+ nchar = 68 - nquote; /* max of 68 chars fit in a FITS string value */
+ }
+ else
+ {
+ /* This a HIERARCH keyword */
+ if (FSTRNCMP(cptr, "HIERARCH ", 9) &&
+ FSTRNCMP(cptr, "hierarch ", 9))
+ nchar = 66 - nquote - namelen;
+ else
+ nchar = 75 - nquote - namelen; /* don't count 'HIERARCH' twice */
+
+ }
+
+ contin = 0;
+ while (remain > 0)
+ {
+ strncpy(tstring, &value[next], nchar); /* copy string to temp buff */
+ tstring[nchar] = '\0';
+ ffs2c(tstring, valstring, status); /* put quotes around the string */
+
+ if (remain > nchar) /* if string is continued, put & as last char */
+ {
+ vlen = strlen(valstring);
+ nchar -= 1; /* outputting one less character now */
+
+ if (valstring[vlen-2] != '\'')
+ valstring[vlen-2] = '&'; /* over write last char with & */
+ else
+ { /* last char was a pair of single quotes, so over write both */
+ valstring[vlen-3] = '&';
+ valstring[vlen-1] = '\0';
+ }
+ }
+
+ if (contin) /* This is a CONTINUEd keyword */
+ {
+ ffmkky("CONTINUE", valstring, comm, card, status); /* make keyword */
+ strncpy(&card[8], " ", 2); /* overwrite the '=' */
+ }
+ else
+ {
+ ffmkky(keyname, valstring, comm, card, status); /* make keyword */
+ }
+
+ ffikey(fptr, card, status); /* insert the keyword */
+
+ contin = 1;
+ remain -= nchar;
+ next += nchar;
+ nchar = 68 - nquote;
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffikyl(fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - keyword name */
+ int value, /* I - keyword value */
+ char *comm, /* I - keyword comment */
+ int *status) /* IO - error status */
+{
+ char valstring[FLEN_VALUE];
+ char card[FLEN_CARD];
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ ffl2c(value, valstring, status); /* convert logical to 'T' or 'F' */
+ ffmkky(keyname, valstring, comm, card, status); /* construct the keyword*/
+ ffikey(fptr, card, status); /* write the keyword*/
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffikyj(fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - keyword name */
+ long value, /* I - keyword value */
+ char *comm, /* I - keyword comment */
+ int *status) /* IO - error status */
+{
+ char valstring[FLEN_VALUE];
+ char card[FLEN_CARD];
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ ffi2c(value, valstring, status); /* convert to formatted string */
+ ffmkky(keyname, valstring, comm, card, status); /* construct the keyword*/
+ ffikey(fptr, card, status); /* write the keyword*/
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffikyf(fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - keyword name */
+ float value, /* I - keyword value */
+ int decim, /* I - no of decimals */
+ char *comm, /* I - keyword comment */
+ int *status) /* IO - error status */
+{
+ char valstring[FLEN_VALUE];
+ char card[FLEN_CARD];
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ ffr2f(value, decim, valstring, status); /* convert to formatted string */
+ ffmkky(keyname, valstring, comm, card, status); /* construct the keyword*/
+ ffikey(fptr, card, status); /* write the keyword*/
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffikye(fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - keyword name */
+ float value, /* I - keyword value */
+ int decim, /* I - no of decimals */
+ char *comm, /* I - keyword comment */
+ int *status) /* IO - error status */
+{
+ char valstring[FLEN_VALUE];
+ char card[FLEN_CARD];
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ ffr2e(value, decim, valstring, status); /* convert to formatted string */
+ ffmkky(keyname, valstring, comm, card, status); /* construct the keyword*/
+ ffikey(fptr, card, status); /* write the keyword*/
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffikyg(fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - keyword name */
+ double value, /* I - keyword value */
+ int decim, /* I - no of decimals */
+ char *comm, /* I - keyword comment */
+ int *status) /* IO - error status */
+{
+ char valstring[FLEN_VALUE];
+ char card[FLEN_CARD];
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ ffd2f(value, decim, valstring, status); /* convert to formatted string */
+ ffmkky(keyname, valstring, comm, card, status); /* construct the keyword*/
+ ffikey(fptr, card, status); /* write the keyword*/
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffikyd(fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - keyword name */
+ double value, /* I - keyword value */
+ int decim, /* I - no of decimals */
+ char *comm, /* I - keyword comment */
+ int *status) /* IO - error status */
+{
+ char valstring[FLEN_VALUE];
+ char card[FLEN_CARD];
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ ffd2e(value, decim, valstring, status); /* convert to formatted string */
+ ffmkky(keyname, valstring, comm, card, status); /* construct the keyword*/
+ ffikey(fptr, card, status); /* write the keyword*/
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffikfc(fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - keyword name */
+ float *value, /* I - keyword value */
+ int decim, /* I - no of decimals */
+ char *comm, /* I - keyword comment */
+ int *status) /* IO - error status */
+{
+ char valstring[FLEN_VALUE], tmpstring[FLEN_VALUE];
+ char card[FLEN_CARD];
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ strcpy(valstring, "(" );
+ ffr2f(value[0], decim, tmpstring, status); /* convert to string */
+ strcat(valstring, tmpstring);
+ strcat(valstring, ", ");
+ ffr2f(value[1], decim, tmpstring, status); /* convert to string */
+ strcat(valstring, tmpstring);
+ strcat(valstring, ")");
+
+ ffmkky(keyname, valstring, comm, card, status); /* construct the keyword*/
+ ffikey(fptr, card, status); /* write the keyword*/
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffikyc(fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - keyword name */
+ float *value, /* I - keyword value */
+ int decim, /* I - no of decimals */
+ char *comm, /* I - keyword comment */
+ int *status) /* IO - error status */
+{
+ char valstring[FLEN_VALUE], tmpstring[FLEN_VALUE];
+ char card[FLEN_CARD];
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ strcpy(valstring, "(" );
+ ffr2e(value[0], decim, tmpstring, status); /* convert to string */
+ strcat(valstring, tmpstring);
+ strcat(valstring, ", ");
+ ffr2e(value[1], decim, tmpstring, status); /* convert to string */
+ strcat(valstring, tmpstring);
+ strcat(valstring, ")");
+
+ ffmkky(keyname, valstring, comm, card, status); /* construct the keyword*/
+ ffikey(fptr, card, status); /* write the keyword*/
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffikfm(fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - keyword name */
+ double *value, /* I - keyword value */
+ int decim, /* I - no of decimals */
+ char *comm, /* I - keyword comment */
+ int *status) /* IO - error status */
+{
+ char valstring[FLEN_VALUE], tmpstring[FLEN_VALUE];
+ char card[FLEN_CARD];
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+
+ strcpy(valstring, "(" );
+ ffd2f(value[0], decim, tmpstring, status); /* convert to string */
+ strcat(valstring, tmpstring);
+ strcat(valstring, ", ");
+ ffd2f(value[1], decim, tmpstring, status); /* convert to string */
+ strcat(valstring, tmpstring);
+ strcat(valstring, ")");
+
+ ffmkky(keyname, valstring, comm, card, status); /* construct the keyword*/
+ ffikey(fptr, card, status); /* write the keyword*/
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffikym(fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - keyword name */
+ double *value, /* I - keyword value */
+ int decim, /* I - no of decimals */
+ char *comm, /* I - keyword comment */
+ int *status) /* IO - error status */
+{
+ char valstring[FLEN_VALUE], tmpstring[FLEN_VALUE];
+ char card[FLEN_CARD];
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ strcpy(valstring, "(" );
+ ffd2e(value[0], decim, tmpstring, status); /* convert to string */
+ strcat(valstring, tmpstring);
+ strcat(valstring, ", ");
+ ffd2e(value[1], decim, tmpstring, status); /* convert to string */
+ strcat(valstring, tmpstring);
+ strcat(valstring, ")");
+
+ ffmkky(keyname, valstring, comm, card, status); /* construct the keyword*/
+ ffikey(fptr, card, status); /* write the keyword*/
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffirec(fitsfile *fptr, /* I - FITS file pointer */
+ int nkey, /* I - position to insert new keyword */
+ char *card, /* I - card string value */
+ int *status) /* IO - error status */
+{
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ ffmaky(fptr, nkey, status); /* move to insert position */
+ ffikey(fptr, card, status); /* insert the keyword card */
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffikey(fitsfile *fptr, /* I - FITS file pointer */
+ char *card, /* I - card string value */
+ int *status) /* IO - error status */
+/*
+ insert a keyword at the position of (fptr->Fptr)->nextkey
+*/
+{
+ int ii, len, nshift;
+ long nblocks;
+ OFF_T bytepos;
+ char *inbuff, *outbuff, *tmpbuff, buff1[FLEN_CARD], buff2[FLEN_CARD];
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ /* reset position to the correct HDU if necessary */
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+
+ if ( ((fptr->Fptr)->datastart - (fptr->Fptr)->headend) == 80) /* only room for END card */
+ {
+ nblocks = 1;
+ if (ffiblk(fptr, nblocks, 0, status) > 0) /* add new 2880-byte block*/
+ return(*status);
+ }
+
+ nshift=( (fptr->Fptr)->headend - (fptr->Fptr)->nextkey ) / 80; /* no. keywords to shift */
+
+ strncpy(buff2, card, 80); /* copy card to output buffer */
+ buff2[80] = '\0';
+
+ len = strlen(buff2);
+ for (ii=len; ii < 80; ii++) /* fill buffer with spaces if necessary */
+ buff2[ii] = ' ';
+
+ for (ii=0; ii < 8; ii++) /* make sure keyword name is uppercase */
+ buff2[ii] = toupper(buff2[ii]);
+
+ fftkey(buff2, status); /* test keyword name contains legal chars */
+ fftrec(buff2, status); /* test rest of keyword for legal chars */
+
+ inbuff = buff1;
+ outbuff = buff2;
+
+ bytepos = (fptr->Fptr)->nextkey; /* pointer to next keyword in header */
+ ffmbyt(fptr, bytepos, REPORT_EOF, status);
+
+ for (ii = 0; ii < nshift; ii++) /* shift each keyword down one position */
+ {
+ ffgbyt(fptr, 80, inbuff, status); /* read the current keyword */
+
+ ffmbyt(fptr, bytepos, REPORT_EOF, status); /* move back */
+ ffpbyt(fptr, 80, outbuff, status); /* overwrite with other buffer */
+
+ tmpbuff = inbuff; /* swap input and output buffers */
+ inbuff = outbuff;
+ outbuff = tmpbuff;
+
+ bytepos += 80;
+ }
+
+ ffpbyt(fptr, 80, outbuff, status); /* write the final keyword */
+
+ (fptr->Fptr)->headend += 80; /* increment the position of the END keyword */
+ (fptr->Fptr)->nextkey += 80; /* increment the pointer to next keyword */
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffdkey(fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - keyword name */
+ int *status) /* IO - error status */
+/*
+ delete a specified header keyword
+*/
+{
+ int keypos, len;
+ char valstring[FLEN_VALUE], comm[FLEN_COMMENT], value[FLEN_VALUE];
+ char message[FLEN_ERRMSG];
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ if (ffgkey(fptr, keyname, valstring, comm, status) > 0) /* read keyword */
+ {
+ sprintf(message, "Could not find the %s keyword to delete (ffdkey)",
+ keyname);
+ ffpmsg(message);
+ return(*status);
+ }
+
+ /* calc position of keyword in header */
+ keypos = (((fptr->Fptr)->nextkey) - ((fptr->Fptr)->headstart[(fptr->Fptr)->curhdu])) / 80;
+
+ ffdrec(fptr, keypos, status); /* delete the keyword */
+
+ /* check for string value which may be continued over multiple keywords */
+ ffc2s(valstring, value, status); /* remove quotes and trailing spaces */
+ len = strlen(value);
+
+ while (len && value[len - 1] == '&') /* ampersand used as continuation char */
+ {
+ ffgcnt(fptr, value, status);
+ if (*value)
+ {
+ ffdrec(fptr, keypos, status); /* delete the keyword */
+ len = strlen(value);
+ }
+ else /* a null valstring indicates no continuation */
+ len = 0;
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffdrec(fitsfile *fptr, /* I - FITS file pointer */
+ int keypos, /* I - position in header of keyword to delete */
+ int *status) /* IO - error status */
+/*
+ Delete a header keyword at position keypos. The 1st keyword is at keypos=1.
+*/
+{
+ int ii, nshift;
+ OFF_T bytepos;
+ char *inbuff, *outbuff, *tmpbuff, buff1[81], buff2[81];
+ char message[FLEN_ERRMSG];
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ /* reset position to the correct HDU if necessary */
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+
+ if (keypos < 1 ||
+ keypos > (fptr->Fptr)->headend - (fptr->Fptr)->headstart[(fptr->Fptr)->curhdu] / 80 )
+ return(*status = KEY_OUT_BOUNDS);
+
+ (fptr->Fptr)->nextkey = (fptr->Fptr)->headstart[(fptr->Fptr)->curhdu] + (keypos - 1) * 80;
+
+ nshift=( (fptr->Fptr)->headend - (fptr->Fptr)->nextkey ) / 80; /* no. keywords to shift */
+
+ if (nshift <= 0)
+ {
+ sprintf(message, "Cannot delete keyword number %d. It does not exist.",
+ keypos);
+ ffpmsg(message);
+ return(*status = KEY_OUT_BOUNDS);
+ }
+
+ bytepos = (fptr->Fptr)->headend - 80; /* last keyword in header */
+
+ /* construct a blank keyword */
+ strcpy(buff2, " ");
+ strcat(buff2, " ");
+ inbuff = buff1;
+ outbuff = buff2;
+ for (ii = 0; ii < nshift; ii++) /* shift each keyword up one position */
+ {
+
+ ffmbyt(fptr, bytepos, REPORT_EOF, status);
+ ffgbyt(fptr, 80, inbuff, status); /* read the current keyword */
+
+ ffmbyt(fptr, bytepos, REPORT_EOF, status);
+ ffpbyt(fptr, 80, outbuff, status); /* overwrite with next keyword */
+
+ tmpbuff = inbuff; /* swap input and output buffers */
+ inbuff = outbuff;
+ outbuff = tmpbuff;
+
+ bytepos -= 80;
+ }
+
+ (fptr->Fptr)->headend -= 80; /* decrement the position of the END keyword */
+ return(*status);
+}
+
diff --git a/pkg/tbtables/cfitsio/pctype.h b/pkg/tbtables/cfitsio/pctype.h
new file mode 100644
index 00000000..2ef4a675
--- /dev/null
+++ b/pkg/tbtables/cfitsio/pctype.h
@@ -0,0 +1,155 @@
+/*
+ * These ones are necessary to override the behaviour of
+ * PINT_cfB, which puts the & on before getting to the
+ * TYPE specific PCINT_cfPP...
+ * The only way to do this is to introduce PCDOUBLE_cfINT,
+ * which means we use PCINT for alot of the generic macros.
+ */
+
+#define PCINT_cfAA PINT_cfAA
+#define PCINT_cfN PINT_cfN
+#define PCINT_cfV PINT_cfV
+#define PCINT_cfZ(T,I,A) (__cfztringv[I]= (int ) *A),
+#define PCINT_cfSEP INT_cfSEP
+#define PCINT_cfCC PINT_cfCC
+#define PCINT_cfB(T,A) _(T,_cfPP) A
+#define PCINT_cfU PINT_cfU
+
+/* These are the real TYPE specific ones, and will need to be
+ * duplicated for FLOAT,...
+ */
+#define PCINT_cfINT PCDOUBLE_cfINT
+#define PCINT_cfAAP(A, B) A
+#define PCINT_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define PCINT_cfTYPE int
+#define PCINT_cfVP(A,B) int B = (int) *A; /* For ZSTRINGV_ARGS */
+#define PCINT_cfPP
+#define PCINT_cfCCC(A,B) A
+
+#define PCFLOAT_cfINT PCDOUBLE_cfINT
+#define PCFLOAT_cfAAP(A, B) A
+#define PCFLOAT_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define PCFLOAT_cfTYPE float
+#define PCFLOAT_cfVP PCINT_cfVP /* For ZSTRINGV_ARGS */
+#define PCFLOAT_cfPP
+#define PCFLOAT_cfCCC(A,B) A
+
+#define PCDOUBLE_cfINT(N,A,B,X,Y,Z) _(CFARGS,N)(A,PCINT,B,X,Y,Z,0)
+#define PCDOUBLE_cfAAP(A, B) A
+#define PCDOUBLE_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define PCDOUBLE_cfTYPE double
+#define PCDOUBLE_cfVP PCINT_cfVP /* For ZSTRINGV_ARGS */
+#define PCDOUBLE_cfPP
+#define PCDOUBLE_cfCCC(A,B) A
+
+#define PCLOGICAL_cfINT PCDOUBLE_cfINT
+#define PCLOGICAL_cfA(M,I,A,B) *A=C2FLOGICAL(*A);
+#define PCLOGICAL_cfAAP(A,B) B = A
+#define PCLOGICAL_cfC(A,B,C) *A=C2FLOGICAL(*A);
+#define PCLOGICAL_cfH(S,U,B)
+#define PCLOGICAL_cfJ(B)
+#define PCLOGICAL_cfW(A,B) PLOGICAL_cfW(A,B)
+#define PCLOGICAL_cfS(M,I,A)
+#define PCLOGICAL_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,PCLOGICAL,A,B,C,D,E)
+#define PCLOGICAL_cfTYPE int
+#define PCLOGICAL_cfVP PLOGICAL_cfVP /* For ZSTRINGV_ARGS */
+#define PCLOGICAL_cfPP
+#define PCLOGICAL_cfKK PLOGICAL_cfKK
+#define PCLOGICAL_cfCCC(A,B) B = A
+
+/*
+ * I can't find where the following three defines are used...
+ * So they may well be wrong.
+ */
+
+#define PCLOGICAL_cfQ(B)
+#define PCLOGICAL_cfR(A,B,D) *A=C2FLOGICAL(*A);
+#define PCLOGICAL_cfT(M,I,A,B,D) ((*A=F2CLOGICAL(*A)),A)
+
+/* This is to get PZTRINGS to work for dynamically allocated
+ * Contiguous arrays... The problem was that the array is massaged
+ * coming in with the call: c2fstrv( A[0], A[0],... )
+ * and coming out with: f2cstrv( (char *) A, (char *) A,... )
+ *
+ * If you dynamically allocate an array with the trick:
+ *
+ * char ** A;
+ * A = (char **) malloc ( nelements * sizeof(char *) );
+ * A[0] = (char *) malloc (nelements * elemSize * sizeof (char) );
+ * for ( i = 1; i < nelements; i++) A[i] = A[0] + i * elemSize;
+ *
+ * Then the coming in call will kill you if you pass in A, and the
+ * coming out call will kill you if you pass in A[0]...
+ * So, I change the coming in call to (char *)A, and you must then
+ * pass in A[0].
+ *
+ */
+
+
+#undef PZTRINGV_cfA
+#define PZTRINGV_cfA(M,I,A,B) APAZTRINGV_cfA(M,I,A,B, \
+ (_3(M,_ELEMS_,I))*(( _3(M,_ELEMLEN_,I))+1), \
+ (_3(M,_ELEMS_,I)),(_3(M,_ELEMLEN_,I))+1)
+#ifdef vmsFortran
+#define AAZTRINGV_cfA(M,I,A,B, sA,filA,silA) \
+ initfstr(B,malloc((sA)-(filA)),(filA),(silA)-1), \ c2fstrv((char *) A,B.dsc$a_pointer,(silA),(sA));
+#define APAZTRINGV_cfA(M,I,A,B, sA,filA,silA) \
+ initfstr(B,(char *) A,(filA),(silA)-1),c2fstrv((char *) A,(char *)A,(silA),(sA));
+#else
+#define AAZTRINGV_cfA(M,I,A,B, sA,filA,silA) \
+ (B.s=malloc((sA)-(filA)),B.fs=c2fstrv((char *)A,B.s,(B.flen=(silA)-1)+1,(sA)));
+#define APAZTRINGV_cfA(M,I,A,B, sA,filA,silA) \
+ B.fs=c2fstrv((char *) A,(char *) A,(B.flen=(silA)-1)+1,B.sizeofA=(sA));
+#endif
+
+
+/*
+ * This allows for character arrays longer than an unsigned short...
+ */
+
+#ifndef vmsFortran
+#undef STRING_cfV
+#undef PSTRINGV_cfV
+#define STRING_cfV(T,A,B,F) struct {unsigned int clen, flen;} B;
+#define PSTRINGV_cfV(T,A,B,F) struct {char *fs; unsigned int sizeofA, flen;} B;
+#endif
+
+/*
+ * This is to introduce a PZTRING ( NO V ) type
+ */
+
+
+#ifdef vmsFortran
+#define PZTRING_cfV(T,A,B,F) static fstring B={0,DSC$K_DTYPE_T,DSC$K_CLASS_S,NULL};
+#define APATRING_cfA(M,I,A,B,silA) \
+ (B.dsc$w_length=strlen(A),B.dsc$a_pointer=A, \
+ B.dsc$w_length >= silA?0:(memset((A)+B.dsc$w_length,' ',silA-B.dsc$w_length-1), \
+ A[B.dsc$w_length=silA-1]='\0'));
+#define PZTRING_cfC(A,B,C) \
+ (B.dsc$w_length=strlen(A),B.dsc$a_pointer=A, \
+ B.dsc$w_length >= C?0:(memset((A)+B.dsc$w_length,' ',C-B.dsc$w_length-1), \
+ A[B.dsc$w_length=C-1]='\0'));
+#else
+#define PZTRING_cfV(T,A,B,F) int B;
+#define APATRING_cfA(M,I,A,B,silA) \
+ (B=strlen(A),B >= silA?0:(memset((A)+B,' ',silA-B-1)),A[B = silA - 1]='\0');
+#define PZTRING_cfC(A,B,C) \
+ (B=strlen(A),B > C?0:(memset((A)+B,' ',(C - 1)-B-1)),A[B = C - 1]='\0');
+#endif
+
+#define PZTRING_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,PZTRING,A,B,C,D,E)
+#define PZTRING_cfINT PVOID_cfINT
+#define PZTRING_cfA(M,I,A,B) APATRING_cfA(M,I,A,B,(_3(M,_ELEMLEN_,I))+1)
+#define PZTRING_cfAA PSTRING_cfCC
+#define PZTRING_cfB PSTRING_cfB
+
+#define PZTRING_cfCC PSTRING_cfCC
+#define PZTRING_cfJ PSTRING_cfJ
+#define PZTRING_cfH STRING_cfH
+#define PZTRING_cfN(T,A) STRING_cfN(T,A) /* CRAY insists on arg.'s here. */
+#define PZTRING_cfS(M,I,A) ,( _3(M,_ELEMLEN_,I) + 1 )
+#define PZTRING_cfU(T,A) char *A
+#define PZTRING_cfW(A,B) kill_trailing(A,' ');
+#define PZTRING_cfZ(T,I,A)
+#define PZTRING_cfSEP INT_cfSEP
+#define PZTRING_cfKK STRING_cfKK
diff --git a/pkg/tbtables/cfitsio/pliocomp.c b/pkg/tbtables/cfitsio/pliocomp.c
new file mode 100644
index 00000000..7550ed67
--- /dev/null
+++ b/pkg/tbtables/cfitsio/pliocomp.c
@@ -0,0 +1,331 @@
+/* stdlib is needed for the abs function */
+#include <stdlib.h>
+/*
+ The following prototype code was provided by Doug Tody, NRAO, for
+ performing conversion between pixel arrays and line lists. The
+ compression technique is used in IRAF.
+*/
+int pl_p2li (int *pxsrc, int xs, short *lldst, int npix);
+int pl_l2pi (short *ll_src, int xs, int *px_dst, int npix);
+
+
+/*
+ * PL_P2L -- Convert a pixel array to a line list. The length of the list is
+ * returned as the function value.
+ *
+ * Translated from the SPP version using xc -f, f2c. 8Sep99 DCT.
+ */
+
+#ifndef min
+#define min(a,b) (((a)<(b))?(a):(b))
+#endif
+#ifndef max
+#define max(a,b) (((a)>(b))?(a):(b))
+#endif
+
+int pl_p2li (int *pxsrc, int xs, short *lldst, int npix)
+/* int *pxsrc; input pixel array */
+/* int xs; starting index in pxsrc (?) */
+/* short *lldst; encoded line list */
+/* int npix; number of pixels to convert */
+{
+ /* System generated locals */
+ int ret_val, i__1, i__2, i__3;
+
+ /* Local variables */
+ static int zero, v, x1, hi, ip, dv, xe, np, op, iz, nv, pv, nz;
+
+ /* Parameter adjustments */
+ --lldst;
+ --pxsrc;
+
+ /* Function Body */
+ if (! (npix <= 0)) {
+ goto L110;
+ }
+ ret_val = 0;
+ goto L100;
+L110:
+ lldst[3] = -100;
+ lldst[2] = 7;
+ lldst[1] = 0;
+ lldst[6] = 0;
+ lldst[7] = 0;
+ xe = xs + npix - 1;
+ op = 8;
+ zero = 0;
+/* Computing MAX */
+ i__1 = zero, i__2 = pxsrc[xs];
+ pv = max(i__1,i__2);
+ x1 = xs;
+ iz = xs;
+ hi = 1;
+ i__1 = xe;
+ for (ip = xs; ip <= i__1; ++ip) {
+ if (! (ip < xe)) {
+ goto L130;
+ }
+/* Computing MAX */
+ i__2 = zero, i__3 = pxsrc[ip + 1];
+ nv = max(i__2,i__3);
+ if (! (nv == pv)) {
+ goto L140;
+ }
+ goto L120;
+L140:
+ if (! (pv == 0)) {
+ goto L150;
+ }
+ pv = nv;
+ x1 = ip + 1;
+ goto L120;
+L150:
+ goto L131;
+L130:
+ if (! (pv == 0)) {
+ goto L160;
+ }
+ x1 = xe + 1;
+L160:
+L131:
+ np = ip - x1 + 1;
+ nz = x1 - iz;
+ if (! (pv > 0)) {
+ goto L170;
+ }
+ dv = pv - hi;
+ if (! (dv != 0)) {
+ goto L180;
+ }
+ hi = pv;
+ if (! (abs(dv) > 4095)) {
+ goto L190;
+ }
+ lldst[op] = (short) ((pv & 4095) + 4096);
+ ++op;
+ lldst[op] = (short) (pv / 4096);
+ ++op;
+ goto L191;
+L190:
+ if (! (dv < 0)) {
+ goto L200;
+ }
+ lldst[op] = (short) (-dv + 12288);
+ goto L201;
+L200:
+ lldst[op] = (short) (dv + 8192);
+L201:
+ ++op;
+ if (! (np == 1 && nz == 0)) {
+ goto L210;
+ }
+ v = lldst[op - 1];
+ lldst[op - 1] = (short) (v | 16384);
+ goto L91;
+L210:
+L191:
+L180:
+L170:
+ if (! (nz > 0)) {
+ goto L220;
+ }
+L230:
+ if (! (nz > 0)) {
+ goto L232;
+ }
+ lldst[op] = (short) min(4095,nz);
+ ++op;
+/* L231: */
+ nz += -4095;
+ goto L230;
+L232:
+ if (! (np == 1 && pv > 0)) {
+ goto L240;
+ }
+ lldst[op - 1] = (short) (lldst[op - 1] + 20481);
+ goto L91;
+L240:
+L220:
+L250:
+ if (! (np > 0)) {
+ goto L252;
+ }
+ lldst[op] = (short) (min(4095,np) + 16384);
+ ++op;
+/* L251: */
+ np += -4095;
+ goto L250;
+L252:
+L91:
+ x1 = ip + 1;
+ iz = x1;
+ pv = nv;
+L120:
+ ;
+ }
+/* L121: */
+ lldst[4] = (short) ((op - 1) % 32768);
+ lldst[5] = (short) ((op - 1) / 32768);
+ ret_val = op - 1;
+ goto L100;
+L100:
+ return ret_val;
+} /* plp2li_ */
+
+/*
+ * PL_L2PI -- Translate a PLIO line list into an integer pixel array.
+ * The number of pixels output (always npix) is returned as the function
+ * value.
+ *
+ * Translated from the SPP version using xc -f, f2c. 8Sep99 DCT.
+ */
+
+int pl_l2pi (short *ll_src, int xs, int *px_dst, int npix)
+/* short *ll_src; encoded line list */
+/* int xs; starting index in ll_src */
+/* int *px_dst; output pixel array */
+/* int npix; number of pixels to convert */
+{
+ /* System generated locals */
+ int ret_val, i__1, i__2;
+
+ /* Local variables */
+ static int data, sw0001, otop, i__, lllen, i1, i2, x1, x2, ip, xe, np,
+ op, pv, opcode, llfirt;
+ static int skipwd;
+
+ /* Parameter adjustments */
+ --px_dst;
+ --ll_src;
+
+ /* Function Body */
+ if (! (ll_src[3] > 0)) {
+ goto L110;
+ }
+ lllen = ll_src[3];
+ llfirt = 4;
+ goto L111;
+L110:
+ lllen = (ll_src[5] << 15) + ll_src[4];
+ llfirt = ll_src[2] + 1;
+L111:
+ if (! (npix <= 0 || lllen <= 0)) {
+ goto L120;
+ }
+ ret_val = 0;
+ goto L100;
+L120:
+ xe = xs + npix - 1;
+ skipwd = 0;
+ op = 1;
+ x1 = 1;
+ pv = 1;
+ i__1 = lllen;
+ for (ip = llfirt; ip <= i__1; ++ip) {
+ if (! skipwd) {
+ goto L140;
+ }
+ skipwd = 0;
+ goto L130;
+L140:
+ opcode = ll_src[ip] / 4096;
+ data = ll_src[ip] & 4095;
+ sw0001 = opcode;
+ goto L150;
+L160:
+ x2 = x1 + data - 1;
+ i1 = max(x1,xs);
+ i2 = min(x2,xe);
+ np = i2 - i1 + 1;
+ if (! (np > 0)) {
+ goto L170;
+ }
+ otop = op + np - 1;
+ if (! (opcode == 4)) {
+ goto L180;
+ }
+ i__2 = otop;
+ for (i__ = op; i__ <= i__2; ++i__) {
+ px_dst[i__] = pv;
+/* L190: */
+ }
+/* L191: */
+ goto L181;
+L180:
+ i__2 = otop;
+ for (i__ = op; i__ <= i__2; ++i__) {
+ px_dst[i__] = 0;
+/* L200: */
+ }
+/* L201: */
+ if (! (opcode == 5 && i2 == x2)) {
+ goto L210;
+ }
+ px_dst[otop] = pv;
+L210:
+L181:
+ op = otop + 1;
+L170:
+ x1 = x2 + 1;
+ goto L151;
+L220:
+ pv = (ll_src[ip + 1] << 12) + data;
+ skipwd = 1;
+ goto L151;
+L230:
+ pv += data;
+ goto L151;
+L240:
+ pv -= data;
+ goto L151;
+L250:
+ pv += data;
+ goto L91;
+L260:
+ pv -= data;
+L91:
+ if (! (x1 >= xs && x1 <= xe)) {
+ goto L270;
+ }
+ px_dst[op] = pv;
+ ++op;
+L270:
+ ++x1;
+ goto L151;
+L150:
+ ++sw0001;
+ if (sw0001 < 1 || sw0001 > 8) {
+ goto L151;
+ }
+ switch ((int)sw0001) {
+ case 1: goto L160;
+ case 2: goto L220;
+ case 3: goto L230;
+ case 4: goto L240;
+ case 5: goto L160;
+ case 6: goto L160;
+ case 7: goto L250;
+ case 8: goto L260;
+ }
+L151:
+ if (! (x1 > xe)) {
+ goto L280;
+ }
+ goto L131;
+L280:
+L130:
+ ;
+ }
+L131:
+ i__1 = npix;
+ for (i__ = op; i__ <= i__1; ++i__) {
+ px_dst[i__] = 0;
+/* L290: */
+ }
+/* L291: */
+ ret_val = npix;
+ goto L100;
+L100:
+ return ret_val;
+} /* pll2pi_ */
+
diff --git a/pkg/tbtables/cfitsio/putcol.c b/pkg/tbtables/cfitsio/putcol.c
new file mode 100644
index 00000000..348d0930
--- /dev/null
+++ b/pkg/tbtables/cfitsio/putcol.c
@@ -0,0 +1,1714 @@
+/* This file, putcol.c, contains routines that write data elements to */
+/* a FITS image or table. These are the generic routines. */
+
+/* The FITSIO software was written by William Pence at the High Energy */
+/* Astrophysic Science Archive Research Center (HEASARC) at the NASA */
+/* Goddard Space Flight Center. */
+
+#include <string.h>
+#include <stdlib.h>
+#include <limits.h>
+#include "fitsio2.h"
+
+OFF_T large_first_elem_val = 0; /* used to pass large firstelem values */
+
+/*--------------------------------------------------------------------------*/
+int ffppx( fitsfile *fptr, /* I - FITS file pointer */
+ int datatype, /* I - datatype of the value */
+ long *firstpix, /* I - coord of first pixel to write(1 based) */
+ long nelem, /* I - number of values to write */
+ void *array, /* I - array of values that are written */
+ int *status) /* IO - error status */
+/*
+ Write an array of pixels to the primary array. The datatype of the
+ input array is defined by the 2nd argument. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being written). This routine
+ is simillar to ffppr, except it supports writing large images with
+ more than 2.1E9 pixels.
+*/
+{
+ int naxis, ii;
+ long naxes[9], firstelem, group = 1;
+ OFF_T dimsize = 1;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ /* get the size of the image */
+ ffgidm(fptr, &naxis, status);
+ ffgisz(fptr, 9, naxes, status);
+
+ /* store the actual first element value in a external variable */
+ /* because we can't pass the value directly to the lower routine */
+ /* because the parameter is declared as 'long' instead of 'off_t'. */
+
+ large_first_elem_val = 0;
+ for (ii=0; ii < naxis; ii++)
+ {
+ large_first_elem_val += ((firstpix[ii] - 1) * dimsize);
+ dimsize *= naxes[ii];
+ }
+ large_first_elem_val++;
+
+ firstelem = USE_LARGE_VALUE; /* special flag value */
+
+ if (datatype == TBYTE)
+ {
+ ffpprb(fptr, group, firstelem, nelem, (unsigned char *) array, status);
+ }
+ else if (datatype == TSBYTE)
+ {
+ ffpprsb(fptr, group, firstelem, nelem, (signed char *) array, status);
+ }
+ else if (datatype == TUSHORT)
+ {
+ ffpprui(fptr, group, firstelem, nelem, (unsigned short *) array,
+ status);
+ }
+ else if (datatype == TSHORT)
+ {
+ ffppri(fptr, group, firstelem, nelem, (short *) array, status);
+ }
+ else if (datatype == TUINT)
+ {
+ ffppruk(fptr, group, firstelem, nelem, (unsigned int *) array, status);
+ }
+ else if (datatype == TINT)
+ {
+ ffpprk(fptr, group, firstelem, nelem, (int *) array, status);
+ }
+ else if (datatype == TULONG)
+ {
+ ffppruj(fptr, group, firstelem, nelem, (unsigned long *) array, status);
+ }
+ else if (datatype == TLONG)
+ {
+ ffpprj(fptr, group, firstelem, nelem, (long *) array, status);
+ }
+ else if (datatype == TLONGLONG)
+ {
+ ffpprjj(fptr, group, firstelem, nelem, (LONGLONG *) array, status);
+ }
+ else if (datatype == TFLOAT)
+ {
+ ffppre(fptr, group, firstelem, nelem, (float *) array, status);
+ }
+ else if (datatype == TDOUBLE)
+ {
+ ffpprd(fptr, group, firstelem, nelem, (double *) array, status);
+ }
+ else
+ *status = BAD_DATATYPE;
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffppxn( fitsfile *fptr, /* I - FITS file pointer */
+ int datatype, /* I - datatype of the value */
+ long *firstpix, /* I - first vector element to write(1 = 1st) */
+ long nelem, /* I - number of values to write */
+ void *array, /* I - array of values that are written */
+ void *nulval, /* I - pointer to the null value */
+ int *status) /* IO - error status */
+/*
+ Write an array of values to the primary array. The datatype of the
+ input array is defined by the 2nd argument. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being written).
+*/
+{
+ int naxis, ii;
+ long naxes[9], firstelem, group = 1;
+ OFF_T dimsize = 1;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ if (nulval == NULL) /* null value not defined? */
+ {
+ ffppx(fptr, datatype, firstpix, nelem, array, status);
+ return(*status);
+ }
+
+ /* get the size of the image */
+ ffgidm(fptr, &naxis, status);
+ ffgisz(fptr, 9, naxes, status);
+
+ /* store the actual first element value in a external variable */
+ /* because we can't pass the value directly to the lower routine */
+ /* because the parameter is declared as 'long' instead of 'off_t'. */
+
+ large_first_elem_val = 0;
+ for (ii=0; ii < naxis; ii++)
+ {
+ large_first_elem_val += ((firstpix[ii] - 1) * dimsize);
+ dimsize *= naxes[ii];
+ }
+ large_first_elem_val++;
+
+ firstelem = USE_LARGE_VALUE; /* special flag value */
+
+ if (datatype == TBYTE)
+ {
+ ffppnb(fptr, group, firstelem, nelem, (unsigned char *) array,
+ *(unsigned char *) nulval, status);
+ }
+ else if (datatype == TSBYTE)
+ {
+ ffppnsb(fptr, group, firstelem, nelem, (signed char *) array,
+ *(signed char *) nulval, status);
+ }
+ else if (datatype == TUSHORT)
+ {
+ ffppnui(fptr, group, firstelem, nelem, (unsigned short *) array,
+ *(unsigned short *) nulval,status);
+ }
+ else if (datatype == TSHORT)
+ {
+ ffppni(fptr, group, firstelem, nelem, (short *) array,
+ *(short *) nulval, status);
+ }
+ else if (datatype == TUINT)
+ {
+ ffppnuk(fptr, group, firstelem, nelem, (unsigned int *) array,
+ *(unsigned int *) nulval, status);
+ }
+ else if (datatype == TINT)
+ {
+ ffppnk(fptr, group, firstelem, nelem, (int *) array,
+ *(int *) nulval, status);
+ }
+ else if (datatype == TULONG)
+ {
+ ffppnuj(fptr, group, firstelem, nelem, (unsigned long *) array,
+ *(unsigned long *) nulval,status);
+ }
+ else if (datatype == TLONG)
+ {
+ ffppnj(fptr, group, firstelem, nelem, (long *) array,
+ *(long *) nulval, status);
+ }
+ else if (datatype == TLONGLONG)
+ {
+ ffppnjj(fptr, group, firstelem, nelem, (LONGLONG *) array,
+ *(LONGLONG *) nulval, status);
+ }
+ else if (datatype == TFLOAT)
+ {
+ ffppne(fptr, group, firstelem, nelem, (float *) array,
+ *(float *) nulval, status);
+ }
+ else if (datatype == TDOUBLE)
+ {
+ ffppnd(fptr, group, firstelem, nelem, (double *) array,
+ *(double *) nulval, status);
+ }
+ else
+ *status = BAD_DATATYPE;
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffppr( fitsfile *fptr, /* I - FITS file pointer */
+ int datatype, /* I - datatype of the value */
+ long firstelem, /* I - first vector element to write(1 = 1st) */
+ long nelem, /* I - number of values to write */
+ void *array, /* I - array of values that are written */
+ int *status) /* IO - error status */
+/*
+ Write an array of values to the primary array. The datatype of the
+ input array is defined by the 2nd argument. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being written).
+*/
+{
+ long group = 1;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ if (datatype == TBYTE)
+ {
+ ffpprb(fptr, group, firstelem, nelem, (unsigned char *) array, status);
+ }
+ else if (datatype == TSBYTE)
+ {
+ ffpprsb(fptr, group, firstelem, nelem, (signed char *) array, status);
+ }
+ else if (datatype == TUSHORT)
+ {
+ ffpprui(fptr, group, firstelem, nelem, (unsigned short *) array,
+ status);
+ }
+ else if (datatype == TSHORT)
+ {
+ ffppri(fptr, group, firstelem, nelem, (short *) array, status);
+ }
+ else if (datatype == TUINT)
+ {
+ ffppruk(fptr, group, firstelem, nelem, (unsigned int *) array, status);
+ }
+ else if (datatype == TINT)
+ {
+ ffpprk(fptr, group, firstelem, nelem, (int *) array, status);
+ }
+ else if (datatype == TULONG)
+ {
+ ffppruj(fptr, group, firstelem, nelem, (unsigned long *) array, status);
+ }
+ else if (datatype == TLONG)
+ {
+ ffpprj(fptr, group, firstelem, nelem, (long *) array, status);
+ }
+ else if (datatype == TLONGLONG)
+ {
+ ffpprjj(fptr, group, firstelem, nelem, (LONGLONG *) array, status);
+ }
+ else if (datatype == TFLOAT)
+ {
+ ffppre(fptr, group, firstelem, nelem, (float *) array, status);
+ }
+ else if (datatype == TDOUBLE)
+ {
+ ffpprd(fptr, group, firstelem, nelem, (double *) array, status);
+ }
+ else
+ *status = BAD_DATATYPE;
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffppn( fitsfile *fptr, /* I - FITS file pointer */
+ int datatype, /* I - datatype of the value */
+ long firstelem, /* I - first vector element to write(1 = 1st) */
+ long nelem, /* I - number of values to write */
+ void *array, /* I - array of values that are written */
+ void *nulval, /* I - pointer to the null value */
+ int *status) /* IO - error status */
+/*
+ Write an array of values to the primary array. The datatype of the
+ input array is defined by the 2nd argument. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being written).
+*/
+{
+ long group = 1;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ if (nulval == NULL) /* null value not defined? */
+ {
+ ffppr(fptr, datatype, firstelem, nelem, array, status);
+ return(*status);
+ }
+
+ if (datatype == TBYTE)
+ {
+ ffppnb(fptr, group, firstelem, nelem, (unsigned char *) array,
+ *(unsigned char *) nulval, status);
+ }
+ else if (datatype == TSBYTE)
+ {
+ ffppnsb(fptr, group, firstelem, nelem, (signed char *) array,
+ *(signed char *) nulval, status);
+ }
+ else if (datatype == TUSHORT)
+ {
+ ffppnui(fptr, group, firstelem, nelem, (unsigned short *) array,
+ *(unsigned short *) nulval,status);
+ }
+ else if (datatype == TSHORT)
+ {
+ ffppni(fptr, group, firstelem, nelem, (short *) array,
+ *(short *) nulval, status);
+ }
+ else if (datatype == TUINT)
+ {
+ ffppnuk(fptr, group, firstelem, nelem, (unsigned int *) array,
+ *(unsigned int *) nulval, status);
+ }
+ else if (datatype == TINT)
+ {
+ ffppnk(fptr, group, firstelem, nelem, (int *) array,
+ *(int *) nulval, status);
+ }
+ else if (datatype == TULONG)
+ {
+ ffppnuj(fptr, group, firstelem, nelem, (unsigned long *) array,
+ *(unsigned long *) nulval,status);
+ }
+ else if (datatype == TLONG)
+ {
+ ffppnj(fptr, group, firstelem, nelem, (long *) array,
+ *(long *) nulval, status);
+ }
+ else if (datatype == TLONGLONG)
+ {
+ ffppnjj(fptr, group, firstelem, nelem, (LONGLONG *) array,
+ *(LONGLONG *) nulval, status);
+ }
+ else if (datatype == TFLOAT)
+ {
+ ffppne(fptr, group, firstelem, nelem, (float *) array,
+ *(float *) nulval, status);
+ }
+ else if (datatype == TDOUBLE)
+ {
+ ffppnd(fptr, group, firstelem, nelem, (double *) array,
+ *(double *) nulval, status);
+ }
+ else
+ *status = BAD_DATATYPE;
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpss( fitsfile *fptr, /* I - FITS file pointer */
+ int datatype, /* I - datatype of the value */
+ long *blc, /* I - 'bottom left corner' of the subsection */
+ long *trc , /* I - 'top right corner' of the subsection */
+ void *array, /* I - array of values that are written */
+ int *status) /* IO - error status */
+/*
+ Write a section of values to the primary array. The datatype of the
+ input array is defined by the 2nd argument. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being written).
+*/
+{
+ int naxis;
+ long naxes[9];
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ /* get the size of the image */
+ ffgidm(fptr, &naxis, status);
+ ffgisz(fptr, 9, naxes, status);
+
+ if (datatype == TBYTE)
+ {
+ ffpssb(fptr, 1, naxis, naxes, blc, trc,
+ (unsigned char *) array, status);
+ }
+ else if (datatype == TSBYTE)
+ {
+ ffpsssb(fptr, 1, naxis, naxes, blc, trc,
+ (signed char *) array, status);
+ }
+ else if (datatype == TUSHORT)
+ {
+ ffpssui(fptr, 1, naxis, naxes, blc, trc,
+ (unsigned short *) array, status);
+ }
+ else if (datatype == TSHORT)
+ {
+ ffpssi(fptr, 1, naxis, naxes, blc, trc,
+ (short *) array, status);
+ }
+ else if (datatype == TUINT)
+ {
+ ffpssuk(fptr, 1, naxis, naxes, blc, trc,
+ (unsigned int *) array, status);
+ }
+ else if (datatype == TINT)
+ {
+ ffpssk(fptr, 1, naxis, naxes, blc, trc,
+ (int *) array, status);
+ }
+ else if (datatype == TULONG)
+ {
+ ffpssuj(fptr, 1, naxis, naxes, blc, trc,
+ (unsigned long *) array, status);
+ }
+ else if (datatype == TLONG)
+ {
+ ffpssj(fptr, 1, naxis, naxes, blc, trc,
+ (long *) array, status);
+ }
+ else if (datatype == TLONGLONG)
+ {
+ ffpssjj(fptr, 1, naxis, naxes, blc, trc,
+ (LONGLONG *) array, status);
+ } else if (datatype == TFLOAT)
+ {
+ ffpsse(fptr, 1, naxis, naxes, blc, trc,
+ (float *) array, status);
+ }
+ else if (datatype == TDOUBLE)
+ {
+ ffpssd(fptr, 1, naxis, naxes, blc, trc,
+ (double *) array, status);
+ }
+ else
+ *status = BAD_DATATYPE;
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpcl( fitsfile *fptr, /* I - FITS file pointer */
+ int datatype, /* I - datatype of the value */
+ int colnum, /* I - number of column to write (1 = 1st col) */
+ long firstrow, /* I - first row to write (1 = 1st row) */
+ long firstelem, /* I - first vector element to write (1 = 1st) */
+ long nelem, /* I - number of elements to write */
+ void *array, /* I - array of values that are written */
+ int *status) /* IO - error status */
+/*
+ Write an array of values to a table column. The datatype of the
+ input array is defined by the 2nd argument. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS column is not the same as the array being written).
+*/
+{
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ if (datatype == TBIT)
+ {
+ ffpclx(fptr, colnum, firstrow, firstelem, nelem, (char *) array,
+ status);
+ }
+ else if (datatype == TBYTE)
+ {
+ ffpclb(fptr, colnum, firstrow, firstelem, nelem, (unsigned char *) array,
+ status);
+ }
+ else if (datatype == TSBYTE)
+ {
+ ffpclsb(fptr, colnum, firstrow, firstelem, nelem, (signed char *) array,
+ status);
+ }
+ else if (datatype == TUSHORT)
+ {
+ ffpclui(fptr, colnum, firstrow, firstelem, nelem,
+ (unsigned short *) array, status);
+ }
+ else if (datatype == TSHORT)
+ {
+ ffpcli(fptr, colnum, firstrow, firstelem, nelem, (short *) array,
+ status);
+ }
+ else if (datatype == TUINT)
+ {
+ ffpcluk(fptr, colnum, firstrow, firstelem, nelem, (unsigned int *) array,
+ status);
+ }
+ else if (datatype == TINT)
+ {
+ ffpclk(fptr, colnum, firstrow, firstelem, nelem, (int *) array,
+ status);
+ }
+ else if (datatype == TULONG)
+ {
+ ffpcluj(fptr, colnum, firstrow, firstelem, nelem, (unsigned long *) array,
+ status);
+ }
+ else if (datatype == TLONG)
+ {
+ ffpclj(fptr, colnum, firstrow, firstelem, nelem, (long *) array,
+ status);
+ }
+ else if (datatype == TLONGLONG)
+ {
+ ffpcljj(fptr, colnum, firstrow, firstelem, nelem, (LONGLONG *) array,
+ status);
+ }
+ else if (datatype == TFLOAT)
+ {
+ ffpcle(fptr, colnum, firstrow, firstelem, nelem, (float *) array,
+ status);
+ }
+ else if (datatype == TDOUBLE)
+ {
+ ffpcld(fptr, colnum, firstrow, firstelem, nelem, (double *) array,
+ status);
+ }
+ else if (datatype == TCOMPLEX)
+ {
+ ffpcle(fptr, colnum, firstrow, (firstelem - 1) * 2 + 1, nelem * 2,
+ (float *) array, status);
+ }
+ else if (datatype == TDBLCOMPLEX)
+ {
+ ffpcld(fptr, colnum, firstrow, (firstelem - 1) * 2 + 1, nelem * 2,
+ (double *) array, status);
+ }
+ else if (datatype == TLOGICAL)
+ {
+ ffpcll(fptr, colnum, firstrow, firstelem, nelem, (char *) array,
+ status);
+ }
+ else if (datatype == TSTRING)
+ {
+ ffpcls(fptr, colnum, firstrow, firstelem, nelem, (char **) array,
+ status);
+ }
+ else
+ *status = BAD_DATATYPE;
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpcn( fitsfile *fptr, /* I - FITS file pointer */
+ int datatype, /* I - datatype of the value */
+ int colnum, /* I - number of column to write (1 = 1st col) */
+ long firstrow, /* I - first row to write (1 = 1st row) */
+ long firstelem, /* I - first vector element to write (1 = 1st) */
+ long nelem, /* I - number of elements to write */
+ void *array, /* I - array of values that are written */
+ void *nulval, /* I - pointer to the null value */
+ int *status) /* IO - error status */
+/*
+ Write an array of values to a table column. The datatype of the
+ input array is defined by the 2nd argument. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS column is not the same as the array being written).
+*/
+{
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ if (nulval == NULL) /* null value not defined? */
+ {
+ ffpcl(fptr, datatype, colnum, firstrow, firstelem, nelem, array,
+ status);
+ return(*status);
+ }
+
+ if (datatype == TBYTE)
+ {
+ ffpcnb(fptr, colnum, firstrow, firstelem, nelem, (unsigned char *) array,
+ *(unsigned char *) nulval, status);
+ }
+ else if (datatype == TSBYTE)
+ {
+ ffpcnsb(fptr, colnum, firstrow, firstelem, nelem, (signed char *) array,
+ *(signed char *) nulval, status);
+ }
+ else if (datatype == TUSHORT)
+ {
+ ffpcnui(fptr, colnum, firstrow, firstelem, nelem, (unsigned short *) array,
+ *(unsigned short *) nulval, status);
+ }
+ else if (datatype == TSHORT)
+ {
+ ffpcni(fptr, colnum, firstrow, firstelem, nelem, (short *) array,
+ *(unsigned short *) nulval, status);
+ }
+ else if (datatype == TUINT)
+ {
+ ffpcnuk(fptr, colnum, firstrow, firstelem, nelem, (unsigned int *) array,
+ *(unsigned int *) nulval, status);
+ }
+ else if (datatype == TINT)
+ {
+ ffpcnk(fptr, colnum, firstrow, firstelem, nelem, (int *) array,
+ *(int *) nulval, status);
+ }
+ else if (datatype == TULONG)
+ {
+ ffpcnuj(fptr, colnum, firstrow, firstelem, nelem, (unsigned long *) array,
+ *(unsigned long *) nulval, status);
+ }
+ else if (datatype == TLONG)
+ {
+ ffpcnj(fptr, colnum, firstrow, firstelem, nelem, (long *) array,
+ *(long *) nulval, status);
+ }
+ else if (datatype == TLONGLONG)
+ {
+ ffpcnjj(fptr, colnum, firstrow, firstelem, nelem, (LONGLONG *) array,
+ *(LONGLONG *) nulval, status);
+ }
+ else if (datatype == TFLOAT)
+ {
+ ffpcne(fptr, colnum, firstrow, firstelem, nelem, (float *) array,
+ *(float *) nulval, status);
+ }
+ else if (datatype == TDOUBLE)
+ {
+ ffpcnd(fptr, colnum, firstrow, firstelem, nelem, (double *) array,
+ *(double *) nulval, status);
+ }
+ else if (datatype == TCOMPLEX)
+ {
+ ffpcne(fptr, colnum, firstrow, (firstelem - 1) * 2 + 1, nelem * 2,
+ (float *) array, *(float *) nulval, status);
+ }
+ else if (datatype == TDBLCOMPLEX)
+ {
+ ffpcnd(fptr, colnum, firstrow, (firstelem - 1) * 2 + 1, nelem * 2,
+ (double *) array, *(double *) nulval, status);
+ }
+ else if (datatype == TLOGICAL)
+ {
+ ffpcnl(fptr, colnum, firstrow, firstelem, nelem, (char *) array,
+ *(char *) nulval, status);
+ }
+ else if (datatype == TSTRING)
+ {
+ ffpcns(fptr, colnum, firstrow, firstelem, nelem, (char **) array,
+ (char *) nulval, status);
+ }
+ else
+ *status = BAD_DATATYPE;
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fits_iter_set_by_name(iteratorCol *col, /* I - iterator col structure */
+ fitsfile *fptr, /* I - FITS file pointer */
+ char *colname, /* I - column name */
+ int datatype, /* I - column datatype */
+ int iotype) /* I - InputCol, InputOutputCol, or OutputCol */
+/*
+ set all the parameters for an iterator column, by column name
+*/
+{
+ col->fptr = fptr;
+ strcpy(col->colname, colname);
+ col->colnum = 0; /* set column number undefined since name is given */
+ col->datatype = datatype;
+ col->iotype = iotype;
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int fits_iter_set_by_num(iteratorCol *col, /* I - iterator column structure */
+ fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - column number */
+ int datatype, /* I - column datatype */
+ int iotype) /* I - InputCol, InputOutputCol, or OutputCol */
+/*
+ set all the parameters for an iterator column, by column number
+*/
+{
+ col->fptr = fptr;
+ col->colnum = colnum;
+ col->datatype = datatype;
+ col->iotype = iotype;
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int fits_iter_set_file(iteratorCol *col, /* I - iterator column structure */
+ fitsfile *fptr) /* I - FITS file pointer */
+/*
+ set iterator column parameter
+*/
+{
+ col->fptr = fptr;
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int fits_iter_set_colname(iteratorCol *col, /* I - iterator col structure */
+ char *colname) /* I - column name */
+/*
+ set iterator column parameter
+*/
+{
+ strcpy(col->colname, colname);
+ col->colnum = 0; /* set column number undefined since name is given */
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int fits_iter_set_colnum(iteratorCol *col, /* I - iterator column structure */
+ int colnum) /* I - column number */
+/*
+ set iterator column parameter
+*/
+{
+ col->colnum = colnum;
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int fits_iter_set_datatype(iteratorCol *col, /* I - iterator col structure */
+ int datatype) /* I - column datatype */
+/*
+ set iterator column parameter
+*/
+{
+ col->datatype = datatype;
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int fits_iter_set_iotype(iteratorCol *col, /* I - iterator column structure */
+ int iotype) /* I - InputCol, InputOutputCol, or OutputCol */
+/*
+ set iterator column parameter
+*/
+{
+ col->iotype = iotype;
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+fitsfile * fits_iter_get_file(iteratorCol *col) /* I -iterator col structure */
+/*
+ get iterator column parameter
+*/
+{
+ return(col->fptr);
+}
+/*--------------------------------------------------------------------------*/
+char * fits_iter_get_colname(iteratorCol *col) /* I -iterator col structure */
+/*
+ get iterator column parameter
+*/
+{
+ return(col->colname);
+}
+/*--------------------------------------------------------------------------*/
+int fits_iter_get_colnum(iteratorCol *col) /* I - iterator column structure */
+/*
+ get iterator column parameter
+*/
+{
+ return(col->colnum);
+}
+/*--------------------------------------------------------------------------*/
+int fits_iter_get_datatype(iteratorCol *col) /* I - iterator col structure */
+/*
+ get iterator column parameter
+*/
+{
+ return(col->datatype);
+}
+/*--------------------------------------------------------------------------*/
+int fits_iter_get_iotype(iteratorCol *col) /* I - iterator column structure */
+/*
+ get iterator column parameter
+*/
+{
+ return(col->iotype);
+}
+/*--------------------------------------------------------------------------*/
+void * fits_iter_get_array(iteratorCol *col) /* I - iterator col structure */
+/*
+ get iterator column parameter
+*/
+{
+ return(col->array);
+}
+/*--------------------------------------------------------------------------*/
+long fits_iter_get_tlmin(iteratorCol *col) /* I - iterator column structure */
+/*
+ get iterator column parameter
+*/
+{
+ return(col->tlmin);
+}
+/*--------------------------------------------------------------------------*/
+long fits_iter_get_tlmax(iteratorCol *col) /* I - iterator column structure */
+/*
+ get iterator column parameter
+*/
+{
+ return(col->tlmax);
+}
+/*--------------------------------------------------------------------------*/
+long fits_iter_get_repeat(iteratorCol *col) /* I - iterator col structure */
+/*
+ get iterator column parameter
+*/
+{
+ return(col->repeat);
+}
+/*--------------------------------------------------------------------------*/
+char * fits_iter_get_tunit(iteratorCol *col) /* I - iterator col structure */
+/*
+ get iterator column parameter
+*/
+{
+ return(col->tunit);
+}
+/*--------------------------------------------------------------------------*/
+char * fits_iter_get_tdisp(iteratorCol *col) /* I -iterator col structure */
+/*
+ get iterator column parameter
+*/
+{
+ return(col->tdisp);
+}
+/*--------------------------------------------------------------------------*/
+int ffiter(int n_cols,
+ iteratorCol *cols,
+ long offset,
+ long n_per_loop,
+ int (*work_fn)(long total_n,
+ long offset,
+ long first_n,
+ long n_values,
+ int n_cols,
+ iteratorCol *cols,
+ void *userPointer),
+ void *userPointer,
+ int *status)
+/*
+ The iterator function. This function will pass the specified
+ columns from a FITS table or pixels from a FITS image to the
+ user-supplied function. Depending on the size of the table
+ or image, only a subset of the rows or pixels may be passed to the
+ function on each call, in which case the function will be called
+ multiple times until all the rows or pixels have been processed.
+*/
+{
+ typedef struct /* structure to store the column null value */
+ {
+ int nullsize; /* length of the null value, in bytes */
+ union { /* default null value for the column */
+ char *stringnull;
+ unsigned char charnull;
+ signed char scharnull;
+ int intnull;
+ short shortnull;
+ long longnull;
+ unsigned int uintnull;
+ unsigned short ushortnull;
+ unsigned long ulongnull;
+ float floatnull;
+ double doublenull;
+ } null;
+ } colNulls;
+
+ void *dataptr, *defaultnull;
+ colNulls *col;
+ int ii, jj, tstatus, naxis, bitpix;
+ int typecode, hdutype, jtype, type, anynul, nfiles, nbytes;
+ long totaln, nleft, frow, felement, n_optimum, i_optimum, ntodo;
+ long rept, rowrept, width, tnull, naxes[9] = {1,1,1,1,1,1,1,1,1}, groups;
+ double zeros = 0.;
+ char message[FLEN_ERRMSG], keyname[FLEN_KEYWORD], nullstr[FLEN_VALUE];
+ char **stringptr, *nullptr, *cptr;
+
+ if (*status > 0)
+ return(*status);
+
+ if (n_cols < 0 || n_cols > 999 )
+ {
+ ffpmsg("Illegal number of columms (ffiter)");
+ return(*status = BAD_COL_NUM); /* negative number of columns */
+ }
+
+ col = calloc(n_cols, sizeof(colNulls) ); /* memory for the null values */
+
+ /*------------------------------------------------------------*/
+ /* Make sure column numbers and datatypes are in legal range */
+ /* and column numbers and datatypes are legal. */
+ /* Also fill in other parameters in the column structure. */
+ /*------------------------------------------------------------*/
+
+ ffghdt(cols[0].fptr, &hdutype, status); /* type of first HDU */
+
+ for (jj = 0; jj < n_cols; jj++)
+ {
+ /* check that output datatype code value is legal */
+ type = cols[jj].datatype;
+
+ /* Allow variable length arrays for InputCol and InputOutputCol columns,
+ but not for OutputCol columns. Variable length arrays have a
+ negative type code value. */
+
+ if ((cols[jj].iotype != OutputCol) && (type<0)) {
+ type*=-1;
+ }
+
+ if (type != 0 && type != TBYTE &&
+ type != TSBYTE && type != TLOGICAL && type != TSTRING &&
+ type != TSHORT && type != TINT && type != TLONG &&
+ type != TFLOAT && type != TDOUBLE && type != TCOMPLEX &&
+ type != TULONG && type != TUSHORT && type != TDBLCOMPLEX)
+ {
+ if (type < 0) {
+ sprintf(message,
+ "Variable length array not allowed for output column number %d (ffiter)",
+ jj + 1);
+ } else {
+ sprintf(message,
+ "Illegal datatype for column number %d: %d (ffiter)",
+ jj + 1, cols[jj].datatype);
+ }
+
+ ffpmsg(message);
+ return(*status = BAD_DATATYPE);
+ }
+
+ /* initialize TLMINn, TLMAXn, column name, and display format */
+ cols[jj].tlmin = 0;
+ cols[jj].tlmax = 0;
+ cols[jj].tunit[0] = '\0';
+ cols[jj].tdisp[0] = '\0';
+
+ ffghdt(cols[jj].fptr, &jtype, status); /* get HDU type */
+
+ if (hdutype == IMAGE_HDU)
+ {
+ if (jtype != IMAGE_HDU)
+ {
+ sprintf(message,
+ "File %d not positioned to an image extension (ffiter)",
+ jj + 1);
+ return(*status = NOT_IMAGE);
+ }
+
+ /* since this is an image, set a dummy column number = 0 */
+ cols[jj].colnum = 0;
+ strcpy(cols[jj].colname, "IMAGE"); /* dummy name for images */
+
+ tstatus = 0;
+ ffgkys(cols[jj].fptr, "BUNIT", cols[jj].tunit, 0, &tstatus);
+ }
+ else
+ {
+ if (jtype == IMAGE_HDU)
+ {
+ sprintf(message,
+ "File %d not positioned to a table extension (ffiter)",
+ jj + 1);
+ return(*status = NOT_TABLE);
+ }
+
+ if (cols[jj].colnum < 1)
+ {
+ /* find the column number for the named column */
+ if (ffgcno(cols[jj].fptr, CASEINSEN, cols[jj].colname,
+ &cols[jj].colnum, status) )
+ {
+ sprintf(message,
+ "Column '%s' not found for column number %d (ffiter)",
+ cols[jj].colname, jj + 1);
+ ffpmsg(message);
+ return(*status);
+ }
+ }
+
+ if (cols[jj].colnum < 1 ||
+ cols[jj].colnum > ((cols[jj].fptr)->Fptr)->tfield)
+ {
+ sprintf(message,
+ "Column %d has illegal table position number: %d (ffiter)",
+ jj + 1, cols[jj].colnum);
+ ffpmsg(message);
+ return(*status = BAD_COL_NUM);
+ }
+
+ /* look for column description keywords and update structure */
+ tstatus = 0;
+ ffkeyn("TLMIN", cols[jj].colnum, keyname, &tstatus);
+ ffgkyj(cols[jj].fptr, keyname, &cols[jj].tlmin, 0, &tstatus);
+
+ tstatus = 0;
+ ffkeyn("TLMAX", cols[jj].colnum, keyname, &tstatus);
+ ffgkyj(cols[jj].fptr, keyname, &cols[jj].tlmax, 0, &tstatus);
+
+ tstatus = 0;
+ ffkeyn("TTYPE", cols[jj].colnum, keyname, &tstatus);
+ ffgkys(cols[jj].fptr, keyname, cols[jj].colname, 0, &tstatus);
+ if (tstatus)
+ cols[jj].colname[0] = '\0';
+
+ tstatus = 0;
+ ffkeyn("TUNIT", cols[jj].colnum, keyname, &tstatus);
+ ffgkys(cols[jj].fptr, keyname, cols[jj].tunit, 0, &tstatus);
+
+ tstatus = 0;
+ ffkeyn("TDISP", cols[jj].colnum, keyname, &tstatus);
+ ffgkys(cols[jj].fptr, keyname, cols[jj].tdisp, 0, &tstatus);
+ }
+ }
+
+ /*-----------------------------------------------------------------*/
+ /* use the first file to set the total number of values to process */
+ /*-----------------------------------------------------------------*/
+
+ offset = maxvalue(offset, 0L); /* make sure offset is legal */
+
+ if (hdutype == IMAGE_HDU) /* get total number of pixels in the image */
+ {
+ fits_get_img_dim(cols[0].fptr, &naxis, status);
+ fits_get_img_size(cols[0].fptr, 9, naxes, status);
+
+ tstatus = 0;
+ ffgkyj(cols[0].fptr, "GROUPS", &groups, NULL, &tstatus);
+ if (!tstatus && groups && (naxis > 1) && (naxes[0] == 0) )
+ {
+ /* this is a random groups file, with NAXIS1 = 0 */
+ /* Use GCOUNT, the number of groups, as the first multiplier */
+ /* to calculate the total number of pixels in all the groups. */
+ ffgkyj(cols[0].fptr, "GCOUNT", &totaln, NULL, status);
+
+ } else {
+ totaln = naxes[0];
+ }
+
+ for (ii = 1; ii < naxis; ii++)
+ totaln *= naxes[ii];
+
+ frow = 1;
+ felement = 1 + offset;
+ }
+ else /* get total number or rows in the table */
+ {
+ ffgkyj(cols[0].fptr, "NAXIS2", &totaln, 0, status);
+ frow = 1 + offset;
+ felement = 1;
+ }
+
+ /* adjust total by the input starting offset value */
+ totaln -= offset;
+ totaln = maxvalue(totaln, 0L); /* don't allow negative number */
+
+ /*------------------------------------------------------------------*/
+ /* Determine number of values to pass to work function on each loop */
+ /*------------------------------------------------------------------*/
+
+ if (n_per_loop == 0)
+ {
+ /* Determine optimum number of values for each iteration. */
+ /* Look at all the fitsfile pointers to determine the number */
+ /* of unique files. */
+
+ nfiles = 1;
+ ffgrsz(cols[0].fptr, &n_optimum, status);
+
+ for (jj = 1; jj < n_cols; jj++)
+ {
+ for (ii = 0; ii < jj; ii++)
+ {
+ if (cols[ii].fptr == cols[jj].fptr)
+ break;
+ }
+
+ if (ii == jj) /* this is a new file */
+ {
+ nfiles++;
+ ffgrsz(cols[jj].fptr, &i_optimum, status);
+ n_optimum = minvalue(n_optimum, i_optimum);
+ }
+ }
+
+ n_optimum = n_optimum / nfiles;
+ n_optimum = maxvalue(n_optimum, 1);
+ }
+ else if (n_per_loop < 0) /* must pass all the values at one time */
+ {
+ n_optimum = totaln;
+ }
+ else /* calling routine specified how many values to pass at a time */
+ {
+ n_optimum = minvalue(n_per_loop, totaln);
+ }
+
+ /*--------------------------------------*/
+ /* allocate work arrays for each column */
+ /* and determine the null pixel value */
+ /*--------------------------------------*/
+
+ for (jj = 0; jj < n_cols; jj++)
+ {
+ /* get image or column datatype and vector length */
+ if (hdutype == IMAGE_HDU) /* get total number of pixels in the image */
+ {
+ fits_get_img_type(cols[jj].fptr, &bitpix, status);
+ switch(bitpix) {
+ case BYTE_IMG:
+ typecode = TBYTE;
+ break;
+ case SHORT_IMG:
+ typecode = TSHORT;
+ break;
+ case LONG_IMG:
+ typecode = TLONG;
+ break;
+ case FLOAT_IMG:
+ typecode = TFLOAT;
+ break;
+ case DOUBLE_IMG:
+ typecode = TDOUBLE;
+ break;
+ }
+ }
+ else
+ {
+ if (ffgtcl(cols[jj].fptr, cols[jj].colnum, &typecode, &rept,
+ &width, status) > 0)
+ goto cleanup;
+
+ if (typecode < 0) { /* if any variable length arrays, then the */
+ n_optimum = 1; /* must process the table 1 row at a time */
+
+ /* Allow variable length arrays for InputCol and InputOutputCol columns,
+ but not for OutputCol columns. Variable length arrays have a
+ negative type code value. */
+
+ if (cols[jj].iotype == OutputCol) {
+ sprintf(message,
+ "Variable length array not allowed for output column number %d (ffiter)",
+ jj + 1);
+ ffpmsg(message);
+ return(*status = BAD_DATATYPE);
+ }
+ }
+ }
+
+ /* special case where sizeof(long) = 8: use TINT instead of TLONG */
+ if (abs(typecode) == TLONG && sizeof(long) == 8 && sizeof(int) == 4) {
+ if(typecode<0) {
+ typecode = -TINT;
+ } else {
+ typecode = TINT;
+ }
+ }
+
+ /* Special case: interprete 'X' column as 'B' */
+ if (abs(typecode) == TBIT)
+ {
+ typecode = typecode / TBIT * TBYTE;
+ rept = (rept + 7) / 8;
+ }
+
+ if (cols[jj].datatype == 0) /* output datatype not specified? */
+ {
+ /* special case if sizeof(long) = 8: use TINT instead of TLONG */
+ if (abs(typecode) == TLONG && sizeof(long) == 8 && sizeof(int) == 4)
+ cols[jj].datatype = TINT;
+ else
+ cols[jj].datatype = abs(typecode);
+ }
+
+ /* calc total number of elements to do on each iteration */
+ if (hdutype == IMAGE_HDU || cols[jj].datatype == TSTRING)
+ {
+ ntodo = n_optimum;
+ cols[jj].repeat = 1;
+
+ /* get the BLANK keyword value, if it exists */
+ if (abs(typecode) == TBYTE || abs(typecode) == TSHORT || abs(typecode) == TLONG)
+ {
+ tstatus = 0;
+ ffgkyj(cols[jj].fptr, "BLANK", &tnull, 0, &tstatus);
+ if (tstatus)
+ {
+ tnull = 0L; /* no null values */
+ }
+ }
+ }
+ else
+ {
+ if (typecode < 0)
+ {
+ /* get max size of the variable length vector; dont't trust the value
+ given by the TFORM keyword */
+ rept = 1;
+ for (ii = 0; ii < totaln; ii++) {
+ ffgdes(cols[jj].fptr, cols[jj].colnum, frow + ii, &rowrept, NULL, status);
+
+ rept = maxvalue(rept, rowrept);
+ }
+ }
+
+ ntodo = n_optimum * rept; /* vector columns */
+ cols[jj].repeat = rept;
+
+ /* get the TNULL keyword value, if it exists */
+ if (abs(typecode) == TBYTE || abs(typecode) == TSHORT || abs(typecode) == TLONG)
+ {
+ tstatus = 0;
+ if (hdutype == ASCII_TBL) /* TNULLn value is a string */
+ {
+ ffkeyn("TNULL", cols[jj].colnum, keyname, &tstatus);
+ ffgkys(cols[jj].fptr, keyname, nullstr, 0, &tstatus);
+ if (tstatus)
+ {
+ tnull = 0L; /* keyword doesn't exist; no null values */
+ }
+ else
+ {
+ cptr = nullstr;
+ while (*cptr == ' ') /* skip over leading blanks */
+ cptr++;
+
+ if (*cptr == '\0') /* TNULLn is all blanks? */
+ tnull = LONG_MIN;
+ else
+ {
+ /* attempt to read TNULLn string as an integer */
+ ffc2ii(nullstr, &tnull, &tstatus);
+
+ if (tstatus)
+ tnull = LONG_MIN; /* choose smallest value */
+ } /* to represent nulls */
+ }
+ }
+ else /* Binary table; TNULLn value is an integer */
+ {
+ ffkeyn("TNULL", cols[jj].colnum, keyname, &tstatus);
+ ffgkyj(cols[jj].fptr, keyname, &tnull, 0, &tstatus);
+ if (tstatus)
+ {
+ tnull = 0L; /* keyword doesn't exist; no null values */
+ }
+ else if (tnull == 0)
+ {
+ /* worst possible case: a value of 0 is used to */
+ /* represent nulls in the FITS file. We have to */
+ /* use a non-zero null value here (zero is used to */
+ /* mean there are no null values in the array) so we */
+ /* will use the smallest possible integer instead. */
+
+ tnull = LONG_MIN; /* choose smallest possible value */
+ }
+ }
+ }
+ }
+
+ /* Note that the data array starts with 2nd element; */
+ /* 1st element of the array gives the null data value */
+
+ switch (cols[jj].datatype)
+ {
+ case TBYTE:
+ cols[jj].array = calloc(ntodo + 1, sizeof(char));
+ col[jj].nullsize = sizeof(char); /* number of bytes per value */
+
+ if (abs(typecode) == TBYTE || abs(typecode) == TSHORT || abs(typecode) == TLONG)
+ {
+ tnull = minvalue(tnull, 255);
+ tnull = maxvalue(tnull, 0);
+ col[jj].null.charnull = (unsigned char) tnull;
+ }
+ else
+ {
+ col[jj].null.charnull = (unsigned char) 255; /* use 255 as null */
+ }
+ break;
+
+ case TSBYTE:
+ cols[jj].array = calloc(ntodo + 1, sizeof(char));
+ col[jj].nullsize = sizeof(char); /* number of bytes per value */
+
+ if (abs(typecode) == TBYTE || abs(typecode) == TSHORT || abs(typecode) == TLONG)
+ {
+ tnull = minvalue(tnull, 127);
+ tnull = maxvalue(tnull, -128);
+ col[jj].null.scharnull = (signed char) tnull;
+ }
+ else
+ {
+ col[jj].null.scharnull = (signed char) -128; /* use -128 null */
+ }
+ break;
+
+ case TSHORT:
+ cols[jj].array = calloc(ntodo + 1, sizeof(short));
+ col[jj].nullsize = sizeof(short); /* number of bytes per value */
+
+ if (abs(typecode) == TBYTE || abs(typecode) == TSHORT || abs(typecode) == TLONG)
+ {
+ tnull = minvalue(tnull, SHRT_MAX);
+ tnull = maxvalue(tnull, SHRT_MIN);
+ col[jj].null.shortnull = (short) tnull;
+ }
+ else
+ {
+ col[jj].null.shortnull = SHRT_MIN; /* use minimum as null */
+ }
+ break;
+
+ case TUSHORT:
+ cols[jj].array = calloc(ntodo + 1, sizeof(unsigned short));
+ col[jj].nullsize = sizeof(unsigned short); /* bytes per value */
+
+ if (abs(typecode) == TBYTE || abs(typecode) == TSHORT || abs(typecode) == TLONG)
+ {
+ tnull = minvalue(tnull, USHRT_MAX);
+ tnull = maxvalue(tnull, 0); /* don't allow negative value */
+ col[jj].null.ushortnull = (unsigned short) tnull;
+ }
+ else
+ {
+ col[jj].null.ushortnull = USHRT_MAX; /* use maximum null */
+ }
+ break;
+
+ case TINT:
+ cols[jj].array = calloc(sizeof(int), ntodo + 1);
+ col[jj].nullsize = sizeof(int); /* number of bytes per value */
+
+ if (abs(typecode) == TBYTE || abs(typecode) == TSHORT || abs(typecode) == TLONG)
+ {
+ tnull = minvalue(tnull, INT_MAX);
+ tnull = maxvalue(tnull, INT_MIN);
+ col[jj].null.intnull = (int) tnull;
+ }
+ else
+ {
+ col[jj].null.intnull = INT_MIN; /* use minimum as null */
+ }
+ break;
+
+ case TUINT:
+ cols[jj].array = calloc(ntodo + 1, sizeof(unsigned int));
+ col[jj].nullsize = sizeof(unsigned int); /* bytes per value */
+
+ if (abs(typecode) == TBYTE || abs(typecode) == TSHORT || abs(typecode) == TLONG)
+ {
+ tnull = minvalue(tnull, INT32_MAX);
+ tnull = maxvalue(tnull, 0);
+ col[jj].null.uintnull = (unsigned int) tnull;
+ }
+ else
+ {
+ col[jj].null.intnull = UINT_MAX; /* use maximum as null */
+ }
+ break;
+
+ case TLONG:
+ cols[jj].array = calloc(ntodo + 1, sizeof(long));
+ col[jj].nullsize = sizeof(long); /* number of bytes per value */
+
+ if (abs(typecode) == TBYTE || abs(typecode) == TSHORT || abs(typecode) == TLONG)
+ {
+ col[jj].null.longnull = tnull;
+ }
+ else
+ {
+ col[jj].null.longnull = LONG_MIN; /* use minimum as null */
+ }
+ break;
+
+ case TULONG:
+ cols[jj].array = calloc(ntodo + 1, sizeof(unsigned long));
+ col[jj].nullsize = sizeof(unsigned long); /* bytes per value */
+
+ if (abs(typecode) == TBYTE || abs(typecode) == TSHORT || abs(typecode) == TLONG)
+ {
+ if (tnull < 0) /* can't use a negative null value */
+ col[jj].null.ulongnull = LONG_MAX;
+ else
+ col[jj].null.ulongnull = (unsigned long) tnull;
+ }
+ else
+ {
+ col[jj].null.ulongnull = LONG_MAX; /* use maximum as null */
+ }
+ break;
+
+ case TFLOAT:
+ cols[jj].array = calloc(ntodo + 1, sizeof(float));
+ col[jj].nullsize = sizeof(float); /* number of bytes per value */
+
+ if (abs(typecode) == TBYTE || abs(typecode) == TSHORT || abs(typecode) == TLONG)
+ {
+ col[jj].null.floatnull = (float) tnull;
+ }
+ else
+ {
+ col[jj].null.floatnull = FLOATNULLVALUE; /* special value */
+ }
+ break;
+
+ case TCOMPLEX:
+ cols[jj].array = calloc((ntodo * 2) + 1, sizeof(float));
+ col[jj].nullsize = sizeof(float); /* number of bytes per value */
+ col[jj].null.floatnull = FLOATNULLVALUE; /* special value */
+ break;
+
+ case TDOUBLE:
+ cols[jj].array = calloc(ntodo + 1, sizeof(double));
+ col[jj].nullsize = sizeof(double); /* number of bytes per value */
+
+ if (abs(typecode) == TBYTE || abs(typecode) == TSHORT || abs(typecode) == TLONG)
+ {
+ col[jj].null.doublenull = (double) tnull;
+ }
+ else
+ {
+ col[jj].null.doublenull = DOUBLENULLVALUE; /* special value */
+ }
+ break;
+
+ case TDBLCOMPLEX:
+ cols[jj].array = calloc((ntodo * 2) + 1, sizeof(double));
+ col[jj].nullsize = sizeof(double); /* number of bytes per value */
+ col[jj].null.doublenull = DOUBLENULLVALUE; /* special value */
+ break;
+
+ case TSTRING:
+ /* allocate array of pointers to all the strings */
+ if( hdutype==ASCII_TBL ) rept = width;
+ stringptr = calloc((ntodo + 1) , sizeof(stringptr));
+ cols[jj].array = stringptr;
+ col[jj].nullsize = rept + 1; /* number of bytes per value */
+
+ if (stringptr)
+ {
+ /* allocate string to store the null string value */
+ col[jj].null.stringnull = calloc(rept + 1, sizeof(char) );
+ col[jj].null.stringnull[1] = 1; /* to make sure string != 0 */
+
+ /* allocate big block for the array of table column strings */
+ stringptr[0] = calloc((ntodo + 1) * (rept + 1), sizeof(char) );
+
+ if (stringptr[0])
+ {
+ for (ii = 1; ii <= ntodo; ii++)
+ { /* pointer to each string */
+ stringptr[ii] = stringptr[ii - 1] + (rept + 1);
+ }
+
+ /* get the TNULL keyword value, if it exists */
+ tstatus = 0;
+ ffkeyn("TNULL", cols[jj].colnum, keyname, &tstatus);
+ ffgkys(cols[jj].fptr, keyname, nullstr, 0, &tstatus);
+ if (!tstatus)
+ strncat(col[jj].null.stringnull, nullstr, rept);
+ }
+ else
+ {
+ ffpmsg("ffiter failed to allocate memory arrays");
+ *status = MEMORY_ALLOCATION; /* memory allocation failed */
+ goto cleanup;
+ }
+ }
+ break;
+
+ case TLOGICAL:
+
+ cols[jj].array = calloc(ntodo + 1, sizeof(char));
+ col[jj].nullsize = sizeof(char); /* number of bytes per value */
+
+ /* use value = 2 to flag null values in logical columns */
+ col[jj].null.charnull = 2;
+ break;
+
+ default:
+ sprintf(message,
+ "Column %d datatype currently not supported: %d: (ffiter)",
+ jj + 1, cols[jj].datatype);
+ ffpmsg(message);
+ *status = BAD_DATATYPE;
+ goto cleanup;
+
+ } /* end of switch block */
+
+ /* check that all the arrays were allocated successfully */
+ if (!cols[jj].array)
+ {
+ ffpmsg("ffiter failed to allocate memory arrays");
+ *status = MEMORY_ALLOCATION; /* memory allocation failed */
+ goto cleanup;
+ }
+ }
+
+ /*--------------------------------------------------*/
+ /* main loop while there are values left to process */
+ /*--------------------------------------------------*/
+
+ nleft = totaln;
+
+ while (nleft)
+ {
+ ntodo = minvalue(nleft, n_optimum); /* no. of values for this loop */
+
+ /* read input columns from FITS file(s) */
+ for (jj = 0; jj < n_cols; jj++)
+ {
+ if (cols[jj].iotype != OutputCol)
+ {
+ if (cols[jj].datatype == TSTRING)
+ {
+ stringptr = cols[jj].array;
+ dataptr = stringptr + 1;
+ defaultnull = col[jj].null.stringnull; /* ptr to the null value */
+ }
+ else
+ {
+ dataptr = (char *) cols[jj].array + col[jj].nullsize;
+ defaultnull = &col[jj].null.charnull; /* ptr to the null value */
+ }
+
+ if (hdutype == IMAGE_HDU)
+ {
+ if (ffgpv(cols[jj].fptr, cols[jj].datatype,
+ felement, cols[jj].repeat * ntodo, defaultnull,
+ dataptr, &anynul, status) > 0)
+ {
+ break;
+ }
+ }
+ else
+ {
+ if (ffgtcl(cols[jj].fptr, cols[jj].colnum, &typecode, &rept,&width, status) > 0)
+ goto cleanup;
+
+ if (typecode<0)
+ {
+ /* get size of the variable length vector */
+ ffgdes(cols[jj].fptr, cols[jj].colnum, frow,&cols[jj].repeat, NULL,status);
+ }
+
+ if (ffgcv(cols[jj].fptr, cols[jj].datatype, cols[jj].colnum,
+ frow, felement, cols[jj].repeat * ntodo, defaultnull,
+ dataptr, &anynul, status) > 0)
+ {
+ break;
+ }
+ }
+
+ /* copy the appropriate null value into first array element */
+
+ if (anynul) /* are there any nulls in the data? */
+ {
+ if (cols[jj].datatype == TSTRING)
+ {
+ stringptr = cols[jj].array;
+ memcpy(*stringptr, col[jj].null.stringnull, col[jj].nullsize);
+ }
+ else
+ {
+ memcpy(cols[jj].array, defaultnull, col[jj].nullsize);
+ }
+ }
+ else /* no null values so copy zero into first element */
+ {
+ if (cols[jj].datatype == TSTRING)
+ {
+ stringptr = cols[jj].array;
+ memset(*stringptr, 0, col[jj].nullsize);
+ }
+ else
+ {
+ memset(cols[jj].array, 0, col[jj].nullsize);
+ }
+ }
+ }
+ }
+
+ if (*status > 0)
+ break; /* looks like an error occurred; quit immediately */
+
+ /* call work function */
+
+ if (hdutype == IMAGE_HDU)
+ *status = work_fn(totaln, offset, felement, ntodo, n_cols, cols,
+ userPointer);
+ else
+ *status = work_fn(totaln, offset, frow, ntodo, n_cols, cols,
+ userPointer);
+
+ if (*status > 0 || *status < -1 )
+ break; /* looks like an error occurred; quit immediately */
+
+ /* write output columns before quiting if status = -1 */
+ tstatus = 0;
+ for (jj = 0; jj < n_cols; jj++)
+ {
+ if (cols[jj].iotype != InputCol)
+ {
+ if (cols[jj].datatype == TSTRING)
+ {
+ stringptr = cols[jj].array;
+ dataptr = stringptr + 1;
+ nullptr = *stringptr;
+ nbytes = 2;
+ }
+ else
+ {
+ dataptr = (char *) cols[jj].array + col[jj].nullsize;
+ nullptr = (char *) cols[jj].array;
+ nbytes = col[jj].nullsize;
+ }
+
+ if (memcmp(nullptr, &zeros, nbytes) )
+ {
+ /* null value flag not zero; must check for and write nulls */
+ if (hdutype == IMAGE_HDU)
+ {
+ if (ffppn(cols[jj].fptr, cols[jj].datatype,
+ felement, cols[jj].repeat * ntodo, dataptr,
+ nullptr, &tstatus) > 0)
+ break;
+ }
+ else
+ {
+ if (ffgtcl(cols[jj].fptr, cols[jj].colnum, &typecode, &rept,&width, status) > 0)
+ goto cleanup;
+
+ if (typecode<0) /* variable length array colum */
+ {
+ ffgdes(cols[jj].fptr, cols[jj].colnum, frow,&cols[jj].repeat, NULL,status);
+ }
+
+ if (ffpcn(cols[jj].fptr, cols[jj].datatype, cols[jj].colnum, frow,
+ felement, cols[jj].repeat * ntodo, dataptr,
+ nullptr, &tstatus) > 0)
+ break;
+ }
+ }
+ else
+ {
+ /* no null values; just write the array */
+ if (hdutype == IMAGE_HDU)
+ {
+ if (ffppr(cols[jj].fptr, cols[jj].datatype,
+ felement, cols[jj].repeat * ntodo, dataptr,
+ &tstatus) > 0)
+ break;
+ }
+ else
+ {
+ if (ffgtcl(cols[jj].fptr, cols[jj].colnum, &typecode, &rept,&width, status) > 0)
+ goto cleanup;
+
+ if (typecode<0) /* variable length array column */
+ {
+ ffgdes(cols[jj].fptr, cols[jj].colnum, frow,&cols[jj].repeat, NULL,status);
+ }
+
+ if (ffpcl(cols[jj].fptr, cols[jj].datatype, cols[jj].colnum, frow,
+ felement, cols[jj].repeat * ntodo, dataptr,
+ &tstatus) > 0)
+ break;
+ }
+ }
+ }
+ }
+
+ if (*status == 0)
+ *status = tstatus; /* propagate any error status from the writes */
+
+ if (*status)
+ break; /* exit on any error */
+
+ nleft -= ntodo;
+
+ if (hdutype == IMAGE_HDU)
+ felement += ntodo;
+ else
+ frow += ntodo;
+ }
+
+cleanup:
+
+ /*----------------------------------*/
+ /* free work arrays for the columns */
+ /*----------------------------------*/
+
+ for (jj = 0; jj < n_cols; jj++)
+ {
+ if (cols[jj].datatype == TSTRING)
+ {
+ if (cols[jj].array)
+ {
+ stringptr = cols[jj].array;
+ free(*stringptr); /* free the block of strings */
+ free(col[jj].null.stringnull); /* free the null string */
+ }
+ }
+ free(cols[jj].array); /* memory for the array of values from the col */
+ }
+ free(col); /* the structure containing the null values */
+ return(*status);
+}
+
diff --git a/pkg/tbtables/cfitsio/putcolb.c b/pkg/tbtables/cfitsio/putcolb.c
new file mode 100644
index 00000000..8f926b2d
--- /dev/null
+++ b/pkg/tbtables/cfitsio/putcolb.c
@@ -0,0 +1,1031 @@
+/* This file, putcolb.c, contains routines that write data elements to */
+/* a FITS image or table with char (byte) datatype. */
+
+/* The FITSIO software was written by William Pence at the High Energy */
+/* Astrophysic Science Archive Research Center (HEASARC) at the NASA */
+/* Goddard Space Flight Center. */
+
+#include <limits.h>
+#include <string.h>
+#include <stdlib.h>
+#include "fitsio2.h"
+
+/* declare variable for passing large firstelem values between routines */
+extern OFF_T large_first_elem_val;
+
+/*--------------------------------------------------------------------------*/
+int ffpprb( fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long firstelem, /* I - first vector element to write(1 = 1st) */
+ long nelem, /* I - number of values to write */
+ unsigned char *array, /* I - array of values that are written */
+ int *status) /* IO - error status */
+/*
+ Write an array of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being written).
+*/
+{
+ long row;
+ unsigned char nullvalue;
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ /* use the OFF_T variable to pass the first element value */
+ if (firstelem != USE_LARGE_VALUE)
+ large_first_elem_val = firstelem;
+
+ fits_write_compressed_pixels(fptr, TBYTE, large_first_elem_val, nelem,
+ 0, array, &nullvalue, status);
+ return(*status);
+ }
+
+ row=maxvalue(1,group);
+
+ ffpclb(fptr, 2, row, firstelem, nelem, array, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffppnb( fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long firstelem, /* I - first vector element to write(1 = 1st) */
+ long nelem, /* I - number of values to write */
+ unsigned char *array, /* I - array of values that are written */
+ unsigned char nulval, /* I - undefined pixel value */
+ int *status) /* IO - error status */
+/*
+ Write an array of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of the
+ FITS array is not the same as the array being written). Any array values
+ that are equal to the value of nulval will be replaced with the null
+ pixel value that is appropriate for this column.
+*/
+{
+ long row;
+ unsigned char nullvalue;
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ /* use the OFF_T variable to pass the first element value */
+ if (firstelem != USE_LARGE_VALUE)
+ large_first_elem_val = firstelem;
+
+ nullvalue = nulval; /* set local variable */
+ fits_write_compressed_pixels(fptr, TBYTE, large_first_elem_val, nelem,
+ 1, array, &nullvalue, status);
+ return(*status);
+ }
+
+ row=maxvalue(1,group);
+
+ ffpcnb(fptr, 2, row, firstelem, nelem, array, nulval, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffp2db(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long ncols, /* I - number of pixels in each row of array */
+ long naxis1, /* I - FITS image NAXIS1 value */
+ long naxis2, /* I - FITS image NAXIS2 value */
+ unsigned char *array, /* I - array to be written */
+ int *status) /* IO - error status */
+/*
+ Write an entire 2-D array of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of the
+ FITS array is not the same as the array being written).
+*/
+{
+ /* call the 3D writing routine, with the 3rd dimension = 1 */
+
+ ffp3db(fptr, group, ncols, naxis2, naxis1, naxis2, 1, array, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffp3db(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long ncols, /* I - number of pixels in each row of array */
+ long nrows, /* I - number of rows in each plane of array */
+ long naxis1, /* I - FITS image NAXIS1 value */
+ long naxis2, /* I - FITS image NAXIS2 value */
+ long naxis3, /* I - FITS image NAXIS3 value */
+ unsigned char *array, /* I - array to be written */
+ int *status) /* IO - error status */
+/*
+ Write an entire 3-D cube of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of the
+ FITS array is not the same as the array being written).
+*/
+{
+ long tablerow, nfits, narray, ii, jj;
+ long fpixel[3]= {1,1,1}, lpixel[3];
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+ lpixel[0] = ncols;
+ lpixel[1] = nrows;
+ lpixel[2] = naxis3;
+
+ fits_write_compressed_img(fptr, TBYTE, fpixel, lpixel,
+ 0, array, NULL, status);
+
+ return(*status);
+ }
+
+ tablerow=maxvalue(1,group);
+
+ if (ncols == naxis1 && nrows == naxis2) /* arrays have same size? */
+ {
+ /* all the image pixels are contiguous, so write all at once */
+ ffpclb(fptr, 2, tablerow, 1L, naxis1 * naxis2 * naxis3, array, status);
+ return(*status);
+ }
+
+ if (ncols < naxis1 || nrows < naxis2)
+ return(*status = BAD_DIMEN);
+
+ nfits = 1; /* next pixel in FITS image to write to */
+ narray = 0; /* next pixel in input array to be written */
+
+ /* loop over naxis3 planes in the data cube */
+ for (jj = 0; jj < naxis3; jj++)
+ {
+ /* loop over the naxis2 rows in the FITS image, */
+ /* writing naxis1 pixels to each row */
+
+ for (ii = 0; ii < naxis2; ii++)
+ {
+ if (ffpclb(fptr, 2, tablerow, nfits, naxis1,&array[narray],status) > 0)
+ return(*status);
+
+ nfits += naxis1;
+ narray += ncols;
+ }
+ narray += (nrows - naxis2) * ncols;
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpssb(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long naxis, /* I - number of data axes in array */
+ long *naxes, /* I - size of each FITS axis */
+ long *fpixel, /* I - 1st pixel in each axis to write (1=1st) */
+ long *lpixel, /* I - last pixel in each axis to write */
+ unsigned char *array, /* I - array to be written */
+ int *status) /* IO - error status */
+/*
+ Write a subsection of pixels to the primary array or image.
+ A subsection is defined to be any contiguous rectangular
+ array of pixels within the n-dimensional FITS data file.
+ Data conversion and scaling will be performed if necessary
+ (e.g, if the datatype of the FITS array is not the same as
+ the array being written).
+*/
+{
+ long tablerow;
+ long fpix[7], irange[7], dimen[7], astart, pstart;
+ long off2, off3, off4, off5, off6, off7;
+ long st10, st20, st30, st40, st50, st60, st70;
+ long st1, st2, st3, st4, st5, st6, st7;
+ long ii, i1, i2, i3, i4, i5, i6, i7;
+
+ if (*status > 0)
+ return(*status);
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ fits_write_compressed_img(fptr, TBYTE, fpixel, lpixel,
+ 0, array, NULL, status);
+
+ return(*status);
+ }
+
+ if (naxis < 1 || naxis > 7)
+ return(*status = BAD_DIMEN);
+
+ tablerow=maxvalue(1,group);
+
+ /* calculate the size and number of loops to perform in each dimension */
+ for (ii = 0; ii < 7; ii++)
+ {
+ fpix[ii]=1;
+ irange[ii]=1;
+ dimen[ii]=1;
+ }
+
+ for (ii = 0; ii < naxis; ii++)
+ {
+ fpix[ii]=fpixel[ii];
+ irange[ii]=lpixel[ii]-fpixel[ii]+1;
+ dimen[ii]=naxes[ii];
+ }
+
+ i1=irange[0];
+
+ /* compute the pixel offset between each dimension */
+ off2 = dimen[0];
+ off3 = off2 * dimen[1];
+ off4 = off3 * dimen[2];
+ off5 = off4 * dimen[3];
+ off6 = off5 * dimen[4];
+ off7 = off6 * dimen[5];
+
+ st10 = fpix[0];
+ st20 = (fpix[1] - 1) * off2;
+ st30 = (fpix[2] - 1) * off3;
+ st40 = (fpix[3] - 1) * off4;
+ st50 = (fpix[4] - 1) * off5;
+ st60 = (fpix[5] - 1) * off6;
+ st70 = (fpix[6] - 1) * off7;
+
+ /* store the initial offset in each dimension */
+ st1 = st10;
+ st2 = st20;
+ st3 = st30;
+ st4 = st40;
+ st5 = st50;
+ st6 = st60;
+ st7 = st70;
+
+ astart = 0;
+
+ for (i7 = 0; i7 < irange[6]; i7++)
+ {
+ for (i6 = 0; i6 < irange[5]; i6++)
+ {
+ for (i5 = 0; i5 < irange[4]; i5++)
+ {
+ for (i4 = 0; i4 < irange[3]; i4++)
+ {
+ for (i3 = 0; i3 < irange[2]; i3++)
+ {
+ pstart = st1 + st2 + st3 + st4 + st5 + st6 + st7;
+ for (i2 = 0; i2 < irange[1]; i2++)
+ {
+ if (ffpclb(fptr, 2, tablerow, pstart, i1, &array[astart],
+ status) > 0)
+ return(*status);
+
+ astart += i1;
+ pstart += off2;
+ }
+ st2 = st20;
+ st3 = st3+off3;
+ }
+ st3 = st30;
+ st4 = st4+off4;
+ }
+ st4 = st40;
+ st5 = st5+off5;
+ }
+ st5 = st50;
+ st6 = st6+off6;
+ }
+ st6 = st60;
+ st7 = st7+off7;
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpgpb( fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long firstelem, /* I - first vector element to write(1 = 1st) */
+ long nelem, /* I - number of values to write */
+ unsigned char *array, /* I - array of values that are written */
+ int *status) /* IO - error status */
+/*
+ Write an array of group parameters to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being written).
+*/
+{
+ long row;
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ row=maxvalue(1,group);
+
+ ffpclb(fptr, 1L, row, firstelem, nelem, array, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpclb( fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to write (1 = 1st col) */
+ long firstrow, /* I - first row to write (1 = 1st row) */
+ long firstelem, /* I - first vector element to write (1 = 1st) */
+ long nelem, /* I - number of values to write */
+ unsigned char *array, /* I - array of values to write */
+ int *status) /* IO - error status */
+/*
+ Write an array of values to a column in the current FITS HDU.
+ The column number may refer to a real column in an ASCII or binary table,
+ or it may refer to a virtual column in a 1 or more grouped FITS primary
+ array. FITSIO treats a primary array as a binary table with
+ 2 vector columns: the first column contains the group parameters (often
+ with length = 0) and the second column contains the array of image pixels.
+ Each row of the table represents a group in the case of multigroup FITS
+ images.
+
+ The input array of values will be converted to the datatype of the column
+ and will be inverse-scaled by the FITS TSCALn and TZEROn values if necessary.
+*/
+{
+ int tcode, maxelem, hdutype, writeraw;
+ long twidth, incre, rownum, remain, next, ntodo;
+ long tnull;
+ OFF_T repeat, startpos, elemnum, large_elem, wrtptr, rowlen;
+ double scale, zero;
+ char tform[20], cform[20];
+ char message[FLEN_ERRMSG];
+
+ char snull[20]; /* the FITS null value */
+
+ double cbuff[DBUFFSIZE / sizeof(double)]; /* align cbuff on word boundary */
+ void *buffer;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ buffer = cbuff;
+
+ if (firstelem == USE_LARGE_VALUE)
+ large_elem = large_first_elem_val;
+ else
+ large_elem = firstelem;
+
+ /*---------------------------------------------------*/
+ /* Check input and get parameters about the column: */
+ /*---------------------------------------------------*/
+ if (ffgcpr( fptr, colnum, firstrow, large_elem, nelem, 1, &scale, &zero,
+ tform, &twidth, &tcode, &maxelem, &startpos, &elemnum, &incre,
+ &repeat, &rowlen, &hdutype, &tnull, snull, status) > 0)
+ return(*status);
+
+ if (tcode == TSTRING)
+ ffcfmt(tform, cform); /* derive C format for writing strings */
+
+ /*
+ if there is no scaling
+ then we can simply write the raw data bytes into the FITS file if the
+ datatype of the FITS column is the same as the input values. Otherwise,
+ we must convert the raw values into the scaled and/or machine dependent
+ format in a temporary buffer that has been allocated for this purpose.
+ */
+ if (scale == 1. && zero == 0. && tcode == TBYTE)
+ {
+ writeraw = 1;
+ maxelem = nelem; /* we can write the entire array at one time */
+ }
+ else
+ writeraw = 0;
+
+ /*---------------------------------------------------------------------*/
+ /* Now write the pixels to the FITS column. */
+ /* First call the ffXXfYY routine to (1) convert the datatype */
+ /* if necessary, and (2) scale the values by the FITS TSCALn and */
+ /* TZEROn linear scaling parameters into a temporary buffer. */
+ /*---------------------------------------------------------------------*/
+ remain = nelem; /* remaining number of values to write */
+ next = 0; /* next element in array to be written */
+ rownum = 0; /* row number, relative to firstrow */
+
+ while (remain)
+ {
+ /* limit the number of pixels to process a one time to the number that
+ will fit in the buffer space or to the number of pixels that remain
+ in the current vector, which ever is smaller.
+ */
+ ntodo = minvalue(remain, maxelem);
+ ntodo = minvalue(ntodo, (repeat - elemnum));
+
+ wrtptr = startpos + ((OFF_T)rownum * rowlen) + (elemnum * incre);
+ ffmbyt(fptr, wrtptr, IGNORE_EOF, status); /* move to write position */
+
+ switch (tcode)
+ {
+ case (TBYTE):
+ if (writeraw)
+ {
+ /* write raw input bytes without conversion */
+ ffpi1b(fptr, ntodo, incre, &array[next], status);
+ }
+ else
+ {
+ /* convert the raw data before writing to FITS file */
+ ffi1fi1(&array[next], ntodo, scale, zero,
+ (unsigned char *) buffer, status);
+ ffpi1b(fptr, ntodo, incre, (unsigned char *) buffer, status);
+ }
+
+ break;
+
+ case (TLONGLONG):
+
+ ffi1fi8(&array[next], ntodo, scale, zero,
+ (LONGLONG *) buffer, status);
+ ffpi8b(fptr, ntodo, incre, (long *) buffer, status);
+ break;
+
+ case (TSHORT):
+
+ ffi1fi2(&array[next], ntodo, scale, zero,
+ (short *) buffer, status);
+ ffpi2b(fptr, ntodo, incre, (short *) buffer, status);
+ break;
+
+ case (TLONG):
+
+ ffi1fi4(&array[next], ntodo, scale, zero,
+ (INT32BIT *) buffer, status);
+ ffpi4b(fptr, ntodo, incre, (INT32BIT *) buffer, status);
+ break;
+
+ case (TFLOAT):
+
+ ffi1fr4(&array[next], ntodo, scale, zero,
+ (float *) buffer, status);
+ ffpr4b(fptr, ntodo, incre, (float *) buffer, status);
+ break;
+
+ case (TDOUBLE):
+ ffi1fr8(&array[next], ntodo, scale, zero,
+ (double *) buffer, status);
+ ffpr8b(fptr, ntodo, incre, (double *) buffer, status);
+ break;
+
+ case (TSTRING): /* numerical column in an ASCII table */
+
+ if (strchr(tform,'A'))
+ {
+ /* write raw input bytes without conversion */
+ /* This case is a hack to let users write a stream */
+ /* of bytes directly to the 'A' format column */
+
+ if (incre == twidth)
+ ffpbyt(fptr, ntodo, &array[next], status);
+ else
+ ffpbytoff(fptr, twidth, ntodo/twidth, incre - twidth,
+ &array[next], status);
+ break;
+ }
+ else if (cform[1] != 's') /* "%s" format is a string */
+ {
+ ffi1fstr(&array[next], ntodo, scale, zero, cform,
+ twidth, (char *) buffer, status);
+
+ if (incre == twidth) /* contiguous bytes */
+ ffpbyt(fptr, ntodo * twidth, buffer, status);
+ else
+ ffpbytoff(fptr, twidth, ntodo, incre - twidth, buffer,
+ status);
+ break;
+ }
+ /* can't write to string column, so fall thru to default: */
+
+ default: /* error trap */
+ sprintf(message,
+ "Cannot write numbers to column %d which has format %s",
+ colnum,tform);
+ ffpmsg(message);
+ if (hdutype == ASCII_TBL)
+ return(*status = BAD_ATABLE_FORMAT);
+ else
+ return(*status = BAD_BTABLE_FORMAT);
+
+ } /* End of switch block */
+
+ /*-------------------------*/
+ /* Check for fatal error */
+ /*-------------------------*/
+ if (*status > 0) /* test for error during previous write operation */
+ {
+ sprintf(message,
+ "Error writing elements %ld thru %ld of input data array (ffpclb).",
+ next+1, next+ntodo);
+ ffpmsg(message);
+ return(*status);
+ }
+
+ /*--------------------------------------------*/
+ /* increment the counters for the next loop */
+ /*--------------------------------------------*/
+ remain -= ntodo;
+ if (remain)
+ {
+ next += ntodo;
+ elemnum += ntodo;
+ if (elemnum == repeat) /* completed a row; start on next row */
+ {
+ elemnum = 0;
+ rownum++;
+ }
+ }
+ } /* End of main while Loop */
+
+
+ /*--------------------------------*/
+ /* check for numerical overflow */
+ /*--------------------------------*/
+ if (*status == OVERFLOW_ERR)
+ {
+ ffpmsg(
+ "Numerical overflow during type conversion while writing FITS data.");
+ *status = NUM_OVERFLOW;
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpcnb( fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to write (1 = 1st col) */
+ long firstrow, /* I - first row to write (1 = 1st row) */
+ long firstelem, /* I - first vector element to write (1 = 1st) */
+ long nelem, /* I - number of values to write */
+ unsigned char *array, /* I - array of values to write */
+ unsigned char nulvalue, /* I - flag for undefined pixels */
+ int *status) /* IO - error status */
+/*
+ Write an array of elements to the specified column of a table. Any input
+ pixels equal to the value of nulvalue will be replaced by the appropriate
+ null value in the output FITS file.
+
+ The input array of values will be converted to the datatype of the column
+ and will be inverse-scaled by the FITS TSCALn and TZEROn values if necessary
+*/
+{
+ tcolumn *colptr;
+ long ngood = 0, nbad = 0, ii, fstrow;
+ OFF_T large_elem, repeat, first, fstelm;
+
+ if (*status > 0)
+ return(*status);
+
+ /* reset position to the correct HDU if necessary */
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ {
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+ }
+ else if ((fptr->Fptr)->datastart == DATA_UNDEFINED)
+ {
+ if ( ffrdef(fptr, status) > 0) /* rescan header */
+ return(*status);
+ }
+
+ colptr = (fptr->Fptr)->tableptr; /* point to first column */
+ colptr += (colnum - 1); /* offset to correct column structure */
+
+ repeat = colptr->trepeat; /* repeat count for this column */
+
+ if (firstelem == USE_LARGE_VALUE)
+ large_elem = large_first_elem_val;
+ else
+ large_elem = firstelem;
+
+ /* hereafter, pass first element parameter via global variable */
+ firstelem = USE_LARGE_VALUE;
+
+ /* absolute element number in the column */
+ first = (firstrow - 1) * repeat + large_elem;
+
+ for (ii = 0; ii < nelem; ii++)
+ {
+ if (array[ii] != nulvalue) /* is this a good pixel? */
+ {
+ if (nbad) /* write previous string of bad pixels */
+ {
+ fstelm = ii - nbad + first; /* absolute element number */
+ fstrow = (fstelm - 1) / repeat + 1; /* starting row number */
+ fstelm = fstelm - (fstrow - 1) * repeat; /* relative number */
+ large_first_elem_val = fstelm;
+
+ if (ffpclu(fptr, colnum, fstrow, firstelem, nbad, status) > 0)
+ return(*status);
+
+ nbad=0;
+ }
+
+ ngood = ngood + 1; /* the consecutive number of good pixels */
+ }
+ else
+ {
+ if (ngood) /* write previous string of good pixels */
+ {
+ fstelm = ii - ngood + first; /* absolute element number */
+ fstrow = (fstelm - 1) / repeat + 1; /* starting row number */
+ fstelm = fstelm - (fstrow - 1) * repeat; /* relative number */
+ large_first_elem_val = fstelm;
+
+ if (ffpclb(fptr, colnum, fstrow, firstelem, ngood, &array[ii-ngood],
+ status) > 0)
+ return(*status);
+
+ ngood=0;
+ }
+
+ nbad = nbad + 1; /* the consecutive number of bad pixels */
+ }
+ }
+
+ /* finished loop; now just write the last set of pixels */
+
+ if (ngood) /* write last string of good pixels */
+ {
+ fstelm = ii - ngood + first; /* absolute element number */
+ fstrow = (fstelm - 1) / repeat + 1; /* starting row number */
+ fstelm = fstelm - (fstrow - 1) * repeat; /* relative number */
+ large_first_elem_val = fstelm;
+
+ ffpclb(fptr, colnum, fstrow, firstelem, ngood, &array[ii-ngood], status);
+ }
+ else if (nbad) /* write last string of bad pixels */
+ {
+ fstelm = ii - nbad + first; /* absolute element number */
+ fstrow = (fstelm - 1) / repeat + 1; /* starting row number */
+ fstelm = fstelm - (fstrow - 1) * repeat; /* relative number */
+ large_first_elem_val = fstelm;
+
+ ffpclu(fptr, colnum, fstrow, firstelem, nbad, status);
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffi1fi1(unsigned char *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ unsigned char *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (scale == 1. && zero == 0.)
+ {
+ memcpy(output, input, ntodo); /* just copy input to output */
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = ( ((double) input[ii]) - zero) / scale;
+
+ if (dvalue < DUCHAR_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DUCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UCHAR_MAX;
+ }
+ else
+ output[ii] = (unsigned char) (dvalue + .5);
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffi1fi2(unsigned char *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ short *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = input[ii]; /* just copy input to output */
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = (((double) input[ii]) - zero) / scale;
+
+ if (dvalue < DSHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MIN;
+ }
+ else if (dvalue > DSHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MAX;
+ }
+ else
+ {
+ if (dvalue >= 0)
+ output[ii] = (short) (dvalue + .5);
+ else
+ output[ii] = (short) (dvalue - .5);
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffi1fi4(unsigned char *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ INT32BIT *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = (INT32BIT) input[ii]; /* copy input to output */
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = (((double) input[ii]) - zero) / scale;
+
+ if (dvalue < DINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT32_MIN;
+ }
+ else if (dvalue > DINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT32_MAX;
+ }
+ else
+ {
+ if (dvalue >= 0)
+ output[ii] = (INT32BIT) (dvalue + .5);
+ else
+ output[ii] = (INT32BIT) (dvalue - .5);
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffi1fi8(unsigned char *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ LONGLONG *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required
+*/
+{
+#if (LONGSIZE == 32) && (! defined HAVE_LONGLONG)
+
+/* don't have a native 8-byte integer, so have to construct the */
+/* 2 equivalent 4-byte integers have the same bit pattern */
+
+ unsigned long *uoutput;
+ long ii, jj, kk, temp;
+ double dvalue;
+
+ uoutput = (unsigned long *) output;
+
+#if BYTESWAPPED /* jj points to the most significant part of the 8-byte int */
+ jj = 1;
+ kk = 0;
+#else
+ jj = 0;
+ kk = 1;
+#endif
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++, jj += 2, kk += 2)
+ {
+ output[jj] = 0;
+ output[kk] = input[ii];
+ }
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++, jj += 2, kk += 2)
+ {
+ dvalue = (input[ii] - zero) / scale;
+
+ if (dvalue < DLONGLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[jj] = LONG_MIN;
+ output[kk] = 0;
+ }
+ else if (dvalue > DLONGLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[jj] = LONG_MAX;
+ output[kk] = -1;
+ }
+ else
+ {
+ if (dvalue < 0)
+ {
+ temp = (dvalue + 1.) / 4294967296. - 1.;
+ output[jj] = temp;
+ uoutput[kk] = 4294967296. +
+ (dvalue - (double) (temp + 1) * 4294967296.);
+ }
+ else
+ {
+ temp = dvalue / 4294967296.;
+ output[jj] = temp;
+ uoutput[kk] = dvalue - (double) temp * 4294967296.;
+ }
+ }
+ }
+ }
+
+#else
+
+/* this is the much simpler case where the native 8-byte integer exists */
+
+ long ii;
+ double dvalue;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = input[ii];
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = (input[ii] - zero) / scale;
+
+ if (dvalue < DLONGLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONGLONG_MIN;
+ }
+ else if (dvalue > DLONGLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONGLONG_MAX;
+ }
+ else
+ {
+ if (dvalue >= 0)
+ output[ii] = (LONGLONG) (dvalue + .5);
+ else
+ output[ii] = (LONGLONG) (dvalue - .5);
+ }
+ }
+ }
+
+#endif
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffi1fr4(unsigned char *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ float *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required.
+*/
+{
+ long ii;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = (float) input[ii];
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = ( ( (double) input[ii] ) - zero) / scale;
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffi1fr8(unsigned char *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ double *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required.
+*/
+{
+ long ii;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = (double) input[ii];
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = ( ( (double) input[ii] ) - zero) / scale;
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffi1fstr(unsigned char *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ char *cform, /* I - format for output string values */
+ long twidth, /* I - width of each field, in chars */
+ char *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do scaling if required.
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ sprintf(output, cform, (double) input[ii]);
+ output += twidth;
+
+ if (*output) /* if this char != \0, then overflow occurred */
+ *status = OVERFLOW_ERR;
+ }
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = ((double) input[ii] - zero) / scale;
+ sprintf(output, cform, dvalue);
+ output += twidth;
+
+ if (*output) /* if this char != \0, then overflow occurred */
+ *status = OVERFLOW_ERR;
+ }
+ }
+ return(*status);
+}
diff --git a/pkg/tbtables/cfitsio/putcold.c b/pkg/tbtables/cfitsio/putcold.c
new file mode 100644
index 00000000..6a79b49f
--- /dev/null
+++ b/pkg/tbtables/cfitsio/putcold.c
@@ -0,0 +1,1147 @@
+/* This file, putcold.c, contains routines that write data elements to */
+/* a FITS image or table, with double datatype. */
+
+/* The FITSIO software was written by William Pence at the High Energy */
+/* Astrophysic Science Archive Research Center (HEASARC) at the NASA */
+/* Goddard Space Flight Center. */
+
+#include <limits.h>
+#include <string.h>
+#include <stdlib.h>
+#include "fitsio2.h"
+
+/* declare variable for passing large firstelem values between routines */
+extern OFF_T large_first_elem_val;
+
+/*--------------------------------------------------------------------------*/
+int ffpprd( fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long firstelem, /* I - first vector element to write(1 = 1st) */
+ long nelem, /* I - number of values to write */
+ double *array, /* I - array of values that are written */
+ int *status) /* IO - error status */
+/*
+ Write an array of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being written).
+*/
+{
+ long row;
+ double nullvalue;
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ /* use the OFF_T variable to pass the first element value */
+ if (firstelem != USE_LARGE_VALUE)
+ large_first_elem_val = firstelem;
+
+ fits_write_compressed_pixels(fptr, TDOUBLE, large_first_elem_val, nelem,
+ 0, array, &nullvalue, status);
+ return(*status);
+ }
+
+ row=maxvalue(1,group);
+
+ ffpcld(fptr, 2, row, firstelem, nelem, array, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffppnd( fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long firstelem, /* I - first vector element to write(1 = 1st) */
+ long nelem, /* I - number of values to write */
+ double *array, /* I - array of values that are written */
+ double nulval, /* I - undefined pixel value */
+ int *status) /* IO - error status */
+/*
+ Write an array of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of the
+ FITS array is not the same as the array being written). Any array values
+ that are equal to the value of nulval will be replaced with the null
+ pixel value that is appropriate for this column.
+*/
+{
+ long row;
+ double nullvalue;
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ /* use the OFF_T variable to pass the first element value */
+ if (firstelem != USE_LARGE_VALUE)
+ large_first_elem_val = firstelem;
+
+ nullvalue = nulval; /* set local variable */
+ fits_write_compressed_pixels(fptr, TDOUBLE, large_first_elem_val, nelem,
+ 1, array, &nullvalue, status);
+ return(*status);
+ }
+
+ row=maxvalue(1,group);
+
+ ffpcnd(fptr, 2, row, firstelem, nelem, array, nulval, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffp2dd(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long ncols, /* I - number of pixels in each row of array */
+ long naxis1, /* I - FITS image NAXIS1 value */
+ long naxis2, /* I - FITS image NAXIS2 value */
+ double *array, /* I - array to be written */
+ int *status) /* IO - error status */
+/*
+ Write an entire 2-D array of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of the
+ FITS array is not the same as the array being written).
+*/
+{
+ /* call the 3D writing routine, with the 3rd dimension = 1 */
+
+ ffp3dd(fptr, group, ncols, naxis2, naxis1, naxis2, 1, array, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffp3dd(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long ncols, /* I - number of pixels in each row of array */
+ long nrows, /* I - number of rows in each plane of array */
+ long naxis1, /* I - FITS image NAXIS1 value */
+ long naxis2, /* I - FITS image NAXIS2 value */
+ long naxis3, /* I - FITS image NAXIS3 value */
+ double *array, /* I - array to be written */
+ int *status) /* IO - error status */
+/*
+ Write an entire 3-D cube of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of the
+ FITS array is not the same as the array being written).
+*/
+{
+ long tablerow, nfits, narray, ii, jj;
+ long fpixel[3]= {1,1,1}, lpixel[3];
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+ lpixel[0] = ncols;
+ lpixel[1] = nrows;
+ lpixel[2] = naxis3;
+
+ fits_write_compressed_img(fptr, TDOUBLE, fpixel, lpixel,
+ 0, array, NULL, status);
+
+ return(*status);
+ }
+
+ tablerow=maxvalue(1,group);
+
+ if (ncols == naxis1 && nrows == naxis2) /* arrays have same size? */
+ {
+ /* all the image pixels are contiguous, so write all at once */
+ ffpcld(fptr, 2, tablerow, 1L, naxis1 * naxis2 * naxis3, array, status);
+ return(*status);
+ }
+
+ if (ncols < naxis1 || nrows < naxis2)
+ return(*status = BAD_DIMEN);
+
+ nfits = 1; /* next pixel in FITS image to write to */
+ narray = 0; /* next pixel in input array to be written */
+
+ /* loop over naxis3 planes in the data cube */
+ for (jj = 0; jj < naxis3; jj++)
+ {
+ /* loop over the naxis2 rows in the FITS image, */
+ /* writing naxis1 pixels to each row */
+
+ for (ii = 0; ii < naxis2; ii++)
+ {
+ if (ffpcld(fptr, 2, tablerow, nfits, naxis1,&array[narray],status) > 0)
+ return(*status);
+
+ nfits += naxis1;
+ narray += ncols;
+ }
+ narray += (nrows - naxis2) * ncols;
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpssd(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long naxis, /* I - number of data axes in array */
+ long *naxes, /* I - size of each FITS axis */
+ long *fpixel, /* I - 1st pixel in each axis to write (1=1st) */
+ long *lpixel, /* I - last pixel in each axis to write */
+ double *array, /* I - array to be written */
+ int *status) /* IO - error status */
+/*
+ Write a subsection of pixels to the primary array or image.
+ A subsection is defined to be any contiguous rectangular
+ array of pixels within the n-dimensional FITS data file.
+ Data conversion and scaling will be performed if necessary
+ (e.g, if the datatype of the FITS array is not the same as
+ the array being written).
+*/
+{
+ long tablerow;
+ long fpix[7], irange[7], dimen[7], astart, pstart;
+ long off2, off3, off4, off5, off6, off7;
+ long st10, st20, st30, st40, st50, st60, st70;
+ long st1, st2, st3, st4, st5, st6, st7;
+ long ii, i1, i2, i3, i4, i5, i6, i7;
+
+ if (*status > 0)
+ return(*status);
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ fits_write_compressed_img(fptr, TDOUBLE, fpixel, lpixel,
+ 0, array, NULL, status);
+
+ return(*status);
+ }
+
+ if (naxis < 1 || naxis > 7)
+ return(*status = BAD_DIMEN);
+
+ tablerow=maxvalue(1,group);
+
+ /* calculate the size and number of loops to perform in each dimension */
+ for (ii = 0; ii < 7; ii++)
+ {
+ fpix[ii]=1;
+ irange[ii]=1;
+ dimen[ii]=1;
+ }
+
+ for (ii = 0; ii < naxis; ii++)
+ {
+ fpix[ii]=fpixel[ii];
+ irange[ii]=lpixel[ii]-fpixel[ii]+1;
+ dimen[ii]=naxes[ii];
+ }
+
+ i1=irange[0];
+
+ /* compute the pixel offset between each dimension */
+ off2 = dimen[0];
+ off3 = off2 * dimen[1];
+ off4 = off3 * dimen[2];
+ off5 = off4 * dimen[3];
+ off6 = off5 * dimen[4];
+ off7 = off6 * dimen[5];
+
+ st10 = fpix[0];
+ st20 = (fpix[1] - 1) * off2;
+ st30 = (fpix[2] - 1) * off3;
+ st40 = (fpix[3] - 1) * off4;
+ st50 = (fpix[4] - 1) * off5;
+ st60 = (fpix[5] - 1) * off6;
+ st70 = (fpix[6] - 1) * off7;
+
+ /* store the initial offset in each dimension */
+ st1 = st10;
+ st2 = st20;
+ st3 = st30;
+ st4 = st40;
+ st5 = st50;
+ st6 = st60;
+ st7 = st70;
+
+ astart = 0;
+
+ for (i7 = 0; i7 < irange[6]; i7++)
+ {
+ for (i6 = 0; i6 < irange[5]; i6++)
+ {
+ for (i5 = 0; i5 < irange[4]; i5++)
+ {
+ for (i4 = 0; i4 < irange[3]; i4++)
+ {
+ for (i3 = 0; i3 < irange[2]; i3++)
+ {
+ pstart = st1 + st2 + st3 + st4 + st5 + st6 + st7;
+ for (i2 = 0; i2 < irange[1]; i2++)
+ {
+ if (ffpcld(fptr, 2, tablerow, pstart, i1, &array[astart],
+ status) > 0)
+ return(*status);
+
+ astart += i1;
+ pstart += off2;
+ }
+ st2 = st20;
+ st3 = st3+off3;
+ }
+ st3 = st30;
+ st4 = st4+off4;
+ }
+ st4 = st40;
+ st5 = st5+off5;
+ }
+ st5 = st50;
+ st6 = st6+off6;
+ }
+ st6 = st60;
+ st7 = st7+off7;
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpgpd( fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long firstelem, /* I - first vector element to write(1 = 1st) */
+ long nelem, /* I - number of values to write */
+ double *array, /* I - array of values that are written */
+ int *status) /* IO - error status */
+/*
+ Write an array of group parameters to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being written).
+*/
+{
+ long row;
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ row=maxvalue(1,group);
+
+ ffpcld(fptr, 1L, row, firstelem, nelem, array, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpcld( fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to write (1 = 1st col) */
+ long firstrow, /* I - first row to write (1 = 1st row) */
+ long firstelem, /* I - first vector element to write (1 = 1st) */
+ long nelem, /* I - number of values to write */
+ double *array, /* I - array of values to write */
+ int *status) /* IO - error status */
+/*
+ Write an array of values to a column in the current FITS HDU.
+ The column number may refer to a real column in an ASCII or binary table,
+ or it may refer to a virtual column in a 1 or more grouped FITS primary
+ array. FITSIO treats a primary array as a binary table
+ with 2 vector columns: the first column contains the group parameters (often
+ with length = 0) and the second column contains the array of image pixels.
+ Each row of the table represents a group in the case of multigroup FITS
+ images.
+
+ The input array of values will be converted to the datatype of the column
+ and will be inverse-scaled by the FITS TSCALn and TZEROn values if necessary.
+*/
+{
+ int tcode, maxelem, hdutype, writeraw;
+ long twidth, incre, rownum, remain, next, ntodo;
+ long tnull;
+ OFF_T repeat, startpos, elemnum, large_elem, wrtptr, rowlen;
+ double scale, zero;
+ char tform[20], cform[20];
+ char message[FLEN_ERRMSG];
+
+ char snull[20]; /* the FITS null value */
+
+ double cbuff[DBUFFSIZE / sizeof(double)]; /* align cbuff on word boundary */
+ void *buffer;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ buffer = cbuff;
+
+ if (firstelem == USE_LARGE_VALUE)
+ large_elem = large_first_elem_val;
+ else
+ large_elem = firstelem;
+
+ /*---------------------------------------------------*/
+ /* Check input and get parameters about the column: */
+ /*---------------------------------------------------*/
+ if (ffgcpr( fptr, colnum, firstrow, large_elem, nelem, 1, &scale, &zero,
+ tform, &twidth, &tcode, &maxelem, &startpos, &elemnum, &incre,
+ &repeat, &rowlen, &hdutype, &tnull, snull, status) > 0)
+ return(*status);
+
+ if (tcode == TSTRING)
+ ffcfmt(tform, cform); /* derive C format for writing strings */
+
+ /*
+ if there is no scaling and the native machine format is not byteswapped,
+ then we can simply write the raw data bytes into the FITS file if the
+ datatype of the FITS column is the same as the input values. Otherwise,
+ we must convert the raw values into the scaled and/or machine dependent
+ format in a temporary buffer that has been allocated for this purpose.
+ */
+ if (scale == 1. && zero == 0. &&
+ MACHINE == NATIVE && tcode == TDOUBLE)
+ {
+ writeraw = 1;
+ maxelem = nelem; /* we can write the entire array at one time */
+ }
+ else
+ writeraw = 0;
+
+ /*---------------------------------------------------------------------*/
+ /* Now write the pixels to the FITS column. */
+ /* First call the ffXXfYY routine to (1) convert the datatype */
+ /* if necessary, and (2) scale the values by the FITS TSCALn and */
+ /* TZEROn linear scaling parameters into a temporary buffer. */
+ /*---------------------------------------------------------------------*/
+ remain = nelem; /* remaining number of values to write */
+ next = 0; /* next element in array to be written */
+ rownum = 0; /* row number, relative to firstrow */
+
+ while (remain)
+ {
+ /* limit the number of pixels to process a one time to the number that
+ will fit in the buffer space or to the number of pixels that remain
+ in the current vector, which ever is smaller.
+ */
+ ntodo = minvalue(remain, maxelem);
+ ntodo = minvalue(ntodo, (repeat - elemnum));
+
+ wrtptr = startpos + ((OFF_T)rownum * rowlen) + (elemnum * incre);
+
+ ffmbyt(fptr, wrtptr, IGNORE_EOF, status); /* move to write position */
+
+ switch (tcode)
+ {
+ case (TDOUBLE):
+ if (writeraw)
+ {
+ /* write raw input bytes without conversion */
+ ffpr8b(fptr, ntodo, incre, &array[next], status);
+ }
+ else
+ {
+ /* convert the raw data before writing to FITS file */
+ ffr8fr8(&array[next], ntodo, scale, zero,
+ (double *) buffer, status);
+ ffpr8b(fptr, ntodo, incre, (double *) buffer, status);
+ }
+
+ break;
+
+ case (TLONGLONG):
+
+ ffr8fi8(&array[next], ntodo, scale, zero,
+ (LONGLONG *) buffer, status);
+ ffpi8b(fptr, ntodo, incre, (long *) buffer, status);
+ break;
+
+ case (TBYTE):
+
+ ffr8fi1(&array[next], ntodo, scale, zero,
+ (unsigned char *) buffer, status);
+ ffpi1b(fptr, ntodo, incre, (unsigned char *) buffer, status);
+ break;
+
+ case (TSHORT):
+
+ ffr8fi2(&array[next], ntodo, scale, zero,
+ (short *) buffer, status);
+ ffpi2b(fptr, ntodo, incre, (short *) buffer, status);
+ break;
+
+ case (TLONG):
+
+ ffr8fi4(&array[next], ntodo, scale, zero,
+ (INT32BIT *) buffer, status);
+ ffpi4b(fptr, ntodo, incre, (INT32BIT *) buffer, status);
+ break;
+
+ case (TFLOAT):
+ ffr8fr4(&array[next], ntodo, scale, zero,
+ (float *) buffer, status);
+ ffpr4b(fptr, ntodo, incre, (float *) buffer, status);
+ break;
+
+ case (TSTRING): /* numerical column in an ASCII table */
+
+ if (cform[1] != 's') /* "%s" format is a string */
+ {
+ ffr8fstr(&array[next], ntodo, scale, zero, cform,
+ twidth, (char *) buffer, status);
+
+ if (incre == twidth) /* contiguous bytes */
+ ffpbyt(fptr, ntodo * twidth, buffer, status);
+ else
+ ffpbytoff(fptr, twidth, ntodo, incre - twidth, buffer,
+ status);
+
+ break;
+ }
+ /* can't write to string column, so fall thru to default: */
+
+ default: /* error trap */
+ sprintf(message,
+ "Cannot write numbers to column %d which has format %s",
+ colnum,tform);
+ ffpmsg(message);
+ if (hdutype == ASCII_TBL)
+ return(*status = BAD_ATABLE_FORMAT);
+ else
+ return(*status = BAD_BTABLE_FORMAT);
+
+ } /* End of switch block */
+
+ /*-------------------------*/
+ /* Check for fatal error */
+ /*-------------------------*/
+ if (*status > 0) /* test for error during previous write operation */
+ {
+ sprintf(message,
+ "Error writing elements %ld thru %ld of input data array (ffpcld).",
+ next+1, next+ntodo);
+ ffpmsg(message);
+ return(*status);
+ }
+
+ /*--------------------------------------------*/
+ /* increment the counters for the next loop */
+ /*--------------------------------------------*/
+ remain -= ntodo;
+ if (remain)
+ {
+ next += ntodo;
+ elemnum += ntodo;
+ if (elemnum == repeat) /* completed a row; start on next row */
+ {
+ elemnum = 0;
+ rownum++;
+ }
+ }
+ } /* End of main while Loop */
+
+
+ /*--------------------------------*/
+ /* check for numerical overflow */
+ /*--------------------------------*/
+ if (*status == OVERFLOW_ERR)
+ {
+ ffpmsg(
+ "Numerical overflow during type conversion while writing FITS data.");
+ *status = NUM_OVERFLOW;
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpclm( fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to write (1 = 1st col) */
+ long firstrow, /* I - first row to write (1 = 1st row) */
+ long firstelem, /* I - first vector element to write (1 = 1st) */
+ long nelem, /* I - number of values to write */
+ double *array, /* I - array of values to write */
+ int *status) /* IO - error status */
+/*
+ Write an array of double complex values to a column in the current FITS HDU.
+ Each complex number if interpreted as a pair of float values.
+ The column number may refer to a real column in an ASCII or binary table,
+ or it may refer to a virtual column in a 1 or more grouped FITS primary
+ array. FITSIO treats a primary array as a binary table
+ with 2 vector columns: the first column contains the group parameters (often
+ with length = 0) and the second column contains the array of image pixels.
+ Each row of the table represents a group in the case of multigroup FITS
+ images.
+
+ The input array of values will be converted to the datatype of the column
+ if necessary, but normally complex values should only be written to a binary
+ table with TFORMn = 'rM' where r is an optional repeat count. The TSCALn and
+ TZERO keywords should not be used with complex numbers because mathmatically
+ the scaling should only be applied to the real (first) component of the
+ complex value.
+*/
+{
+ /* simply multiply the number of elements by 2, and call ffpcld */
+
+ ffpcld(fptr, colnum, firstrow, (firstelem - 1) * 2 + 1,
+ nelem * 2, array, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpcnd( fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to write (1 = 1st col) */
+ long firstrow, /* I - first row to write (1 = 1st row) */
+ long firstelem, /* I - first vector element to write (1 = 1st) */
+ long nelem, /* I - number of values to write */
+ double *array, /* I - array of values to write */
+ double nulvalue, /* I - value used to flag undefined pixels */
+ int *status) /* IO - error status */
+/*
+ Write an array of elements to the specified column of a table. Any input
+ pixels equal to the value of nulvalue will be replaced by the appropriate
+ null value in the output FITS file.
+
+ The input array of values will be converted to the datatype of the column
+ and will be inverse-scaled by the FITS TSCALn and TZEROn values if necessary
+*/
+{
+ tcolumn *colptr;
+ long ngood = 0, nbad = 0, ii, fstrow;
+ OFF_T large_elem, repeat, first, fstelm;
+ int tcode, overflow = 0;
+
+ if (*status > 0)
+ return(*status);
+
+ /* reset position to the correct HDU if necessary */
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ {
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+ }
+ else if ((fptr->Fptr)->datastart == DATA_UNDEFINED)
+ {
+ if ( ffrdef(fptr, status) > 0) /* rescan header */
+ return(*status);
+ }
+
+ colptr = (fptr->Fptr)->tableptr; /* point to first column */
+ colptr += (colnum - 1); /* offset to correct column structure */
+
+ repeat = colptr->trepeat; /* repeat count for this column */
+ fits_get_coltype(fptr, colnum, &tcode, NULL, NULL, status);
+
+ if (tcode >= TCOMPLEX)
+ { /* treat complex columns as pairs of numbers */
+ repeat *= 2;
+ }
+
+ if (firstelem == USE_LARGE_VALUE)
+ large_elem = large_first_elem_val;
+ else
+ large_elem = firstelem;
+
+ /* hereafter, pass first element parameter via global variable */
+ firstelem = USE_LARGE_VALUE;
+
+ /* absolute element number in the column */
+ first = (firstrow - 1) * repeat + large_elem;
+
+ for (ii = 0; ii < nelem; ii++)
+ {
+ if (array[ii] != nulvalue) /* is this a good pixel? */
+ {
+ if (nbad) /* write previous string of bad pixels */
+ {
+ fstelm = ii - nbad + first; /* absolute element number */
+ fstrow = (fstelm - 1) / repeat + 1; /* starting row number */
+ fstelm = fstelm - (fstrow - 1) * repeat; /* relative number */
+ large_first_elem_val = fstelm;
+
+ /* call ffpcluc, not ffpclu, in case we are writing to a
+ complex ('C') binary table column */
+ if (ffpcluc(fptr, colnum, fstrow, firstelem, nbad, status) > 0)
+ return(*status);
+
+ nbad=0;
+ }
+
+ ngood = ngood +1; /* the consecutive number of good pixels */
+ }
+ else
+ {
+ if (ngood) /* write previous string of good pixels */
+ {
+ fstelm = ii - ngood + first; /* absolute element number */
+ fstrow = (fstelm - 1) / repeat + 1; /* starting row number */
+ fstelm = fstelm - (fstrow - 1) * repeat; /* relative number */
+ large_first_elem_val = fstelm;
+
+ if (ffpcld(fptr, colnum, fstrow, firstelem, ngood, &array[ii-ngood],
+ status) > 0) {
+ if (*status == NUM_OVERFLOW)
+ {
+ overflow = 1;
+ *status = 0;
+ } else {
+ return(*status);
+ }
+ }
+
+ ngood=0;
+ }
+
+ nbad = nbad +1; /* the consecutive number of bad pixels */
+ }
+ }
+
+ /* finished loop; now just write the last set of pixels */
+
+ if (ngood) /* write last string of good pixels */
+ {
+ fstelm = ii - ngood + first; /* absolute element number */
+ fstrow = (fstelm - 1) / repeat + 1; /* starting row number */
+ fstelm = fstelm - (fstrow - 1) * repeat; /* relative number */
+ large_first_elem_val = fstelm;
+
+ ffpcld(fptr, colnum, fstrow, firstelem, ngood, &array[ii-ngood], status);
+ }
+ else if (nbad) /* write last string of bad pixels */
+ {
+ fstelm = ii - nbad + first; /* absolute element number */
+ fstrow = (fstelm - 1) / repeat + 1; /* starting row number */
+ fstelm = fstelm - (fstrow - 1) * repeat; /* relative number */
+ large_first_elem_val = fstelm;
+ ffpcluc(fptr, colnum, fstrow, firstelem, nbad, status);
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffr8fi1(double *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ unsigned char *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required.
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] < DUCHAR_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (input[ii] > DUCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UCHAR_MAX;
+ }
+ else
+ output[ii] = (unsigned char) input[ii];
+ }
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = (input[ii] - zero) / scale;
+
+ if (dvalue < DUCHAR_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DUCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UCHAR_MAX;
+ }
+ else
+ output[ii] = (unsigned char) (dvalue + .5);
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffr8fi2(double *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ short *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required.
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] < DSHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MIN;
+ }
+ else if (input[ii] > DSHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MAX;
+ }
+ else
+ output[ii] = (short) input[ii];
+ }
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = (input[ii] - zero) / scale;
+
+ if (dvalue < DSHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MIN;
+ }
+ else if (dvalue > DSHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MAX;
+ }
+ else
+ {
+ if (dvalue >= 0)
+ output[ii] = (short) (dvalue + .5);
+ else
+ output[ii] = (short) (dvalue - .5);
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffr8fi4(double *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ INT32BIT *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required.
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] < DINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT32_MIN;
+ }
+ else if (input[ii] > DINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT32_MAX;
+ }
+ else
+ output[ii] = (INT32BIT) input[ii];
+ }
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = (input[ii] - zero) / scale;
+
+ if (dvalue < DINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT32_MIN;
+ }
+ else if (dvalue > DINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT32_MAX;
+ }
+ else
+ {
+ if (dvalue >= 0)
+ output[ii] = (INT32BIT) (dvalue + .5);
+ else
+ output[ii] = (INT32BIT) (dvalue - .5);
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffr8fi8(double *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ LONGLONG *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required.
+*/
+{
+#if (LONGSIZE == 32) && (! defined HAVE_LONGLONG)
+
+/* don't have a native 8-byte integer, so have to construct the */
+/* 2 equivalent 4-byte integers have the same bit pattern */
+
+ unsigned long *uoutput;
+ long ii, jj, kk, temp;
+ double dvalue;
+
+ uoutput = (unsigned long *) output;
+
+#if BYTESWAPPED /* jj points to the most significant part of the 8-byte int */
+ jj = 1;
+ kk = 0;
+#else
+ jj = 0;
+ kk = 1;
+#endif
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++, jj += 2, kk += 2)
+ {
+ if (input[ii] < DLONGLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[jj] = LONG_MIN;
+ output[kk] = 0;
+ }
+ else if (input[ii] > DLONGLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[jj] = LONG_MAX;
+ output[kk] = -1;
+ }
+ else
+ {
+ if (input[ii] < 0)
+ {
+ temp = (input[ii] + 1.) / 4294967296. - 1.;
+ output[jj] = temp;
+ uoutput[kk] = 4294967296. +
+ (input[ii] - (double) (temp + 1) * 4294967296.);
+ }
+ else
+ {
+ temp = input[ii] / 4294967296.;
+ output[jj] = temp;
+ uoutput[kk] = input[ii] - (double) temp * 4294967296.;
+ }
+ }
+ }
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++, jj += 2, kk += 2)
+ {
+ dvalue = (input[ii] - zero) / scale;
+
+ if (dvalue < DLONGLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[jj] = LONG_MIN;
+ output[kk] = 0;
+ }
+ else if (dvalue > DLONGLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[jj] = LONG_MAX;
+ output[kk] = -1;
+ }
+ else
+ {
+ if (dvalue < 0)
+ {
+ temp = (dvalue + 1.) / 4294967296. - 1.;
+ output[jj] = temp;
+ uoutput[kk] = 4294967296. +
+ (dvalue - (double) (temp + 1) * 4294967296.);
+ }
+ else
+ {
+ temp = dvalue / 4294967296.;
+ output[jj] = temp;
+ uoutput[kk] = dvalue - (double) temp * 4294967296.;
+ }
+ }
+ }
+ }
+
+#else
+
+/* this is the much simpler case where the native 8-byte integer exists */
+
+ long ii;
+ double dvalue;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] < DLONGLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONGLONG_MIN;
+ }
+ else if (input[ii] > DLONGLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONGLONG_MAX;
+ }
+ else
+ output[ii] = (LONGLONG) input[ii];
+ }
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = (input[ii] - zero) / scale;
+
+ if (dvalue < DLONGLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONGLONG_MIN;
+ }
+ else if (dvalue > DLONGLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONGLONG_MAX;
+ }
+ else
+ {
+ if (dvalue >= 0)
+ output[ii] = (LONGLONG) (dvalue + .5);
+ else
+ output[ii] = (LONGLONG) (dvalue - .5);
+ }
+ }
+ }
+
+#endif
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffr8fr4(double *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ float *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required.
+*/
+{
+ long ii;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = (float) input[ii];
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = (input[ii] - zero) / scale;
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffr8fr8(double *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ double *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required.
+*/
+{
+ long ii;
+
+ if (scale == 1. && zero == 0.)
+ {
+ memcpy(output, input, ntodo * sizeof(double) ); /* copy input to output */
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = (input[ii] - zero) / scale;
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffr8fstr(double *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ char *cform, /* I - format for output string values */
+ long twidth, /* I - width of each field, in chars */
+ char *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do scaling if required.
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ sprintf(output, cform, input[ii]);
+ output += twidth;
+
+ if (*output) /* if this char != \0, then overflow occurred */
+ *status = OVERFLOW_ERR;
+ }
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = (input[ii] - zero) / scale;
+ sprintf(output, cform, dvalue);
+ output += twidth;
+
+ if (*output) /* if this char != \0, then overflow occurred */
+ *status = OVERFLOW_ERR;
+ }
+ }
+ return(*status);
+}
diff --git a/pkg/tbtables/cfitsio/putcole.c b/pkg/tbtables/cfitsio/putcole.c
new file mode 100644
index 00000000..5857b772
--- /dev/null
+++ b/pkg/tbtables/cfitsio/putcole.c
@@ -0,0 +1,1154 @@
+/* This file, putcole.c, contains routines that write data elements to */
+/* a FITS image or table, with float datatype. */
+
+/* The FITSIO software was written by William Pence at the High Energy */
+/* Astrophysic Science Archive Research Center (HEASARC) at the NASA */
+/* Goddard Space Flight Center. */
+
+#include <limits.h>
+#include <string.h>
+#include <stdlib.h>
+#include "fitsio2.h"
+
+/* declare variable for passing large firstelem values between routines */
+extern OFF_T large_first_elem_val;
+
+/*--------------------------------------------------------------------------*/
+int ffppre( fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long firstelem, /* I - first vector element to write(1 = 1st) */
+ long nelem, /* I - number of values to write */
+ float *array, /* I - array of values that are written */
+ int *status) /* IO - error status */
+/*
+ Write an array of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being written).
+*/
+{
+ long row;
+ float nullvalue;
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ /* use the OFF_T variable to pass the first element value */
+ if (firstelem != USE_LARGE_VALUE)
+ large_first_elem_val = firstelem;
+
+ fits_write_compressed_pixels(fptr, TFLOAT, large_first_elem_val, nelem,
+ 0, array, &nullvalue, status);
+ return(*status);
+ }
+
+ row=maxvalue(1,group);
+
+ ffpcle(fptr, 2, row, firstelem, nelem, array, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffppne( fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long firstelem, /* I - first vector element to write(1 = 1st) */
+ long nelem, /* I - number of values to write */
+ float *array, /* I - array of values that are written */
+ float nulval, /* I - undefined pixel value */
+ int *status) /* IO - error status */
+/*
+ Write an array of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of the
+ FITS array is not the same as the array being written). Any array values
+ that are equal to the value of nulval will be replaced with the null
+ pixel value that is appropriate for this column.
+*/
+{
+ long row;
+ float nullvalue;
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ /* use the OFF_T variable to pass the first element value */
+ if (firstelem != USE_LARGE_VALUE)
+ large_first_elem_val = firstelem;
+
+ nullvalue = nulval; /* set local variable */
+ fits_write_compressed_pixels(fptr, TFLOAT, large_first_elem_val, nelem,
+ 1, array, &nullvalue, status);
+ return(*status);
+ }
+
+ row=maxvalue(1,group);
+
+ ffpcne(fptr, 2, row, firstelem, nelem, array, nulval, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffp2de(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long ncols, /* I - number of pixels in each row of array */
+ long naxis1, /* I - FITS image NAXIS1 value */
+ long naxis2, /* I - FITS image NAXIS2 value */
+ float *array, /* I - array to be written */
+ int *status) /* IO - error status */
+/*
+ Write an entire 2-D array of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of the
+ FITS array is not the same as the array being written).
+*/
+{
+ /* call the 3D writing routine, with the 3rd dimension = 1 */
+
+ ffp3de(fptr, group, ncols, naxis2, naxis1, naxis2, 1, array, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffp3de(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long ncols, /* I - number of pixels in each row of array */
+ long nrows, /* I - number of rows in each plane of array */
+ long naxis1, /* I - FITS image NAXIS1 value */
+ long naxis2, /* I - FITS image NAXIS2 value */
+ long naxis3, /* I - FITS image NAXIS3 value */
+ float *array, /* I - array to be written */
+ int *status) /* IO - error status */
+/*
+ Write an entire 3-D cube of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of the
+ FITS array is not the same as the array being written).
+*/
+{
+ long tablerow, nfits, narray, ii, jj;
+ long fpixel[3]= {1,1,1}, lpixel[3];
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+ lpixel[0] = ncols;
+ lpixel[1] = nrows;
+ lpixel[2] = naxis3;
+
+ fits_write_compressed_img(fptr, TFLOAT, fpixel, lpixel,
+ 0, array, NULL, status);
+
+ return(*status);
+ }
+
+ tablerow=maxvalue(1,group);
+
+ if (ncols == naxis1 && nrows == naxis2) /* arrays have same size? */
+ {
+ /* all the image pixels are contiguous, so write all at once */
+ ffpcle(fptr, 2, tablerow, 1L, naxis1 * naxis2 * naxis3, array, status);
+ return(*status);
+ }
+
+ if (ncols < naxis1 || nrows < naxis2)
+ return(*status = BAD_DIMEN);
+
+ nfits = 1; /* next pixel in FITS image to write to */
+ narray = 0; /* next pixel in input array to be written */
+
+ /* loop over naxis3 planes in the data cube */
+ for (jj = 0; jj < naxis3; jj++)
+ {
+ /* loop over the naxis2 rows in the FITS image, */
+ /* writing naxis1 pixels to each row */
+
+ for (ii = 0; ii < naxis2; ii++)
+ {
+ if (ffpcle(fptr, 2, tablerow, nfits, naxis1,&array[narray],status) > 0)
+ return(*status);
+
+ nfits += naxis1;
+ narray += ncols;
+ }
+ narray += (nrows - naxis2) * ncols;
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpsse(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long naxis, /* I - number of data axes in array */
+ long *naxes, /* I - size of each FITS axis */
+ long *fpixel, /* I - 1st pixel in each axis to write (1=1st) */
+ long *lpixel, /* I - last pixel in each axis to write */
+ float *array, /* I - array to be written */
+ int *status) /* IO - error status */
+/*
+ Write a subsection of pixels to the primary array or image.
+ A subsection is defined to be any contiguous rectangular
+ array of pixels within the n-dimensional FITS data file.
+ Data conversion and scaling will be performed if necessary
+ (e.g, if the datatype of the FITS array is not the same as
+ the array being written).
+*/
+{
+ long tablerow;
+ long fpix[7], irange[7], dimen[7], astart, pstart;
+ long off2, off3, off4, off5, off6, off7;
+ long st10, st20, st30, st40, st50, st60, st70;
+ long st1, st2, st3, st4, st5, st6, st7;
+ long ii, i1, i2, i3, i4, i5, i6, i7;
+
+ if (*status > 0)
+ return(*status);
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ fits_write_compressed_img(fptr, TFLOAT, fpixel, lpixel,
+ 0, array, NULL, status);
+
+ return(*status);
+ }
+
+ if (naxis < 1 || naxis > 7)
+ return(*status = BAD_DIMEN);
+
+ tablerow=maxvalue(1,group);
+
+ /* calculate the size and number of loops to perform in each dimension */
+ for (ii = 0; ii < 7; ii++)
+ {
+ fpix[ii]=1;
+ irange[ii]=1;
+ dimen[ii]=1;
+ }
+
+ for (ii = 0; ii < naxis; ii++)
+ {
+ fpix[ii]=fpixel[ii];
+ irange[ii]=lpixel[ii]-fpixel[ii]+1;
+ dimen[ii]=naxes[ii];
+ }
+
+ i1=irange[0];
+
+ /* compute the pixel offset between each dimension */
+ off2 = dimen[0];
+ off3 = off2 * dimen[1];
+ off4 = off3 * dimen[2];
+ off5 = off4 * dimen[3];
+ off6 = off5 * dimen[4];
+ off7 = off6 * dimen[5];
+
+ st10 = fpix[0];
+ st20 = (fpix[1] - 1) * off2;
+ st30 = (fpix[2] - 1) * off3;
+ st40 = (fpix[3] - 1) * off4;
+ st50 = (fpix[4] - 1) * off5;
+ st60 = (fpix[5] - 1) * off6;
+ st70 = (fpix[6] - 1) * off7;
+
+ /* store the initial offset in each dimension */
+ st1 = st10;
+ st2 = st20;
+ st3 = st30;
+ st4 = st40;
+ st5 = st50;
+ st6 = st60;
+ st7 = st70;
+
+ astart = 0;
+
+ for (i7 = 0; i7 < irange[6]; i7++)
+ {
+ for (i6 = 0; i6 < irange[5]; i6++)
+ {
+ for (i5 = 0; i5 < irange[4]; i5++)
+ {
+ for (i4 = 0; i4 < irange[3]; i4++)
+ {
+ for (i3 = 0; i3 < irange[2]; i3++)
+ {
+ pstart = st1 + st2 + st3 + st4 + st5 + st6 + st7;
+ for (i2 = 0; i2 < irange[1]; i2++)
+ {
+ if (ffpcle(fptr, 2, tablerow, pstart, i1, &array[astart],
+ status) > 0)
+ return(*status);
+
+ astart += i1;
+ pstart += off2;
+ }
+ st2 = st20;
+ st3 = st3+off3;
+ }
+ st3 = st30;
+ st4 = st4+off4;
+ }
+ st4 = st40;
+ st5 = st5+off5;
+ }
+ st5 = st50;
+ st6 = st6+off6;
+ }
+ st6 = st60;
+ st7 = st7+off7;
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpgpe( fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long firstelem, /* I - first vector element to write(1 = 1st) */
+ long nelem, /* I - number of values to write */
+ float *array, /* I - array of values that are written */
+ int *status) /* IO - error status */
+/*
+ Write an array of group parameters to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being written).
+*/
+{
+ long row;
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ row=maxvalue(1,group);
+
+ ffpcle(fptr, 1L, row, firstelem, nelem, array, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpcle( fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to write (1 = 1st col) */
+ long firstrow, /* I - first row to write (1 = 1st row) */
+ long firstelem, /* I - first vector element to write (1 = 1st) */
+ long nelem, /* I - number of values to write */
+ float *array, /* I - array of values to write */
+ int *status) /* IO - error status */
+/*
+ Write an array of values to a column in the current FITS HDU.
+ The column number may refer to a real column in an ASCII or binary table,
+ or it may refer to a virtual column in a 1 or more grouped FITS primary
+ array. FITSIO treats a primary array as a binary table
+ with 2 vector columns: the first column contains the group parameters (often
+ with length = 0) and the second column contains the array of image pixels.
+ Each row of the table represents a group in the case of multigroup FITS
+ images.
+
+ The input array of values will be converted to the datatype of the column
+ and will be inverse-scaled by the FITS TSCALn and TZEROn values if necessary.
+*/
+{
+ int tcode, maxelem, hdutype, writeraw;
+ long twidth, incre, rownum, remain, next, ntodo;
+ long tnull;
+ OFF_T repeat, startpos, elemnum, large_elem, wrtptr, rowlen;
+ double scale, zero;
+ char tform[20], cform[20];
+ char message[FLEN_ERRMSG];
+
+ char snull[20]; /* the FITS null value */
+
+ double cbuff[DBUFFSIZE / sizeof(double)]; /* align cbuff on word boundary */
+ void *buffer;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ buffer = cbuff;
+
+ if (firstelem == USE_LARGE_VALUE)
+ large_elem = large_first_elem_val;
+ else
+ large_elem = firstelem;
+
+ /*---------------------------------------------------*/
+ /* Check input and get parameters about the column: */
+ /*---------------------------------------------------*/
+ if (ffgcpr( fptr, colnum, firstrow, large_elem, nelem, 1, &scale, &zero,
+ tform, &twidth, &tcode, &maxelem, &startpos, &elemnum, &incre,
+ &repeat, &rowlen, &hdutype, &tnull, snull, status) > 0)
+ return(*status);
+
+
+ if (tcode == TSTRING)
+ ffcfmt(tform, cform); /* derive C format for writing strings */
+
+ /*
+ if there is no scaling and the native machine format is not byteswapped
+ then we can simply write the raw data bytes into the FITS file if the
+ datatype of the FITS column is the same as the input values. Otherwise,
+ we must convert the raw values into the scaled and/or machine dependent
+ format in a temporary buffer that has been allocated for this purpose.
+ */
+ if (scale == 1. && zero == 0. &&
+ MACHINE == NATIVE && tcode == TFLOAT)
+ {
+ writeraw = 1;
+ maxelem = nelem; /* we can write the entire array at one time */
+ }
+ else
+ writeraw = 0;
+
+ /*---------------------------------------------------------------------*/
+ /* Now write the pixels to the FITS column. */
+ /* First call the ffXXfYY routine to (1) convert the datatype */
+ /* if necessary, and (2) scale the values by the FITS TSCALn and */
+ /* TZEROn linear scaling parameters into a temporary buffer. */
+ /*---------------------------------------------------------------------*/
+ remain = nelem; /* remaining number of values to write */
+ next = 0; /* next element in array to be written */
+ rownum = 0; /* row number, relative to firstrow */
+
+ while (remain)
+ {
+ /* limit the number of pixels to process a one time to the number that
+ will fit in the buffer space or to the number of pixels that remain
+ in the current vector, which ever is smaller.
+ */
+ ntodo = minvalue(remain, maxelem);
+ ntodo = minvalue(ntodo, (repeat - elemnum));
+
+ wrtptr = startpos + ((OFF_T)rownum * rowlen) + (elemnum * incre);
+
+ ffmbyt(fptr, wrtptr, IGNORE_EOF, status); /* move to write position */
+
+ switch (tcode)
+ {
+ case (TFLOAT):
+ if (writeraw)
+ {
+ /* write raw input bytes without conversion */
+ ffpr4b(fptr, ntodo, incre, &array[next], status);
+ }
+ else
+ {
+ /* convert the raw data before writing to FITS file */
+ ffr4fr4(&array[next], ntodo, scale, zero,
+ (float *) buffer, status);
+ ffpr4b(fptr, ntodo, incre, (float *) buffer, status);
+ }
+
+ break;
+
+ case (TLONGLONG):
+
+ ffr4fi8(&array[next], ntodo, scale, zero,
+ (LONGLONG *) buffer, status);
+ ffpi8b(fptr, ntodo, incre, (long *) buffer, status);
+ break;
+
+ case (TBYTE):
+
+ ffr4fi1(&array[next], ntodo, scale, zero,
+ (unsigned char *) buffer, status);
+ ffpi1b(fptr, ntodo, incre, (unsigned char *) buffer, status);
+ break;
+
+ case (TSHORT):
+
+ ffr4fi2(&array[next], ntodo, scale, zero,
+ (short *) buffer, status);
+ ffpi2b(fptr, ntodo, incre, (short *) buffer, status);
+ break;
+
+ case (TLONG):
+
+ ffr4fi4(&array[next], ntodo, scale, zero,
+ (INT32BIT *) buffer, status);
+ ffpi4b(fptr, ntodo, incre, (INT32BIT *) buffer, status);
+ break;
+
+ case (TDOUBLE):
+ ffr4fr8(&array[next], ntodo, scale, zero,
+ (double *) buffer, status);
+ ffpr8b(fptr, ntodo, incre, (double *) buffer, status);
+ break;
+
+ case (TSTRING): /* numerical column in an ASCII table */
+
+ if (cform[1] != 's') /* "%s" format is a string */
+ {
+ ffr4fstr(&array[next], ntodo, scale, zero, cform,
+ twidth, (char *) buffer, status);
+
+ if (incre == twidth) /* contiguous bytes */
+ ffpbyt(fptr, ntodo * twidth, buffer, status);
+ else
+ ffpbytoff(fptr, twidth, ntodo, incre - twidth, buffer,
+ status);
+
+ break;
+ }
+ /* can't write to string column, so fall thru to default: */
+
+ default: /* error trap */
+ sprintf(message,
+ "Cannot write numbers to column %d which has format %s",
+ colnum,tform);
+ ffpmsg(message);
+ if (hdutype == ASCII_TBL)
+ return(*status = BAD_ATABLE_FORMAT);
+ else
+ return(*status = BAD_BTABLE_FORMAT);
+
+ } /* End of switch block */
+
+ /*-------------------------*/
+ /* Check for fatal error */
+ /*-------------------------*/
+ if (*status > 0) /* test for error during previous write operation */
+ {
+ sprintf(message,
+ "Error writing elements %ld thru %ld of input data array (ffpcle).",
+ next+1, next+ntodo);
+ ffpmsg(message);
+ return(*status);
+ }
+
+ /*--------------------------------------------*/
+ /* increment the counters for the next loop */
+ /*--------------------------------------------*/
+ remain -= ntodo;
+ if (remain)
+ {
+ next += ntodo;
+ elemnum += ntodo;
+ if (elemnum == repeat) /* completed a row; start on next row */
+ {
+ elemnum = 0;
+ rownum++;
+ }
+ }
+ } /* End of main while Loop */
+
+
+ /*--------------------------------*/
+ /* check for numerical overflow */
+ /*--------------------------------*/
+ if (*status == OVERFLOW_ERR)
+ {
+ ffpmsg(
+ "Numerical overflow during type conversion while writing FITS data.");
+ *status = NUM_OVERFLOW;
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpclc( fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to write (1 = 1st col) */
+ long firstrow, /* I - first row to write (1 = 1st row) */
+ long firstelem, /* I - first vector element to write (1 = 1st) */
+ long nelem, /* I - number of values to write */
+ float *array, /* I - array of values to write */
+ int *status) /* IO - error status */
+/*
+ Write an array of complex values to a column in the current FITS HDU.
+ Each complex number if interpreted as a pair of float values.
+ The column number may refer to a real column in an ASCII or binary table,
+ or it may refer to a virtual column in a 1 or more grouped FITS primary
+ array. FITSIO treats a primary array as a binary table
+ with 2 vector columns: the first column contains the group parameters (often
+ with length = 0) and the second column contains the array of image pixels.
+ Each row of the table represents a group in the case of multigroup FITS
+ images.
+
+ The input array of values will be converted to the datatype of the column
+ if necessary, but normally complex values should only be written to a binary
+ table with TFORMn = 'rC' where r is an optional repeat count. The TSCALn and
+ TZERO keywords should not be used with complex numbers because mathmatically
+ the scaling should only be applied to the real (first) component of the
+ complex value.
+*/
+{
+ /* simply multiply the number of elements by 2, and call ffpcle */
+
+ ffpcle(fptr, colnum, firstrow, (firstelem - 1) * 2 + 1,
+ nelem * 2, array, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpcne( fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to write (1 = 1st col) */
+ long firstrow, /* I - first row to write (1 = 1st row) */
+ long firstelem, /* I - first vector element to write (1 = 1st) */
+ long nelem, /* I - number of values to write */
+ float *array, /* I - array of values to write */
+ float nulvalue, /* I - value used to flag undefined pixels */
+ int *status) /* IO - error status */
+/*
+ Write an array of elements to the specified column of a table. Any input
+ pixels equal to the value of nulvalue will be replaced by the appropriate
+ null value in the output FITS file.
+
+ The input array of values will be converted to the datatype of the column
+ and will be inverse-scaled by the FITS TSCALn and TZEROn values if necessary
+*/
+{
+ tcolumn *colptr;
+ long ngood = 0, nbad = 0, ii, fstrow;
+ OFF_T large_elem, repeat, first, fstelm;
+ int tcode, overflow = 0;
+
+ if (*status > 0)
+ return(*status);
+
+ /* reset position to the correct HDU if necessary */
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ {
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+ }
+ else if ((fptr->Fptr)->datastart == DATA_UNDEFINED)
+ {
+ if ( ffrdef(fptr, status) > 0) /* rescan header */
+ return(*status);
+ }
+
+ colptr = (fptr->Fptr)->tableptr; /* point to first column */
+ colptr += (colnum - 1); /* offset to correct column structure */
+
+ repeat = colptr->trepeat; /* repeat count for this column */
+ fits_get_coltype(fptr, colnum, &tcode, NULL, NULL, status);
+
+ if (tcode >= TCOMPLEX)
+ { /* treat complex columns as pairs of numbers */
+ repeat *= 2;
+ }
+
+ if (firstelem == USE_LARGE_VALUE)
+ large_elem = large_first_elem_val;
+ else
+ large_elem = firstelem;
+
+ /* hereafter, pass first element parameter via global variable */
+ firstelem = USE_LARGE_VALUE;
+
+ /* absolute element number in the column */
+ first = (firstrow - 1) * repeat + large_elem;
+
+ for (ii = 0; ii < nelem; ii++)
+ {
+ if (array[ii] != nulvalue) /* is this a good pixel? */
+ {
+ if (nbad) /* write previous string of bad pixels */
+ {
+ fstelm = ii - nbad + first; /* absolute element number */
+ fstrow = (fstelm - 1) / repeat + 1; /* starting row number */
+ fstelm = fstelm - (fstrow - 1) * repeat; /* relative number */
+ large_first_elem_val = fstelm;
+
+ /* call ffpcluc, not ffpclu, in case we are writing to a
+ complex ('C') binary table column */
+ if (ffpcluc(fptr, colnum, fstrow, firstelem, nbad, status) > 0)
+ return(*status);
+
+ nbad=0;
+ }
+
+ ngood = ngood +1; /* the consecutive number of good pixels */
+ }
+ else
+ {
+ if (ngood) /* write previous string of good pixels */
+ {
+ fstelm = ii - ngood + first; /* absolute element number */
+ fstrow = (fstelm - 1) / repeat + 1; /* starting row number */
+ fstelm = fstelm - (fstrow - 1) * repeat; /* relative number */
+ large_first_elem_val = fstelm;
+
+ if (ffpcle(fptr, colnum, fstrow, firstelem, ngood, &array[ii-ngood],
+ status) > 0) {
+ if (*status == NUM_OVERFLOW)
+ {
+ overflow = 1;
+ *status = 0;
+ } else {
+ return(*status);
+ }
+ }
+
+ ngood=0;
+ }
+
+ nbad = nbad +1; /* the consecutive number of bad pixels */
+ }
+ }
+
+ /* finished loop; now just write the last set of pixels */
+
+ if (ngood) /* write last string of good pixels */
+ {
+ fstelm = ii - ngood + first; /* absolute element number */
+ fstrow = (fstelm - 1) / repeat + 1; /* starting row number */
+ fstelm = fstelm - (fstrow - 1) * repeat; /* relative number */
+ large_first_elem_val = fstelm;
+
+ ffpcle(fptr, colnum, fstrow, firstelem, ngood, &array[ii-ngood], status);
+ }
+ else if (nbad) /* write last string of bad pixels */
+ {
+ fstelm = ii - nbad + first; /* absolute element number */
+ fstrow = (fstelm - 1) / repeat + 1; /* starting row number */
+ fstelm = fstelm - (fstrow - 1) * repeat; /* relative number */
+ large_first_elem_val = fstelm;
+ ffpcluc(fptr, colnum, fstrow, firstelem, nbad, status);
+ }
+
+ if (*status <= 0) {
+ if (overflow) {
+ *status = NUM_OVERFLOW;
+ }
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffr4fi1(float *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ unsigned char *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required.
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] < DUCHAR_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (input[ii] > DUCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UCHAR_MAX;
+ }
+ else
+ output[ii] = (unsigned char) input[ii];
+ }
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = (input[ii] - zero) / scale;
+
+ if (dvalue < DUCHAR_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DUCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UCHAR_MAX;
+ }
+ else
+ output[ii] = (unsigned char) (dvalue + .5);
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffr4fi2(float *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ short *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required.
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] < DSHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MIN;
+ }
+ else if (input[ii] > DSHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MAX;
+ }
+ else
+ output[ii] = (short) input[ii];
+ }
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = (input[ii] - zero) / scale;
+
+ if (dvalue < DSHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MIN;
+ }
+ else if (dvalue > DSHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MAX;
+ }
+ else
+ {
+ if (dvalue >= 0)
+ output[ii] = (short) (dvalue + .5);
+ else
+ output[ii] = (short) (dvalue - .5);
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffr4fi4(float *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ INT32BIT *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required.
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] < DINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT32_MIN;
+ }
+ else if (input[ii] > DINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT32_MAX;
+ }
+ else
+ output[ii] = (INT32BIT) input[ii];
+ }
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = (input[ii] - zero) / scale;
+
+ if (dvalue < DINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT32_MIN;
+ }
+ else if (dvalue > DINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT32_MAX;
+ }
+ else
+ {
+ if (dvalue >= 0)
+ output[ii] = (INT32BIT) (dvalue + .5);
+ else
+ output[ii] = (INT32BIT) (dvalue - .5);
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffr4fi8(float *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ LONGLONG *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required.
+*/
+{
+#if (LONGSIZE == 32) && (! defined HAVE_LONGLONG)
+
+/* don't have a native 8-byte integer, so have to construct the */
+/* 2 equivalent 4-byte integers have the same bit pattern */
+
+ unsigned long *uoutput;
+ long ii, jj, kk, temp;
+ double dvalue;
+
+ uoutput = (unsigned long *) output;
+
+#if BYTESWAPPED /* jj points to the most significant part of the 8-byte int */
+ jj = 1;
+ kk = 0;
+#else
+ jj = 0;
+ kk = 1;
+#endif
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++, jj += 2, kk += 2)
+ {
+ if (input[ii] < DLONGLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[jj] = LONG_MIN;
+ output[kk] = 0;
+ }
+ else if (input[ii] > DLONGLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[jj] = LONG_MAX;
+ output[kk] = -1;
+ }
+ else
+ {
+ if (input[ii] < 0)
+ {
+ temp = (input[ii] + 1.) / 4294967296. - 1.;
+ output[jj] = temp;
+ uoutput[kk] = 4294967296. +
+ (input[ii] - (double) (temp + 1) * 4294967296.);
+ }
+ else
+ {
+ temp = input[ii] / 4294967296.;
+ output[jj] = temp;
+ uoutput[kk] = input[ii] - (double) temp * 4294967296.;
+ }
+ }
+ }
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++, jj += 2, kk += 2)
+ {
+ dvalue = (input[ii] - zero) / scale;
+
+ if (dvalue < DLONGLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[jj] = LONG_MIN;
+ output[kk] = 0;
+ }
+ else if (dvalue > DLONGLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[jj] = LONG_MAX;
+ output[kk] = -1;
+ }
+ else
+ {
+ if (dvalue < 0)
+ {
+ temp = (dvalue + 1.) / 4294967296. - 1.;
+ output[jj] = temp;
+ uoutput[kk] = 4294967296. +
+ (dvalue - (double) (temp + 1) * 4294967296.);
+ }
+ else
+ {
+ temp = dvalue / 4294967296.;
+ output[jj] = temp;
+ uoutput[kk] = dvalue - (double) temp * 4294967296.;
+ }
+ }
+ }
+ }
+
+#else
+
+/* this is the much simpler case where the native 8-byte integer exists */
+
+ long ii;
+ double dvalue;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] < DLONGLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONGLONG_MIN;
+ }
+ else if (input[ii] > DLONGLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONGLONG_MAX;
+ }
+ else
+ output[ii] = (long) input[ii];
+ }
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = (input[ii] - zero) / scale;
+
+ if (dvalue < DLONGLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONGLONG_MIN;
+ }
+ else if (dvalue > DINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONGLONG_MAX;
+ }
+ else
+ {
+ if (dvalue >= 0)
+ output[ii] = (LONGLONG) (dvalue + .5);
+ else
+ output[ii] = (LONGLONG) (dvalue - .5);
+ }
+ }
+ }
+
+#endif
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffr4fr4(float *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ float *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required.
+*/
+{
+ long ii;
+
+ if (scale == 1. && zero == 0.)
+ {
+ memcpy(output, input, ntodo * sizeof(float) ); /* copy input to output */
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = (input[ii] - zero) / scale;
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffr4fr8(float *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ double *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required.
+*/
+{
+ long ii;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = (double) input[ii];
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = (input[ii] - zero) / scale;
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffr4fstr(float *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ char *cform, /* I - format for output string values */
+ long twidth, /* I - width of each field, in chars */
+ char *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do scaling if required.
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ sprintf(output, cform, (double) input[ii]);
+ output += twidth;
+
+ if (*output) /* if this char != \0, then overflow occurred */
+ *status = OVERFLOW_ERR;
+ }
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = (input[ii] - zero) / scale;
+ sprintf(output, cform, dvalue);
+ output += twidth;
+
+ if (*output) /* if this char != \0, then overflow occurred */
+ *status = OVERFLOW_ERR;
+ }
+ }
+ return(*status);
+}
diff --git a/pkg/tbtables/cfitsio/putcoli.c b/pkg/tbtables/cfitsio/putcoli.c
new file mode 100644
index 00000000..a413f952
--- /dev/null
+++ b/pkg/tbtables/cfitsio/putcoli.c
@@ -0,0 +1,1039 @@
+/* This file, putcoli.c, contains routines that write data elements to */
+/* a FITS image or table, with short datatype. */
+
+/* The FITSIO software was written by William Pence at the High Energy */
+/* Astrophysic Science Archive Research Center (HEASARC) at the NASA */
+/* Goddard Space Flight Center. */
+
+#include <limits.h>
+#include <string.h>
+#include <stdlib.h>
+#include "fitsio2.h"
+
+/* declare variable for passing large firstelem values between routines */
+extern OFF_T large_first_elem_val;
+
+/*--------------------------------------------------------------------------*/
+int ffppri( fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write (1 = 1st group) */
+ long firstelem, /* I - first vector element to write (1 = 1st) */
+ long nelem, /* I - number of values to write */
+ short *array, /* I - array of values that are written */
+ int *status) /* IO - error status */
+/*
+ Write an array of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being written).
+*/
+{
+ long row;
+ short nullvalue;
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ /* use the OFF_T variable to pass the first element value */
+ if (firstelem != USE_LARGE_VALUE)
+ large_first_elem_val = firstelem;
+
+ fits_write_compressed_pixels(fptr, TSHORT, large_first_elem_val, nelem,
+ 0, array, &nullvalue, status);
+ return(*status);
+ }
+
+ row=maxvalue(1,group);
+
+ ffpcli(fptr, 2, row, firstelem, nelem, array, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffppni( fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long firstelem, /* I - first vector element to write(1 = 1st) */
+ long nelem, /* I - number of values to write */
+ short *array, /* I - array of values that are written */
+ short nulval, /* I - undefined pixel value */
+ int *status) /* IO - error status */
+/*
+ Write an array of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of the
+ FITS array is not the same as the array being written). Any array values
+ that are equal to the value of nulval will be replaced with the null
+ pixel value that is appropriate for this column.
+*/
+{
+ long row;
+ short nullvalue;
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ /* use the OFF_T variable to pass the first element value */
+ if (firstelem != USE_LARGE_VALUE)
+ large_first_elem_val = firstelem;
+
+ nullvalue = nulval; /* set local variable */
+ fits_write_compressed_pixels(fptr, TSHORT, large_first_elem_val, nelem,
+ 1, array, &nullvalue, status);
+ return(*status);
+ }
+
+ row=maxvalue(1,group);
+
+ ffpcni(fptr, 2, row, firstelem, nelem, array, nulval, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffp2di(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long ncols, /* I - number of pixels in each row of array */
+ long naxis1, /* I - FITS image NAXIS1 value */
+ long naxis2, /* I - FITS image NAXIS2 value */
+ short *array, /* I - array to be written */
+ int *status) /* IO - error status */
+/*
+ Write an entire 2-D array of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of the
+ FITS array is not the same as the array being written).
+*/
+{
+ /* call the 3D writing routine, with the 3rd dimension = 1 */
+
+ ffp3di(fptr, group, ncols, naxis2, naxis1, naxis2, 1, array, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffp3di(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long ncols, /* I - number of pixels in each row of array */
+ long nrows, /* I - number of rows in each plane of array */
+ long naxis1, /* I - FITS image NAXIS1 value */
+ long naxis2, /* I - FITS image NAXIS2 value */
+ long naxis3, /* I - FITS image NAXIS3 value */
+ short *array, /* I - array to be written */
+ int *status) /* IO - error status */
+/*
+ Write an entire 3-D cube of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of the
+ FITS array is not the same as the array being written).
+*/
+{
+ long tablerow, nfits, narray, ii, jj;
+ long fpixel[3]= {1,1,1}, lpixel[3];
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+ lpixel[0] = ncols;
+ lpixel[1] = nrows;
+ lpixel[2] = naxis3;
+
+ fits_write_compressed_img(fptr, TSHORT, fpixel, lpixel,
+ 0, array, NULL, status);
+
+ return(*status);
+ }
+
+ tablerow=maxvalue(1,group);
+
+ if (ncols == naxis1 && nrows == naxis2) /* arrays have same size? */
+ {
+ /* all the image pixels are contiguous, so write all at once */
+ ffpcli(fptr, 2, tablerow, 1L, naxis1 * naxis2 * naxis3, array, status);
+ return(*status);
+ }
+
+ if (ncols < naxis1 || nrows < naxis2)
+ return(*status = BAD_DIMEN);
+
+ nfits = 1; /* next pixel in FITS image to write to */
+ narray = 0; /* next pixel in input array to be written */
+
+ /* loop over naxis3 planes in the data cube */
+ for (jj = 0; jj < naxis3; jj++)
+ {
+ /* loop over the naxis2 rows in the FITS image, */
+ /* writing naxis1 pixels to each row */
+
+ for (ii = 0; ii < naxis2; ii++)
+ {
+ if (ffpcli(fptr, 2, tablerow, nfits, naxis1,&array[narray],status) > 0)
+ return(*status);
+
+ nfits += naxis1;
+ narray += ncols;
+ }
+ narray += (nrows - naxis2) * ncols;
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpssi(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long naxis, /* I - number of data axes in array */
+ long *naxes, /* I - size of each FITS axis */
+ long *fpixel, /* I - 1st pixel in each axis to write (1=1st) */
+ long *lpixel, /* I - last pixel in each axis to write */
+ short *array, /* I - array to be written */
+ int *status) /* IO - error status */
+/*
+ Write a subsection of pixels to the primary array or image.
+ A subsection is defined to be any contiguous rectangular
+ array of pixels within the n-dimensional FITS data file.
+ Data conversion and scaling will be performed if necessary
+ (e.g, if the datatype of the FITS array is not the same as
+ the array being written).
+*/
+{
+ long tablerow;
+ long fpix[7], irange[7], dimen[7], astart, pstart;
+ long off2, off3, off4, off5, off6, off7;
+ long st10, st20, st30, st40, st50, st60, st70;
+ long st1, st2, st3, st4, st5, st6, st7;
+ long ii, i1, i2, i3, i4, i5, i6, i7;
+
+ if (*status > 0)
+ return(*status);
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ fits_write_compressed_img(fptr, TSHORT, fpixel, lpixel,
+ 0, array, NULL, status);
+
+ return(*status);
+ }
+
+ if (naxis < 1 || naxis > 7)
+ return(*status = BAD_DIMEN);
+
+ tablerow=maxvalue(1,group);
+
+ /* calculate the size and number of loops to perform in each dimension */
+ for (ii = 0; ii < 7; ii++)
+ {
+ fpix[ii]=1;
+ irange[ii]=1;
+ dimen[ii]=1;
+ }
+
+ for (ii = 0; ii < naxis; ii++)
+ {
+ fpix[ii]=fpixel[ii];
+ irange[ii]=lpixel[ii]-fpixel[ii]+1;
+ dimen[ii]=naxes[ii];
+ }
+
+ i1=irange[0];
+
+ /* compute the pixel offset between each dimension */
+ off2 = dimen[0];
+ off3 = off2 * dimen[1];
+ off4 = off3 * dimen[2];
+ off5 = off4 * dimen[3];
+ off6 = off5 * dimen[4];
+ off7 = off6 * dimen[5];
+
+ st10 = fpix[0];
+ st20 = (fpix[1] - 1) * off2;
+ st30 = (fpix[2] - 1) * off3;
+ st40 = (fpix[3] - 1) * off4;
+ st50 = (fpix[4] - 1) * off5;
+ st60 = (fpix[5] - 1) * off6;
+ st70 = (fpix[6] - 1) * off7;
+
+ /* store the initial offset in each dimension */
+ st1 = st10;
+ st2 = st20;
+ st3 = st30;
+ st4 = st40;
+ st5 = st50;
+ st6 = st60;
+ st7 = st70;
+
+ astart = 0;
+
+ for (i7 = 0; i7 < irange[6]; i7++)
+ {
+ for (i6 = 0; i6 < irange[5]; i6++)
+ {
+ for (i5 = 0; i5 < irange[4]; i5++)
+ {
+ for (i4 = 0; i4 < irange[3]; i4++)
+ {
+ for (i3 = 0; i3 < irange[2]; i3++)
+ {
+ pstart = st1 + st2 + st3 + st4 + st5 + st6 + st7;
+ for (i2 = 0; i2 < irange[1]; i2++)
+ {
+ if (ffpcli(fptr, 2, tablerow, pstart, i1, &array[astart],
+ status) > 0)
+ return(*status);
+
+ astart += i1;
+ pstart += off2;
+ }
+ st2 = st20;
+ st3 = st3+off3;
+ }
+ st3 = st30;
+ st4 = st4+off4;
+ }
+ st4 = st40;
+ st5 = st5+off5;
+ }
+ st5 = st50;
+ st6 = st6+off6;
+ }
+ st6 = st60;
+ st7 = st7+off7;
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpgpi( fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long firstelem, /* I - first vector element to write(1 = 1st) */
+ long nelem, /* I - number of values to write */
+ short *array, /* I - array of values that are written */
+ int *status) /* IO - error status */
+/*
+ Write an array of group parameters to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being written).
+*/
+{
+ long row;
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ row=maxvalue(1,group);
+
+ ffpcli(fptr, 1L, row, firstelem, nelem, array, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpcli( fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to write (1 = 1st col) */
+ long firstrow, /* I - first row to write (1 = 1st row) */
+ long firstelem, /* I - first vector element to write (1 = 1st) */
+ long nelem, /* I - number of values to write */
+ short *array, /* I - array of values to write */
+ int *status) /* IO - error status */
+/*
+ Write an array of values to a column in the current FITS HDU.
+ The column number may refer to a real column in an ASCII or binary table,
+ or it may refer to a virtual column in a 1 or more grouped FITS primary
+ array. FITSIO treats a primary array as a binary table with
+ 2 vector columns: the first column contains the group parameters (often
+ with length = 0) and the second column contains the array of image pixels.
+ Each row of the table represents a group in the case of multigroup FITS
+ images.
+
+ The input array of values will be converted to the datatype of the column
+ and will be inverse-scaled by the FITS TSCALn and TZEROn values if necessary.
+*/
+{
+ int tcode, maxelem, hdutype, writeraw;
+ long twidth, incre, rownum, remain, next, ntodo;
+ long tnull;
+ OFF_T repeat, startpos, elemnum, large_elem, wrtptr, rowlen;
+ double scale, zero;
+ char tform[20], cform[20];
+ char message[FLEN_ERRMSG];
+
+ char snull[20]; /* the FITS null value */
+
+ double cbuff[DBUFFSIZE / sizeof(double)]; /* align cbuff on word boundary */
+ void *buffer;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ buffer = cbuff;
+
+ if (firstelem == USE_LARGE_VALUE)
+ large_elem = large_first_elem_val;
+ else
+ large_elem = firstelem;
+
+ /*---------------------------------------------------*/
+ /* Check input and get parameters about the column: */
+ /*---------------------------------------------------*/
+ if (ffgcpr( fptr, colnum, firstrow, large_elem, nelem, 1, &scale, &zero,
+ tform, &twidth, &tcode, &maxelem, &startpos, &elemnum, &incre,
+ &repeat, &rowlen, &hdutype, &tnull, snull, status) > 0)
+ return(*status);
+
+ if (tcode == TSTRING)
+ ffcfmt(tform, cform); /* derive C format for writing strings */
+
+ /*
+ if there is no scaling and the native machine format is not byteswapped,
+ then we can simply write the raw data bytes into the FITS file if the
+ datatype of the FITS column is the same as the input values. Otherwise,
+ we must convert the raw values into the scaled and/or machine dependent
+ format in a temporary buffer that has been allocated for this purpose.
+ */
+ if (scale == 1. && zero == 0. &&
+ MACHINE == NATIVE && tcode == TSHORT)
+ {
+ writeraw = 1;
+ maxelem = nelem; /* we can write the entire array at one time */
+ }
+ else
+ writeraw = 0;
+
+ /*---------------------------------------------------------------------*/
+ /* Now write the pixels to the FITS column. */
+ /* First call the ffXXfYY routine to (1) convert the datatype */
+ /* if necessary, and (2) scale the values by the FITS TSCALn and */
+ /* TZEROn linear scaling parameters into a temporary buffer. */
+ /*---------------------------------------------------------------------*/
+ remain = nelem; /* remaining number of values to write */
+ next = 0; /* next element in array to be written */
+ rownum = 0; /* row number, relative to firstrow */
+
+ while (remain)
+ {
+ /* limit the number of pixels to process a one time to the number that
+ will fit in the buffer space or to the number of pixels that remain
+ in the current vector, which ever is smaller.
+ */
+ ntodo = minvalue(remain, maxelem);
+ ntodo = minvalue(ntodo, (repeat - elemnum));
+
+ wrtptr = startpos + ((OFF_T)rownum * rowlen) + (elemnum * incre);
+
+ ffmbyt(fptr, wrtptr, IGNORE_EOF, status); /* move to write position */
+
+ switch (tcode)
+ {
+ case (TSHORT):
+ if (writeraw)
+ {
+ /* write raw input bytes without conversion */
+ ffpi2b(fptr, ntodo, incre, &array[next], status);
+ }
+ else
+ {
+ /* convert the raw data before writing to FITS file */
+ ffi2fi2(&array[next], ntodo, scale, zero,
+ (short *) buffer, status);
+ ffpi2b(fptr, ntodo, incre, (short *) buffer, status);
+ }
+
+ break;
+
+ case (TLONGLONG):
+
+ ffi2fi8(&array[next], ntodo, scale, zero,
+ (LONGLONG *) buffer, status);
+ ffpi8b(fptr, ntodo, incre, (long *) buffer, status);
+ break;
+
+ case (TBYTE):
+
+ ffi2fi1(&array[next], ntodo, scale, zero,
+ (unsigned char *) buffer, status);
+ ffpi1b(fptr, ntodo, incre, (unsigned char *) buffer, status);
+ break;
+
+ case (TLONG):
+
+ ffi2fi4(&array[next], ntodo, scale, zero,
+ (INT32BIT *) buffer, status);
+ ffpi4b(fptr, ntodo, incre, (INT32BIT *) buffer, status);
+ break;
+
+ case (TFLOAT):
+
+ ffi2fr4(&array[next], ntodo, scale, zero,
+ (float *) buffer, status);
+ ffpr4b(fptr, ntodo, incre, (float *) buffer, status);
+ break;
+
+ case (TDOUBLE):
+ ffi2fr8(&array[next], ntodo, scale, zero,
+ (double *) buffer, status);
+ ffpr8b(fptr, ntodo, incre, (double *) buffer, status);
+ break;
+
+ case (TSTRING): /* numerical column in an ASCII table */
+
+ if (cform[1] != 's') /* "%s" format is a string */
+ {
+ ffi2fstr(&array[next], ntodo, scale, zero, cform,
+ twidth, (char *) buffer, status);
+
+
+ if (incre == twidth) /* contiguous bytes */
+ ffpbyt(fptr, ntodo * twidth, buffer, status);
+ else
+ ffpbytoff(fptr, twidth, ntodo, incre - twidth, buffer,
+ status);
+
+ break;
+ }
+ /* can't write to string column, so fall thru to default: */
+
+ default: /* error trap */
+ sprintf(message,
+ "Cannot write numbers to column %d which has format %s",
+ colnum,tform);
+ ffpmsg(message);
+ if (hdutype == ASCII_TBL)
+ return(*status = BAD_ATABLE_FORMAT);
+ else
+ return(*status = BAD_BTABLE_FORMAT);
+
+ } /* End of switch block */
+
+ /*-------------------------*/
+ /* Check for fatal error */
+ /*-------------------------*/
+ if (*status > 0) /* test for error during previous write operation */
+ {
+ sprintf(message,
+ "Error writing elements %ld thru %ld of input data array (ffpcli).",
+ next+1, next+ntodo);
+ ffpmsg(message);
+ return(*status);
+ }
+
+ /*--------------------------------------------*/
+ /* increment the counters for the next loop */
+ /*--------------------------------------------*/
+ remain -= ntodo;
+ if (remain)
+ {
+ next += ntodo;
+ elemnum += ntodo;
+ if (elemnum == repeat) /* completed a row; start on next row */
+ {
+ elemnum = 0;
+ rownum++;
+ }
+ }
+ } /* End of main while Loop */
+
+
+ /*--------------------------------*/
+ /* check for numerical overflow */
+ /*--------------------------------*/
+ if (*status == OVERFLOW_ERR)
+ {
+ ffpmsg(
+ "Numerical overflow during type conversion while writing FITS data.");
+ *status = NUM_OVERFLOW;
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpcni( fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to write (1 = 1st col) */
+ long firstrow, /* I - first row to write (1 = 1st row) */
+ long firstelem, /* I - first vector element to write (1 = 1st) */
+ long nelem, /* I - number of values to write */
+ short *array, /* I - array of values to write */
+ short nulvalue, /* I - value used to flag undefined pixels */
+ int *status) /* IO - error status */
+/*
+ Write an array of elements to the specified column of a table. Any input
+ pixels equal to the value of nulvalue will be replaced by the appropriate
+ null value in the output FITS file.
+
+ The input array of values will be converted to the datatype of the column
+ and will be inverse-scaled by the FITS TSCALn and TZEROn values if necessary
+*/
+{
+ tcolumn *colptr;
+ long ngood = 0, nbad = 0, ii, fstrow;
+ OFF_T large_elem, repeat, first, fstelm;
+
+ if (*status > 0)
+ return(*status);
+
+ /* reset position to the correct HDU if necessary */
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ {
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+ }
+ else if ((fptr->Fptr)->datastart == DATA_UNDEFINED)
+ {
+ if ( ffrdef(fptr, status) > 0) /* rescan header */
+ return(*status);
+ }
+
+ colptr = (fptr->Fptr)->tableptr; /* point to first column */
+ colptr += (colnum - 1); /* offset to correct column structure */
+
+ repeat = colptr->trepeat; /* repeat count for this column */
+
+ if (firstelem == USE_LARGE_VALUE)
+ large_elem = large_first_elem_val;
+ else
+ large_elem = firstelem;
+
+ /* hereafter, pass first element parameter via global variable */
+ firstelem = USE_LARGE_VALUE;
+
+ /* absolute element number in the column */
+ first = (firstrow - 1) * repeat + large_elem;
+
+ for (ii = 0; ii < nelem; ii++)
+ {
+ if (array[ii] != nulvalue) /* is this a good pixel? */
+ {
+ if (nbad) /* write previous string of bad pixels */
+ {
+ fstelm = ii - nbad + first; /* absolute element number */
+ fstrow = (fstelm - 1) / repeat + 1; /* starting row number */
+ fstelm = fstelm - (fstrow - 1) * repeat; /* relative number */
+ large_first_elem_val = fstelm;
+
+ if (ffpclu(fptr, colnum, fstrow, firstelem, nbad, status) > 0)
+ return(*status);
+
+ nbad=0;
+ }
+
+ ngood = ngood +1; /* the consecutive number of good pixels */
+ }
+ else
+ {
+ if (ngood) /* write previous string of good pixels */
+ {
+ fstelm = ii - ngood + first; /* absolute element number */
+ fstrow = (fstelm - 1) / repeat + 1; /* starting row number */
+ fstelm = fstelm - (fstrow - 1) * repeat; /* relative number */
+ large_first_elem_val = fstelm;
+
+ if (ffpcli(fptr, colnum, fstrow, firstelem, ngood, &array[ii-ngood],
+ status) > 0)
+ return(*status);
+
+ ngood=0;
+ }
+
+ nbad = nbad +1; /* the consecutive number of bad pixels */
+ }
+ }
+
+ /* finished loop; now just write the last set of pixels */
+
+ if (ngood) /* write last string of good pixels */
+ {
+ fstelm = ii - ngood + first; /* absolute element number */
+ fstrow = (fstelm - 1) / repeat + 1; /* starting row number */
+ fstelm = fstelm - (fstrow - 1) * repeat; /* relative number */
+ large_first_elem_val = fstelm;
+
+ ffpcli(fptr, colnum, fstrow, firstelem, ngood, &array[ii-ngood], status);
+ }
+ else if (nbad) /* write last string of bad pixels */
+ {
+ fstelm = ii - nbad + first; /* absolute element number */
+ fstrow = (fstelm - 1) / repeat + 1; /* starting row number */
+ fstelm = fstelm - (fstrow - 1) * repeat; /* relative number */
+ large_first_elem_val = fstelm;
+
+ ffpclu(fptr, colnum, fstrow, firstelem, nbad, status);
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffi2fi1(short *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ unsigned char *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] < 0)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (input[ii] > UCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UCHAR_MAX;
+ }
+ else
+ output[ii] = input[ii];
+ }
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = (input[ii] - zero) / scale;
+
+ if (dvalue < DUCHAR_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DUCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UCHAR_MAX;
+ }
+ else
+ output[ii] = (unsigned char) (dvalue + .5);
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffi2fi2(short *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ short *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (scale == 1. && zero == 0.)
+ {
+ memcpy(output, input, ntodo * sizeof(short) );
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = (input[ii] - zero) / scale;
+
+ if (dvalue < DSHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MIN;
+ }
+ else if (dvalue > DSHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MAX;
+ }
+ else
+ {
+ if (dvalue >= 0)
+ output[ii] = (short) (dvalue + .5);
+ else
+ output[ii] = (short) (dvalue - .5);
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffi2fi4(short *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ INT32BIT *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = (INT32BIT) input[ii]; /* just copy input to output */
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = (input[ii] - zero) / scale;
+
+ if (dvalue < DINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT32_MIN;
+ }
+ else if (dvalue > DINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT32_MAX;
+ }
+ else
+ {
+ if (dvalue >= 0)
+ output[ii] = (INT32BIT) (dvalue + .5);
+ else
+ output[ii] = (INT32BIT) (dvalue - .5);
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffi2fi8(short *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ LONGLONG *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required
+*/
+{
+#if (LONGSIZE == 32) && (! defined HAVE_LONGLONG)
+
+/* don't have a native 8-byte integer, so have to construct the */
+/* 2 equivalent 4-byte integers have the same bit pattern */
+
+ unsigned long *uoutput;
+ long ii, jj, kk, temp;
+ double dvalue;
+
+ uoutput = (unsigned long *) output;
+
+#if BYTESWAPPED /* jj points to the most significant part of the 8-byte int */
+ jj = 1;
+ kk = 0;
+#else
+ jj = 0;
+ kk = 1;
+#endif
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++, jj += 2, kk += 2)
+ {
+ if (input[ii] < 0)
+ output[jj] = -1;
+ else
+ output[jj] = 0;
+
+ output[kk] = input[ii];
+ }
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++, jj += 2, kk += 2)
+ {
+ dvalue = (input[ii] - zero) / scale;
+
+ if (dvalue < DLONGLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[jj] = LONG_MIN;
+ output[kk] = 0;
+ }
+ else if (dvalue > DLONGLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[jj] = LONG_MAX;
+ output[kk] = -1;
+ }
+ else
+ {
+ if (dvalue < 0)
+ {
+ temp = (dvalue + 1.) / 4294967296. - 1.;
+ output[jj] = temp;
+ uoutput[kk] = 4294967296. +
+ (dvalue - (double) (temp + 1) * 4294967296.);
+ }
+ else
+ {
+ temp = dvalue / 4294967296.;
+ output[jj] = temp;
+ uoutput[kk] = dvalue - (double) temp * 4294967296.;
+ }
+ }
+ }
+ }
+
+#else
+
+/* this is the much simpler case where the native 8-byte integer exists */
+
+ long ii;
+ double dvalue;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = input[ii];
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = (input[ii] - zero) / scale;
+
+ if (dvalue < DLONGLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONGLONG_MIN;
+ }
+ else if (dvalue > DLONGLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONGLONG_MAX;
+ }
+ else
+ {
+ if (dvalue >= 0)
+ output[ii] = (LONGLONG) (dvalue + .5);
+ else
+ output[ii] = (LONGLONG) (dvalue - .5);
+ }
+ }
+ }
+
+#endif
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffi2fr4(short *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ float *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required.
+*/
+{
+ long ii;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = (float) input[ii];
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = (input[ii] - zero) / scale;
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffi2fr8(short *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ double *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required.
+*/
+{
+ long ii;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = (double) input[ii];
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = (input[ii] - zero) / scale;
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffi2fstr(short *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ char *cform, /* I - format for output string values */
+ long twidth, /* I - width of each field, in chars */
+ char *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do scaling if required.
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ sprintf(output, cform, (double) input[ii]);
+ output += twidth;
+
+ if (*output) /* if this char != \0, then overflow occurred */
+ *status = OVERFLOW_ERR;
+ }
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = (input[ii] - zero) / scale;
+ sprintf(output, cform, dvalue);
+ output += twidth;
+
+ if (*output) /* if this char != \0, then overflow occurred */
+ *status = OVERFLOW_ERR;
+ }
+ }
+ return(*status);
+}
diff --git a/pkg/tbtables/cfitsio/putcolj.c b/pkg/tbtables/cfitsio/putcolj.c
new file mode 100644
index 00000000..8cfee07c
--- /dev/null
+++ b/pkg/tbtables/cfitsio/putcolj.c
@@ -0,0 +1,2018 @@
+/* This file, putcolj.c, contains routines that write data elements to */
+/* a FITS image or table, with long datatype. */
+
+/* The FITSIO software was written by William Pence at the High Energy */
+/* Astrophysic Science Archive Research Center (HEASARC) at the NASA */
+/* Goddard Space Flight Center. */
+
+#include <limits.h>
+#include <string.h>
+#include <stdlib.h>
+#include "fitsio2.h"
+
+/* declare variable for passing large firstelem values between routines */
+extern OFF_T large_first_elem_val;
+
+/*--------------------------------------------------------------------------*/
+int ffpprj( fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long firstelem, /* I - first vector element to write(1 = 1st) */
+ long nelem, /* I - number of values to write */
+ long *array, /* I - array of values that are written */
+ int *status) /* IO - error status */
+/*
+ Write an array of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being written).
+*/
+{
+ long row;
+ long nullvalue;
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ /* use the OFF_T variable to pass the first element value */
+ if (firstelem != USE_LARGE_VALUE)
+ large_first_elem_val = firstelem;
+
+ fits_write_compressed_pixels(fptr, TLONG, large_first_elem_val, nelem,
+ 0, array, &nullvalue, status);
+ return(*status);
+ }
+
+ row=maxvalue(1,group);
+
+ ffpclj(fptr, 2, row, firstelem, nelem, array, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffppnj( fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long firstelem, /* I - first vector element to write(1 = 1st) */
+ long nelem, /* I - number of values to write */
+ long *array, /* I - array of values that are written */
+ long nulval, /* I - undefined pixel value */
+ int *status) /* IO - error status */
+/*
+ Write an array of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of the
+ FITS array is not the same as the array being written). Any array values
+ that are equal to the value of nulval will be replaced with the null
+ pixel value that is appropriate for this column.
+*/
+{
+ long row;
+ long nullvalue;
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ /* use the OFF_T variable to pass the first element value */
+ if (firstelem != USE_LARGE_VALUE)
+ large_first_elem_val = firstelem;
+
+ nullvalue = nulval; /* set local variable */
+ fits_write_compressed_pixels(fptr, TLONG, large_first_elem_val, nelem,
+ 1, array, &nullvalue, status);
+ return(*status);
+ }
+
+ row=maxvalue(1,group);
+
+ ffpcnj(fptr, 2, row, firstelem, nelem, array, nulval, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffp2dj(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long ncols, /* I - number of pixels in each row of array */
+ long naxis1, /* I - FITS image NAXIS1 value */
+ long naxis2, /* I - FITS image NAXIS2 value */
+ long *array, /* I - array to be written */
+ int *status) /* IO - error status */
+/*
+ Write an entire 2-D array of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of the
+ FITS array is not the same as the array being written).
+*/
+{
+
+ /* call the 3D writing routine, with the 3rd dimension = 1 */
+
+ ffp3dj(fptr, group, ncols, naxis2, naxis1, naxis2, 1, array, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffp3dj(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long ncols, /* I - number of pixels in each row of array */
+ long nrows, /* I - number of rows in each plane of array */
+ long naxis1, /* I - FITS image NAXIS1 value */
+ long naxis2, /* I - FITS image NAXIS2 value */
+ long naxis3, /* I - FITS image NAXIS3 value */
+ long *array, /* I - array to be written */
+ int *status) /* IO - error status */
+/*
+ Write an entire 3-D cube of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of the
+ FITS array is not the same as the array being written).
+*/
+{
+ long tablerow, nfits, narray, ii, jj;
+ long fpixel[3]= {1,1,1}, lpixel[3];
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+ lpixel[0] = ncols;
+ lpixel[1] = nrows;
+ lpixel[2] = naxis3;
+
+ fits_write_compressed_img(fptr, TLONG, fpixel, lpixel,
+ 0, array, NULL, status);
+
+ return(*status);
+ }
+
+ tablerow=maxvalue(1,group);
+
+ if (ncols == naxis1 && nrows == naxis2) /* arrays have same size? */
+ {
+ /* all the image pixels are contiguous, so write all at once */
+ ffpclj(fptr, 2, tablerow, 1L, naxis1 * naxis2 * naxis3, array, status);
+ return(*status);
+ }
+
+ if (ncols < naxis1 || nrows < naxis2)
+ return(*status = BAD_DIMEN);
+
+ nfits = 1; /* next pixel in FITS image to write to */
+ narray = 0; /* next pixel in input array to be written */
+
+ /* loop over naxis3 planes in the data cube */
+ for (jj = 0; jj < naxis3; jj++)
+ {
+ /* loop over the naxis2 rows in the FITS image, */
+ /* writing naxis1 pixels to each row */
+
+ for (ii = 0; ii < naxis2; ii++)
+ {
+ if (ffpclj(fptr, 2, tablerow, nfits, naxis1,&array[narray],status) > 0)
+ return(*status);
+
+ nfits += naxis1;
+ narray += ncols;
+ }
+ narray += (nrows - naxis2) * ncols;
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpssj(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long naxis, /* I - number of data axes in array */
+ long *naxes, /* I - size of each FITS axis */
+ long *fpixel, /* I - 1st pixel in each axis to write (1=1st) */
+ long *lpixel, /* I - last pixel in each axis to write */
+ long *array, /* I - array to be written */
+ int *status) /* IO - error status */
+/*
+ Write a subsection of pixels to the primary array or image.
+ A subsection is defined to be any contiguous rectangular
+ array of pixels within the n-dimensional FITS data file.
+ Data conversion and scaling will be performed if necessary
+ (e.g, if the datatype of the FITS array is not the same as
+ the array being written).
+*/
+{
+ long tablerow;
+ long fpix[7], irange[7], dimen[7], astart, pstart;
+ long off2, off3, off4, off5, off6, off7;
+ long st10, st20, st30, st40, st50, st60, st70;
+ long st1, st2, st3, st4, st5, st6, st7;
+ long ii, i1, i2, i3, i4, i5, i6, i7;
+
+ if (*status > 0)
+ return(*status);
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ fits_write_compressed_img(fptr, TLONG, fpixel, lpixel,
+ 0, array, NULL, status);
+
+ return(*status);
+ }
+
+ if (naxis < 1 || naxis > 7)
+ return(*status = BAD_DIMEN);
+
+ tablerow=maxvalue(1,group);
+
+ /* calculate the size and number of loops to perform in each dimension */
+ for (ii = 0; ii < 7; ii++)
+ {
+ fpix[ii]=1;
+ irange[ii]=1;
+ dimen[ii]=1;
+ }
+
+ for (ii = 0; ii < naxis; ii++)
+ {
+ fpix[ii]=fpixel[ii];
+ irange[ii]=lpixel[ii]-fpixel[ii]+1;
+ dimen[ii]=naxes[ii];
+ }
+
+ i1=irange[0];
+
+ /* compute the pixel offset between each dimension */
+ off2 = dimen[0];
+ off3 = off2 * dimen[1];
+ off4 = off3 * dimen[2];
+ off5 = off4 * dimen[3];
+ off6 = off5 * dimen[4];
+ off7 = off6 * dimen[5];
+
+ st10 = fpix[0];
+ st20 = (fpix[1] - 1) * off2;
+ st30 = (fpix[2] - 1) * off3;
+ st40 = (fpix[3] - 1) * off4;
+ st50 = (fpix[4] - 1) * off5;
+ st60 = (fpix[5] - 1) * off6;
+ st70 = (fpix[6] - 1) * off7;
+
+ /* store the initial offset in each dimension */
+ st1 = st10;
+ st2 = st20;
+ st3 = st30;
+ st4 = st40;
+ st5 = st50;
+ st6 = st60;
+ st7 = st70;
+
+ astart = 0;
+
+ for (i7 = 0; i7 < irange[6]; i7++)
+ {
+ for (i6 = 0; i6 < irange[5]; i6++)
+ {
+ for (i5 = 0; i5 < irange[4]; i5++)
+ {
+ for (i4 = 0; i4 < irange[3]; i4++)
+ {
+ for (i3 = 0; i3 < irange[2]; i3++)
+ {
+ pstart = st1 + st2 + st3 + st4 + st5 + st6 + st7;
+ for (i2 = 0; i2 < irange[1]; i2++)
+ {
+ if (ffpclj(fptr, 2, tablerow, pstart, i1, &array[astart],
+ status) > 0)
+ return(*status);
+
+ astart += i1;
+ pstart += off2;
+ }
+ st2 = st20;
+ st3 = st3+off3;
+ }
+ st3 = st30;
+ st4 = st4+off4;
+ }
+ st4 = st40;
+ st5 = st5+off5;
+ }
+ st5 = st50;
+ st6 = st6+off6;
+ }
+ st6 = st60;
+ st7 = st7+off7;
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpgpj( fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long firstelem, /* I - first vector element to write(1 = 1st) */
+ long nelem, /* I - number of values to write */
+ long *array, /* I - array of values that are written */
+ int *status) /* IO - error status */
+/*
+ Write an array of group parameters to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being written).
+*/
+{
+ long row;
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ row=maxvalue(1,group);
+
+ ffpclj(fptr, 1L, row, firstelem, nelem, array, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpclj( fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to write (1 = 1st col) */
+ long firstrow, /* I - first row to write (1 = 1st row) */
+ long firstelem, /* I - first vector element to write (1 = 1st) */
+ long nelem, /* I - number of values to write */
+ long *array, /* I - array of values to write */
+ int *status) /* IO - error status */
+/*
+ Write an array of values to a column in the current FITS HDU.
+ The column number may refer to a real column in an ASCII or binary table,
+ or it may refer to a virtual column in a 1 or more grouped FITS primary
+ array. FITSIO treats a primary array as a binary table
+ with 2 vector columns: the first column contains the group parameters (often
+ with length = 0) and the second column contains the array of image pixels.
+ Each row of the table represents a group in the case of multigroup FITS
+ images.
+
+ The input array of values will be converted to the datatype of the column
+ and will be inverse-scaled by the FITS TSCALn and TZEROn values if necessary.
+*/
+{
+ int tcode, maxelem, hdutype, writeraw;
+ long twidth, incre, rownum, remain, next, ntodo;
+ long tnull;
+ OFF_T repeat, startpos, elemnum, large_elem, wrtptr, rowlen;
+ double scale, zero;
+ char tform[20], cform[20];
+ char message[FLEN_ERRMSG];
+
+ char snull[20]; /* the FITS null value */
+
+ double cbuff[DBUFFSIZE / sizeof(double)]; /* align cbuff on word boundary */
+ void *buffer;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ buffer = cbuff;
+
+ if (firstelem == USE_LARGE_VALUE)
+ large_elem = large_first_elem_val;
+ else
+ large_elem = firstelem;
+
+ /*---------------------------------------------------*/
+ /* Check input and get parameters about the column: */
+ /*---------------------------------------------------*/
+ if (ffgcpr( fptr, colnum, firstrow, large_elem, nelem, 1, &scale, &zero,
+ tform, &twidth, &tcode, &maxelem, &startpos, &elemnum, &incre,
+ &repeat, &rowlen, &hdutype, &tnull, snull, status) > 0)
+ return(*status);
+
+ if (tcode == TSTRING)
+ ffcfmt(tform, cform); /* derive C format for writing strings */
+
+ /*
+ if there is no scaling and the native machine format is not byteswapped
+ then we can simply write the raw data bytes into the FITS file if the
+ datatype of the FITS column is the same as the input values. Otherwise
+ we must convert the raw values into the scaled and/or machine dependent
+ format in a temporary buffer that has been allocated for this purpose.
+ */
+ if (scale == 1. && zero == 0. &&
+ MACHINE == NATIVE && tcode == TLONG && LONGSIZE == 32)
+ {
+ writeraw = 1;
+ maxelem = nelem; /* we can write the entire array at one time */
+ }
+ else
+ writeraw = 0;
+
+ /*---------------------------------------------------------------------*/
+ /* Now write the pixels to the FITS column. */
+ /* First call the ffXXfYY routine to (1) convert the datatype */
+ /* if necessary, and (2) scale the values by the FITS TSCALn and */
+ /* TZEROn linear scaling parameters into a temporary buffer. */
+ /*---------------------------------------------------------------------*/
+ remain = nelem; /* remaining number of values to write */
+ next = 0; /* next element in array to be written */
+ rownum = 0; /* row number, relative to firstrow */
+
+ while (remain)
+ {
+ /* limit the number of pixels to process a one time to the number that
+ will fit in the buffer space or to the number of pixels that remain
+ in the current vector, which ever is smaller.
+ */
+ ntodo = minvalue(remain, maxelem);
+ ntodo = minvalue(ntodo, (repeat - elemnum));
+
+ wrtptr = startpos + ((OFF_T)rownum * rowlen) + (elemnum * incre);
+
+ ffmbyt(fptr, wrtptr, IGNORE_EOF, status); /* move to write position */
+
+ switch (tcode)
+ {
+ case (TLONG):
+ if (writeraw)
+ {
+ /* write raw input bytes without conversion */
+ ffpi4b(fptr, ntodo, incre, (INT32BIT *) &array[next], status);
+ }
+ else
+ {
+ /* convert the raw data before writing to FITS file */
+ ffi4fi4(&array[next], ntodo, scale, zero,
+ (INT32BIT *) buffer, status);
+ ffpi4b(fptr, ntodo, incre, (INT32BIT *) buffer, status);
+ }
+
+ break;
+
+ case (TLONGLONG):
+
+ fflongfi8(&array[next], ntodo, scale, zero,
+ (LONGLONG *) buffer, status);
+ ffpi8b(fptr, ntodo, incre, (long *) buffer, status);
+ break;
+
+ case (TBYTE):
+
+ ffi4fi1(&array[next], ntodo, scale, zero,
+ (unsigned char *) buffer, status);
+ ffpi1b(fptr, ntodo, incre, (unsigned char *) buffer, status);
+ break;
+
+ case (TSHORT):
+
+ ffi4fi2(&array[next], ntodo, scale, zero,
+ (short *) buffer, status);
+ ffpi2b(fptr, ntodo, incre, (short *) buffer, status);
+ break;
+
+ case (TFLOAT):
+
+ ffi4fr4(&array[next], ntodo, scale, zero,
+ (float *) buffer, status);
+ ffpr4b(fptr, ntodo, incre, (float *) buffer, status);
+ break;
+
+ case (TDOUBLE):
+ ffi4fr8(&array[next], ntodo, scale, zero,
+ (double *) buffer, status);
+ ffpr8b(fptr, ntodo, incre, (double *) buffer, status);
+ break;
+
+ case (TSTRING): /* numerical column in an ASCII table */
+
+ if (cform[1] != 's') /* "%s" format is a string */
+ {
+ ffi4fstr(&array[next], ntodo, scale, zero, cform,
+ twidth, (char *) buffer, status);
+
+ if (incre == twidth) /* contiguous bytes */
+ ffpbyt(fptr, ntodo * twidth, buffer, status);
+ else
+ ffpbytoff(fptr, twidth, ntodo, incre - twidth, buffer,
+ status);
+
+ break;
+ }
+ /* can't write to string column, so fall thru to default: */
+
+ default: /* error trap */
+ sprintf(message,
+ "Cannot write numbers to column %d which has format %s",
+ colnum,tform);
+ ffpmsg(message);
+ if (hdutype == ASCII_TBL)
+ return(*status = BAD_ATABLE_FORMAT);
+ else
+ return(*status = BAD_BTABLE_FORMAT);
+
+ } /* End of switch block */
+
+ /*-------------------------*/
+ /* Check for fatal error */
+ /*-------------------------*/
+ if (*status > 0) /* test for error during previous write operation */
+ {
+ sprintf(message,
+ "Error writing elements %ld thru %ld of input data array (ffpclj).",
+ next+1, next+ntodo);
+ ffpmsg(message);
+ return(*status);
+ }
+
+ /*--------------------------------------------*/
+ /* increment the counters for the next loop */
+ /*--------------------------------------------*/
+ remain -= ntodo;
+ if (remain)
+ {
+ next += ntodo;
+ elemnum += ntodo;
+ if (elemnum == repeat) /* completed a row; start on next row */
+ {
+ elemnum = 0;
+ rownum++;
+ }
+ }
+ } /* End of main while Loop */
+
+
+ /*--------------------------------*/
+ /* check for numerical overflow */
+ /*--------------------------------*/
+ if (*status == OVERFLOW_ERR)
+ {
+ ffpmsg(
+ "Numerical overflow during type conversion while writing FITS data.");
+ *status = NUM_OVERFLOW;
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpcnj( fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to write (1 = 1st col) */
+ long firstrow, /* I - first row to write (1 = 1st row) */
+ long firstelem, /* I - first vector element to write (1 = 1st) */
+ long nelem, /* I - number of values to write */
+ long *array, /* I - array of values to write */
+ long nulvalue, /* I - value used to flag undefined pixels */
+ int *status) /* IO - error status */
+/*
+ Write an array of elements to the specified column of a table. Any input
+ pixels equal to the value of nulvalue will be replaced by the appropriate
+ null value in the output FITS file.
+
+ The input array of values will be converted to the datatype of the column
+ and will be inverse-scaled by the FITS TSCALn and TZEROn values if necessary
+*/
+{
+ tcolumn *colptr;
+ long ngood = 0, nbad = 0, ii, fstrow;
+ OFF_T large_elem, repeat, first, fstelm;
+
+ if (*status > 0)
+ return(*status);
+
+ /* reset position to the correct HDU if necessary */
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ {
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+ }
+ else if ((fptr->Fptr)->datastart == DATA_UNDEFINED)
+ {
+ if ( ffrdef(fptr, status) > 0) /* rescan header */
+ return(*status);
+ }
+
+ colptr = (fptr->Fptr)->tableptr; /* point to first column */
+ colptr += (colnum - 1); /* offset to correct column structure */
+
+ repeat = colptr->trepeat; /* repeat count for this column */
+
+ if (firstelem == USE_LARGE_VALUE)
+ large_elem = large_first_elem_val;
+ else
+ large_elem = firstelem;
+
+ /* hereafter, pass first element parameter via global variable */
+ firstelem = USE_LARGE_VALUE;
+
+ /* absolute element number in the column */
+ first = (firstrow - 1) * repeat + large_elem;
+
+ for (ii = 0; ii < nelem; ii++)
+ {
+ if (array[ii] != nulvalue) /* is this a good pixel? */
+ {
+ if (nbad) /* write previous string of bad pixels */
+ {
+ fstelm = ii - nbad + first; /* absolute element number */
+ fstrow = (fstelm - 1) / repeat + 1; /* starting row number */
+ fstelm = fstelm - (fstrow - 1) * repeat; /* relative number */
+ large_first_elem_val = fstelm;
+
+ if (ffpclu(fptr, colnum, fstrow, firstelem, nbad, status) > 0)
+ return(*status);
+
+ nbad=0;
+ }
+
+ ngood = ngood +1; /* the consecutive number of good pixels */
+ }
+ else
+ {
+ if (ngood) /* write previous string of good pixels */
+ {
+ fstelm = ii - ngood + first; /* absolute element number */
+ fstrow = (fstelm - 1) / repeat + 1; /* starting row number */
+ fstelm = fstelm - (fstrow - 1) * repeat; /* relative number */
+ large_first_elem_val = fstelm;
+
+ if (ffpclj(fptr, colnum, fstrow, firstelem, ngood, &array[ii-ngood],
+ status) > 0)
+ return(*status);
+
+ ngood=0;
+ }
+
+ nbad = nbad +1; /* the consecutive number of bad pixels */
+ }
+ }
+
+ /* finished loop; now just write the last set of pixels */
+
+ if (ngood) /* write last string of good pixels */
+ {
+ fstelm = ii - ngood + first; /* absolute element number */
+ fstrow = (fstelm - 1) / repeat + 1; /* starting row number */
+ fstelm = fstelm - (fstrow - 1) * repeat; /* relative number */
+ large_first_elem_val = fstelm;
+
+ ffpclj(fptr, colnum, fstrow, firstelem, ngood, &array[ii-ngood], status);
+ }
+ else if (nbad) /* write last string of bad pixels */
+ {
+ fstelm = ii - nbad + first; /* absolute element number */
+ fstrow = (fstelm - 1) / repeat + 1; /* starting row number */
+ fstelm = fstelm - (fstrow - 1) * repeat; /* relative number */
+ large_first_elem_val = fstelm;
+
+ ffpclu(fptr, colnum, fstrow, firstelem, nbad, status);
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffi4fi1(long *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ unsigned char *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required.
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] < 0)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (input[ii] > UCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UCHAR_MAX;
+ }
+ else
+ output[ii] = input[ii];
+ }
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = (input[ii] - zero) / scale;
+
+ if (dvalue < DUCHAR_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DUCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UCHAR_MAX;
+ }
+ else
+ output[ii] = (unsigned char) (dvalue + .5);
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffi4fi2(long *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ short *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required.
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] < SHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MIN;
+ }
+ else if (input[ii] > SHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MAX;
+ }
+ else
+ output[ii] = input[ii];
+ }
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = (input[ii] - zero) / scale;
+
+ if (dvalue < DSHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MIN;
+ }
+ else if (dvalue > DSHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MAX;
+ }
+ else
+ {
+ if (dvalue >= 0)
+ output[ii] = (short) (dvalue + .5);
+ else
+ output[ii] = (short) (dvalue - .5);
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffi4fi4(long *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ INT32BIT *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = (INT32BIT) input[ii];
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = (input[ii] - zero) / scale;
+
+ if (dvalue < DINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT32_MIN;
+ }
+ else if (dvalue > DINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT32_MAX;
+ }
+ else
+ {
+ if (dvalue >= 0)
+ output[ii] = (INT32BIT) (dvalue + .5);
+ else
+ output[ii] = (INT32BIT) (dvalue - .5);
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fflongfi8(long *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ LONGLONG *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required
+*/
+{
+#if (LONGSIZE == 32) && (! defined HAVE_LONGLONG)
+
+/* don't have a native 8-byte integer, so have to construct the */
+/* 2 equivalent 4-byte integers have the same bit pattern */
+
+ unsigned long *uoutput;
+ long ii, jj, kk, temp;
+ double dvalue;
+
+ uoutput = (unsigned long *) output;
+
+#if BYTESWAPPED /* jj points to the most significant part of the 8-byte int */
+ jj = 1;
+ kk = 0;
+#else
+ jj = 0;
+ kk = 1;
+#endif
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++, jj += 2, kk += 2)
+ {
+ if (input[ii] < 0)
+ output[jj] = -1;
+ else
+ output[jj] = 0;
+
+ output[kk] = input[ii];
+ }
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++, jj += 2, kk += 2)
+ {
+ dvalue = (input[ii] - zero) / scale;
+
+ if (dvalue < DLONGLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[jj] = LONG_MIN;
+ output[kk] = 0;
+ }
+ else if (dvalue > DLONGLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[jj] = LONG_MAX;
+ output[kk] = -1;
+ }
+ else
+ {
+ if (dvalue < 0)
+ {
+ temp = (dvalue + 1.) / 4294967296. - 1.;
+ output[jj] = temp;
+ uoutput[kk] = 4294967296. +
+ (dvalue - (double) (temp + 1) * 4294967296.);
+ }
+ else
+ {
+ temp = dvalue / 4294967296.;
+ output[jj] = temp;
+ uoutput[kk] = dvalue - (double) temp * 4294967296.;
+ }
+ }
+ }
+ }
+
+#else
+
+/* this is the much simpler case where the native 8-byte integer exists */
+
+ long ii;
+ double dvalue;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = input[ii];
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = (input[ii] - zero) / scale;
+
+ if (dvalue < DLONGLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONGLONG_MIN;
+ }
+ else if (dvalue > DLONGLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONGLONG_MAX;
+ }
+ else
+ {
+ if (dvalue >= 0)
+ output[ii] = (LONGLONG) (dvalue + .5);
+ else
+ output[ii] = (LONGLONG) (dvalue - .5);
+ }
+ }
+ }
+
+#endif
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffi4fr4(long *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ float *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required.
+*/
+{
+ long ii;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = (float) input[ii];
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = (input[ii] - zero) / scale;
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffi4fr8(long *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ double *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required.
+*/
+{
+ long ii;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = (double) input[ii];
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = (input[ii] - zero) / scale;
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffi4fstr(long *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ char *cform, /* I - format for output string values */
+ long twidth, /* I - width of each field, in chars */
+ char *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do scaling if required.
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ sprintf(output, cform, (double) input[ii]);
+ output += twidth;
+
+ if (*output) /* if this char != \0, then overflow occurred */
+ *status = OVERFLOW_ERR;
+ }
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = (input[ii] - zero) / scale;
+ sprintf(output, cform, dvalue);
+ output += twidth;
+
+ if (*output) /* if this char != \0, then overflow occurred */
+ *status = OVERFLOW_ERR;
+ }
+ }
+ return(*status);
+}
+
+/* ======================================================================== */
+/* the following routines support the 'long long' data type */
+/* ======================================================================== */
+
+/*--------------------------------------------------------------------------*/
+int ffpprjj(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long firstelem, /* I - first vector element to write(1 = 1st) */
+ long nelem, /* I - number of values to write */
+ LONGLONG *array, /* I - array of values that are written */
+ int *status) /* IO - error status */
+/*
+ Write an array of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being written).
+*/
+{
+ long row;
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ ffpmsg("writing to compressed image is not supported");
+
+ return(*status = DATA_COMPRESSION_ERR);
+ }
+
+ row=maxvalue(1,group);
+
+ ffpcljj(fptr, 2, row, firstelem, nelem, array, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffppnjj(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long firstelem, /* I - first vector element to write(1 = 1st) */
+ long nelem, /* I - number of values to write */
+ LONGLONG *array, /* I - array of values that are written */
+ long nulval, /* I - undefined pixel value */
+ int *status) /* IO - error status */
+/*
+ Write an array of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of the
+ FITS array is not the same as the array being written). Any array values
+ that are equal to the value of nulval will be replaced with the null
+ pixel value that is appropriate for this column.
+*/
+{
+ long row;
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ ffpmsg("writing to compressed image is not supported");
+
+ return(*status = DATA_COMPRESSION_ERR);
+ }
+
+ row=maxvalue(1,group);
+
+ ffpcnjj(fptr, 2, row, firstelem, nelem, array, nulval, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffp2djj(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long ncols, /* I - number of pixels in each row of array */
+ long naxis1, /* I - FITS image NAXIS1 value */
+ long naxis2, /* I - FITS image NAXIS2 value */
+ LONGLONG *array, /* I - array to be written */
+ int *status) /* IO - error status */
+/*
+ Write an entire 2-D array of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of the
+ FITS array is not the same as the array being written).
+*/
+{
+
+ /* call the 3D writing routine, with the 3rd dimension = 1 */
+
+ ffp3djj(fptr, group, ncols, naxis2, naxis1, naxis2, 1, array, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffp3djj(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long ncols, /* I - number of pixels in each row of array */
+ long nrows, /* I - number of rows in each plane of array */
+ long naxis1, /* I - FITS image NAXIS1 value */
+ long naxis2, /* I - FITS image NAXIS2 value */
+ long naxis3, /* I - FITS image NAXIS3 value */
+ LONGLONG *array, /* I - array to be written */
+ int *status) /* IO - error status */
+/*
+ Write an entire 3-D cube of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of the
+ FITS array is not the same as the array being written).
+*/
+{
+ long tablerow, nfits, narray, ii, jj;
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ ffpmsg("writing to compressed image is not supported");
+
+ return(*status = DATA_COMPRESSION_ERR);
+ }
+
+ tablerow=maxvalue(1,group);
+
+ if (ncols == naxis1 && nrows == naxis2) /* arrays have same size? */
+ {
+ /* all the image pixels are contiguous, so write all at once */
+ ffpcljj(fptr, 2, tablerow, 1L, naxis1 * naxis2 * naxis3, array, status);
+ return(*status);
+ }
+
+ if (ncols < naxis1 || nrows < naxis2)
+ return(*status = BAD_DIMEN);
+
+ nfits = 1; /* next pixel in FITS image to write to */
+ narray = 0; /* next pixel in input array to be written */
+
+ /* loop over naxis3 planes in the data cube */
+ for (jj = 0; jj < naxis3; jj++)
+ {
+ /* loop over the naxis2 rows in the FITS image, */
+ /* writing naxis1 pixels to each row */
+
+ for (ii = 0; ii < naxis2; ii++)
+ {
+ if (ffpcljj(fptr, 2, tablerow, nfits, naxis1,&array[narray],status) > 0)
+ return(*status);
+
+ nfits += naxis1;
+ narray += ncols;
+ }
+ narray += (nrows - naxis2) * ncols;
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpssjj(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long naxis, /* I - number of data axes in array */
+ long *naxes, /* I - size of each FITS axis */
+ long *fpixel, /* I - 1st pixel in each axis to write (1=1st) */
+ long *lpixel, /* I - last pixel in each axis to write */
+ LONGLONG *array, /* I - array to be written */
+ int *status) /* IO - error status */
+/*
+ Write a subsection of pixels to the primary array or image.
+ A subsection is defined to be any contiguous rectangular
+ array of pixels within the n-dimensional FITS data file.
+ Data conversion and scaling will be performed if necessary
+ (e.g, if the datatype of the FITS array is not the same as
+ the array being written).
+*/
+{
+ long tablerow;
+ long fpix[7], irange[7], dimen[7], astart, pstart;
+ long off2, off3, off4, off5, off6, off7;
+ long st10, st20, st30, st40, st50, st60, st70;
+ long st1, st2, st3, st4, st5, st6, st7;
+ long ii, i1, i2, i3, i4, i5, i6, i7;
+
+ if (*status > 0)
+ return(*status);
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ ffpmsg("writing to compressed image is not supported");
+
+ return(*status = DATA_COMPRESSION_ERR);
+ }
+
+ if (naxis < 1 || naxis > 7)
+ return(*status = BAD_DIMEN);
+
+ tablerow=maxvalue(1,group);
+
+ /* calculate the size and number of loops to perform in each dimension */
+ for (ii = 0; ii < 7; ii++)
+ {
+ fpix[ii]=1;
+ irange[ii]=1;
+ dimen[ii]=1;
+ }
+
+ for (ii = 0; ii < naxis; ii++)
+ {
+ fpix[ii]=fpixel[ii];
+ irange[ii]=lpixel[ii]-fpixel[ii]+1;
+ dimen[ii]=naxes[ii];
+ }
+
+ i1=irange[0];
+
+ /* compute the pixel offset between each dimension */
+ off2 = dimen[0];
+ off3 = off2 * dimen[1];
+ off4 = off3 * dimen[2];
+ off5 = off4 * dimen[3];
+ off6 = off5 * dimen[4];
+ off7 = off6 * dimen[5];
+
+ st10 = fpix[0];
+ st20 = (fpix[1] - 1) * off2;
+ st30 = (fpix[2] - 1) * off3;
+ st40 = (fpix[3] - 1) * off4;
+ st50 = (fpix[4] - 1) * off5;
+ st60 = (fpix[5] - 1) * off6;
+ st70 = (fpix[6] - 1) * off7;
+
+ /* store the initial offset in each dimension */
+ st1 = st10;
+ st2 = st20;
+ st3 = st30;
+ st4 = st40;
+ st5 = st50;
+ st6 = st60;
+ st7 = st70;
+
+ astart = 0;
+
+ for (i7 = 0; i7 < irange[6]; i7++)
+ {
+ for (i6 = 0; i6 < irange[5]; i6++)
+ {
+ for (i5 = 0; i5 < irange[4]; i5++)
+ {
+ for (i4 = 0; i4 < irange[3]; i4++)
+ {
+ for (i3 = 0; i3 < irange[2]; i3++)
+ {
+ pstart = st1 + st2 + st3 + st4 + st5 + st6 + st7;
+ for (i2 = 0; i2 < irange[1]; i2++)
+ {
+ if (ffpcljj(fptr, 2, tablerow, pstart, i1, &array[astart],
+ status) > 0)
+ return(*status);
+
+ astart += i1;
+ pstart += off2;
+ }
+ st2 = st20;
+ st3 = st3+off3;
+ }
+ st3 = st30;
+ st4 = st4+off4;
+ }
+ st4 = st40;
+ st5 = st5+off5;
+ }
+ st5 = st50;
+ st6 = st6+off6;
+ }
+ st6 = st60;
+ st7 = st7+off7;
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpgpjj(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long firstelem, /* I - first vector element to write(1 = 1st) */
+ long nelem, /* I - number of values to write */
+ LONGLONG *array, /* I - array of values that are written */
+ int *status) /* IO - error status */
+/*
+ Write an array of group parameters to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being written).
+*/
+{
+ long row;
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ row=maxvalue(1,group);
+
+ ffpcljj(fptr, 1L, row, firstelem, nelem, array, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpcljj(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to write (1 = 1st col) */
+ long firstrow, /* I - first row to write (1 = 1st row) */
+ long firstelem, /* I - first vector element to write (1 = 1st) */
+ long nelem, /* I - number of values to write */
+ LONGLONG *array, /* I - array of values to write */
+ int *status) /* IO - error status */
+/*
+ Write an array of values to a column in the current FITS HDU.
+ The column number may refer to a real column in an ASCII or binary table,
+ or it may refer to a virtual column in a 1 or more grouped FITS primary
+ array. FITSIO treats a primary array as a binary table
+ with 2 vector columns: the first column contains the group parameters (often
+ with length = 0) and the second column contains the array of image pixels.
+ Each row of the table represents a group in the case of multigroup FITS
+ images.
+
+ The input array of values will be converted to the datatype of the column
+ and will be inverse-scaled by the FITS TSCALn and TZEROn values if necessary.
+*/
+{
+ int tcode, maxelem, hdutype, writeraw;
+ long twidth, incre, rownum, remain, next, ntodo;
+ long tnull;
+ OFF_T repeat, startpos, elemnum, large_elem, wrtptr, rowlen;
+ double scale, zero;
+ char tform[20], cform[20];
+ char message[FLEN_ERRMSG];
+
+ char snull[20]; /* the FITS null value */
+
+ double cbuff[DBUFFSIZE / sizeof(double)]; /* align cbuff on word boundary */
+ void *buffer;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ buffer = cbuff;
+
+ if (firstelem == USE_LARGE_VALUE)
+ large_elem = large_first_elem_val;
+ else
+ large_elem = firstelem;
+
+ /*---------------------------------------------------*/
+ /* Check input and get parameters about the column: */
+ /*---------------------------------------------------*/
+ if (ffgcpr( fptr, colnum, firstrow, large_elem, nelem, 1, &scale, &zero,
+ tform, &twidth, &tcode, &maxelem, &startpos, &elemnum, &incre,
+ &repeat, &rowlen, &hdutype, &tnull, snull, status) > 0)
+ return(*status);
+
+ if (tcode == TSTRING)
+ ffcfmt(tform, cform); /* derive C format for writing strings */
+
+ /*
+ if there is no scaling and the native machine format is not byteswapped
+ then we can simply write the raw data bytes into the FITS file if the
+ datatype of the FITS column is the same as the input values. Otherwise
+ we must convert the raw values into the scaled and/or machine dependent
+ format in a temporary buffer that has been allocated for this purpose.
+ */
+ if (scale == 1. && zero == 0. &&
+ MACHINE == NATIVE && tcode == TLONGLONG)
+ {
+ writeraw = 1;
+ maxelem = nelem; /* we can write the entire array at one time */
+ }
+ else
+ writeraw = 0;
+
+ /*---------------------------------------------------------------------*/
+ /* Now write the pixels to the FITS column. */
+ /* First call the ffXXfYY routine to (1) convert the datatype */
+ /* if necessary, and (2) scale the values by the FITS TSCALn and */
+ /* TZEROn linear scaling parameters into a temporary buffer. */
+ /*---------------------------------------------------------------------*/
+ remain = nelem; /* remaining number of values to write */
+ next = 0; /* next element in array to be written */
+ rownum = 0; /* row number, relative to firstrow */
+
+ while (remain)
+ {
+ /* limit the number of pixels to process a one time to the number that
+ will fit in the buffer space or to the number of pixels that remain
+ in the current vector, which ever is smaller.
+ */
+ ntodo = minvalue(remain, maxelem);
+ ntodo = minvalue(ntodo, (repeat - elemnum));
+
+ wrtptr = startpos + ((OFF_T)rownum * rowlen) + (elemnum * incre);
+
+ ffmbyt(fptr, wrtptr, IGNORE_EOF, status); /* move to write position */
+
+ switch (tcode)
+ {
+ case (TLONGLONG):
+ if (writeraw)
+ {
+ /* write raw input bytes without conversion */
+ ffpi8b(fptr, ntodo, incre, (long *) &array[next], status);
+ }
+ else
+ {
+ /* convert the raw data before writing to FITS file */
+ ffi8fi8(&array[next], ntodo, scale, zero,
+ (LONGLONG *) buffer, status);
+ ffpi8b(fptr, ntodo, incre, (long *) buffer, status);
+ }
+
+ break;
+
+ case (TLONG):
+
+ ffi8fi4(&array[next], ntodo, scale, zero,
+ (INT32BIT *) buffer, status);
+ ffpi4b(fptr, ntodo, incre, (INT32BIT *) buffer, status);
+ break;
+
+ case (TBYTE):
+
+ ffi8fi1(&array[next], ntodo, scale, zero,
+ (unsigned char *) buffer, status);
+ ffpi1b(fptr, ntodo, incre, (unsigned char *) buffer, status);
+ break;
+
+ case (TSHORT):
+
+ ffi8fi2(&array[next], ntodo, scale, zero,
+ (short *) buffer, status);
+ ffpi2b(fptr, ntodo, incre, (short *) buffer, status);
+ break;
+
+ case (TFLOAT):
+
+ ffi8fr4(&array[next], ntodo, scale, zero,
+ (float *) buffer, status);
+ ffpr4b(fptr, ntodo, incre, (float *) buffer, status);
+ break;
+
+ case (TDOUBLE):
+ ffi8fr8(&array[next], ntodo, scale, zero,
+ (double *) buffer, status);
+ ffpr8b(fptr, ntodo, incre, (double *) buffer, status);
+ break;
+
+ case (TSTRING): /* numerical column in an ASCII table */
+
+ if (cform[1] != 's') /* "%s" format is a string */
+ {
+ ffi8fstr(&array[next], ntodo, scale, zero, cform,
+ twidth, (char *) buffer, status);
+
+ if (incre == twidth) /* contiguous bytes */
+ ffpbyt(fptr, ntodo * twidth, buffer, status);
+ else
+ ffpbytoff(fptr, twidth, ntodo, incre - twidth, buffer,
+ status);
+
+ break;
+ }
+ /* can't write to string column, so fall thru to default: */
+
+ default: /* error trap */
+ sprintf(message,
+ "Cannot write numbers to column %d which has format %s",
+ colnum,tform);
+ ffpmsg(message);
+ if (hdutype == ASCII_TBL)
+ return(*status = BAD_ATABLE_FORMAT);
+ else
+ return(*status = BAD_BTABLE_FORMAT);
+
+ } /* End of switch block */
+
+ /*-------------------------*/
+ /* Check for fatal error */
+ /*-------------------------*/
+ if (*status > 0) /* test for error during previous write operation */
+ {
+ sprintf(message,
+ "Error writing elements %ld thru %ld of input data array (ffpclj).",
+ next+1, next+ntodo);
+ ffpmsg(message);
+ return(*status);
+ }
+
+ /*--------------------------------------------*/
+ /* increment the counters for the next loop */
+ /*--------------------------------------------*/
+ remain -= ntodo;
+ if (remain)
+ {
+ next += ntodo;
+ elemnum += ntodo;
+ if (elemnum == repeat) /* completed a row; start on next row */
+ {
+ elemnum = 0;
+ rownum++;
+ }
+ }
+ } /* End of main while Loop */
+
+
+ /*--------------------------------*/
+ /* check for numerical overflow */
+ /*--------------------------------*/
+ if (*status == OVERFLOW_ERR)
+ {
+ ffpmsg(
+ "Numerical overflow during type conversion while writing FITS data.");
+ *status = NUM_OVERFLOW;
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpcnjj(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to write (1 = 1st col) */
+ long firstrow, /* I - first row to write (1 = 1st row) */
+ long firstelem, /* I - first vector element to write (1 = 1st) */
+ long nelem, /* I - number of values to write */
+ LONGLONG *array, /* I - array of values to write */
+ LONGLONG nulvalue, /* I - value used to flag undefined pixels */
+ int *status) /* IO - error status */
+/*
+ Write an array of elements to the specified column of a table. Any input
+ pixels equal to the value of nulvalue will be replaced by the appropriate
+ null value in the output FITS file.
+
+ The input array of values will be converted to the datatype of the column
+ and will be inverse-scaled by the FITS TSCALn and TZEROn values if necessary
+*/
+{
+ tcolumn *colptr;
+ long ngood = 0, nbad = 0, ii, fstrow;
+ OFF_T large_elem, repeat, first, fstelm;
+
+ if (*status > 0)
+ return(*status);
+
+ /* reset position to the correct HDU if necessary */
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ {
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+ }
+ else if ((fptr->Fptr)->datastart == DATA_UNDEFINED)
+ {
+ if ( ffrdef(fptr, status) > 0) /* rescan header */
+ return(*status);
+ }
+
+ colptr = (fptr->Fptr)->tableptr; /* point to first column */
+ colptr += (colnum - 1); /* offset to correct column structure */
+
+ repeat = colptr->trepeat; /* repeat count for this column */
+
+ if (firstelem == USE_LARGE_VALUE)
+ large_elem = large_first_elem_val;
+ else
+ large_elem = firstelem;
+
+ /* hereafter, pass first element parameter via global variable */
+ firstelem = USE_LARGE_VALUE;
+
+ /* absolute element number in the column */
+ first = (firstrow - 1) * repeat + large_elem;
+
+ for (ii = 0; ii < nelem; ii++)
+ {
+ if (array[ii] != nulvalue) /* is this a good pixel? */
+ {
+ if (nbad) /* write previous string of bad pixels */
+ {
+ fstelm = ii - nbad + first; /* absolute element number */
+ fstrow = (fstelm - 1) / repeat + 1; /* starting row number */
+ fstelm = fstelm - (fstrow - 1) * repeat; /* relative number */
+ large_first_elem_val = fstelm;
+
+ if (ffpclu(fptr, colnum, fstrow, firstelem, nbad, status) > 0)
+ return(*status);
+
+ nbad=0;
+ }
+
+ ngood = ngood +1; /* the consecutive number of good pixels */
+ }
+ else
+ {
+ if (ngood) /* write previous string of good pixels */
+ {
+ fstelm = ii - ngood + first; /* absolute element number */
+ fstrow = (fstelm - 1) / repeat + 1; /* starting row number */
+ fstelm = fstelm - (fstrow - 1) * repeat; /* relative number */
+ large_first_elem_val = fstelm;
+
+ if (ffpcljj(fptr, colnum, fstrow,firstelem, ngood, &array[ii-ngood],
+ status) > 0)
+ return(*status);
+
+ ngood=0;
+ }
+
+ nbad = nbad +1; /* the consecutive number of bad pixels */
+ }
+ }
+
+ /* finished loop; now just write the last set of pixels */
+
+ if (ngood) /* write last string of good pixels */
+ {
+ fstelm = ii - ngood + first; /* absolute element number */
+ fstrow = (fstelm - 1) / repeat + 1; /* starting row number */
+ fstelm = fstelm - (fstrow - 1) * repeat; /* relative number */
+ large_first_elem_val = fstelm;
+
+ ffpcljj(fptr, colnum, fstrow, firstelem, ngood, &array[ii-ngood], status);
+ }
+ else if (nbad) /* write last string of bad pixels */
+ {
+ fstelm = ii - nbad + first; /* absolute element number */
+ fstrow = (fstelm - 1) / repeat + 1; /* starting row number */
+ fstelm = fstelm - (fstrow - 1) * repeat; /* relative number */
+ large_first_elem_val = fstelm;
+
+ ffpclu(fptr, colnum, fstrow, firstelem, nbad, status);
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffi8fi1(LONGLONG *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ unsigned char *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required.
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] < 0)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (input[ii] > UCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UCHAR_MAX;
+ }
+ else
+ output[ii] = input[ii];
+ }
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = (input[ii] - zero) / scale;
+
+ if (dvalue < DUCHAR_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DUCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UCHAR_MAX;
+ }
+ else
+ output[ii] = (unsigned char) (dvalue + .5);
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffi8fi2(LONGLONG *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ short *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required.
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] < SHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MIN;
+ }
+ else if (input[ii] > SHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MAX;
+ }
+ else
+ output[ii] = input[ii];
+ }
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = (input[ii] - zero) / scale;
+
+ if (dvalue < DSHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MIN;
+ }
+ else if (dvalue > DSHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MAX;
+ }
+ else
+ {
+ if (dvalue >= 0)
+ output[ii] = (short) (dvalue + .5);
+ else
+ output[ii] = (short) (dvalue - .5);
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffi8fi4(LONGLONG *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ INT32BIT *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] < INT32_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT32_MIN;
+ }
+ else if (input[ii] > INT32_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT32_MAX;
+ }
+ else
+ output[ii] = (INT32BIT) input[ii];
+ }
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = (input[ii] - zero) / scale;
+
+ if (dvalue < DINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT32_MIN;
+ }
+ else if (dvalue > DINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT32_MAX;
+ }
+ else
+ {
+ if (dvalue >= 0)
+ output[ii] = (INT32BIT) (dvalue + .5);
+ else
+ output[ii] = (INT32BIT) (dvalue - .5);
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffi8fi8(LONGLONG *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ LONGLONG *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = input[ii];
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = (input[ii] - zero) / scale;
+
+ if (dvalue < DLONGLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONGLONG_MIN;
+ }
+ else if (dvalue > DLONGLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONGLONG_MAX;
+ }
+ else
+ {
+ if (dvalue >= 0)
+ output[ii] = (LONGLONG) (dvalue + .5);
+ else
+ output[ii] = (LONGLONG) (dvalue - .5);
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffi8fr4(LONGLONG *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ float *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required.
+*/
+{
+ long ii;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = (float) input[ii];
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = (input[ii] - zero) / scale;
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffi8fr8(LONGLONG *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ double *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required.
+*/
+{
+ long ii;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = (double) input[ii];
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = (input[ii] - zero) / scale;
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffi8fstr(LONGLONG *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ char *cform, /* I - format for output string values */
+ long twidth, /* I - width of each field, in chars */
+ char *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do scaling if required.
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ sprintf(output, cform, (double) input[ii]);
+ output += twidth;
+
+ if (*output) /* if this char != \0, then overflow occurred */
+ *status = OVERFLOW_ERR;
+ }
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = (input[ii] - zero) / scale;
+ sprintf(output, cform, dvalue);
+ output += twidth;
+
+ if (*output) /* if this char != \0, then overflow occurred */
+ *status = OVERFLOW_ERR;
+ }
+ }
+ return(*status);
+}
diff --git a/pkg/tbtables/cfitsio/putcolk.c b/pkg/tbtables/cfitsio/putcolk.c
new file mode 100644
index 00000000..16bf4c93
--- /dev/null
+++ b/pkg/tbtables/cfitsio/putcolk.c
@@ -0,0 +1,1067 @@
+/* This file, putcolk.c, contains routines that write data elements to */
+/* a FITS image or table, with 'int' datatype. */
+
+/* The FITSIO software was written by William Pence at the High Energy */
+/* Astrophysic Science Archive Research Center (HEASARC) at the NASA */
+/* Goddard Space Flight Center. */
+
+#include <limits.h>
+#include <string.h>
+#include <stdlib.h>
+#include "fitsio2.h"
+
+/* declare variable for passing large firstelem values between routines */
+extern OFF_T large_first_elem_val;
+
+/*--------------------------------------------------------------------------*/
+int ffpprk( fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long firstelem, /* I - first vector element to write(1 = 1st) */
+ long nelem, /* I - number of values to write */
+ int *array, /* I - array of values that are written */
+ int *status) /* IO - error status */
+/*
+ Write an array of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being written).
+*/
+{
+ long row;
+ int nullvalue;
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ /* use the OFF_T variable to pass the first element value */
+ if (firstelem != USE_LARGE_VALUE)
+ large_first_elem_val = firstelem;
+
+ fits_write_compressed_pixels(fptr, TINT, large_first_elem_val, nelem,
+ 0, array, &nullvalue, status);
+ return(*status);
+ }
+
+ row=maxvalue(1,group);
+
+ ffpclk(fptr, 2, row, firstelem, nelem, array, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffppnk( fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long firstelem, /* I - first vector element to write(1 = 1st) */
+ long nelem, /* I - number of values to write */
+ int *array, /* I - array of values that are written */
+ int nulval, /* I - undefined pixel value */
+ int *status) /* IO - error status */
+/*
+ Write an array of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of the
+ FITS array is not the same as the array being written). Any array values
+ that are equal to the value of nulval will be replaced with the null
+ pixel value that is appropriate for this column.
+*/
+{
+ long row;
+ int nullvalue;
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ /* use the OFF_T variable to pass the first element value */
+ if (firstelem != USE_LARGE_VALUE)
+ large_first_elem_val = firstelem;
+
+ nullvalue = nulval; /* set local variable */
+ fits_write_compressed_pixels(fptr, TINT, large_first_elem_val, nelem,
+ 1, array, &nullvalue, status);
+ return(*status);
+ }
+
+ row=maxvalue(1,group);
+
+ ffpcnk(fptr, 2, row, firstelem, nelem, array, nulval, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffp2dk(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long ncols, /* I - number of pixels in each row of array */
+ long naxis1, /* I - FITS image NAXIS1 value */
+ long naxis2, /* I - FITS image NAXIS2 value */
+ int *array, /* I - array to be written */
+ int *status) /* IO - error status */
+/*
+ Write an entire 2-D array of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of the
+ FITS array is not the same as the array being written).
+*/
+{
+ /* call the 3D writing routine, with the 3rd dimension = 1 */
+
+ ffp3dk(fptr, group, ncols, naxis2, naxis1, naxis2, 1, array, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffp3dk(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long ncols, /* I - number of pixels in each row of array */
+ long nrows, /* I - number of rows in each plane of array */
+ long naxis1, /* I - FITS image NAXIS1 value */
+ long naxis2, /* I - FITS image NAXIS2 value */
+ long naxis3, /* I - FITS image NAXIS3 value */
+ int *array, /* I - array to be written */
+ int *status) /* IO - error status */
+/*
+ Write an entire 3-D cube of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of the
+ FITS array is not the same as the array being written).
+*/
+{
+ long tablerow, nfits, narray, ii, jj;
+ long fpixel[3]= {1,1,1}, lpixel[3];
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+ lpixel[0] = ncols;
+ lpixel[1] = nrows;
+ lpixel[2] = naxis3;
+
+ fits_write_compressed_img(fptr, TINT, fpixel, lpixel,
+ 0, array, NULL, status);
+
+ return(*status);
+ }
+
+ tablerow=maxvalue(1,group);
+
+ if (ncols == naxis1 && nrows == naxis2) /* arrays have same size? */
+ {
+ /* all the image pixels are contiguous, so write all at once */
+ ffpclk(fptr, 2, tablerow, 1L, naxis1 * naxis2 * naxis3, array, status);
+ return(*status);
+ }
+
+ if (ncols < naxis1 || nrows < naxis2)
+ return(*status = BAD_DIMEN);
+
+ nfits = 1; /* next pixel in FITS image to write to */
+ narray = 0; /* next pixel in input array to be written */
+
+ /* loop over naxis3 planes in the data cube */
+ for (jj = 0; jj < naxis3; jj++)
+ {
+ /* loop over the naxis2 rows in the FITS image, */
+ /* writing naxis1 pixels to each row */
+
+ for (ii = 0; ii < naxis2; ii++)
+ {
+ if (ffpclk(fptr, 2, tablerow, nfits, naxis1,&array[narray],status) > 0)
+ return(*status);
+
+ nfits += naxis1;
+ narray += ncols;
+ }
+ narray += (nrows - naxis2) * ncols;
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpssk(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long naxis, /* I - number of data axes in array */
+ long *naxes, /* I - size of each FITS axis */
+ long *fpixel, /* I - 1st pixel in each axis to write (1=1st) */
+ long *lpixel, /* I - last pixel in each axis to write */
+ int *array, /* I - array to be written */
+ int *status) /* IO - error status */
+/*
+ Write a subsection of pixels to the primary array or image.
+ A subsection is defined to be any contiguous rectangular
+ array of pixels within the n-dimensional FITS data file.
+ Data conversion and scaling will be performed if necessary
+ (e.g, if the datatype of the FITS array is not the same as
+ the array being written).
+*/
+{
+ long tablerow;
+ long fpix[7], irange[7], dimen[7], astart, pstart;
+ long off2, off3, off4, off5, off6, off7;
+ long st10, st20, st30, st40, st50, st60, st70;
+ long st1, st2, st3, st4, st5, st6, st7;
+ long ii, i1, i2, i3, i4, i5, i6, i7;
+
+ if (*status > 0)
+ return(*status);
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+ fits_write_compressed_img(fptr, TINT, fpixel, lpixel,
+ 0, array, NULL, status);
+
+ return(*status);
+ }
+
+ if (naxis < 1 || naxis > 7)
+ return(*status = BAD_DIMEN);
+
+ tablerow=maxvalue(1,group);
+
+ /* calculate the size and number of loops to perform in each dimension */
+ for (ii = 0; ii < 7; ii++)
+ {
+ fpix[ii]=1;
+ irange[ii]=1;
+ dimen[ii]=1;
+ }
+
+ for (ii = 0; ii < naxis; ii++)
+ {
+ fpix[ii]=fpixel[ii];
+ irange[ii]=lpixel[ii]-fpixel[ii]+1;
+ dimen[ii]=naxes[ii];
+ }
+
+ i1=irange[0];
+
+ /* compute the pixel offset between each dimension */
+ off2 = dimen[0];
+ off3 = off2 * dimen[1];
+ off4 = off3 * dimen[2];
+ off5 = off4 * dimen[3];
+ off6 = off5 * dimen[4];
+ off7 = off6 * dimen[5];
+
+ st10 = fpix[0];
+ st20 = (fpix[1] - 1) * off2;
+ st30 = (fpix[2] - 1) * off3;
+ st40 = (fpix[3] - 1) * off4;
+ st50 = (fpix[4] - 1) * off5;
+ st60 = (fpix[5] - 1) * off6;
+ st70 = (fpix[6] - 1) * off7;
+
+ /* store the initial offset in each dimension */
+ st1 = st10;
+ st2 = st20;
+ st3 = st30;
+ st4 = st40;
+ st5 = st50;
+ st6 = st60;
+ st7 = st70;
+
+ astart = 0;
+
+ for (i7 = 0; i7 < irange[6]; i7++)
+ {
+ for (i6 = 0; i6 < irange[5]; i6++)
+ {
+ for (i5 = 0; i5 < irange[4]; i5++)
+ {
+ for (i4 = 0; i4 < irange[3]; i4++)
+ {
+ for (i3 = 0; i3 < irange[2]; i3++)
+ {
+ pstart = st1 + st2 + st3 + st4 + st5 + st6 + st7;
+ for (i2 = 0; i2 < irange[1]; i2++)
+ {
+ if (ffpclk(fptr, 2, tablerow, pstart, i1, &array[astart],
+ status) > 0)
+ return(*status);
+
+ astart += i1;
+ pstart += off2;
+ }
+ st2 = st20;
+ st3 = st3+off3;
+ }
+ st3 = st30;
+ st4 = st4+off4;
+ }
+ st4 = st40;
+ st5 = st5+off5;
+ }
+ st5 = st50;
+ st6 = st6+off6;
+ }
+ st6 = st60;
+ st7 = st7+off7;
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpgpk( fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long firstelem, /* I - first vector element to write(1 = 1st) */
+ long nelem, /* I - number of values to write */
+ int *array, /* I - array of values that are written */
+ int *status) /* IO - error status */
+/*
+ Write an array of group parameters to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being written).
+*/
+{
+ long row;
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ row=maxvalue(1,group);
+
+ ffpclk(fptr, 1L, row, firstelem, nelem, array, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpclk( fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to write (1 = 1st col) */
+ long firstrow, /* I - first row to write (1 = 1st row) */
+ long firstelem, /* I - first vector element to write (1 = 1st) */
+ long nelem, /* I - number of values to write */
+ int *array, /* I - array of values to write */
+ int *status) /* IO - error status */
+/*
+ Write an array of values to a column in the current FITS HDU.
+ The column number may refer to a real column in an ASCII or binary table,
+ or it may refer to a virtual column in a 1 or more grouped FITS primary
+ array. FITSIO treats a primary array as a binary table
+ with 2 vector columns: the first column contains the group parameters (often
+ with length = 0) and the second column contains the array of image pixels.
+ Each row of the table represents a group in the case of multigroup FITS
+ images.
+
+ The input array of values will be converted to the datatype of the column
+ and will be inverse-scaled by the FITS TSCALn and TZEROn values if necessary.
+*/
+{
+ int tcode, maxelem, hdutype, writeraw;
+ long twidth, incre, rownum, remain, next, ntodo;
+ long tnull;
+ OFF_T repeat, startpos, elemnum, large_elem, wrtptr, rowlen;
+ double scale, zero;
+ char tform[20], cform[20];
+ char message[FLEN_ERRMSG];
+
+ char snull[20]; /* the FITS null value */
+
+ double cbuff[DBUFFSIZE / sizeof(double)]; /* align cbuff on word boundary */
+ void *buffer;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ /* call the 'short' or 'long' version of this routine, if possible */
+ if (sizeof(int) == sizeof(short))
+ ffpcli(fptr, colnum, firstrow, firstelem, nelem,
+ (short *) array, status);
+ else if (sizeof(int) == sizeof(long))
+ ffpclj(fptr, colnum, firstrow, firstelem, nelem,
+ (long *) array, status);
+ else
+ {
+ /*
+ This is a special case: sizeof(int) is not equal to sizeof(short) or
+ sizeof(long). This occurs on Alpha OSF systems where short = 2 bytes,
+ int = 4 bytes, and long = 8 bytes.
+ */
+
+ buffer = cbuff;
+
+ if (firstelem == USE_LARGE_VALUE)
+ large_elem = large_first_elem_val;
+ else
+ large_elem = firstelem;
+
+ /*---------------------------------------------------*/
+ /* Check input and get parameters about the column: */
+ /*---------------------------------------------------*/
+ if (ffgcpr( fptr, colnum, firstrow, large_elem, nelem, 1, &scale, &zero,
+ tform, &twidth, &tcode, &maxelem, &startpos, &elemnum, &incre,
+ &repeat, &rowlen, &hdutype, &tnull, snull, status) > 0)
+ return(*status);
+
+ if (tcode == TSTRING)
+ ffcfmt(tform, cform); /* derive C format for writing strings */
+
+ /*
+ if there is no scaling and the native machine format is not byteswapped
+ then we can simply write the raw data bytes into the FITS file if the
+ datatype of the FITS column is the same as the input values. Otherwise
+ we must convert the raw values into the scaled and/or machine dependent
+ format in a temporary buffer that has been allocated for this purpose.
+ */
+ if (scale == 1. && zero == 0. &&
+ MACHINE == NATIVE && tcode == TLONG)
+ {
+ writeraw = 1;
+ maxelem = nelem; /* we can write the entire array at one time */
+ }
+ else
+ writeraw = 0;
+
+ /*---------------------------------------------------------------------*/
+ /* Now write the pixels to the FITS column. */
+ /* First call the ffXXfYY routine to (1) convert the datatype */
+ /* if necessary, and (2) scale the values by the FITS TSCALn and */
+ /* TZEROn linear scaling parameters into a temporary buffer. */
+ /*---------------------------------------------------------------------*/
+ remain = nelem; /* remaining number of values to write */
+ next = 0; /* next element in array to be written */
+ rownum = 0; /* row number, relative to firstrow */
+
+ while (remain)
+ {
+ /* limit the number of pixels to process a one time to the number that
+ will fit in the buffer space or to the number of pixels that remain
+ in the current vector, which ever is smaller.
+ */
+ ntodo = minvalue(remain, maxelem);
+ ntodo = minvalue(ntodo, (repeat - elemnum));
+
+ wrtptr = startpos + ((OFF_T)rownum * rowlen) + (elemnum * incre);
+
+ ffmbyt(fptr, wrtptr, IGNORE_EOF, status); /* move to write position */
+
+ switch (tcode)
+ {
+ case (TLONG):
+ if (writeraw)
+ {
+ /* write raw input bytes without conversion */
+ ffpi4b(fptr, ntodo, incre, (INT32BIT *) &array[next], status);
+ }
+ else
+ {
+ /* convert the raw data before writing to FITS file */
+ ffintfi4(&array[next], ntodo, scale, zero,
+ (INT32BIT *) buffer, status);
+ ffpi4b(fptr, ntodo, incre, (INT32BIT *) buffer, status);
+ }
+
+ break;
+
+ case (TLONGLONG):
+
+ ffintfi8(&array[next], ntodo, scale, zero,
+ (LONGLONG *) buffer, status);
+ ffpi8b(fptr, ntodo, incre, (long *) buffer, status);
+ break;
+
+ case (TBYTE):
+
+ ffintfi1(&array[next], ntodo, scale, zero,
+ (unsigned char *) buffer, status);
+ ffpi1b(fptr, ntodo, incre, (unsigned char *) buffer, status);
+ break;
+
+ case (TSHORT):
+
+ ffintfi2(&array[next], ntodo, scale, zero,
+ (short *) buffer, status);
+ ffpi2b(fptr, ntodo, incre, (short *) buffer, status);
+ break;
+
+ case (TFLOAT):
+
+ ffintfr4(&array[next], ntodo, scale, zero,
+ (float *) buffer, status);
+ ffpr4b(fptr, ntodo, incre, (float *) buffer, status);
+ break;
+
+ case (TDOUBLE):
+ ffintfr8(&array[next], ntodo, scale, zero,
+ (double *) buffer, status);
+ ffpr8b(fptr, ntodo, incre, (double *) buffer, status);
+ break;
+
+ case (TSTRING): /* numerical column in an ASCII table */
+
+ if (cform[1] != 's') /* "%s" format is a string */
+ {
+ ffintfstr(&array[next], ntodo, scale, zero, cform,
+ twidth, (char *) buffer, status);
+
+ if (incre == twidth) /* contiguous bytes */
+ ffpbyt(fptr, ntodo * twidth, buffer, status);
+ else
+ ffpbytoff(fptr, twidth, ntodo, incre - twidth, buffer,
+ status);
+
+ break;
+ }
+ /* can't write to string column, so fall thru to default: */
+
+ default: /* error trap */
+ sprintf(message,
+ "Cannot write numbers to column %d which has format %s",
+ colnum,tform);
+ ffpmsg(message);
+ if (hdutype == ASCII_TBL)
+ return(*status = BAD_ATABLE_FORMAT);
+ else
+ return(*status = BAD_BTABLE_FORMAT);
+
+ } /* End of switch block */
+
+ /*-------------------------*/
+ /* Check for fatal error */
+ /*-------------------------*/
+ if (*status > 0) /* test for error during previous write operation */
+ {
+ sprintf(message,
+ "Error writing elements %ld thru %ld of input data array (ffpclk).",
+ next+1, next+ntodo);
+ ffpmsg(message);
+ return(*status);
+ }
+
+ /*--------------------------------------------*/
+ /* increment the counters for the next loop */
+ /*--------------------------------------------*/
+ remain -= ntodo;
+ if (remain)
+ {
+ next += ntodo;
+ elemnum += ntodo;
+ if (elemnum == repeat) /* completed a row; start on next row */
+ {
+ elemnum = 0;
+ rownum++;
+ }
+ }
+ } /* End of main while Loop */
+
+
+ /*--------------------------------*/
+ /* check for numerical overflow */
+ /*--------------------------------*/
+ if (*status == OVERFLOW_ERR)
+ {
+ ffpmsg(
+ "Numerical overflow during type conversion while writing FITS data.");
+ *status = NUM_OVERFLOW;
+ }
+
+ } /* end of Dec ALPHA special case */
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpcnk( fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to write (1 = 1st col) */
+ long firstrow, /* I - first row to write (1 = 1st row) */
+ long firstelem, /* I - first vector element to write (1 = 1st) */
+ long nelem, /* I - number of values to write */
+ int *array, /* I - array of values to write */
+ int nulvalue, /* I - value used to flag undefined pixels */
+ int *status) /* IO - error status */
+/*
+ Write an array of elements to the specified column of a table. Any input
+ pixels equal to the value of nulvalue will be replaced by the appropriate
+ null value in the output FITS file.
+
+ The input array of values will be converted to the datatype of the column
+ and will be inverse-scaled by the FITS TSCALn and TZEROn values if necessary
+*/
+{
+ tcolumn *colptr;
+ long ngood = 0, nbad = 0, ii, fstrow;
+ OFF_T large_elem, repeat, first, fstelm;
+
+ if (*status > 0)
+ return(*status);
+
+ /* reset position to the correct HDU if necessary */
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ {
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+ }
+ else if ((fptr->Fptr)->datastart == DATA_UNDEFINED)
+ {
+ if ( ffrdef(fptr, status) > 0) /* rescan header */
+ return(*status);
+ }
+
+ colptr = (fptr->Fptr)->tableptr; /* point to first column */
+ colptr += (colnum - 1); /* offset to correct column structure */
+
+ repeat = colptr->trepeat; /* repeat count for this column */
+
+ if (firstelem == USE_LARGE_VALUE)
+ large_elem = large_first_elem_val;
+ else
+ large_elem = firstelem;
+
+ /* hereafter, pass first element parameter via global variable */
+ firstelem = USE_LARGE_VALUE;
+
+ /* absolute element number in the column */
+ first = (firstrow - 1) * repeat + large_elem;
+
+ for (ii = 0; ii < nelem; ii++)
+ {
+ if (array[ii] != nulvalue) /* is this a good pixel? */
+ {
+ if (nbad) /* write previous string of bad pixels */
+ {
+ fstelm = ii - nbad + first; /* absolute element number */
+ fstrow = (fstelm - 1) / repeat + 1; /* starting row number */
+ fstelm = fstelm - (fstrow - 1) * repeat; /* relative number */
+ large_first_elem_val = fstelm;
+
+ if (ffpclu(fptr, colnum, fstrow, firstelem, nbad, status) > 0)
+ return(*status);
+
+ nbad=0;
+ }
+
+ ngood = ngood +1; /* the consecutive number of good pixels */
+ }
+ else
+ {
+ if (ngood) /* write previous string of good pixels */
+ {
+ fstelm = ii - ngood + first; /* absolute element number */
+ fstrow = (fstelm - 1) / repeat + 1; /* starting row number */
+ fstelm = fstelm - (fstrow - 1) * repeat; /* relative number */
+ large_first_elem_val = fstelm;
+
+ if (ffpclk(fptr, colnum, fstrow, firstelem, ngood, &array[ii-ngood],
+ status) > 0)
+ return(*status);
+
+ ngood=0;
+ }
+
+ nbad = nbad +1; /* the consecutive number of bad pixels */
+ }
+ }
+
+ /* finished loop; now just write the last set of pixels */
+
+ if (ngood) /* write last string of good pixels */
+ {
+ fstelm = ii - ngood + first; /* absolute element number */
+ fstrow = (fstelm - 1) / repeat + 1; /* starting row number */
+ fstelm = fstelm - (fstrow - 1) * repeat; /* relative number */
+ large_first_elem_val = fstelm;
+
+ ffpclk(fptr, colnum, fstrow, firstelem, ngood, &array[ii-ngood], status);
+ }
+ else if (nbad) /* write last string of bad pixels */
+ {
+ fstelm = ii - nbad + first; /* absolute element number */
+ fstrow = (fstelm - 1) / repeat + 1; /* starting row number */
+ fstelm = fstelm - (fstrow - 1) * repeat; /* relative number */
+ large_first_elem_val = fstelm;
+
+ ffpclu(fptr, colnum, fstrow, firstelem, nbad, status);
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffintfi1(int *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ unsigned char *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required.
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] < 0)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (input[ii] > UCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UCHAR_MAX;
+ }
+ else
+ output[ii] = input[ii];
+ }
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = (input[ii] - zero) / scale;
+
+ if (dvalue < DUCHAR_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DUCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UCHAR_MAX;
+ }
+ else
+ output[ii] = (unsigned char) (dvalue + .5);
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffintfi2(int *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ short *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required.
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] < SHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MIN;
+ }
+ else if (input[ii] > SHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MAX;
+ }
+ else
+ output[ii] = input[ii];
+ }
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = (input[ii] - zero) / scale;
+
+ if (dvalue < DSHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MIN;
+ }
+ else if (dvalue > DSHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MAX;
+ }
+ else
+ {
+ if (dvalue >= 0)
+ output[ii] = (short) (dvalue + .5);
+ else
+ output[ii] = (short) (dvalue - .5);
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffintfi4(int *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ INT32BIT *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (scale == 1. && zero == 0.)
+ {
+ memcpy(output, input, ntodo * sizeof(int) );
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = (input[ii] - zero) / scale;
+
+ if (dvalue < DINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT32_MIN;
+ }
+ else if (dvalue > DINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT32_MAX;
+ }
+ else
+ {
+ if (dvalue >= 0)
+ output[ii] = (INT32BIT) (dvalue + .5);
+ else
+ output[ii] = (INT32BIT) (dvalue - .5);
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffintfi8(int *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ LONGLONG *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required
+*/
+{
+#if (LONGSIZE == 32) && (! defined HAVE_LONGLONG)
+
+/* don't have a native 8-byte integer, so have to construct the */
+/* 2 equivalent 4-byte integers have the same bit pattern */
+
+ unsigned long *uoutput;
+ long ii, jj, kk, temp;
+ double dvalue;
+
+ uoutput = (unsigned long *) output;
+
+#if BYTESWAPPED /* jj points to the most significant part of the 8-byte int */
+ jj = 1;
+ kk = 0;
+#else
+ jj = 0;
+ kk = 1;
+#endif
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++, jj += 2, kk += 2)
+ {
+ if (input[ii] < 0)
+ output[jj] = -1;
+ else
+ output[jj] = 0;
+
+ output[kk] = input[ii];
+ }
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++, jj += 2, kk += 2)
+ {
+ dvalue = (input[ii] - zero) / scale;
+
+ if (dvalue < DLONGLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[jj] = LONG_MIN;
+ output[kk] = 0;
+ }
+ else if (dvalue > DLONGLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[jj] = LONG_MAX;
+ output[kk] = -1;
+ }
+ else
+ {
+ if (dvalue < 0)
+ {
+ temp = (dvalue + 1.) / 4294967296. - 1.;
+ output[jj] = temp;
+ uoutput[kk] = 4294967296. +
+ (dvalue - (double) (temp + 1) * 4294967296.);
+ }
+ else
+ {
+ temp = dvalue / 4294967296.;
+ output[jj] = temp;
+ uoutput[kk] = dvalue - (double) temp * 4294967296.;
+ }
+ }
+ }
+ }
+
+#else
+
+/* this is the much simpler case where the native 8-byte integer exists */
+
+ long ii;
+ double dvalue;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = input[ii];
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = (input[ii] - zero) / scale;
+
+ if (dvalue < DLONGLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONGLONG_MIN;
+ }
+ else if (dvalue > DLONGLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONGLONG_MAX;
+ }
+ else
+ {
+ if (dvalue >= 0)
+ output[ii] = (LONGLONG) (dvalue + .5);
+ else
+ output[ii] = (LONGLONG) (dvalue - .5);
+ }
+ }
+ }
+
+#endif
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffintfr4(int *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ float *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required.
+*/
+{
+ long ii;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = (float) input[ii];
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = (input[ii] - zero) / scale;
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffintfr8(int *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ double *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required.
+*/
+{
+ long ii;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = (double) input[ii];
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = (input[ii] - zero) / scale;
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffintfstr(int *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ char *cform, /* I - format for output string values */
+ long twidth, /* I - width of each field, in chars */
+ char *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do scaling if required.
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ sprintf(output, cform, (double) input[ii]);
+ output += twidth;
+
+ if (*output) /* if this char != \0, then overflow occurred */
+ *status = OVERFLOW_ERR;
+ }
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = (input[ii] - zero) / scale;
+ sprintf(output, cform, dvalue);
+ output += twidth;
+
+ if (*output) /* if this char != \0, then overflow occurred */
+ *status = OVERFLOW_ERR;
+ }
+ }
+ return(*status);
+}
diff --git a/pkg/tbtables/cfitsio/putcoll.c b/pkg/tbtables/cfitsio/putcoll.c
new file mode 100644
index 00000000..0c5de8a1
--- /dev/null
+++ b/pkg/tbtables/cfitsio/putcoll.c
@@ -0,0 +1,355 @@
+/* This file, putcoll.c, contains routines that write data elements to */
+/* a FITS image or table, with logical datatype. */
+
+/* The FITSIO software was written by William Pence at the High Energy */
+/* Astrophysic Science Archive Research Center (HEASARC) at the NASA */
+/* Goddard Space Flight Center. */
+
+#include <string.h>
+#include <stdlib.h>
+#include "fitsio2.h"
+/*--------------------------------------------------------------------------*/
+int ffpcll( fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to write (1 = 1st col) */
+ long firstrow, /* I - first row to write (1 = 1st row) */
+ long firstelem, /* I - first vector element to write (1 = 1st) */
+ long nelem, /* I - number of values to write */
+ char *array, /* I - array of values to write */
+ int *status) /* IO - error status */
+/*
+ Write an array of logical values to a column in the current FITS HDU.
+*/
+{
+ int tcode, maxelem, hdutype;
+ long twidth, incre, rownum, remain, next;
+ long tnull;
+ OFF_T repeat, startpos, elemnum, wrtptr, rowlen;
+ double scale, zero;
+ char tform[20], ctrue = 'T', cfalse = 'F';
+ char message[FLEN_ERRMSG];
+ char snull[20]; /* the FITS null value */
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ /*---------------------------------------------------*/
+ /* Check input and get parameters about the column: */
+ /*---------------------------------------------------*/
+ if (ffgcpr( fptr, colnum, firstrow, firstelem, nelem, 1, &scale, &zero,
+ tform, &twidth, &tcode, &maxelem, &startpos, &elemnum, &incre,
+ &repeat, &rowlen, &hdutype, &tnull, snull, status) > 0)
+ return(*status);
+
+ if (tcode != TLOGICAL)
+ return(*status = NOT_LOGICAL_COL);
+
+ /*---------------------------------------------------------------------*/
+ /* Now write the logical values one at a time to the FITS column. */
+ /*---------------------------------------------------------------------*/
+ remain = nelem; /* remaining number of values to write */
+ next = 0; /* next element in array to be written */
+ rownum = 0; /* row number, relative to firstrow */
+
+ while (remain)
+ {
+ wrtptr = startpos + (rowlen * rownum) + (elemnum * incre);
+
+ ffmbyt(fptr, wrtptr, IGNORE_EOF, status); /* move to write position */
+
+ if (array[next])
+ ffpbyt(fptr, 1, &ctrue, status);
+ else
+ ffpbyt(fptr, 1, &cfalse, status);
+
+ if (*status > 0) /* test for error during previous write operation */
+ {
+ sprintf(message,
+ "Error writing element %ld of input array of logicals (ffpcll).",
+ next+1);
+ ffpmsg(message);
+ return(*status);
+ }
+
+ /*--------------------------------------------*/
+ /* increment the counters for the next loop */
+ /*--------------------------------------------*/
+ remain--;
+ if (remain)
+ {
+ next++;
+ elemnum++;
+ if (elemnum == repeat) /* completed a row; start on next row */
+ {
+ elemnum = 0;
+ rownum++;
+ }
+ }
+
+ } /* End of main while Loop */
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpcnl( fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to write (1 = 1st col) */
+ long firstrow, /* I - first row to write (1 = 1st row) */
+ long firstelem, /* I - first vector element to write (1 = 1st) */
+ long nelem, /* I - number of values to write */
+ char *array, /* I - array of values to write */
+ char nulvalue, /* I - array flagging undefined pixels if true */
+ int *status) /* IO - error status */
+/*
+ Write an array of elements to the specified column of a table. Any input
+ pixels flagged as null will be replaced by the appropriate
+ null value in the output FITS file.
+*/
+{
+ tcolumn *colptr;
+ long repeat, first, ngood = 0, nbad = 0, ii, fstelm, fstrow;
+
+ if (*status > 0)
+ return(*status);
+
+ /* reset position to the correct HDU if necessary */
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ {
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+ }
+ else if ((fptr->Fptr)->datastart == DATA_UNDEFINED)
+ {
+ if ( ffrdef(fptr, status) > 0) /* rescan header */
+ return(*status);
+ }
+
+ colptr = (fptr->Fptr)->tableptr; /* point to first column */
+ colptr += (colnum - 1); /* offset to correct column structure */
+
+ repeat = colptr->trepeat; /* repeat count for this column */
+
+ /* absolute element number in the column */
+ first = (firstrow - 1) * repeat + firstelem;
+
+ for (ii = 0; ii < nelem; ii++)
+ {
+ if (array[ii] != nulvalue) /* is this a good pixel? */
+ {
+ if (nbad) /* write previous string of bad pixels */
+ {
+ fstelm = ii - nbad + first; /* absolute element number */
+ fstrow = (fstelm - 1) / repeat + 1; /* starting row number */
+ fstelm = fstelm - (fstrow - 1) * repeat; /* relative number */
+
+ if (ffpclu(fptr, colnum, fstrow, fstelm, nbad, status) > 0)
+ return(*status);
+
+ nbad=0;
+ }
+
+ ngood = ngood +1; /* the consecutive number of good pixels */
+ }
+ else
+ {
+ if (ngood) /* write previous string of good pixels */
+ {
+ fstelm = ii - ngood + first; /* absolute element number */
+ fstrow = (fstelm - 1) / repeat + 1; /* starting row number */
+ fstelm = fstelm - (fstrow - 1) * repeat; /* relative number */
+
+ if (ffpcll(fptr, colnum, fstrow, fstelm, ngood, &array[ii-ngood],
+ status) > 0)
+ return(*status);
+
+ ngood=0;
+ }
+
+ nbad = nbad +1; /* the consecutive number of bad pixels */
+ }
+ }
+
+ /* finished loop; now just write the last set of pixels */
+
+ if (ngood) /* write last string of good pixels */
+ {
+ fstelm = ii - ngood + first; /* absolute element number */
+ fstrow = (fstelm - 1) / repeat + 1; /* starting row number */
+ fstelm = fstelm - (fstrow - 1) * repeat; /* relative number */
+
+ ffpcll(fptr, colnum, fstrow, fstelm, ngood, &array[ii-ngood], status);
+ }
+ else if (nbad) /* write last string of bad pixels */
+ {
+ fstelm = ii - nbad + first; /* absolute element number */
+ fstrow = (fstelm - 1) / repeat + 1; /* starting row number */
+ fstelm = fstelm - (fstrow - 1) * repeat; /* relative number */
+
+ ffpclu(fptr, colnum, fstrow, fstelm, nbad, status);
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpclx( fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to write (1 = 1st col) */
+ long frow, /* I - first row to write (1 = 1st row) */
+ long fbit, /* I - first bit to write (1 = 1st) */
+ long nbit, /* I - number of bits to write */
+ char *larray, /* I - array of logicals corresponding to bits */
+ int *status) /* IO - error status */
+/*
+ write an array of logical values to a specified bit or byte
+ column of the binary table. If larray is TRUE, then the corresponding
+ bit is set to 1, otherwise it is set to 0.
+ The binary table column being written to must have datatype 'B' or 'X'.
+*/
+{
+ OFF_T bstart, repeat, rowlen, elemnum;
+ long offset, fbyte, lbyte, nbyte, bitloc, ndone;
+ long ii, rstart, estart, twidth, incre, tnull;
+ int tcode, descrp, maxelem, hdutype;
+ double dummyd;
+ char tform[12], snull[12];
+ unsigned char cbuff;
+ static unsigned char onbit[8] = {128, 64, 32, 16, 8, 4, 2, 1};
+ static unsigned char offbit[8] = {127, 191, 223, 239, 247, 251, 253, 254};
+ tcolumn *colptr;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ /* check input parameters */
+ if (nbit < 1)
+ return(*status);
+ else if (frow < 1)
+ return(*status = BAD_ROW_NUM);
+ else if (fbit < 1)
+ return(*status = BAD_ELEM_NUM);
+
+ /* reset position to the correct HDU if necessary */
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+
+ /* rescan header if data structure is undefined */
+ else if ((fptr->Fptr)->datastart == DATA_UNDEFINED)
+ if ( ffrdef(fptr, status) > 0)
+ return(*status);
+
+ fbyte = (fbit + 7) / 8;
+ lbyte = (fbit + nbit + 6) / 8;
+ nbyte = lbyte - fbyte +1;
+
+ /* Save the current heapsize; ffgcpr will increment the value if */
+ /* we are writing to a variable length column. */
+ offset = (fptr->Fptr)->heapsize;
+
+ /* call ffgcpr in case we are writing beyond the current end of */
+ /* the table; it will allocate more space and shift any following */
+ /* HDU's. Otherwise, we have little use for most of the returned */
+ /* parameters, therefore just use dummy parameters. */
+
+ if (ffgcpr( fptr, colnum, frow, fbyte, nbyte, 1, &dummyd, &dummyd,
+ tform, &twidth, &tcode, &maxelem, &bstart, &elemnum, &incre,
+ &repeat, &rowlen, &hdutype, &tnull, snull, status) > 0)
+ return(*status);
+
+ bitloc = fbit - 1 - ((fbit - 1) / 8 * 8);
+ ndone = 0;
+ rstart = frow - 1;
+ estart = fbyte - 1;
+
+ colptr = (fptr->Fptr)->tableptr; /* point to first column */
+ colptr += (colnum - 1); /* offset to correct column structure */
+
+ tcode = colptr->tdatatype;
+
+ if (abs(tcode) > TBYTE)
+ return(*status = NOT_LOGICAL_COL); /* not correct datatype column */
+
+ if (tcode > 0)
+ {
+ descrp = FALSE; /* not a variable length descriptor column */
+ repeat = colptr->trepeat;
+
+ if (tcode == TBIT)
+ repeat = (repeat + 7) / 8; /* convert from bits to bytes */
+
+ if (fbyte > repeat)
+ return(*status = BAD_ELEM_NUM);
+
+ /* calc the i/o pointer location to start of sequence of pixels */
+ bstart = (fptr->Fptr)->datastart + ((fptr->Fptr)->rowlength * rstart) +
+ colptr->tbcol + estart;
+ }
+ else
+ {
+ descrp = TRUE; /* a variable length descriptor column */
+ /* only bit arrays (tform = 'X') are supported for variable */
+ /* length arrays. REPEAT is the number of BITS in the array. */
+
+ repeat = fbit + nbit -1;
+
+ /* write the number of elements and the starting offset. */
+ /* Note: ffgcpr previous wrote the descripter, but with the */
+ /* wrong repeat value (gave bytes instead of bits). */
+
+ if (tcode == -TBIT)
+ ffpdes(fptr, colnum, frow, (long) repeat, offset, status);
+
+ /* Calc the i/o pointer location to start of sequence of pixels. */
+ /* ffgcpr has already calculated a value for bstart that */
+ /* points to the first element of the vector; we just have to */
+ /* increment it to point to the first element we want to write to. */
+ /* Note: ffgcpr also already updated the size of the heap, so we */
+ /* don't have to do that again here. */
+
+ bstart += estart;
+ }
+
+ /* move the i/o pointer to the start of the pixel sequence */
+ ffmbyt(fptr, bstart, IGNORE_EOF, status);
+
+ /* read the next byte (we may only be modifying some of the bits) */
+ while (1)
+ {
+ if (ffgbyt(fptr, 1, &cbuff, status) == END_OF_FILE)
+ {
+ /* hit end of file trying to read the byte, so just set byte = 0 */
+ *status = 0;
+ cbuff = 0;
+ }
+
+ /* move back, to be able to overwrite the byte */
+ ffmbyt(fptr, bstart, IGNORE_EOF, status);
+
+ for (ii = bitloc; (ii < 8) && (ndone < nbit); ii++, ndone++)
+ {
+ if(larray[ndone])
+ cbuff = cbuff | onbit[ii];
+ else
+ cbuff = cbuff & offbit[ii];
+ }
+
+ ffpbyt(fptr, 1, &cbuff, status); /* write the modified byte */
+
+ if (ndone == nbit) /* finished all the bits */
+ return(*status);
+
+ /* not done, so get the next byte */
+ bstart++;
+ if (!descrp)
+ {
+ estart++;
+ if (estart == repeat)
+ {
+ /* move the i/o pointer to the next row of pixels */
+ estart = 0;
+ rstart = rstart + 1;
+ bstart = (fptr->Fptr)->datastart + ((fptr->Fptr)->rowlength * rstart) +
+ colptr->tbcol;
+
+ ffmbyt(fptr, bstart, IGNORE_EOF, status);
+ }
+ }
+ bitloc = 0;
+ }
+}
+
diff --git a/pkg/tbtables/cfitsio/putcols.c b/pkg/tbtables/cfitsio/putcols.c
new file mode 100644
index 00000000..7e27a29c
--- /dev/null
+++ b/pkg/tbtables/cfitsio/putcols.c
@@ -0,0 +1,284 @@
+/* This file, putcols.c, contains routines that write data elements to */
+/* a FITS image or table, of type character string. */
+
+/* The FITSIO software was written by William Pence at the High Energy */
+/* Astrophysic Science Archive Research Center (HEASARC) at the NASA */
+/* Goddard Space Flight Center. */
+
+#include <string.h>
+#include <stdlib.h>
+#include "fitsio2.h"
+/*--------------------------------------------------------------------------*/
+int ffpcls( fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to write (1 = 1st col) */
+ long firstrow, /* I - first row to write (1 = 1st row) */
+ long firstelem, /* I - first vector element to write (1 = 1st) */
+ long nelem, /* I - number of strings to write */
+ char **array, /* I - array of pointers to strings */
+ int *status) /* IO - error status */
+/*
+ Write an array of string values to a column in the current FITS HDU.
+*/
+{
+ int tcode, maxelem, hdutype, nchar;
+ long twidth, incre, rownum, remain, next;
+ long ii, jj, ntodo, tnull;
+ OFF_T repeat, startpos, elemnum, wrtptr, rowlen;
+ double scale, zero;
+ char tform[20], *blanks;
+ char message[FLEN_ERRMSG];
+ char snull[20]; /* the FITS null value */
+ tcolumn *colptr;
+
+ double cbuff[DBUFFSIZE / sizeof(double)]; /* align cbuff on word boundary */
+ char *buffer, *arrayptr;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ /* reset position to the correct HDU if necessary */
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ {
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+ }
+ else if ((fptr->Fptr)->datastart == DATA_UNDEFINED)
+ {
+ if ( ffrdef(fptr, status) > 0) /* rescan header */
+ return(*status);
+ }
+
+ /*---------------------------------------------------*/
+ /* Check input and get parameters about the column: */
+ /*---------------------------------------------------*/
+ if (colnum < 1 || colnum > (fptr->Fptr)->tfield)
+ {
+ sprintf(message, "Specified column number is out of range: %d",
+ colnum);
+ ffpmsg(message);
+ return(*status = BAD_COL_NUM);
+ }
+
+ colptr = (fptr->Fptr)->tableptr; /* point to first column */
+ colptr += (colnum - 1); /* offset to correct column structure */
+ tcode = colptr->tdatatype;
+
+ if (tcode == -TSTRING) /* variable length column in a binary table? */
+ {
+ /* only write a single string; ignore value of firstelem */
+ nchar = maxvalue(1,strlen(array[0])); /* will write at least 1 char */
+ /* even if input string is null */
+
+ if (ffgcpr( fptr, colnum, firstrow, 1, nchar, 1, &scale, &zero,
+ tform, &twidth, &tcode, &maxelem, &startpos, &elemnum, &incre,
+ &repeat, &rowlen, &hdutype, &tnull, snull, status) > 0)
+ return(*status);
+
+ remain = 1;
+ twidth = nchar;
+ blanks = 0; /* initialize null pointer */
+ }
+ else if (tcode == TSTRING)
+ {
+ if (ffgcpr( fptr, colnum, firstrow, firstelem, nelem, 1, &scale, &zero,
+ tform, &twidth, &tcode, &maxelem, &startpos, &elemnum, &incre,
+ &repeat, &rowlen, &hdutype, &tnull, snull, status) > 0)
+ return(*status);
+
+ blanks = (char *) malloc(twidth); /* string for blank fill values */
+ if (!blanks)
+ {
+ ffpmsg("Could not allocate memory for string (ffpcls)");
+ return(*status = ARRAY_TOO_BIG);
+ }
+
+ for (ii = 0; ii < twidth; ii++)
+ blanks[ii] = ' '; /* fill string with blanks */
+
+ remain = nelem; /* remaining number of values to write */
+ }
+ else
+ return(*status = NOT_ASCII_COL);
+
+ /*-------------------------------------------------------*/
+ /* Now write the strings to the FITS column. */
+ /*-------------------------------------------------------*/
+
+ next = 0; /* next element in array to be written */
+ rownum = 0; /* row number, relative to firstrow */
+
+ while (remain)
+ {
+ /* limit the number of pixels to process at one time to the number that
+ will fit in the buffer space or to the number of pixels that remain
+ in the current vector, which ever is smaller.
+ */
+ ntodo = minvalue(remain, maxelem);
+ ntodo = minvalue(ntodo, (repeat - elemnum));
+
+ wrtptr = startpos + ((OFF_T)rownum * rowlen) + (elemnum * incre);
+ ffmbyt(fptr, wrtptr, IGNORE_EOF, status); /* move to write position */
+
+ buffer = (char *) cbuff;
+
+ /* copy the user's strings into the buffer */
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ arrayptr = array[next];
+
+ for (jj = 0; jj < twidth; jj++) /* copy the string, char by char */
+ {
+ if (*arrayptr)
+ {
+ *buffer = *arrayptr;
+ buffer++;
+ arrayptr++;
+ }
+ else
+ break;
+ }
+
+ for (;jj < twidth; jj++) /* fill field with blanks, if needed */
+ {
+ *buffer = ' ';
+ buffer++;
+ }
+
+ next++;
+ }
+
+ /* write the buffer full of strings to the FITS file */
+ if (incre == twidth)
+ ffpbyt(fptr, ntodo * twidth, cbuff, status);
+ else
+ ffpbytoff(fptr, twidth, ntodo, incre - twidth, cbuff, status);
+
+ if (*status > 0) /* test for error during previous write operation */
+ {
+ sprintf(message,
+ "Error writing elements %ld thru %ld of input data array (ffpcls).",
+ next+1, next+ntodo);
+ ffpmsg(message);
+
+ if (blanks)
+ free(blanks);
+
+ return(*status);
+ }
+
+ /*--------------------------------------------*/
+ /* increment the counters for the next loop */
+ /*--------------------------------------------*/
+ remain -= ntodo;
+ if (remain)
+ {
+ elemnum += ntodo;
+ if (elemnum == repeat) /* completed a row; start on next row */
+ {
+ elemnum = 0;
+ rownum++;
+ }
+ }
+ } /* End of main while Loop */
+
+ if (blanks)
+ free(blanks);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpcns( fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to write (1 = 1st col) */
+ long firstrow, /* I - first row to write (1 = 1st row) */
+ long firstelem, /* I - first vector element to write (1 = 1st) */
+ long nelem, /* I - number of values to write */
+ char **array, /* I - array of values to write */
+ char *nulvalue, /* I - string representing a null value */
+ int *status) /* IO - error status */
+/*
+ Write an array of elements to the specified column of a table. Any input
+ pixels flagged as null will be replaced by the appropriate
+ null value in the output FITS file.
+*/
+{
+ long repeat, width, first, ngood = 0, nbad = 0, ii, fstelm, fstrow;
+
+ if (*status > 0)
+ return(*status);
+
+ /* reset position to the correct HDU if necessary */
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ {
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+ }
+ else if ((fptr->Fptr)->datastart == DATA_UNDEFINED)
+ {
+ if ( ffrdef(fptr, status) > 0) /* rescan header */
+ return(*status);
+ }
+
+ /* get the vector repeat length of the column */
+ ffgtcl(fptr, colnum, NULL, &repeat, &width, status);
+
+ if ((fptr->Fptr)->hdutype == BINARY_TBL)
+ repeat = repeat / width; /* convert from chars to unit strings */
+
+ /* absolute element number in the column */
+ first = (firstrow - 1) * repeat + firstelem;
+
+ for (ii = 0; ii < nelem; ii++)
+ {
+ if (strcmp(nulvalue, array[ii])) /* is this a good pixel? */
+ {
+ if (nbad) /* write previous string of bad pixels */
+ {
+ fstelm = ii - nbad + first; /* absolute element number */
+ fstrow = (fstelm - 1) / repeat + 1; /* starting row number */
+ fstelm = fstelm - (fstrow - 1) * repeat; /* relative number */
+
+ if (ffpclu(fptr, colnum, fstrow, fstelm, nbad, status) > 0)
+ return(*status);
+ nbad=0;
+ }
+
+ ngood = ngood +1; /* the consecutive number of good pixels */
+ }
+ else
+ {
+ if (ngood) /* write previous string of good pixels */
+ {
+ fstelm = ii - ngood + first; /* absolute element number */
+ fstrow = (fstelm - 1) / repeat + 1; /* starting row number */
+ fstelm = fstelm - (fstrow - 1) * repeat; /* relative number */
+
+ if (ffpcls(fptr, colnum, fstrow, fstelm, ngood, &array[ii-ngood],
+ status) > 0)
+ return(*status);
+
+ ngood=0;
+ }
+
+ nbad = nbad +1; /* the consecutive number of bad pixels */
+ }
+ }
+
+ /* finished loop; now just write the last set of pixels */
+
+ if (ngood) /* write last string of good pixels */
+ {
+ fstelm = ii - ngood + first; /* absolute element number */
+ fstrow = (fstelm - 1) / repeat + 1; /* starting row number */
+ fstelm = fstelm - (fstrow - 1) * repeat; /* relative number */
+
+ ffpcls(fptr, colnum, fstrow, fstelm, ngood, &array[ii-ngood], status);
+ }
+ else if (nbad) /* write last string of bad pixels */
+ {
+ fstelm = ii - nbad + first; /* absolute element number */
+ fstrow = (fstelm - 1) / repeat + 1; /* starting row number */
+ fstelm = fstelm - (fstrow - 1) * repeat; /* relative number */
+
+ ffpclu(fptr, colnum, fstrow, fstelm, nbad, status);
+ }
+
+ return(*status);
+}
diff --git a/pkg/tbtables/cfitsio/putcolsb.c b/pkg/tbtables/cfitsio/putcolsb.c
new file mode 100644
index 00000000..2a0e95a4
--- /dev/null
+++ b/pkg/tbtables/cfitsio/putcolsb.c
@@ -0,0 +1,1030 @@
+/* This file, putcolsb.c, contains routines that write data elements to */
+/* a FITS image or table with signed char (signed byte) datatype. */
+
+/* The FITSIO software was written by William Pence at the High Energy */
+/* Astrophysic Science Archive Research Center (HEASARC) at the NASA */
+/* Goddard Space Flight Center. */
+
+#include <limits.h>
+#include <string.h>
+#include <stdlib.h>
+#include "fitsio2.h"
+
+/* declare variable for passing large firstelem values between routines */
+extern OFF_T large_first_elem_val;
+
+/*--------------------------------------------------------------------------*/
+int ffpprsb( fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long firstelem, /* I - first vector element to write(1 = 1st) */
+ long nelem, /* I - number of values to write */
+ signed char *array, /* I - array of values that are written */
+ int *status) /* IO - error status */
+/*
+ Write an array of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being written).
+*/
+{
+ long row;
+ signed char nullvalue;
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ /* use the OFF_T variable to pass the first element value */
+ if (firstelem != USE_LARGE_VALUE)
+ large_first_elem_val = firstelem;
+
+ fits_write_compressed_pixels(fptr, TSBYTE, large_first_elem_val, nelem,
+ 0, array, &nullvalue, status);
+ return(*status);
+ }
+
+ row=maxvalue(1,group);
+
+ ffpclsb(fptr, 2, row, firstelem, nelem, array, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffppnsb( fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long firstelem, /* I - first vector element to write(1 = 1st) */
+ long nelem, /* I - number of values to write */
+ signed char *array, /* I - array of values that are written */
+ signed char nulval, /* I - undefined pixel value */
+ int *status) /* IO - error status */
+/*
+ Write an array of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of the
+ FITS array is not the same as the array being written). Any array values
+ that are equal to the value of nulval will be replaced with the null
+ pixel value that is appropriate for this column.
+*/
+{
+ long row;
+ signed char nullvalue;
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ /* use the OFF_T variable to pass the first element value */
+ if (firstelem != USE_LARGE_VALUE)
+ large_first_elem_val = firstelem;
+
+ nullvalue = nulval; /* set local variable */
+ fits_write_compressed_pixels(fptr, TSBYTE, large_first_elem_val, nelem,
+ 1, array, &nullvalue, status);
+ return(*status);
+ }
+
+ row=maxvalue(1,group);
+
+ ffpcnsb(fptr, 2, row, firstelem, nelem, array, nulval, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffp2dsb(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long ncols, /* I - number of pixels in each row of array */
+ long naxis1, /* I - FITS image NAXIS1 value */
+ long naxis2, /* I - FITS image NAXIS2 value */
+ signed char *array, /* I - array to be written */
+ int *status) /* IO - error status */
+/*
+ Write an entire 2-D array of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of the
+ FITS array is not the same as the array being written).
+*/
+{
+ /* call the 3D writing routine, with the 3rd dimension = 1 */
+
+ ffp3dsb(fptr, group, ncols, naxis2, naxis1, naxis2, 1, array, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffp3dsb(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long ncols, /* I - number of pixels in each row of array */
+ long nrows, /* I - number of rows in each plane of array */
+ long naxis1, /* I - FITS image NAXIS1 value */
+ long naxis2, /* I - FITS image NAXIS2 value */
+ long naxis3, /* I - FITS image NAXIS3 value */
+ signed char *array, /* I - array to be written */
+ int *status) /* IO - error status */
+/*
+ Write an entire 3-D cube of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of the
+ FITS array is not the same as the array being written).
+*/
+{
+ long tablerow, nfits, narray, ii, jj;
+ long fpixel[3]= {1,1,1}, lpixel[3];
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+ lpixel[0] = ncols;
+ lpixel[1] = nrows;
+ lpixel[2] = naxis3;
+
+ fits_write_compressed_img(fptr, TSBYTE, fpixel, lpixel,
+ 0, array, NULL, status);
+
+ return(*status);
+ }
+
+ tablerow=maxvalue(1,group);
+
+ if (ncols == naxis1 && nrows == naxis2) /* arrays have same size? */
+ {
+ /* all the image pixels are contiguous, so write all at once */
+ ffpclsb(fptr, 2, tablerow, 1L, naxis1 * naxis2 * naxis3, array, status);
+ return(*status);
+ }
+
+ if (ncols < naxis1 || nrows < naxis2)
+ return(*status = BAD_DIMEN);
+
+ nfits = 1; /* next pixel in FITS image to write to */
+ narray = 0; /* next pixel in input array to be written */
+
+ /* loop over naxis3 planes in the data cube */
+ for (jj = 0; jj < naxis3; jj++)
+ {
+ /* loop over the naxis2 rows in the FITS image, */
+ /* writing naxis1 pixels to each row */
+
+ for (ii = 0; ii < naxis2; ii++)
+ {
+ if (ffpclsb(fptr, 2, tablerow, nfits, naxis1,&array[narray],status) > 0)
+ return(*status);
+
+ nfits += naxis1;
+ narray += ncols;
+ }
+ narray += (nrows - naxis2) * ncols;
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpsssb(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long naxis, /* I - number of data axes in array */
+ long *naxes, /* I - size of each FITS axis */
+ long *fpixel, /* I - 1st pixel in each axis to write (1=1st) */
+ long *lpixel, /* I - last pixel in each axis to write */
+ signed char *array, /* I - array to be written */
+ int *status) /* IO - error status */
+/*
+ Write a subsection of pixels to the primary array or image.
+ A subsection is defined to be any contiguous rectangular
+ array of pixels within the n-dimensional FITS data file.
+ Data conversion and scaling will be performed if necessary
+ (e.g, if the datatype of the FITS array is not the same as
+ the array being written).
+*/
+{
+ long tablerow;
+ long fpix[7], irange[7], dimen[7], astart, pstart;
+ long off2, off3, off4, off5, off6, off7;
+ long st10, st20, st30, st40, st50, st60, st70;
+ long st1, st2, st3, st4, st5, st6, st7;
+ long ii, i1, i2, i3, i4, i5, i6, i7;
+
+ if (*status > 0)
+ return(*status);
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ fits_write_compressed_img(fptr, TSBYTE, fpixel, lpixel,
+ 0, array, NULL, status);
+
+ return(*status);
+ }
+
+ if (naxis < 1 || naxis > 7)
+ return(*status = BAD_DIMEN);
+
+ tablerow=maxvalue(1,group);
+
+ /* calculate the size and number of loops to perform in each dimension */
+ for (ii = 0; ii < 7; ii++)
+ {
+ fpix[ii]=1;
+ irange[ii]=1;
+ dimen[ii]=1;
+ }
+
+ for (ii = 0; ii < naxis; ii++)
+ {
+ fpix[ii]=fpixel[ii];
+ irange[ii]=lpixel[ii]-fpixel[ii]+1;
+ dimen[ii]=naxes[ii];
+ }
+
+ i1=irange[0];
+
+ /* compute the pixel offset between each dimension */
+ off2 = dimen[0];
+ off3 = off2 * dimen[1];
+ off4 = off3 * dimen[2];
+ off5 = off4 * dimen[3];
+ off6 = off5 * dimen[4];
+ off7 = off6 * dimen[5];
+
+ st10 = fpix[0];
+ st20 = (fpix[1] - 1) * off2;
+ st30 = (fpix[2] - 1) * off3;
+ st40 = (fpix[3] - 1) * off4;
+ st50 = (fpix[4] - 1) * off5;
+ st60 = (fpix[5] - 1) * off6;
+ st70 = (fpix[6] - 1) * off7;
+
+ /* store the initial offset in each dimension */
+ st1 = st10;
+ st2 = st20;
+ st3 = st30;
+ st4 = st40;
+ st5 = st50;
+ st6 = st60;
+ st7 = st70;
+
+ astart = 0;
+
+ for (i7 = 0; i7 < irange[6]; i7++)
+ {
+ for (i6 = 0; i6 < irange[5]; i6++)
+ {
+ for (i5 = 0; i5 < irange[4]; i5++)
+ {
+ for (i4 = 0; i4 < irange[3]; i4++)
+ {
+ for (i3 = 0; i3 < irange[2]; i3++)
+ {
+ pstart = st1 + st2 + st3 + st4 + st5 + st6 + st7;
+ for (i2 = 0; i2 < irange[1]; i2++)
+ {
+ if (ffpclsb(fptr, 2, tablerow, pstart, i1, &array[astart],
+ status) > 0)
+ return(*status);
+
+ astart += i1;
+ pstart += off2;
+ }
+ st2 = st20;
+ st3 = st3+off3;
+ }
+ st3 = st30;
+ st4 = st4+off4;
+ }
+ st4 = st40;
+ st5 = st5+off5;
+ }
+ st5 = st50;
+ st6 = st6+off6;
+ }
+ st6 = st60;
+ st7 = st7+off7;
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpgpsb( fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long firstelem, /* I - first vector element to write(1 = 1st) */
+ long nelem, /* I - number of values to write */
+ signed char *array, /* I - array of values that are written */
+ int *status) /* IO - error status */
+/*
+ Write an array of group parameters to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being written).
+*/
+{
+ long row;
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ row=maxvalue(1,group);
+
+ ffpclsb(fptr, 1L, row, firstelem, nelem, array, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpclsb( fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to write (1 = 1st col) */
+ long firstrow, /* I - first row to write (1 = 1st row) */
+ long firstelem, /* I - first vector element to write (1 = 1st) */
+ long nelem, /* I - number of values to write */
+ signed char *array, /* I - array of values to write */
+ int *status) /* IO - error status */
+/*
+ Write an array of values to a column in the current FITS HDU.
+ The column number may refer to a real column in an ASCII or binary table,
+ or it may refer to a virtual column in a 1 or more grouped FITS primary
+ array. FITSIO treats a primary array as a binary table with
+ 2 vector columns: the first column contains the group parameters (often
+ with length = 0) and the second column contains the array of image pixels.
+ Each row of the table represents a group in the case of multigroup FITS
+ images.
+
+ The input array of values will be converted to the datatype of the column
+ and will be inverse-scaled by the FITS TSCALn and TZEROn values if necessary.
+*/
+{
+ int tcode, maxelem, hdutype;
+ long twidth, incre, rownum, remain, next, ntodo;
+ long tnull;
+ OFF_T repeat, startpos, elemnum, large_elem, wrtptr, rowlen;
+ double scale, zero;
+ char tform[20], cform[20];
+ char message[FLEN_ERRMSG];
+
+ char snull[20]; /* the FITS null value */
+
+ double cbuff[DBUFFSIZE / sizeof(double)]; /* align cbuff on word boundary */
+ void *buffer;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ buffer = cbuff;
+
+ if (firstelem == USE_LARGE_VALUE)
+ large_elem = large_first_elem_val;
+ else
+ large_elem = firstelem;
+
+ /*---------------------------------------------------*/
+ /* Check input and get parameters about the column: */
+ /*---------------------------------------------------*/
+ if (ffgcpr( fptr, colnum, firstrow, large_elem, nelem, 1, &scale, &zero,
+ tform, &twidth, &tcode, &maxelem, &startpos, &elemnum, &incre,
+ &repeat, &rowlen, &hdutype, &tnull, snull, status) > 0)
+ return(*status);
+
+ if (tcode == TSTRING)
+ ffcfmt(tform, cform); /* derive C format for writing strings */
+
+ /*---------------------------------------------------------------------*/
+ /* Now write the pixels to the FITS column. */
+ /* First call the ffXXfYY routine to (1) convert the datatype */
+ /* if necessary, and (2) scale the values by the FITS TSCALn and */
+ /* TZEROn linear scaling parameters into a temporary buffer. */
+ /*---------------------------------------------------------------------*/
+ remain = nelem; /* remaining number of values to write */
+ next = 0; /* next element in array to be written */
+ rownum = 0; /* row number, relative to firstrow */
+
+ while (remain)
+ {
+ /* limit the number of pixels to process a one time to the number that
+ will fit in the buffer space or to the number of pixels that remain
+ in the current vector, which ever is smaller.
+ */
+ ntodo = minvalue(remain, maxelem);
+ ntodo = minvalue(ntodo, (repeat - elemnum));
+
+ wrtptr = startpos + ((OFF_T)rownum * rowlen) + (elemnum * incre);
+ ffmbyt(fptr, wrtptr, IGNORE_EOF, status); /* move to write position */
+
+ switch (tcode)
+ {
+ case (TBYTE):
+
+ /* convert the raw data before writing to FITS file */
+ ffs1fi1(&array[next], ntodo, scale, zero,
+ (unsigned char *) buffer, status);
+ ffpi1b(fptr, ntodo, incre, (unsigned char *) buffer, status);
+
+ break;
+
+ case (TLONGLONG):
+
+ ffs1fi8(&array[next], ntodo, scale, zero,
+ (LONGLONG *) buffer, status);
+ ffpi8b(fptr, ntodo, incre, (long *) buffer, status);
+ break;
+
+ case (TSHORT):
+
+ ffs1fi2(&array[next], ntodo, scale, zero,
+ (short *) buffer, status);
+ ffpi2b(fptr, ntodo, incre, (short *) buffer, status);
+ break;
+
+ case (TLONG):
+
+ ffs1fi4(&array[next], ntodo, scale, zero,
+ (INT32BIT *) buffer, status);
+ ffpi4b(fptr, ntodo, incre, (INT32BIT *) buffer, status);
+ break;
+
+ case (TFLOAT):
+
+ ffs1fr4(&array[next], ntodo, scale, zero,
+ (float *) buffer, status);
+ ffpr4b(fptr, ntodo, incre, (float *) buffer, status);
+ break;
+
+ case (TDOUBLE):
+ ffs1fr8(&array[next], ntodo, scale, zero,
+ (double *) buffer, status);
+ ffpr8b(fptr, ntodo, incre, (double *) buffer, status);
+ break;
+
+ case (TSTRING): /* numerical column in an ASCII table */
+
+ if (strchr(tform,'A'))
+ {
+ /* write raw input bytes without conversion */
+ /* This case is a hack to let users write a stream */
+ /* of bytes directly to the 'A' format column */
+
+ if (incre == twidth)
+ ffpbyt(fptr, ntodo, &array[next], status);
+ else
+ ffpbytoff(fptr, twidth, ntodo/twidth, incre - twidth,
+ &array[next], status);
+ break;
+ }
+ else if (cform[1] != 's') /* "%s" format is a string */
+ {
+ ffs1fstr(&array[next], ntodo, scale, zero, cform,
+ twidth, (char *) buffer, status);
+
+ if (incre == twidth) /* contiguous bytes */
+ ffpbyt(fptr, ntodo * twidth, buffer, status);
+ else
+ ffpbytoff(fptr, twidth, ntodo, incre - twidth, buffer,
+ status);
+ break;
+ }
+ /* can't write to string column, so fall thru to default: */
+
+ default: /* error trap */
+ sprintf(message,
+ "Cannot write numbers to column %d which has format %s",
+ colnum,tform);
+ ffpmsg(message);
+ if (hdutype == ASCII_TBL)
+ return(*status = BAD_ATABLE_FORMAT);
+ else
+ return(*status = BAD_BTABLE_FORMAT);
+
+ } /* End of switch block */
+
+ /*-------------------------*/
+ /* Check for fatal error */
+ /*-------------------------*/
+ if (*status > 0) /* test for error during previous write operation */
+ {
+ sprintf(message,
+ "Error writing elements %ld thru %ld of input data array (ffpclsb).",
+ next+1, next+ntodo);
+ ffpmsg(message);
+ return(*status);
+ }
+
+ /*--------------------------------------------*/
+ /* increment the counters for the next loop */
+ /*--------------------------------------------*/
+ remain -= ntodo;
+ if (remain)
+ {
+ next += ntodo;
+ elemnum += ntodo;
+ if (elemnum == repeat) /* completed a row; start on next row */
+ {
+ elemnum = 0;
+ rownum++;
+ }
+ }
+ } /* End of main while Loop */
+
+
+ /*--------------------------------*/
+ /* check for numerical overflow */
+ /*--------------------------------*/
+ if (*status == OVERFLOW_ERR)
+ {
+ ffpmsg(
+ "Numerical overflow during type conversion while writing FITS data.");
+ *status = NUM_OVERFLOW;
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpcnsb( fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to write (1 = 1st col) */
+ long firstrow, /* I - first row to write (1 = 1st row) */
+ long firstelem, /* I - first vector element to write (1 = 1st) */
+ long nelem, /* I - number of values to write */
+ signed char *array, /* I - array of values to write */
+ signed char nulvalue, /* I - flag for undefined pixels */
+ int *status) /* IO - error status */
+/*
+ Write an array of elements to the specified column of a table. Any input
+ pixels equal to the value of nulvalue will be replaced by the appropriate
+ null value in the output FITS file.
+
+ The input array of values will be converted to the datatype of the column
+ and will be inverse-scaled by the FITS TSCALn and TZEROn values if necessary
+*/
+{
+ tcolumn *colptr;
+ long ngood = 0, nbad = 0, ii, fstrow;
+ OFF_T large_elem, repeat, first, fstelm;
+
+ if (*status > 0)
+ return(*status);
+
+ /* reset position to the correct HDU if necessary */
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ {
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+ }
+ else if ((fptr->Fptr)->datastart == DATA_UNDEFINED)
+ {
+ if ( ffrdef(fptr, status) > 0) /* rescan header */
+ return(*status);
+ }
+
+ colptr = (fptr->Fptr)->tableptr; /* point to first column */
+ colptr += (colnum - 1); /* offset to correct column structure */
+
+ repeat = colptr->trepeat; /* repeat count for this column */
+
+ if (firstelem == USE_LARGE_VALUE)
+ large_elem = large_first_elem_val;
+ else
+ large_elem = firstelem;
+
+ /* hereafter, pass first element parameter via global variable */
+ firstelem = USE_LARGE_VALUE;
+
+ /* absolute element number in the column */
+ first = (firstrow - 1) * repeat + large_elem;
+
+ for (ii = 0; ii < nelem; ii++)
+ {
+ if (array[ii] != nulvalue) /* is this a good pixel? */
+ {
+ if (nbad) /* write previous string of bad pixels */
+ {
+ fstelm = ii - nbad + first; /* absolute element number */
+ fstrow = (fstelm - 1) / repeat + 1; /* starting row number */
+ fstelm = fstelm - (fstrow - 1) * repeat; /* relative number */
+ large_first_elem_val = fstelm;
+
+ if (ffpclu(fptr, colnum, fstrow, firstelem, nbad, status) > 0)
+ return(*status);
+
+ nbad=0;
+ }
+
+ ngood = ngood + 1; /* the consecutive number of good pixels */
+ }
+ else
+ {
+ if (ngood) /* write previous string of good pixels */
+ {
+ fstelm = ii - ngood + first; /* absolute element number */
+ fstrow = (fstelm - 1) / repeat + 1; /* starting row number */
+ fstelm = fstelm - (fstrow - 1) * repeat; /* relative number */
+ large_first_elem_val = fstelm;
+
+ if (ffpclsb(fptr, colnum, fstrow, firstelem,ngood, &array[ii-ngood],
+ status) > 0)
+ return(*status);
+
+ ngood=0;
+ }
+
+ nbad = nbad + 1; /* the consecutive number of bad pixels */
+ }
+ }
+
+ /* finished loop; now just write the last set of pixels */
+
+ if (ngood) /* write last string of good pixels */
+ {
+ fstelm = ii - ngood + first; /* absolute element number */
+ fstrow = (fstelm - 1) / repeat + 1; /* starting row number */
+ fstelm = fstelm - (fstrow - 1) * repeat; /* relative number */
+ large_first_elem_val = fstelm;
+
+ ffpclsb(fptr, colnum, fstrow, firstelem, ngood, &array[ii-ngood], status);
+ }
+ else if (nbad) /* write last string of bad pixels */
+ {
+ fstelm = ii - nbad + first; /* absolute element number */
+ fstrow = (fstelm - 1) / repeat + 1; /* starting row number */
+ fstelm = fstelm - (fstrow - 1) * repeat; /* relative number */
+ large_first_elem_val = fstelm;
+
+ ffpclu(fptr, colnum, fstrow, firstelem, nbad, status);
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffs1fi1(signed char *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ unsigned char *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (scale == 1. && zero == -128.)
+ {
+ /* Instead of adding 128, it is more efficient */
+ /* to just flip the sign bit with the XOR operator */
+
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = ( *(unsigned char *) &input[ii] ) ^ 0x80;
+ }
+ else if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] < 0)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else
+ output[ii] = (unsigned char) input[ii];
+ }
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = ( ((double) input[ii]) - zero) / scale;
+
+ if (dvalue < DUCHAR_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DUCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UCHAR_MAX;
+ }
+ else
+ output[ii] = (unsigned char) (dvalue + .5);
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffs1fi2(signed char *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ short *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = input[ii]; /* just copy input to output */
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = (((double) input[ii]) - zero) / scale;
+
+ if (dvalue < DSHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MIN;
+ }
+ else if (dvalue > DSHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MAX;
+ }
+ else
+ {
+ if (dvalue >= 0)
+ output[ii] = (short) (dvalue + .5);
+ else
+ output[ii] = (short) (dvalue - .5);
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffs1fi4(signed char *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ INT32BIT *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = (INT32BIT) input[ii]; /* copy input to output */
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = (((double) input[ii]) - zero) / scale;
+
+ if (dvalue < DINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT32_MIN;
+ }
+ else if (dvalue > DINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT32_MAX;
+ }
+ else
+ {
+ if (dvalue >= 0)
+ output[ii] = (INT32BIT) (dvalue + .5);
+ else
+ output[ii] = (INT32BIT) (dvalue - .5);
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffs1fi8(signed char *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ LONGLONG *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required
+*/
+{
+#if (LONGSIZE == 32) && (! defined HAVE_LONGLONG)
+
+/* don't have a native 8-byte integer, so have to construct the */
+/* 2 equivalent 4-byte integers have the same bit pattern */
+
+ unsigned long *uoutput;
+ long ii, jj, kk, temp;
+ double dvalue;
+
+ uoutput = (unsigned long *) output;
+
+#if BYTESWAPPED /* jj points to the most significant part of the 8-byte int */
+ jj = 1;
+ kk = 0;
+#else
+ jj = 0;
+ kk = 1;
+#endif
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++, jj += 2, kk += 2)
+ {
+ if (input[ii] < 0)
+ output[jj] = -1;
+ else
+ output[jj] = 0;
+
+ output[kk] = input[ii];
+ }
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++, jj += 2, kk += 2)
+ {
+ dvalue = (input[ii] - zero) / scale;
+
+ if (dvalue < DLONGLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[jj] = LONG_MIN;
+ output[kk] = 0;
+ }
+ else if (dvalue > DLONGLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[jj] = LONG_MAX;
+ output[kk] = -1;
+ }
+ else
+ {
+ if (dvalue < 0)
+ {
+ temp = (dvalue + 1.) / 4294967296. - 1.;
+ output[jj] = temp;
+ uoutput[kk] = 4294967296. +
+ (dvalue - (double) (temp + 1) * 4294967296.);
+ }
+ else
+ {
+ temp = dvalue / 4294967296.;
+ output[jj] = temp;
+ uoutput[kk] = dvalue - (double) temp * 4294967296.;
+ }
+ }
+ }
+ }
+
+#else
+
+/* this is the much simpler case where the native 8-byte integer exists */
+
+ long ii;
+ double dvalue;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = input[ii];
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = (input[ii] - zero) / scale;
+
+ if (dvalue < DLONGLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONGLONG_MIN;
+ }
+ else if (dvalue > DLONGLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONGLONG_MAX;
+ }
+ else
+ {
+ if (dvalue >= 0)
+ output[ii] = (LONGLONG) (dvalue + .5);
+ else
+ output[ii] = (LONGLONG) (dvalue - .5);
+ }
+ }
+ }
+
+#endif
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffs1fr4(signed char *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ float *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required.
+*/
+{
+ long ii;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = (float) input[ii];
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = ( ( (double) input[ii] ) - zero) / scale;
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffs1fr8(signed char *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ double *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required.
+*/
+{
+ long ii;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = (double) input[ii];
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = ( ( (double) input[ii] ) - zero) / scale;
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffs1fstr(signed char *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ char *cform, /* I - format for output string values */
+ long twidth, /* I - width of each field, in chars */
+ char *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do scaling if required.
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ sprintf(output, cform, (double) input[ii]);
+ output += twidth;
+
+ if (*output) /* if this char != \0, then overflow occurred */
+ *status = OVERFLOW_ERR;
+ }
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = ((double) input[ii] - zero) / scale;
+ sprintf(output, cform, dvalue);
+ output += twidth;
+
+ if (*output) /* if this char != \0, then overflow occurred */
+ *status = OVERFLOW_ERR;
+ }
+ }
+ return(*status);
+}
diff --git a/pkg/tbtables/cfitsio/putcolu.c b/pkg/tbtables/cfitsio/putcolu.c
new file mode 100644
index 00000000..46814440
--- /dev/null
+++ b/pkg/tbtables/cfitsio/putcolu.c
@@ -0,0 +1,587 @@
+/* This file, putcolu.c, contains routines that write data elements to */
+/* a FITS image or table. Writes null values. */
+
+/* The FITSIO software was written by William Pence at the High Energy */
+/* Astrophysic Science Archive Research Center (HEASARC) at the NASA */
+/* Goddard Space Flight Center. */
+
+#include <string.h>
+#include <stdlib.h>
+#include "fitsio2.h"
+
+/* declare variable for passing large firstelem values between routines */
+extern OFF_T large_first_elem_val;
+
+/*--------------------------------------------------------------------------*/
+int ffppru( fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long firstelem, /* I - first vector element to write(1 = 1st) */
+ long nelem, /* I - number of values to write */
+ int *status) /* IO - error status */
+/*
+ Write null values to the primary array.
+*/
+{
+ long row;
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ ffpmsg("writing to compressed image is not supported");
+
+ return(*status = DATA_COMPRESSION_ERR);
+ }
+
+ row=maxvalue(1,group);
+
+ ffpclu(fptr, 2, row, firstelem, nelem, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpprn( fitsfile *fptr, /* I - FITS file pointer */
+ long firstelem, /* I - first vector element to write(1 = 1st) */
+ long nelem, /* I - number of values to write */
+ int *status) /* IO - error status */
+/*
+ Write null values to the primary array. (Doesn't support groups).
+*/
+{
+ long row = 1;
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ ffpmsg("writing to compressed image is not supported");
+
+ return(*status = DATA_COMPRESSION_ERR);
+ }
+
+ ffpclu(fptr, 2, row, firstelem, nelem, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpclu( fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to write (1 = 1st col) */
+ long firstrow, /* I - first row to write (1 = 1st row) */
+ long firstelem, /* I - first vector element to write (1 = 1st) */
+ long nelempar, /* I - number of values to write */
+ int *status) /* IO - error status */
+/*
+ Set elements of a table column to the appropriate null value for the column
+ The column number may refer to a real column in an ASCII or binary table,
+ or it may refer to a virtual column in a 1 or more grouped FITS primary
+ array. FITSIO treats a primary array as a binary table
+ with 2 vector columns: the first column contains the group parameters (often
+ with length = 0) and the second column contains the array of image pixels.
+ Each row of the table represents a group in the case of multigroup FITS
+ images.
+
+ This routine support COMPLEX and DOUBLE COMPLEX binary table columns, and
+ sets both the real and imaginary components of the element to a NaN.
+*/
+{
+ int tcode, maxelem, hdutype, writemode = 2, leng;
+ short i2null;
+ INT32BIT i4null, i8null[2];
+ long twidth, incre, rownum, remain, next, ntodo;
+ long tnull, ii, nelem;
+ OFF_T repeat, startpos, elemnum, large_elem, wrtptr, rowlen;
+ double scale, zero;
+ unsigned char i1null, lognul = 0;
+ char tform[20], *cstring = 0;
+ char message[FLEN_ERRMSG];
+ char snull[20]; /* the FITS null value */
+ long jbuff[2] = { -1, -1}; /* all bits set is equivalent to a NaN */
+ size_t buffsize;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ nelem = nelempar;
+
+ if (firstelem == USE_LARGE_VALUE)
+ large_elem = large_first_elem_val;
+ else
+ large_elem = firstelem;
+
+ /*---------------------------------------------------*/
+ /* Check input and get parameters about the column: */
+ /*---------------------------------------------------*/
+
+ /* note that writemode = 2 by default (not 1), so that the returned */
+ /* repeat and incre values will be the actual values for this column. */
+
+ /* If writing nulls to a variable length column then dummy data values */
+ /* must have already been written to the heap. */
+ /* We just have to overwrite the previous values with null values. */
+ /* Set writemode = 0 in this case, to test that values have been written */
+
+ fits_get_coltype(fptr, colnum, &tcode, NULL, NULL, status);
+ if (tcode < 0)
+ writemode = 0; /* this is a variable length column */
+
+ if (abs(tcode) >= TCOMPLEX)
+ { /* treat complex columns as pairs of numbers */
+ large_elem = (large_elem - 1) * 2 + 1;
+ nelem *= 2;
+ }
+
+ if (ffgcpr( fptr, colnum, firstrow, large_elem, nelem, writemode, &scale,
+ &zero, tform, &twidth, &tcode, &maxelem, &startpos, &elemnum, &incre,
+ &repeat, &rowlen, &hdutype, &tnull, snull, status) > 0)
+ return(*status);
+
+ if (tcode == TSTRING)
+ {
+ if (snull[0] == ASCII_NULL_UNDEFINED)
+ {
+ ffpmsg(
+ "Null value string for ASCII table column is not defined (FTPCLU).");
+ return(*status = NO_NULL);
+ }
+
+ /* allocate buffer to hold the null string. Must write the entire */
+ /* width of the column (twidth bytes) to avoid possible problems */
+ /* with uninitialized FITS blocks, in case the field spans blocks */
+
+ buffsize = maxvalue(20, twidth);
+ cstring = (char *) malloc(buffsize);
+ if (!cstring)
+ return(*status = MEMORY_ALLOCATION);
+
+ memset(cstring, ' ', buffsize); /* initialize with blanks */
+
+ leng = strlen(snull);
+ if (hdutype == BINARY_TBL)
+ leng++; /* copy the terminator too in binary tables */
+
+ strncpy(cstring, snull, leng); /* copy null string to temp buffer */
+
+ }
+ else if ( tcode == TBYTE ||
+ tcode == TSHORT ||
+ tcode == TLONG ||
+ tcode == TLONGLONG)
+ {
+ if (tnull == NULL_UNDEFINED)
+ {
+ ffpmsg(
+ "Null value for integer table column is not defined (FTPCLU).");
+ return(*status = NO_NULL);
+ }
+
+ if (tcode == TBYTE)
+ i1null = tnull;
+ else if (tcode == TSHORT)
+ {
+ i2null = tnull;
+#if BYTESWAPPED
+ ffswap2(&i2null, 1); /* reverse order of bytes */
+#endif
+ }
+ else if (tcode == TLONG)
+ {
+ i4null = tnull;
+#if BYTESWAPPED
+ ffswap4(&i4null, 1); /* reverse order of bytes */
+#endif
+ }
+ else
+ {
+ if (tnull < 0)
+ i8null[0] = -1;
+ else
+ i8null[0] = 0;
+
+ i8null[1] = tnull;
+#if BYTESWAPPED
+ ffswap8( (double *) i8null, 1); /* reverse order of bytes */
+#endif
+ }
+ }
+
+ /*---------------------------------------------------------------------*/
+ /* Now write the pixels to the FITS column. */
+ /*---------------------------------------------------------------------*/
+ remain = nelem; /* remaining number of values to write */
+ next = 0; /* next element in array to be written */
+ rownum = 0; /* row number, relative to firstrow */
+ ntodo = remain; /* number of elements to write at one time */
+
+ while (ntodo)
+ {
+ /* limit the number of pixels to process at one time to the number that
+ will fit in the buffer space or to the number of pixels that remain
+ in the current vector, which ever is smaller.
+ */
+ ntodo = minvalue(ntodo, (repeat - elemnum));
+ wrtptr = startpos + ((OFF_T)rownum * rowlen) + (elemnum * incre);
+
+ ffmbyt(fptr, wrtptr, IGNORE_EOF, status); /* move to write position */
+
+ switch (tcode)
+ {
+ case (TBYTE):
+
+ for (ii = 0; ii < ntodo; ii++)
+ ffpbyt(fptr, 1, &i1null, status);
+ break;
+
+ case (TSHORT):
+
+ for (ii = 0; ii < ntodo; ii++)
+ ffpbyt(fptr, 2, &i2null, status);
+ break;
+
+ case (TLONG):
+
+ for (ii = 0; ii < ntodo; ii++)
+ ffpbyt(fptr, 4, &i4null, status);
+ break;
+
+ case (TLONGLONG):
+
+ for (ii = 0; ii < ntodo; ii++)
+ ffpbyt(fptr, 8, i8null, status);
+ break;
+
+ case (TFLOAT):
+
+ for (ii = 0; ii < ntodo; ii++)
+ ffpbyt(fptr, 4, jbuff, status);
+ break;
+
+ case (TDOUBLE):
+
+ for (ii = 0; ii < ntodo; ii++)
+ ffpbyt(fptr, 8, jbuff, status);
+ break;
+
+ case (TLOGICAL):
+
+ for (ii = 0; ii < ntodo; ii++)
+ ffpbyt(fptr, 1, &lognul, status);
+ break;
+
+ case (TSTRING): /* an ASCII table column */
+ /* repeat always = 1, so ntodo is also guaranteed to = 1 */
+ ffpbyt(fptr, twidth, cstring, status);
+ break;
+
+ default: /* error trap */
+ sprintf(message,
+ "Cannot write null value to column %d which has format %s",
+ colnum,tform);
+ ffpmsg(message);
+ return(*status);
+
+ } /* End of switch block */
+
+ /*-------------------------*/
+ /* Check for fatal error */
+ /*-------------------------*/
+ if (*status > 0) /* test for error during previous write operation */
+ {
+ sprintf(message,
+ "Error writing %ld thru %ld of null values (ffpclu).",
+ next+1, next+ntodo);
+ ffpmsg(message);
+
+ if (cstring)
+ free(cstring);
+
+ return(*status);
+ }
+
+ /*--------------------------------------------*/
+ /* increment the counters for the next loop */
+ /*--------------------------------------------*/
+ remain -= ntodo;
+ if (remain)
+ {
+ next += ntodo;
+ elemnum += ntodo;
+ if (elemnum == repeat) /* completed a row; start on next row */
+ {
+ elemnum = 0;
+ rownum++;
+ }
+ }
+ ntodo = remain; /* this is the maximum number to do in next loop */
+
+ } /* End of main while Loop */
+
+ if (cstring)
+ free(cstring);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpcluc( fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to write (1 = 1st col) */
+ long firstrow, /* I - first row to write (1 = 1st row) */
+ long firstelem, /* I - first vector element to write (1 = 1st) */
+ long nelem, /* I - number of values to write */
+ int *status) /* IO - error status */
+/*
+ Set elements of a table column to the appropriate null value for the column
+ The column number may refer to a real column in an ASCII or binary table,
+ or it may refer to a virtual column in a 1 or more grouped FITS primary
+ array. FITSIO treats a primary array as a binary table
+ with 2 vector columns: the first column contains the group parameters (often
+ with length = 0) and the second column contains the array of image pixels.
+ Each row of the table represents a group in the case of multigroup FITS
+ images.
+
+ This routine does not do anything special in the case of COMPLEX table columns
+ (unlike the similar ffpclu routine). This routine is mainly for use by
+ ffpcne which already compensates for the effective doubling of the number of
+ elements in a complex column.
+*/
+{
+ int tcode, maxelem, hdutype, writemode = 2, leng;
+ short i2null;
+ INT32BIT i4null, i8null[2];
+ long twidth, incre, rownum, remain, next, ntodo;
+ long tnull, ii;
+ OFF_T repeat, startpos, elemnum, large_elem, wrtptr, rowlen;
+ double scale, zero;
+ unsigned char i1null, lognul = 0;
+ char tform[20], *cstring = 0;
+ char message[FLEN_ERRMSG];
+ char snull[20]; /* the FITS null value */
+ long jbuff[2] = { -1, -1}; /* all bits set is equivalent to a NaN */
+ size_t buffsize;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ if (firstelem == USE_LARGE_VALUE)
+ large_elem = large_first_elem_val;
+ else
+ large_elem = firstelem;
+
+ /*---------------------------------------------------*/
+ /* Check input and get parameters about the column: */
+ /*---------------------------------------------------*/
+
+ /* note that writemode = 2 by default (not 1), so that the returned */
+ /* repeat and incre values will be the actual values for this column. */
+
+ /* If writing nulls to a variable length column then dummy data values */
+ /* must have already been written to the heap. */
+ /* We just have to overwrite the previous values with null values. */
+ /* Set writemode = 0 in this case, to test that values have been written */
+
+ fits_get_coltype(fptr, colnum, &tcode, NULL, NULL, status);
+ if (tcode < 0)
+ writemode = 0; /* this is a variable length column */
+
+ if (ffgcpr( fptr, colnum, firstrow, large_elem, nelem, writemode, &scale,
+ &zero, tform, &twidth, &tcode, &maxelem, &startpos, &elemnum, &incre,
+ &repeat, &rowlen, &hdutype, &tnull, snull, status) > 0)
+ return(*status);
+
+ if (tcode == TSTRING)
+ {
+ if (snull[0] == ASCII_NULL_UNDEFINED)
+ {
+ ffpmsg(
+ "Null value string for ASCII table column is not defined (FTPCLU).");
+ return(*status = NO_NULL);
+ }
+
+ /* allocate buffer to hold the null string. Must write the entire */
+ /* width of the column (twidth bytes) to avoid possible problems */
+ /* with uninitialized FITS blocks, in case the field spans blocks */
+
+ buffsize = maxvalue(20, twidth);
+ cstring = (char *) malloc(buffsize);
+ if (!cstring)
+ return(*status = MEMORY_ALLOCATION);
+
+ memset(cstring, ' ', buffsize); /* initialize with blanks */
+
+ leng = strlen(snull);
+ if (hdutype == BINARY_TBL)
+ leng++; /* copy the terminator too in binary tables */
+
+ strncpy(cstring, snull, leng); /* copy null string to temp buffer */
+
+ }
+ else if ( tcode == TBYTE ||
+ tcode == TSHORT ||
+ tcode == TLONG ||
+ tcode == TLONGLONG)
+ {
+ if (tnull == NULL_UNDEFINED)
+ {
+ ffpmsg(
+ "Null value for integer table column is not defined (FTPCLU).");
+ return(*status = NO_NULL);
+ }
+
+ if (tcode == TBYTE)
+ i1null = tnull;
+ else if (tcode == TSHORT)
+ {
+ i2null = tnull;
+#if BYTESWAPPED
+ ffswap2(&i2null, 1); /* reverse order of bytes */
+#endif
+ }
+ else if (tcode == TLONG)
+ {
+ i4null = tnull;
+#if BYTESWAPPED
+ ffswap4(&i4null, 1); /* reverse order of bytes */
+#endif
+ }
+ else
+ {
+ if (tnull < 0)
+ i8null[0] = -1;
+ else
+ i8null[0] = 0;
+
+ i8null[1] = tnull;
+#if BYTESWAPPED
+ ffswap8( (double *) i8null, 1); /* reverse order of bytes */
+#endif
+ }
+ }
+
+ /*---------------------------------------------------------------------*/
+ /* Now write the pixels to the FITS column. */
+ /*---------------------------------------------------------------------*/
+ remain = nelem; /* remaining number of values to write */
+ next = 0; /* next element in array to be written */
+ rownum = 0; /* row number, relative to firstrow */
+ ntodo = remain; /* number of elements to write at one time */
+
+ while (ntodo)
+ {
+ /* limit the number of pixels to process at one time to the number that
+ will fit in the buffer space or to the number of pixels that remain
+ in the current vector, which ever is smaller.
+ */
+ ntodo = minvalue(ntodo, (repeat - elemnum));
+ wrtptr = startpos + ((OFF_T)rownum * rowlen) + (elemnum * incre);
+
+ ffmbyt(fptr, wrtptr, IGNORE_EOF, status); /* move to write position */
+
+ switch (tcode)
+ {
+ case (TBYTE):
+
+ for (ii = 0; ii < ntodo; ii++)
+ ffpbyt(fptr, 1, &i1null, status);
+ break;
+
+ case (TSHORT):
+
+ for (ii = 0; ii < ntodo; ii++)
+ ffpbyt(fptr, 2, &i2null, status);
+ break;
+
+ case (TLONG):
+
+ for (ii = 0; ii < ntodo; ii++)
+ ffpbyt(fptr, 4, &i4null, status);
+ break;
+
+ case (TLONGLONG):
+
+ for (ii = 0; ii < ntodo; ii++)
+ ffpbyt(fptr, 8, i8null, status);
+ break;
+
+ case (TFLOAT):
+
+ for (ii = 0; ii < ntodo; ii++)
+ ffpbyt(fptr, 4, jbuff, status);
+ break;
+
+ case (TDOUBLE):
+
+ for (ii = 0; ii < ntodo; ii++)
+ ffpbyt(fptr, 8, jbuff, status);
+ break;
+
+ case (TLOGICAL):
+
+ for (ii = 0; ii < ntodo; ii++)
+ ffpbyt(fptr, 1, &lognul, status);
+ break;
+
+ case (TSTRING): /* an ASCII table column */
+ /* repeat always = 1, so ntodo is also guaranteed to = 1 */
+ ffpbyt(fptr, twidth, cstring, status);
+ break;
+
+ default: /* error trap */
+ sprintf(message,
+ "Cannot write null value to column %d which has format %s",
+ colnum,tform);
+ ffpmsg(message);
+ return(*status);
+
+ } /* End of switch block */
+
+ /*-------------------------*/
+ /* Check for fatal error */
+ /*-------------------------*/
+ if (*status > 0) /* test for error during previous write operation */
+ {
+ sprintf(message,
+ "Error writing %ld thru %ld of null values (ffpclu).",
+ next+1, next+ntodo);
+ ffpmsg(message);
+
+ if (cstring)
+ free(cstring);
+
+ return(*status);
+ }
+
+ /*--------------------------------------------*/
+ /* increment the counters for the next loop */
+ /*--------------------------------------------*/
+ remain -= ntodo;
+ if (remain)
+ {
+ next += ntodo;
+ elemnum += ntodo;
+ if (elemnum == repeat) /* completed a row; start on next row */
+ {
+ elemnum = 0;
+ rownum++;
+ }
+ }
+ ntodo = remain; /* this is the maximum number to do in next loop */
+
+ } /* End of main while Loop */
+
+ if (cstring)
+ free(cstring);
+
+ return(*status);
+}
+
+
diff --git a/pkg/tbtables/cfitsio/putcolui.c b/pkg/tbtables/cfitsio/putcolui.c
new file mode 100644
index 00000000..3406edf4
--- /dev/null
+++ b/pkg/tbtables/cfitsio/putcolui.c
@@ -0,0 +1,1022 @@
+/* This file, putcolui.c, contains routines that write data elements to */
+/* a FITS image or table, with unsigned short datatype. */
+
+/* The FITSIO software was written by William Pence at the High Energy */
+/* Astrophysic Science Archive Research Center (HEASARC) at the NASA */
+/* Goddard Space Flight Center. */
+
+#include <limits.h>
+#include <string.h>
+#include <stdlib.h>
+#include "fitsio2.h"
+
+/* declare variable for passing large firstelem values between routines */
+extern OFF_T large_first_elem_val;
+
+/*--------------------------------------------------------------------------*/
+int ffpprui(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write (1 = 1st group) */
+ long firstelem, /* I - first vector element to write (1 = 1st) */
+ long nelem, /* I - number of values to write */
+ unsigned short *array, /* I - array of values that are written */
+ int *status) /* IO - error status */
+/*
+ Write an array of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being written).
+*/
+{
+ long row;
+ unsigned short nullvalue;
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ /* use the OFF_T variable to pass the first element value */
+ if (firstelem != USE_LARGE_VALUE)
+ large_first_elem_val = firstelem;
+
+ fits_write_compressed_pixels(fptr, TUSHORT, large_first_elem_val, nelem,
+ 0, array, &nullvalue, status);
+ return(*status);
+ }
+
+ row=maxvalue(1,group);
+
+ ffpclui(fptr, 2, row, firstelem, nelem, array, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffppnui(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long firstelem, /* I - first vector element to write(1 = 1st) */
+ long nelem, /* I - number of values to write */
+ unsigned short *array, /* I - array of values that are written */
+ unsigned short nulval, /* I - undefined pixel value */
+ int *status) /* IO - error status */
+/*
+ Write an array of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of the
+ FITS array is not the same as the array being written). Any array values
+ that are equal to the value of nulval will be replaced with the null
+ pixel value that is appropriate for this column.
+*/
+{
+ long row;
+ unsigned short nullvalue;
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ /* use the OFF_T variable to pass the first element value */
+ if (firstelem != USE_LARGE_VALUE)
+ large_first_elem_val = firstelem;
+
+ nullvalue = nulval; /* set local variable */
+ fits_write_compressed_pixels(fptr, TUSHORT, large_first_elem_val, nelem,
+ 1, array, &nullvalue, status);
+ return(*status);
+ }
+
+ row=maxvalue(1,group);
+
+ ffpcnui(fptr, 2, row, firstelem, nelem, array, nulval, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffp2dui(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long ncols, /* I - number of pixels in each row of array */
+ long naxis1, /* I - FITS image NAXIS1 value */
+ long naxis2, /* I - FITS image NAXIS2 value */
+ unsigned short *array, /* I - array to be written */
+ int *status) /* IO - error status */
+/*
+ Write an entire 2-D array of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of the
+ FITS array is not the same as the array being written).
+*/
+{
+ /* call the 3D writing routine, with the 3rd dimension = 1 */
+
+ ffp3dui(fptr, group, ncols, naxis2, naxis1, naxis2, 1, array, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffp3dui(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long ncols, /* I - number of pixels in each row of array */
+ long nrows, /* I - number of rows in each plane of array */
+ long naxis1, /* I - FITS image NAXIS1 value */
+ long naxis2, /* I - FITS image NAXIS2 value */
+ long naxis3, /* I - FITS image NAXIS3 value */
+ unsigned short *array, /* I - array to be written */
+ int *status) /* IO - error status */
+/*
+ Write an entire 3-D cube of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of the
+ FITS array is not the same as the array being written).
+*/
+{
+ long tablerow, nfits, narray, ii, jj;
+ long fpixel[3]= {1,1,1}, lpixel[3];
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+ lpixel[0] = ncols;
+ lpixel[1] = nrows;
+ lpixel[2] = naxis3;
+
+ fits_write_compressed_img(fptr, TUSHORT, fpixel, lpixel,
+ 0, array, NULL, status);
+
+ return(*status);
+ }
+
+ tablerow=maxvalue(1,group);
+
+ if (ncols == naxis1 && nrows == naxis2) /* arrays have same size? */
+ {
+ /* all the image pixels are contiguous, so write all at once */
+ ffpclui(fptr, 2, tablerow, 1L, naxis1 * naxis2 * naxis3, array, status);
+ return(*status);
+ }
+
+ if (ncols < naxis1 || nrows < naxis2)
+ return(*status = BAD_DIMEN);
+
+ nfits = 1; /* next pixel in FITS image to write to */
+ narray = 0; /* next pixel in input array to be written */
+
+ /* loop over naxis3 planes in the data cube */
+ for (jj = 0; jj < naxis3; jj++)
+ {
+ /* loop over the naxis2 rows in the FITS image, */
+ /* writing naxis1 pixels to each row */
+
+ for (ii = 0; ii < naxis2; ii++)
+ {
+ if (ffpclui(fptr, 2, tablerow, nfits, naxis1,&array[narray],status) > 0)
+ return(*status);
+
+ nfits += naxis1;
+ narray += ncols;
+ }
+ narray += (nrows - naxis2) * ncols;
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpssui(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long naxis, /* I - number of data axes in array */
+ long *naxes, /* I - size of each FITS axis */
+ long *fpixel, /* I - 1st pixel in each axis to write (1=1st) */
+ long *lpixel, /* I - last pixel in each axis to write */
+ unsigned short *array, /* I - array to be written */
+ int *status) /* IO - error status */
+/*
+ Write a subsection of pixels to the primary array or image.
+ A subsection is defined to be any contiguous rectangular
+ array of pixels within the n-dimensional FITS data file.
+ Data conversion and scaling will be performed if necessary
+ (e.g, if the datatype of the FITS array is not the same as
+ the array being written).
+*/
+{
+ long tablerow;
+ long fpix[7], irange[7], dimen[7], astart, pstart;
+ long off2, off3, off4, off5, off6, off7;
+ long st10, st20, st30, st40, st50, st60, st70;
+ long st1, st2, st3, st4, st5, st6, st7;
+ long ii, i1, i2, i3, i4, i5, i6, i7;
+
+ if (*status > 0)
+ return(*status);
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ fits_write_compressed_img(fptr, TUSHORT, fpixel, lpixel,
+ 0, array, NULL, status);
+
+ return(*status);
+ }
+
+ if (naxis < 1 || naxis > 7)
+ return(*status = BAD_DIMEN);
+
+ tablerow=maxvalue(1,group);
+
+ /* calculate the size and number of loops to perform in each dimension */
+ for (ii = 0; ii < 7; ii++)
+ {
+ fpix[ii]=1;
+ irange[ii]=1;
+ dimen[ii]=1;
+ }
+
+ for (ii = 0; ii < naxis; ii++)
+ {
+ fpix[ii]=fpixel[ii];
+ irange[ii]=lpixel[ii]-fpixel[ii]+1;
+ dimen[ii]=naxes[ii];
+ }
+
+ i1=irange[0];
+
+ /* compute the pixel offset between each dimension */
+ off2 = dimen[0];
+ off3 = off2 * dimen[1];
+ off4 = off3 * dimen[2];
+ off5 = off4 * dimen[3];
+ off6 = off5 * dimen[4];
+ off7 = off6 * dimen[5];
+
+ st10 = fpix[0];
+ st20 = (fpix[1] - 1) * off2;
+ st30 = (fpix[2] - 1) * off3;
+ st40 = (fpix[3] - 1) * off4;
+ st50 = (fpix[4] - 1) * off5;
+ st60 = (fpix[5] - 1) * off6;
+ st70 = (fpix[6] - 1) * off7;
+
+ /* store the initial offset in each dimension */
+ st1 = st10;
+ st2 = st20;
+ st3 = st30;
+ st4 = st40;
+ st5 = st50;
+ st6 = st60;
+ st7 = st70;
+
+ astart = 0;
+
+ for (i7 = 0; i7 < irange[6]; i7++)
+ {
+ for (i6 = 0; i6 < irange[5]; i6++)
+ {
+ for (i5 = 0; i5 < irange[4]; i5++)
+ {
+ for (i4 = 0; i4 < irange[3]; i4++)
+ {
+ for (i3 = 0; i3 < irange[2]; i3++)
+ {
+ pstart = st1 + st2 + st3 + st4 + st5 + st6 + st7;
+ for (i2 = 0; i2 < irange[1]; i2++)
+ {
+ if (ffpclui(fptr, 2, tablerow, pstart, i1, &array[astart],
+ status) > 0)
+ return(*status);
+
+ astart += i1;
+ pstart += off2;
+ }
+ st2 = st20;
+ st3 = st3+off3;
+ }
+ st3 = st30;
+ st4 = st4+off4;
+ }
+ st4 = st40;
+ st5 = st5+off5;
+ }
+ st5 = st50;
+ st6 = st6+off6;
+ }
+ st6 = st60;
+ st7 = st7+off7;
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpgpui( fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long firstelem, /* I - first vector element to write(1 = 1st) */
+ long nelem, /* I - number of values to write */
+ unsigned short *array, /* I - array of values that are written */
+ int *status) /* IO - error status */
+/*
+ Write an array of group parameters to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being written).
+*/
+{
+ long row;
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ row=maxvalue(1,group);
+
+ ffpclui(fptr, 1L, row, firstelem, nelem, array, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpclui( fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to write (1 = 1st col) */
+ long firstrow, /* I - first row to write (1 = 1st row) */
+ long firstelem, /* I - first vector element to write (1 = 1st) */
+ long nelem, /* I - number of values to write */
+ unsigned short *array, /* I - array of values to write */
+ int *status) /* IO - error status */
+/*
+ Write an array of values to a column in the current FITS HDU.
+ The column number may refer to a real column in an ASCII or binary table,
+ or it may refer to a virtual column in a 1 or more grouped FITS primary
+ array. FITSIO treats a primary array as a binary table with
+ 2 vector columns: the first column contains the group parameters (often
+ with length = 0) and the second column contains the array of image pixels.
+ Each row of the table represents a group in the case of multigroup FITS
+ images.
+
+ The input array of values will be converted to the datatype of the column
+ and will be inverse-scaled by the FITS TSCALn and TZEROn values if necessary.
+*/
+{
+ int tcode, maxelem, hdutype;
+ long twidth, incre, rownum, remain, next, ntodo;
+ long tnull;
+ OFF_T repeat, startpos, elemnum, large_elem, wrtptr, rowlen;
+ double scale, zero;
+ char tform[20], cform[20];
+ char message[FLEN_ERRMSG];
+
+ char snull[20]; /* the FITS null value */
+
+ double cbuff[DBUFFSIZE / sizeof(double)]; /* align cbuff on word boundary */
+ void *buffer;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ buffer = cbuff;
+
+ if (firstelem == USE_LARGE_VALUE)
+ large_elem = large_first_elem_val;
+ else
+ large_elem = firstelem;
+
+ /*---------------------------------------------------*/
+ /* Check input and get parameters about the column: */
+ /*---------------------------------------------------*/
+ if (ffgcpr( fptr, colnum, firstrow, large_elem, nelem, 1, &scale, &zero,
+ tform, &twidth, &tcode, &maxelem, &startpos, &elemnum, &incre,
+ &repeat, &rowlen, &hdutype, &tnull, snull, status) > 0)
+ return(*status);
+
+ if (tcode == TSTRING)
+ ffcfmt(tform, cform); /* derive C format for writing strings */
+
+ /*---------------------------------------------------------------------*/
+ /* Now write the pixels to the FITS column. */
+ /* First call the ffXXfYY routine to (1) convert the datatype */
+ /* if necessary, and (2) scale the values by the FITS TSCALn and */
+ /* TZEROn linear scaling parameters into a temporary buffer. */
+ /*---------------------------------------------------------------------*/
+ remain = nelem; /* remaining number of values to write */
+ next = 0; /* next element in array to be written */
+ rownum = 0; /* row number, relative to firstrow */
+
+ while (remain)
+ {
+ /* limit the number of pixels to process a one time to the number that
+ will fit in the buffer space or to the number of pixels that remain
+ in the current vector, which ever is smaller.
+ */
+ ntodo = minvalue(remain, maxelem);
+ ntodo = minvalue(ntodo, (repeat - elemnum));
+
+ wrtptr = startpos + ((OFF_T)rownum * rowlen) + (elemnum * incre);
+
+ ffmbyt(fptr, wrtptr, IGNORE_EOF, status); /* move to write position */
+
+ switch (tcode)
+ {
+ case (TSHORT):
+
+ ffu2fi2(&array[next], ntodo, scale, zero,
+ (short *) buffer, status);
+ ffpi2b(fptr, ntodo, incre, (short *) buffer, status);
+ break;
+
+ case (TLONGLONG):
+
+ ffu2fi8(&array[next], ntodo, scale, zero,
+ (LONGLONG *) buffer, status);
+ ffpi8b(fptr, ntodo, incre, (long *) buffer, status);
+ break;
+
+ case (TBYTE):
+
+ ffu2fi1(&array[next], ntodo, scale, zero,
+ (unsigned char *) buffer, status);
+ ffpi1b(fptr, ntodo, incre, (unsigned char *) buffer, status);
+ break;
+
+ case (TLONG):
+
+ ffu2fi4(&array[next], ntodo, scale, zero,
+ (INT32BIT *) buffer, status);
+ ffpi4b(fptr, ntodo, incre, (INT32BIT *) buffer, status);
+ break;
+
+ case (TFLOAT):
+
+ ffu2fr4(&array[next], ntodo, scale, zero,
+ (float *) buffer, status);
+ ffpr4b(fptr, ntodo, incre, (float *) buffer, status);
+ break;
+
+ case (TDOUBLE):
+ ffu2fr8(&array[next], ntodo, scale, zero,
+ (double *) buffer, status);
+ ffpr8b(fptr, ntodo, incre, (double *) buffer, status);
+ break;
+
+ case (TSTRING): /* numerical column in an ASCII table */
+
+ if (cform[1] != 's') /* "%s" format is a string */
+ {
+ ffu2fstr(&array[next], ntodo, scale, zero, cform,
+ twidth, (char *) buffer, status);
+
+
+ if (incre == twidth) /* contiguous bytes */
+ ffpbyt(fptr, ntodo * twidth, buffer, status);
+ else
+ ffpbytoff(fptr, twidth, ntodo, incre - twidth, buffer,
+ status);
+
+ break;
+ }
+ /* can't write to string column, so fall thru to default: */
+
+ default: /* error trap */
+ sprintf(message,
+ "Cannot write numbers to column %d which has format %s",
+ colnum,tform);
+ ffpmsg(message);
+ if (hdutype == ASCII_TBL)
+ return(*status = BAD_ATABLE_FORMAT);
+ else
+ return(*status = BAD_BTABLE_FORMAT);
+
+ } /* End of switch block */
+
+ /*-------------------------*/
+ /* Check for fatal error */
+ /*-------------------------*/
+ if (*status > 0) /* test for error during previous write operation */
+ {
+ sprintf(message,
+ "Error writing elements %ld thru %ld of input data array (ffpclui).",
+ next+1, next+ntodo);
+ ffpmsg(message);
+ return(*status);
+ }
+
+ /*--------------------------------------------*/
+ /* increment the counters for the next loop */
+ /*--------------------------------------------*/
+ remain -= ntodo;
+ if (remain)
+ {
+ next += ntodo;
+ elemnum += ntodo;
+ if (elemnum == repeat) /* completed a row; start on next row */
+ {
+ elemnum = 0;
+ rownum++;
+ }
+ }
+ } /* End of main while Loop */
+
+
+ /*--------------------------------*/
+ /* check for numerical overflow */
+ /*--------------------------------*/
+ if (*status == OVERFLOW_ERR)
+ {
+ ffpmsg(
+ "Numerical overflow during type conversion while writing FITS data.");
+ *status = NUM_OVERFLOW;
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpcnui(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to write (1 = 1st col) */
+ long firstrow, /* I - first row to write (1 = 1st row) */
+ long firstelem, /* I - first vector element to write (1 = 1st) */
+ long nelem, /* I - number of values to write */
+ unsigned short *array, /* I - array of values to write */
+ unsigned short nulvalue, /* I - value used to flag undefined pixels */
+ int *status) /* IO - error status */
+/*
+ Write an array of elements to the specified column of a table. Any input
+ pixels equal to the value of nulvalue will be replaced by the appropriate
+ null value in the output FITS file.
+
+ The input array of values will be converted to the datatype of the column
+ and will be inverse-scaled by the FITS TSCALn and TZEROn values if necessary
+*/
+{
+ tcolumn *colptr;
+ long ngood = 0, nbad = 0, ii, fstrow;
+ OFF_T large_elem, repeat, first, fstelm;
+
+ if (*status > 0)
+ return(*status);
+
+ /* reset position to the correct HDU if necessary */
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ {
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+ }
+ else if ((fptr->Fptr)->datastart == DATA_UNDEFINED)
+ {
+ if ( ffrdef(fptr, status) > 0) /* rescan header */
+ return(*status);
+ }
+
+ colptr = (fptr->Fptr)->tableptr; /* point to first column */
+ colptr += (colnum - 1); /* offset to correct column structure */
+
+ repeat = colptr->trepeat; /* repeat count for this column */
+
+ if (firstelem == USE_LARGE_VALUE)
+ large_elem = large_first_elem_val;
+ else
+ large_elem = firstelem;
+
+ /* hereafter, pass first element parameter via global variable */
+ firstelem = USE_LARGE_VALUE;
+
+ /* absolute element number in the column */
+ first = (firstrow - 1) * repeat + large_elem;
+
+ for (ii = 0; ii < nelem; ii++)
+ {
+ if (array[ii] != nulvalue) /* is this a good pixel? */
+ {
+ if (nbad) /* write previous string of bad pixels */
+ {
+ fstelm = ii - nbad + first; /* absolute element number */
+ fstrow = (fstelm - 1) / repeat + 1; /* starting row number */
+ fstelm = fstelm - (fstrow - 1) * repeat; /* relative number */
+ large_first_elem_val = fstelm;
+
+ if (ffpclu(fptr, colnum, fstrow, firstelem, nbad, status) > 0)
+ return(*status);
+
+ nbad=0;
+ }
+
+ ngood = ngood +1; /* the consecutive number of good pixels */
+ }
+ else
+ {
+ if (ngood) /* write previous string of good pixels */
+ {
+ fstelm = ii - ngood + first; /* absolute element number */
+ fstrow = (fstelm - 1) / repeat + 1; /* starting row number */
+ fstelm = fstelm - (fstrow - 1) * repeat; /* relative number */
+ large_first_elem_val = fstelm;
+
+ if (ffpclui(fptr, colnum, fstrow, firstelem,ngood, &array[ii-ngood],
+ status) > 0)
+ return(*status);
+
+ ngood=0;
+ }
+
+ nbad = nbad +1; /* the consecutive number of bad pixels */
+ }
+ }
+
+ /* finished loop; now just write the last set of pixels */
+
+ if (ngood) /* write last string of good pixels */
+ {
+ fstelm = ii - ngood + first; /* absolute element number */
+ fstrow = (fstelm - 1) / repeat + 1; /* starting row number */
+ fstelm = fstelm - (fstrow - 1) * repeat; /* relative number */
+ large_first_elem_val = fstelm;
+
+ ffpclui(fptr, colnum, fstrow, firstelem, ngood, &array[ii-ngood], status);
+ }
+ else if (nbad) /* write last string of bad pixels */
+ {
+ fstelm = ii - nbad + first; /* absolute element number */
+ fstrow = (fstelm - 1) / repeat + 1; /* starting row number */
+ fstelm = fstelm - (fstrow - 1) * repeat; /* relative number */
+ large_first_elem_val = fstelm;
+
+ ffpclu(fptr, colnum, fstrow, firstelem, nbad, status);
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffu2fi1(unsigned short *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ unsigned char *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] > UCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UCHAR_MAX;
+ }
+ else
+ output[ii] = (unsigned char) input[ii];
+ }
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = ((double) input[ii] - zero) / scale;
+
+ if (dvalue < DUCHAR_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DUCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UCHAR_MAX;
+ }
+ else
+ output[ii] = (unsigned char) (dvalue + .5);
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffu2fi2(unsigned short *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ short *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (scale == 1. && zero == 32768.)
+ {
+ /* Instead of subtracting 32768, it is more efficient */
+ /* to just flip the sign bit with the XOR operator */
+
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = ( *(short *) &input[ii] ) ^ 0x8000;
+ }
+ else if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] > SHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MAX;
+ }
+ else
+ output[ii] = input[ii];
+ }
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = ((double) input[ii] - zero) / scale;
+
+ if (dvalue < DSHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MIN;
+ }
+ else if (dvalue > DSHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MAX;
+ }
+ else
+ {
+ if (dvalue >= 0)
+ output[ii] = (short) (dvalue + .5);
+ else
+ output[ii] = (short) (dvalue - .5);
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffu2fi4(unsigned short *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ INT32BIT *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = (INT32BIT) input[ii]; /* copy input to output */
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = ((double) input[ii] - zero) / scale;
+
+ if (dvalue < DINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT32_MIN;
+ }
+ else if (dvalue > DINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT32_MAX;
+ }
+ else
+ {
+ if (dvalue >= 0)
+ output[ii] = (INT32BIT) (dvalue + .5);
+ else
+ output[ii] = (INT32BIT) (dvalue - .5);
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffu2fi8(unsigned short *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ LONGLONG *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required
+*/
+{
+#if (LONGSIZE == 32) && (! defined HAVE_LONGLONG)
+
+/* don't have a native 8-byte integer, so have to construct the */
+/* 2 equivalent 4-byte integers have the same bit pattern */
+
+ unsigned long *uoutput;
+ long ii, jj, kk, temp;
+ double dvalue;
+
+ uoutput = (unsigned long *) output;
+
+#if BYTESWAPPED /* jj points to the most significant part of the 8-byte int */
+ jj = 1;
+ kk = 0;
+#else
+ jj = 0;
+ kk = 1;
+#endif
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++, jj += 2, kk += 2)
+ {
+ output[jj] = 0;
+ output[kk] = input[ii];
+ }
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++, jj += 2, kk += 2)
+ {
+ dvalue = (input[ii] - zero) / scale;
+
+ if (dvalue < DLONGLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[jj] = LONG_MIN;
+ output[kk] = 0;
+ }
+ else if (dvalue > DLONGLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[jj] = LONG_MAX;
+ output[kk] = -1;
+ }
+ else
+ {
+ if (dvalue < 0)
+ {
+ temp = (dvalue + 1.) / 4294967296. - 1.;
+ output[jj] = temp;
+ uoutput[kk] = 4294967296. +
+ (dvalue - (double) (temp + 1) * 4294967296.);
+ }
+ else
+ {
+ temp = dvalue / 4294967296.;
+ output[jj] = temp;
+ uoutput[kk] = dvalue - (double) temp * 4294967296.;
+ }
+ }
+ }
+ }
+
+#else
+
+/* this is the much simpler case where the native 8-byte integer exists */
+
+ long ii;
+ double dvalue;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = input[ii];
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = (input[ii] - zero) / scale;
+
+ if (dvalue < DLONGLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONGLONG_MIN;
+ }
+ else if (dvalue > DLONGLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONGLONG_MAX;
+ }
+ else
+ {
+ if (dvalue >= 0)
+ output[ii] = (LONGLONG) (dvalue + .5);
+ else
+ output[ii] = (LONGLONG) (dvalue - .5);
+ }
+ }
+ }
+
+#endif
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffu2fr4(unsigned short *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ float *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required.
+*/
+{
+ long ii;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = (float) input[ii];
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = ((double) input[ii] - zero) / scale;
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffu2fr8(unsigned short *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ double *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required.
+*/
+{
+ long ii;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = (double) input[ii];
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = ((double) input[ii] - zero) / scale;
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffu2fstr(unsigned short *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ char *cform, /* I - format for output string values */
+ long twidth, /* I - width of each field, in chars */
+ char *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do scaling if required.
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ sprintf(output, cform, (double) input[ii]);
+ output += twidth;
+
+ if (*output) /* if this char != \0, then overflow occurred */
+ *status = OVERFLOW_ERR;
+ }
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = ((double) input[ii] - zero) / scale;
+ sprintf(output, cform, dvalue);
+ output += twidth;
+
+ if (*output) /* if this char != \0, then overflow occurred */
+ *status = OVERFLOW_ERR;
+ }
+ }
+ return(*status);
+}
diff --git a/pkg/tbtables/cfitsio/putcoluj.c b/pkg/tbtables/cfitsio/putcoluj.c
new file mode 100644
index 00000000..af4c7fd4
--- /dev/null
+++ b/pkg/tbtables/cfitsio/putcoluj.c
@@ -0,0 +1,1029 @@
+/* This file, putcoluj.c, contains routines that write data elements to */
+/* a FITS image or table, with unsigned long datatype. */
+
+/* The FITSIO software was written by William Pence at the High Energy */
+/* Astrophysic Science Archive Research Center (HEASARC) at the NASA */
+/* Goddard Space Flight Center. */
+
+#include <limits.h>
+#include <string.h>
+#include <stdlib.h>
+#include "fitsio2.h"
+
+/* declare variable for passing large firstelem values between routines */
+extern OFF_T large_first_elem_val;
+
+/*--------------------------------------------------------------------------*/
+int ffppruj( fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long firstelem, /* I - first vector element to write(1 = 1st) */
+ long nelem, /* I - number of values to write */
+ unsigned long *array, /* I - array of values that are written */
+ int *status) /* IO - error status */
+/*
+ Write an array of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being written).
+*/
+{
+ long row;
+ unsigned long nullvalue;
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ /* use the OFF_T variable to pass the first element value */
+ if (firstelem != USE_LARGE_VALUE)
+ large_first_elem_val = firstelem;
+
+ fits_write_compressed_pixels(fptr, TULONG, large_first_elem_val, nelem,
+ 0, array, &nullvalue, status);
+ return(*status);
+ }
+
+ row=maxvalue(1,group);
+
+ ffpcluj(fptr, 2, row, firstelem, nelem, array, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffppnuj( fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long firstelem, /* I - first vector element to write(1 = 1st) */
+ long nelem, /* I - number of values to write */
+ unsigned long *array, /* I - array of values that are written */
+ unsigned long nulval, /* I - undefined pixel value */
+ int *status) /* IO - error status */
+/*
+ Write an array of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of the
+ FITS array is not the same as the array being written). Any array values
+ that are equal to the value of nulval will be replaced with the null
+ pixel value that is appropriate for this column.
+*/
+{
+ long row;
+ unsigned long nullvalue;
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ /* use the OFF_T variable to pass the first element value */
+ if (firstelem != USE_LARGE_VALUE)
+ large_first_elem_val = firstelem;
+
+ nullvalue = nulval; /* set local variable */
+ fits_write_compressed_pixels(fptr, TULONG, large_first_elem_val, nelem,
+ 1, array, &nullvalue, status);
+ return(*status);
+ }
+
+ row=maxvalue(1,group);
+
+ ffpcnuj(fptr, 2, row, firstelem, nelem, array, nulval, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffp2duj(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long ncols, /* I - number of pixels in each row of array */
+ long naxis1, /* I - FITS image NAXIS1 value */
+ long naxis2, /* I - FITS image NAXIS2 value */
+ unsigned long *array, /* I - array to be written */
+ int *status) /* IO - error status */
+/*
+ Write an entire 2-D array of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of the
+ FITS array is not the same as the array being written).
+*/
+{
+ /* call the 3D writing routine, with the 3rd dimension = 1 */
+
+ ffp3duj(fptr, group, ncols, naxis2, naxis1, naxis2, 1, array, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffp3duj(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long ncols, /* I - number of pixels in each row of array */
+ long nrows, /* I - number of rows in each plane of array */
+ long naxis1, /* I - FITS image NAXIS1 value */
+ long naxis2, /* I - FITS image NAXIS2 value */
+ long naxis3, /* I - FITS image NAXIS3 value */
+ unsigned long *array, /* I - array to be written */
+ int *status) /* IO - error status */
+/*
+ Write an entire 3-D cube of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of the
+ FITS array is not the same as the array being written).
+*/
+{
+ long tablerow, nfits, narray, ii, jj;
+ long fpixel[3]= {1,1,1}, lpixel[3];
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+ lpixel[0] = ncols;
+ lpixel[1] = nrows;
+ lpixel[2] = naxis3;
+
+ fits_write_compressed_img(fptr, TULONG, fpixel, lpixel,
+ 0, array, NULL, status);
+
+ return(*status);
+ }
+
+ tablerow=maxvalue(1,group);
+
+ if (ncols == naxis1 && nrows == naxis2) /* arrays have same size? */
+ {
+ /* all the image pixels are contiguous, so write all at once */
+ ffpcluj(fptr, 2, tablerow, 1L, naxis1 * naxis2 * naxis3, array, status);
+ return(*status);
+ }
+
+ if (ncols < naxis1 || nrows < naxis2)
+ return(*status = BAD_DIMEN);
+
+ nfits = 1; /* next pixel in FITS image to write to */
+ narray = 0; /* next pixel in input array to be written */
+
+ /* loop over naxis3 planes in the data cube */
+ for (jj = 0; jj < naxis3; jj++)
+ {
+ /* loop over the naxis2 rows in the FITS image, */
+ /* writing naxis1 pixels to each row */
+
+ for (ii = 0; ii < naxis2; ii++)
+ {
+ if (ffpcluj(fptr, 2, tablerow, nfits, naxis1,&array[narray],status) > 0)
+ return(*status);
+
+ nfits += naxis1;
+ narray += ncols;
+ }
+ narray += (nrows - naxis2) * ncols;
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpssuj(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long naxis, /* I - number of data axes in array */
+ long *naxes, /* I - size of each FITS axis */
+ long *fpixel, /* I - 1st pixel in each axis to write (1=1st) */
+ long *lpixel, /* I - last pixel in each axis to write */
+ unsigned long *array, /* I - array to be written */
+ int *status) /* IO - error status */
+/*
+ Write a subsection of pixels to the primary array or image.
+ A subsection is defined to be any contiguous rectangular
+ array of pixels within the n-dimensional FITS data file.
+ Data conversion and scaling will be performed if necessary
+ (e.g, if the datatype of the FITS array is not the same as
+ the array being written).
+*/
+{
+ long tablerow;
+ long fpix[7], irange[7], dimen[7], astart, pstart;
+ long off2, off3, off4, off5, off6, off7;
+ long st10, st20, st30, st40, st50, st60, st70;
+ long st1, st2, st3, st4, st5, st6, st7;
+ long ii, i1, i2, i3, i4, i5, i6, i7;
+
+ if (*status > 0)
+ return(*status);
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ fits_write_compressed_img(fptr, TULONG, fpixel, lpixel,
+ 0, array, NULL, status);
+
+ return(*status);
+ }
+
+ if (naxis < 1 || naxis > 7)
+ return(*status = BAD_DIMEN);
+
+ tablerow=maxvalue(1,group);
+
+ /* calculate the size and number of loops to perform in each dimension */
+ for (ii = 0; ii < 7; ii++)
+ {
+ fpix[ii]=1;
+ irange[ii]=1;
+ dimen[ii]=1;
+ }
+
+ for (ii = 0; ii < naxis; ii++)
+ {
+ fpix[ii]=fpixel[ii];
+ irange[ii]=lpixel[ii]-fpixel[ii]+1;
+ dimen[ii]=naxes[ii];
+ }
+
+ i1=irange[0];
+
+ /* compute the pixel offset between each dimension */
+ off2 = dimen[0];
+ off3 = off2 * dimen[1];
+ off4 = off3 * dimen[2];
+ off5 = off4 * dimen[3];
+ off6 = off5 * dimen[4];
+ off7 = off6 * dimen[5];
+
+ st10 = fpix[0];
+ st20 = (fpix[1] - 1) * off2;
+ st30 = (fpix[2] - 1) * off3;
+ st40 = (fpix[3] - 1) * off4;
+ st50 = (fpix[4] - 1) * off5;
+ st60 = (fpix[5] - 1) * off6;
+ st70 = (fpix[6] - 1) * off7;
+
+ /* store the initial offset in each dimension */
+ st1 = st10;
+ st2 = st20;
+ st3 = st30;
+ st4 = st40;
+ st5 = st50;
+ st6 = st60;
+ st7 = st70;
+
+ astart = 0;
+
+ for (i7 = 0; i7 < irange[6]; i7++)
+ {
+ for (i6 = 0; i6 < irange[5]; i6++)
+ {
+ for (i5 = 0; i5 < irange[4]; i5++)
+ {
+ for (i4 = 0; i4 < irange[3]; i4++)
+ {
+ for (i3 = 0; i3 < irange[2]; i3++)
+ {
+ pstart = st1 + st2 + st3 + st4 + st5 + st6 + st7;
+ for (i2 = 0; i2 < irange[1]; i2++)
+ {
+ if (ffpcluj(fptr, 2, tablerow, pstart, i1, &array[astart],
+ status) > 0)
+ return(*status);
+
+ astart += i1;
+ pstart += off2;
+ }
+ st2 = st20;
+ st3 = st3+off3;
+ }
+ st3 = st30;
+ st4 = st4+off4;
+ }
+ st4 = st40;
+ st5 = st5+off5;
+ }
+ st5 = st50;
+ st6 = st6+off6;
+ }
+ st6 = st60;
+ st7 = st7+off7;
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpgpuj( fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long firstelem, /* I - first vector element to write(1 = 1st) */
+ long nelem, /* I - number of values to write */
+ unsigned long *array, /* I - array of values that are written */
+ int *status) /* IO - error status */
+/*
+ Write an array of group parameters to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being written).
+*/
+{
+ long row;
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ row=maxvalue(1,group);
+
+ ffpcluj(fptr, 1L, row, firstelem, nelem, array, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpcluj( fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to write (1 = 1st col) */
+ long firstrow, /* I - first row to write (1 = 1st row) */
+ long firstelem, /* I - first vector element to write (1 = 1st) */
+ long nelem, /* I - number of values to write */
+ unsigned long *array, /* I - array of values to write */
+ int *status) /* IO - error status */
+/*
+ Write an array of values to a column in the current FITS HDU.
+ The column number may refer to a real column in an ASCII or binary table,
+ or it may refer to a virtual column in a 1 or more grouped FITS primary
+ array. FITSIO treats a primary array as a binary table
+ with 2 vector columns: the first column contains the group parameters (often
+ with length = 0) and the second column contains the array of image pixels.
+ Each row of the table represents a group in the case of multigroup FITS
+ images.
+
+ The input array of values will be converted to the datatype of the column
+ and will be inverse-scaled by the FITS TSCALn and TZEROn values if necessary.
+*/
+{
+ int tcode, maxelem, hdutype;
+ long twidth, incre, rownum, remain, next, ntodo;
+ long tnull;
+ OFF_T repeat, startpos, elemnum, large_elem, wrtptr, rowlen;
+ double scale, zero;
+ char tform[20], cform[20];
+ char message[FLEN_ERRMSG];
+
+ char snull[20]; /* the FITS null value */
+
+ double cbuff[DBUFFSIZE / sizeof(double)]; /* align cbuff on word boundary */
+ void *buffer;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ buffer = cbuff;
+
+ if (firstelem == USE_LARGE_VALUE)
+ large_elem = large_first_elem_val;
+ else
+ large_elem = firstelem;
+
+ /*---------------------------------------------------*/
+ /* Check input and get parameters about the column: */
+ /*---------------------------------------------------*/
+ if (ffgcpr( fptr, colnum, firstrow, large_elem, nelem, 1, &scale, &zero,
+ tform, &twidth, &tcode, &maxelem, &startpos, &elemnum, &incre,
+ &repeat, &rowlen, &hdutype, &tnull, snull, status) > 0)
+ return(*status);
+
+ if (tcode == TSTRING)
+ ffcfmt(tform, cform); /* derive C format for writing strings */
+
+ /*---------------------------------------------------------------------*/
+ /* Now write the pixels to the FITS column. */
+ /* First call the ffXXfYY routine to (1) convert the datatype */
+ /* if necessary, and (2) scale the values by the FITS TSCALn and */
+ /* TZEROn linear scaling parameters into a temporary buffer. */
+ /*---------------------------------------------------------------------*/
+ remain = nelem; /* remaining number of values to write */
+ next = 0; /* next element in array to be written */
+ rownum = 0; /* row number, relative to firstrow */
+
+ while (remain)
+ {
+ /* limit the number of pixels to process a one time to the number that
+ will fit in the buffer space or to the number of pixels that remain
+ in the current vector, which ever is smaller.
+ */
+ ntodo = minvalue(remain, maxelem);
+ ntodo = minvalue(ntodo, (repeat - elemnum));
+
+ wrtptr = startpos + ((OFF_T)rownum * rowlen) + (elemnum * incre);
+
+ ffmbyt(fptr, wrtptr, IGNORE_EOF, status); /* move to write position */
+
+ switch (tcode)
+ {
+ case (TLONG):
+
+ ffu4fi4(&array[next], ntodo, scale, zero,
+ (INT32BIT *) buffer, status);
+ ffpi4b(fptr, ntodo, incre, (INT32BIT *) buffer, status);
+ break;
+
+ case (TLONGLONG):
+
+ ffu4fi8(&array[next], ntodo, scale, zero,
+ (LONGLONG *) buffer, status);
+ ffpi8b(fptr, ntodo, incre, (long *) buffer, status);
+ break;
+
+ case (TBYTE):
+
+ ffu4fi1(&array[next], ntodo, scale, zero,
+ (unsigned char *) buffer, status);
+ ffpi1b(fptr, ntodo, incre, (unsigned char *) buffer, status);
+ break;
+
+ case (TSHORT):
+
+ ffu4fi2(&array[next], ntodo, scale, zero,
+ (short *) buffer, status);
+ ffpi2b(fptr, ntodo, incre, (short *) buffer, status);
+ break;
+
+ case (TFLOAT):
+
+ ffu4fr4(&array[next], ntodo, scale, zero,
+ (float *) buffer, status);
+ ffpr4b(fptr, ntodo, incre, (float *) buffer, status);
+ break;
+
+ case (TDOUBLE):
+ ffu4fr8(&array[next], ntodo, scale, zero,
+ (double *) buffer, status);
+ ffpr8b(fptr, ntodo, incre, (double *) buffer, status);
+ break;
+
+ case (TSTRING): /* numerical column in an ASCII table */
+
+ if (cform[1] != 's') /* "%s" format is a string */
+ {
+ ffu4fstr(&array[next], ntodo, scale, zero, cform,
+ twidth, (char *) buffer, status);
+
+ if (incre == twidth) /* contiguous bytes */
+ ffpbyt(fptr, ntodo * twidth, buffer, status);
+ else
+ ffpbytoff(fptr, twidth, ntodo, incre - twidth, buffer,
+ status);
+
+ break;
+ }
+ /* can't write to string column, so fall thru to default: */
+
+ default: /* error trap */
+ sprintf(message,
+ "Cannot write numbers to column %d which has format %s",
+ colnum,tform);
+ ffpmsg(message);
+ if (hdutype == ASCII_TBL)
+ return(*status = BAD_ATABLE_FORMAT);
+ else
+ return(*status = BAD_BTABLE_FORMAT);
+
+ } /* End of switch block */
+
+ /*-------------------------*/
+ /* Check for fatal error */
+ /*-------------------------*/
+ if (*status > 0) /* test for error during previous write operation */
+ {
+ sprintf(message,
+ "Error writing elements %ld thru %ld of input data array (ffpcluj).",
+ next+1, next+ntodo);
+ ffpmsg(message);
+ return(*status);
+ }
+
+ /*--------------------------------------------*/
+ /* increment the counters for the next loop */
+ /*--------------------------------------------*/
+ remain -= ntodo;
+ if (remain)
+ {
+ next += ntodo;
+ elemnum += ntodo;
+ if (elemnum == repeat) /* completed a row; start on next row */
+ {
+ elemnum = 0;
+ rownum++;
+ }
+ }
+ } /* End of main while Loop */
+
+
+ /*--------------------------------*/
+ /* check for numerical overflow */
+ /*--------------------------------*/
+ if (*status == OVERFLOW_ERR)
+ {
+ ffpmsg(
+ "Numerical overflow during type conversion while writing FITS data.");
+ *status = NUM_OVERFLOW;
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpcnuj( fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to write (1 = 1st col) */
+ long firstrow, /* I - first row to write (1 = 1st row) */
+ long firstelem, /* I - first vector element to write (1 = 1st) */
+ long nelem, /* I - number of values to write */
+ unsigned long *array, /* I - array of values to write */
+ unsigned long nulvalue, /* I - value used to flag undefined pixels */
+ int *status) /* IO - error status */
+/*
+ Write an array of elements to the specified column of a table. Any input
+ pixels equal to the value of nulvalue will be replaced by the appropriate
+ null value in the output FITS file.
+
+ The input array of values will be converted to the datatype of the column
+ and will be inverse-scaled by the FITS TSCALn and TZEROn values if necessary
+*/
+{
+ tcolumn *colptr;
+ long ngood = 0, nbad = 0, ii, fstrow;
+ OFF_T large_elem, repeat, first, fstelm;
+
+ if (*status > 0)
+ return(*status);
+
+ /* reset position to the correct HDU if necessary */
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ {
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+ }
+ else if ((fptr->Fptr)->datastart == DATA_UNDEFINED)
+ {
+ if ( ffrdef(fptr, status) > 0) /* rescan header */
+ return(*status);
+ }
+
+ colptr = (fptr->Fptr)->tableptr; /* point to first column */
+ colptr += (colnum - 1); /* offset to correct column structure */
+
+ repeat = colptr->trepeat; /* repeat count for this column */
+
+ if (firstelem == USE_LARGE_VALUE)
+ large_elem = large_first_elem_val;
+ else
+ large_elem = firstelem;
+
+ /* hereafter, pass first element parameter via global variable */
+ firstelem = USE_LARGE_VALUE;
+
+ /* absolute element number in the column */
+ first = (firstrow - 1) * repeat + large_elem;
+
+ for (ii = 0; ii < nelem; ii++)
+ {
+ if (array[ii] != nulvalue) /* is this a good pixel? */
+ {
+ if (nbad) /* write previous string of bad pixels */
+ {
+ fstelm = ii - nbad + first; /* absolute element number */
+ fstrow = (fstelm - 1) / repeat + 1; /* starting row number */
+ fstelm = fstelm - (fstrow - 1) * repeat; /* relative number */
+ large_first_elem_val = fstelm;
+
+ if (ffpclu(fptr, colnum, fstrow, firstelem, nbad, status) > 0)
+ return(*status);
+
+ nbad=0;
+ }
+
+ ngood = ngood +1; /* the consecutive number of good pixels */
+ }
+ else
+ {
+ if (ngood) /* write previous string of good pixels */
+ {
+ fstelm = ii - ngood + first; /* absolute element number */
+ fstrow = (fstelm - 1) / repeat + 1; /* starting row number */
+ fstelm = fstelm - (fstrow - 1) * repeat; /* relative number */
+ large_first_elem_val = fstelm;
+
+ if (ffpcluj(fptr, colnum, fstrow, firstelem,ngood, &array[ii-ngood],
+ status) > 0)
+ return(*status);
+
+ ngood=0;
+ }
+
+ nbad = nbad +1; /* the consecutive number of bad pixels */
+ }
+ }
+
+ /* finished loop; now just write the last set of pixels */
+
+ if (ngood) /* write last string of good pixels */
+ {
+ fstelm = ii - ngood + first; /* absolute element number */
+ fstrow = (fstelm - 1) / repeat + 1; /* starting row number */
+ fstelm = fstelm - (fstrow - 1) * repeat; /* relative number */
+ large_first_elem_val = fstelm;
+
+ ffpcluj(fptr, colnum, fstrow, firstelem, ngood, &array[ii-ngood], status);
+ }
+ else if (nbad) /* write last string of bad pixels */
+ {
+ fstelm = ii - nbad + first; /* absolute element number */
+ fstrow = (fstelm - 1) / repeat + 1; /* starting row number */
+ fstelm = fstelm - (fstrow - 1) * repeat; /* relative number */
+ large_first_elem_val = fstelm;
+
+ ffpclu(fptr, colnum, fstrow, firstelem, nbad, status);
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffu4fi1(unsigned long *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ unsigned char *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required.
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] > UCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UCHAR_MAX;
+ }
+ else
+ output[ii] = input[ii];
+ }
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = (input[ii] - zero) / scale;
+
+ if (dvalue < DUCHAR_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DUCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UCHAR_MAX;
+ }
+ else
+ output[ii] = (unsigned char) (dvalue + .5);
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffu4fi2(unsigned long *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ short *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required.
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] > SHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MAX;
+ }
+ else
+ output[ii] = input[ii];
+ }
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = (input[ii] - zero) / scale;
+
+ if (dvalue < DSHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MIN;
+ }
+ else if (dvalue > DSHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MAX;
+ }
+ else
+ {
+ if (dvalue >= 0)
+ output[ii] = (short) (dvalue + .5);
+ else
+ output[ii] = (short) (dvalue - .5);
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffu4fi4(unsigned long *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ INT32BIT *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (scale == 1. && zero == 2147483648. && sizeof(long) == 4)
+ {
+ /* Instead of subtracting 2147483648, it is more efficient */
+ /* to just flip the sign bit with the XOR operator */
+
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = ( *(long *) &input[ii] ) ^ 0x80000000;
+ }
+ else if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] > INT32_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT32_MAX;
+ }
+ else
+ output[ii] = input[ii];
+ }
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = (input[ii] - zero) / scale;
+
+ if (dvalue < DINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT32_MIN;
+ }
+ else if (dvalue > DINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT32_MAX;
+ }
+ else
+ {
+ if (dvalue >= 0)
+ output[ii] = (INT32BIT) (dvalue + .5);
+ else
+ output[ii] = (INT32BIT) (dvalue - .5);
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffu4fi8(unsigned long *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ LONGLONG *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required
+*/
+{
+#if (LONGSIZE == 32) && (! defined HAVE_LONGLONG)
+
+/* don't have a native 8-byte integer, so have to construct the */
+/* 2 equivalent 4-byte integers have the same bit pattern */
+
+ unsigned long *uoutput;
+ long ii, jj, kk, temp;
+ double dvalue;
+
+ uoutput = (unsigned long *) output;
+
+#if BYTESWAPPED /* jj points to the most significant part of the 8-byte int */
+ jj = 1;
+ kk = 0;
+#else
+ jj = 0;
+ kk = 1;
+#endif
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++, jj += 2, kk += 2)
+ {
+ output[jj] = 0;
+ uoutput[kk] = input[ii];
+ }
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++, jj += 2, kk += 2)
+ {
+ dvalue = (input[ii] - zero) / scale;
+
+ if (dvalue < DLONGLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[jj] = LONG_MIN;
+ output[kk] = 0;
+ }
+ else if (dvalue > DLONGLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[jj] = LONG_MAX;
+ output[kk] = -1;
+ }
+ else
+ {
+ if (dvalue < 0)
+ {
+ temp = (dvalue + 1.) / 4294967296. - 1.;
+ output[jj] = temp;
+ uoutput[kk] = 4294967296. +
+ (dvalue - (double) (temp + 1) * 4294967296.);
+ }
+ else
+ {
+ temp = dvalue / 4294967296.;
+ output[jj] = temp;
+ uoutput[kk] = dvalue - (double) temp * 4294967296.;
+ }
+ }
+ }
+ }
+
+#else
+
+/* this is the much simpler case where the native 8-byte integer exists */
+
+ long ii;
+ double dvalue;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = input[ii];
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = (input[ii] - zero) / scale;
+
+ if (dvalue < DLONGLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONGLONG_MIN;
+ }
+ else if (dvalue > DLONGLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONGLONG_MAX;
+ }
+ else
+ {
+ if (dvalue >= 0)
+ output[ii] = (LONGLONG) (dvalue + .5);
+ else
+ output[ii] = (LONGLONG) (dvalue - .5);
+ }
+ }
+ }
+
+#endif
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffu4fr4(unsigned long *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ float *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required.
+*/
+{
+ long ii;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = (float) input[ii];
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = (input[ii] - zero) / scale;
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffu4fr8(unsigned long *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ double *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required.
+*/
+{
+ long ii;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = (double) input[ii];
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = (input[ii] - zero) / scale;
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffu4fstr(unsigned long *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ char *cform, /* I - format for output string values */
+ long twidth, /* I - width of each field, in chars */
+ char *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do scaling if required.
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ sprintf(output, cform, (double) input[ii]);
+ output += twidth;
+
+ if (*output) /* if this char != \0, then overflow occurred */
+ *status = OVERFLOW_ERR;
+ }
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = (input[ii] - zero) / scale;
+ sprintf(output, cform, dvalue);
+ output += twidth;
+
+ if (*output) /* if this char != \0, then overflow occurred */
+ *status = OVERFLOW_ERR;
+ }
+ }
+ return(*status);
+}
diff --git a/pkg/tbtables/cfitsio/putcoluk.c b/pkg/tbtables/cfitsio/putcoluk.c
new file mode 100644
index 00000000..4d1c5239
--- /dev/null
+++ b/pkg/tbtables/cfitsio/putcoluk.c
@@ -0,0 +1,1046 @@
+/* This file, putcolk.c, contains routines that write data elements to */
+/* a FITS image or table, with 'unsigned int' datatype. */
+
+/* The FITSIO software was written by William Pence at the High Energy */
+/* Astrophysic Science Archive Research Center (HEASARC) at the NASA */
+/* Goddard Space Flight Center. */
+
+#include <limits.h>
+#include <string.h>
+#include <stdlib.h>
+#include "fitsio2.h"
+
+/* declare variable for passing large firstelem values between routines */
+extern OFF_T large_first_elem_val;
+
+/*--------------------------------------------------------------------------*/
+int ffppruk(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long firstelem, /* I - first vector element to write(1 = 1st) */
+ long nelem, /* I - number of values to write */
+ unsigned int *array, /* I - array of values that are written */
+ int *status) /* IO - error status */
+/*
+ Write an array of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being written).
+*/
+{
+ long row;
+ unsigned int nullvalue;
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ /* use the OFF_T variable to pass the first element value */
+ if (firstelem != USE_LARGE_VALUE)
+ large_first_elem_val = firstelem;
+
+ fits_write_compressed_pixels(fptr, TUINT, large_first_elem_val, nelem,
+ 0, array, &nullvalue, status);
+ return(*status);
+ }
+
+ row=maxvalue(1,group);
+
+ ffpcluk(fptr, 2, row, firstelem, nelem, array, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffppnuk(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long firstelem, /* I - first vector element to write(1 = 1st) */
+ long nelem, /* I - number of values to write */
+ unsigned int *array, /* I - array of values that are written */
+ unsigned int nulval, /* I - undefined pixel value */
+ int *status) /* IO - error status */
+/*
+ Write an array of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of the
+ FITS array is not the same as the array being written). Any array values
+ that are equal to the value of nulval will be replaced with the null
+ pixel value that is appropriate for this column.
+*/
+{
+ long row;
+ unsigned int nullvalue;
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ /* use the OFF_T variable to pass the first element value */
+ if (firstelem != USE_LARGE_VALUE)
+ large_first_elem_val = firstelem;
+
+ nullvalue = nulval; /* set local variable */
+ fits_write_compressed_pixels(fptr, TUINT, large_first_elem_val, nelem,
+ 1, array, &nullvalue, status);
+ return(*status);
+ }
+
+ row=maxvalue(1,group);
+
+ ffpcnuk(fptr, 2, row, firstelem, nelem, array, nulval, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffp2duk(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long ncols, /* I - number of pixels in each row of array */
+ long naxis1, /* I - FITS image NAXIS1 value */
+ long naxis2, /* I - FITS image NAXIS2 value */
+ unsigned int *array, /* I - array to be written */
+ int *status) /* IO - error status */
+/*
+ Write an entire 2-D array of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of the
+ FITS array is not the same as the array being written).
+*/
+{
+ /* call the 3D writing routine, with the 3rd dimension = 1 */
+
+ ffp3duk(fptr, group, ncols, naxis2, naxis1, naxis2, 1, array, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffp3duk(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long ncols, /* I - number of pixels in each row of array */
+ long nrows, /* I - number of rows in each plane of array */
+ long naxis1, /* I - FITS image NAXIS1 value */
+ long naxis2, /* I - FITS image NAXIS2 value */
+ long naxis3, /* I - FITS image NAXIS3 value */
+ unsigned int *array, /* I - array to be written */
+ int *status) /* IO - error status */
+/*
+ Write an entire 3-D cube of values to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of the
+ FITS array is not the same as the array being written).
+*/
+{
+ long tablerow, nfits, narray, ii, jj;
+ long fpixel[3]= {1,1,1}, lpixel[3];
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+ lpixel[0] = ncols;
+ lpixel[1] = nrows;
+ lpixel[2] = naxis3;
+
+ fits_write_compressed_img(fptr, TUINT, fpixel, lpixel,
+ 0, array, NULL, status);
+
+ return(*status);
+ }
+
+ tablerow=maxvalue(1,group);
+
+ if (ncols == naxis1 && nrows == naxis2) /* arrays have same size? */
+ {
+ /* all the image pixels are contiguous, so write all at once */
+ ffpcluk(fptr, 2, tablerow, 1L, naxis1 * naxis2 * naxis3, array, status);
+ return(*status);
+ }
+
+ if (ncols < naxis1 || nrows < naxis2)
+ return(*status = BAD_DIMEN);
+
+ nfits = 1; /* next pixel in FITS image to write to */
+ narray = 0; /* next pixel in input array to be written */
+
+ /* loop over naxis3 planes in the data cube */
+ for (jj = 0; jj < naxis3; jj++)
+ {
+ /* loop over the naxis2 rows in the FITS image, */
+ /* writing naxis1 pixels to each row */
+
+ for (ii = 0; ii < naxis2; ii++)
+ {
+ if (ffpcluk(fptr, 2, tablerow, nfits, naxis1,&array[narray],status) > 0)
+ return(*status);
+
+ nfits += naxis1;
+ narray += ncols;
+ }
+ narray += (nrows - naxis2) * ncols;
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpssuk(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long naxis, /* I - number of data axes in array */
+ long *naxes, /* I - size of each FITS axis */
+ long *fpixel, /* I - 1st pixel in each axis to write (1=1st) */
+ long *lpixel, /* I - last pixel in each axis to write */
+ unsigned int *array, /* I - array to be written */
+ int *status) /* IO - error status */
+/*
+ Write a subsection of pixels to the primary array or image.
+ A subsection is defined to be any contiguous rectangular
+ array of pixels within the n-dimensional FITS data file.
+ Data conversion and scaling will be performed if necessary
+ (e.g, if the datatype of the FITS array is not the same as
+ the array being written).
+*/
+{
+ long tablerow;
+ long fpix[7], irange[7], dimen[7], astart, pstart;
+ long off2, off3, off4, off5, off6, off7;
+ long st10, st20, st30, st40, st50, st60, st70;
+ long st1, st2, st3, st4, st5, st6, st7;
+ long ii, i1, i2, i3, i4, i5, i6, i7;
+
+ if (*status > 0)
+ return(*status);
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ fits_write_compressed_img(fptr, TUINT, fpixel, lpixel,
+ 0, array, NULL, status);
+
+ return(*status);
+ }
+
+ if (naxis < 1 || naxis > 7)
+ return(*status = BAD_DIMEN);
+
+ tablerow=maxvalue(1,group);
+
+ /* calculate the size and number of loops to perform in each dimension */
+ for (ii = 0; ii < 7; ii++)
+ {
+ fpix[ii]=1;
+ irange[ii]=1;
+ dimen[ii]=1;
+ }
+
+ for (ii = 0; ii < naxis; ii++)
+ {
+ fpix[ii]=fpixel[ii];
+ irange[ii]=lpixel[ii]-fpixel[ii]+1;
+ dimen[ii]=naxes[ii];
+ }
+
+ i1=irange[0];
+
+ /* compute the pixel offset between each dimension */
+ off2 = dimen[0];
+ off3 = off2 * dimen[1];
+ off4 = off3 * dimen[2];
+ off5 = off4 * dimen[3];
+ off6 = off5 * dimen[4];
+ off7 = off6 * dimen[5];
+
+ st10 = fpix[0];
+ st20 = (fpix[1] - 1) * off2;
+ st30 = (fpix[2] - 1) * off3;
+ st40 = (fpix[3] - 1) * off4;
+ st50 = (fpix[4] - 1) * off5;
+ st60 = (fpix[5] - 1) * off6;
+ st70 = (fpix[6] - 1) * off7;
+
+ /* store the initial offset in each dimension */
+ st1 = st10;
+ st2 = st20;
+ st3 = st30;
+ st4 = st40;
+ st5 = st50;
+ st6 = st60;
+ st7 = st70;
+
+ astart = 0;
+
+ for (i7 = 0; i7 < irange[6]; i7++)
+ {
+ for (i6 = 0; i6 < irange[5]; i6++)
+ {
+ for (i5 = 0; i5 < irange[4]; i5++)
+ {
+ for (i4 = 0; i4 < irange[3]; i4++)
+ {
+ for (i3 = 0; i3 < irange[2]; i3++)
+ {
+ pstart = st1 + st2 + st3 + st4 + st5 + st6 + st7;
+ for (i2 = 0; i2 < irange[1]; i2++)
+ {
+ if (ffpcluk(fptr, 2, tablerow, pstart, i1, &array[astart],
+ status) > 0)
+ return(*status);
+
+ astart += i1;
+ pstart += off2;
+ }
+ st2 = st20;
+ st3 = st3+off3;
+ }
+ st3 = st30;
+ st4 = st4+off4;
+ }
+ st4 = st40;
+ st5 = st5+off5;
+ }
+ st5 = st50;
+ st6 = st6+off6;
+ }
+ st6 = st60;
+ st7 = st7+off7;
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpgpuk(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ long firstelem, /* I - first vector element to write(1 = 1st) */
+ long nelem, /* I - number of values to write */
+ unsigned int *array, /* I - array of values that are written */
+ int *status) /* IO - error status */
+/*
+ Write an array of group parameters to the primary array. Data conversion
+ and scaling will be performed if necessary (e.g, if the datatype of
+ the FITS array is not the same as the array being written).
+*/
+{
+ long row;
+
+ /*
+ the primary array is represented as a binary table:
+ each group of the primary array is a row in the table,
+ where the first column contains the group parameters
+ and the second column contains the image itself.
+ */
+
+ row=maxvalue(1,group);
+
+ ffpcluk(fptr, 1L, row, firstelem, nelem, array, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpcluk(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to write (1 = 1st col) */
+ long firstrow, /* I - first row to write (1 = 1st row) */
+ long firstelem, /* I - first vector element to write (1 = 1st) */
+ long nelem, /* I - number of values to write */
+ unsigned int *array, /* I - array of values to write */
+ int *status) /* IO - error status */
+/*
+ Write an array of values to a column in the current FITS HDU.
+ The column number may refer to a real column in an ASCII or binary table,
+ or it may refer to a virtual column in a 1 or more grouped FITS primary
+ array. FITSIO treats a primary array as a binary table
+ with 2 vector columns: the first column contains the group parameters (often
+ with length = 0) and the second column contains the array of image pixels.
+ Each row of the table represents a group in the case of multigroup FITS
+ images.
+
+ The input array of values will be converted to the datatype of the column
+ and will be inverse-scaled by the FITS TSCALn and TZEROn values if necessary.
+*/
+{
+ int tcode, maxelem, hdutype;
+ long twidth, incre, rownum, remain, next, ntodo;
+ long tnull;
+ OFF_T repeat, startpos, elemnum, large_elem, wrtptr, rowlen;
+ double scale, zero;
+ char tform[20], cform[20];
+ char message[FLEN_ERRMSG];
+
+ char snull[20]; /* the FITS null value */
+
+ double cbuff[DBUFFSIZE / sizeof(double)]; /* align cbuff on word boundary */
+ void *buffer;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ /* call the 'short' or 'long' version of this routine, if possible */
+ if (sizeof(int) == sizeof(short))
+ ffpclui(fptr, colnum, firstrow, firstelem, nelem,
+ (unsigned short *) array, status);
+ else if (sizeof(int) == sizeof(long))
+ ffpcluj(fptr, colnum, firstrow, firstelem, nelem,
+ (unsigned long *) array, status);
+ else
+ {
+ /*
+ This is a special case: sizeof(int) is not equal to sizeof(short) or
+ sizeof(long). This occurs on Alpha OSF systems where short = 2 bytes,
+ int = 4 bytes, and long = 8 bytes.
+ */
+
+ buffer = cbuff;
+
+ if (firstelem == USE_LARGE_VALUE)
+ large_elem = large_first_elem_val;
+ else
+ large_elem = firstelem;
+
+ /*---------------------------------------------------*/
+ /* Check input and get parameters about the column: */
+ /*---------------------------------------------------*/
+ if (ffgcpr( fptr, colnum, firstrow, large_elem, nelem, 1, &scale, &zero,
+ tform, &twidth, &tcode, &maxelem, &startpos, &elemnum, &incre,
+ &repeat, &rowlen, &hdutype, &tnull, snull, status) > 0)
+ return(*status);
+
+ if (tcode == TSTRING)
+ ffcfmt(tform, cform); /* derive C format for writing strings */
+
+ /*---------------------------------------------------------------------*/
+ /* Now write the pixels to the FITS column. */
+ /* First call the ffXXfYY routine to (1) convert the datatype */
+ /* if necessary, and (2) scale the values by the FITS TSCALn and */
+ /* TZEROn linear scaling parameters into a temporary buffer. */
+ /*---------------------------------------------------------------------*/
+ remain = nelem; /* remaining number of values to write */
+ next = 0; /* next element in array to be written */
+ rownum = 0; /* row number, relative to firstrow */
+
+ while (remain)
+ {
+ /* limit the number of pixels to process a one time to the number that
+ will fit in the buffer space or to the number of pixels that remain
+ in the current vector, which ever is smaller.
+ */
+ ntodo = minvalue(remain, maxelem);
+ ntodo = minvalue(ntodo, (repeat - elemnum));
+
+ wrtptr = startpos + ((OFF_T)rownum * rowlen) + (elemnum * incre);
+
+ ffmbyt(fptr, wrtptr, IGNORE_EOF, status); /* move to write position */
+
+ switch (tcode)
+ {
+ case (TLONG):
+ /* convert the raw data before writing to FITS file */
+ ffuintfi4(&array[next], ntodo, scale, zero,
+ (INT32BIT *) buffer, status);
+ ffpi4b(fptr, ntodo, incre, (INT32BIT *) buffer, status);
+ break;
+
+ case (TLONGLONG):
+
+ ffuintfi8(&array[next], ntodo, scale, zero,
+ (LONGLONG *) buffer, status);
+ ffpi8b(fptr, ntodo, incre, (long *) buffer, status);
+ break;
+
+ case (TBYTE):
+
+ ffuintfi1(&array[next], ntodo, scale, zero,
+ (unsigned char *) buffer, status);
+ ffpi1b(fptr, ntodo, incre, (unsigned char *) buffer, status);
+ break;
+
+ case (TSHORT):
+
+ ffuintfi2(&array[next], ntodo, scale, zero,
+ (short *) buffer, status);
+ ffpi2b(fptr, ntodo, incre, (short *) buffer, status);
+ break;
+
+ case (TFLOAT):
+
+ ffuintfr4(&array[next], ntodo, scale, zero,
+ (float *) buffer, status);
+ ffpr4b(fptr, ntodo, incre, (float *) buffer, status);
+ break;
+
+ case (TDOUBLE):
+ ffuintfr8(&array[next], ntodo, scale, zero,
+ (double *) buffer, status);
+ ffpr8b(fptr, ntodo, incre, (double *) buffer, status);
+ break;
+
+ case (TSTRING): /* numerical column in an ASCII table */
+
+ if (cform[1] != 's') /* "%s" format is a string */
+ {
+ ffuintfstr(&array[next], ntodo, scale, zero, cform,
+ twidth, (char *) buffer, status);
+
+ if (incre == twidth) /* contiguous bytes */
+ ffpbyt(fptr, ntodo * twidth, buffer, status);
+ else
+ ffpbytoff(fptr, twidth, ntodo, incre - twidth, buffer,
+ status);
+
+ break;
+ }
+ /* can't write to string column, so fall thru to default: */
+
+ default: /* error trap */
+ sprintf(message,
+ "Cannot write numbers to column %d which has format %s",
+ colnum,tform);
+ ffpmsg(message);
+ if (hdutype == ASCII_TBL)
+ return(*status = BAD_ATABLE_FORMAT);
+ else
+ return(*status = BAD_BTABLE_FORMAT);
+
+ } /* End of switch block */
+
+ /*-------------------------*/
+ /* Check for fatal error */
+ /*-------------------------*/
+ if (*status > 0) /* test for error during previous write operation */
+ {
+ sprintf(message,
+ "Error writing elements %ld thru %ld of input data array (ffpcluk).",
+ next+1, next+ntodo);
+ ffpmsg(message);
+ return(*status);
+ }
+
+ /*--------------------------------------------*/
+ /* increment the counters for the next loop */
+ /*--------------------------------------------*/
+ remain -= ntodo;
+ if (remain)
+ {
+ next += ntodo;
+ elemnum += ntodo;
+ if (elemnum == repeat) /* completed a row; start on next row */
+ {
+ elemnum = 0;
+ rownum++;
+ }
+ }
+ } /* End of main while Loop */
+
+
+ /*--------------------------------*/
+ /* check for numerical overflow */
+ /*--------------------------------*/
+ if (*status == OVERFLOW_ERR)
+ {
+ ffpmsg(
+ "Numerical overflow during type conversion while writing FITS data.");
+ *status = NUM_OVERFLOW;
+ }
+
+ } /* end of Dec ALPHA special case */
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpcnuk(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - number of column to write (1 = 1st col) */
+ long firstrow, /* I - first row to write (1 = 1st row) */
+ long firstelem, /* I - first vector element to write (1 = 1st) */
+ long nelem, /* I - number of values to write */
+ unsigned int *array, /* I - array of values to write */
+ unsigned int nulvalue, /* I - value used to flag undefined pixels */
+ int *status) /* IO - error status */
+/*
+ Write an array of elements to the specified column of a table. Any input
+ pixels equal to the value of nulvalue will be replaced by the appropriate
+ null value in the output FITS file.
+
+ The input array of values will be converted to the datatype of the column
+ and will be inverse-scaled by the FITS TSCALn and TZEROn values if necessary
+*/
+{
+ tcolumn *colptr;
+ long ngood = 0, nbad = 0, ii, fstrow;
+ OFF_T large_elem, repeat, first, fstelm;
+
+ if (*status > 0)
+ return(*status);
+
+ /* reset position to the correct HDU if necessary */
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ {
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+ }
+ else if ((fptr->Fptr)->datastart == DATA_UNDEFINED)
+ {
+ if ( ffrdef(fptr, status) > 0) /* rescan header */
+ return(*status);
+ }
+
+ colptr = (fptr->Fptr)->tableptr; /* point to first column */
+ colptr += (colnum - 1); /* offset to correct column structure */
+
+ repeat = colptr->trepeat; /* repeat count for this column */
+
+ if (firstelem == USE_LARGE_VALUE)
+ large_elem = large_first_elem_val;
+ else
+ large_elem = firstelem;
+
+ /* hereafter, pass first element parameter via global variable */
+ firstelem = USE_LARGE_VALUE;
+
+ /* absolute element number in the column */
+ first = (firstrow - 1) * repeat + large_elem;
+
+ for (ii = 0; ii < nelem; ii++)
+ {
+ if (array[ii] != nulvalue) /* is this a good pixel? */
+ {
+ if (nbad) /* write previous string of bad pixels */
+ {
+ fstelm = ii - nbad + first; /* absolute element number */
+ fstrow = (fstelm - 1) / repeat + 1; /* starting row number */
+ fstelm = fstelm - (fstrow - 1) * repeat; /* relative number */
+ large_first_elem_val = fstelm;
+
+ if (ffpclu(fptr, colnum, fstrow, firstelem, nbad, status) > 0)
+ return(*status);
+
+ nbad=0;
+ }
+
+ ngood = ngood +1; /* the consecutive number of good pixels */
+ }
+ else
+ {
+ if (ngood) /* write previous string of good pixels */
+ {
+ fstelm = ii - ngood + first; /* absolute element number */
+ fstrow = (fstelm - 1) / repeat + 1; /* starting row number */
+ fstelm = fstelm - (fstrow - 1) * repeat; /* relative number */
+ large_first_elem_val = fstelm;
+
+ if (ffpcluk(fptr, colnum, fstrow, firstelem,ngood, &array[ii-ngood],
+ status) > 0)
+ return(*status);
+
+ ngood=0;
+ }
+
+ nbad = nbad +1; /* the consecutive number of bad pixels */
+ }
+ }
+
+ /* finished loop; now just write the last set of pixels */
+
+ if (ngood) /* write last string of good pixels */
+ {
+ fstelm = ii - ngood + first; /* absolute element number */
+ fstrow = (fstelm - 1) / repeat + 1; /* starting row number */
+ fstelm = fstelm - (fstrow - 1) * repeat; /* relative number */
+ large_first_elem_val = fstelm;
+
+ ffpcluk(fptr, colnum, fstrow, firstelem, ngood, &array[ii-ngood], status);
+ }
+ else if (nbad) /* write last string of bad pixels */
+ {
+ fstelm = ii - nbad + first; /* absolute element number */
+ fstrow = (fstelm - 1) / repeat + 1; /* starting row number */
+ fstelm = fstelm - (fstrow - 1) * repeat; /* relative number */
+ large_first_elem_val = fstelm;
+
+ ffpclu(fptr, colnum, fstrow, firstelem, nbad, status);
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffuintfi1(unsigned int *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ unsigned char *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required.
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] > UCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UCHAR_MAX;
+ }
+ else
+ output[ii] = input[ii];
+ }
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = (input[ii] - zero) / scale;
+
+ if (dvalue < DUCHAR_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = 0;
+ }
+ else if (dvalue > DUCHAR_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = UCHAR_MAX;
+ }
+ else
+ output[ii] = (unsigned char) (dvalue + .5);
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffuintfi2(unsigned int *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ short *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required.
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] > SHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MAX;
+ }
+ else
+ output[ii] = input[ii];
+ }
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = (input[ii] - zero) / scale;
+
+ if (dvalue < DSHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MIN;
+ }
+ else if (dvalue > DSHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = SHRT_MAX;
+ }
+ else
+ {
+ if (dvalue >= 0)
+ output[ii] = (short) (dvalue + .5);
+ else
+ output[ii] = (short) (dvalue - .5);
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffuintfi4(unsigned int *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ INT32BIT *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (scale == 1. && zero == 2147483648.)
+ {
+ /* Instead of subtracting 2147483648, it is more efficient */
+ /* to just flip the sign bit with the XOR operator */
+
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = ( *(int *) &input[ii] ) ^ 0x80000000;
+ }
+ else if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ if (input[ii] > INT32_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT32_MAX;
+ }
+ else
+ output[ii] = input[ii];
+ }
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = (input[ii] - zero) / scale;
+
+ if (dvalue < DINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT32_MIN;
+ }
+ else if (dvalue > DINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = INT32_MAX;
+ }
+ else
+ {
+ if (dvalue >= 0)
+ output[ii] = (INT32BIT) (dvalue + .5);
+ else
+ output[ii] = (INT32BIT) (dvalue - .5);
+ }
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffuintfi8(unsigned int *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ LONGLONG *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required
+*/
+{
+#if (LONGSIZE == 32) && (! defined HAVE_LONGLONG)
+
+/* don't have a native 8-byte integer, so have to construct the */
+/* 2 equivalent 4-byte integers have the same bit pattern */
+
+ unsigned long *uoutput;
+ long ii, jj, kk, temp;
+ double dvalue;
+
+ uoutput = (unsigned long *) output;
+
+#if BYTESWAPPED /* jj points to the most significant part of the 8-byte int */
+ jj = 1;
+ kk = 0;
+#else
+ jj = 0;
+ kk = 1;
+#endif
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++, jj += 2, kk += 2)
+ {
+ output[jj] = 0;
+ uoutput[kk] = input[ii];
+ }
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++, jj += 2, kk += 2)
+ {
+ dvalue = (input[ii] - zero) / scale;
+
+ if (dvalue < DLONGLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[jj] = LONG_MIN;
+ output[kk] = 0;
+ }
+ else if (dvalue > DLONGLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[jj] = LONG_MAX;
+ output[kk] = -1;
+ }
+ else
+ {
+ if (dvalue < 0)
+ {
+ temp = (dvalue + 1.) / 4294967296. - 1.;
+ output[jj] = temp;
+ uoutput[kk] = 4294967296. +
+ (dvalue - (double) (temp + 1) * 4294967296.);
+ }
+ else
+ {
+ temp = dvalue / 4294967296.;
+ output[jj] = temp;
+ uoutput[kk] = dvalue - (double) temp * 4294967296.;
+ }
+ }
+ }
+ }
+
+#else
+
+/* this is the much simpler case where the native 8-byte integer exists */
+
+ long ii;
+ double dvalue;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = input[ii];
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = (input[ii] - zero) / scale;
+
+ if (dvalue < DLONGLONG_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONGLONG_MIN;
+ }
+ else if (dvalue > DLONGLONG_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ output[ii] = LONGLONG_MAX;
+ }
+ else
+ {
+ if (dvalue >= 0)
+ output[ii] = (LONGLONG) (dvalue + .5);
+ else
+ output[ii] = (LONGLONG) (dvalue - .5);
+ }
+ }
+ }
+
+#endif
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffuintfr4(unsigned int *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ float *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required.
+*/
+{
+ long ii;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = (float) input[ii];
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = (input[ii] - zero) / scale;
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffuintfr8(unsigned int *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ double *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do datatype conversion and scaling if required.
+*/
+{
+ long ii;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = (double) input[ii];
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ output[ii] = (input[ii] - zero) / scale;
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffuintfstr(unsigned int *input, /* I - array of values to be converted */
+ long ntodo, /* I - number of elements in the array */
+ double scale, /* I - FITS TSCALn or BSCALE value */
+ double zero, /* I - FITS TZEROn or BZERO value */
+ char *cform, /* I - format for output string values */
+ long twidth, /* I - width of each field, in chars */
+ char *output, /* O - output array of converted values */
+ int *status) /* IO - error status */
+/*
+ Copy input to output prior to writing output to a FITS file.
+ Do scaling if required.
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (scale == 1. && zero == 0.)
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ sprintf(output, cform, (double) input[ii]);
+ output += twidth;
+
+ if (*output) /* if this char != \0, then overflow occurred */
+ *status = OVERFLOW_ERR;
+ }
+ }
+ else
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ dvalue = (input[ii] - zero) / scale;
+ sprintf(output, cform, dvalue);
+ output += twidth;
+
+ if (*output) /* if this char != \0, then overflow occurred */
+ *status = OVERFLOW_ERR;
+ }
+ }
+ return(*status);
+}
diff --git a/pkg/tbtables/cfitsio/putkey.c b/pkg/tbtables/cfitsio/putkey.c
new file mode 100644
index 00000000..f240df0a
--- /dev/null
+++ b/pkg/tbtables/cfitsio/putkey.c
@@ -0,0 +1,2706 @@
+/* This file, putkey.c, contains routines that write keywords to */
+/* a FITS header. */
+
+/* The FITSIO software was written by William Pence at the High Energy */
+/* Astrophysic Science Archive Research Center (HEASARC) at the NASA */
+/* Goddard Space Flight Center. */
+
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <time.h>
+/* stddef.h is apparently needed to define size_t */
+#include <stddef.h>
+#include "fitsio2.h"
+
+/*--------------------------------------------------------------------------*/
+int ffcrim(fitsfile *fptr, /* I - FITS file pointer */
+ int bitpix, /* I - bits per pixel */
+ int naxis, /* I - number of axes in the array */
+ long *naxes, /* I - size of each axis */
+ int *status) /* IO - error status */
+/*
+ create an IMAGE extension following the current HDU. If the
+ current HDU is empty (contains no header keywords), then simply
+ write the required image (or primary array) keywords to the current
+ HDU.
+*/
+{
+ if (*status > 0)
+ return(*status);
+
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+
+ /* create new extension if current header is not empty */
+ if ((fptr->Fptr)->headend != (fptr->Fptr)->headstart[(fptr->Fptr)->curhdu] )
+ ffcrhd(fptr, status);
+
+ /* write the required header keywords */
+ ffphpr(fptr, TRUE, bitpix, naxis, naxes, 0, 1, TRUE, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffcrtb(fitsfile *fptr, /* I - FITS file pointer */
+ int tbltype, /* I - type of table to create */
+ long naxis2, /* I - number of rows in the table */
+ int tfields, /* I - number of columns in the table */
+ char **ttype, /* I - name of each column */
+ char **tform, /* I - value of TFORMn keyword for each column */
+ char **tunit, /* I - value of TUNITn keyword for each column */
+ char *extnm, /* I - value of EXTNAME keyword, if any */
+ int *status) /* IO - error status */
+/*
+ Create a table extension in a FITS file.
+*/
+{
+ long naxis1 = 0, *tbcol = 0;
+
+ if (*status > 0)
+ return(*status);
+
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+
+ /* create new extension if current header is not empty */
+ if ((fptr->Fptr)->headend != (fptr->Fptr)->headstart[(fptr->Fptr)->curhdu] )
+ ffcrhd(fptr, status);
+
+ if ((fptr->Fptr)->curhdu == 0) /* have to create dummy primary array */
+ {
+ ffcrim(fptr, 16, 0, tbcol, status);
+ ffcrhd(fptr, status);
+ }
+
+ if (tbltype == BINARY_TBL)
+ {
+ /* write the required header keywords. This will write PCOUNT = 0 */
+ /* so variable length array columns are not supported */
+ ffphbn(fptr, naxis2, tfields, ttype, tform, tunit, extnm, 0, status);
+ }
+ else if (tbltype == ASCII_TBL)
+ {
+ /* write the required header keywords */
+ /* default values for naxis1 and tbcol will be calculated */
+ ffphtb(fptr, naxis1, naxis2, tfields, ttype, tbcol, tform, tunit,
+ extnm, status);
+ }
+ else
+ *status = NOT_TABLE;
+
+ return(*status);
+}
+/*-------------------------------------------------------------------------*/
+int ffpktp(fitsfile *fptr, /* I - FITS file pointer */
+ const char *filename, /* I - name of template file */
+ int *status) /* IO - error status */
+/*
+ read keywords from template file and append to the FITS file
+*/
+{
+ FILE *diskfile;
+ char card[FLEN_CARD], template[161];
+ char keyname[FLEN_KEYWORD], newname[FLEN_KEYWORD];
+ int keytype;
+ size_t slen;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ diskfile = fopen(filename,"r");
+ if (!diskfile) /* couldn't open file */
+ {
+ ffpmsg("ffpktp could not open the following template file:");
+ ffpmsg(filename);
+ return(*status = FILE_NOT_OPENED);
+ }
+
+ while (fgets(template, 160, diskfile) ) /* get next template line */
+ {
+ template[160] = '\0'; /* make sure string is terminated */
+ slen = strlen(template); /* get string length */
+ template[slen - 1] = '\0'; /* over write the 'newline' char */
+
+ if (ffgthd(template, card, &keytype, status) > 0) /* parse template */
+ break;
+
+ strncpy(keyname, card, 8);
+ keyname[8] = '\0';
+
+ if (keytype == -2) /* rename the card */
+ {
+ strncpy(newname, &card[40], 8);
+ newname[8] = '\0';
+
+ ffmnam(fptr, keyname, newname, status);
+ }
+ else if (keytype == -1) /* delete the card */
+ {
+ ffdkey(fptr, keyname, status);
+ }
+ else if (keytype == 0) /* update the card */
+ {
+ ffucrd(fptr, keyname, card, status);
+ }
+ else if (keytype == 1) /* append the card */
+ {
+ ffprec(fptr, card, status);
+ }
+ else /* END card; stop here */
+ {
+ break;
+ }
+ }
+
+ fclose(diskfile); /* close the template file */
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpky( fitsfile *fptr, /* I - FITS file pointer */
+ int datatype, /* I - datatype of the value */
+ char *keyname, /* I - name of keyword to write */
+ void *value, /* I - keyword value */
+ char *comm, /* I - keyword comment */
+ int *status) /* IO - error status */
+/*
+ Write (put) the keyword, value and comment into the FITS header.
+ Writes a keyword value with the datatype specified by the 2nd argument.
+*/
+{
+ char errmsg[81];
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ if (datatype == TSTRING)
+ {
+ ffpkys(fptr, keyname, (char *) value, comm, status);
+ }
+ else if (datatype == TBYTE)
+ {
+ ffpkyj(fptr, keyname, (long) *(unsigned char *) value, comm, status);
+ }
+ else if (datatype == TSBYTE)
+ {
+ ffpkyj(fptr, keyname, (long) *(signed char *) value, comm, status);
+ }
+ else if (datatype == TUSHORT)
+ {
+ ffpkyj(fptr, keyname, (long) *(unsigned short *) value, comm, status);
+ }
+ else if (datatype == TSHORT)
+ {
+ ffpkyj(fptr, keyname, (long) *(short *) value, comm, status);
+ }
+ else if (datatype == TUINT)
+ {
+ ffpkyg(fptr, keyname, (double) *(unsigned int *) value, 0,
+ comm, status);
+ }
+ else if (datatype == TINT)
+ {
+ ffpkyj(fptr, keyname, (long) *(int *) value, comm, status);
+ }
+ else if (datatype == TLOGICAL)
+ {
+ ffpkyl(fptr, keyname, *(int *) value, comm, status);
+ }
+ else if (datatype == TULONG)
+ {
+ ffpkyg(fptr, keyname, (double) *(unsigned long *) value, 0,
+ comm, status);
+ }
+ else if (datatype == TLONG)
+ {
+ ffpkyj(fptr, keyname, *(long *) value, comm, status);
+ }
+ else if (datatype == TFLOAT)
+ {
+ ffpkye(fptr, keyname, *(float *) value, -7, comm, status);
+ }
+ else if (datatype == TDOUBLE)
+ {
+ ffpkyd(fptr, keyname, *(double *) value, -15, comm, status);
+ }
+ else if (datatype == TCOMPLEX)
+ {
+ ffpkyc(fptr, keyname, (float *) value, -7, comm, status);
+ }
+ else if (datatype == TDBLCOMPLEX)
+ {
+ ffpkym(fptr, keyname, (double *) value, -15, comm, status);
+ }
+ else
+ {
+ sprintf(errmsg, "Bad keyword datatype code: %d (ffpky)", datatype);
+ ffpmsg(errmsg);
+ *status = BAD_DATATYPE;
+ }
+
+ return(*status);
+}
+/*-------------------------------------------------------------------------*/
+int ffprec(fitsfile *fptr, /* I - FITS file pointer */
+ const char *card, /* I - string to be written */
+ int *status) /* IO - error status */
+/*
+ write a keyword record (80 bytes long) to the end of the header
+*/
+{
+ char tcard[FLEN_CARD];
+ size_t len, ii;
+ long nblocks;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+
+ if ( ((fptr->Fptr)->datastart - (fptr->Fptr)->headend) == 80) /* no room */
+ {
+ nblocks = 1;
+ if (ffiblk(fptr, nblocks, 0, status) > 0) /* insert 2880-byte block */
+ return(*status);
+ }
+
+ strncpy(tcard,card,80);
+ tcard[80] = '\0';
+
+ len = strlen(tcard);
+ for (ii=len; ii < 80; ii++) /* fill card with spaces if necessary */
+ tcard[ii] = ' ';
+
+ for (ii=0; ii < 8; ii++) /* make sure keyword name is uppercase */
+ tcard[ii] = toupper(tcard[ii]);
+
+ fftkey(tcard, status); /* test keyword name contains legal chars */
+
+ fftrec(tcard, status); /* test rest of keyword for legal chars */
+
+ ffmbyt(fptr, (fptr->Fptr)->headend, IGNORE_EOF, status); /* move to end */
+
+ ffpbyt(fptr, 80, tcard, status); /* write the 80 byte card */
+
+ if (*status <= 0)
+ (fptr->Fptr)->headend += 80; /* update end-of-header position */
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpkyu( fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - name of keyword to write */
+ char *comm, /* I - keyword comment */
+ int *status) /* IO - error status */
+/*
+ Write (put) a null-valued keyword and comment into the FITS header.
+*/
+{
+ char valstring[FLEN_VALUE];
+ char card[FLEN_CARD];
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ strcpy(valstring," "); /* create a dummy value string */
+ ffmkky(keyname, valstring, comm, card, status); /* construct the keyword */
+ ffprec(fptr, card, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpkys( fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - name of keyword to write */
+ char *value, /* I - keyword value */
+ char *comm, /* I - keyword comment */
+ int *status) /* IO - error status */
+/*
+ Write (put) the keyword, value and comment into the FITS header.
+ The value string will be truncated at 68 characters which is the
+ maximum length that will fit on a single FITS keyword.
+*/
+{
+ char valstring[FLEN_VALUE];
+ char card[FLEN_CARD];
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ ffs2c(value, valstring, status); /* put quotes around the string */
+ ffmkky(keyname, valstring, comm, card, status); /* construct the keyword */
+ ffprec(fptr, card, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpkls( fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - name of keyword to write */
+ char *value, /* I - keyword value */
+ char *comm, /* I - keyword comment */
+ int *status) /* IO - error status */
+/*
+ Write (put) the keyword, value and comment into the FITS header.
+ This routine is a modified version of ffpkys which supports the
+ HEASARC long string convention and can write arbitrarily long string
+ keyword values. The value is continued over multiple keywords that
+ have the name COMTINUE without an equal sign in column 9 of the card.
+ This routine also supports simple string keywords which are less than
+ 69 characters in length.
+*/
+{
+ char valstring[FLEN_CARD];
+ char card[FLEN_CARD];
+ char tstring[FLEN_CARD], *cptr;
+ int next, remain, vlen, nquote, nchar, namelen, contin, tstatus = -1;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ remain = maxvalue(strlen(value), 1); /* no. of chars to write (at least 1) */
+ /* count the number of single quote characters are in the string */
+ tstring[0] = '\0';
+ strncat(tstring, value, 68); /* copy 1st part of string to temp buff */
+ nquote = 0;
+ cptr = strchr(tstring, '\''); /* search for quote character */
+ while (cptr) /* search for quote character */
+ {
+ nquote++; /* increment no. of quote characters */
+ cptr++; /* increment pointer to next character */
+ cptr = strchr(cptr, '\''); /* search for another quote char */
+ }
+
+ cptr = keyname;
+ while(*cptr == ' ') /* skip over leading spaces in name */
+ cptr++;
+
+ /* determine the number of characters that will fit on the line */
+ /* Note: each quote character is expanded to 2 quotes */
+
+ namelen = strlen(cptr);
+ if (namelen <= 8 && (fftkey(cptr, &tstatus) <= 0) )
+ {
+ /* This a normal 8-character FITS keyword */
+ nchar = 68 - nquote; /* max of 68 chars fit in a FITS string value */
+ }
+ else
+ {
+ /* This a HIERARCH keyword */
+ if (FSTRNCMP(cptr, "HIERARCH ", 9) &&
+ FSTRNCMP(cptr, "hierarch ", 9))
+ nchar = 66 - nquote - namelen;
+ else
+ nchar = 75 - nquote - namelen; /* don't count 'HIERARCH' twice */
+
+ }
+
+ contin = 0;
+ next = 0; /* pointer to next character to write */
+
+ while (remain > 0)
+ {
+ tstring[0] = '\0';
+ strncat(tstring, &value[next], nchar); /* copy string to temp buff */
+ ffs2c(tstring, valstring, status); /* put quotes around the string */
+
+ if (remain > nchar) /* if string is continued, put & as last char */
+ {
+ vlen = strlen(valstring);
+ nchar -= 1; /* outputting one less character now */
+
+ if (valstring[vlen-2] != '\'')
+ valstring[vlen-2] = '&'; /* over write last char with & */
+ else
+ { /* last char was a pair of single quotes, so over write both */
+ valstring[vlen-3] = '&';
+ valstring[vlen-1] = '\0';
+ }
+ }
+
+ if (contin) /* This is a CONTINUEd keyword */
+ {
+ ffmkky("CONTINUE", valstring, comm, card, status); /* make keyword */
+ strncpy(&card[8], " ", 2); /* overwrite the '=' */
+ }
+ else
+ {
+ ffmkky(keyname, valstring, comm, card, status); /* make keyword */
+ }
+
+ ffprec(fptr, card, status); /* write the keyword */
+
+ contin = 1;
+ remain -= nchar;
+ next += nchar;
+
+ if (remain > 0)
+ {
+ /* count the number of single quote characters in next section */
+ tstring[0] = '\0';
+ strncat(tstring, &value[next], 68); /* copy next part of string */
+ nquote = 0;
+ cptr = strchr(tstring, '\''); /* search for quote character */
+ while (cptr) /* search for quote character */
+ {
+ nquote++; /* increment no. of quote characters */
+ cptr++; /* increment pointer to next character */
+ cptr = strchr(cptr, '\''); /* search for another quote char */
+ }
+ nchar = 68 - nquote; /* max number of chars to write this time */
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffplsw( fitsfile *fptr, /* I - FITS file pointer */
+ int *status) /* IO - error status */
+/*
+ Write the LONGSTRN keyword and a series of related COMMENT keywords
+ which document that this FITS header may contain long string keyword
+ values which are continued over multiple keywords using the HEASARC
+ long string keyword convention. If the LONGSTRN keyword already exists
+ then this routine simple returns without doing anything.
+*/
+{
+ char valstring[FLEN_VALUE], comm[FLEN_COMMENT];
+ int tstatus;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ tstatus = 0;
+ if (ffgkys(fptr, "LONGSTRN", valstring, comm, &tstatus) == 0)
+ return(*status); /* keyword already exists, so just return */
+
+ ffpkys(fptr, "LONGSTRN", "OGIP 1.0",
+ "The HEASARC Long String Convention may be used.", status);
+
+ ffpcom(fptr,
+ " This FITS file may contain long string keyword values that are", status);
+
+ ffpcom(fptr,
+ " continued over multiple keywords. The HEASARC convention uses the &",
+ status);
+
+ ffpcom(fptr,
+ " character at the end of each substring which is then continued", status);
+
+ ffpcom(fptr,
+ " on the next keyword which has the name CONTINUE.", status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpkyl( fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - name of keyword to write */
+ int value, /* I - keyword value */
+ char *comm, /* I - keyword comment */
+ int *status) /* IO - error status */
+/*
+ Write (put) the keyword, value and comment into the FITS header.
+ Values equal to 0 will result in a False FITS keyword; any other
+ non-zero value will result in a True FITS keyword.
+*/
+{
+ char valstring[FLEN_VALUE];
+ char card[FLEN_CARD];
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ ffl2c(value, valstring, status); /* convert to formatted string */
+ ffmkky(keyname, valstring, comm, card, status); /* construct the keyword*/
+ ffprec(fptr, card, status); /* write the keyword*/
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpkyj( fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - name of keyword to write */
+ long value, /* I - keyword value */
+ char *comm, /* I - keyword comment */
+ int *status) /* IO - error status */
+/*
+ Write (put) the keyword, value and comment into the FITS header.
+ Writes an integer keyword value.
+*/
+{
+ char valstring[FLEN_VALUE];
+ char card[FLEN_CARD];
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ ffi2c(value, valstring, status); /* convert to formatted string */
+ ffmkky(keyname, valstring, comm, card, status); /* construct the keyword*/
+ ffprec(fptr, card, status); /* write the keyword*/
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpkyf( fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - name of keyword to write */
+ float value, /* I - keyword value */
+ int decim, /* I - number of decimal places to display */
+ char *comm, /* I - keyword comment */
+ int *status) /* IO - error status */
+/*
+ Write (put) the keyword, value and comment into the FITS header.
+ Writes a fixed float keyword value.
+*/
+{
+ char valstring[FLEN_VALUE];
+ char card[FLEN_CARD];
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ ffr2f(value, decim, valstring, status); /* convert to formatted string */
+ ffmkky(keyname, valstring, comm, card, status); /* construct the keyword*/
+ ffprec(fptr, card, status); /* write the keyword*/
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpkye( fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - name of keyword to write */
+ float value, /* I - keyword value */
+ int decim, /* I - number of decimal places to display */
+ char *comm, /* I - keyword comment */
+ int *status) /* IO - error status */
+/*
+ Write (put) the keyword, value and comment into the FITS header.
+ Writes an exponential float keyword value.
+*/
+{
+ char valstring[FLEN_VALUE];
+ char card[FLEN_CARD];
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ ffr2e(value, decim, valstring, status); /* convert to formatted string */
+ ffmkky(keyname, valstring, comm, card, status); /* construct the keyword*/
+ ffprec(fptr, card, status); /* write the keyword*/
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpkyg( fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - name of keyword to write */
+ double value, /* I - keyword value */
+ int decim, /* I - number of decimal places to display */
+ char *comm, /* I - keyword comment */
+ int *status) /* IO - error status */
+/*
+ Write (put) the keyword, value and comment into the FITS header.
+ Writes a fixed double keyword value.*/
+{
+ char valstring[FLEN_VALUE];
+ char card[FLEN_CARD];
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ ffd2f(value, decim, valstring, status); /* convert to formatted string */
+ ffmkky(keyname, valstring, comm, card, status); /* construct the keyword*/
+ ffprec(fptr, card, status); /* write the keyword*/
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpkyd( fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - name of keyword to write */
+ double value, /* I - keyword value */
+ int decim, /* I - number of decimal places to display */
+ char *comm, /* I - keyword comment */
+ int *status) /* IO - error status */
+/*
+ Write (put) the keyword, value and comment into the FITS header.
+ Writes an exponential double keyword value.*/
+{
+ char valstring[FLEN_VALUE];
+ char card[FLEN_CARD];
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ ffd2e(value, decim, valstring, status); /* convert to formatted string */
+ ffmkky(keyname, valstring, comm, card, status); /* construct the keyword*/
+ ffprec(fptr, card, status); /* write the keyword*/
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpkyc( fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - name of keyword to write */
+ float *value, /* I - keyword value (real, imaginary) */
+ int decim, /* I - number of decimal places to display */
+ char *comm, /* I - keyword comment */
+ int *status) /* IO - error status */
+/*
+ Write (put) the keyword, value and comment into the FITS header.
+ Writes an complex float keyword value. Format = (realvalue, imagvalue)
+*/
+{
+ char valstring[FLEN_VALUE], tmpstring[FLEN_VALUE];
+ char card[FLEN_CARD];
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ strcpy(valstring, "(" );
+ ffr2e(value[0], decim, tmpstring, status); /* convert to string */
+ strcat(valstring, tmpstring);
+ strcat(valstring, ", ");
+ ffr2e(value[1], decim, tmpstring, status); /* convert to string */
+ strcat(valstring, tmpstring);
+ strcat(valstring, ")");
+
+ ffmkky(keyname, valstring, comm, card, status); /* construct the keyword*/
+ ffprec(fptr, card, status); /* write the keyword*/
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpkym( fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - name of keyword to write */
+ double *value, /* I - keyword value (real, imaginary) */
+ int decim, /* I - number of decimal places to display */
+ char *comm, /* I - keyword comment */
+ int *status) /* IO - error status */
+/*
+ Write (put) the keyword, value and comment into the FITS header.
+ Writes an complex double keyword value. Format = (realvalue, imagvalue)
+*/
+{
+ char valstring[FLEN_VALUE], tmpstring[FLEN_VALUE];
+ char card[FLEN_CARD];
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ strcpy(valstring, "(" );
+ ffd2e(value[0], decim, tmpstring, status); /* convert to string */
+ strcat(valstring, tmpstring);
+ strcat(valstring, ", ");
+ ffd2e(value[1], decim, tmpstring, status); /* convert to string */
+ strcat(valstring, tmpstring);
+ strcat(valstring, ")");
+
+ ffmkky(keyname, valstring, comm, card, status); /* construct the keyword*/
+ ffprec(fptr, card, status); /* write the keyword*/
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpkfc( fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - name of keyword to write */
+ float *value, /* I - keyword value (real, imaginary) */
+ int decim, /* I - number of decimal places to display */
+ char *comm, /* I - keyword comment */
+ int *status) /* IO - error status */
+/*
+ Write (put) the keyword, value and comment into the FITS header.
+ Writes an complex float keyword value. Format = (realvalue, imagvalue)
+*/
+{
+ char valstring[FLEN_VALUE], tmpstring[FLEN_VALUE];
+ char card[FLEN_CARD];
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ strcpy(valstring, "(" );
+ ffr2f(value[0], decim, tmpstring, status); /* convert to string */
+ strcat(valstring, tmpstring);
+ strcat(valstring, ", ");
+ ffr2f(value[1], decim, tmpstring, status); /* convert to string */
+ strcat(valstring, tmpstring);
+ strcat(valstring, ")");
+
+ ffmkky(keyname, valstring, comm, card, status); /* construct the keyword*/
+ ffprec(fptr, card, status); /* write the keyword*/
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpkfm( fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - name of keyword to write */
+ double *value, /* I - keyword value (real, imaginary) */
+ int decim, /* I - number of decimal places to display */
+ char *comm, /* I - keyword comment */
+ int *status) /* IO - error status */
+/*
+ Write (put) the keyword, value and comment into the FITS header.
+ Writes an complex double keyword value. Format = (realvalue, imagvalue)
+*/
+{
+ char valstring[FLEN_VALUE], tmpstring[FLEN_VALUE];
+ char card[FLEN_CARD];
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ strcpy(valstring, "(" );
+ ffd2f(value[0], decim, tmpstring, status); /* convert to string */
+ strcat(valstring, tmpstring);
+ strcat(valstring, ", ");
+ ffd2f(value[1], decim, tmpstring, status); /* convert to string */
+ strcat(valstring, tmpstring);
+ strcat(valstring, ")");
+
+ ffmkky(keyname, valstring, comm, card, status); /* construct the keyword*/
+ ffprec(fptr, card, status); /* write the keyword*/
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpkyt( fitsfile *fptr, /* I - FITS file pointer */
+ char *keyname, /* I - name of keyword to write */
+ long intval, /* I - integer part of value */
+ double fraction, /* I - fractional part of value */
+ char *comm, /* I - keyword comment */
+ int *status) /* IO - error status */
+/*
+ Write (put) a 'triple' precision keyword where the integer and
+ fractional parts of the value are passed in separate parameters to
+ increase the total amount of numerical precision.
+*/
+{
+ char valstring[FLEN_VALUE];
+ char card[FLEN_CARD];
+ char fstring[20], *cptr;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ if (fraction > 1. || fraction < 0.)
+ {
+ ffpmsg("fraction must be between 0. and 1. (ffpkyt)");
+ return(*status = BAD_F2C);
+ }
+
+ ffi2c(intval, valstring, status); /* convert integer to string */
+ ffd2f(fraction, 16, fstring, status); /* convert to 16 decimal string */
+
+ cptr = strchr(fstring, '.'); /* find the decimal point */
+ strcat(valstring, cptr); /* append the fraction to the integer */
+
+ ffmkky(keyname, valstring, comm, card, status); /* construct the keyword*/
+ ffprec(fptr, card, status); /* write the keyword*/
+
+ return(*status);
+}
+/*-----------------------------------------------------------------*/
+int ffpcom( fitsfile *fptr, /* I - FITS file pointer */
+ const char *comm, /* I - comment string */
+ int *status) /* IO - error status */
+/*
+ Write 1 or more COMMENT keywords. If the comment string is too
+ long to fit on a single keyword (72 chars) then it will automatically
+ be continued on multiple CONTINUE keywords.
+*/
+{
+ char card[FLEN_CARD];
+ int len, ii;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ len = strlen(comm);
+ ii = 0;
+
+ for (; len > 0; len -= 72)
+ {
+ strcpy(card, "COMMENT ");
+ strncat(card, &comm[ii], 72);
+ ffprec(fptr, card, status);
+ ii += 72;
+ }
+
+ return(*status);
+}
+/*-----------------------------------------------------------------*/
+int ffphis( fitsfile *fptr, /* I - FITS file pointer */
+ const char *history, /* I - history string */
+ int *status) /* IO - error status */
+/*
+ Write 1 or more HISTORY keywords. If the history string is too
+ long to fit on a single keyword (72 chars) then it will automatically
+ be continued on multiple HISTORY keywords.
+*/
+{
+ char card[FLEN_CARD];
+ int len, ii;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ len = strlen(history);
+ ii = 0;
+
+ for (; len > 0; len -= 72)
+ {
+ strcpy(card, "HISTORY ");
+ strncat(card, &history[ii], 72);
+ ffprec(fptr, card, status);
+ ii += 72;
+ }
+
+ return(*status);
+}
+/*-----------------------------------------------------------------*/
+int ffpdat( fitsfile *fptr, /* I - FITS file pointer */
+ int *status) /* IO - error status */
+/*
+ Write the DATE keyword into the FITS header. If the keyword already
+ exists then the date will simply be updated in the existing keyword.
+*/
+{
+ int timeref;
+ char date[30], tmzone[10], card[FLEN_CARD];
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ ffgstm(date, &timeref, status);
+
+ if (timeref) /* GMT not available on this machine */
+ strcpy(tmzone, " Local");
+ else
+ strcpy(tmzone, " UT");
+
+ strcpy(card, "DATE = '");
+ strcat(card, date);
+ strcat(card, "' / file creation date (YYYY-MM-DDThh:mm:ss");
+ strcat(card, tmzone);
+ strcat(card, ")");
+
+ ffucrd(fptr, "DATE", card, status);
+
+ return(*status);
+}
+/*-----------------------------------------------------------------*/
+int ffgstm( char *timestr, /* O - returned system date and time string */
+ int *timeref, /* O - GMT = 0, Local time = 1 */
+ int *status) /* IO - error status */
+/*
+ Returns the current date and time in format 'yyyy-mm-ddThh:mm:ss'.
+*/
+{
+ time_t tp;
+ struct tm *ptr;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ time(&tp);
+ ptr = gmtime(&tp); /* get GMT (= UTC) time */
+
+ if (timeref)
+ {
+ if (ptr)
+ *timeref = 0; /* returning GMT */
+ else
+ *timeref = 1; /* returning local time */
+ }
+
+ if (!ptr) /* GMT not available on this machine */
+ ptr = localtime(&tp);
+
+ strftime(timestr, 25, "%Y-%m-%dT%H:%M:%S", ptr);
+
+ return(*status);
+}
+/*-----------------------------------------------------------------*/
+int ffdt2s(int year, /* I - year (0 - 9999) */
+ int month, /* I - month (1 - 12) */
+ int day, /* I - day (1 - 31) */
+ char *datestr, /* O - date string: "YYYY-MM-DD" */
+ int *status) /* IO - error status */
+/*
+ Construct a date character string
+*/
+{
+ char errmsg[81];
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ if (year < 0 || year > 9999)
+ {
+ sprintf(errmsg,
+ "input year value is out of range 0 - 9999: %d (ffdt2s)", year);
+ ffpmsg(errmsg);
+ return(*status = BAD_DATE);
+ }
+ else if (month < 1 || month > 12)
+ {
+ sprintf(errmsg,
+ "input month value is out of range 1 - 12: %d (ffdt2s)", month);
+ ffpmsg(errmsg);
+ return(*status = BAD_DATE);
+ }
+ else if (day < 1 || day > 31)
+ {
+ sprintf(errmsg,
+ "input day value is out of range 1 - 31: %d (ffdt2s)", day);
+ ffpmsg(errmsg);
+ return(*status = BAD_DATE);
+ }
+
+ if (year >= 1900 && year <= 1998) /* use old 'dd/mm/yy' format */
+ sprintf(datestr, "%.2d/%.2d/%.2d", day, month, year - 1900);
+
+ else /* use the new 'YYYY-MM-DD' format */
+ sprintf(datestr, "%.4d-%.2d-%.2d", year, month, day);
+
+ return(*status);
+}
+/*-----------------------------------------------------------------*/
+int ffs2dt(char *datestr, /* I - date string: "YYYY-MM-DD" or "dd/mm/yy" */
+ int *year, /* O - year (0 - 9999) */
+ int *month, /* O - month (1 - 12) */
+ int *day, /* O - day (1 - 31) */
+ int *status) /* IO - error status */
+/*
+ Parse a date character string into year, month, and date values
+*/
+{
+ int slen;
+ char errmsg[81];
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ if (!datestr)
+ {
+ ffpmsg("error: null input date string (ffs2dt)");
+ return(*status = BAD_DATE); /* Null datestr pointer ??? */
+ }
+
+ slen = strlen(datestr);
+
+ if (slen == 8 && datestr[2] == '/' && datestr[5] == '/')
+ {
+ if (isdigit((int) datestr[0]) && isdigit((int) datestr[1])
+ && isdigit((int) datestr[3]) && isdigit((int) datestr[4])
+ && isdigit((int) datestr[6]) && isdigit((int) datestr[7]) )
+ {
+ /* this is an old format string: "dd/mm/yy" */
+ if (year)
+ *year = atoi(&datestr[6]) + 1900;
+
+ if (month)
+ *month = atoi(&datestr[3]);
+ if (day)
+ *day = atoi(datestr);
+ }
+ else
+ {
+ ffpmsg("input date string has illegal format:");
+ ffpmsg(datestr);
+ return(*status = BAD_DATE);
+ }
+ }
+ else if (slen >= 10 && datestr[4] == '-' && datestr[7] == '-')
+ {
+ if (isdigit((int) datestr[0]) && isdigit((int) datestr[1])
+ && isdigit((int) datestr[2]) && isdigit((int) datestr[3])
+ && isdigit((int) datestr[5]) && isdigit((int) datestr[6])
+ && isdigit((int) datestr[8]) && isdigit((int) datestr[9]) )
+ {
+ if (slen > 10 && datestr[10] != 'T')
+ {
+ ffpmsg("input date string has illegal format:");
+ ffpmsg(datestr);
+ return(*status = BAD_DATE);
+ }
+
+ /* this is a new format string: "yyyy-mm-dd" */
+ if (year)
+ *year = atoi(datestr);
+
+ if (month)
+ *month = atoi(&datestr[5]);
+
+ if (day)
+ *day = atoi(&datestr[8]);
+ }
+ else
+ {
+ ffpmsg("input date string has illegal format:");
+ ffpmsg(datestr);
+ return(*status = BAD_DATE);
+ }
+ }
+ else
+ {
+ ffpmsg("input date string has illegal format:");
+ ffpmsg(datestr);
+ return(*status = BAD_DATE);
+ }
+
+
+ if (year)
+ if (*year < 0 || *year > 9999)
+ {
+ sprintf(errmsg,
+ "year value is out of range 0 - 9999: %d (ffs2dt)", *year);
+ ffpmsg(errmsg);
+ return(*status = BAD_DATE);
+ }
+
+ if (month)
+ if (*month < 1 || *month > 12)
+ {
+ sprintf(errmsg,
+ "month value is out of range 1 - 12: %d (ffs2dt)", *month);
+ ffpmsg(errmsg);
+ return(*status = BAD_DATE);
+ }
+
+
+ if (day)
+ if (*day < 1 || *day > 31)
+ {
+ sprintf(errmsg,
+ "day value is out of range 1 - 31: %d (ffs2dt)", *day);
+ ffpmsg(errmsg);
+ return(*status = BAD_DATE);
+ }
+
+ return(*status);
+}
+/*-----------------------------------------------------------------*/
+int fftm2s(int year, /* I - year (0 - 9999) */
+ int month, /* I - month (1 - 12) */
+ int day, /* I - day (1 - 31) */
+ int hour, /* I - hour (0 - 23) */
+ int minute, /* I - minute (0 - 59) */
+ double second, /* I - second (0. - 60.9999999) */
+ int decimals, /* I - number of decimal points to write */
+ char *datestr, /* O - date string: "YYYY-MM-DDThh:mm:ss.ddd" */
+ /* or "hh:mm:ss.ddd" if year, month day = 0 */
+ int *status) /* IO - error status */
+/*
+ Construct a date and time character string
+*/
+{
+ int width;
+ char errmsg[81];
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ if (year < 0 || year > 9999)
+ {
+ sprintf(errmsg,
+ "input year value is out of range 0 - 9999: %d (fftm2s)", year);
+ ffpmsg(errmsg);
+ return(*status = BAD_DATE);
+ }
+ else if (month < 0 || month > 12)
+ {
+ sprintf(errmsg,
+ "input month value is out of range 0 - 12: %d (fftm2s)", month);
+ ffpmsg(errmsg);
+ return(*status = BAD_DATE);
+ }
+ else if (day < 0 || day > 31)
+ {
+ sprintf(errmsg,
+ "input day value is out of range 0 - 31: %d (fftm2s)", day);
+ ffpmsg(errmsg);
+ return(*status = BAD_DATE);
+ }
+ else if (hour < 0 || hour > 23)
+ {
+ sprintf(errmsg,
+ "input hour value is out of range 0 - 23: %d (fftm2s)", hour);
+ ffpmsg(errmsg);
+ return(*status = BAD_DATE);
+ }
+ else if (minute < 0 || minute > 59)
+ {
+ sprintf(errmsg,
+ "input minute value is out of range 0 - 59: %d (fftm2s)", minute);
+ ffpmsg(errmsg);
+ return(*status = BAD_DATE);
+ }
+ else if (second < 0. || second >= 61)
+ {
+ sprintf(errmsg,
+ "input second value is out of range 0 - 60.999: %f (fftm2s)", second);
+ ffpmsg(errmsg);
+ return(*status = BAD_DATE);
+ }
+ else if (decimals > 25)
+ {
+ sprintf(errmsg,
+ "input decimals value is out of range 0 - 25: %d (fftm2s)", decimals);
+ ffpmsg(errmsg);
+ return(*status = BAD_DATE);
+ }
+
+ if (decimals == 0)
+ width = 2;
+ else
+ width = decimals + 3;
+
+ if (decimals < 0)
+ {
+ /* a negative decimals value means return only the date, not time */
+ sprintf(datestr, "%.4d-%.2d-%.2d", year, month, day);
+ }
+ else if (year == 0 && month == 0 && day == 0)
+ {
+ /* return only the time, not the date */
+ sprintf(datestr, "%.2d:%.2d:%0*.*f",
+ hour, minute, width, decimals, second);
+ }
+ else
+ {
+ /* return both the time and date */
+ sprintf(datestr, "%.4d-%.2d-%.2dT%.2d:%.2d:%0*.*f",
+ year, month, day, hour, minute, width, decimals, second);
+ }
+ return(*status);
+}
+/*-----------------------------------------------------------------*/
+int ffs2tm(char *datestr, /* I - date string: "YYYY-MM-DD" */
+ /* or "YYYY-MM-DDThh:mm:ss.ddd" */
+ /* or "dd/mm/yy" */
+ int *year, /* O - year (0 - 9999) */
+ int *month, /* O - month (1 - 12) */
+ int *day, /* O - day (1 - 31) */
+ int *hour, /* I - hour (0 - 23) */
+ int *minute, /* I - minute (0 - 59) */
+ double *second, /* I - second (0. - 60.9999999) */
+ int *status) /* IO - error status */
+/*
+ Parse a date character string into date and time values
+*/
+{
+ int slen;
+ char errmsg[81];
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ if (!datestr)
+ {
+ ffpmsg("error: null input date string (ffs2tm)");
+ return(*status = BAD_DATE); /* Null datestr pointer ??? */
+ }
+
+ if (hour)
+ *hour = 0;
+
+ if (minute)
+ *minute = 0;
+
+ if (second)
+ *second = 0.;
+
+ if (datestr[2] == '/' || datestr[4] == '-')
+ {
+ /* Parse the year, month, and date */
+ if (ffs2dt(datestr, year, month, day, status) > 0)
+ return(*status);
+
+ slen = strlen(datestr);
+ if (slen == 8 || slen == 10)
+ return(*status); /* OK, no time fields */
+ else if (slen < 19)
+ {
+ ffpmsg("input date string has illegal format:");
+ ffpmsg(datestr);
+ return(*status = BAD_DATE);
+ }
+
+ else if (datestr[10] == 'T' && datestr[13] == ':' && datestr[16] == ':')
+ {
+ if (isdigit((int) datestr[11]) && isdigit((int) datestr[12])
+ && isdigit((int) datestr[14]) && isdigit((int) datestr[15])
+ && isdigit((int) datestr[17]) && isdigit((int) datestr[18]) )
+ {
+ if (slen > 19 && datestr[19] != '.')
+ {
+ ffpmsg("input date string has illegal format:");
+ ffpmsg(datestr);
+ return(*status = BAD_DATE);
+ }
+
+ /* this is a new format string: "yyyy-mm-ddThh:mm:ss.dddd" */
+ if (hour)
+ *hour = atoi(&datestr[11]);
+
+ if (minute)
+ *minute = atoi(&datestr[14]);
+
+ if (second)
+ *second = atof(&datestr[17]);
+ }
+ else
+ {
+ ffpmsg("input date string has illegal format:");
+ ffpmsg(datestr);
+ return(*status = BAD_DATE);
+ }
+
+ }
+ }
+ else /* no date fields */
+ {
+ if (year)
+ *year = 0;
+
+ if (month)
+ *month = 0;
+
+ if (day)
+ *day = 0;
+
+ if (datestr[2] == ':' && datestr[5] == ':') /* time string */
+ {
+ if (isdigit((int) datestr[0]) && isdigit((int) datestr[1])
+ && isdigit((int) datestr[3]) && isdigit((int) datestr[4])
+ && isdigit((int) datestr[6]) && isdigit((int) datestr[7]) )
+ {
+ /* this is a time string: "hh:mm:ss.dddd" */
+ if (hour)
+ *hour = atoi(&datestr[0]);
+
+ if (minute)
+ *minute = atoi(&datestr[3]);
+
+ if (second)
+ *second = atof(&datestr[6]);
+ }
+ else
+ {
+ ffpmsg("input date string has illegal format:");
+ ffpmsg(datestr);
+ return(*status = BAD_DATE);
+ }
+
+ }
+ else
+ {
+ ffpmsg("input date string has illegal format:");
+ ffpmsg(datestr);
+ return(*status = BAD_DATE);
+ }
+
+ }
+
+ if (hour)
+ if (*hour < 0 || *hour > 23)
+ {
+ sprintf(errmsg,
+ "hour value is out of range 0 - 23: %d (ffs2tm)", *hour);
+ ffpmsg(errmsg);
+ return(*status = BAD_DATE);
+ }
+
+ if (minute)
+ if (*minute < 0 || *minute > 59)
+ {
+ sprintf(errmsg,
+ "minute value is out of range 0 - 59: %d (ffs2tm)", *minute);
+ ffpmsg(errmsg);
+ return(*status = BAD_DATE);
+ }
+
+ if (second)
+ if (*second < 0 || *second >= 61.)
+ {
+ sprintf(errmsg,
+ "second value is out of range 0 - 60.9999: %f (ffs2tm)", *second);
+ ffpmsg(errmsg);
+ return(*status = BAD_DATE);
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgsdt( int *day, int *month, int *year, int *status )
+{
+/*
+ This routine is included for backward compatibility
+ with the Fortran FITSIO library.
+
+ ffgsdt : Get current System DaTe (GMT if available)
+
+ Return integer values of the day, month, and year
+
+ Function parameters:
+ day Day of the month
+ month Numerical month (1=Jan, etc.)
+ year Year (1999, 2000, etc.)
+ status output error status
+
+*/
+ time_t now;
+ struct tm *date;
+
+ now = time( NULL );
+ date = gmtime(&now); /* get GMT (= UTC) time */
+
+ if (!date) /* GMT not available on this machine */
+ {
+ date = localtime(&now);
+ }
+
+ *day = date->tm_mday;
+ *month = date->tm_mon + 1;
+ *year = date->tm_year + 1900; /* tm_year is defined as years since 1900 */
+ return( *status );
+}
+/*--------------------------------------------------------------------------*/
+int ffpkns( fitsfile *fptr, /* I - FITS file pointer */
+ char *keyroot, /* I - root name of keywords to write */
+ int nstart, /* I - starting index number */
+ int nkey, /* I - number of keywords to write */
+ char *value[], /* I - array of pointers to keyword values */
+ char *comm[], /* I - array of pointers to keyword comment */
+ int *status) /* IO - error status */
+/*
+ Write (put) an indexed array of keywords with index numbers between
+ NSTART and (NSTART + NKEY -1) inclusive. Writes string keywords.
+ The value strings will be truncated at 68 characters, and the HEASARC
+ long string keyword convention is not supported by this routine.
+*/
+{
+ char keyname[FLEN_KEYWORD], tcomment[FLEN_COMMENT];
+ int ii, jj, repeat, len;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ /* check if first comment string is to be repeated for all the keywords */
+ /* by looking to see if the last non-blank character is a '&' char */
+
+ repeat = 0;
+
+ if (comm)
+ {
+ len = strlen(comm[0]);
+
+ while (len > 0 && comm[0][len - 1] == ' ')
+ len--; /* ignore trailing blanks */
+
+ if (comm[0][len - 1] == '&')
+ {
+ len = minvalue(len, FLEN_COMMENT);
+ tcomment[0] = '\0';
+ strncat(tcomment, comm[0], len-1); /* don't copy the final '&' char */
+ repeat = 1;
+ }
+ }
+ else
+ {
+ repeat = 1;
+ tcomment[0] = '\0';
+ }
+
+ for (ii=0, jj=nstart; ii < nkey; ii++, jj++)
+ {
+ ffkeyn(keyroot, jj, keyname, status);
+ if (repeat)
+ ffpkys(fptr, keyname, value[ii], tcomment, status);
+ else
+ ffpkys(fptr, keyname, value[ii], comm[ii], status);
+
+ if (*status > 0)
+ return(*status);
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpknl( fitsfile *fptr, /* I - FITS file pointer */
+ char *keyroot, /* I - root name of keywords to write */
+ int nstart, /* I - starting index number */
+ int nkey, /* I - number of keywords to write */
+ int *value, /* I - array of keyword values */
+ char *comm[], /* I - array of pointers to keyword comment */
+ int *status) /* IO - error status */
+/*
+ Write (put) an indexed array of keywords with index numbers between
+ NSTART and (NSTART + NKEY -1) inclusive. Writes logical keywords
+ Values equal to zero will be written as a False FITS keyword value; any
+ other non-zero value will result in a True FITS keyword.
+*/
+{
+ char keyname[FLEN_KEYWORD], tcomment[FLEN_COMMENT];
+ int ii, jj, repeat, len;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ /* check if first comment string is to be repeated for all the keywords */
+ /* by looking to see if the last non-blank character is a '&' char */
+
+ repeat = 0;
+ if (comm)
+ {
+ len = strlen(comm[0]);
+
+ while (len > 0 && comm[0][len - 1] == ' ')
+ len--; /* ignore trailing blanks */
+
+ if (comm[0][len - 1] == '&')
+ {
+ len = minvalue(len, FLEN_COMMENT);
+ tcomment[0] = '\0';
+ strncat(tcomment, comm[0], len-1); /* don't copy the final '&' char */
+ repeat = 1;
+ }
+ }
+ else
+ {
+ repeat = 1;
+ tcomment[0] = '\0';
+ }
+
+
+ for (ii=0, jj=nstart; ii < nkey; ii++, jj++)
+ {
+ ffkeyn(keyroot, jj, keyname, status);
+
+ if (repeat)
+ ffpkyl(fptr, keyname, value[ii], tcomment, status);
+ else
+ ffpkyl(fptr, keyname, value[ii], comm[ii], status);
+
+ if (*status > 0)
+ return(*status);
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpknj( fitsfile *fptr, /* I - FITS file pointer */
+ char *keyroot, /* I - root name of keywords to write */
+ int nstart, /* I - starting index number */
+ int nkey, /* I - number of keywords to write */
+ long *value, /* I - array of keyword values */
+ char *comm[], /* I - array of pointers to keyword comment */
+ int *status) /* IO - error status */
+/*
+ Write (put) an indexed array of keywords with index numbers between
+ NSTART and (NSTART + NKEY -1) inclusive. Write integer keywords
+*/
+{
+ char keyname[FLEN_KEYWORD], tcomment[FLEN_COMMENT];
+ int ii, jj, repeat, len;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ /* check if first comment string is to be repeated for all the keywords */
+ /* by looking to see if the last non-blank character is a '&' char */
+
+ repeat = 0;
+
+ if (comm)
+ {
+ len = strlen(comm[0]);
+
+ while (len > 0 && comm[0][len - 1] == ' ')
+ len--; /* ignore trailing blanks */
+
+ if (comm[0][len - 1] == '&')
+ {
+ len = minvalue(len, FLEN_COMMENT);
+ tcomment[0] = '\0';
+ strncat(tcomment, comm[0], len-1); /* don't copy the final '&' char */
+ repeat = 1;
+ }
+ }
+ else
+ {
+ repeat = 1;
+ tcomment[0] = '\0';
+ }
+
+ for (ii=0, jj=nstart; ii < nkey; ii++, jj++)
+ {
+ ffkeyn(keyroot, jj, keyname, status);
+ if (repeat)
+ ffpkyj(fptr, keyname, value[ii], tcomment, status);
+ else
+ ffpkyj(fptr, keyname, value[ii], comm[ii], status);
+
+ if (*status > 0)
+ return(*status);
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpknf( fitsfile *fptr, /* I - FITS file pointer */
+ char *keyroot, /* I - root name of keywords to write */
+ int nstart, /* I - starting index number */
+ int nkey, /* I - number of keywords to write */
+ float *value, /* I - array of keyword values */
+ int decim, /* I - number of decimals to display */
+ char *comm[], /* I - array of pointers to keyword comment */
+ int *status) /* IO - error status */
+/*
+ Write (put) an indexed array of keywords with index numbers between
+ NSTART and (NSTART + NKEY -1) inclusive. Writes fixed float values.
+*/
+{
+ char keyname[FLEN_KEYWORD], tcomment[FLEN_COMMENT];
+ int ii, jj, repeat, len;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ /* check if first comment string is to be repeated for all the keywords */
+ /* by looking to see if the last non-blank character is a '&' char */
+
+ repeat = 0;
+
+ if (comm)
+ {
+ len = strlen(comm[0]);
+
+ while (len > 0 && comm[0][len - 1] == ' ')
+ len--; /* ignore trailing blanks */
+
+ if (comm[0][len - 1] == '&')
+ {
+ len = minvalue(len, FLEN_COMMENT);
+ tcomment[0] = '\0';
+ strncat(tcomment, comm[0], len-1); /* don't copy the final '&' char */
+ repeat = 1;
+ }
+ }
+ else
+ {
+ repeat = 1;
+ tcomment[0] = '\0';
+ }
+
+ for (ii=0, jj=nstart; ii < nkey; ii++, jj++)
+ {
+ ffkeyn(keyroot, jj, keyname, status);
+ if (repeat)
+ ffpkyf(fptr, keyname, value[ii], decim, tcomment, status);
+ else
+ ffpkyf(fptr, keyname, value[ii], decim, comm[ii], status);
+
+ if (*status > 0)
+ return(*status);
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpkne( fitsfile *fptr, /* I - FITS file pointer */
+ char *keyroot, /* I - root name of keywords to write */
+ int nstart, /* I - starting index number */
+ int nkey, /* I - number of keywords to write */
+ float *value, /* I - array of keyword values */
+ int decim, /* I - number of decimals to display */
+ char *comm[], /* I - array of pointers to keyword comment */
+ int *status) /* IO - error status */
+/*
+ Write (put) an indexed array of keywords with index numbers between
+ NSTART and (NSTART + NKEY -1) inclusive. Writes exponential float values.
+*/
+{
+ char keyname[FLEN_KEYWORD], tcomment[FLEN_COMMENT];
+ int ii, jj, repeat, len;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ /* check if first comment string is to be repeated for all the keywords */
+ /* by looking to see if the last non-blank character is a '&' char */
+
+ repeat = 0;
+
+ if (comm)
+ {
+ len = strlen(comm[0]);
+
+ while (len > 0 && comm[0][len - 1] == ' ')
+ len--; /* ignore trailing blanks */
+
+ if (comm[0][len - 1] == '&')
+ {
+ len = minvalue(len, FLEN_COMMENT);
+ tcomment[0] = '\0';
+ strncat(tcomment, comm[0], len-1); /* don't copy the final '&' char */
+ repeat = 1;
+ }
+ }
+ else
+ {
+ repeat = 1;
+ tcomment[0] = '\0';
+ }
+
+ for (ii=0, jj=nstart; ii < nkey; ii++, jj++)
+ {
+ ffkeyn(keyroot, jj, keyname, status);
+ if (repeat)
+ ffpkye(fptr, keyname, value[ii], decim, tcomment, status);
+ else
+ ffpkye(fptr, keyname, value[ii], decim, comm[ii], status);
+
+ if (*status > 0)
+ return(*status);
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpkng( fitsfile *fptr, /* I - FITS file pointer */
+ char *keyroot, /* I - root name of keywords to write */
+ int nstart, /* I - starting index number */
+ int nkey, /* I - number of keywords to write */
+ double *value, /* I - array of keyword values */
+ int decim, /* I - number of decimals to display */
+ char *comm[], /* I - array of pointers to keyword comment */
+ int *status) /* IO - error status */
+/*
+ Write (put) an indexed array of keywords with index numbers between
+ NSTART and (NSTART + NKEY -1) inclusive. Writes fixed double values.
+*/
+{
+ char keyname[FLEN_KEYWORD], tcomment[FLEN_COMMENT];
+ int ii, jj, repeat, len;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ /* check if first comment string is to be repeated for all the keywords */
+ /* by looking to see if the last non-blank character is a '&' char */
+
+ repeat = 0;
+
+ if (comm)
+ {
+ len = strlen(comm[0]);
+
+ while (len > 0 && comm[0][len - 1] == ' ')
+ len--; /* ignore trailing blanks */
+
+ if (comm[0][len - 1] == '&')
+ {
+ len = minvalue(len, FLEN_COMMENT);
+ tcomment[0] = '\0';
+ strncat(tcomment, comm[0], len-1); /* don't copy the final '&' char */
+ repeat = 1;
+ }
+ }
+ else
+ {
+ repeat = 1;
+ tcomment[0] = '\0';
+ }
+
+ for (ii=0, jj=nstart; ii < nkey; ii++, jj++)
+ {
+ ffkeyn(keyroot, jj, keyname, status);
+ if (repeat)
+ ffpkyg(fptr, keyname, value[ii], decim, tcomment, status);
+ else
+ ffpkyg(fptr, keyname, value[ii], decim, comm[ii], status);
+
+ if (*status > 0)
+ return(*status);
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpknd( fitsfile *fptr, /* I - FITS file pointer */
+ char *keyroot, /* I - root name of keywords to write */
+ int nstart, /* I - starting index number */
+ int nkey, /* I - number of keywords to write */
+ double *value, /* I - array of keyword values */
+ int decim, /* I - number of decimals to display */
+ char *comm[], /* I - array of pointers to keyword comment */
+ int *status) /* IO - error status */
+/*
+ Write (put) an indexed array of keywords with index numbers between
+ NSTART and (NSTART + NKEY -1) inclusive. Writes exponential double values.
+*/
+{
+ char keyname[FLEN_KEYWORD], tcomment[FLEN_COMMENT];
+ int ii, jj, repeat, len;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ /* check if first comment string is to be repeated for all the keywords */
+ /* by looking to see if the last non-blank character is a '&' char */
+
+ repeat = 0;
+
+ if (comm)
+ {
+ len = strlen(comm[0]);
+
+ while (len > 0 && comm[0][len - 1] == ' ')
+ len--; /* ignore trailing blanks */
+
+ if (comm[0][len - 1] == '&')
+ {
+ len = minvalue(len, FLEN_COMMENT);
+ tcomment[0] = '\0';
+ strncat(tcomment, comm[0], len-1); /* don't copy the final '&' char */
+ repeat = 1;
+ }
+ }
+ else
+ {
+ repeat = 1;
+ tcomment[0] = '\0';
+ }
+
+ for (ii=0, jj=nstart; ii < nkey; ii++, jj++)
+ {
+ ffkeyn(keyroot, jj, keyname, status);
+ if (repeat)
+ ffpkyd(fptr, keyname, value[ii], decim, tcomment, status);
+ else
+ ffpkyd(fptr, keyname, value[ii], decim, comm[ii], status);
+
+ if (*status > 0)
+ return(*status);
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffptdm( fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - column number */
+ int naxis, /* I - number of axes in the data array */
+ long naxes[], /* I - length of each data axis */
+ int *status) /* IO - error status */
+/*
+ write the TDIMnnn keyword describing the dimensionality of a column
+*/
+{
+ char keyname[FLEN_KEYWORD], tdimstr[FLEN_VALUE], comm[FLEN_COMMENT];
+ char value[80], message[81];
+ int ii;
+ long totalpix = 1, repeat;
+ tcolumn *colptr;
+
+ if (*status > 0)
+ return(*status);
+
+ if (colnum < 1 || colnum > 999)
+ {
+ ffpmsg("column number is out of range 1 - 999 (ffptdm)");
+ return(*status = BAD_COL_NUM);
+ }
+
+ if (naxis < 1)
+ {
+ ffpmsg("naxis is less than 1 (ffptdm)");
+ return(*status = BAD_DIMEN);
+ }
+
+ /* reset position to the correct HDU if necessary */
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+ else if ((fptr->Fptr)->datastart == DATA_UNDEFINED)
+ if ( ffrdef(fptr, status) > 0) /* rescan header */
+ return(*status);
+
+ if ( (fptr->Fptr)->hdutype != BINARY_TBL)
+ {
+ ffpmsg(
+ "Error: The TDIMn keyword is only allowed in BINTABLE extensions (ffptdm)");
+ return(*status = NOT_BTABLE);
+ }
+
+ strcpy(tdimstr, "("); /* start constructing the TDIM value */
+
+ for (ii = 0; ii < naxis; ii++)
+ {
+ if (ii > 0)
+ strcat(tdimstr, ","); /* append the comma separator */
+
+ if (naxes[ii] < 0)
+ {
+ ffpmsg("one or more TDIM values are less than 0 (ffptdm)");
+ return(*status = BAD_TDIM);
+ }
+
+ sprintf(value, "%ld", naxes[ii]);
+ strcat(tdimstr, value); /* append the axis size */
+
+ totalpix *= naxes[ii];
+ }
+
+ colptr = (fptr->Fptr)->tableptr; /* point to first column structure */
+ colptr += (colnum - 1); /* point to the specified column number */
+
+ if ((long) colptr->trepeat != totalpix)
+ {
+ /* There is an apparent inconsistency between TDIMn and TFORMn. */
+ /* The colptr->trepeat value may be out of date, so re-read */
+ /* the TFORMn keyword to be sure. */
+
+ ffkeyn("TFORM", colnum, keyname, status); /* construct TFORMn name */
+ ffgkys(fptr, keyname, value, NULL, status); /* read TFORMn keyword */
+ ffbnfm(value, NULL, &repeat, NULL, status); /* parse the repeat count */
+
+ if (*status > 0 || repeat != totalpix)
+ {
+ sprintf(message,
+ "column vector length, %ld, does not equal TDIMn array size, %ld",
+ (long) colptr->trepeat, totalpix);
+ ffpmsg(message);
+ return(*status = BAD_TDIM);
+ }
+ }
+
+ strcat(tdimstr, ")" ); /* append the closing parenthesis */
+
+ strcpy(comm, "size of the multidimensional array");
+ ffkeyn("TDIM", colnum, keyname, status); /* construct TDIMn name */
+ ffpkys(fptr, keyname, tdimstr, comm, status); /* write the keyword */
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffphps( fitsfile *fptr, /* I - FITS file pointer */
+ int bitpix, /* I - number of bits per data value pixel */
+ int naxis, /* I - number of axes in the data array */
+ long naxes[], /* I - length of each data axis */
+ int *status) /* IO - error status */
+/*
+ write STANDARD set of required primary header keywords
+*/
+{
+ int simple = 1; /* does file conform to FITS standard? 1/0 */
+ long pcount = 0; /* number of group parameters (usually 0) */
+ long gcount = 1; /* number of random groups (usually 1 or 0) */
+ int extend = 1; /* may FITS file have extensions? */
+
+ ffphpr(fptr, simple, bitpix, naxis, naxes, pcount, gcount, extend, status);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffphpr( fitsfile *fptr, /* I - FITS file pointer */
+ int simple, /* I - does file conform to FITS standard? 1/0 */
+ int bitpix, /* I - number of bits per data value pixel */
+ int naxis, /* I - number of axes in the data array */
+ long naxes[], /* I - length of each data axis */
+ long pcount, /* I - number of group parameters (usually 0) */
+ long gcount, /* I - number of random groups (usually 1 or 0) */
+ int extend, /* I - may FITS file have extensions? */
+ int *status) /* IO - error status */
+/*
+ write required primary header keywords
+*/
+{
+ int ii;
+ long longbitpix;
+ char name[FLEN_KEYWORD], comm[FLEN_COMMENT], message[FLEN_ERRMSG];
+
+ if (*status > 0)
+ return(*status);
+
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+
+ if ((fptr->Fptr)->headend != (fptr->Fptr)->headstart[(fptr->Fptr)->curhdu] )
+ return(*status = HEADER_NOT_EMPTY);
+
+ if (naxis != 0) /* never try to compress a null image */
+ {
+ if ( (fptr->Fptr)->request_compress_type )
+ {
+ /* write header for a compressed image */
+ imcomp_init_table(fptr, (fptr->Fptr)->request_compress_type,
+ bitpix, naxis, naxes, (fptr->Fptr)->request_tilesize, 32,
+ (fptr->Fptr)->request_rice_nbits, status);
+ return(*status);
+ }
+ }
+
+ if ((fptr->Fptr)->curhdu == 0)
+ { /* write primary array header */
+ if (simple)
+ strcpy(comm, "file does conform to FITS standard");
+ else
+ strcpy(comm, "file does not conform to FITS standard");
+
+ ffpkyl(fptr, "SIMPLE", simple, comm, status);
+ }
+ else
+ { /* write IMAGE extension header */
+ strcpy(comm, "IMAGE extension");
+ ffpkys(fptr, "XTENSION", "IMAGE", comm, status);
+ }
+
+ longbitpix = bitpix;
+
+ /* test for the 2 special cases that represent unsigned integers */
+ if (longbitpix == USHORT_IMG)
+ longbitpix = SHORT_IMG;
+ else if (longbitpix == ULONG_IMG)
+ longbitpix = LONG_IMG;
+
+ if (longbitpix != BYTE_IMG && longbitpix != SHORT_IMG &&
+ longbitpix != LONG_IMG && longbitpix != LONGLONG_IMG &&
+ longbitpix != FLOAT_IMG && longbitpix != DOUBLE_IMG)
+ {
+ sprintf(message,
+ "Illegal value for BITPIX keyword: %d", bitpix);
+ ffpmsg(message);
+ return(*status = BAD_BITPIX);
+ }
+
+ strcpy(comm, "number of bits per data pixel");
+ if (ffpkyj(fptr, "BITPIX", longbitpix, comm, status) > 0)
+ return(*status);
+
+ if (naxis < 0 || naxis > 999)
+ {
+ sprintf(message,
+ "Illegal value for NAXIS keyword: %d", naxis);
+ ffpmsg(message);
+ return(*status = BAD_NAXIS);
+ }
+
+ strcpy(comm, "number of data axes");
+ ffpkyj(fptr, "NAXIS", naxis, comm, status);
+
+ strcpy(comm, "length of data axis ");
+ for (ii = 0; ii < naxis; ii++)
+ {
+ if (naxes[ii] < 0)
+ {
+ sprintf(message,
+ "Illegal value for NAXIS%d keyword: %ld", ii + 1, naxes[ii]);
+ ffpmsg(message);
+ return(*status = BAD_NAXES);
+ }
+
+ sprintf(&comm[20], "%d", ii + 1);
+ ffkeyn("NAXIS", ii + 1, name, status);
+ ffpkyj(fptr, name, naxes[ii], comm, status);
+ }
+
+ if ((fptr->Fptr)->curhdu == 0) /* the primary array */
+ {
+ if (extend)
+ {
+ /* only write EXTEND keyword if value = true */
+ strcpy(comm, "FITS dataset may contain extensions");
+ ffpkyl(fptr, "EXTEND", extend, comm, status);
+ }
+
+ if (pcount < 0)
+ {
+ ffpmsg("pcount value is less than 0");
+ return(*status = BAD_PCOUNT);
+ }
+
+ else if (gcount < 1)
+ {
+ ffpmsg("gcount value is less than 1");
+ return(*status = BAD_GCOUNT);
+ }
+
+ else if (pcount > 0 || gcount > 1)
+ {
+ /* only write these keyword if non-standard values */
+ strcpy(comm, "random group records are present");
+ ffpkyl(fptr, "GROUPS", 1, comm, status);
+
+ strcpy(comm, "number of random group parameters");
+ ffpkyj(fptr, "PCOUNT", pcount, comm, status);
+
+ strcpy(comm, "number of random groups");
+ ffpkyj(fptr, "GCOUNT", gcount, comm, status);
+ }
+
+ /* write standard block of self-documentating comments */
+ ffprec(fptr,
+ "COMMENT FITS (Flexible Image Transport System) format is defined in 'Astronomy",
+ status);
+ ffprec(fptr,
+ "COMMENT and Astrophysics', volume 376, page 359; bibcode: 2001A&A...376..359H",
+ status);
+ }
+
+ else /* an IMAGE extension */
+
+ { /* image extension; cannot have random groups */
+ if (pcount != 0)
+ {
+ ffpmsg("image extensions must have pcount = 0");
+ *status = BAD_PCOUNT;
+ }
+
+ else if (gcount != 1)
+ {
+ ffpmsg("image extensions must have gcount = 1");
+ *status = BAD_GCOUNT;
+ }
+
+ else
+ {
+ strcpy(comm, "required keyword; must = 0");
+ ffpkyj(fptr, "PCOUNT", pcount, comm, status);
+
+ strcpy(comm, "required keyword; must = 1");
+ ffpkyj(fptr, "GCOUNT", gcount, comm, status);
+ }
+ }
+
+ /* Write the BSCALE and BZERO keywords, if an unsigned integer image */
+ if (bitpix == USHORT_IMG)
+ {
+ strcpy(comm, "offset data range to that of unsigned short");
+ ffpkyg(fptr, "BZERO", 32768., 0, comm, status);
+ strcpy(comm, "default scaling factor");
+ ffpkyg(fptr, "BSCALE", 1.0, 0, comm, status);
+ }
+ else if (bitpix == ULONG_IMG)
+ {
+ strcpy(comm, "offset data range to that of unsigned long");
+ ffpkyg(fptr, "BZERO", 2147483648., 0, comm, status);
+ strcpy(comm, "default scaling factor");
+ ffpkyg(fptr, "BSCALE", 1.0, 0, comm, status);
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffphtb(fitsfile *fptr, /* I - FITS file pointer */
+ long naxis1, /* I - width of row in the table */
+ long naxis2, /* I - number of rows in the table */
+ int tfields, /* I - number of columns in the table */
+ char **ttype, /* I - name of each column */
+ long *tbcol, /* I - byte offset in row to each column */
+ char **tform, /* I - value of TFORMn keyword for each column */
+ char **tunit, /* I - value of TUNITn keyword for each column */
+ char *extnm, /* I - value of EXTNAME keyword, if any */
+ int *status) /* IO - error status */
+/*
+ Put required Header keywords into the ASCII TaBle:
+*/
+{
+ int ii, ncols, gotmem = 0;
+ long rowlen;
+ char tfmt[30], name[FLEN_KEYWORD], comm[FLEN_COMMENT];
+
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+
+ if (*status > 0)
+ return(*status);
+ else if ((fptr->Fptr)->headend != (fptr->Fptr)->headstart[(fptr->Fptr)->curhdu] )
+ return(*status = HEADER_NOT_EMPTY);
+ else if (naxis1 < 0)
+ return(*status = NEG_WIDTH);
+ else if (naxis2 < 0)
+ return(*status = NEG_ROWS);
+ else if (tfields < 0 || tfields > 999)
+ return(*status = BAD_TFIELDS);
+
+ rowlen = naxis1;
+
+ if (!tbcol || !tbcol[0] || (!naxis1 && tfields)) /* spacing not defined? */
+ {
+ /* allocate mem for tbcol; malloc can have problems allocating small */
+ /* arrays, so allocate at least 20 bytes */
+
+ ncols = maxvalue(5, tfields);
+ tbcol = (long *) calloc(ncols, sizeof(long));
+
+ if (tbcol)
+ {
+ gotmem = 1;
+
+ /* calculate width of a row and starting position of each column. */
+ /* Each column will be separated by 1 blank space */
+ ffgabc(tfields, tform, 1, &rowlen, tbcol, status);
+ }
+ }
+ ffpkys(fptr, "XTENSION", "TABLE", "ASCII table extension", status);
+ ffpkyj(fptr, "BITPIX", 8, "8-bit ASCII characters", status);
+ ffpkyj(fptr, "NAXIS", 2, "2-dimensional ASCII table", status);
+ ffpkyj(fptr, "NAXIS1", rowlen, "width of table in characters", status);
+ ffpkyj(fptr, "NAXIS2", naxis2, "number of rows in table", status);
+ ffpkyj(fptr, "PCOUNT", 0, "no group parameters (required keyword)", status);
+ ffpkyj(fptr, "GCOUNT", 1, "one data group (required keyword)", status);
+ ffpkyj(fptr, "TFIELDS", tfields, "number of fields in each row", status);
+
+ for (ii = 0; ii < tfields; ii++) /* loop over every column */
+ {
+ if ( *(ttype[ii]) ) /* optional TTYPEn keyword */
+ {
+ sprintf(comm, "label for field %3d", ii + 1);
+ ffkeyn("TTYPE", ii + 1, name, status);
+ ffpkys(fptr, name, ttype[ii], comm, status);
+ }
+
+ if (tbcol[ii] < 1 || tbcol[ii] > rowlen)
+ *status = BAD_TBCOL;
+
+ sprintf(comm, "beginning column of field %3d", ii + 1);
+ ffkeyn("TBCOL", ii + 1, name, status);
+ ffpkyj(fptr, name, tbcol[ii], comm, status);
+
+ strcpy(tfmt, tform[ii]); /* required TFORMn keyword */
+ ffupch(tfmt);
+ ffkeyn("TFORM", ii + 1, name, status);
+ ffpkys(fptr, name, tfmt, "Fortran-77 format of field", status);
+
+ if (tunit)
+ {
+ if (*tunit && *(tunit[ii]) ) /* optional TUNITn keyword */
+ {
+ ffkeyn("TUNIT", ii + 1, name, status);
+ ffpkys(fptr, name, tunit[ii], "physical unit of field", status) ;
+ }
+ }
+
+ if (*status > 0)
+ break; /* abort loop on error */
+ }
+
+ if (extnm)
+ {
+ if (extnm[0]) /* optional EXTNAME keyword */
+ ffpkys(fptr, "EXTNAME", extnm,
+ "name of this ASCII table extension", status);
+ }
+
+ if (*status > 0)
+ ffpmsg("Failed to write ASCII table header keywords (ffphtb)");
+
+ if (gotmem)
+ free(tbcol);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffphbn(fitsfile *fptr, /* I - FITS file pointer */
+ long naxis2, /* I - number of rows in the table */
+ int tfields, /* I - number of columns in the table */
+ char **ttype, /* I - name of each column */
+ char **tform, /* I - value of TFORMn keyword for each column */
+ char **tunit, /* I - value of TUNITn keyword for each column */
+ char *extnm, /* I - value of EXTNAME keyword, if any */
+ long pcount, /* I - size of the variable length heap area */
+ int *status) /* IO - error status */
+/*
+ Put required Header keywords into the Binary Table:
+*/
+{
+ int ii, datatype, iread = 0;
+ long repeat, width, naxis1;
+
+ char tfmt[30], name[FLEN_KEYWORD], comm[FLEN_COMMENT];
+ char *cptr;
+
+ if (*status > 0)
+ return(*status);
+
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+
+ if ((fptr->Fptr)->headend != (fptr->Fptr)->headstart[(fptr->Fptr)->curhdu] )
+ return(*status = HEADER_NOT_EMPTY);
+ else if (naxis2 < 0)
+ return(*status = NEG_ROWS);
+ else if (pcount < 0)
+ return(*status = BAD_PCOUNT);
+ else if (tfields < 0 || tfields > 999)
+ return(*status = BAD_TFIELDS);
+
+ ffpkys(fptr, "XTENSION", "BINTABLE", "binary table extension", status);
+ ffpkyj(fptr, "BITPIX", 8, "8-bit bytes", status);
+ ffpkyj(fptr, "NAXIS", 2, "2-dimensional binary table", status);
+
+ naxis1 = 0;
+ for (ii = 0; ii < tfields; ii++) /* sum the width of each field */
+ {
+ ffbnfm(tform[ii], &datatype, &repeat, &width, status);
+
+ if (datatype == TSTRING)
+ naxis1 += repeat; /* one byte per char */
+ else if (datatype == TBIT)
+ naxis1 += (repeat + 7) / 8;
+ else if (datatype > 0)
+ naxis1 += repeat * (datatype / 10);
+ else /* this is a variable length descriptor (neg. datatype) */
+ naxis1 += 8;
+
+ if (*status > 0)
+ break; /* abort loop on error */
+ }
+
+ ffpkyj(fptr, "NAXIS1", naxis1, "width of table in bytes", status);
+ ffpkyj(fptr, "NAXIS2", naxis2, "number of rows in table", status);
+
+ /*
+ the initial value of PCOUNT (= size of the variable length array heap)
+ should always be zero. If any variable length data is written, then
+ the value of PCOUNT will be updated when the HDU is closed
+ */
+ ffpkyj(fptr, "PCOUNT", 0, "size of special data area", status);
+ ffpkyj(fptr, "GCOUNT", 1, "one data group (required keyword)", status);
+ ffpkyj(fptr, "TFIELDS", tfields, "number of fields in each row", status);
+
+ for (ii = 0; ii < tfields; ii++) /* loop over every column */
+ {
+ if ( *(ttype[ii]) ) /* optional TTYPEn keyword */
+ {
+ sprintf(comm, "label for field %3d", ii + 1);
+ ffkeyn("TTYPE", ii + 1, name, status);
+ ffpkys(fptr, name, ttype[ii], comm, status);
+ }
+
+ strcpy(tfmt, tform[ii]); /* required TFORMn keyword */
+ ffupch(tfmt);
+
+ ffkeyn("TFORM", ii + 1, name, status);
+ strcpy(comm, "data format of field");
+
+ ffbnfm(tfmt, &datatype, &repeat, &width, status);
+
+ if (datatype == TSTRING)
+ {
+ strcat(comm, ": ASCII Character");
+
+ /* Do sanity check to see if an ASCII table format was used, */
+ /* e.g., 'A8' instead of '8A', or a bad unit width eg '8A9'. */
+ /* Don't want to return an error status, so write error into */
+ /* the keyword comment. */
+
+ cptr = strchr(tfmt,'A');
+ cptr++;
+
+ if (cptr)
+ iread = sscanf(cptr,"%ld", &width);
+
+ if (iread == 1 && (width > repeat))
+ {
+ if (repeat == 1)
+ strcpy(comm, "ERROR?? USING ASCII TABLE SYNTAX BY MISTAKE??");
+ else
+ strcpy(comm, "rAw FORMAT ERROR! UNIT WIDTH w > COLUMN WIDTH r");
+ }
+ }
+ else if (datatype == TBIT)
+ strcat(comm, ": BIT");
+ else if (datatype == TBYTE)
+ strcat(comm, ": BYTE");
+ else if (datatype == TLOGICAL)
+ strcat(comm, ": 1-byte LOGICAL");
+ else if (datatype == TSHORT)
+ strcat(comm, ": 2-byte INTEGER");
+ else if (datatype == TUSHORT)
+ strcat(comm, ": 2-byte INTEGER");
+ else if (datatype == TLONG)
+ strcat(comm, ": 4-byte INTEGER");
+ else if (datatype == TLONGLONG)
+ strcat(comm, ": 8-byte INTEGER");
+ else if (datatype == TULONG)
+ strcat(comm, ": 4-byte INTEGER");
+ else if (datatype == TFLOAT)
+ strcat(comm, ": 4-byte REAL");
+ else if (datatype == TDOUBLE)
+ strcat(comm, ": 8-byte DOUBLE");
+ else if (datatype == TCOMPLEX)
+ strcat(comm, ": COMPLEX");
+ else if (datatype == TDBLCOMPLEX)
+ strcat(comm, ": DOUBLE COMPLEX");
+ else if (datatype < 0)
+ strcat(comm, ": variable length array");
+
+ if (abs(datatype) == TSBYTE) /* signed bytes */
+ {
+ /* Replace the 'S' with an 'B' in the TFORMn code */
+ cptr = tfmt;
+ while (*cptr != 'S')
+ cptr++;
+
+ *cptr = 'B';
+ ffpkys(fptr, name, tfmt, comm, status);
+
+ /* write the TZEROn and TSCALn keywords */
+ ffkeyn("TZERO", ii + 1, name, status);
+ strcpy(comm, "offset for signed bytes");
+
+ ffpkyg(fptr, name, -128., 0, comm, status);
+
+ ffkeyn("TSCAL", ii + 1, name, status);
+ strcpy(comm, "data are not scaled");
+ ffpkyg(fptr, name, 1., 0, comm, status);
+ }
+ else if (abs(datatype) == TUSHORT)
+ {
+ /* Replace the 'U' with an 'I' in the TFORMn code */
+ cptr = tfmt;
+ while (*cptr != 'U')
+ cptr++;
+
+ *cptr = 'I';
+ ffpkys(fptr, name, tfmt, comm, status);
+
+ /* write the TZEROn and TSCALn keywords */
+ ffkeyn("TZERO", ii + 1, name, status);
+ strcpy(comm, "offset for unsigned integers");
+
+ ffpkyg(fptr, name, 32768., 0, comm, status);
+
+ ffkeyn("TSCAL", ii + 1, name, status);
+ strcpy(comm, "data are not scaled");
+ ffpkyg(fptr, name, 1., 0, comm, status);
+ }
+ else if (abs(datatype) == TULONG)
+ {
+ /* Replace the 'V' with an 'J' in the TFORMn code */
+ cptr = tfmt;
+ while (*cptr != 'V')
+ cptr++;
+
+ *cptr = 'J';
+ ffpkys(fptr, name, tfmt, comm, status);
+
+ /* write the TZEROn and TSCALn keywords */
+ ffkeyn("TZERO", ii + 1, name, status);
+ strcpy(comm, "offset for unsigned integers");
+
+ ffpkyg(fptr, name, 2147483648., 0, comm, status);
+
+ ffkeyn("TSCAL", ii + 1, name, status);
+ strcpy(comm, "data are not scaled");
+ ffpkyg(fptr, name, 1., 0, comm, status);
+ }
+ else
+ {
+ ffpkys(fptr, name, tfmt, comm, status);
+ }
+
+ if (tunit)
+ {
+ if (*tunit && *(tunit[ii]) ) /* optional TUNITn keyword */
+ {
+ ffkeyn("TUNIT", ii + 1, name, status);
+ ffpkys(fptr, name, tunit[ii],
+ "physical unit of field", status);
+ }
+ }
+
+ if (*status > 0)
+ break; /* abort loop on error */
+ }
+
+ if (extnm)
+ {
+ if (extnm[0]) /* optional EXTNAME keyword */
+ ffpkys(fptr, "EXTNAME", extnm,
+ "name of this binary table extension", status);
+ }
+
+ if (*status > 0)
+ ffpmsg("Failed to write binary table header keywords (ffphbn)");
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffi2c(long ival, /* I - value to be converted to a string */
+ char *cval, /* O - character string representation of the value */
+ int *status) /* IO - error status */
+/*
+ convert value to a null-terminated formatted string.
+*/
+{
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ cval[0] = '\0';
+
+ if (sprintf(cval, "%ld", ival) < 0)
+ {
+ ffpmsg("Error in ffi2c converting integer to string");
+ *status = BAD_I2C;
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffl2c(int lval, /* I - value to be converted to a string */
+ char *cval, /* O - character string representation of the value */
+ int *status) /* IO - error status ) */
+/*
+ convert logical value to a null-terminated formatted string. If the
+ input value == 0, then the output character is the letter F, else
+ the output character is the letter T. The output string is null terminated.
+*/
+{
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ if (lval)
+ strcpy(cval,"T");
+ else
+ strcpy(cval,"F");
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffs2c(char *instr, /* I - null terminated input string */
+ char *outstr, /* O - null terminated quoted output string */
+ int *status) /* IO - error status */
+/*
+ convert an input string to a quoted string. Leading spaces
+ are significant. FITS string keyword values must be at least
+ 8 chars long so pad out string with spaces if necessary.
+ Example: km/s ==> 'km/s '
+ Single quote characters in the input string will be replace by
+ two single quote characters. e.g., o'brian ==> 'o''brian'
+*/
+{
+ size_t len, ii, jj;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ if (!instr) /* a null input pointer?? */
+ {
+ strcpy(outstr, "''"); /* a null FITS string */
+ return(*status);
+ }
+
+ outstr[0] = '\''; /* start output string with a quote */
+
+ len = strlen(instr);
+ if (len > 68)
+ len = 68; /* limit input string to 68 chars */
+
+ for (ii=0, jj=1; ii < len && jj < 69; ii++, jj++)
+ {
+ outstr[jj] = instr[ii]; /* copy each char from input to output */
+ if (instr[ii] == '\'')
+ {
+ jj++;
+ outstr[jj]='\''; /* duplicate any apostrophies in the input */
+ }
+ }
+
+ for (; jj < 9; jj++) /* pad string so it is at least 8 chars long */
+ outstr[jj] = ' ';
+
+ if (jj == 70) /* only occurs if the last char of string was a quote */
+ outstr[69] = '\0';
+ else
+ {
+ outstr[jj] = '\''; /* append closing quote character */
+ outstr[jj+1] = '\0'; /* terminate the string */
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffr2f(float fval, /* I - value to be converted to a string */
+ int decim, /* I - number of decimal places to display */
+ char *cval, /* O - character string representation of the value */
+ int *status) /* IO - error status */
+/*
+ convert float value to a null-terminated F format string
+*/
+{
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ cval[0] = '\0';
+
+ if (decim < 0)
+ {
+ ffpmsg("Error in ffr2f: no. of decimal places < 0");
+ return(*status = BAD_DECIM);
+ }
+
+ if (sprintf(cval, "%.*f", decim, fval) < 0)
+ {
+ ffpmsg("Error in ffr2f converting float to string");
+ *status = BAD_F2C;
+ }
+
+ /* test if output string is 'NaN', 'INDEF', or 'INF' */
+ if (strchr(cval, 'N'))
+ {
+ ffpmsg("Error in ffr2f: float value is a NaN or INDEF");
+ *status = BAD_F2C;
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffr2e(float fval, /* I - value to be converted to a string */
+ int decim, /* I - number of decimal places to display */
+ char *cval, /* O - character string representation of the value */
+ int *status) /* IO - error status */
+/*
+ convert float value to a null-terminated exponential format string
+*/
+{
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ cval[0] = '\0';
+
+ if (decim < 0)
+ { /* use G format if decim is negative */
+ if ( sprintf(cval, "%.*G", -decim, fval) < 0)
+ {
+ ffpmsg("Error in ffr2e converting float to string");
+ *status = BAD_F2C;
+ }
+ else
+ {
+ /* test if E format was used, and there is no displayed decimal */
+ if ( !strchr(cval, '.') && strchr(cval,'E') )
+ {
+ /* reformat value with a decimal point and single zero */
+ if ( sprintf(cval, "%.1E", fval) < 0)
+ {
+ ffpmsg("Error in ffr2e converting float to string");
+ *status = BAD_F2C;
+ }
+
+ return(*status);
+ }
+ }
+ }
+ else
+ {
+ if ( sprintf(cval, "%.*E", decim, fval) < 0)
+ {
+ ffpmsg("Error in ffr2e converting float to string");
+ *status = BAD_F2C;
+ }
+ }
+
+ if (*status <= 0)
+ {
+ /* test if output string is 'NaN', 'INDEF', or 'INF' */
+ if (strchr(cval, 'N'))
+ {
+ ffpmsg("Error in ffr2e: float value is a NaN or INDEF");
+ *status = BAD_F2C;
+ }
+ else if ( !strchr(cval, '.') && !strchr(cval,'E') )
+ {
+ /* add decimal point if necessary to distinquish from integer */
+ strcat(cval, ".");
+ }
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffd2f(double dval, /* I - value to be converted to a string */
+ int decim, /* I - number of decimal places to display */
+ char *cval, /* O - character string representation of the value */
+ int *status) /* IO - error status */
+/*
+ convert double value to a null-terminated F format string
+*/
+{
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ cval[0] = '\0';
+
+ if (decim < 0)
+ {
+ ffpmsg("Error in ffd2f: no. of decimal places < 0");
+ return(*status = BAD_DECIM);
+ }
+
+ if (sprintf(cval, "%.*f", decim, dval) < 0)
+ {
+ ffpmsg("Error in ffd2f converting double to string");
+ *status = BAD_F2C;
+ }
+
+ /* test if output string is 'NaN', 'INDEF', or 'INF' */
+ if (strchr(cval, 'N'))
+ {
+ ffpmsg("Error in ffd2f: double value is a NaN or INDEF");
+ *status = BAD_F2C;
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffd2e(double dval, /* I - value to be converted to a string */
+ int decim, /* I - number of decimal places to display */
+ char *cval, /* O - character string representation of the value */
+ int *status) /* IO - error status */
+/*
+ convert double value to a null-terminated exponential format string.
+*/
+{
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ cval[0] = '\0';
+
+ if (decim < 0)
+ { /* use G format if decim is negative */
+ if ( sprintf(cval, "%.*G", -decim, dval) < 0)
+ {
+ ffpmsg("Error in ffd2e converting float to string");
+ *status = BAD_F2C;
+ }
+ else
+ {
+ /* test if E format was used, and there is no displayed decimal */
+ if ( !strchr(cval, '.') && strchr(cval,'E') )
+ {
+ /* reformat value with a decimal point and single zero */
+ if ( sprintf(cval, "%.1E", dval) < 0)
+ {
+ ffpmsg("Error in ffd2e converting float to string");
+ *status = BAD_F2C;
+ }
+
+ return(*status);
+ }
+ }
+ }
+ else
+ {
+ if ( sprintf(cval, "%.*E", decim, dval) < 0)
+ {
+ ffpmsg("Error in ffd2e converting float to string");
+ *status = BAD_F2C;
+ }
+ }
+
+ if (*status <= 0)
+ {
+ /* test if output string is 'NaN', 'INDEF', or 'INF' */
+ if (strchr(cval, 'N'))
+ {
+ ffpmsg("Error in ffd2e: double value is a NaN or INDEF");
+ *status = BAD_F2C;
+ }
+ else if ( !strchr(cval, '.') && !strchr(cval,'E') )
+ {
+ /* add decimal point if necessary to distinquish from integer */
+ strcat(cval, ".");
+ }
+ }
+
+ return(*status);
+}
+
diff --git a/pkg/tbtables/cfitsio/quantize.c b/pkg/tbtables/cfitsio/quantize.c
new file mode 100644
index 00000000..a9c06e76
--- /dev/null
+++ b/pkg/tbtables/cfitsio/quantize.c
@@ -0,0 +1,613 @@
+/*
+ The following code was written by Richard White at STScI and made
+ available for use in CFITSIO in July 1999.
+*/
+
+# include <stdio.h>
+# include <stdlib.h>
+# include <math.h>
+
+#include "fitsio2.h"
+
+/* nearest integer function */
+# define NINT(x) ((x >= 0.) ? (int) (x + 0.5) : (int) (x - 0.5))
+# define SORT_CUTOFF 100 /* used by xMedian */
+# define NELEM 5 /* used by xMedian */
+
+#define NULL_VALUE -2147483647 /* value used to represent undefined pixels */
+#define N_RESERVED_VALUES 1 /* number of reserved values, starting with */
+ /* and including NULL_VALUE. These values */
+ /* may not be used to represent the quantized */
+ /* and scaled floating point pixel values */
+
+/* factor to convert from median deviation to rms */
+# define MEDIAN_TO_RMS 1.4826
+
+/* more than this many standard deviations from the mean is an outlier */
+# define SIGMA_CLIP 5.
+
+# define NITER 3 /* number of sigma-clipping iterations */
+
+static float xMedian (float [], int);
+static void InsertionSort (float x[], int);
+static int FqCompare (const void *, const void *);
+static void FqMean (float [], int, double *, double *);
+
+
+/*---------------------------------------------------------------------------*/
+/* this routine used to be called 'quantize' (WDP) */
+
+int fits_quantize_float (float fdata[], int nx, float in_null_value,
+ int noise_bits, int idata[], double *bscale,
+ double *bzero, int *iminval, int *imaxval) {
+
+/* arguments:
+float fdata[] i: array of image pixels to be compressed
+int nx i: length of fdata array
+float in_null_value i: value used to represent undefined pixels in fdata
+int noise_bits i: quantization level (number of bits)
+int idata[] o: values of fdata after applying bzero and bscale
+double bscale o: scale factor
+double bzero o: zero offset
+int iminval o: minimum quantized value that is returned
+int imaxval o: maximum quantized value that is returned
+
+The function value will be one if the input fdata were copied to idata;
+in this case the parameters bscale and bzero can be used to convert back to
+nearly the original floating point values: fdata ~= idata * bscale + bzero.
+If the function value is zero, the data were not copied to idata.
+*/
+
+ float *diff; /* difference array */
+ int ndiff; /* size of diff array */
+ int intflag; /* true if data are really integer */
+ int i, j, iter; /* loop indices */
+ int anynulls = 0; /* set if fdata contains any null values */
+ int nshift;
+ int first_nonnull = 0;
+ double mean, stdev; /* mean and RMS of differences */
+ double minval = 0., maxval = 0.; /* min & max of fdata */
+ double delta; /* bscale, 1 in idata = delta in fdata */
+ double zeropt; /* bzero */
+ double median; /* median of diff array */
+ double temp;
+
+ if (nx <= 1) {
+ *bscale = 1.;
+ *bzero = 0.;
+ return (0);
+ }
+
+ *iminval = INT32_MAX;
+ *imaxval = INT32_MIN;
+
+ /* Check to see if data are "floating point integer." */
+ /* This also catches the case where all the pixels are null */
+ intflag = 1; /* initial value */
+ for (i = 0; i < nx; i++) {
+ if (fdata[i] == in_null_value) {
+ idata[i] = NULL_VALUE;
+ anynulls = 1;
+ }
+ else if (fdata[i] > INT32_MAX ||
+ fdata[i] < NULL_VALUE + N_RESERVED_VALUES) {
+ intflag = 0; /* not integer */
+ break;
+ }
+ else {
+ idata[i] = (int)(fdata[i] + 0.5);
+ *iminval = minvalue(idata[i], *iminval);
+ *imaxval = maxvalue(idata[i], *imaxval);
+
+ if (idata[i] != fdata[i]) {
+ intflag = 0; /* not integer */
+ break;
+ }
+ }
+ }
+ if (intflag) { /* data are "floating point integer" */
+ if (anynulls) {
+ /* Shift the range of values so they lie close to NULL_VALUE. */
+ /* This will make the compression more efficient. */
+ nshift = *iminval - NULL_VALUE - N_RESERVED_VALUES;
+ for (i = 0; i < nx; i++) {
+ if (idata[i] != NULL_VALUE) {
+ idata[i] -= nshift;
+ }
+ }
+ *iminval = *iminval - nshift;
+ *imaxval = *imaxval - nshift;
+ *bscale = 1.;
+ *bzero = (double) nshift;
+ }
+ else {
+ /* there were no null values, so no need to shift the range */
+ *bscale = 1.;
+ *bzero = 0.;
+ }
+ return (1);
+ }
+
+ /* data are not "floating point integer"; need to quantize them */
+
+ /* find first non-null pixel, and initialize min and max values */
+ for (i = 0; i < nx; i++) {
+ if (fdata[i] != in_null_value) {
+ minval = fdata[i];
+ maxval = fdata[i];
+ first_nonnull = i;
+ break;
+ }
+ }
+
+ /* allocate temporary buffer for differences */
+ ndiff = nx - first_nonnull - 1;
+ if ((diff = malloc (ndiff * sizeof (float))) == NULL) {
+ ffpmsg("Out of memory in 'fits_quantize_float'.");
+ return (0);
+ }
+
+ /* calc ABS difference between successive non-null pixels */
+ j = first_nonnull;
+ ndiff = 0;
+ for (i = j + 1 ; i < nx; i++) {
+ if (fdata[i] != in_null_value) {
+ diff[ndiff] = fabs (fdata[i] - fdata[j]);
+ j = i;
+ ndiff++;
+ minval = minvalue(minval, fdata[i]);
+ maxval = maxvalue(maxval, fdata[i]);
+ }
+ }
+
+ /* check if there were any null values */
+ if (ndiff + 1 == nx)
+ anynulls = 0;
+ else
+ anynulls = 1;
+
+ /* use median of absolute deviations */
+
+ median = xMedian (diff, ndiff);
+ stdev = median * MEDIAN_TO_RMS;
+ /* substitute sigma-clipping if median is zero */
+ if (stdev == 0.0) {
+
+ /* calculate differences between non-null pixels */
+ j = first_nonnull;
+ ndiff = 0;
+ for (i = j + 1 ; i < nx; i++) {
+ if (fdata[i] != in_null_value) {
+ diff[ndiff] = fdata[i] - fdata[j];
+ j = i;
+ ndiff++;
+ }
+ }
+
+ FqMean (diff, ndiff, &mean, &stdev);
+
+ for (iter = 0; iter < NITER; iter++) {
+ j = 0;
+ for (i = 0; i < ndiff; i++) {
+ if (fabs (diff[i] - mean) < SIGMA_CLIP * stdev) {
+ if (j < i)
+ diff[j] = diff[i];
+ j++;
+ }
+ }
+ if (j == ndiff)
+ break;
+ ndiff = j;
+ FqMean (diff, ndiff, &mean, &stdev);
+ }
+ }
+ free (diff);
+
+ delta = stdev / pow (2., (double)noise_bits);
+ if (delta == 0. && ndiff > 0)
+ return (0); /* Zero variance in differences! Don't quantize. */
+
+ /* check that the range of quantized levels is not > range of int */
+ if ((maxval - minval) / delta > 2. * 2147483647. - N_RESERVED_VALUES )
+ return (0); /* don't quantize */
+
+ if (!anynulls) { /* don't have to check for nulls */
+ /* return all positive values, if possible since some */
+ /* compression algorithms either only work for positive integers, */
+ /* or are more efficient. */
+ if ((maxval - minval) / delta < 2147483647. - N_RESERVED_VALUES )
+ {
+ zeropt = minval;
+ }
+ else
+ {
+ /* center the quantized levels around zero */
+ zeropt = (minval + maxval) / 2.;
+ }
+
+ for (i = 0; i < nx; i++) {
+ temp = (fdata[i] - zeropt) / delta;
+ idata[i] = NINT (temp);
+ }
+ }
+ else {
+ /* data contains null values; shift the range to be */
+ /* close to the value used to represent null values */
+ zeropt = minval - delta * (NULL_VALUE + N_RESERVED_VALUES);
+ for (i = 0; i < nx; i++) {
+ if (fdata[i] != in_null_value) {
+ temp = (fdata[i] - zeropt) / delta;
+ idata[i] = NINT (temp);
+ }
+ else
+ idata[i] = NULL_VALUE;
+ }
+ }
+
+ /* calc min and max values */
+ temp = (minval - zeropt) / delta;
+ *iminval = NINT (temp);
+ temp = (maxval - zeropt) / delta;
+ *imaxval = NINT (temp);
+
+ *bscale = delta;
+ *bzero = zeropt;
+
+ return (1); /* yes, data have been quantized */
+}
+
+/*---------------------------------------------------------------------------*/
+int fits_quantize_double (double fdata[], int nx, double in_null_value,
+ int noise_bits, int idata[], double *bscale,
+ double *bzero, int *iminval, int *imaxval) {
+
+/* arguments:
+double fdata[] i: array of image pixels to be compressed
+int nx i: length of fdata array
+double in_null_value i: value used to represent undefined pixels in fdata
+int noise_bits i: quantization level (number of bits)
+int idata[] o: values of fdata after applying bzero and bscale
+double bscale o: scale factor
+double bzero o: zero offset
+int imaxval o: maximum quantized value that is returned
+int iminval o: minimum quantized value that is returned
+
+The function value will be one if the input fdata were copied to idata;
+in this case the parameters bscale and bzero can be used to convert back to
+nearly the original floating point values: fdata ~= idata * bscale + bzero.
+If the function value is zero, the data were not copied to idata.
+*/
+
+ float *diff; /* difference array */
+ int ndiff; /* size of diff array */
+ int intflag; /* true if data are really integer */
+ int i, j, iter; /* loop indices */
+ int anynulls = 0; /* set if fdata contains any null values */
+ int nshift;
+ int first_nonnull = 0;
+ double mean, stdev; /* mean and RMS of differences */
+ double minval = 0., maxval = 0.; /* min & max of fdata */
+ double delta; /* bscale, 1 in idata = delta in fdata */
+ double zeropt; /* bzero */
+ double median; /* median of diff array */
+ double temp;
+
+ if (nx <= 1) {
+ *bscale = 1.;
+ *bzero = 0.;
+ return (0);
+ }
+
+ *iminval = INT32_MAX;
+ *imaxval = INT32_MIN;
+
+ /* Check to see if data are "floating point integer." */
+ /* This also catches the case where all the pixels are null */
+ intflag = 1; /* initial value */
+ for (i = 0; i < nx; i++) {
+ if (fdata[i] == in_null_value) {
+ idata[i] = NULL_VALUE;
+ anynulls = 1;
+ }
+ else if (fdata[i] > INT32_MAX ||
+ fdata[i] < NULL_VALUE + N_RESERVED_VALUES) {
+ intflag = 0; /* not integer */
+ break;
+ }
+ else {
+ idata[i] = (int)(fdata[i] + 0.5);
+ *iminval = minvalue(idata[i], *iminval);
+ *imaxval = maxvalue(idata[i], *imaxval);
+
+ if (idata[i] != fdata[i]) {
+ intflag = 0; /* not integer */
+ break;
+ }
+ }
+ }
+ if (intflag) { /* data are "floating point integer" */
+ if (anynulls) {
+ /* Shift the range of values so they lie close to NULL_VALUE. */
+ /* This will make the compression more efficient. */
+ nshift = *iminval - NULL_VALUE - N_RESERVED_VALUES;
+ for (i = 0; i < nx; i++) {
+ if (idata[i] != NULL_VALUE) {
+ idata[i] -= nshift;
+ }
+ }
+ *iminval = *iminval - nshift;
+ *imaxval = *imaxval - nshift;
+ *bscale = 1.;
+ *bzero = (double) nshift;
+ }
+ else {
+ /* there were no null values, so no need to shift the range */
+ *bscale = 1.;
+ *bzero = 0.;
+ }
+ return (1);
+ }
+
+ /* data are not "floating point integer"; need to quantize them */
+
+ /* find first non-null pixel, and initialize min and max values */
+ for (i = 0; i < nx; i++) {
+ if (fdata[i] != in_null_value) {
+ minval = fdata[i];
+ maxval = fdata[i];
+ first_nonnull = i;
+ break;
+ }
+ }
+
+ /* allocate temporary buffer for differences */
+ ndiff = nx - first_nonnull - 1;
+ if ((diff = malloc (ndiff * sizeof (float))) == NULL) {
+ ffpmsg("Out of memory in 'fits_quantize_double'.");
+ return (0);
+ }
+
+ /* calc ABS difference between successive non-null pixels */
+ j = first_nonnull;
+ ndiff = 0;
+ for (i = j + 1 ; i < nx; i++) {
+ if (fdata[i] != in_null_value) {
+ diff[ndiff] = fabs (fdata[i] - fdata[j]);
+ j = i;
+ ndiff++;
+ minval = minvalue(minval, fdata[i]);
+ maxval = maxvalue(maxval, fdata[i]);
+ }
+ }
+
+ /* check if there were any null values */
+ if (ndiff + 1 == nx)
+ anynulls = 0;
+ else
+ anynulls = 1;
+
+ /* use median of absolute deviations */
+
+ median = xMedian (diff, ndiff);
+ stdev = median * MEDIAN_TO_RMS;
+ /* substitute sigma-clipping if median is zero */
+ if (stdev == 0.0) {
+
+ /* calculate differences between non-null pixels */
+ j = first_nonnull;
+ ndiff = 0;
+ for (i = j + 1 ; i < nx; i++) {
+ if (fdata[i] != in_null_value) {
+ diff[ndiff] = fdata[i] - fdata[j];
+ j = i;
+ ndiff++;
+ }
+ }
+
+ FqMean (diff, ndiff, &mean, &stdev);
+
+ for (iter = 0; iter < NITER; iter++) {
+ j = 0;
+ for (i = 0; i < ndiff; i++) {
+ if (fabs (diff[i] - mean) < SIGMA_CLIP * stdev) {
+ if (j < i)
+ diff[j] = diff[i];
+ j++;
+ }
+ }
+ if (j == ndiff)
+ break;
+ ndiff = j;
+ FqMean (diff, ndiff, &mean, &stdev);
+ }
+ }
+ free (diff);
+
+ delta = stdev / pow (2., (double)noise_bits);
+ if (delta == 0. && ndiff > 0)
+ return (0); /* Zero variance in differences! Don't quantize. */
+
+ /* check that the range of quantized levels is not > range of int */
+ if ((maxval - minval) / delta > 2. * 2147483647 - N_RESERVED_VALUES )
+ return (0); /* don't quantize */
+ if (!anynulls) { /* don't have to check for nulls */
+ /* center the quantized levels around zero */
+ zeropt = (minval + maxval) / 2.;
+ for (i = 0; i < nx; i++) {
+ temp = (fdata[i] - zeropt) / delta;
+ idata[i] = NINT (temp);
+ }
+ }
+ else {
+ /* data contains null values; shift the range to be */
+ /* close to the value used to represent null values */
+ zeropt = minval - delta * (NULL_VALUE + N_RESERVED_VALUES);
+ for (i = 0; i < nx; i++) {
+ if (fdata[i] != in_null_value) {
+ temp = (fdata[i] - zeropt) / delta;
+ idata[i] = NINT (temp);
+ }
+ else
+ idata[i] = NULL_VALUE;
+ }
+ }
+
+ /* calc min and max values */
+ temp = (minval - zeropt) / delta;
+ *iminval = NINT (temp);
+ temp = (maxval - zeropt) / delta;
+ *imaxval = NINT (temp);
+
+ *bscale = delta;
+ *bzero = zeropt;
+
+ return (1); /* yes, data have been quantized */
+}
+/*---------------------------------------------------------------------------*/
+/* This computes the mean and standard deviation. */
+
+static void FqMean (float diff[], int ndiff, double *mean, double *stdev) {
+
+ int i;
+ double sum, sumsq;
+ double m; /* mean */
+ double xn; /* = ndiff */
+ double temp;
+
+ if (ndiff < 2) {
+ if (ndiff < 1)
+ *mean = 0.;
+ else
+ *mean = diff[0];
+ *stdev = 0.;
+ return;
+ }
+
+ xn = (double)ndiff;
+
+ sum = 0.;
+ sumsq = 0.;
+ for (i = 0; i < ndiff; i++) {
+ sum += diff[i];
+ sumsq += (diff[i] * diff[i]);
+ }
+
+ m = sum / xn;
+ *mean = m;
+ temp = (sumsq / xn - m*m) * xn;
+ if (temp <= 0)
+ *stdev = 0.;
+ else
+ *stdev = sqrt (temp / (xn-1.));
+}
+
+/*---------------------------------------------------------------------------*/
+/* This returns an approximation to the median.
+ The input array will be clobbered.
+*/
+
+static float xMedian (float x[], int n) {
+
+/* arguments:
+float x[] io: the array (will be scrambled and possibly modified)
+int n i: number of elements in x (modified locally)
+*/
+
+ int i, j;
+ int next_n;
+ int npix;
+ int done;
+ float median = 0.;
+
+ if (n < 1) {
+ ffpmsg("xMedian: no data");
+ return (0.);
+ }
+ if (n == 1)
+ return (x[0]);
+ if (n == 2)
+ return ((x[0] + x[1]) / 2.);
+
+ done = 0;
+ while (!done) {
+
+ if (n < SORT_CUTOFF) {
+ qsort (x, n, sizeof (float), FqCompare);
+ if (n / 2 * 2 == n)
+ median = (x[n/2-1] + x[n/2]) / 2.;
+ else
+ median = x[n/2];
+ return (median);
+ }
+
+ /* ignore trailing groups of less than three elements */
+ next_n = (n + NELEM-3) / NELEM;
+
+ for (j = 0; j < next_n; j++) {
+
+ i = j * NELEM;
+ npix = minvalue (NELEM, n - j*NELEM);
+
+ InsertionSort (&x[i], npix);
+
+ switch (npix) {
+ case 1:
+ median = x[i];
+ break;
+ case 2:
+ median = (x[i] + x[i+1]) / 2.;
+ break;
+ case 3:
+ median = x[i+1];
+ break;
+ case 4:
+ median = (x[i+1] + x[i+2]) / 2.;
+ break;
+ case 5: /* NELEM = 5 */
+ median = x[i+2];
+ break;
+ default:
+ ffpmsg("npix should be 1..5");
+ }
+
+ x[j] = median;
+ }
+
+ if (next_n <= 1)
+ done = 1;
+ else
+ n = next_n;
+ }
+
+ return (x[0]);
+}
+/*---------------------------------------------------------------------------*/
+static void InsertionSort (float x[], int n) {
+
+ float a;
+ int i, j;
+
+ for (j = 1; j < n; j++) {
+
+ a = x[j];
+ i = j - 1;
+ while (i >= 0 && x[i] > a) {
+ x[i+1] = x[i];
+ i--;
+ }
+ x[i+1] = a;
+ }
+}
+/*---------------------------------------------------------------------------*/
+static int FqCompare (const void *vp, const void *vq) {
+
+ const float *p = vp;
+ const float *q = vq;
+
+ if (*p > *q)
+ return (1);
+ else if (*p < *q)
+ return (-1);
+ else
+ return (0);
+}
diff --git a/pkg/tbtables/cfitsio/quick.ps b/pkg/tbtables/cfitsio/quick.ps
new file mode 100644
index 00000000..7503d841
--- /dev/null
+++ b/pkg/tbtables/cfitsio/quick.ps
@@ -0,0 +1,3850 @@
+%!PS-Adobe-2.0
+%%Creator: dvips(k) 5.86 Copyright 1999 Radical Eye Software
+%%Title: quick.dvi
+%%Pages: 41
+%%PageOrder: Ascend
+%%BoundingBox: 0 0 596 842
+%%EndComments
+%DVIPSWebPage: (www.radicaleye.com)
+%DVIPSCommandLine: dvips -N0 quick
+%DVIPSParameters: dpi=600, compressed
+%DVIPSSource: TeX output 2003.06.23:1300
+%%BeginProcSet: texc.pro
+%!
+/TeXDict 300 dict def TeXDict begin/N{def}def/B{bind def}N/S{exch}N/X{S
+N}B/A{dup}B/TR{translate}N/isls false N/vsize 11 72 mul N/hsize 8.5 72
+mul N/landplus90{false}def/@rigin{isls{[0 landplus90{1 -1}{-1 1}ifelse 0
+0 0]concat}if 72 Resolution div 72 VResolution div neg scale isls{
+landplus90{VResolution 72 div vsize mul 0 exch}{Resolution -72 div hsize
+mul 0}ifelse TR}if Resolution VResolution vsize -72 div 1 add mul TR[
+matrix currentmatrix{A A round sub abs 0.00001 lt{round}if}forall round
+exch round exch]setmatrix}N/@landscape{/isls true N}B/@manualfeed{
+statusdict/manualfeed true put}B/@copies{/#copies X}B/FMat[1 0 0 -1 0 0]
+N/FBB[0 0 0 0]N/nn 0 N/IEn 0 N/ctr 0 N/df-tail{/nn 8 dict N nn begin
+/FontType 3 N/FontMatrix fntrx N/FontBBox FBB N string/base X array
+/BitMaps X/BuildChar{CharBuilder}N/Encoding IEn N end A{/foo setfont}2
+array copy cvx N load 0 nn put/ctr 0 N[}B/sf 0 N/df{/sf 1 N/fntrx FMat N
+df-tail}B/dfs{div/sf X/fntrx[sf 0 0 sf neg 0 0]N df-tail}B/E{pop nn A
+definefont setfont}B/Cw{Cd A length 5 sub get}B/Ch{Cd A length 4 sub get
+}B/Cx{128 Cd A length 3 sub get sub}B/Cy{Cd A length 2 sub get 127 sub}
+B/Cdx{Cd A length 1 sub get}B/Ci{Cd A type/stringtype ne{ctr get/ctr ctr
+1 add N}if}B/id 0 N/rw 0 N/rc 0 N/gp 0 N/cp 0 N/G 0 N/CharBuilder{save 3
+1 roll S A/base get 2 index get S/BitMaps get S get/Cd X pop/ctr 0 N Cdx
+0 Cx Cy Ch sub Cx Cw add Cy setcachedevice Cw Ch true[1 0 0 -1 -.1 Cx
+sub Cy .1 sub]/id Ci N/rw Cw 7 add 8 idiv string N/rc 0 N/gp 0 N/cp 0 N{
+rc 0 ne{rc 1 sub/rc X rw}{G}ifelse}imagemask restore}B/G{{id gp get/gp
+gp 1 add N A 18 mod S 18 idiv pl S get exec}loop}B/adv{cp add/cp X}B
+/chg{rw cp id gp 4 index getinterval putinterval A gp add/gp X adv}B/nd{
+/cp 0 N rw exit}B/lsh{rw cp 2 copy get A 0 eq{pop 1}{A 255 eq{pop 254}{
+A A add 255 and S 1 and or}ifelse}ifelse put 1 adv}B/rsh{rw cp 2 copy
+get A 0 eq{pop 128}{A 255 eq{pop 127}{A 2 idiv S 128 and or}ifelse}
+ifelse put 1 adv}B/clr{rw cp 2 index string putinterval adv}B/set{rw cp
+fillstr 0 4 index getinterval putinterval adv}B/fillstr 18 string 0 1 17
+{2 copy 255 put pop}for N/pl[{adv 1 chg}{adv 1 chg nd}{1 add chg}{1 add
+chg nd}{adv lsh}{adv lsh nd}{adv rsh}{adv rsh nd}{1 add adv}{/rc X nd}{
+1 add set}{1 add clr}{adv 2 chg}{adv 2 chg nd}{pop nd}]A{bind pop}
+forall N/D{/cc X A type/stringtype ne{]}if nn/base get cc ctr put nn
+/BitMaps get S ctr S sf 1 ne{A A length 1 sub A 2 index S get sf div put
+}if put/ctr ctr 1 add N}B/I{cc 1 add D}B/bop{userdict/bop-hook known{
+bop-hook}if/SI save N @rigin 0 0 moveto/V matrix currentmatrix A 1 get A
+mul exch 0 get A mul add .99 lt{/QV}{/RV}ifelse load def pop pop}N/eop{
+SI restore userdict/eop-hook known{eop-hook}if showpage}N/@start{
+userdict/start-hook known{start-hook}if pop/VResolution X/Resolution X
+1000 div/DVImag X/IEn 256 array N 2 string 0 1 255{IEn S A 360 add 36 4
+index cvrs cvn put}for pop 65781.76 div/vsize X 65781.76 div/hsize X}N
+/p{show}N/RMat[1 0 0 -1 0 0]N/BDot 260 string N/Rx 0 N/Ry 0 N/V{}B/RV/v{
+/Ry X/Rx X V}B statusdict begin/product where{pop false[(Display)(NeXT)
+(LaserWriter 16/600)]{A length product length le{A length product exch 0
+exch getinterval eq{pop true exit}if}{pop}ifelse}forall}{false}ifelse
+end{{gsave TR -.1 .1 TR 1 1 scale Rx Ry false RMat{BDot}imagemask
+grestore}}{{gsave TR -.1 .1 TR Rx Ry scale 1 1 false RMat{BDot}
+imagemask grestore}}ifelse B/QV{gsave newpath transform round exch round
+exch itransform moveto Rx 0 rlineto 0 Ry neg rlineto Rx neg 0 rlineto
+fill grestore}B/a{moveto}B/delta 0 N/tail{A/delta X 0 rmoveto}B/M{S p
+delta add tail}B/b{S p tail}B/c{-4 M}B/d{-3 M}B/e{-2 M}B/f{-1 M}B/g{0 M}
+B/h{1 M}B/i{2 M}B/j{3 M}B/k{4 M}B/w{0 rmoveto}B/l{p -4 w}B/m{p -3 w}B/n{
+p -2 w}B/o{p -1 w}B/q{p 1 w}B/r{p 2 w}B/s{p 3 w}B/t{p 4 w}B/x{0 S
+rmoveto}B/y{3 2 roll p a}B/bos{/SS save N}B/eos{SS restore}B end
+
+%%EndProcSet
+TeXDict begin 39158280 55380996 1000 600 600 (quick.dvi)
+@start
+%DVIPSBitmapFont: Fa cmsy10 10.95 4
+/Fa 4 107 df<EB0FFCEB3FFF90B512C0000314F04880488048804880A2481580A3B712
+C0AA6C1580A36C1500A26C5C6C5C6C5C6C5CC614C0013F90C7FCEB0FFC22227BA72D>15
+D<153FEC03FFEC0FE0EC3F80EC7E00495A5C495AA2495AB3AA130F5C131F495A91C7FC13
+FEEA03F8EA7FE048C8FCEA7FE0EA03F8EA00FE133F806D7E130F801307B3AA6D7EA26D7E
+80EB007EEC3F80EC0FE0EC03FFEC003F205B7AC32D>102 D<12FCEAFFC0EA07F0EA01FC
+EA007E6D7E131F6D7EA26D7EB3AA801303806D7E1300147FEC1FC0EC07FEEC00FFEC07FE
+EC1FC0EC7F0014FC1301495A5C13075CB3AA495AA2495A133F017EC7FC485AEA07F0EAFF
+C000FCC8FC205B7AC32D>I<126012F0B3B3B3B3B11260045B76C319>106
+D E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fb cmbx12 12 41
+/Fb 41 122 df<B612F8A91D097F9A25>45 D<EA07C0EA1FF0EA3FF8EA7FFCEAFFFEA7EA
+7FFCEA3FF8EA1FF0EA07C00F0F788E1F>I<EE01C0EE03E01607A2160F17C0161F1780A2
+163F17005E167EA216FE5E15015EA215035EA215075E150F5EA2151F5E153F93C7FCA25D
+157E15FE5DA214015D14035DA214075D140F5DA2141F5D143F92C8FCA25C147EA214FE5C
+13015CA213035C13075CA2130F5C131F5CA2133F91C9FC5B137EA213FE5B12015BA21203
+5BA212075B120F5BA2121F5B123F90CAFCA25A127E12FE5AA25A12782B647ACA38>I<EC
+03C01407141F147FEB03FF133FB6FCA413C3EA0003B3B3ADB712FCA5264177C038>49
+D<ECFFE0010F13FE013F6D7E90B612E0000315F82607FC0313FE3A0FE0007FFFD81F806D
+138048C7000F13C0488001C015E001F07F00FF6E13F07F17F881A46C5A6C5A6C5AC9FC17
+F05DA217E05D17C04B13804B1300A2ED1FFC4B5A5E4B5A4B5A4A90C7FC4A5A4A5AEC0FF0
+4A5AEC3F804AC7127814FE495A494814F8D907E014F0495A495A49C8FC017C1401491403
+48B7FC4816E05A5A5A5A5AB8FC17C0A42D417BC038>I<ECFFF0010713FF011F14C0017F
+14F049C66C7ED803F8EB3FFED807E06D7E81D80FF86D138013FE001F16C07FA66C5A6C48
+15806C485BC814005D5E4B5A4B5A4B5A4A5B020F1380902607FFFEC7FC15F815FF16C090
+C713F0ED3FFCED0FFEEEFF80816F13C017E0A26F13F0A217F8A3EA0FC0EA3FF0487EA248
+7EA217F0A25D17E06C5A494913C05BD83F80491380D81FF0491300D80FFEEBFFFE6CB612
+F800015D6C6C14C0011F49C7FC010113E02D427BC038>I<163FA25E5E5D5DA25D5D5D5D
+A25D92B5FCEC01F7EC03E7140715C7EC0F87EC1F07143E147E147C14F8EB01F0EB03E013
+0714C0EB0F80EB1F00133E5BA25B485A485A485A120F5B48C7FC123E5A12FCB91280A5C8
+000F90C7FCAC027FB61280A531417DC038>I<0007150301E0143F01FFEB07FF91B6FC5E
+5E5E5E5E16804BC7FC5D15E092C8FC01C0C9FCAAEC3FF001C1B5FC01C714C001DF14F090
+39FFE03FFC9138000FFE01FC6D7E01F06D13804915C0497F6C4815E0C8FC6F13F0A317F8
+A4EA0F80EA3FE0487E12FF7FA317F05B5D6C4815E05B007EC74813C0123E003F4A1380D8
+1FC0491300D80FF0495AD807FEEBFFFC6CB612F0C65D013F1480010F01FCC7FC010113C0
+2D427BC038>I<4AB47E021F13F0027F13FC49B6FC01079038807F8090390FFC001FD93F
+F014C04948137F4948EBFFE048495A5A1400485A120FA248486D13C0EE7F80EE1E00003F
+92C7FCA25B127FA2EC07FC91381FFF8000FF017F13E091B512F89039F9F01FFC9039FBC0
+07FE9039FF8003FF17804A6C13C05B6F13E0A24915F0A317F85BA4127FA5123FA217F07F
+121FA2000F4A13E0A26C6C15C06D4913806C018014006C6D485A6C9038E01FFC6DB55A01
+1F5C010714C0010191C7FC9038003FF02D427BC038>I<121E121F13FC90B712FEA45A17
+FC17F817F017E017C0A2481680007EC8EA3F00007C157E5E00785D15014B5A00F84A5A48
+4A5A5E151FC848C7FC157E5DA24A5A14035D14074A5AA2141F5D143FA2147F5D14FFA25B
+A35B92C8FCA35BA55BAA6D5A6D5A6D5A2F447AC238>I<DCFFF01470031F01FF14F04AB6
+EAE0010207EDF803023FEDFE0791B539E001FF0F4949C7EA3F9F010701F0EC0FFF4901C0
+804990C87E4948814948814948167F4849163F4849161F5A4A160F485B19074890CAFC19
+035A5BA2007F1801A34994C7FC12FFAE127F7F1AF0A2123FA27F6C18011AE06C7F19036C
+6D17C06E16077E6C6DEE0F806C6DEE1F006D6C5E6D6C167E6D6C6C5D6D6D4A5A6D01F0EC
+07F0010101FEEC1FE06D903AFFF001FF80023F90B6C7FC020715FC020115F0DA001F1480
+030001F8C8FC44467AC451>67 D<B9FC18F018FE727E19E026003FFEC7001F13F805017F
+9438003FFF060F7F727F727F727F84737E737EA2737EA2737EA21B80A2851BC0A51BE0AD
+1BC0A51B8061A21B006162193F624F5A19FF624E5B06075B4E5B063F90C7FC4DB45A050F
+13F8BA5A19C04EC8FC18F095C9FC4B447CC356>I<BA12F8A485D8001F90C71201EF003F
+180F180318011800A2197E193EA3191EA21778A285A405F890C7FCA316011603161F92B5
+FCA5ED001F160316011600A2F101E01778A2F103C0A494C7FC1907A21A80A2190FA2191F
+A2193FF17F0061601807181F4DB5FCBBFC61A443447DC34A>I<BA1280A419C026003FFE
+C7121F1701EF007F183F181F180F180719E01803A31801A3EE01E0F000F0A419001603A3
+1607160F167F91B6FCA59138FE007F160F16071603A31601A693C9FCAFB712F0A53C447C
+C346>I<B7D88003B612FEA526003FFEC9EBF800B3A791B9FCA54AC9FCB3AAB7D88003B6
+12FEA54F447CC358>72 D<B712E0A5D8001F90C7FCB3B3B3A4B712E0A523447DC32A>I<
+B76C0103B512F8A526003FFEC93807E0004F5A4F5A077EC7FC614E5A4E5A4E5AF01F804E
+C8FC187E604D5AEF07F0EF0FC04D5A4DC9FC177E4C5AEE03F04C5A4C5A4C7EEE7FF04C7E
+5D4B7F4B7F4B7FED3F3FDB7E1F7F03FC806E486C7F4B7E4B6C7F0380804B6C7F4A7F717E
+84717F83717F85717F83717F85717F187F727E86727F84727F86727F84B76C90B612FCA5
+4E447CC358>75 D<B64BB512FE8181A281D8003F6D91C7EA780081013D7F81133C6E7E6E
+7F6E7F6E7F6E7F82806E7F6E7F6F7E6F7F83816F7F6F7F6F7F6F7F6F7F8382707F707F70
+7F707F8482707F707F717E7113807113C019E0837113F07113F87113FC7113FE19FF8472
+13F884848484A28484197F193F191FA2190F1907B61603190119001A78A24F447CC358>
+78 D<923807FFC092B512FE0207ECFFC0021F15F091267FFE0013FC902601FFF0EB1FFF
+01070180010313C04990C76C7FD91FFC6E6C7E49486F7E49486F7E01FF8348496F7E4849
+6F1380A248496F13C0A24890C96C13E0A24819F04982003F19F8A3007F19FC49177FA400
+FF19FEAD007F19FC6D17FFA3003F19F8A26D5E6C19F0A26E5D6C19E0A26C6D4B13C06C19
+806E5D6C6D4B13006C6D4B5A6D6C4B5A6D6C4B5A6D6C4A5B6D01C001075B6D01F0011F5B
+010101FE90B5C7FC6D90B65A023F15F8020715C002004AC8FC030713C047467AC454>I<
+B812F8EFFFC018F818FE727ED8001F90C7003F13E005037F05007F727E727E727EA28684
+A286A762A24E90C7FCA24E5A61187F943801FFF005075B053F138092B7C8FC18F818E018
+F892C77FEF3FFF050F7F717F717FA2717FA2717FA785A61B0F85A2187F73131F72141EB7
+00E06DEB803E72EBE0FC72EBFFF8060114F0726C13E0CC0007138050457DC354>82
+D<003FBA12E0A59026FE000FEB8003D87FE09338003FF049171F90C71607A2007E180300
+7C1801A300781800A400F819F8481978A5C81700B3B3A20107B8FCA545437CC24E>84
+D<B76C010FB512F8A526003FFEC93803E000B3B3A9011F17076280190F6D606F151F6D95
+C7FC6D6D5D197E6D6D5D6D6D1403DA7FFC4A5A6EB4EC3FF0020F9039F003FFE06E90B612
+80020193C8FC6E6C14FC030F14E09226007FFEC9FC4D457CC356>I<903801FFE0011F13
+FE017F6D7E48B612E03A03FE007FF84848EB1FFC6D6D7E486C6D7EA26F7FA36F7F6C5A6C
+5AEA00F090C7FCA40203B5FC91B6FC1307013F13F19038FFFC01000313E0000F1380381F
+FE00485A5B127F5B12FF5BA35DA26D5B6C6C5B4B13F0D83FFE013EEBFFC03A1FFF80FC7F
+0007EBFFF86CECE01FC66CEB8007D90FFCC9FC322F7DAD36>97 D<EB7FC0B5FCA512037E
+B1ED0FF892B57E02C314E002CF14F89139DFC03FFC9139FF000FFE02FCEB03FF4A6D1380
+4A15C04A6D13E05CEF7FF0A218F8173FA318FCAC18F8A2177F18F0A3EFFFE06E15C06E5B
+6E491380027C491300496C495A903AFC1FC07FFC496CB512F0D9F00314C049C691C7FCC8
+EA1FF036467DC43E>I<EE03FEED07FFA5ED001F160FB1EC3FE0903803FFFC010FEBFF8F
+013F14CF9039FFF807FF48EBC00148903880007F4890C7123F4848141F49140F121F485A
+A3127F5BA212FFAC127FA37F123FA26C6C141FA26C6C143F0007157F6C6C91B5FC6CD9C0
+0314FC6C9038F01FEF6DB5128F011FEBFE0F010713F89026007FC0EBF80036467CC43E>
+100 D<EC3FF80103B57E010F14E0013F8090397FF83FF89039FFC007FC48496C7E48496C
+7E48486D1380485A001FED7FC05B003FED3FE0A2127F5B17F0161F12FFA290B7FCA401F0
+C9FCA5127FA27FA2123F17F06C7E16016C6C15E06C6C14036C6DEB07C06C6DEB0F806C01
+F0EB3F0090397FFE01FE011FB55A010714F0010114C09026001FFEC7FC2C2F7DAD33>I<
+DAFFE0137E010F9039FE03FF80013FEBFF8F90B812C048D9C07F133F489038001FF84848
+EB0FFC4848903907FE1F80001F9238FF0F00496D90C7FCA2003F82A8001F93C7FCA26D5B
+000F5D6C6C495A6C6C495A6C9038C07FF04890B55A1680D8078F49C8FC018013E0000F90
+CAFCA47F7F7F90B612C016FC6CEDFF8017E06C826C16FC7E000382000F82D81FF0C77ED8
+3FC014074848020113808248C9FC177FA46D15FF007F17006D5C6C6C4A5A6C6C4A5AD80F
+FEEC3FF83B07FFC001FFF0000190B612C06C6C92C7FC010F14F8D9007F90C8FC32427DAC
+38>103 D<137C48B4FC4813804813C0A24813E0A56C13C0A26C13806C1300EA007C90C7
+FCAAEB7FC0EA7FFFA512037EB3AFB6FCA518467CC520>105 D<EB7FC0B5FCA512037EB3
+B3B3A3B61280A519457CC420>108 D<90277F8007FEEC0FFCB590263FFFC090387FFF80
+92B5D8F001B512E002816E4880913D87F01FFC0FE03FF8913D8FC00FFE1F801FFC0003D9
+9F009026FF3E007F6C019E6D013C130F02BC5D02F86D496D7EA24A5D4A5DA34A5DB3A7B6
+0081B60003B512FEA5572D7CAC5E>I<90397F8007FEB590383FFF8092B512E0028114F8
+913987F03FFC91388F801F000390399F000FFE6C139E14BC02F86D7E5CA25CA35CB3A7B6
+0083B512FEA5372D7CAC3E>I<EC1FFC49B512C0010714F0011F14FC90397FF80FFF9026
+FFC0017F48496C7F4848C7EA3FE000078248486E7E49140F001F82A2003F82491407007F
+82A400FF1780AA007F1700A46C6C4A5AA2001F5E6D141F000F5E6C6C4A5AA26C6C6CEBFF
+E06C6D485B27007FF80F90C7FC6DB55A010F14F8010114C09026001FFCC8FC312F7DAD38
+>I<90397FC00FF8B590B57E02C314E002CF14F89139DFC03FFC9139FF001FFE000301FC
+EB07FF6C496D13804A15C04A6D13E05C7013F0A2EF7FF8A4EF3FFCACEF7FF8A318F017FF
+A24C13E06E15C06E5B6E4913806E4913006E495A9139DFC07FFC02CFB512F002C314C002
+C091C7FCED1FF092C9FCADB67EA536407DAC3E>I<90387F807FB53881FFE0028313F002
+8F13F8ED8FFC91389F1FFE000313BE6C13BC14F8A214F0ED0FFC9138E007F8ED01E092C7
+FCA35CB3A5B612E0A5272D7DAC2E>114 D<90391FFC038090B51287000314FF120F381F
+F003383FC00049133F48C7121F127E00FE140FA215077EA27F01E090C7FC13FE387FFFF0
+14FF6C14C015F06C14FC6C800003806C15806C7E010F14C0EB003F020313E0140000F014
+3FA26C141F150FA27EA26C15C06C141FA26DEB3F8001E0EB7F009038F803FE90B55A00FC
+5CD8F03F13E026E007FEC7FC232F7CAD2C>I<EB01E0A51303A41307A2130FA2131FA213
+3F137F13FF1203000F90B51280B7FCA4C601E0C7FCB3A3ED01E0A9150302F013C0137F15
+0790393FF80F8090391FFC1F006DB5FC6D13FC01015B9038003FE023407EBE2C>I<D97F
+C049B4FCB50103B5FCA50003EC000F6C81B3A85EA25EA25E7E6E491380017FD901F713FE
+9138F807E76DB512C7010F1407010313FE9026007FF0EBFC00372E7CAC3E>I<B6903803
+FFFCA5000101E09038003E006C163C80017F5D8017F8013F5D6E1301011F5D6E1303010F
+5D6E13076D5DED800F6D92C7FC15C05E6DEBE01E163E6D143CEDF07C027F1378EDF8F802
+3F5B15FD021F5B15FF6E5BA36E5BA26E90C8FCA26E5AA26E5AA21578362C7EAB3B>I<B5
+D8FE1FB539801FFFF0A500019027C0003FE0C7EA7C007114786E17F86C6F6C5C6E160101
+7F6E6C5CA26E011F1403013F6F5C6E013F1407011F6F5CA26E0179140F010F048090C7FC
+6E01F95C6D02F0EBC01E15806D902681E07F5B18E003C3157C6D9139C03FF07815E76DDA
+801F5B18F803FF14F96E9039000FFDE018FF6E486D5BA36E486D5BA26E486D90C8FCA24B
+7F02075DA26E48147C4B143C4C2C7EAB51>I<B500FE90383FFFF0A5C601F0903803E000
+6D6C495A013F4A5A6D6C49C7FC6E5B6D6C137E6DEB807C6D6D5A6DEBC1F0EDE3E06DEBF7
+C06EB45A806E90C8FC5D6E7E6E7F6E7FA24A7F4A7F8291381F3FFCEC3E1F027C7F4A6C7E
+49486C7F01036D7F49487E02C08049486C7F49C76C7E013E6E7E017E141FB500E090B512
+FCA5362C7EAB3B>I<B6903803FFFCA5000101E09038003E006C163C80017F5D8017F801
+3F5D6E1301011F5D6E1303010F5D6E13076D5DED800F6D92C7FC15C05E6DEBE01E163E6D
+143CEDF07C027F1378EDF8F8023F5B15FD021F5B15FF6E5BA36E5BA26E90C8FCA26E5AA2
+6E5AA21578A215F85D14015D001F1303D83F805B387FC007D8FFE05B140F92C9FC5C143E
+495A387FC1F8EB07F06CB45A6C5B000790CAFCEA01FC36407EAB3B>I
+E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fc cmtt10 10.95 94
+/Fc 94 127 df<121C127FEAFF80B3EA7F00B2123EC7FCA8121C127FA2EAFF80A3EA7F00
+A2121C09396DB830>33 D<00101304007C131F00FEEB3F80A26C137FA248133FB2007E14
+00007C7F003C131E00101304191C75B830>I<903907C007C0A2496C487EA8011F131FA2
+02C05BA3007FB7FCA2B81280A36C16006C5D3A007F807F80A2020090C7FCA9495BA2003F
+90B512FE4881B81280A36C1600A22701FC01FCC7FCA300031303A201F85BA76C486C5AA2
+29387DB730>I<1438147C14FCA4EB03FF011F13E090B512FC4880000780481580261FFE
+FD13C09039F0FC3FE0D83FC0131FD87F80EB0FF001001307007E15F800FE14035A1507A3
+6CEC03F0A2007F91C7FC138013C0EA3FF0EA1FFE13FF6C13FF6C14E0000114F86C6C7F01
+1F7F01037F0100148002FD13C09138FC7FE0151FED0FF015070018EC03F8127E1501B4FC
+A35AA26CEC03F07E01801307ED0FE0D83FC0131F01F0EB7FC0D81FFEB512806CB612006C
+5C6C5CC614F0013F13C0D907FEC7FCEB00FCA5147C143825477BBE30>I<D803C0EB01E0
+D80FF01303486C497E487E150F487ED87E7E495AEAFE7F5E486C133FA25E157FA24BC7FC
+6C5A5D387E7E01EA7FFED83FFC5B1403EA1FF86C48485AEA03C0C75B140FA25D141FA24A
+5AA25D147FA292C8FC5CA2495AA25C1303A25C1307A290390FF001E0ED07F84A487E011F
+497EA24A487E133F163F90267F807F1380ED7E1F14005BA25B1201A24848EB7F3F033F13
+004914FF12076F5A5B6F5A6C486D5A0001EC01E029477DBE30>I<EB07E0EB1FF8497E13
+7F497E803801FC7F497E810003131F13F0A6143F92C8FC91387F0FFF9026F87E1F138000
+0113FEEBF9FC13FB4A6C1300D9FFF013C06C13E0151F02C05BEB7F809038FF003F4892C7
+FC485C48EB807E5A15FE391FDFC0FC383F8FE014E1397F07F1F8EB03F300FEEBFBF0EB01
+FF5D7FEDC006027F130F91393F801F8015C06C137F6CEBFFE049EBF83F018701FC130026
+3FFFFBB5FC6C01F15B14E06C9038C03FFC00039038001FF8D801FCEB07E0293A7DB830>
+I<EA07C0EA0FF0EA1FF8A213FCA213FE120F1207EA007EA513FE13FCA2120113F81203EA
+07F0120FEA1FE0127FEAFFC013801300127C12380F1D70B730>I<141E147F14FF5BEB03
+FEEB07FCEB0FF0EB1FE0EB3FC0EB7F80EBFF00485A5B12035B485A120F5BA2485AA2123F
+5BA2127F90C7FCA412FEAD127FA47F123FA27F121FA26C7EA27F12076C7E7F12017F6C7E
+EB7F80EB3FC0EB1FE0EB0FF0EB07FCEB03FEEB01FF7F147F141E184771BE30>I<127812
+FE7E7F6C7E6C7EEA0FF06C7E6C7E6C7E6C7EEB7F80133F14C0131FEB0FE014F01307A2EB
+03F8A214FC1301A214FE1300A4147FAD14FEA4130114FCA2130314F8A2EB07F0A2130F14
+E0EB1FC0133F1480137FEBFF00485A485A485A485AEA3FE0485A485A90C7FC5A12781847
+78BE30>I<14E0497E497EA60038EC0380007EEC0FC0D8FF83EB3FE001C3137F9038F3F9
+FF267FFBFB13C06CB61280000FECFE00000314F86C5C6C6C13C0011F90C7FC017F13C048
+B512F04880000F14FE003FECFF80267FFBFB13C026FFF3F913E09038C3F87F0183133FD8
+7E03EB0FC00038EC0380000091C7FCA66D5A6D5A23277AAE30>I<143EA2147FAF007FB7
+FCA2B81280A36C1600A2C76CC8FCAF143EA229297DAF30>I<EA03E0EA0FF0EA1FF813FC
+EA3FFEA213FFA27EA27E1203EA007FA2137E13FEEA01FC1203EA07F8EA3FF0127FEAFFE0
+EA7F801300123C1019708B30>I<007FB612F0A2B712F8A36C15F0A225077B9E30>I<120F
+EA3FC0EA7FE0A2EAFFF0A4EA7FE0A2EA3FC0EA0F000C0C6E8B30>I<16F01501ED03F8A2
+1507A2ED0FF0A2ED1FE0A2ED3FC0A2ED7F80A2EDFF00A24A5AA25D1403A24A5AA24A5AA2
+4A5AA24A5AA24A5AA24AC7FCA2495AA25C1303A2495AA2495AA2495AA2495AA2495AA249
+C8FCA2485AA25B1203A2485AA2485AA2485AA2485AA2485AA248C9FCA25AA2127CA22547
+7BBE30>I<14FE903807FFC0497F013F13F8497F90B57E48EB83FF4848C6138049137F48
+48EB3FC04848EB1FE049130F001F15F0491307A24848EB03F8A290C712014815FCA400FE
+EC00FEAD6C14016C15FCA36D1303003F15F8A26D1307001F15F0A26D130F6C6CEB1FE0A2
+6C6CEB3FC06C6CEB7F806D13FF2601FF8313006CEBFFFE6D5B6D5B010F13E06D5BD900FE
+C7FC273A7CB830>I<EB03C0497EA2130FA2131FA2133F137F13FF1203123FB5FCA213EF
+138FEA7E0F1200B3B0003FB512F84814FCB612FEA26C14FC6C14F81F3977B830>I<EB07
+FC90383FFFC090B512F00003804814FE4880261FF80F1380263FE00113C09038C0007F48
+48EB3FE090C7121FED0FF04814075A6C15F81503A3127E1218C8FCA2150716F0150F16E0
+151F16C0153FED7F8015FF4A13005DEC07FC4A5A4A5A4A5A4A5A4A5A4990C7FC495A495A
+EB0FF0EB3FE0495A495A4890C8FC4848EB01F04848EB03F8485AEA1FE048B6FCB7FCA37E
+6C15F025397BB830>I<EB03FF013F13E090B512F84814FE4880481580260FFE0113C090
+38F0007F4848EB1FE0150F16F01507A26C5A6C5AC8FC150F16E0A2151FED3FC0157FEDFF
+8002071300903807FFFE495B5D8115FF6D1480D9000113C09138003FE0ED1FF0ED07F815
+0316FC150116FE1500A21218127EB4FCA2150116FC4814036C15F86C6C13076DEB1FF0D8
+3FF0133F3A1FFE01FFE06CB612C06C15806CECFE00C65C013F13F001031380273A7CB830
+>I<EC03FC4A7E140F141FA2143F147F157E14FEA2EB01FCEB03F8A2EB07F0A2EB0FE0EB
+1FC0A2EB3F80A2EB7F0013FEA2485A485AA2485AA2485A485AA2485AA248C7FC12FEB8FC
+1780A46C1600C8007EC7FCAA91387FFFFE91B6FCA46E5B29397DB830>I<000FB6128048
+15C05AA316800180C8FCAEEB83FF019F13C090B512F015FC8181D9FE0313809039F0007F
+C049133F0180EB1FE06CC7120F000E15F0C81207A216F81503A31218127EA2B4FC150716
+F048140F6C15E06C141F6DEB3FC06D137F3A3FE001FF80261FFC0F13006CB55A6C5C6C5C
+6C14E06C6C1380D90FFCC7FC25397BB730>I<EC0FF8EC7FFF49B51280010714E0131F49
+14F090387FF80F9039FFC007F84813803803FE005B485A4848EB03F0ED01E0484890C7FC
+5B123F5BA2127FEB000C903803FFE0010F13F8D8FF3F13FE48B6FCB7128016C09039FE00
+7FE001F8EB1FF001E0130F49EB07F849EB03FCA290C7120116FE1500A37EA46C7E15016D
+14FC121F6D1303000FEC07F86D130F6C6CEB1FF06DEB3FE03A03FF81FFC06C90B512806C
+15006D5B011F13F8010713E001011380273A7CB830>I<127CB712FC16FEA416FC48C7EA
+0FF816F0ED1FE0007CEC3FC0C8EA7F80EDFF00A24A5A4A5A5D14075D140F5D4A5AA24A5A
+A24AC7FCA25C5C13015CA213035CA213075CA4495AA6131F5CA96D5A6DC8FC273A7CB830
+>I<49B4FC011F13F0017F13FC90B57E0003ECFF804815C048010113E03A1FF8003FF049
+131FD83FC0EB07F8A24848EB03FC90C71201A56D1303003F15F86D13076C6CEB0FF06C6C
+EB1FE0D807FCEB7FC03A03FF83FF806C90B512006C6C13FC011F13F0497F90B512FE4880
+2607FE0013C0D80FF8EB3FE0D81FE0EB0FF04848EB07F8491303007F15FC90C712014815
+FE481400A66C14016C15FC6D1303003F15F86D1307D81FF0EB1FF06D133F3A0FFF01FFE0
+6C90B512C06C1580C6ECFE006D5B011F13F0010190C7FC273A7CB830>I<49B4FC010F13
+E0013F13F890B57E4880488048010113803A0FFC007FC0D81FF0EB3FE04848131F49EB0F
+F048481307A290C7EA03F85A4815FC1501A416FEA37E7E6D1303A26C6C13076C6C130F6D
+133FD80FFC13FF6CB6FC7E6C14FE6C14F9013FEBE1FC010F138190380060011400ED03F8
+A2150716F0150F000F15E0486C131F486CEB3FC0157FEDFF804A1300EC07FE391FF01FFC
+90B55A6C5C6C5C6C1480C649C7FCEB3FF0273A7CB830>I<120FEA3FC0EA7FE0A2EAFFF0
+A4EA7FE0A2EA3FC0EA0F00C7FCAF120FEA3FC0EA7FE0A2EAFFF0A4EA7FE0A2EA3FC0EA0F
+000C276EA630>I<EA03C0EA0FF0EA1FF8A2EA3FFCA4EA1FF8A2EA0FF0EA03C0C7FCAFEA
+03C0EA0FF0121F13F8123F13FCA3121FA2120F12031200120113F8120313F01207EA1FE0
+123FEA7FC0EAFF80EA7F00127E12380E3470A630>I<16F01503ED07F8151F157FEDFFF0
+14034A13C0021F138091383FFE00ECFFF8495B010713C0495BD93FFEC7FC495A3801FFF0
+485B000F13804890C8FCEA7FFC5BEAFFE05B7FEA7FF87FEA1FFF6C7F000313E06C7F3800
+7FFC6D7E90380FFF806D7F010113F06D7FEC3FFE91381FFF80020713C06E13F01400ED7F
+F8151F1507ED03F01500252F7BB230>I<007FB7FCA2B81280A36C16006C5DCBFCA7003F
+B612FE4881B81280A36C1600A229157DA530>I<1278127EB4FC13C07FEA7FF813FEEA1F
+FF6C13C000037F6C13F86C6C7EEB1FFF6D7F010313E06D7F9038007FFC6E7E91380FFF80
+6E13C0020113F080ED3FF8151F153FEDFFF05C020713C04A138091383FFE004A5A903801
+FFF0495B010F13804990C7FCEB7FFC48485A4813E0000F5B4890C8FCEA7FFE13F8EAFFE0
+5B90C9FC127E1278252F7BB230>I<EB1FFE90B512E0000314F8000F14FE488048158026
+7FF80313C09038C0007F48C7121F16E0150FA3127E151F0018EC7FC0C812FF020313804A
+13004A5AEC1FF84A5AEC7FC04A5A92C7FC495AA2495A5CA213075CA86D5A90C9FCA8EB01
+C0EB07F0A2497EA36D5AA2EB01C023397AB830>I<EC1FE0ECFFF8010313FE010F7F4914
+804914C090397FF03FE09038FF800F4890380007F0D803FC13033A07F801FBF89038F007
+FF380FE01F4A13FCEA1FC0495A003FEBFF0F903800FE07903901FC03FE007FEBF801EA7E
+03ECF000A2EAFE0700FC49137EAA00FE6D13FED87E0314FCA2ECF801D87F0114F8003FEB
+FC03903900FE07F0903880FF0F001F90387FFFE06D6C13C0EA0FE06E13803A07F007FE00
+9038F801F86C6CC7127C6CB414FE6CEB800390387FF01F6DB512FC6D14F86D14E0010314
+C00100EBFE00EC1FF0273A7CB830>I<147F4A7EA2497FA4497F14F7A401077F14E3A301
+0F7FA314C1A2011F7FA490383F80FEA590387F007FA4498049133F90B6FCA34881A39038
+FC001F00038149130FA4000781491307A2D87FFFEB7FFFB56CB51280A46C496C13002939
+7DB830>I<007FB512F0B612FE6F7E82826C813A03F8001FF815076F7E1501A26F7EA615
+015EA24B5A1507ED1FF0ED7FE090B65A5E4BC7FC6F7E16E0829039F8000FF8ED03FC6F7E
+1500167FA3EE3F80A6167F1700A25E4B5A1503ED1FFC007FB6FCB75A5E16C05E6C02FCC7
+FC29387EB730>I<91387F803C903903FFF03E49EBFC7E011F13FE49EBFFFE5B9038FFE0
+7F48EB801F3903FE000F484813075B48481303A2484813015B123F491300A2127F90C8FC
+167C16005A5AAC7E7EA2167C6D14FE123FA27F121F6D13016C6C14FCA26C6CEB03F86D13
+076C6CEB0FF03901FF801F6C9038E07FE06DB512C06D14806D1400010713FC6D13F09038
+007FC0273A7CB830>I<003FB512E04814FCB67E6F7E6C816C813A03F8007FF0ED1FF815
+0F6F7E6F7E15016F7EA2EE7F80A2163F17C0161FA4EE0FE0AC161F17C0A3163F1780A216
+7F17005E4B5A15034B5A150F4B5AED7FF0003FB65A485DB75A93C7FC6C14FC6C14E02B38
+7FB730>I<007FB7FCB81280A47ED803F8C7123FA8EE1F0093C7FCA4157C15FEA490B5FC
+A6EBF800A4157C92C8FCA5EE07C0EE0FE0A9007FB7FCB8FCA46C16C02B387EB730>I<00
+3FB712804816C0B8FCA27E7ED801FCC7121FA8EE0F8093C7FCA5153E157FA490B6FCA690
+38FC007FA4153E92C8FCAE383FFFF8487FB5FCA27E6C5B2A387EB730>I<02FF13F00103
+EBC0F8010F13F1013F13FD4913FF90B6FC4813C1EC007F4848133F4848131F49130F485A
+491307121F5B123F491303A2127F90C7FC6F5A92C8FC5A5AA892B5FC4A14805CA26C7F6C
+6D1400ED03F8A27F003F1407A27F121F6D130F120F7F6C6C131FA2D803FE133F6C6C137F
+ECC1FF6C90B5FC7F6D13FB010F13F30103EBC1F0010090C8FC293A7DB830>I<3B3FFF80
+0FFFE0486D4813F0B56C4813F8A26C496C13F06C496C13E0D803F8C7EAFE00B290B6FCA6
+01F8C7FCB3A23B3FFF800FFFE0486D4813F0B56C4813F8A26C496C13F06C496C13E02D38
+7FB730>I<007FB6FCB71280A46C1500260007F0C7FCB3B3A8007FB6FCB71280A46C1500
+213879B730>I<49B512F04914F85BA27F6D14F090C7EAFE00B3B3123C127EB4FCA24A5A
+1403EB8007397FF01FF86CB55A5D6C5C00075C000149C7FC38003FF025397AB730>I<D8
+3FFF90380FFF80486D4813C0B56C5AA26C497E6C496C1380D803F0903803F8004B5A4B5A
+151F4B5A5E4BC7FC15FE14014A5A5D4A5A4A5A141F5D4A5A4AC8FC5C13F18101F37F13F7
+90B57E14EFECC7F01483EC03F8140101FE7F496C7E5B157F497F82151F82150F826F7EA2
+6F7E1501821500D83FFF903803FFC0486D4813E0B56C5AA26C497E6C496C13C02B387FB7
+30>I<383FFFF8487FB57EA26C5B6C5BD801FCC9FCB3B0EE0F80EE1FC0A9003FB7FC5AB8
+FCA27E6C16802A387EB730>I<D83FF8ECFFE0486C4913F0486C4913F8A2007F16F06C6C
+4913E00007160001EF14BFEC800FA39039E7C01F3FA4ECE03F01E3133EA2ECF07EA201E1
+137CA2ECF8FCA201E013F8A214FDEC7DF0A3147FEC3FE0A3EC1FC0A2EC070091C7FCADD8
+3FFC903801FFE0486C4913F0B54913F8A26C486D13F06C486D13E02D387FB730>I<D83F
+FC90381FFF80486C4913C0B54913E0A26C6D6C13C06C6E13800003913801F800EBF7C0A3
+EBF3E0A314F013F1A214F8A213F014FCA2147C147EA2143E143FA2141FA21581A2140F15
+C1A2140715E1A2140315F1A21401A215F91400A3157DA3153FEA3FFF481380B5EAC01FA2
+6CEB800F6C496C5A2B387EB730>I<90383FFFE048B512FC000714FF4815804815C04815
+E0EBF80001E0133FD87F80EB0FF0A290C71207A44815F8481403B3A96C1407A26C15F0A3
+6D130FA26D131F6C6CEB3FE001F813FF90B6FC6C15C06C15806C1500000114FCD8003F13
+E0253A7BB830>I<007FB512F0B612FE6F7E16E0826C813903F8003FED0FFCED03FE1501
+6F7EA2821780163FA6167F17005EA24B5A1503ED0FFCED3FF890B6FC5E5E16804BC7FC15
+F001F8C9FCB0387FFFC0B57EA46C5B29387EB730>I<90383FFFE048B512FC000714FF48
+15804815C04815E0EBF80001E0133F4848EB1FF049130F90C71207A44815F8481403B3A8
+147E14FE6CEBFF076C15F0EC7F87A2EC3FC7018013CF9038C01FFFD83FE014E0EBF80F90
+B6FC6C15C06C15806C1500000114FCD8003F7FEB00016E7EA21680157F16C0153F16E015
+1F16F0150FED07E025467BB830>I<003FB57E4814F0B612FC15FF6C816C812603F8017F
+9138003FF0151F6F7E15071503821501A515035E1507150F4B5A153F4AB45A90B65A5E93
+C7FC5D8182D9F8007FED3FE0151F150F821507A817F8EEF1FCA53A3FFF8003FB4801C0EB
+FFF8B56C7E17F06C496C13E06C49EB7FC0C9EA1F002E397FB730>I<90390FF803C0D97F
+FF13E048B512C74814F74814FF5A381FF80F383FE001497E4848137F90C7123F5A48141F
+A2150FA37EED07C06C91C7FC7F7FEA3FF0EA1FFEEBFFF06C13FF6C14E0000114F86C8001
+1F13FF01031480D9003F13C014019138007FE0151FED0FF0A2ED07F8A2007C140312FEA5
+6C140716F07F6DEB0FE06D131F01F8EB3FC001FF13FF91B51280160000FD5CD8FC7F13F8
+D8F81F5BD878011380253A7BB830>I<003FB712C04816E0B8FCA43AFE003F800FA8007C
+ED07C0C791C7FCB3B1011FB5FC4980A46D91C7FC2B387EB730>I<3B7FFFC007FFFCB56C
+4813FEA46C496C13FCD803F8C7EA3F80B3B16D147F00011600A36C6C14FE6D13016D5CEC
+800390393FE00FF890391FF83FF06DB55A6D5C6D5C6D91C7FC9038007FFCEC1FF02F3980
+B730>I<D87FFE90380FFFC0B54913E06E5AA24A7E6C486D13C0D807F0903801FC00A26D
+130300035DA46C6C495AA46C6C495AA46D131F6D5CA3EC803F013F5CA46D6C48C7FCA490
+380FE0FEA401075B14F1A301035BA314FB01015BA314FFA26D5BA46E5A6E5A2B397EB730
+>I<D83FFC903801FFE0486C4913F000FF16F8A2007F16F06C486D13E0D81FC09038001F
+C0000F1680A76D143F00071600A7000390380F803E9039F01FC07EEC3FE0A3EC7FF0A214
+7D0001157CA29039F8FDF8FCA314F8A300005D01F913FCA2ECF07CA201FD137DA2017D5C
+ECE03DA3017F133FA2ECC01FA2013F5CA2EC800F6D486C5A2D397FB730>I<3A3FFF01FF
+F84801837F02C77FA202835B6C01015B3A01FC007F806D91C7FC00005C6D5BEB7F01EC81
+FCEB3F8314C3011F5B14E7010F5B14FF6D5BA26D5BA26D5BA26D90C8FCA4497FA2497FA2
+815B81EB0FE781EB1FC381EB3F8181EB7F0081497F49800001143F49800003141F498000
+07140FD87FFEEB7FFFB590B5128080A25C6C486D130029387DB730>I<D87FFF90381FFF
+C0B56C4813E0A46C496C13C0D803F8903803F8006D1307A26C6C495AA26C6C5C151F6D5C
+EC803F013F5CECC07F011F91C7FCA290380FE0FEA214F101075BA2903803FBF8A201015B
+14FF6D5BA26E5AA36E5AB1903803FFF8497F497FA26D5B6D5B2B387EB730>I<001FB612
+FC4815FE5AA490C7EA03FCED07F816F0150FED1FE016C0153FED7F80003E1500C85A4A5A
+5D14034A5A5D140F4A5A5D143F4A5A92C7FC5C495A5C1303495A5C130F495A5C133F495A
+91C8FC5B4848147C4914FE1203485A5B120F485A5B123F485A90B6FCB7FCA46C15FC2738
+7CB730>I<007FB5FCB61280A4150048C8FCB3B3B3A5B6FC1580A46C140019476DBE30>I<
+127CA212FEA27EA26C7EA26C7EA26C7EA26C7EA26C7EA26C7EA212017FA26C7EA26D7EA2
+6D7EA26D7EA26D7EA26D7EA26D7EA2130180A26D7EA26E7EA26E7EA26E7EA26E7EA26E7E
+A26E7EA2140181A26E7EA2ED7F80A2ED3FC0A2ED1FE0A2ED0FF0A2ED07F8A21503A2ED01
+F0150025477BBE30>I<007FB5FCB61280A47EC7123FB3B3B3A5007FB5FCB6FCA46C1400
+19477DBE30>I<1307EB1FC0EB7FF0497E000313FE000FEBFF80003F14E0D87FFD13F039
+FFF07FF8EBC01FEB800F38FE0003007CEB01F00010EB00401D0E77B730>I<007FB612F0
+A2B712F8A36C15F0A225077B7D30>I<1338137CEA01FE12031207EA0FFC13F0EA1FE013
+C0EA3F8013005A127EA212FE5AA5EAFFC013E013F0127FA2123FA2EA1FE0EA07C00F1D70
+BE30>I<EB7FF80003B5FC4814C04880488048809038E01FFC9038C003FE14016E7E6C48
+7F6CC77FC8123FA491B5FC130F137F48B6FC12075A48EB803F383FF800EA7FE0138048C7
+FC5AA4157F7E6C6C13FFEBC003263FF01FEBFF8090B712C07E6C14EF000314876CD9FE01
+138026003FE0C8FC2A2A7BA830>I<EA3FFC487E12FFA2127F123F1200AAEC03FE91381F
+FF80027F13E091B57E90B612FC82ECFE079138F001FF4A6C13804A137F4AEB3FC091C712
+1F17E049140FA217F01607A8160FA217E07F161F6EEB3FC0A26EEB7F806E13FFDAF00313
+009138FC0FFE91B55A5E495CD97E7F13C0D93C1F90C7FC90380003FC2C3980B730>I<EC
+FFE0010713FC011F7F017F7F90B612804815C048EB807F3907FC003F485A485A49EB1F80
+4848EB0F004990C7FC127F90C9FCA25A5AA87E7EA27F003FEC07C06DEB0FE06C7E6D131F
+6C6C14C0D807FE133F9039FFC0FF806C90B5FCC615006D5B011F13F801075B0101138023
+2A7AA830>I<913801FFE04A7F5CA28080EC0007AAEB03FE90381FFF874913E790B6FC5A
+5A481303380FFC00D81FF0133F49131F485A150F4848130790C7FCA25AA25AA87E6C140F
+A27F003F141F6D133F6C7E6D137F390FF801FF2607FE07EBFFC06CB712E06C16F06C14F7
+6D01C713E0011F010313C0D907FCC8FC2C397DB730>I<49B4FC010713E0011F13F8017F
+7F90B57E488048018113803A07FC007FC04848133FD81FE0EB1FE0150F484814F0491307
+127F90C7FCED03F85A5AB7FCA516F048C9FC7E7EA27F003FEC01F06DEB03F86C7E6C7E6D
+1307D807FEEB1FF03A03FFC07FE06C90B5FC6C15C0013F14806DEBFE00010713F8010013
+C0252A7CA830>I<EDFF80020713E0021F13F05C4A13F891B5FC491387903803FE079138
+FC03F0903907F800C04A1300A8003FB612C04815E0B7FCA36C15C0260007F0C7FCB3A900
+3FB512FE4880B71280A26C15006C5C25397DB830>I<D903FC13FF90261FFF8713C04913
+DF90B712E05A5A2607FE07138F903AF801FE07C048486C6CC7FCA2497F001F8149133FA5
+6D137F000F92C7FC6D5BA26C6C485AEBFE0790B55A5D485C15C001DF5BD9C3FCC8FC01C0
+C9FCA37F7F6CB512F015FF6C15C04815F0488148813A3FE0001FFE0180130148C8127F00
+7E8100FE168048151FA56C153F007FED7F006D5C6C6C495A01F013076CB4EB7FFC6C90B5
+5A6C5D000115C06C6C91C7FC011F13FC010113C02B3E7DA730>I<EA3FFC487E12FFA212
+7F123F1200AAEC01FE91380FFF80023F13E091B57E90B67EA29138FE07FCECF8039138E0
+01FE14C0EC8000A291C7FCA25BB3A23B3FFFF81FFFF8486D4813FCB500FE14FEA26C01FC
+14FC6C496C13F82F3880B730>I<14E0EB03F8A2497EA36D5AA2EB00E091C8FCA9381FFF
+F8487F5AA27E7EEA0001B3A9003FB612C04815E0B7FCA27E6C15C023397AB830>I<EC01
+C0EC07F0A2EC0FF8A3EC07F0A2EC01C091C7FCA990B512F04814F8A47EEB0003B3B3A5EC
+07F0A2123C007EEB0FE0B4131FEC3FC0147F90B512806C14005C6C5B000F13F0000313C0
+1D4E7CB830>I<EA7FF8487EA4127F1200AB0203B512804A14C017E0A217C06E14809139
+001FE0004B5A4B5A4BC7FC4A5A4A5AEC0FF84A5A4A5A4A5A4A5A01FD7F90B57E8114F7EC
+E3F8ECC1FCEC81FEEC00FF497F496D7E6F7E826F7E15076F7E6F7E3B7FFFF81FFFE0B56C
+4813F017F8A217F06C496C13E02D387FB730>I<387FFFF8B57EA47EEA0001B3B3A8007F
+B612F0B712F8A46C15F025387BB730>I<02FC137E3B7FC3FF01FF80D8FFEF01877F90B5
+00CF7F15DF92B57E6C010F13872607FE07EB03F801FC13FE9039F803FC01A201F013F8A3
+01E013F0B3A23C7FFE0FFF07FF80B548018F13C0A46C486C01071380322881A730>I<EC
+01FE3A3FFC0FFF80267FFE3F13E000FF90B57E90B67E7E6C9038FE07FCC6EBF8039138E0
+01FE14C0EC8000A291C7FCA25BB3A23B3FFFF81FFFF8486D4813FCB500FE14FEA26C01FC
+14FC6C496C13F82F2880A730>I<49B4FC010F13E0013F13F8497F90B57E0003ECFF8014
+013A07FC007FC04848EB3FE0D81FE0EB0FF0A24848EB07F8491303007F15FC90C71201A3
+00FEEC00FEA86C14016C15FCA26D1303003F15F86D13076D130F6C6CEB1FF06C6CEB3FE0
+6D137F3A07FF01FFC06C90B512806C15006C6C13FC6D5B010F13E0010190C7FC272A7CA8
+30>I<EC03FE3A3FFC1FFF80267FFE7F13E000FF90B57E90B612FC6C816CEBFE07C69038
+F001FF4A6C13804A137F4AEB3FC091C7121F17E049140FA217F01607A8160FA217E07F16
+1F6EEB3FC0A26EEB7F806E13FFDAF00313009138FC0FFE91B55A5E495C6E13C0021F90C7
+FCEC03FC91C9FCAD383FFFF8487FB57EA26C5B6C5B2C3C80A730>I<49B413F8010FEBC1
+FC013F13F14913FD48B6FC5A481381390FFC007F49131F4848130F491307485A49130312
+7F90C7FC15015A5AA77E7E15037FA26C6C1307150F6C6C131F6C6C133F01FC137F3907FF
+01FF6C90B5FC6C14FD6C14F9013F13F1010F13C1903803FE0190C7FCAD92B512F84A14FC
+A46E14F82E3C7DA730>I<ED07F83A3FFF803FFF486DB51280B512C302CF14C06C13DF6C
+9038FFFC3FD8001F13E09238801F809238000F004A90C7FC5C5C5CA25CA45CAF003FB512
+FC4880B7FCA26C5C6C5C2A287EA730>I<90381FFC1E48B5129F000714FF5A5A5A387FF0
+07EB800100FEC7FC4880A46C143E007F91C7FC13E06CB4FC6C13FC6CEBFF806C14E00001
+14F86C6C7F01037F9038000FFF02001380007C147F00FEEC1FC0A2150F7EA27F151F6DEB
+3F806D137F9039FC03FF0090B6FC5D5D00FC14F0D8F83F13C026780FFEC7FC222A79A830
+>I<EB0780497E131FA9003FB612E04815F0B7FCA36C15E026001FC0C7FCB216F8ED01FC
+A5ECE003010FEB07F814F09138FC1FF06DB512E06D14C016806D14009038007FFCEC1FF0
+26337EB130>I<D83FFCEB3FFC486C497E00FF14FFA2007F147F003F143F00001400B3A4
+1501A2150315076D130F903A7FC07FFFF891B612FC6D15FE7F6D4913FC6D9038F87FF801
+0001C0C7FC2F2880A630>I<3B3FFFC07FFF80486DB512C0B515E0A26C16C06C496C1380
+3B01F80003F000A26D130700005DA26D130F017E5CA2017F131F6D5CA2EC803F011F91C7
+FCA26E5A010F137EA2ECE0FE01075BA214F101035BA3903801FBF0A314FF6D5BA36E5A6E
+5A2B277EA630>I<3B3FFFC01FFFE0486D4813F0B515F8A26C16F06C496C13E0D807E0C7
+EA3F00A26D5C0003157EA56D14FE00015DEC0F80EC1FC0EC3FE0A33A00FC7FF1F8A2147D
+A2ECFDF9017C5C14F8A3017E13FBA290393FF07FE0A3ECE03FA2011F5C90390F800F802D
+277FA630>I<3A3FFF81FFFC4801C37FB580A26C5D6C01815BC648C66CC7FC137FEC80FE
+90383F81FC90381FC3F8EB0FE3ECE7F06DB45A6D5B7F6D5B92C8FC147E147F5C497F8190
+3803F7E0EB07E790380FE3F0ECC1F890381F81FC90383F80FE90387F007E017E137F01FE
+6D7E48486D7E267FFF80B5FCB500C1148014E3A214C16C0180140029277DA630>I<3B3F
+FFC07FFF80486DB512C0B515E0A26C16C06C496C13803B01FC0003F000A2000014076D5C
+137E150F017F5C7F151FD91F805BA214C0010F49C7FCA214E00107137EA2EB03F0157C15
+FCEB01F85DA2EB00F9ECFDF0147D147FA26E5AA36E5AA35DA2143F92C8FCA25C147EA200
+0F13FE486C5AEA3FC1EBC3F81387EB8FF0EBFFE06C5B5C6C90C9FC6C5AEA01F02B3C7EA6
+30>I<001FB612FC4815FE5AA316FC90C7EA0FF8ED1FF0ED3FE0ED7FC0EDFF80003E4913
+00C7485A4A5A4A5A4A5A4A5A4A5A4A5A4990C7FC495A495A495A495A495A495A4948133E
+4890C7127F485A485A485A485A485A48B7FCB8FCA46C15FE28277DA630>I<ED3FF09138
+03FFF8140F5C147F16F09138FFF00092C7FC495A5CB3A21303495A133F383FFFF0B55A5C
+91C8FC14C080003F7F38003FF813076D7E1301B3A2806D7E15F091387FFFF016F8141F80
+14039138003FF025477BBE30>I<127CA212FEB3B3B3AD127CA207476CBE30>I<EA7FE0EA
+FFFE6D7E8014F07EC66C7E13076D7E1301B3A2806D7E15E091387FFFE06E13F880140714
+1F5C4A13E09138FFE00092C7FC495A5CB3A21303495A137F387FFFF0B5FC14C05C49C8FC
+EA7FE025477BBE30>I<017C133848B4137C48EB80FE4813C14813C348EBEFFC397FEFFF
+F0D8FF8713E0010713C0486C1380D87C0113003838007C1F0C78B730>I
+E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fd cmti9 9 16
+/Fd 16 119 df<121C127F12FFA412FE12380808778718>46 D<ED3FC0913803FFF89138
+0FC03E91383E000702F0EB03C04948EB01E0D90780EB00F049C81270011E15385B4901FC
+131C9038F003FF3B01E00F83C01E903AC03E01E00E0003EB7C004848481370D901F0137E
+484848133F380E07C0121C4948133EEA3C1F003890C7127EEA783FD8703E147CA2EEFC1E
+EAF07ED8E07CECF81CA20301133CEEF038A303031378923807E07017F0013C010F13E001
+3E131F011E90383BE1C06DEBF3C33BF00783E3E7803B7003FF81FF00903900FE007C6C90
+C9FCA27E001EED07806C151F6C6CECFE00D801C0EB07F0D800F8EBFF8090263FFFFCC7FC
+010790C8FC2F3674B43B>64 D<0107B612C04915F017FC903A003F8001FEEE007FEF1F80
+92C7EA0FC0EF07E05CEF03F0147E170102FE15F8A25CA21301A25CA2130317035CA21307
+18F04A1407A2130F18E04A140F18C0011F151F18805CEF3F00133F177E91C85AA2494A5A
+4C5A017E4A5A4C5A01FE4A5A047EC7FC49495A0001EC0FF8007FB612E0B7C8FC15F83533
+7BB23A>68 D<0107B612C04915F883903A003F8001FEEE003FEF1F8092C713C0170F5C18
+E0147EA214FEEF1FC05CA201011680173F4A1500177E010315FE5F4AEB03F8EE07E00107
+EC3FC091B6C7FC16F802E0C9FC130FA25CA2131FA25CA2133FA291CAFCA25BA2137EA213
+FEA25B1201387FFFF0B5FCA233337CB234>80 D<B53CC03FFFF003FFF8601480280FF000
+01FCC7EA7F806C484AEC3E00193CA219386115036115074E5A030F140361031D4AC7FCA2
+DB38FC130EA203705C15F06C6C01E05C140103C05CDA038014F060DA0700130160020E4A
+5AA24A4AC8FCA24A140E147802705C5C5FD9F1C014781770D9F3805CA201F7C7EA7FC0A2
+01FE5DA26C4892C9FCA249147E5B167C5B1678491470453570B24D>87
+D<EB03F0EB0FF890383E1C6090387C0FF0EBF807EA01F0EA03E00007EB03E0EA0FC0A238
+1F800715C0EA3F00A2140F481480127EA2141F00FE14005A1506EC3F07EC3E0F150E147E
+007C141EECFE1CEB01FCD83C03133C393E07BE38391F0E1E783907FC0FF03901F003C020
+2278A027>97 D<14FCEB07FF90381F078090383E03C0EBFC013801F8033803F0073807E0
+0F13C0120F391F80070091C7FC48C8FCA35A127EA312FE5AA4007C14C0EC01E0A2EC03C0
+6CEB0F80EC1F006C137C380F81F03803FFC0C648C7FC1B2278A023>99
+D<EB03F8EB0FFEEB3E0F9038F807803801F003EA03E0EA07C0120FEA1F801407D83F0013
+005C007E133EEB03F8387FFFE04848C7FC00FCC8FCA45AA4EC0180EC03C0A2007CEB0780
+EC1F00003C133E6C13F8380F03E03807FF80D801FCC7FC1A2277A023>101
+D<143FECFF80903803E1E6903807C0FF90380F807FEB1F00133E017E133F49133EA24848
+137EA24848137CA215FC12074913F8A21401A2D80FC013F0A21403120715E01407140F14
+1F3903E03FC00001137FEBF0FF38007FCF90381F0F801300141FA21500A25C143E123800
+7E137E5C00FE5B48485A387803E0387C0F80D81FFFC7FCEA07F820317CA023>103
+D<EB0180EB07E0A2130FEB07C0EB038090C7FCABEA01F0EA03FCEA0F1E120E121C123C12
+38EA783E1270A2137EEAF07CEA60FCC65AA212015BA212035BA2000713C0EBC1E0000F13
+C01381A21383EB038013071400130E131EEA07F8EA01F013337AB118>105
+D<133FEA07FF5A13FEEA007EA3137CA213FCA213F8A21201A213F0A21203A213E0A21207
+A213C0A2120FA21380A2121FA21300A25AA2123EA2127EA2127C1318EAFC1C133CEAF838
+A21378137012F013F0EAF8E01279EA3FC0EA0F00103579B314>108
+D<2703C003F8137F3C0FF00FFE01FFC03C1E783C1F07C1E03C1C7CF00F8F01F03B3C3DE0
+079E0026383FC001FC7FD97F805B007001005B5E137ED8F0FC90380FC00100E05FD860F8
+148012000001021F130360491400A200034A13076049013E130FF081800007027EEC83C0
+051F138049017C1403A2000F02FC1407053E130049495CEF1E0E001F01015D183C010049
+EB0FF0000E6D48EB03E03A227AA03F>I<3903C007F0390FF01FFC391E787C1E391C7CF0
+1F393C3DE00F26383FC01380EB7F8000781300EA707EA2D8F0FC131F00E01500EA60F812
+0000015C153E5BA20003147E157C4913FCEDF8180007153C0201133801C013F0A2000F15
+78EDE070018014F016E0001FECE1C015E390C7EAFF00000E143E26227AA02B>I<14FCEB
+07FF90381F07C090383E03E09038FC01F0EA01F83903F000F8485A5B120F484813FCA248
+C7FCA214014814F8127EA2140300FE14F05AA2EC07E0A2007CEB0FC01580141FEC3F006C
+137E5C381F01F0380F83E03803FF80D800FCC7FC1E2278A027>I<EB03F0EB1FFCEB3C1E
+EB780FEBF007EA01E0140F0003131F13C0A2EBE00414007FEBFF8014E06C13F06C13F8EB
+7FFC1307EB00FE147E143E123800FC133CA3147C00F013784813F0EAF001387803E0383C
+0F80381FFE00EA03F818227AA01F>115 D<01F01338D803FC13FCEA0F1E120E121C123C
+0038147CEA783E0070143CA2137ED8F07C1338EA60FCC65A1578000114705BA215F00003
+14E05BA2EC01C0A2EBC003158014071500EBE00EA26C6C5A3800F878EB7FE0EB1F801E22
+7AA023>118 D E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fe cmr9 9 23
+/Fe 23 117 df<123C127EB4FCA21380A2127F123D1201A412031300A25A1206120E120C
+121C5A5A126009177A8715>44 D<15E0A34A7EA24A7EA34A7EA3EC0DFE140CA2EC187FA3
+4A6C7EA202707FEC601FA202E07FECC00FA2D901807F1507A249486C7EA301066D7EA201
+0E80010FB5FCA249800118C77EA24981163FA2496E7EA3496E7EA20001821607487ED81F
+F04A7ED8FFFE49B512E0A333367DB53A>65 D<DA03FE130C91393FFF801C91B512E0903A
+03FE01F83C903A0FF0003C7CD91FC0EB0EFCD97F80130701FEC712034848140100031500
+5B4848157C485A173C485A171C123F5B007F160CA390C9FC481600AB7E6D150CA3123F7F
+001F161C17186C7E17386C6C15306C6C15706D15E012016C6CEC01C0D97F80EB0380D91F
+C0EB0F00D90FF0131ED903FE13FC0100B512F0023F13C0DA03FEC7FC2E377CB437>67
+D<B812C0A3D803FCC7127F0001150FEE03E01601A21600A21760A403061330A41700150E
+A2151E157E90B512FEA39038FC007E151E150EA21506170CA3171892C7FCA41738A21770
+A217F01601160316070003157FB812E0A32E337DB234>69 D<B81280A3D803FCC7FC0001
+151FEE07C01603A21601A21600A41760150CA31700A2151CA2153C15FC90B5FCA3EBFC00
+153C151CA2150CA592C8FCAB487EB512FEA32B337DB232>I<DA03FE130C91393FFF801C
+91B512E0903A03FE01F83C903A0FF0003C7CD91FC0EB0EFCD97F80130701FEC712034848
+1401000315005B4848157C485A173C485A171C123F5B007F160CA390C9FC4893C7FCAA03
+03B512E07E7F92390003FE00705A123F7F121FA26C7E7F12076C7E7F6C6C14036C7E6D6C
+1307D91FC0EB0E7CD90FF0EB1C3CD903FEEBF81C0100B5EAF00C023F01C0C7FCDA03FEC8
+FC33377CB43C>I<B5D8FE03B512F8A3000190C73807FC006C486E5AB390B7FCA349C712
+03B3A3486C4A7EB5D8FE03B512F8A335337EB23A>I<D8FFFE91381FFFF87F80C6030013
+006E143CD9DFE01418EBCFF0A2EBC7F8EBC3FCA2EBC1FEEBC0FF6E7EA26E7E6E7EA26E7E
+6E7E6E7EA26E7E6E7EA2ED7F80ED3FC0ED1FE0A2ED0FF0ED07F8A2ED03FCED01FEED00FF
+A2EE7F98EE3FD8A2EE1FF8160F1607A216031601A2486C1400D807F81578B500C01438A2
+171835337EB23A>78 D<B612FCEDFF8016F03A01FE0007FC0000EC01FEED007F707E707E
+83160F83A65FA24C5AA24C5A047EC7FC4B5AED0FF090B612C093C8FC9039FE001FC0ED07
+F06F7E6F7E150082167E167FA583A5180C17C0A2043F131C486C1618B500FEEB1FE0040F
+1338933807F070C93801FFE09338003F8036357EB239>82 D<90381FE00390387FFC0748
+B5FC3907F01FCF390F8003FF48C7FC003E80814880A200788000F880A46C80A27E92C7FC
+127F13C0EA3FF013FF6C13F06C13FF6C14C06C14F0C680013F7F01037F9038003FFF1403
+02001380157F153FED1FC0150F12C0A21507A37EA26CEC0F80A26C15006C5C6C143E6C14
+7E01C05B39F1FC03F800E0B512E0011F138026C003FEC7FC22377CB42B>I<EB7F803803
+FFF0380F80FC381C003E003F133F6D6C7E6E7EA26E7EEA1F00C7FCA4EB01FF131FEBFF87
+3803FC07EA0FF0EA1FC0EA3F80127F13004815C05AA3140FA26C131F6C133B3A3F8071F1
+80391FC1E1FF2607FFC013003900FE003C22237DA126>97 D<EB07F8EB3FFF9038FC07C0
+3901F000E03903E003F03807C007120FEA1F80123F90380003E04890C7FCA2127E12FEAA
+127FA26C14187F001F14386D1330000F14706C6C13E03903F001C03900FC0F8090383FFE
+00EB07F01D237EA122>99 D<153FEC0FFFA3EC007F81AEEB07F0EB3FFCEBFC0F3901F003
+BF3907E001FF48487E48487F8148C7FCA25A127E12FEAA127E127FA27E6C6C5BA26C6C5B
+6C6C4813803A03F007BFFC3900F81E3FEB3FFCD90FE0130026357DB32B>I<EB0FE0EB7F
+FCEBF83F3903F00F80D807E013C0390FC007E0381F800315F0EA3F0014014814F8127EA2
+12FEA2B6FCA248C8FCA5127E127FA26C1418A26C6C1338000F14306D13706C6C13E03901
+F003C03900FC0F00EB3FFEEB07F01D237EA122>I<151F90391FC07F809039FFF8E3C039
+01F07FC73907E03F033A0FC01F83809039800F8000001F80EB00074880A66C5CEB800F00
+0F5CEBC01F6C6C48C7FCEBF07C380EFFF8380C1FC0001CC9FCA3121EA2121F380FFFFEEC
+FFC06C14F06C14FC4880381F0001003EEB007F4880ED1F8048140FA56C141F007C15006C
+143E6C5C390FC001F83903F007E0C6B51280D91FFCC7FC22337EA126>103
+D<EA03F012FFA312071203AEEC1FC0EC7FF09038F1E0FC9038F3807C9038F7007E13FE49
+7FA25BA25BB3486CEB7F80B538C7FFFCA326347EB32B>I<EA0780EA0FC0EA1FE0A4EA0F
+C0EA0780C7FCAAEA07E012FFA3120F1207B3A6EA0FF0B5FCA310337EB215>I<EA07E012
+FFA3120F1207B3B3A7EA0FF0B5FCA310347EB315>108 D<3903F01FC000FFEB7FF09038
+F1E0FC9038F3807C3907F7007EEA03FE497FA25BA25BB3486CEB7F80B538C7FFFCA32621
+7EA02B>110 D<EB07F0EB3FFE9038FC1F803901F007C03903C001E000078048486C7E48
+C7127CA248147E003E143E007E143FA300FE1580A8007E1500A36C147EA26C147C6D13FC
+6C6C485A00075C3903F007E03900FC1F80D93FFEC7FCEB07F021237EA126>I<3903F03F
+8000FFEBFFE09038F3C0F89038F7007ED807FE7F6C48EB1F804914C049130F16E0ED07F0
+A3ED03F8A9150716F0A216E0150F16C06D131F6DEB3F80160001FF13FC9038F381F89038
+F1FFE0D9F07FC7FC91C8FCAA487EB512C0A325307EA02B>I<3803E07C38FFE1FF9038E3
+8F809038E71FC0EA07EEEA03ECA29038FC0F8049C7FCA35BB2487EB512E0A31A217FA01E
+>114 D<1330A51370A313F0A21201A212031207381FFFFEB5FCA23803F000AF1403A814
+073801F806A23800FC0EEB7E1CEB1FF8EB07E0182F7FAD1E>116
+D E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Ff cmsy6 6 1
+/Ff 1 4 df<136013701360A20040132000E0137038F861F0387E67E0381FFF803807FE
+00EA00F0EA07FE381FFF80387E67E038F861F038E060700040132000001300A213701360
+14157B9620>3 D E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fg cmr10 10.95 89
+/Fg 89 124 df<4AB4EB0FE0021F9038E03FFC913A7F00F8FC1ED901FC90383FF03FD907
+F090397FE07F80494801FF13FF4948485BD93F805C137F0200ED7F00EF003E01FE6D91C7
+FC82ADB97EA3C648C76CC8FCB3AE486C4A7E007FD9FC3FEBFF80A339407FBF35>11
+D<EC03FE91383FFF809138FE03E0903903F800F0D90FE013384948137C90393F8001FE90
+387F00035B5BA2485A6F5AED007093C7FCAA16FEB7FCA33901FC000315011500B3AC486C
+497EB5D8F87F13FCA32E407EBF33>I<EC03FF023F13EE9138FE01FEEB03F090380FE003
+EB1FC0EB3F80EB7F005B5B150148481300AEB7FCA3D801FCC7FCB3AE486C497EB5D8F87F
+13FCA32E407EBF33>I<DA03FE49B4FC91273FFF801F13C0913BFE03E07F01F0903C03F0
+00F1FC0078D90FE0D97FF0131C49484948133E4948484913FF494848495A5B491500A248
+485C03016E5A0300153896C7FCAA197FBBFCA3D801FCC738FE00018485B3AC486C496CEC
+FF80B5D8F87FD9FC3F13FEA347407EBF4C>I<121EEA7F80EAFFC0A9EA7F80ACEA3F00AC
+121EAB120CC7FCA8121EEA7F80A2EAFFC0A4EA7F80A2EA1E000A4179C019>33
+D<001E130F397F803FC000FF137F01C013E0A201E013F0A3007F133F391E600F30000013
+00A401E01370491360A3000114E04913C00003130101001380481303000EEB070048130E
+0018130C0038131C003013181C1C7DBE2D>I<4B6C130C4B6C131EA20307143EA24C133C
+A2030F147CA293C71278A24B14F8A2031E5CA2033E1301A2033C5CA3037C1303A203785C
+A203F81307A24B5CA20201140F007FBAFCBB1280A26C1900C72707C0003EC8FC4B133CA3
+020F147CA292C71278A24A14F8A2021E5CA3023E1301007FBAFCBB1280A26C1900C727F8
+0007C0C8FC4A5CA20101140FA24A91C9FCA301035CA24A131EA20107143EA24A133CA201
+0F147CA291C71278A34914F8A2011E5CA2013E1301A2013C5CA201186D5A41517BBE4C>
+I<14E0A4EB07FC90383FFF8090B512E03901F8E3F03903E0E0FCD807C0133CD80F807FD8
+1F007F003E80003C1580007C140316C00078141F00F8143F157FA47EED3F806CEC0E0092
+C7FC127F138013C0EA3FF013FEEA1FFF6C13FC6C13FF6C14C06C806C6C13F8011F7F1303
+01007FECE7FF14E102E01380157F153FED1FC0A2003E140F127FD8FF801307A5130000FC
+158000F0140F1270007815005D6C141E153E6C5C6C5C3907C0E1F03903F8EFE0C6B51280
+D93FFEC7FCEB0FF8EB00E0A422497BC32D>I<EC0F80EC7FE0ECF870903803E038010713
+3CECC01CEB0F80011F131E150EA2EB3F00A55D1480A25D157815705D6D6C5A14C1ECC380
+02C7CAFC02EE91387FFFFCEB0FEC14FC4A020713C06D48913801FE006E5DEF00F06D7E01
+074B5A496C5D011D1503D939FF4A5A017093C7FC496D5B0001017F140E496C6C131E0003
+6E131C2607801F143C000F6E5B001F6D6C1370263F000714F0486E485ADA03FE5B913801
+FF03486D495A0487C8FCED7FCFED3FFE6F4814386D5C150F007F6E6C14786D6D6C147000
+3F4A6C14F06D496C6C13E0001F91393E3FC0016C6C903AFC1FF003C03D07FC07F007FC1F
+800001B5D8C001B512006C6C90C7EA7FFCD90FF8EC0FF03E437CC047>38
+D<121EEA7F8012FF13C0A213E0A3127FEA1E601200A413E013C0A312011380120313005A
+120E5A1218123812300B1C79BE19>I<1430147014E0EB01C0EB03801307EB0F00131E13
+3E133C5B13F85B12015B1203A2485AA2120F5BA2121F90C7FCA25AA3123E127EA6127C12
+FCB2127C127EA6123E123FA37EA27F120FA27F1207A26C7EA212017F12007F13787F133E
+131E7FEB07801303EB01C0EB00E014701430145A77C323>I<12C07E12707E7E121E7E6C
+7E7F12036C7E7F12007F1378137CA27FA2133F7FA21480130FA214C0A3130714E0A61303
+14F0B214E01307A614C0130FA31480A2131F1400A25B133EA25BA2137813F85B12015B48
+5A12075B48C7FC121E121C5A5A5A5A145A7BC323>I<EB03C0A2805CA600F0140F00FC14
+3F00FE147F00FF14FF393FC3C3FC390FE187F03903F18FC03900FDBF00EB3FFCEB0FF0EB
+03C0EB0FF0EB3FFCEBFDBF3903F18FC0390FE187F0393FC3C3FC39FF03C0FF00FE147F00
+FC143F00F0140F00001400A6805CA220277AC32D>I<1506150FB3A9007FB912E0BA12F0
+A26C18E0C8000FC9FCB3A915063C3C7BB447>I<121EEA7F8012FF13C0A213E0A3127FEA
+1E601200A413E013C0A312011380120313005A120E5A1218123812300B1C798919>I<B5
+12FEA617067F961E>I<121EEA7F80A2EAFFC0A4EA7F80A2EA1E000A0A798919>I<ED0180
+ED03C01507A21680150FA216005DA2151E153EA2153C157CA2157815F8A25D1401A25D14
+03A25D1407A25D140FA24AC7FCA2141E143EA2143C147CA2147814F8A25C1301A25C1303
+A25C1307A25C130FA291C8FC5BA2131E133EA25BA2137813F8A25B1201A25B1203A25B12
+07A25B120FA290C9FC5AA2121E123EA2123C127CA2127812F8A25A1260225B7BC32D>I<
+EB01FE90380FFFC090383F03F090387C00F849137C48487F48487F4848EB0F80A2000F15
+C04848EB07E0A3003F15F0A290C712034815F8A64815FCB3A26C15F8A56C6CEB07F0A300
+1F15E0A36C6CEB0FC0A26C6CEB1F80000315006C6C133E6C6C5B017C5B90383F03F09038
+0FFFC0D901FEC7FC263F7DBC2D>I<EB01C013031307131F137FEA07FFB5FC139FEAF81F
+1200B3B3ACEB7FF0B612F8A31D3D78BC2D>I<EB07FC90383FFF8090B512E03903F01FF8
+3907C007FC390F0001FE001E6D7E001C1580003CEC7FC05AED3FE01270B4FC6DEB1FF07F
+A56C5A6CC7FC120CC813E0153FA216C0157F168015FF16004A5A5D4A5A4A5A5D4A5A4A5A
+4AC7FC147E147C5C495A495A495A495A49C71270133E133C5B4914E0485A485A485A48C7
+120148B6FCA25A4815C0B7FCA3243D7CBC2D>I<EB07FC90383FFF809038F80FE03901E0
+03F839078001FCD80F007F000E6D7E001E1580D81F80137F486C14C07FA27F5BA2121F6C
+5AC8138015FF1600A24A5AA24A5A5DEC07E04A5A023FC7FCEB1FFCECFF809038000FE0EC
+07F86E7E6E7E6E7E1680ED7FC0A216E0153FA216F0A2120C123F487E487EA316E0A24913
+7F6CC713C01278EDFF807E6C4913006C495A3907C007FC3903F80FF0C6B55A013F1380D9
+07F8C7FC243F7CBC2D>I<150E151E153EA2157EA215FE1401A21403EC077E1406140E14
+1CA214381470A214E0EB01C0A2EB0380EB0700A2130E5BA25B5BA25B5B1201485A90C7FC
+5A120E120C121C5AA25A5AB8FCA3C8EAFE00AC4A7E49B6FCA3283E7EBD2D>I<00061403
+D80780131F01F813FE90B5FC5D5D5D15C092C7FC14FCEB3FE090C9FCACEB01FE90380FFF
+8090383E03E090387001F8496C7E49137E497F90C713800006141FC813C0A216E0150FA3
+16F0A3120C127F7F12FFA416E090C7121F12FC007015C012780038EC3F80123C6CEC7F00
+001F14FE6C6C485A6C6C485A3903F80FE0C6B55A013F90C7FCEB07F8243F7CBC2D>I<EC
+1FE0ECFFF8903803F03E90380FC00F90391F000780133E017EEB1FC049133F4848137F12
+035B12074848EB3F80ED1F00001F91C7FC5BA2123FA3485AA214FE903887FF8039FF8F07
+E090389C01F09038B800FC01B0137E13F0497F16804914C0A2ED1FE0A34914F0A5127FA6
+123F6D14E0A2121FED3FC0A26C6C1480A20007EC7F006C6C137E6C6C5B6C6C485A90387E
+07F06DB45A010F1380D903FCC7FC243F7CBC2D>I<1238123C123F90B612FCA316F85A16
+F016E00078C712010070EC03C0ED078016005D48141E151C153C5DC8127015F04A5A5D14
+034A5A92C7FC5C141EA25CA2147C147814F8A213015C1303A31307A3130F5CA2131FA613
+3FAA6D5A0107C8FC26407BBD2D>I<EB03FC90381FFF8090387C07E09038F001F83901E0
+007C48487F48487F48C7FCED0F80121E16C0003E1407A4123FA26DEB0F807F6C6C131F6D
+140001FC133E6C6C5B9038FF80786C6D5A6CEBF3E06CEBFF806C91C7FC133F6D13C06D7F
+013F13F801787F48486C7E3903E01FFF48486C1380260F800313C048487E489038007FE0
+003E143F007E141F007CEC0FF01507481403A31501A46C15E0007C1403A2007E15C06C14
+076CEC0F806DEB1F006C6C133ED807F05B3901FC03F86CB512E0011F1380D903FCC7FC24
+3F7CBC2D>I<EB03FCEB1FFF90387E07C09038FC03F048486C7E48486C7E4848137C000F
+147E4848137F81003F15805B007F15C0A2151F12FF16E0A516F0A5127F153FA36C7EA200
+1F147F120F6C6C13FF6D13DF000313013900F8039F90387E0F1FD91FFE13E0EB07F090C7
+FCA2ED3FC0A41680157FD80F801400487E486C13FEA24A5A5D49485AEB8007391E000FE0
+001F495A260FC07FC7FC3803FFFE6C13F838003FC0243F7CBC2D>I<121EEA7F80A2EAFF
+C0A4EA7F80A2EA1E00C7FCB3121EEA7F80A2EAFFC0A4EA7F80A2EA1E000A2779A619>I<
+121EEA7F80A2EAFFC0A4EA7F80A2EA1E00C7FCB3121E127FEAFF80A213C0A4127F121E12
+00A412011380A3120313005A1206120E120C121C5A1230A20A3979A619>I<007FB912E0
+BA12F0A26C18E0CDFCAE007FB912E0BA12F0A26C18E03C167BA147>61
+D<EB1FF890B5FC3903E01FC0390F0007F0001EEB03F848EB01FC4814FE140000FE14FF7E
+7FA46CC7FC123EC7EA01FEA2EC03FCEC07F815F0EC0FC0EC1F80EC3F00143E5C147814F8
+5C13015CA2495AA25CAB91C7FC90C8FCA8EB0780EB1FE0A2497EA46D5AA2EB078020407B
+BF2B>63 D<ED7FE0913807FFFE91391F801F809139780001E0D901E0EB0078D90780141E
+49C87E011E6F7E0138ED01C0496F7E4916700001177848488249D93F80131C28070001FF
+F07F48902607E07C130F000E90260FC01E7F001E90263F00071480001C49903803800300
+3C01FED901C013C0003849ECFE010101EC00FF267803F8027F13E000701700495AA200F0
+18F000E01870495AA96D7E12F01270A26D7E007818E0263801FC5C01005C003C7F001C01
+7F49EB01C0001E6DEB077F000E903B0FC01E3F8380000F903B07E07C1F87006C903A01FF
+F007FE3C0380003F8001F86D90CAFC6C7E120013707F011EEE03F06D160F6D6CED3FC0D9
+01E0913801FE00D90078EC1FF0913A1F8003FF800207B500F8C7FC9126007FFEC8FC3C41
+7BBF47>I<15074B7EA34B7EA34B7EA34B7EA34B7E15E7A2913801C7FC15C3A291380381
+FEA34AC67EA3020E6D7EA34A6D7EA34A6D7EA34A6D7EA34A6D7EA349486D7E91B6FCA249
+819138800001A249C87EA24982010E157FA2011E82011C153FA2013C820138151FA20178
+82170F13FC00034C7ED80FFF4B7EB500F0010FB512F8A33D417DC044>I<B712FCEEFF80
+17F00001903980000FF86C6CC7EA03FE707E701380EF7FC0EF3FE0A2EF1FF0A218F8A317
+0F171FA318F0A2EF3FE0177F18C0EFFF804C1300EE03FCEE0FF8EE7FE091B6C7FC17E091
+C7EA07FCEE01FE933800FF80EF7FC0EF3FE0EF1FF018F8170F18FC1707A218FEA718FC17
+0FA2EF1FF818F0173FEF7FE0EFFFC00403138048486C90380FFE00B85A17E094C7FC373E
+7DBD40>I<DB3FF01306912603FFFE130E020F9038FF801E913A3FF007E03E9139FF8000
+F8D903FEC7EA7C7ED907F8EC1EFE4948140FD93FE0140749481403495A91C81201484815
+0012034848167E5B000F173EA24848161EA2123F5B180E127FA349160012FFAC127F7F18
+0EA2123FA27F001F171E181C6C7EA20007173C6D16386C6C1678000117706C6C16F06EEC
+01E06D6C15C06D6C1403D90FF0EC07806D6CEC1F00D903FE143E902600FF8013F891393F
+F007F0020FB512C0020391C7FC9138003FF037427BBF42>I<B712FCEEFF8017E0000190
+39C0001FF86C6C48EB03FEEE00FF717E717EEF0FE084717E717E170184717EA21980187F
+19C0A3F03FE0A519F0AB19E0A5F07FC0A21980A218FF19004D5AA24D5A6017074D5A4D5A
+EF7FC04DC7FCEE03FE48486CEB1FF8B85A178004FCC8FC3C3E7DBD45>I<B912E0A30001
+9038C000016C6C48EB001FEF0FF01703A217011700A31870A418381638A41800A21678A2
+16F81501150791B5FCA3EC8007150115001678A21638A2180EA3181C93C7FCA4183C1838
+A21878A318F8EF01F0A21707170F173F48486CEB03FFB912E0A3373E7DBD3E>I<B91280
+A300019038C000036C6C48EB007FEF1FC0170F1707A21703A31701A4EF00E0A21638A318
+00A31678A216F81501150791B5FCA3EC8007150115001678A21638A693C8FCAF3801FFE0
+B612F0A3333E7DBD3B>I<DB3FE0130C912603FFFE131C021F9038FF803C913A7FF00FC0
+7C9139FF0001F0D903FC90380078FC4948143DD91FE0141F4948140F4948140701FF1503
+4890C8FC491501485A000716005B000F177C5B001F173CA2485AA2181C127FA25B95C7FC
+12FFAB041FB512F0127FA26D9139000FFE00EF03FC123FA27F121FA26C7EA212077F1203
+6C7E7F6C7F6D6C14076D7E6D6C140FD907F8141ED903FEEC3C7C902600FF80EBF83C913A
+7FF007F01C021FB5EAC00C020391C8FC9138003FF03C427BBF47>I<B6D8C01FB512F8A3
+000101E0C7383FFC0026007F80EC0FF0B3A691B7FCA30280C7120FB3A92601FFE0EC3FFC
+B6D8C01FB512F8A33D3E7DBD44>I<B612F0A3C6EBF000EB3FC0B3B3B2EBFFF0B612F0A3
+1C3E7EBD21>I<011FB512FCA3D9000713006E5A1401B3B3A6123FEA7F80EAFFC0A44A5A
+1380D87F005B007C130700385C003C495A6C495A6C495A2603E07EC7FC3800FFF8EB3FC0
+26407CBD2F>I<B600C090387FFFFCA3000101E0C7000F138026007F80913807FE0018F8
+18E0604D5A4DC7FC173E5F5F4C5A4C5A4C5A4C5A4CC8FC163E5E5E4B5A4B5AED07804B7E
+151F4B7E4B7E15FF913881EFF8913883C7FCEC878791388F03FE91389E01FF14BCDAF800
+7F4A6D7E5C4A6D7E4A6D7EA2707E707EA2707E707EA2707F717E84173F717E717EA2717E
+848419802601FFE04A13C0B600C090B6FCA3403E7DBD47>I<B612F8A3000101E0C9FC38
+007F80B3B0EF0380A517071800A45FA35FA25F5F5F4C5A160748486C133FB8FCA3313E7D
+BD39>I<B500C093B512C0A300016D4BEBE000D8007F1880D977F0ED03BFA3D973F8ED07
+3FA3D971FC150EA2D970FE151CA3027F1538A36E6C1470A36E6C14E0A26E6CEB01C0A36E
+6CEB0380A36E6CEB0700A26E6C130EA36E6C5BA3037F5BA26F6C5AA36F6C5AA392380FE1
+C0A3923807F380A26FB4C7FCA36F5AA213F8486C6D5AD807FFEFFFE0B500F80178017FEB
+FFC0A34A3E7CBD53>I<B56C91B512F88080D8007F030713006EEC01FC6E6E5A1870EB77
+FCEB73FEA2EB71FF01707FA26E7E6E7EA26E7E6E7EA26E7E6E7EA26E7E6E7FA26F7E6F7E
+A26F7E6F7EA26F7E6F7EA26F7E6F1380A2EE7FC0EE3FE0A2EE1FF0EE0FF8A2EE07FCEE03
+FEA2EE01FF7013F0A2177F173FA2171F170FA2170701F81503487ED807FF1501B500F814
+00A218703D3E7DBD44>I<ED7FE0913807FFFE91391FC03F8091397E0007E04948EB03F8
+D907F0EB00FE4948147F49486E7E49486E7E49C86C7E01FE6F7E00018349150300038348
+486F7EA248486F7EA2001F188049167F003F18C0A3007F18E049163FA300FF18F0AC007F
+18E06D167FA4003F18C0A26C6CEEFF80A36C6C4B1300A26C6C4B5A00035F6D150700015F
+6C6C4B5A6D5E6D6C4A5A6D6C4A5A6D6C4AC7FC6D6C14FED901FCEB03F8D9007FEB0FE091
+391FC03F80912607FFFEC8FC9138007FE03C427BBF47>I<B712F8EEFF8017E000019039
+C0003FF86C6C48EB07FCEE01FE707EEF7F80EF3FC018E0A2EF1FF0A218F8A818F0A2EF3F
+E0A218C0EF7F80EFFF004C5AEE07FCEE3FF091B612C04CC7FC0280C9FCB3A73801FFE0B6
+12C0A3353E7DBD3E>I<B712C016FCEEFF800001D9C00013E06C6C48EB1FF0EE07FCEE01
+FE707E84717EA2717EA284A760177F606017FF95C7FCEE01FCEE07F8EE1FE0EEFF8091B5
+00FCC8FC16F091388001FCED003FEE1FC0707E707E83160383160183A383A484A4F0C004
+190EA28218E0057F131E2601FFE0161CB600C0EB3FF094381FF83805071370CA3801FFE0
+9438003F803F407DBD43>82 D<D907FC131890391FFF8038017FEBE0783901FC03F83A03
+F0007CF8D807C0133F4848130F001F140748C7FC003E1403007E1401A2007C140012FC16
+78A46C1538A27EA26C6C14007F7FEA3FF8EBFF806C13F86CEBFF806C14F06C14FC6C14FF
+6C15C0013F14E0010714F0EB007F020713F89138007FFC150FED07FE15031501ED00FFA2
+00E0157FA3163FA27EA3163E7E167E6C157C6C15FC6C15F86D13016DEB03F06DEB07E0D8
+F9FCEB0FC03AF07F803F8090391FFFFE00D8E00713F839C0007FC028427BBF33>I<003F
+B91280A3903AF0007FE001018090393FC0003F48C7ED1FC0007E1707127C00781703A300
+701701A548EF00E0A5C81600B3B14B7E4B7E0107B612FEA33B3D7DBC42>I<B600C090B5
+12F8A3000101E0C70007130026007F80EC01FC715A1870B3B3A4013F16F06E5DA2170101
+1F5E80010F15036E4A5A010793C7FC6D6C5C6D6C141E6D6C5C027F14F86E6C485A91390F
+F00FE00203B51280020049C8FCED1FF03D407DBD44>I<B691380FFFFEA3000301E00201
+13E06C01809138007F806CEF3F00017F163E181C6E153C013F1638A26E1578011F1670A2
+6D6C5DA26E140101075EA26E140301035EA26D6C4AC7FCA2806D150EA26F131E027F141C
+A26F133C023F1438A26E6C5BA26F13F0020F5CA2EDF80102075CA26E6C485AA2EDFE0702
+0191C8FCA26F5A6E130EA2ED7F9CA216DCED3FF8A36F5AA36F5AA26F5AA36F5A3F407EBD
+44>I<B500FE017FB5D88007B5FCA3000301C0010101E0C713F86C90C849EC3FE07148EC
+0F807E7215006E143F017F190E84A26D6C60A24D7E6D6C60A2EFE7F86D6C60A2933801C3
+FC6E18F001076104037F6E0281140101036104077F17006D6C4D5AA2040EEB7F806D6C4D
+C7FCA24CEB3FC0DA7F80160EA24CEB1FE003C0161E023F171C047814F0DBE070010F133C
+021F173804F014F84C1307DA0FF05EA2DBF1C0EB03FCDA07F95EA2DBFB80EB01FEDA03FF
+6F5AA293C8FCA26E5FA24B157F020094C8FCA24B81037C153EA20378151E0338151C5840
+7EBD5D>I<007FB5D8C003B512E0A3C649C7EBFC00D93FF8EC3FE06D48EC1F806D6C92C7
+FC171E6D6C141C6D6C143C5F6D6C14706D6D13F04C5ADA7FC05B023F13036F485ADA1FF0
+90C8FC020F5BEDF81E913807FC1C163C6E6C5A913801FF7016F06E5B6F5AA26F7E6F7EA2
+8282153FED3BFEED71FF15F103E07F913801C07F0203804B6C7EEC07004A6D7E020E6D7E
+5C023C6D7E02386D7E14784A6D7E4A6D7F130149486E7E4A6E7E130749C86C7E496F7E49
+7ED9FFC04A7E00076DEC7FFFB500FC0103B512FEA33F3E7EBD44>I<B66C0103B51280A3
+000101F0C8EBF8006C6C48ED3FC0725A013F041EC7FC6D7E606D6C15386D6C1578606D6C
+5D6E14016D5E6D6D1303606E6C49C8FC6E6C5B170E6E6C131E171C6E6C5B6E6C13781770
+6E6C13F06F5B6E13016EEB83C05FED7FC7DB3FE7C9FC16EFED1FFE5E150F6F5AB3A4ED1F
+FC020FB512FCA3413E7FBD44>I<003FB712F8A391C7EA1FF013F801E0EC3FE00180EC7F
+C090C8FC003EEDFF80A2003C4A1300007C4A5A12784B5A4B5AA200704A5AA24B5A4B5AA2
+C8485A4A90C7FCA24A5A4A5AA24A5AA24A5A4A5AA24A5A4A5AA24990C8FCA2495A494814
+1CA2495A495AA2495A495A173C495AA24890C8FC485A1778485A484815F8A24848140116
+034848140F4848143FED01FFB8FCA32E3E7BBD38>I<EAFFFCA4EAF000B3B3B3B3ABEAFF
+FCA40E5B77C319>I<486C13C00003130101001380481303000EEB070048130E0018130C
+0038131C003013180070133800601330A300E01370481360A400CFEB678039FFC07FE001
+E013F0A3007F133FA2003F131F01C013E0390F0007801C1C73BE2D>I<EAFFFCA4EA003C
+B3B3B3B3ABEAFFFCA40E5B7FC319>I<EA0180120313005A120E5A121812381230127012
+60A312E05AA412CFEAFFC013E0A3127FA2123F13C0EA0F000B1C7ABE19>96
+D<EB0FF8EBFFFE3903F01F8039078007E0000F6D7E9038E001F8D81FF07F6E7EA3157F6C
+5AEA0380C8FCA4EC1FFF0103B5FC90381FF87FEB7F803801FC00EA07F8EA0FE0485A485A
+A248C7FCEE038012FEA315FFA3007F5BEC03BF3B3F80071F8700261FC00E13CF3A07F03C
+0FFE3A01FFF807FC3A003FC001F0292A7DA82D>I<EA01FC12FFA3120712031201B1EC03
+FC91381FFF8091387C07E09039FDE001F09039FFC000FC4A137E91C77E49158049141F17
+C0EE0FE0A217F0A2160717F8AA17F0A2160FA217E0161F17C06D1580EE3F006D5C6E13FE
+9039F3C001F89039F1E003F09039E0780FC09026C03FFFC7FCC7EA07F82D407EBE33>I<
+49B4FC010F13E090383F00F8017C131E4848131F4848137F0007ECFF80485A5B121FA248
+48EB7F00151C007F91C7FCA290C9FC5AAB6C7EA3003FEC01C07F001F140316806C6C1307
+6C6C14000003140E6C6C131E6C6C137890383F01F090380FFFC0D901FEC7FC222A7DA828
+>I<ED01FC15FFA3150715031501B114FF010713E190381F80F990387E003D49131FD803
+F81307485A49130348481301121F123F5B127FA290C7FCA25AAA7E7FA2123FA26C7E000F
+14037F000714076C6C497E6C6C497ED8007C017913F890383F01F190380FFFC1903A01FE
+01FC002D407DBE33>I<EB01FE90380FFFC090383F03F09038FC01F848486C7E4848137E
+48487F000F158049131F001F15C04848130FA2127F16E090C7FCA25AA290B6FCA290C9FC
+A67EA27F123F16E06C7E1501000F15C06C6C13036DEB07806C6C1400C66C131E017E5B90
+381F80F8903807FFE0010090C7FC232A7EA828>I<EC1FC0EC7FF8903801F83C903807E0
+7E90380FC0FFEB1FC1EB3F811401137FEC00FE01FE137C1500AEB6FCA3C648C7FCB3AE48
+7E007F13FFA320407EBF1C>I<167C903903F801FF903A1FFF078F8090397E0FDE1F9038
+F803F83803F001A23B07E000FC0600000F6EC7FC49137E001F147FA8000F147E6D13FE00
+075C6C6C485AA23901F803E03903FE0FC026071FFFC8FCEB03F80006CAFC120EA3120FA2
+7F7F6CB512E015FE6C6E7E6C15E06C810003813A0FC0001FFC48C7EA01FE003E14004815
+7E825A82A46C5D007C153E007E157E6C5D6C6C495A6C6C495AD803F0EB0FC0D800FE017F
+C7FC90383FFFFC010313C0293D7EA82D>I<EA01FC12FFA3120712031201B1EC01FE9138
+07FFC091381E07E091387803F09138E001F8D9FDC07F148001FF6D7E91C7FCA25BA25BB3
+A6486C497EB5D8F87F13FCA32E3F7DBE33>I<EA01E0EA07F8A2487EA46C5AA2EA01E0C8
+FCACEA01FC127FA3120712031201B3AC487EB512F0A3143E7DBD1A>I<1478EB01FEA2EB
+03FFA4EB01FEA2EB00781400AC147FEB7FFFA313017F147FB3B3A5123E127F38FF807E14
+FEA214FCEB81F8EA7F01387C03F0381E07C0380FFF803801FC00185185BD1C>I<EA01FC
+12FFA3120712031201B292B51280A392383FFC0016E0168093C7FC153C5D5D4A5AEC07C0
+4A5A4AC8FC143E147F4A7E13FD9038FFDFC0EC9FE0140F496C7E01FC7F496C7E1401816E
+7E81826F7E151F826F7EA282486C14FEB539F07FFFE0A32B3F7EBE30>I<EA01FC12FFA3
+120712031201B3B3B1487EB512F8A3153F7DBE1A>I<2701F801FE14FF00FF902707FFC0
+0313E0913B1E07E00F03F0913B7803F03C01F80007903BE001F87000FC2603F9C06D487F
+000101805C01FBD900FF147F91C75B13FF4992C7FCA2495CB3A6486C496CECFF80B5D8F8
+7FD9FC3F13FEA347287DA74C>I<3901F801FE00FF903807FFC091381E07E091387803F0
+00079038E001F82603F9C07F0001138001FB6D7E91C7FC13FF5BA25BB3A6486C497EB5D8
+F87F13FCA32E287DA733>I<14FF010713E090381F81F890387E007E01F8131F4848EB0F
+804848EB07C04848EB03E0000F15F04848EB01F8A2003F15FCA248C812FEA44815FFA96C
+15FEA36C6CEB01FCA3001F15F86C6CEB03F0A26C6CEB07E06C6CEB0FC06C6CEB1F80D800
+7EEB7E0090383F81FC90380FFFF0010090C7FC282A7EA82D>I<3901FC03FC00FF90381F
+FF8091387C0FE09039FDE003F03A07FFC001FC6C496C7E6C90C7127F49EC3F805BEE1FC0
+17E0A2EE0FF0A3EE07F8AAEE0FF0A4EE1FE0A2EE3FC06D1580EE7F007F6E13FE9138C001
+F89039FDE007F09039FC780FC0DA3FFFC7FCEC07F891C9FCAD487EB512F8A32D3A7EA733
+>I<02FF131C0107EBC03C90381F80F090397F00387C01FC131CD803F8130E4848EB0FFC
+150748481303121F485A1501485AA448C7FCAA6C7EA36C7EA2001F14036C7E15076C6C13
+0F6C7E6C6C133DD8007E137990383F81F190380FFFC1903801FE0190C7FCAD4B7E92B512
+F8A32D3A7DA730>I<3901F807E000FFEB1FF8EC787CECE1FE3807F9C100031381EA01FB
+1401EC00FC01FF1330491300A35BB3A5487EB512FEA31F287EA724>I<90383FC0603901
+FFF8E03807C03F381F000F003E1307003C1303127C0078130112F81400A27E7E7E6D1300
+EA7FF8EBFFC06C13F86C13FE6C7F6C1480000114C0D8003F13E0010313F0EB001FEC0FF8
+00E01303A214017E1400A27E15F07E14016C14E06CEB03C0903880078039F3E01F0038E0
+FFFC38C01FE01D2A7DA824>I<131CA6133CA4137CA213FCA2120112031207001FB512C0
+B6FCA2D801FCC7FCB3A215E0A912009038FE01C0A2EB7F03013F138090381F8700EB07FE
+EB01F81B397EB723>I<D801FC14FE00FF147FA3000714030003140100011400B3A51501
+A31503120015076DEB06FF017E010E13806D4913FC90381FC078903807FFE00100903880
+FE002E297DA733>I<B539E00FFFE0A32707FE000313006C48EB00FC5E00015D7F00005D
+A26D13016D5CA26D6C485AA2ECC007011F91C7FCA290380FE00EA2ECF01E0107131CA26D
+6C5AA2ECFC7801011370A2ECFEF001005BA2EC7FC0A36E5AA26EC8FCA3140E2B287EA630
+>I<B53BC3FFFE03FFF8A3290FFE003FE00013C06C486D48EB3F806C4817006D010F141E
+00016F131C15076D163C00004A6C1338A2017F5E4B7E151DD93F805DED3DFC1538D91FC0
+4A5AED78FE9238707E03D90FE0017F5BEDE03F02F0140701070387C7FC9138F1C01F02F9
+148F010315CE9138FB800F02FF14DE6D15FCED00076D5DA24A1303027E5CA2027C130102
+3C5C023813003D287EA642>I<B539F01FFFE0A30003D9C00F1300C690388007F8D97F00
+13E002805BD93FC05B011F49C7FC90380FE00EECF01E6D6C5A01035B6D6C5A6E5AEB00FF
+6E5A6E5A81141F814A7E81147BECF1FC903801E1FEECC0FF01037F49486C7ED90F007F01
+1E6D7E013E130F496D7E01FC80486C80000F4A7EB539803FFFF8A32D277FA630>I<B539
+E00FFFE0A32707FE000313006C48EB01FC6F5A00015D7F00005DA2017F495AA2EC800301
+3F5CA26D6C48C7FCA26E5A010F130EA26D6C5AA2ECF83C01031338A26D6C5AA2ECFEF001
+005BA2EC7FC0A36E5AA36EC8FCA2140EA2141E141C143C1438A2147800181370127EB45B
+A2495AA248485AD87E07C9FCEA780EEA3C3CEA1FF8EA07E02B3A7EA630>I<001FB61280
+A2EBE0000180140049485A001E495A121C4A5A003C495A141F00385C4A5A147F5D4AC7FC
+C6485AA2495A495A130F5C495A90393FC00380A2EB7F80EBFF005A5B4848130712074914
+00485A48485BA248485B4848137F00FF495A90B6FCA221277EA628>I<B812F0A22C0280
+982D>I E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fh cmbx10 10.95 43
+/Fh 43 122 df<EA0FC0EA1FE0EA3FF0EA7FF8EAFFFCA6EA7FF8EA3FF0EA1FE0EA0FC00E
+0E798D1D>46 D<140F143F5C495A130F48B5FCB6FCA313F7EAFE071200B3B3A8007FB612
+F0A5243C78BB34>49 D<903803FF80013F13F890B512FE00036E7E4881260FF80F7F261F
+C0037F4848C67F486C6D7E6D6D7E487E6D6D7EA26F1380A46C5A6C5A6C5A0007C7FCC8FC
+4B1300A25E153F5E4B5AA24B5A5E4A5B4A5B4A48C7FC5D4A5AEC1FE04A5A4A5A9139FF00
+0F80EB01FC495A4948EB1F00495AEB1F8049C7FC017E5C5B48B7FC485D5A5A5A5A5AB7FC
+5EA4293C7BBB34>I<903801FFE0010F13FE013F6D7E90B612E04801817F3A03FC007FF8
+D807F06D7E82D80FFC131F6D80121F7FA56C5A5E6C48133FD801F05CC8FC4B5A5E4B5A4A
+5B020F5B902607FFFEC7FC15F815FEEDFFC0D9000113F06E6C7E6F7E6F7E6F7E1780A26F
+13C0A217E0EA0FC0487E487E487E487EA317C0A25D491580127F49491300D83FC0495A6C
+6C495A3A0FFE01FFF86CB65A6C5DC61580013F49C7FC010313E02B3D7CBB34>I<ED01F8
+15031507A2150F151F153FA2157F15FF5C5CA25C5CEC1FBFEC3F3F143E147C14FCEB01F8
+14F0EB03E01307EB0FC0EB1F801400133E137E5B485A5B485A1207485A5B48C7FC5A127E
+5AB812F8A5C8387FF800AA49B612F8A52D3C7DBB34>I<00071538D80FE0EB01F801FE13
+3F90B6FC5E5E5E5E93C7FC5D15F85D15C04AC8FC0180C9FCA9ECFFC0018713FC019F13FF
+90B67E020113E09039F8007FF0496D7E01C06D7E5B6CC77FC8120F82A31780A21207EA1F
+C0487E487E12FF7FA21700A25B4B5A6C5A01805C6CC7123F6D495AD81FE0495A260FFC07
+5B6CB65A6C92C7FCC614FC013F13F0010790C8FC293D7BBB34>I<EC07FF023F13C049B5
+12F001078049EB03FC90383FF80090397FE001FE9038FFC0034849487E48495AA2485A12
+0FA2485A6F5A003F6E5A6F5A92C8FC485AA21402EC3FFE00FF496C7E01F9B512E001FB80
+9138E03FF89039FF800FFC4A6C7E825B6F13804915C0A317E05BA4127FA5123FA26D15C0
+121FA2000F4A13806D150012076C6C495A6C6D485A6C9038E07FF86DB55A6D5C6D148001
+0749C7FC010013F02B3D7CBB34>I<ECFFF0010713FE011F6D7E017F14E09039FFC07FF0
+3A01FE001FF848486D7E48486D7E1503485A8281121FA27F7F7F6D5B02C05B14F06C6D48
+5A9138FE0FF89138FF9FF06CECFFE06C5D5E6C92C7FC6C816D14E0011F80498090B67E48
+812607FE3F7F48486C1480381FF807D9F00114C048486C7E007F8049010F13E015034848
+7F81167FA2163FA36D15C0127FEE7F807F6C6CECFF006C6C5B01FEEB07FE3A0FFFC03FFC
+6C90B55A000115E06C6C5C011F49C7FC010113F02B3D7CBB34>56
+D<B812F8EFFF8018F018FC8426003FFCC7EA3FFF050F13807113C07113E08319F0A27113
+F8A719F05FA24D13E019C04D13804D1300EF3FFE933801FFF891B712E0188018F818FE02
+FCC7380FFF80050313C07113E07113F019F8F07FFCA2F03FFEA219FFA38460A419FE187F
+A2F0FFFC4D13F85F4D13F0053F13E0BA12C0190018FC18F095C7FC403E7DBD4A>66
+D<922607FFC0130E92B500FC131E020702FF133E023FEDC07E91B7EAE1FE01039138803F
+FB499039F80003FF4901C01300013F90C8127F4948151FD9FFF8150F48491507485B4A15
+03481701485B18004890CAFC197E5A5B193E127FA349170012FFAC127F7F193EA2123FA2
+7F6C187E197C6C7F19FC6C6D16F86C6D150119F06C6D15036C6DED07E0D97FFEED0FC06D
+6CED3F80010F01C0ECFF006D01F8EB03FE6D9039FF801FFC010091B55A023F15E0020715
+80020002FCC7FC030713C03F407ABE4C>I<BAFCA4198026003FFEC7123F170717018318
+3FA2181FF00FC0A31807EE07C0A3F003E0A3160F95C7FC161F163F16FF91B6FCA54AC6FC
+163F161F040F147CA2160719F8A593C71201A219F01803A21807A2180FF01FE0183F18FF
+1703173FBAFCA219C0A33E3D7DBC45>69 D<B912FEA48426003FFEC77E170F1703170084
+A284F01F80A3180FA2EE07C0A2F007C0A4040F90C7FCA2161F163F16FF91B6FCA54AC6FC
+163F161F160FA21607A693C9FCACB712E0A53A3D7DBC42>I<922607FFC0130E92B500FC
+131E020702FF133E023FEDC07E91B7EAE1FE01039138803FFB499039F80003FF4901C013
+00013F90C8127F4948151FD9FFF8150F48491507485B4A1503481701485B18004890CAFC
+197E5A5B193E127FA34994C7FC12FFAB0407B612FC127F7FA3003F92C7383FFE00A27F7E
+A26C7FA26C7F6C7FA26C7F6C7FD97FFE157F6D6C7E010F01E014FF6D01F813036D9038FF
+801F010091B512F3023F15C00207ED803E02009138FE000E030701E090C7FC46407ABE52
+>I<B71280A526003FFEC7FCB3B3B0B71280A5213E7DBD28>73 D<B76C90B6FCA526003F
+FEC8D801FCC7FCF007F84E5A4E5AF03F804EC8FC18FEEF03FC4D5A4D5AEF1FC04D5A4DC9
+FCEE01FE4C5A4C5AEE0FE04C5A4C5A16FF4B7F4B7F5D4B7F4B7F037F7F92B5FC6E486C7E
+9238F83FFF03F0804B7E4B6C7F4B6C7F0300804A7F707F707F84717E83717F85717F8371
+7F85717F83727E85727F84B7D88007B612C0A54A3E7DBD52>75 D<B6037FB512E0A28181
+81D8003F6D9139001F800081A281816E7E6E7F6E7F80826E7F6E7F6E7F6E7F157F826F7F
+6F7F6F7F6F7F81836F7F6F7F707E701380A27013C07013E07013F07013F87013FCA27013
+FEEF7FFF71139F7113DF8319FF8383838384A28484848484A284B600C080197F193F191F
+A24B3E7DBD52>78 D<ED3FFF0203B512F0021F14FE027F6E7E902701FFF80713E00107D9
+C00013F84990C7EA3FFCD93FFCEC0FFF49486E7F49486E7F48496E7F4A80488448496F7E
+A24890C96C7E4884A249161F003F84A34848701380A400FF19C0AD007F19806D5EA3003F
+1900A26D5E6C60A26C6D4B5AA26C6D4B5A6C6D4A5BA26C6D4A5B6C6D4A5B6D6C4A5B6DB4
+023F90C7FC6D01C0EBFFFE0107D9F80713F8010190B612E06D5E021F4AC8FC020314F0DA
+003F90C9FC42407ABE4F>I<B812F017FF18C018F018FC26003FFCC77FEF1FFF71138071
+13C07113E0A27113F0A319F8A819F0A34D13E019C05F4D1380053F1300EFFFFE91B712F8
+60188005FCC7FC4ACAFCB3A4B77EA53D3E7DBD47>I<B87E17FCEFFF8018F08428003FFC
+000113FE9338003FFF050F7F717F717FA2858385A761A25F61614D5B4D90C8FCEF3FFE4C
+B45A91B712F018C04DC9FC717E9126FC000F7F040113F0707F717EA2717EA2717EA685A6
+F207C019C0A271140F07E01380B76DEBF01F719038FC3F007190B5FC716C5B061F13F8CB
+000113E04A3F7DBD4E>82 D<903A03FFC001C0011FEBF803017FEBFE0748B6128F4815DF
+48010013FFD80FF8130F48481303497F4848EB007F127F49143F161F12FF160FA27F1607
+A27F7F01FC91C7FCEBFF806C13F8ECFFC06C14FCEDFF806C15E016F86C816C816C816C16
+806C6C15C07F010715E0EB007F020714F0EC003F1503030013F8167F163F127800F8151F
+A2160FA27EA217F07E161F6C16E06D143F01E015C001F8EC7F8001FEEB01FF9026FFE007
+13004890B55A486C14F8D8F81F5CD8F00314C027E0003FFEC7FC2D407ABE3A>I<003FB9
+12FCA5903BFE003FFE003FD87FF0EE0FFE01C0160349160190C71500197E127EA2007C18
+3EA400FC183F48181FA5C81600B3AF010FB712F8A5403D7CBC49>I<B76C90B61280A526
+003FFEC9003EC7FCB3B3A4197E011F177C80A26D17FC616D6D14014E5A6D6D4A5A6D6D14
+0F6D01F8EC3FC0DA7FFEECFF8091273FFFC00F90C8FC020F90B512FC02035D020015E003
+1F1480030101F8C9FC493F7DBD50>I<903807FFC0013F13F848B6FC48812607FE037F26
+0FF8007F6DEB3FF0486C806F7EA36F7EA26C5A6C5AEA01E0C8FC153F91B5FC130F137F39
+01FFFE0F4813E0000F1380381FFE00485A5B485A12FF5BA4151F7F007F143F6D90387BFF
+806C6C01FB13FE391FFF07F36CEBFFE100031480C6EC003FD91FF890C7FC2F2B7DA933>
+97 D<13FFB5FCA512077EAFEDFFE0020713FC021FEBFF80027F80DAFF8113F09139FC00
+3FF802F06D7E4A6D7E4A13074A80701380A218C082A318E0AA18C0A25E1880A218005E6E
+5C6E495A6E495A02FCEB7FF0903AFCFF01FFE0496CB55AD9F01F91C7FCD9E00713FCC700
+0113C033407DBE3A>I<EC7FF00107B5FC011F14C0017F14E09039FFF01FF0489038800F
+F848EB001F4848EB3FFC120F485AA2485AA2007FEC1FF849EB0FF0ED03C000FF91C7FCAB
+127F7FA3003F153E7F001F157E6C6C147C6C6C14FC91388001F86C9038C003F0C69038F8
+1FE06DB512C0011F14800107EBFE009038007FF0272B7DA92E>I<EE07F8ED07FFA5ED00
+3F161FAFEC7FF0903807FFFE011FEBFF9F017F14DF9039FFF01FFF48EBC00348EB000148
+48EB007F485A001F153F5B123FA2127F5BA212FFAA127FA37F123FA26C6C147F120F6D14
+FF6C6C01037F6C6D48EBFFE06CEBF03F6C6CB512BF6D143F010713FC010001E0EBE00033
+407DBE3A>I<ECFFF0010713FE011F6D7E017F809039FFE07FE0489038801FF048496C7E
+48486D7E48486D7E121F491301003F81A2485A6F1380A212FFA290B7FCA401F0C9FCA512
+7FA27F123FEE0F806C7E161F6C6C15006C6C5C6C6D137E6C9038E001FC6C9038F80FF801
+3FB55A6D14C0010391C7FC9038007FF8292B7DA930>I<EC07FE91387FFF8049B512C001
+0714E090390FFE3FF0EB1FF090393FE07FF8EB7FC013FF1480A2489038003FF0ED1FE0ED
+0FC092C7FCAAB612E0A500010180C7FCB3AC007FEBFF80A525407DBF20>I<903A03FF80
+07F0013F9038F83FF8499038FCFFFC48B712FE48018313F93A07FC007FC34848EB3FE100
+1FEDF1FC4990381FF0F81700003F81A7001F5DA26D133F000F5D6C6C495A3A03FF83FF80
+91B5C7FC4814FC01BF5BD80F03138090CAFCA2487EA27F13F06CB6FC16F016FC6C15FF17
+806C16C06C16E01207001F16F0393FE000034848EB003F49EC1FF800FF150F90C81207A5
+6C6CEC0FF06D141F003F16E001F0147FD81FFC903801FFC02707FF800F13006C90B55AC6
+15F8013F14E0010101FCC7FC2F3D7DA834>I<EA01F8487E487E487E481380A66C13006C
+5A6C5A6C5AC8FCA913FFB5FCA512077EB3ABB512F8A515407CBF1D>105
+D<13FFB5FCA512077EB3B3AFB512FCA5163F7CBE1D>108 D<01FFD91FF8ECFFC0B590B5
+010713F80203DAC01F13FE4A6E487FDA0FE09026F07F077F91261F003FEBF8010007013E
+DAF9F0806C0178ECFBC04A6DB4486C7FA24A92C7FC4A5CA34A5CB3A4B5D8FE07B5D8F03F
+EBFF80A551297CA858>I<01FFEB1FF8B5EBFFFE02036D7E4A80DA0FE07F91381F007F00
+07013C806C5B4A6D7E5CA25CA35CB3A4B5D8FE0FB512E0A533297CA83A>I<EC7FF09038
+03FFFE011FEBFFC0017F14F09039FFE03FF8489038800FFC3A03FE0003FE48486D7E000F
+168048486D13C0A2003F16E049147F007F16F0A400FF16F8AA007F16F0A46C6CECFFE0A2
+001F16C06C6C491380A26C6C4913003A03FF800FFE6C9038E03FFC6C6CB512F0011F14C0
+010791C7FC9038007FF02D2B7DA934>I<01FFEBFFE0B5000713FC021FEBFF80027F80DA
+FF8113F09139FC007FF8000701F06D7E6C496D7E4A130F4A6D7E1880A27013C0A38218E0
+AA4C13C0A318805E18005E6E5C6E495A6E495A02FCEBFFF0DAFF035B92B55A029F91C7FC
+028713FC028113C00280C9FCACB512FEA5333B7DA83A>I<3901FE01FE00FF903807FF80
+4A13E04A13F0EC3F1F91387C3FF8000713F8000313F0EBFFE0A29138C01FF0ED0FE09138
+8007C092C7FCA391C8FCB3A2B6FCA525297DA82B>114 D<90383FFC1E48B512BE000714
+FE5A381FF00F383F800148C7FC007E147EA200FE143EA27E7F6D90C7FC13F8EBFFE06C13
+FF15C06C14F06C806C806C806C80C61580131F1300020713C014000078147F00F8143F15
+1F7EA27E16806C143F6D140001E013FF9038F803FE90B55A15F0D8F87F13C026E00FFEC7
+FC222B7DA929>I<EB07C0A5130FA4131FA3133F137FA213FF5A1207001FEBFFFEB6FCA4
+0001EBC000B3151FA96CEBE03EA2017F137EECF8FC90383FFFF86D13F0010713E0010013
+80203B7EB929>I<D9FF80EB0FF8B5EB0FFFA50007EC007F6C153FB3A5167FA316FF6C5C
+4B7F6C903AC007DFFFE09138F01F9F6DB5121F6D13FE010F13F8010101E0EBE000332A7C
+A83A>I<B500FC90383FFFC0A5000101C0903803E0006E1307A26C5E6E130F017F5D6E13
+1F013F92C7FC6E5B011F143E6E137E010F147C6E13FCA26D5C15816D5C15C36D5C15E76D
+5C15FF6E5BA36E90C8FCA26E5AA26E5AA26E5AA26E5AA232287EA737>I<B53CFC3FFFFC
+03FFFEA50003D980009039C0000F806E161F6C037F15006E496C5B6C183E836E48157E01
+7F177C6E486D13FC013F02EF5C83DAFC071401011F02C75CDAFE0FEBFE03010F02835C17
+FFDAFF1F14076D02015C03BF148F6DD9BE005C18CF03FE14DF6D49017F90C7FC18FF6D49
+6D5AA36E486D5AA26E486D5AA36E486D5AA26E486D5A47287EA74C>I<B5D8FC03B51280
+A5C69026E0007FC7FC6E13FE6D6C5B6D6C485A6D6C485A010F13076D6C485AED9FC06DEB
+FF806D91C8FC6D5B6E5AA2143F6E7E140F814A7F4A7F4A7F02FE7F903801FC7F49486C7E
+02F07F49486C7E49486C7E011F7F49486C7FD97F008001FE6D7FB5D8C007EBFFC0A53228
+7EA737>I<B500FC90383FFFC0A5000101C0903803E0006E1307A26C5E6E130F017F5D6E
+131F013F92C7FC6E5B011F143E6E137E010F147C6E13FCA26D5C15816D5C15C36D5C15E7
+6D5C15FF6E5BA36E90C8FCA26E5AA26E5AA26E5AA26E5AA35D14075D000E130FD83F805B
+387FC01FD8FFE090C9FC5C143E147E5CEBC1F8387FC3F0387E0FE06CB45A6C5B6C48CAFC
+EA03F8323B7EA737>I E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fi cmbx12 14.4 33
+/Fi 33 121 df<157815FC14031407141F14FF130F0007B5FCB6FCA2147F13F0EAF800C7
+FCB3B3B3A6007FB712FEA52F4E76CD43>49 D<EC3FFE0103B512E0010F14FC013F14FF90
+B712C048D9C07F7F2703FE000F13F8D807F801037FD80FE06D7F48486D7F48488001F016
+80486C6E13C07F486C6E13E07FA27013F0A56C5AA26C5AEA0FF0EA03C0C914E05EA218C0
+5E1880A24C13005F4C5A4B5B5F4B5B5F4B5B4B90C7FC4B5A5E4B5AED7FE04B5A4A5B4A48
+C8FC4A5A5D4A48EB01F04A5AEC3F804AC7FC02FEEC03E0495A495A495A495AD91F801407
+49C8FC013E150F017FB7FC90B812C05A5A5A5A5A5A5AB9FC1880A4344E79CD43>I<9138
+0FFFC091B512FC0107ECFF80011F15E090263FF8077F9026FF800113FC4848C76C7ED803
+F86E7E491680D807FC8048B416C080486D15E0A4805CA36C17C06C5B6C90C75AD801FC16
+80C9FC4C13005FA24C5A4B5B4B5B4B13C04B5BDBFFFEC7FC91B512F816E016FCEEFF80DA
+000713E0030113F89238007FFE707E7013807013C018E07013F0A218F8A27013FCA218FE
+A2EA03E0EA0FF8487E487E487EB57EA318FCA25E18F891C7FC6C17F0495C6C4816E001F0
+4A13C06C484A1380D80FF84A13006CB44A5A6CD9F0075BC690B612F06D5D011F15800103
+02FCC7FCD9001F1380374F7ACD43>I<177C17FEA2160116031607160FA2161F163F167F
+A216FF5D5DA25D5DED1FBFED3F3F153E157C15FCEC01F815F0EC03E01407EC0FC01580EC
+1F005C147E147C5C1301495A495A5C495A131F49C7FC133E5B13FC485A5B485A1207485A
+485A90C8FC123E127E5ABA12C0A5C96C48C7FCAF020FB712C0A53A4F7CCE43>I<D80380
+150ED807E0157E01FEEC03FED9FFF0137F91B65A5F5F5F5F5F94C7FC5E5E16F016C093C8
+FC15F801E190C9FC01E0CAFCABEC0FFF027F13F001E3B512FE01E76E7E9026FFF8077FDA
+C0017F49C713F8496E7E49143F4981496E7E6C481680C9FC18C08218E0A418F0A3EA0FE0
+487E487E487E487EA418E0A35B6C484A13C05B491680003EC85A003F17006C6C4A5A6D5D
+6C6C4A5AD807F8495BD803FE01075B2701FFC03F5B6C90B65A013F4AC7FC6D14F8010314
+C09026007FF8C8FC344F79CD43>I<ED0FFF92B512E0020780021F14FC91397FFE03FE90
+3A01FFF0007F4901C0EB3F804990C7121F4948EC7FC0494814FF49484913E049485B01FF
+5C485BA2485B5AA2486F13C04A6D1380486F1300177E94C7FC5AA291CAFC5AA215089138
+01FFF8020713FFB54814C04A14F04AC66C7E023C6D7E4A6D7E4A6D7E7013804A15C0A24A
+15E07013F05C18F8A491C714FCA37EA67EA46C17F880A27E18F06C5D18E06C6D15C07E6E
+4913806C6D15006D6C495A6D6CEB7FFC6DB448485A6D90B55A010315C0010092C7FC023F
+13FC020713C0364F7ACD43>I<932601FFFCEC01C0047FD9FFC013030307B600F8130703
+3F03FE131F92B8EA803F0203DAE003EBC07F020F01FCC7383FF0FF023F01E0EC0FF94A01
+800203B5FC494848C9FC4901F8824949824949824949824949824990CA7E494883A24849
+83485B1B7F485B481A3FA24849181FA3485B1B0FA25AA298C7FC5CA2B5FCAE7EA280A2F3
+07C07EA36C7FA21B0F6C6D1980A26C1A1F6C7F1C006C6D606C6D187EA26D6C606D6D4C5A
+6D6D16036D6D4C5A6D6D4C5A6D01FC4C5A6D6DEE7F806D6C6C6C4BC7FC6E01E0EC07FE02
+0F01FEEC1FF80203903AFFE001FFF0020091B612C0033F93C8FC030715FCDB007F14E004
+0101FCC9FC525479D261>67 D<BC1280A5D8000701F8C7000114C0F0001F19071901851A
+7F1A3F1A1FA2F20FE0A21A07A31A03A318F81BF01A01A497C7FC1701A317031707170F17
+7F92B6FCA59238F8007F170F170717031701A317001B3EA31B7CA395C8FCA21BFCA21BF8
+A21A01A31A031BF01A071A0FA21A1F1A3FF27FE0F101FF1907191F0603B5FCBCFCA21BC0
+A34F517CD058>69 D<BB12FEA5D8000701F8C700077FF0007F191F190785858586861B80
+A21A1FA31A0FA41BC006F81307A497C7FCA31701A317031707170F177F92B6FCA59238F8
+007F170F170717031701A31700A795C9FCB3B812F8A54A517CD055>I<B812C0A5D80007
+01F8C7FCB3B3B3B2B812C0A52A527CD132>73 D<B600FC93B7FC8181A282D800076E9239
+003FFC0070EE07E08282A28202EF7F02E77F02E380A202E18002E0806F7F6F7F6F7FA26F
+7F6F7F6F806F80A26F80707F707F707F707FA2707F7080708070808583717F717F717F71
+7FA27114807114C07114E07213F07213F8A27213FC7213FE7213FF721487A27214C77214
+E77313F77313FF85A285858585A28586868686A286868686A2D93FFC187FB7173F1B1F1B
+0F1B07755A60527CD169>78 D<93380FFFC00303B6FC031F15E092B712FC0203D9FC0013
+FF020F01C0010F13C0023F90C7000313F0DA7FFC02007F494848ED7FFE4901E0ED1FFF49
+496F7F49496F7F4990C96C7F49854948707F4948707FA24849717E48864A83481B804A83
+481BC0A2481BE04A83A2481BF0A348497113F8A5B51AFCAF6C1BF86E5FA46C1BF0A26E5F
+6C1BE0A36C6D4D13C0A26C6D4D1380A26C1B006C6D4D5A6E5E6C626D6C4C5B6D6D4B5B6D
+6D4B5B6D6D4B5B6D6D4B5B6D6D4B90C7FC6D6D4B5A6D01FF02035B023F01E0011F13F002
+0F01FC90B512C0020390B7C8FC020016FC031F15E0030392C9FCDB001F13E0565479D265
+>I<BAFC19F819FF1AE086D8000701F0C7001F13FC060113FF726C13807313C0070F13E0
+1BF0857313F81BFCA27313FEA41BFFA81BFEA31BFC61A21BF84F13F04F13E0614F13C04F
+13004E485A061F5B92B812F01AC04FC7FC19E003F8CBFCB3AEB812C0A550527CD15C>I<
+B912F0F0FF8019F819FF1AC0D8000701F0C714F0060F7F060113FE727F737F737F85737F
+87A2737FA387A863A2616363A24F5B4F5B4F90C8FC4F5A06035B060F13F095B512C092B8
+C9FC19F819E019F89226F0000313FE9439007FFF80727F727F727F727F727F8684A28684
+A787A71D1C75133EA38575137E73157C7513FC731401B86C6D9038F803F807039038FE07
+F07390B512E0736C14C0080F1400CEEA7FFC5F537CD164>82 D<91260FFF80130791B500
+F85B010702FF5B011FEDC03F49EDF07F9026FFFC006D5A4801E0EB0FFD4801800101B5FC
+4848C87E48488149150F001F824981123F4981007F82A28412FF84A27FA26D82A27F7F6D
+93C7FC14C06C13F014FF15F86CECFF8016FC6CEDFFC017F06C16FC6C16FF6C17C06C836C
+836D826D82010F821303010082021F16801400030F15C0ED007F040714E01600173F050F
+13F08383A200788200F882A3187FA27EA219E07EA26CEFFFC0A27F6D4B13806D17006D5D
+01FC4B5A01FF4B5A02C04A5A02F8EC7FF0903B1FFFC003FFE0486C90B65AD8FC0393C7FC
+48C66C14FC48010F14F048D9007F90C8FC3C5479D24B>I<003FBC1280A59126C0003F90
+38C0007F49C71607D87FF8060113C001E08449197F49193F90C8171FA2007E1A0FA3007C
+1A07A500FC1BE0481A03A6C994C7FCB3B3AC91B912F0A553517BD05E>I<B800C00103B6
+12FCA5D8000701F8CAEBF000F31F80B3B3B11B3FA26D97C7FC81637F1B7E6D6D17FE505A
+6E7E505A6E6D15076E4D5A6E6D4B5A6E6D4B5A6E01F84B5A6E6DDA03FFC8FC6E6CB46CEB
+0FFE6F9039F001FFF8030F90B65A030316C0DB007F92C9FC040F14F8DC007F13805E537C
+D167>I<EC7FFF0107B512F0013F14FE90B77E48D9E00F7F2703FE000113F0486C6D7F6E
+EB3FFC48826E131F83707FA36C496D7FA26C90C7FC6C5AC9FCA6037FB5FC020FB6FC91B7
+FC01071487013FEBF0074913803901FFFC004813F0485B485B485B4890C7FC5A5BA2485A
+A45EA26D5C007F151D163D6C6C02797F6C6D01F113F86C9026C003E1EBFFE06C9026F81F
+C014F06C90B5487EC6ED001F011F01FC010713E0010101E090C8FC3C387CB641>97
+D<913801FFF8021FEBFF8091B612F0010315FC010F9038C00FFE903A1FFE0001FFD97FFC
+491380D9FFF05B4817C048495B5C5A485BA2486F138091C7FC486F1300705A4892C8FC5B
+A312FFAD127F7FA27EA2EF03E06C7F17076C6D15C07E6E140F6CEE1F806C6DEC3F006C6D
+147ED97FFE5C6D6CEB03F8010F9038E01FF0010390B55A01001580023F49C7FC020113E0
+33387CB63C>99 D<4DB47E0407B5FCA5EE001F1707B3A4913801FFE0021F13FC91B6FC01
+0315C7010F9038E03FE74990380007F7D97FFC0101B5FC49487F4849143F484980485B83
+485B5A91C8FC5AA3485AA412FFAC127FA36C7EA37EA26C7F5F6C6D5C7E6C6D5C6C6D49B5
+FC6D6C4914E0D93FFED90FEFEBFF80903A0FFFC07FCF6D90B5128F0101ECFE0FD9003F13
+F8020301C049C7FC41547CD24B>I<913803FFC0023F13FC49B6FC010715C04901817F90
+3A3FFC007FF849486D7E49486D7E4849130F48496D7E48178048497F18C0488191C7FC48
+17E0A248815B18F0A212FFA490B8FCA318E049CAFCA6127FA27F7EA218E06CEE01F06E14
+037E6C6DEC07E0A26C6DEC0FC06C6D141F6C6DEC3F806D6CECFF00D91FFEEB03FE903A0F
+FFC03FF8010390B55A010015C0021F49C7FC020113F034387CB63D>I<DA3FFF14FF0103
+B5D8F00713C0010FDAFC1F13E0013FECFF7F90267FFC0F9038FF9FF09026FFE001EBF83F
+48496C13E0484990387FF01F4890C7D83FF813E0489338FC0FC0F0078048486E6CC7FCA2
+003F82A9001F5EA26C6C4A5AA26C5E6C6D495A6C6D495A6C6D485BDAFC0F5B4890B6C8FC
+D803EF14FC01C314F02607C03F90C9FC91CBFCA2120FA37FA213F813FE90B7FC6C16F817
+FF18C06C836C836C836D828448B9FC12074848C700031480D81FF8EC003F484815074848
+6F13C083485A83A56D5D007F18806D5D003F18006C6C4B5AD80FFEED1FFC6C6C6CEC7FF8
+6C01E049485A6C01FE011F5B6C6CB71280010F03FCC7FC010115E0D9000F01FCC8FC3C4F
+7CB543>103 D<137F497E000313E0487FA2487FA76C5BA26C5BC613806DC7FC90C8FCAD
+EB3FF0B5FCA512017EB3B3A6B612E0A51B547BD325>105 D<EB3FF0B5FCA512017EB3B3
+B3B1B612F0A51C537BD225>108 D<D93FF0D91FFCEDFFE0B591B500C0010713FE030302
+F0011F6D7E030F6E017F8092271FE07FFCD9FF037F922A3F001FFE01F8007F0003027C91
+26FF03E080C602F06DD90780137FDAF1E0038FC77FDAF3C0159EDAF7806D01BC143F07FC
+8102FFC75C4A5EA24A5EA44A5EB3ACB6D8F807B6D8C03FB512FEA567367BB570>I<D93F
+F0EB1FFCB591B512C0030314F0030F8092391FE07FFC92393F001FFE0003027C80C602F0
+7FDAF1E081ECF3C0DAF7807F8502FFC7FC5CA25CA45CB3ACB6D8F807B612C0A542367BB5
+4B>I<913801FFE0021F13FE91B612C0010315F0010F9038807FFC903A1FFC000FFED97F
+F86D6C7E49486D7F48496D7F48496D7F4A147F48834890C86C7EA24883A248486F7EA300
+7F1880A400FF18C0AC007F1880A3003F18006D5DA26C5FA26C5F6E147F6C5F6C6D4A5A6C
+6D495B6C6D495B6D6C495BD93FFE011F90C7FC903A0FFF807FFC6D90B55A010015C0023F
+91C8FC020113E03A387CB643>I<903A3FF001FFE0B5010F13FE033FEBFFC092B612F002
+F301017F913AF7F8007FFE0003D9FFE0EB1FFFC602806D7F92C76C7F4A824A6E7F4A6E7F
+A2717FA285187F85A4721380AC1A0060A36118FFA2615F616E4A5BA26E4A5B6E4A5B6F49
+5B6F4990C7FC03F0EBFFFC9126FBFE075B02F8B612E06F1480031F01FCC8FC030313C092
+CBFCB1B612F8A5414D7BB54B>I<90397FE003FEB590380FFF80033F13E04B13F09238FE
+1FF89139E1F83FFC0003D9E3E013FEC6ECC07FECE78014EF150014EE02FEEB3FFC5CEE1F
+F8EE0FF04A90C7FCA55CB3AAB612FCA52F367CB537>114 D<903903FFF00F013FEBFE1F
+90B7FC120348EB003FD80FF81307D81FE0130148487F4980127F90C87EA24881A27FA27F
+01F091C7FC13FCEBFFC06C13FF15F86C14FF16C06C15F06C816C816C81C681013F158001
+0F15C01300020714E0EC003F030713F015010078EC007F00F8153F161F7E160FA27E17E0
+7E6D141F17C07F6DEC3F8001F8EC7F0001FEEB01FE9039FFC00FFC6DB55AD8FC1F14E0D8
+F807148048C601F8C7FC2C387CB635>I<143EA6147EA414FEA21301A313031307A2130F
+131F133F13FF5A000F90B6FCB8FCA426003FFEC8FCB3A9EE07C0AB011FEC0F8080A26DEC
+1F0015806DEBC03E6DEBF0FC6DEBFFF86D6C5B021F5B020313802A4D7ECB34>I<D93FF8
+913801FFC0B50207B5FCA50003ED001FC61607B3AE5FA35FA2017F5D173B177B6D6C14F3
+DC01E313F06D6CD907C3EBFFC0903A0FFFC03F836D90B51203010114FE6D6C13F8020701
+E091C7FC42377BB54B>I<007FB500F090387FFFFEA5C66C48C7000F90C7FC6D6CEC07F8
+6D6D5C6D6D495A6D4B5A6F495A6D6D91C8FC6D6D137E6D6D5B91387FFE014C5A6E6C485A
+6EEB8FE06EEBCFC06EEBFF806E91C9FCA26E5B6E5B6F7E6F7EA26F7F834B7F4B7F92B5FC
+DA01FD7F03F87F4A486C7E4A486C7E020F7FDA1FC0804A486C7F4A486C7F02FE6D7F4A6D
+7F495A49486D7F01076F7E49486E7E49486E7FEBFFF0B500FE49B612C0A542357EB447>
+120 D E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fj cmsy8 8 1
+/Fj 1 4 df<130C131EA50060EB01800078130739FC0C0FC0007FEB3F80393F8C7F0038
+07CCF83801FFE038007F80011EC7FCEB7F803801FFE03807CCF8383F8C7F397F0C3F8000
+FCEB0FC039781E078000601301000090C7FCA5130C1A1D7C9E23>3
+D E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fk cmr12 12 16
+/Fk 16 122 df<14FF010713E090381F81F890383E007C01FC133F4848EB1F8049130F48
+48EB07C04848EB03E0A2000F15F0491301001F15F8A2003F15FCA390C8FC4815FEA54815
+FFB3A46C15FEA56D1301003F15FCA3001F15F8A26C6CEB03F0A36C6CEB07E0000315C06D
+130F6C6CEB1F806C6CEB3F00013E137C90381F81F8903807FFE0010090C7FC28447CC131
+>48 D<EB03FE90381FFFC0017F13F03901F80FFC3903C001FE48486C7E000EC7EA7F8048
+EC3FC0ED1FE04815F00030140F007015F800601407126CB415FC7F7F1503A46C4813076C
+C7FCC8FC16F8A2150F16F0151F16E0A2ED3FC0ED7F8016005D5D4A5A4A5A4A5A5D4A5A4A
+5A4AC7FC147C5C5C495A495A495A49C7120C131E5B013814185B5B485A4848143848C812
+30000E1570001FB612F0A25A5AB712E0A326427BC131>50 D<49B4FC010F13E0013F13FC
+9038FE01FE3A01F0007F80D803C0EB3FC048C7EA1FE0120EED0FF0EA0FE0486C14F8A215
+077F5BA26C48130FEA03C0C813F0A3ED1FE0A2ED3FC01680ED7F0015FE4A5AEC03F0EC1F
+C0D90FFFC7FC15F090380001FCEC007FED3F80ED1FC0ED0FE016F0ED07F816FC150316FE
+A2150116FFA3121EEA7F80487EA416FE491303A2007EC713FC00701407003015F8003814
+0F6C15F06CEC1FE06C6CEB3FC0D803E0EB7F803A01FE01FE0039007FFFF8010F13E00101
+90C7FC28447CC131>I<010FB512FEA3D9000313806E130080B3B3AB123F487E487EA44A
+5A13801300006C495A00705C6C13076C5C6C495A6CEB1F802603E07FC7FC3800FFFCEB1F
+E027467BC332>74 D<B712FCEEFFC017F800019039C0000FFC6C6C48EB01FF9338007F80
+EF1FE0170FEF07F018F8EF03FCA218FE1701A218FFA718FEA2170318FCA2EF07F818F0EF
+0FE0EF1FC0EF7F80933801FE00EE0FFC91B612F017800280C9FCB3AA3801FFE0B612C0A3
+38447CC342>80 D<B60107B500F890380FFFFEA3000301E0D9001F90C813F06C0180DA0F
+FCED3FC091C86C48ED1F006C871C0E6D6C6E7E1C0CA26D6C6F5DA36EDA06FF1538011F1A
+30A26E020E6D1470010FDB0C7F1560A26E021C7F0107DB183F5DA2856D6CDA301F4A5AA3
+6D6C4A6C6C49C7FCA36D6C4A6C6C1306A3DB80016E130E027FDA8003140CA2DBC0038002
+3FDA00015CA203E081021F01066D5CA36E6C486E6C5AA36E6C486E6C5AA36F48EC1FE102
+0360A2DBFE7015F302010160020F90C8FCA2DBFFE015FB6E49EC07FEA36F486E5AA36FC8
+6C5AA3031E6F5AA4030C16605F467EC364>87 D<EB07FC90383FFF809038F80FE03903C0
+03F048C66C7E000E6D7ED80FC0137E486C137F6D6D7EA36F7EA26C5AEA0380C8FCA4EC0F
+FF49B5FC90380FFE1FEB3FC0EBFF00EA03FC485A485A485A485A127F5B176048C7FCA315
+3FA36D137F007F14EF6D9038C7E0C0003F13013A1FE00783F13B07F81E03FF802701FFFC
+0113003A001FE0007C2B2E7CAC31>97 D<EC7F80903803FFF090380FC07C90383F000F01
+FCEB03804848EB01C00003140F4848EB1FE049133F120F485AA2485AED1FC0007FEC0700
+92C7FCA290C9FC5AAB7E7FA2123F16307F001F15706C6C146016E06C6C14C06C6C130100
+01EC03806C6CEB0700013F131E90381FC078903807FFF001001380242E7DAC2B>99
+D<EB01FE903807FFC090381F03F090387E00FC49137E48487F485A4848EB1F80000F15C0
+49130F121F484814E01507A2007F15F090C7FCA25AA390B6FCA290C9FCA67EA27FA2123F
+16306C7E1670000F15606D14E06C6C14C0000314016C6CEB03806C6CEB0700013E131E90
+381F80F8903803FFE0010090C7FC242E7DAC2B>101 D<EA01E0EA07F8A2487EA46C5AA2
+EA01E0C8FCADEA01FC12FFA3120712031201B3B0487EB512F8A315437DC21C>105
+D<EA01FC12FFA3120712031201B3B3B3A5487EB512F8A315457DC41C>108
+D<D801FC01FFEC1FE000FF010701E0EBFFFC913B0F03F801E07F913C3C01FC07803F8000
+07903C7000FE0E001FC0000349D97E1C130F2601FDC0D97F38804A143001FFDA3FF06D7E
+91C75BA2495DA3495DB3A8486C4A6C497EB5D8F81FB50003B512E0A34B2C7DAB52>I<39
+01FC01FE00FF903807FFC091381E07F091383801F8000701707F0003EBE0002601FDC07F
+5C01FF147F91C7FCA25BA35BB3A8486CECFF80B5D8F83F13FEA32F2C7DAB36>I<3903F8
+03F000FFEB1FFCEC3C3EEC707F0007EBE0FF3803F9C000015B13FBEC007E153C01FF1300
+5BA45BB3A748B4FCB512FEA3202C7DAB26>114 D<D801FC147F00FFEC3FFFA300071401
+000380000181B3A85EA35DA212006D5B017E9038077F80017F010E13C06D011C13FE9038
+0FC078903803FFF09026007F8013002F2D7DAB36>117 D<B539F001FFFCA3000790C7EA
+7FE06C48EC1F8000011600160E0000150C6D141C6D1418A26E1338013F1430A26D6C5BA2
+6E13E0010F5CA26D6C485AA2ECF803010391C7FCA2903801FC06A2ECFE0E0100130CA2EC
+7F18A215B8EC3FB0A2EC1FE0A36E5AA26E5AA36EC8FCA21406A35CA25CA2123C007E5BB4
+FC5CA25CEAFE01387C0380D87007C9FCEA3C1EEA0FFCEA03F02E3F7EAA33>121
+D E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fl cmr17 17.28 17
+/Fl 17 118 df<DD7FF81560040FB56C14E0047F14E00303B600FC1301030F9038E003FE
+DB3FFEC7383F8003DBFFF0EC07C04A01C0913803F007020790C9EAF80FDA0FFC167C4A48
+EE1E1FDA7FE0160F4A48EE07BF4949EE03FF4990CAFC4948834948834A187F495A013F19
+3F4948181F5C01FF190F485BA24890CC1207A248481903A2485A1B01121FA25B123F1B00
+5BA2127F1C00A4485AB06C7EA5123F1CE07FA2121F7FA2000F1A011CC06C7EA26C7E1B03
+6C6D19801B076C7F017F1A006E606D6C181E131F6D6C606E18386D6C18786D6C606D6D4C
+5A6D6D4C5A6E6C1607DA1FF84C5A6E6C4CC7FC6EB4167C020101C04A5A6E01F0EC07F0DB
+3FFEEC1FC092280FFFE001FFC8FC030390B512FCDB007F14F0040F14809326007FF8C9FC
+53667AE360>67 D<BB12FCA4C601FCC8120FD93FF89238007FFE011F171F190719031900
+A21A7E1A3EA21A1EA21A1F86A486A6F20380A318E0A297C7FCA61701A417031707170F17
+1F17FF91B7FCA402F8C7FC171F170F170717031701A41700A895C9FCB3A580133F90B57E
+B712E0A4496279E156>70 D<DDFFF015C0040F01FF1401047F14E00303B600F81303030F
+9038E003FEDB3FFCC7007F1307DBFFE0EC0FC002030180913803E00F4A48C83801F01F4A
+48ED0078DA3FF0EE3C3F4A48161E4A48EE0F7F4949EE07FF4990CA7E495A494883494883
+5C013F197F4948183F495A1B1F485B1B0F4890CCFCA248481907A2485A1B03121F5BA212
+3F1B015BA2127F98C8FCA35B12FFB06C7EA24EB712E0A3123F95C7000FEBF0006D06015B
+64001F857FA2120F7F1207A26C7EA26C7FA26C7FA26D7E6D7E131F806D7E6D6C5F6D7E6D
+6D5E6D7F6E6CEE07BFDA3FF8EE0F3FDA0FFCEE1F1F6EB4163E6E01C0EDFC0F020001F091
+3801F807DB3FFEEC0FE092260FFFF09038FF8003030390B538FE0001DB007F02F8130004
+0F02C091C7FC040001F8CAFC5B667AE368>I<B712C0A4C66CEB8000D91FFEC7FC6D5AB3
+B3B3B3AE497E90387FFF80B712C0A422627AE12F>73 D<933801FFE0043F13FF4BB612E0
+03079038003FF8DB1FF0EB03FEDB7FC0903800FF804A48C8EA3FE0DA03FCED0FF0DA0FF0
+ED03FC4A486F7E4A486F7E4A48707E4ACA6C7E4948717E4948717E4948717E4948717E49
+48717E013F854A83017F864948727EA24890CC6C7EA24848737EA24848737EA2000F8749
+1907001F87A34848737EA4007F1C80A24985A400FF1CC0AF6C6C4F1380A5003F1C006D61
+A3001F63A26D190F000F63A26C6C4F5AA36C6C4F5AA26C6D4E5A6C636E18FF017F626D6C
+4D90C7FC6E5F011F616D6C4D5A6D6C4D5A0103616E171F6D6C4D5A6D6D4C5ADA3FC04CC8
+FCDA1FF0ED03FE6E6C4B5A6E6C4B5ADA01FFED3FE09126007FC0ECFF80DB1FF0D903FEC9
+FCDB07FFEB3FF8030190B512E0DB003F91CAFC040113E05A667AE367>79
+D<933801FFE0043F13FF4BB612E003079038003FF8DB1FF0EB03FEDB7FC0903800FF804A
+48C8EA3FE0DA03FCED0FF0DA0FF8ED07FCDA1FE0ED01FE4A486F7E4A48707E4ACA6C7E49
+48717E4948717E4948717E010F854948717E4948717EA24948717F01FF864A187F4890CC
+6C7EA2488749191F00078749190F000F87A2001F87491907A2003F87A24985A2007F1C80
+A44985A200FF1CC0AF007F1C806D61A4003F1C00A36D61001F63A36C6C4F5AA20007636D
+191FA26C6C4F5AA26C636C6DDA3F804A5AEFFFE06D6C010301F84A5A6D6C902607C07C49
+90C7FC93380F001E6D6C011E6D495A6D6C6F495A0107021CD903805B6D6C013C6D6C485A
+6E0138151F6D6C0300495A6D01806F485ADA3FC04CC8FCDA1FE0ED71FE91260FF83CEC77
+FC912607FC1CEC7FF8912601FF1EEC3FE09126007FDEECFF80DB1FFFD903FEC9FC030790
+38C03FF8030190B56C1560DB003F143C0401EBE01C93C8121EA21DE0191FA3736C13011D
+C0741303A274130774130F736CEB1F8074133F9738FF01FF7390B51200A264856485745B
+745B745B08071380E001FEC7FC5B807AE367>81 D<DA07FF1403023F01F05B49B512FC01
+0702FF5B90260FFC0013C0D93FE090380FF01FD97F80EB03F801FEC86C5A4848157E4848
+ED1F7F48486F5A4848815B001F824981003F8290CAFC4883A2007E83A212FE84A384A27E
+A36D82A26C7EA26D93C7FC6C7E7F7F6C7E6D7E6C13E06C13FCECFFC06C14F86CECFF806C
+15F86DECFF80011F15E06D15F8010315FE01006F7E021F81020181DA003F80030380DB00
+3F7F04037FEE007FEF1FFF71138017037113C083A2F07FE0183FA2181F00E018F0180FA4
+1807A27EA47E19E0180F7E19C07E6C171F19806D163F6D17006D5E6D16FE486C5E6D4B5A
+D8FC7F1503D91F80EC0FF026F80FE04A5AD907FCEC7F8029F001FFE003FFC7FC6D6CB512
+FC48011F14F0020314C0489026001FFEC8FC3C667AE349>83 D<003FBC12F8A49126C000
+039038C0000301FCC76C49EB007F01F0190F01C019074848F103FC90C81701007E1A0000
+7C1B7CA300781B3CA400701B1CA600F01B1E481B0EA7C91800B3B3B3A54C7FA2041F13F8
+4AB87EA457627CE160>I<EC3FF0903803FFFE010F6D7E90393FC03FE090397E0007F801
+F86D7ED801E06D7E48486D7E48486E7E48C86C7E7F01F06E7E487E6D6E7EA3707EA36C5A
+EA03E0C9FCA6167FED7FFF020FB5FC91387FF807903801FF80903807FC00EB1FF0EB7FC0
+495AD803FEC7FC485A120F5B485A485AA2484817E0A312FF5BA2160FA3161F6D141B007F
+153B16736D913971FC01C06C6C14E1001FEC01C1D80FFC903A0780FE03806C6C903A0F00
+FF07002701FF807E6DB4FC27007FFFF86D5A011F01E0EB1FF8010190C7EA07E03B417ABF
+42>97 D<4AB47E020F13F8023F13FE9139FF007F80D903FCEB07E0D907F0EB01F0D91FE0
+EB007849488049488049C87E48485D4915FF00034B138048485CA2485AA2485AA2003F6F
+130049EC007C94C7FC127FA35B12FFAD127F7FA4123F7FA2001FEE01C07F000F16036D16
+8012076C6C15076D160000015E6C6C151E6D6C5C6D6C5C6D6C5CD90FF8495AD903FCEB07
+C0903A00FF803F8091263FFFFEC7FC020F13F80201138032417CBF3A>99
+D<181EEF3FFEEE07FFA4EE000F1703A21701B3AAEDFF80020F13F8023F13FE9139FF803F
+81903A03FC0007C14948EB01E1D91FE0EB00F94948147D4948143D49C8121F4848150F49
+1507120348481503491501120F121F5BA2123F5B127FA45B12FFAD127F7FA3123FA27F12
+1FA26C6C1503A26C6C150712036D150F6C6C151F0000163D137F6D6CECF9FF6D6CEB01F1
+D90FF0D903C113C06D6CD90F81EBFF80D901FFEB7F019039007FFFFC021F13E002010100
+91C7FC41657CE349>I<EC03FE91381FFFE091B512F8903901FE03FE903A07F0007F8049
+486D7ED93FC06D7E49C76C7E496E7E49140348488148481401000782491400000F828348
+5A1880123F49153FA2007F17C0A35BA212FF90B8FCA30180CAFCA9127F7FA3123FA27F12
+1FEF01C06C7E17036C6C1680A26C6C15070001EE0F006D150E6C6C151E6D6C5C6D6C5C6D
+6C5CD907F0EB03E0D903FC495A902700FF803FC7FC91383FFFFC020F13F0020113803241
+7CBF3A>I<133C13FF487F487FA66C5B6C90C7FC133C90C8FCB3A2EB03C0EA07FF127FA4
+1201EA007FA2133FB3B3AC497E497EB612E0A41B5F7DDE23>105
+D<EB03C0EA07FFB5FCA41201EA007FA2133FB3AB0403B512F8A40400148094387FFC0018
+E06095C7FC177E5F17F04C5A4C5A4C5A4CC8FC163E5E5E4B5A4B5A4B5A4B5A151F4B7E4B
+7E15FF02C17F9138C3CFF8ECC7879138CF07FC9138FE03FEECFC0102F87F4A6C7F4A137F
+4A80707E161F83707E160783707E160183707F177F84717E171F84717E84A284496CEDFF
+80496C4A13E0B600F090B6FCA440647CE346>107 D<9039078003F8D807FFEB0FFFB501
+3F13C092387C0FE0913881F01F9238E03FF00001EB838039007F8700148FEB3F8E029CEB
+1FE0EE0FC00298EB030002B890C7FCA214B014F0A25CA55CB3B0497EEBFFF8B612FCA42C
+3F7CBE33>114 D<1438A71478A414F8A31301A31303A21307130F131FA2137F13FF1203
+000F90B6FCB8FCA3260007F8C8FCB3AE17E0AE6D6CEB01C0A316036D6C148016076D6C14
+006E6C5A91383FC01E91381FF07C6EB45A020313E09138007F802B597FD733>116
+D<D903C0150FD807FFED1FFFB50203B5FCA40001ED0007D8007F1501A2013F81B3B25FA3
+5FA35F011F15066E140E5F130F6E4A7F01075D6D6C494813E0D901FE4948EBFFC0903A00
+FFC01F8091393FFFFE00020F13F8020001C0EC800042407DBE49>I
+E
+%EndDVIPSBitmapFont
+end
+%%EndProlog
+%%BeginSetup
+%%Feature: *Resolution 600dpi
+TeXDict begin
+%%PaperSize: A4
+
+%%EndSetup
+%%Page: 1 1
+1 0 bop 1125 937 a Fl(CFITSIO)44 b(Quic)l(k)h(Start)d(Guide)1625
+1190 y Fk(William)28 b(P)m(ence)2277 1154 y Fj(\003)1666
+1394 y Fk(Jan)m(uary)33 b(2003)120 1916 y Fi(Con)l(ten)l(ts)120
+2120 y Fh(1)84 b(In)m(tro)s(duction)2897 b(2)120 2324
+y(2)84 b(Installing)35 b(and)g(Using)h(CFITSIO)2080 b(3)120
+2528 y(3)84 b(Example)34 b(Programs)2600 b(4)120 2731
+y(4)84 b(CFITSIO)33 b(Routines)2603 b(6)256 2844 y Fg(4.1)94
+b(Error)30 b(Rep)s(orting)24 b(.)45 b(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h
+(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)
+g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)174 b(6)256 2957 y(4.2)94
+b(File)30 b(Op)s(en/Close)f(Routines)57 b(.)46 b(.)f(.)h(.)g(.)f(.)h(.)
+g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g
+(.)g(.)f(.)h(.)g(.)174 b(6)256 3070 y(4.3)94 b(HDU-lev)m(el)32
+b(Routines)85 b(.)45 b(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)h(.)g
+(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)
+g(.)174 b(7)256 3183 y(4.4)94 b(Image)32 b(I/O)e(Routines)79
+b(.)45 b(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)
+g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)174
+b(9)256 3296 y(4.5)94 b(T)-8 b(able)30 b(I/O)h(Routines)d(.)46
+b(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g
+(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)129
+b(12)256 3409 y(4.6)94 b(Header)31 b(Keyw)m(ord)f(I/O)h(Routines)78
+b(.)46 b(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)
+h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)129 b(19)256 3522
+y(4.7)94 b(Utilit)m(y)30 b(Routines)c(.)45 b(.)h(.)g(.)f(.)h(.)g(.)g(.)
+f(.)h(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f
+(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)129 b(22)120 3726
+y Fh(5)84 b(CFITSIO)33 b(File)i(Names)f(and)g(Filters)1907
+b(23)256 3839 y Fg(5.1)94 b(Creating)30 b(New)h(Files)43
+b(.)j(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h
+(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)129
+b(23)256 3951 y(5.2)94 b(Op)s(ening)29 b(Existing)f(Files)39
+b(.)46 b(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)
+f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)129
+b(24)256 4064 y(5.3)94 b(Image)32 b(Filtering)53 b(.)45
+b(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f
+(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)129
+b(26)465 4177 y(5.3.1)106 b(Extracting)31 b(a)g(subsection)e(of)i(an)f
+(image)76 b(.)46 b(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g
+(.)g(.)f(.)h(.)g(.)129 b(26)465 4290 y(5.3.2)106 b(Create)32
+b(an)e(Image)h(b)m(y)f(Binning)e(T)-8 b(able)30 b(Columns)i(.)45
+b(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)129
+b(26)256 4403 y(5.4)94 b(T)-8 b(able)30 b(Filtering)74
+b(.)45 b(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)
+g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g
+(.)129 b(28)465 4516 y(5.4.1)106 b(Column)29 b(and)h(Keyw)m(ord)g
+(Filtering)47 b(.)e(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g
+(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)129 b(28)465 4629 y(5.4.2)106
+b(Ro)m(w)31 b(Filtering)39 b(.)45 b(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g
+(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)
+g(.)f(.)h(.)g(.)129 b(29)465 4742 y(5.4.3)106 b(Go)s(o)s(d)30
+b(Time)g(In)m(terv)-5 b(al)30 b(Filtering)59 b(.)46 b(.)f(.)h(.)g(.)g
+(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)
+129 b(32)465 4855 y(5.4.4)106 b(Spatial)29 b(Region)i(Filtering)56
+b(.)46 b(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)
+h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)129 b(32)465 4968
+y(5.4.5)106 b(Example)30 b(Ro)m(w)h(Filters)f(.)45 b(.)h(.)g(.)f(.)h(.)
+g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g
+(.)g(.)f(.)h(.)g(.)129 b(34)256 5081 y(5.5)94 b(Com)m(bined)29
+b(Filtering)g(Examples)44 b(.)i(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h
+(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)129
+b(36)120 5284 y Fh(6)84 b(CFITSIO)33 b(Error)i(Status)f(Co)s(des)2069
+b(38)p 120 5346 1465 4 v 222 5400 a Ff(\003)258 5431
+y Fe(HEASAR)n(C,)25 b(NASA)f(Go)r(ddard)i(Space)f(Fligh)n(t)h(Cen)n
+(ter,)g Fd(Wil)t(liam.D.Penc)l(e@nasa.gov)1928 5809 y
+Fg(1)p eop
+%%Page: 2 2
+2 1 bop 120 573 a Fi(1)135 b(In)l(tro)t(duction)120 776
+y Fg(This)33 b(do)s(cumen)m(t)h(is)f(in)m(tended)g(to)i(help)e(y)m(ou)i
+(quic)m(kly)e(start)i(writing)d(C)i(programs)g(to)h(read)f(and)g(write)
+120 889 y(FITS)45 b(\014les)f(using)g(the)h(CFITSIO)f(library)-8
+b(.)84 b(It)45 b(co)m(v)m(ers)i(the)f(most)f(imp)s(ortan)m(t)g(CFITSIO)
+e(routines)120 1002 y(that)i(are)f(needed)g(to)h(p)s(erform)d(most)i(t)
+m(yp)s(es)h(of)f(op)s(erations)f(on)h(FITS)f(\014les.)81
+b(F)-8 b(or)45 b(more)f(complete)120 1115 y(information)39
+b(ab)s(out)g(these)i(and)f(all)f(the)h(other)h(a)m(v)-5
+b(ailable)39 b(routines)g(in)g(the)i(library)d(please)i(refer)g(to)120
+1227 y(the)c(\\CFITSIO)e(User's)i(Reference)g(Guide",)h(whic)m(h)d(is)g
+(a)m(v)-5 b(ailable)35 b(from)g(the)h(CFITSIO)e(W)-8
+b(eb)36 b(site)g(at)120 1340 y Fc(http://heasarc.gsfc.nasa)o(.gov)o
+(/fit)o(sio)o Fg(.)261 1453 y(F)-8 b(or)41 b(more)f(general)f
+(information)f(ab)s(out)i(the)g(FITS)f(data)h(format,)j(refer)d(to)g
+(the)g(follo)m(wing)e(w)m(eb)120 1566 y(page:)j(h)m
+(ttp://heasarc.gsfc.nasa.go)m(v/do)s(cs/heasa)q(rc/\014ts.h)m(t)q(ml)
+261 1679 y(FITS)27 b(stands)h(for)g(Flexible)e(Image)j(T)-8
+b(ransp)s(ort)27 b(System)h(and)f(is)g(the)i(standard)e(\014le)g
+(format)h(used)g(to)120 1792 y(store)j(most)g(astronomical)f(data)i
+(\014les.)40 b(There)30 b(are)h(2)g(basic)f(t)m(yp)s(es)g(of)h(FITS)f
+(\014les:)40 b(images)30 b(and)g(tables.)120 1905 y(FITS)j(images)h
+(often)g(con)m(tain)g(a)g(2-dimensional)d(arra)m(y)k(of)e(pixels)f
+(represen)m(ting)h(an)h(image)g(of)f(a)h(piece)120 2018
+y(of)f(the)f(sky)-8 b(,)34 b(but)e(FITS)g(images)g(can)h(also)g(con)m
+(tain)g(1-D)g(arra)m(ys)g(\(i.e,)h(a)f(sp)s(ectrum)e(or)i(ligh)m(t)e
+(curv)m(e\),)j(or)120 2131 y(3-D)40 b(arra)m(ys)f(\(a)g(data)g(cub)s
+(e\),)i(or)d(ev)m(en)i(higher)d(dimensional)f(arra)m(ys)i(of)h(data.)66
+b(An)38 b(image)h(ma)m(y)g(also)120 2244 y(ha)m(v)m(e)30
+b(zero)g(dimensions,)c(in)i(whic)m(h)f(case)j(it)e(is)g(referred)g(to)i
+(as)f(a)g(n)m(ull)e(or)i(empt)m(y)g(arra)m(y)-8 b(.)41
+b(The)28 b(supp)s(orted)120 2357 y(datat)m(yp)s(es)f(for)f(the)h(image)
+g(arra)m(ys)f(are)h(8,)h(16,)g(and)e(32-bit)h(in)m(tegers,)h(and)d(32)j
+(and)d(64-bit)i(\015oating)f(p)s(oin)m(t)120 2469 y(real)k(n)m(um)m(b)s
+(ers.)39 b(Both)31 b(signed)f(and)f(unsigned)g(in)m(tegers)h(are)h
+(supp)s(orted.)261 2582 y(FITS)j(tables)g(con)m(tain)g(ro)m(ws)g(and)g
+(columns)f(of)h(data,)i(similar)c(to)j(a)g(spreadsheet.)52
+b(All)33 b(the)h(v)-5 b(alues)120 2695 y(in)30 b(a)h(particular)e
+(column)h(m)m(ust)g(ha)m(v)m(e)j(the)e(same)g(datat)m(yp)s(e.)43
+b(A)31 b(cell)f(of)h(a)g(column)f(is)g(not)h(restricted)g(to)120
+2808 y(a)h(single)d(n)m(um)m(b)s(er,)i(and)f(instead)h(can)g(con)m
+(tain)h(an)f(arra)m(y)g(or)h(v)m(ector)g(of)g(n)m(um)m(b)s(ers.)41
+b(There)31 b(are)h(actually)120 2921 y(2)43 b(subt)m(yp)s(es)f(of)h
+(FITS)f(tables:)65 b(ASCI)s(I)41 b(and)i(binary)-8 b(.)76
+b(As)43 b(the)g(names)g(imply)-8 b(,)44 b(ASCI)s(I)d(tables)i(store)120
+3034 y(the)37 b(data)h(v)-5 b(alues)36 b(in)g(an)g(ASCI)s(I)g(represen)
+m(tation)h(whereas)f(binary)g(tables)g(store)i(the)f(data)g(v)-5
+b(alues)37 b(in)120 3147 y(a)c(more)f(e\016cien)m(t)h(mac)m
+(hine-readable)e(binary)g(format.)46 b(Binary)32 b(tables)g(are)g
+(generally)g(more)g(compact)120 3260 y(and)25 b(supp)s(ort)e(more)j
+(features)f(\(e.g.,)j(a)e(wider)e(range)h(of)h(datat)m(yp)s(es,)h(and)e
+(v)m(ector)i(columns\))d(than)h(ASCI)s(I)120 3373 y(tables.)261
+3486 y(A)31 b(single)e(FITS)h(\014le)g(man)m(y)h(con)m(tain)g(m)m
+(ultiple)d(images)j(or)g(tables.)41 b(Eac)m(h)31 b(table)g(or)f(image)h
+(is)f(called)120 3599 y(a)k(Header-Data)j(Unit,)d(or)g(HDU.)h(The)f
+(\014rst)f(HDU)i(in)d(a)j(FITS)e(\014le)g(m)m(ust)h(b)s(e)f(an)h(image)
+h(\(but)e(it)h(ma)m(y)120 3711 y(ha)m(v)m(e)c(zero)f(axes\))h(and)e(is)
+g(called)g(the)h(Primary)e(Arra)m(y)-8 b(.)41 b(An)m(y)28
+b(additional)f(HDUs)i(in)f(the)g(\014le)g(\(whic)m(h)g(are)120
+3824 y(also)i(referred)g(to)h(as)g(`extensions'\))f(ma)m(y)h(con)m
+(tain)g(either)f(an)g(image)h(or)f(a)h(table.)261 3937
+y(Ev)m(ery)38 b(HDU)g(con)m(tains)g(a)g(header)g(con)m(taining)f(k)m
+(eyw)m(ord)h(records.)62 b(Eac)m(h)38 b(k)m(eyw)m(ord)g(record)g(is)f
+(80)120 4050 y(ASCI)s(I)29 b(c)m(haracters)j(long)e(and)f(has)i(the)f
+(follo)m(wing)f(format:)120 4263 y Fc(KEYWORD)46 b(=)h(value)g(/)g
+(comment)f(string)261 4475 y Fg(The)23 b(k)m(eyw)m(ord)i(name)f(can)g
+(b)s(e)f(up)g(to)h(8)g(c)m(haracters)i(long)d(\(all)g(upp)s(ercase\).)
+38 b(The)23 b(v)-5 b(alue)24 b(can)g(b)s(e)f(either)120
+4588 y(an)k(in)m(teger)g(or)f(\015oating)h(p)s(oin)m(t)e(n)m(um)m(b)s
+(er,)i(a)g(logical)f(v)-5 b(alue)26 b(\(T)h(or)f(F\),)i(or)e(a)h(c)m
+(haracter)i(string)c(enclosed)i(in)120 4701 y(single)d(quotes.)40
+b(Eac)m(h)26 b(header)f(b)s(egins)f(with)g(a)i(series)f(of)h(required)e
+(k)m(eyw)m(ords)h(to)i(describ)s(e)d(the)h(datat)m(yp)s(e)120
+4814 y(and)35 b(format)h(of)f(the)h(follo)m(wing)e(data)i(unit,)f(if)f
+(an)m(y)-8 b(.)57 b(An)m(y)35 b(n)m(um)m(b)s(er)g(of)g(other)h
+(optional)e(k)m(eyw)m(ords)i(can)120 4927 y(b)s(e)d(included)e(in)h
+(the)h(header)h(to)g(pro)m(vide)e(other)i(descriptiv)m(e)f(information)
+e(ab)s(out)j(the)f(data.)51 b(F)-8 b(or)34 b(the)120
+5040 y(most)g(part,)g(the)g(CFITSIO)d(routines)i(automatically)g(write)
+f(the)i(required)e(FITS)g(k)m(eyw)m(ords)i(for)f(eac)m(h)120
+5153 y(HDU,)e(so)g(y)m(ou,)g(the)g(programmer,)f(usually)e(do)i(not)h
+(need)f(to)h(w)m(orry)f(ab)s(out)g(them.)1928 5809 y(2)p
+eop
+%%Page: 3 3
+3 2 bop 120 573 a Fi(2)135 b(Installing)46 b(and)f(Using)g(CFITSIO)120
+776 y Fg(First,)32 b(y)m(ou)g(should)d(do)m(wnload)i(the)h(CFITSIO)e
+(soft)m(w)m(are)j(and)e(the)h(set)g(of)g(example)g(FITS)f(utilit)m(y)f
+(pro-)120 889 y(grams)h(from)f(the)g(w)m(eb)h(site)f(at)i(h)m
+(ttp://heasarc.gsfc.nasa.go)m(v/\014tsio.)46 b(The)30
+b(example)g(programs)g(illus-)120 1002 y(trate)g(ho)m(w)e(to)h(p)s
+(erform)f(man)m(y)g(common)h(t)m(yp)s(es)f(of)h(op)s(erations)f(on)g
+(FITS)g(\014les)g(using)f(CFITSIO.)g(They)120 1115 y(are)h(also)g
+(useful)d(when)i(writing)f(a)i(new)f(program)g(b)s(ecause)h(it)f(is)g
+(often)h(easier)f(to)i(tak)m(e)g(a)f(cop)m(y)g(of)g(one)g(of)120
+1227 y(these)k(utilit)m(y)e(programs)h(as)g(a)h(template)g(and)f(then)g
+(mo)s(dify)e(it)i(for)g(y)m(our)h(o)m(wn)f(purp)s(oses,)f(rather)i
+(than)120 1340 y(writing)c(the)j(new)f(program)g(completely)g(from)g
+(scratc)m(h.)261 1453 y(T)-8 b(o)28 b(build)c(the)k(CFITSIO)d(library)g
+(on)i(Unix)f(platforms,)i(`un)m(tar')f(the)h(source)f(co)s(de)h
+(distribution)23 b(\014le)120 1566 y(and)30 b(then)g(execute)i(the)e
+(follo)m(wing)f(commands)h(in)f(the)i(directory)e(con)m(taining)h(the)h
+(source)g(co)s(de:)120 1779 y Fc(>)95 b(./configure)45
+b([--prefix=/target/instal)o(lati)o(on/)o(path)o(])120
+1892 y(>)95 b(make)524 b(\(or)47 b('make)f(shared'\))120
+2005 y(>)95 b(make)47 b(install)141 b(\(this)46 b(step)h(is)g
+(optional\))261 2217 y Fg(The)40 b(optional)g('pre\014x')g(argumen)m(t)
+h(to)g(con\014gure)f(giv)m(es)h(the)g(path)f(to)h(the)g(directory)f
+(where)g(the)120 2330 y(CFITSIO)30 b(library)g(and)h(include)f(\014les)
+h(should)f(b)s(e)h(installed)f(via)i(the)g(later)g('mak)m(e)h(install')
+d(command.)120 2443 y(F)-8 b(or)31 b(example,)120 2655
+y Fc(>)95 b(./configure)45 b(--prefix=/usr1/local)261
+2868 y Fg(will)18 b(cause)j(the)g('mak)m(e)h(install')d(command)h(to)h
+(cop)m(y)h(the)e(CFITSIO)f(lib)s(c\014tsio)f(\014le)i(to)h(/usr1/lo)s
+(cal/lib)120 2981 y(and)35 b(the)h(necessary)g(include)e(\014les)h(to)h
+(/usr1/lo)s(cal/include)e(\(assuming)h(of)g(course)h(that)h(the)f(pro)s
+(cess)120 3094 y(has)30 b(p)s(ermission)d(to)32 b(write)d(to)i(these)g
+(directories\).)261 3207 y(Pre-compiled)d(v)m(ersions)h(of)h(the)g
+(CFITSIO)e(DLL)i(library)d(are)j(a)m(v)-5 b(ailable)29
+b(for)g(PCs.)40 b(On)29 b(Macin)m(tosh)120 3320 y(mac)m(hines,)45
+b(refer)d(to)g(the)h(README.MacOS)g(\014le)e(for)h(instructions)e(on)i
+(building)c(CFITSIO)j(using)120 3432 y(Co)s(deW)-8 b(arrior.)261
+3545 y(An)m(y)40 b(programs)g(that)h(use)f(CFITSIO)f(m)m(ust)h(of)g
+(course)h(b)s(e)e(link)m(ed)g(with)g(the)h(CFITSIO)f(library)120
+3658 y(when)e(creating)h(the)g(executable)h(\014le.)63
+b(The)37 b(exact)j(pro)s(cedure)c(for)i(linking)d(a)k(program)e(dep)s
+(ends)f(on)120 3771 y(y)m(our)31 b(soft)m(w)m(are)i(en)m(vironmen)m(t,)
+e(but)g(on)g(Unix)f(platforms,)h(the)g(command)g(line)f(to)i(compile)e
+(and)h(link)e(a)120 3884 y(program)h(will)e(lo)s(ok)i(something)g(lik)m
+(e)f(this:)120 4097 y Fc(gcc)47 b(-o)g(myprog)f(myprog.c)g(-L.)h
+(-lcfitsio)e(-lm)i(-lnsl)f(-lsocket)261 4309 y Fg(Y)-8
+b(ou)37 b(ma)m(y)g(not)f(need)g(to)h(include)e(all)g(of)h(the)h('m',)h
+('nsl',)f(and)f('so)s(c)m(k)m(et')i(system)f(libraries)c(on)j(y)m(our)
+120 4422 y(particular)j(mac)m(hine.)72 b(T)-8 b(o)42
+b(\014nd)d(out)i(what)g(libraries)d(are)j(required)e(on)i(y)m(our)g
+(\(Unix\))f(system,)k(t)m(yp)s(e)120 4535 y Fc('make)i(testprog')28
+b Fg(and)i(see)h(what)f(libraries)e(are)i(then)h(included)c(on)j(the)h
+(resulting)e(link)f(line.)1928 5809 y(3)p eop
+%%Page: 4 4
+4 3 bop 120 573 a Fi(3)135 b(Example)46 b(Programs)120
+776 y Fg(Before)32 b(describing)d(the)j(individual)27
+b(CFITSIO)i(routines)i(in)f(detail,)h(it)f(is)h(instructiv)m(e)f(to)i
+(\014rst)f(lo)s(ok)g(at)120 889 y(an)c(actual)g(program.)40
+b(The)26 b(names)h(of)g(the)g(CFITSIO)f(routines)g(are)h(fairly)e
+(descriptiv)m(e)h(\(they)i(all)e(b)s(egin)120 1002 y(with)j
+Fc(fits)p 525 1002 29 4 v 33 w Fg(,)i(so)g(it)e(should)g(b)s(e)h
+(reasonably)f(clear)i(what)f(this)f(program)h(do)s(es:)120
+1202 y Fc(------------------------)o(----)o(----)o(---)o(----)o(----)o
+(---)o(----)o(----)o(---)o(----)o(---)311 1315 y(#include)45
+b(<string.h>)311 1428 y(#include)g(<stdio.h>)120 1541
+y(1:)95 b(#include)45 b("fitsio.h")311 1767 y(int)i(main\(int)e(argc,)i
+(char)f(*argv[]\))311 1879 y({)120 1992 y(2:)286 b(fitsfile)45
+b(*fptr;)502 2105 y(char)h(card[FLEN_CARD];)120 2218
+y(3:)286 b(int)47 b(status)f(=)h(0,)95 b(nkeys,)46 b(ii;)95
+b(/*)47 b(MUST)g(initialize)e(status)h(*/)120 2444 y(4:)286
+b(fits_open_file\(&fptr,)42 b(argv[1],)j(READONLY,)h(&status\);)502
+2557 y(fits_get_hdrspace\(fptr,)41 b(&nkeys,)46 b(NULL,)g(&status\);)
+502 2783 y(for)h(\(ii)g(=)g(1;)g(ii)g(<=)h(nkeys;)e(ii++\))94
+b({)597 2896 y(fits_read_record\(fptr,)42 b(ii,)47 b(card,)f
+(&status\);)g(/*)h(read)f(keyword)g(*/)597 3009 y(printf\("\045s\\n",)e
+(card\);)502 3121 y(})502 3234 y(printf\("END\\n\\n"\);)90
+b(/*)48 b(terminate)d(listing)h(with)g(END)h(*/)502 3347
+y(fits_close_file\(fptr,)42 b(&status\);)502 3573 y(if)47
+b(\(status\))475 b(/*)47 b(print)g(any)g(error)f(messages)f(*/)120
+3686 y(5:)477 b(fits_report_error\(stder)o(r,)42 b(status\);)502
+3799 y(return\(status\);)311 3912 y(})120 4025 y
+(------------------------)o(----)o(----)o(---)o(----)o(----)o(---)o
+(----)o(----)o(---)o(----)o(---)261 4225 y Fg(This)28
+b(program)h(op)s(ens)f(the)h(sp)s(eci\014ed)f(FITS)g(\014le)h(and)f
+(prin)m(ts)g(out)h(all)f(the)i(header)f(k)m(eyw)m(ords)g(in)f(the)120
+4338 y(curren)m(t)i(HDU.)i(Some)e(other)h(p)s(oin)m(ts)e(to)i(notice)g
+(ab)s(out)f(the)g(program)g(are:)231 4516 y(1.)46 b(The)30
+b Fc(fitsio.h)e Fg(header)i(\014le)f(m)m(ust)i(b)s(e)e(included)f(to)j
+(de\014ne)e(the)i(v)-5 b(arious)29 b(routines)g(and)h(sym)m(b)s(ols)347
+4629 y(used)g(in)f(CFITSIO.)231 4812 y(2.)46 b(The)37
+b Fc(fitsfile)e Fg(parameter)i(is)f(the)h(\014rst)g(argumen)m(t)g(in)f
+(almost)h(ev)m(ery)h(CFITSIO)d(routine.)60 b(It)347 4925
+y(is)40 b(a)i(p)s(oin)m(ter)e(to)i(a)g(structure)e(\(de\014ned)g(in)g
+Fc(fitsio.h)p Fg(\))g(that)h(stores)h(information)d(ab)s(out)i(the)347
+5038 y(particular)g(FITS)g(\014le)g(that)i(the)g(routine)e(will)e(op)s
+(erate)k(on.)76 b(Memory)43 b(for)f(this)f(structure)g(is)347
+5151 y(automatically)33 b(allo)s(cated)f(when)g(the)h(\014le)f(is)f
+(\014rst)h(op)s(ened)g(or)h(created,)h(and)e(is)g(freed)g(when)g(the)
+347 5264 y(\014le)e(is)f(closed.)231 5447 y(3.)46 b(Almost)40
+b(ev)m(ery)g(CFITSIO)e(routine)g(has)i(a)g Fc(status)d
+Fg(parameter)j(as)g(the)g(last)f(argumen)m(t.)69 b(The)347
+5560 y(status)28 b(v)-5 b(alue)27 b(is)g(also)h(usually)d(returned)i
+(as)h(the)g(v)-5 b(alue)27 b(of)h(the)f(function)g(itself.)38
+b(Normally)27 b(status)1928 5809 y(4)p eop
+%%Page: 5 5
+5 4 bop 347 573 a Fg(=)22 b(0,)i(and)d(a)h(p)s(ositiv)m(e)f(status)h(v)
+-5 b(alue)21 b(indicates)g(an)h(error)f(of)h(some)g(sort.)38
+b(The)22 b(status)g(v)-5 b(ariable)20 b(m)m(ust)347 686
+y(alw)m(a)m(ys)32 b(b)s(e)e(initialized)e(to)k(zero)g(b)s(efore)f(use,)
+g(b)s(ecause)g(if)f(status)h(is)f(greater)j(than)d(zero)i(on)f(input)
+347 799 y(then)e(the)g(CFITSIO)f(routines)g(will)e(simply)g(return)i
+(without)g(doing)g(an)m(ything.)40 b(This)27 b(`inherited)347
+912 y(status')46 b(feature,)j(where)44 b(eac)m(h)i(CFITSIO)e(routine)g
+(inherits)e(the)j(status)g(from)g(the)g(previous)347
+1024 y(routine,)e(mak)m(es)e(it)f(unnecessary)g(to)i(c)m(hec)m(k)g(the)
+f(status)g(v)-5 b(alue)40 b(after)h(ev)m(ery)h(single)d(CFITSIO)347
+1137 y(routine)f(call.)64 b(Generally)38 b(y)m(ou)h(should)e(c)m(hec)m
+(k)j(the)e(status)h(after)g(an)g(esp)s(ecially)e(imp)s(ortan)m(t)g(or)
+347 1250 y(complicated)31 b(routine)f(has)h(b)s(een)g(called,)g(or)g
+(after)h(a)f(blo)s(c)m(k)g(of)g(closely)g(related)g(CFITSIO)f(calls.)
+347 1363 y(This)25 b(example)h(program)h(has)f(tak)m(en)i(this)e
+(feature)h(to)g(the)g(extreme)g(and)f(only)g(c)m(hec)m(ks)i(the)f
+(status)347 1476 y(v)-5 b(alue)30 b(at)h(the)g(v)m(ery)g(end)e(of)i
+(the)f(program.)231 1664 y(4.)46 b(In)37 b(this)e(example)i(program)g
+(the)g(\014le)f(name)h(to)h(b)s(e)e(op)s(ened)h(is)f(giv)m(en)h(as)g
+(an)g(argumen)m(t)g(on)g(the)347 1777 y(command)e(line)f(\()p
+Fc(arg[1])p Fg(\).)53 b(If)35 b(the)g(\014le)g(con)m(tains)g(more)g
+(than)g(1)g(HDU)h(or)f(extension,)i(y)m(ou)e(can)347
+1890 y(sp)s(ecify)19 b(whic)m(h)g(particular)g(HDU)i(to)g(b)s(e)f(op)s
+(ened)f(b)m(y)h(enclosing)g(the)g(name)g(or)h(n)m(um)m(b)s(er)e(of)h
+(the)h(HDU)347 2002 y(in)j(square)i(brac)m(k)m(ets)h(follo)m(wing)d
+(the)h(ro)s(ot)h(name)g(of)f(the)h(\014le.)38 b(F)-8
+b(or)26 b(example,)h Fc(file.fts[0])22 b Fg(op)s(ens)347
+2115 y(the)31 b(primary)d(arra)m(y)-8 b(,)32 b(while)d
+Fc(file.fts[2])e Fg(will)h(mo)m(v)m(e)k(to)f(and)f(op)s(en)f(the)i(2nd)
+f(extension)g(in)f(the)347 2228 y(\014le,)36 b(and)e
+Fc(file.fit[EVENTS])d Fg(will)h(op)s(en)j(the)g(extension)f(that)i(has)
+f(a)g Fc(EXTNAME)46 b(=)i('EVENTS')347 2341 y Fg(k)m(eyw)m(ord)31
+b(in)e(the)h(header.)41 b(Note)31 b(that)g(on)f(the)h(Unix)e(command)h
+(line)f(y)m(ou)h(m)m(ust)g(enclose)h(the)f(\014le)347
+2454 y(name)h(in)e(single)g(or)i(double)e(quote)j(c)m(haracters)g(if)d
+(the)i(name)g(con)m(tains)f(sp)s(ecial)g(c)m(haracters)i(suc)m(h)347
+2567 y(as)f(`[')g(or)f(`]'.)347 2717 y(All)42 b(of)h(the)h(CFITSIO)d
+(routines)h(whic)m(h)g(read)h(or)g(write)g(header)g(k)m(eyw)m(ords,)k
+(image)c(data,)k(or)347 2830 y(table)31 b(data)g(op)s(erate)g(only)f
+(within)e(the)j(curren)m(tly)f(op)s(ened)g(HDU)h(in)e(the)i(\014le.)41
+b(T)-8 b(o)31 b(read)g(or)f(write)347 2943 y(information)36
+b(in)g(a)i(di\013eren)m(t)f(HDU)h(y)m(ou)g(m)m(ust)f(\014rst)g
+(explicitly)e(mo)m(v)m(e)j(to)h(that)f(HDU)g(\(see)g(the)347
+3056 y Fc(fits)p 545 3056 29 4 v 34 w(movabs)p 867 3056
+V 32 w(hdu)30 b Fg(and)g Fc(fits)p 1442 3056 V 33 w(movrel)p
+1763 3056 V 33 w(hdu)f Fg(routines)g(in)g(section)i(4.3\).)231
+3244 y(5.)46 b(The)25 b Fc(fits)p 727 3244 V 33 w(report)p
+1048 3244 V 33 w(error)e Fg(routine)h(pro)m(vides)g(a)h(con)m(v)m
+(enien)m(t)h(w)m(a)m(y)g(to)g(prin)m(t)e(out)h(diagnostic)f(mes-)347
+3357 y(sages)32 b(ab)s(out)e(an)m(y)g(error)g(that)h(ma)m(y)g(ha)m(v)m
+(e)h(o)s(ccurred.)261 3544 y(A)f(set)g(of)f(example)g(FITS)g(utilit)m
+(y)f(programs)h(are)g(a)m(v)-5 b(ailable)30 b(from)g(the)g(CFITSIO)f(w)
+m(eb)i(site)f(at)120 3657 y(h)m(ttp://heasarc.gsfc.nasa.go)m(v/do)s
+(cs/soft)n(w)m(are/)q(\014tsio/cexa)q(mples.h)m(tml.)87
+b(These)45 b(are)g(real)f(w)m(orking)120 3770 y(programs)e(whic)m(h)e
+(illustrate)g(ho)m(w)i(to)h(read,)i(write,)f(and)d(mo)s(dify)f(FITS)i
+(\014les)e(using)h(the)h(CFITSIO)120 3883 y(library)-8
+b(.)36 b(Most)24 b(of)g(these)f(programs)g(are)h(v)m(ery)f(short,)i
+(con)m(taining)e(only)f(a)i(few)f(10s)h(of)f(lines)e(of)j(executable)
+120 3996 y(co)s(de)32 b(or)g(less,)g(y)m(et)h(they)f(p)s(erform)e
+(quite)h(useful)f(op)s(erations)h(on)h(FITS)f(\014les.)44
+b(Running)30 b(eac)m(h)j(program)120 4109 y(without)40
+b(an)m(y)h(command)f(line)f(argumen)m(ts)i(will)d(pro)s(duce)h(a)i
+(short)f(description)f(of)i(ho)m(w)g(to)g(use)f(the)120
+4222 y(program.)g(The)30 b(curren)m(tly)g(a)m(v)-5 b(ailable)29
+b(programs)h(are:)347 4409 y(\014tscop)m(y)h(-)g(cop)m(y)g(a)g(\014le)
+347 4522 y(listhead)e(-)i(list)e(header)h(k)m(eyw)m(ords)347
+4635 y(liststruc)f(-)i(sho)m(w)f(the)g(structure)g(of)h(a)g(FITS)e
+(\014le.)347 4748 y(mo)s(dhead)h(-)g(write)g(or)g(mo)s(dify)f(a)i
+(header)f(k)m(eyw)m(ord)347 4861 y(imarith)f(-)h(add,)g(subtract,)h(m)m
+(ultiply)-8 b(,)28 b(or)j(divide)d(2)j(images)347 4974
+y(imlist)d(-)j(list)e(pixel)g(v)-5 b(alues)29 b(in)g(an)i(image)347
+5087 y(imstat)g(-)f(compute)h(mean,)g(min,)e(and)g(max)i(pixel)e(v)-5
+b(alues)29 b(in)g(an)i(image)347 5200 y(tablist)f(-)g(displa)m(y)f(the)
+h(con)m(ten)m(ts)i(of)f(a)g(FITS)e(table)347 5313 y(tab)s(calc)i(-)g
+(general)f(table)g(calculator)1928 5809 y(5)p eop
+%%Page: 6 6
+6 5 bop 120 573 a Fi(4)135 b(CFITSIO)44 b(Routines)120
+776 y Fg(This)36 b(c)m(hapter)i(describ)s(es)e(the)h(main)g(CFITSIO)f
+(routines)g(that)i(can)g(b)s(e)f(used)g(to)h(p)s(erform)e(the)i(most)
+120 889 y(common)31 b(t)m(yp)s(es)f(of)h(op)s(erations)e(on)i(FITS)e
+(\014les.)120 1136 y Fb(4.1)112 b(Error)37 b(Rep)s(orting)120
+1310 y Fc(void)47 b(fits_report_error\(FILE)41 b(*stream,)46
+b(int)h(status\))120 1423 y(void)g(fits_get_errstatus\(int)41
+b(status,)46 b(char)h(*err_text\))120 1536 y(float)f
+(fits_get_version\(float)c(*version\))261 1748 y Fg(The)24
+b(\014rst)g(routine)f(prin)m(ts)g(out)i(information)e(ab)s(out)h(an)m
+(y)h(error)f(that)h(has)g(o)s(ccurred.)38 b(Whenev)m(er)25
+b(an)m(y)120 1861 y(CFITSIO)f(routine)h(encoun)m(ters)i(an)f(error)f
+(it)h(usually)d(writes)i(a)i(message)g(describing)c(the)j(nature)g(of)g
+(the)120 1974 y(error)g(to)i(an)e(in)m(ternal)f(error)i(message)g(stac)
+m(k)h(and)e(then)h(returns)e(with)g(a)i(p)s(ositiv)m(e)f(in)m(teger)h
+(status)g(v)-5 b(alue.)120 2087 y(P)m(assing)27 b(the)h(error)f(status)
+h(v)-5 b(alue)27 b(to)h(this)f(routine)f(will)f(cause)j(a)g(generic)g
+(description)d(of)j(the)g(error)f(and)120 2200 y(all)e(the)i(messages)h
+(from)e(the)h(in)m(ternal)e(CFITSIO)g(error)h(stac)m(k)i(to)g(b)s(e)e
+(prin)m(ted)f(to)i(the)g(sp)s(eci\014ed)e(stream.)120
+2313 y(The)30 b Fc(stream)f Fg(parameter)h(is)g(usually)e(set)j(equal)f
+(to)h Fc("stdout")d Fg(or)i Fc("stderr")p Fg(.)261 2426
+y(The)25 b(second)g(routine)f(simply)e(returns)i(a)h(30-c)m(haracter)j
+(descriptiv)m(e)c(error)g(message)i(corresp)s(onding)120
+2538 y(to)31 b(the)g(input)d(status)j(v)-5 b(alue.)261
+2651 y(The)30 b(last)g(routine)g(returns)f(the)h(curren)m(t)g(CFITSIO)f
+(library)f(v)m(ersion)i(n)m(um)m(b)s(er.)120 2899 y Fb(4.2)112
+b(File)37 b(Op)s(en/Close)g(Routines)120 3072 y Fc(int)47
+b(fits_open_file\()d(fitsfile)h(**fptr,)h(char)h(*filename,)e(int)h
+(mode,)h(int)g(*status\))120 3185 y(int)g(fits_open_data\()d(fitsfile)h
+(**fptr,)h(char)h(*filename,)e(int)h(mode,)h(int)g(*status\))120
+3298 y(int)g(fits_open_table\(fitsfile)41 b(**fptr,)46
+b(char)h(*filename,)e(int)h(mode,)h(int)g(*status\))120
+3411 y(int)g(fits_open_image\(fitsfile)41 b(**fptr,)46
+b(char)h(*filename,)e(int)h(mode,)h(int)g(*status\))120
+3637 y(int)g(fits_create_file\(fitsfil)o(e)42 b(**fptr,)k(char)g
+(*filename,)f(int)i(*status\))120 3750 y(int)g
+(fits_close_file\(fitsfile)41 b(*fptr,)46 b(int)h(*status\))261
+3962 y Fg(These)38 b(routines)e(op)s(en)i(or)f(close)i(a)f(\014le.)62
+b(The)37 b(\014rst)g Fc(fitsfile)f Fg(parameter)i(in)f(these)h(and)f
+(nearly)120 4075 y(ev)m(ery)28 b(other)g(CFITSIO)f(routine)f(is)h(a)h
+(p)s(oin)m(ter)f(to)h(a)g(structure)g(that)g(CFITSIO)e(uses)h(to)i
+(store)f(relev)-5 b(an)m(t)120 4188 y(parameters)31 b(ab)s(out)f(eac)m
+(h)i(op)s(ened)e(\014le.)41 b(Y)-8 b(ou)31 b(should)e(nev)m(er)i
+(directly)e(read)i(or)f(write)g(an)m(y)h(information)120
+4301 y(in)23 b(this)h(structure.)38 b(Memory)26 b(for)e(this)g
+(structure)g(is)g(allo)s(cated)g(automatically)h(when)f(the)h(\014le)e
+(is)h(op)s(ened)120 4414 y(or)30 b(created,)i(and)e(is)f(freed)h(when)g
+(the)g(\014le)g(is)f(closed.)261 4527 y(The)f Fc(mode)e
+Fg(parameter)j(in)d(the)i Fc(fits)p 1552 4527 29 4 v
+34 w(open)p 1778 4527 V 33 w(xxxx)f Fg(set)h(of)g(routines)f(can)h(b)s
+(e)f(set)i(to)f(either)g Fc(READONLY)120 4640 y Fg(or)i
+Fc(READWRITE)d Fg(to)j(select)g(the)g(t)m(yp)s(e)f(of)h(\014le)f
+(access)i(that)f(will)d(b)s(e)i(allo)m(w)m(ed.)40 b(These)29
+b(sym)m(b)s(olic)f(constan)m(ts)120 4753 y(are)j(de\014ned)e(in)g
+Fc(fitsio.h)p Fg(.)261 4866 y(The)k Fc(fits)p 649 4866
+V 33 w(open)p 874 4866 V 34 w(file)f Fg(routine)h(op)s(ens)f(the)i
+(\014le)f(and)f(p)s(ositions)g(the)i(in)m(ternal)e(\014le)g(p)s(oin)m
+(ter)h(to)h(the)120 4979 y(b)s(eginning)21 b(of)j(the)g(\014le,)g(or)g
+(to)h(the)f(sp)s(eci\014ed)e(extension)h(if)g(an)h(extension)f(name)h
+(or)g(n)m(um)m(b)s(er)e(is)h(app)s(ended)120 5092 y(to)k(the)f(\014le)g
+(name)g(\(see)h(the)g(later)f(section)h(on)f(\\CFITSIO)f(File)g(Names)i
+(and)f(Filters")g(for)g(a)g(description)120 5204 y(of)32
+b(the)f(syn)m(tax\).)45 b Fc(fits)p 945 5204 V 33 w(open)p
+1170 5204 V 33 w(data)31 b Fg(b)s(eha)m(v)m(es)g(similarly)d(except)33
+b(that)f(it)f(will)d(mo)m(v)m(e)33 b(to)f(the)g(\014rst)f(HDU)120
+5317 y(con)m(taining)k(signi\014can)m(t)f(data)i(if)e(a)i(HDU)g(name)g
+(or)f(n)m(um)m(b)s(er)f(to)i(op)s(en)f(is)f(not)i(explicitly)c(sp)s
+(eci\014ed)i(as)120 5430 y(part)23 b(of)h(the)g(\014lename.)38
+b(It)23 b(will)e(mo)m(v)m(e)k(to)g(the)e(\014rst)g(IMA)m(GE)i(HDU)f
+(with)e(NAXIS)i(greater)h(than)e(0,)j(or)d(the)1928 5809
+y(6)p eop
+%%Page: 7 7
+7 6 bop 120 573 a Fg(\014rst)29 b(table)g(that)i(do)s(es)e(not)h(con)m
+(tain)g(the)g(strings)e(`GTI')i(\(a)g(Go)s(o)s(d)g(Time)e(In)m(terv)-5
+b(al)30 b(extension\))f(or)h(`OB-)120 686 y(ST)-8 b(ABLE')37
+b(in)f(the)h(EXTNAME)h(k)m(eyw)m(ord)f(v)-5 b(alue.)61
+b(The)36 b Fc(fits)p 2380 686 29 4 v 34 w(open)p 2606
+686 V 33 w(table)g Fg(and)g Fc(fits)p 3290 686 V 34 w(open)p
+3516 686 V 33 w(image)120 799 y Fg(routines)e(are)i(similar)c(except)37
+b(that)f(they)f(will)e(mo)m(v)m(e)j(to)g(the)g(\014rst)e(signi\014can)m
+(t)h(table)g(HDU)h(or)f(image)120 912 y(HDU,)c(resp)s(ectiv)m(ely)f(if)
+f(a)i(HDU)g(name)g(of)f(n)m(um)m(b)s(er)f(is)h(not)g(sp)s(eci\014ed)f
+(as)i(part)f(of)g(the)h(input)d(\014le)i(name.)261 1024
+y(When)e(op)s(ening)f(an)h(existing)f(\014le,)h(the)h
+Fc(filename)d Fg(can)i(include)e(optional)i(argumen)m(ts,)h(enclosed)f
+(in)120 1137 y(square)h(brac)m(k)m(ets)i(that)f(sp)s(ecify)e
+(\014ltering)g(op)s(erations)g(that)i(should)e(b)s(e)h(applied)e(to)j
+(the)g(input)d(\014le.)40 b(F)-8 b(or)120 1250 y(example,)263
+1428 y Fc(myfile.fit[EVENTS][counts)41 b(>)48 b(0])120
+1605 y Fg(op)s(ens)27 b(the)i(table)f(in)f(the)i(EVENTS)e(extension)h
+(and)g(creates)i(a)e(virtual)f(table)h(b)m(y)g(selecting)g(only)g
+(those)120 1718 y(ro)m(ws)g(where)f(the)i(COUNTS)d(column)h(v)-5
+b(alue)28 b(is)f(greater)i(than)f(0.)40 b(See)28 b(section)g(5)h(for)f
+(more)g(examples)f(of)120 1831 y(these)k(p)s(o)m(w)m(erful)e
+(\014ltering)f(capabilities.)261 1944 y(In)38 b Fc(fits)p
+581 1944 V 33 w(create)p 902 1944 V 33 w(file)p Fg(,)h(the)g
+Fc(filename)d Fg(is)i(simply)e(the)i(ro)s(ot)h(name)f(of)h(the)g
+(\014le)e(to)i(b)s(e)f(created.)120 2057 y(Y)-8 b(ou)36
+b(can)g(o)m(v)m(erwrite)g(an)g(existing)e(\014le)h(b)m(y)g(pre\014xing)
+f(the)i(name)g(with)e(a)i(`!')57 b(c)m(haracter)37 b(\(on)f(the)f(Unix)
+120 2170 y(command)30 b(line)e(this)h(m)m(ust)g(b)s(e)g(pre\014xed)g
+(with)g(a)h(bac)m(kslash,)g(as)g(in)e Fc(`\\!file.fit')p
+Fg(\).)38 b(If)29 b(the)h(\014le)f(name)120 2282 y(ends)f(with)f
+Fc(.gz)h Fg(the)h(\014le)f(will)e(b)s(e)i(compressed)g(using)f(the)i
+(gzip)f(algorithm.)39 b(If)29 b(the)f(\014lename)g(is)g
+Fc(stdout)120 2395 y Fg(or)h Fc("-")e Fg(\(a)j(single)d(dash)h(c)m
+(haracter\))j(then)d(the)h(output)f(\014le)g(will)e(b)s(e)i(pip)s(ed)e
+(to)k(the)f(stdout)f(stream.)41 b(Y)-8 b(ou)120 2508
+y(can)27 b(c)m(hain)f(sev)m(eral)g(tasks)h(together)h(b)m(y)f(writing)d
+(the)j(output)f(from)g(the)g(\014rst)g(task)h(to)g Fc(stdout)e
+Fg(and)h(then)120 2621 y(reading)j(the)i(input)d(\014le)i(in)f(the)i
+(2nd)e(task)i(from)f Fc(stdin)f Fg(or)h Fc("-")p Fg(.)120
+2867 y Fb(4.3)112 b(HDU-lev)m(el)36 b(Routines)261 3040
+y Fg(The)30 b(routines)f(listed)g(in)g(this)h(section)g(op)s(erate)h
+(on)f(Header-Data)j(Units)d(\(HDUs\))h(in)e(a)i(\014le.)120
+3153 y Fc(________________________)o(____)o(____)o(___)o(____)o(____)o
+(___)o(____)o(____)o(___)o(____)o(__)120 3266 y(int)47
+b(fits_get_num_hdus\(fitsfi)o(le)42 b(*fptr,)k(int)h(*hdunum,)e(int)i
+(*status\))120 3379 y(int)g(fits_get_hdu_num\(fitsfil)o(e)42
+b(*fptr,)94 b(int)47 b(*hdunum\))261 3579 y Fg(The)39
+b(\014rst)f(routines)g(returns)g(the)h(total)h(n)m(um)m(b)s(er)e(of)h
+(HDUs)h(in)d(the)j(FITS)e(\014le,)j(and)d(the)h(second)120
+3692 y(routine)32 b(returns)f(the)i(p)s(osition)e(of)i(the)g(curren)m
+(tly)e(op)s(ened)h(HDU)i(in)d(the)i(FITS)f(\014le)g(\(starting)g(with)g
+(1,)120 3805 y(not)f(0\).)120 4005 y Fc(________________________)o
+(____)o(____)o(___)o(____)o(____)o(___)o(____)o(____)o(___)o(____)o
+(____)o(___)o(____)o(__)120 4118 y(int)47 b(fits_movabs_hdu\(fitsfile)
+41 b(*fptr,)46 b(int)h(hdunum,)f(int)h(*hdutype,)e(int)i(*status\))120
+4231 y(int)g(fits_movrel_hdu\(fitsfile)41 b(*fptr,)46
+b(int)h(nmove,)94 b(int)47 b(*hdutype,)e(int)i(*status\))120
+4344 y(int)g(fits_movnam_hdu\(fitsfile)41 b(*fptr,)46
+b(int)h(hdutype,)f(char)g(*extname,)1075 4457 y(int)g(extver,)g(int)h
+(*status\))261 4657 y Fg(These)31 b(routines)f(enable)h(y)m(ou)g(to)h
+(mo)m(v)m(e)g(to)g(a)g(di\013eren)m(t)e(HDU)i(in)e(the)h(\014le.)42
+b(Most)32 b(of)g(the)f(CFITSIO)120 4770 y(functions)g(whic)m(h)h(read)h
+(or)g(write)f(k)m(eyw)m(ords)h(or)g(data)h(op)s(erate)f(only)g(on)f
+(the)h(curren)m(tly)f(op)s(ened)h(HDU)120 4883 y(in)h(the)h(\014le.)53
+b(The)34 b(\014rst)g(routine)g(mo)m(v)m(es)i(to)g(the)f(sp)s(eci\014ed)
+e(absolute)i(HDU)g(n)m(um)m(b)s(er)f(in)f(the)i(FITS)f(\014le)120
+4996 y(\(the)e(\014rst)f(HDU)i(=)e(1\),)i(whereas)f(the)g(second)f
+(routine)g(mo)m(v)m(es)i(a)f(relativ)m(e)g(n)m(um)m(b)s(er)f(of)h(HDUs)
+g(forw)m(ard)120 5109 y(or)f(bac)m(kw)m(ard)h(from)e(the)i(curren)m
+(tly)e(op)s(en)g(HDU.)i(The)f Fc(hdutype)e Fg(parameter)i(returns)f
+(the)i(t)m(yp)s(e)f(of)g(the)120 5222 y(newly)d(op)s(ened)h(HDU,)i(and)
+e(will)e(b)s(e)i(equal)g(to)h(one)g(of)g(these)g(sym)m(b)s(olic)e
+(constan)m(t)j(v)-5 b(alues:)40 b Fc(IMAGE)p 3564 5222
+V 33 w(HDU,)120 5334 y(ASCII)p 366 5334 V 33 w(TBL,)47
+b(or)g(BINARY)p 1069 5334 V 33 w(TBL)p Fg(.)37 b Fc(hdutype)g
+Fg(ma)m(y)h(b)s(e)g(set)h(to)g(NULL)f(if)f(it)h(is)g(not)g(needed.)64
+b(The)38 b(third)120 5447 y(routine)30 b(mo)m(v)m(es)j(to)f(the)f
+(\(\014rst\))h(HDU)g(that)f(matc)m(hes)i(the)e(input)f(extension)h(t)m
+(yp)s(e,)g(name,)h(and)f(v)m(ersion)120 5560 y(n)m(um)m(b)s(er,)23
+b(as)f(giv)m(en)h(b)m(y)f(the)g Fc(XTENSION,)46 b(EXTNAME)20
+b Fg(\(or)j Fc(HDUNAME)p Fg(\))d(and)i Fc(EXTVER)f Fg(k)m(eyw)m(ords.)
+38 b(If)22 b(the)g(input)1928 5809 y(7)p eop
+%%Page: 8 8
+8 7 bop 120 573 a Fg(v)-5 b(alue)33 b(of)g Fc(extver)e
+Fg(=)i(0,)i(then)e(the)g(v)m(ersion)g(n)m(um)m(b)s(er)e(will)g(b)s(e)h
+(ignored)h(when)f(lo)s(oking)g(for)h(a)g(matc)m(hing)120
+686 y(HDU.)120 898 y Fc(________________________)o(____)o(____)o(___)o
+(____)o(____)o(___)o(____)o(____)o(___)o(____)o(____)120
+1011 y(int)47 b(fits_get_hdu_type\(fitsfi)o(le)42 b(*fptr,)93
+b(int)47 b(*hdutype,)f(int)g(*status\))261 1224 y Fg(Get)21
+b(the)g(t)m(yp)s(e)f(of)h(the)f(curren)m(t)g(HDU)h(in)e(the)i(FITS)e
+(\014le:)35 b Fc(IMAGE)p 2435 1224 29 4 v 33 w(HDU,)47
+b(ASCII)p 2947 1224 V 33 w(TBL,)f(or)h(BINARY)p 3649
+1224 V 33 w(TBL)p Fg(.)120 1436 y Fc(________________________)o(____)o
+(____)o(___)o(____)o(____)o(___)o(____)o(____)o(___)o(____)o(____)o
+(___)120 1549 y(int)g(fits_copy_hdu\(fitsfile)42 b(*infptr,)j(fitsfile)
+h(*outfptr,)f(int)i(morekeys,)979 1662 y(int)g(*status\))120
+1775 y(int)g(fits_copy_file\(fitsfile)41 b(*infptr,)46
+b(fitsfile)f(*outfptr,)h(int)h(previous,)979 1888 y(int)g(current,)f
+(int)g(following,)f(>)j(int)f(*status\))261 2100 y Fg(The)34
+b(\014rst)g(routine)f(copies)i(the)f(curren)m(t)g(HDU)i(from)e(the)g
+(FITS)g(\014le)g(asso)s(ciated)g(with)g(infptr)e(and)120
+2213 y(app)s(ends)i(it)i(to)h(the)f(end)f(of)h(the)g(FITS)g(\014le)f
+(asso)s(ciated)h(with)f(outfptr.)57 b(Space)36 b(ma)m(y)h(b)s(e)e
+(reserv)m(ed)i(for)120 2326 y Fc(morekeys)32 b Fg(additional)h(k)m(eyw)
+m(ords)i(in)f(the)g(output)h(header.)53 b(The)35 b(second)f(routine)g
+(copies)h(an)m(y)g(HDUs)120 2439 y(previous)41 b(to)j(the)e(curren)m(t)
+h(HDU,)h(and/or)e(the)h(curren)m(t)f(HDU,)i(and/or)f(an)m(y)g(HDUs)g
+(follo)m(wing)e(the)120 2552 y(curren)m(t)22 b(HDU,)h(dep)s(ending)c
+(on)j(the)g(v)-5 b(alue)22 b(\(T)-8 b(rue)22 b(or)g(F)-8
+b(alse\))23 b(of)f Fc(previous,)45 b(current)p Fg(,)22
+b(and)g Fc(following)p Fg(,)120 2665 y(resp)s(ectiv)m(ely)-8
+b(.)40 b(F)-8 b(or)32 b(example,)215 2853 y Fc(fits_copy_file\(infptr,)
+42 b(outfptr,)k(0,)h(1,)g(1,)g(&status\);)120 3040 y
+Fg(will)32 b(cop)m(y)k(the)f(curren)m(t)g(HDU)g(and)g(an)m(y)g(HDUs)g
+(that)h(follo)m(w)e(it)g(from)h(the)g(input)e(to)i(the)h(output)e
+(\014le,)120 3153 y(but)c(it)g(will)d(not)k(cop)m(y)g(an)m(y)g(HDUs)g
+(preceding)e(the)i(curren)m(t)f(HDU.)1928 5809 y(8)p
+eop
+%%Page: 9 9
+9 8 bop 120 573 a Fb(4.4)112 b(Image)37 b(I/O)h(Routines)120
+744 y Fg(This)29 b(section)h(lists)f(the)i(more)f(imp)s(ortan)m(t)g
+(CFITSIO)e(routines)i(whic)m(h)f(op)s(erate)i(on)f(FITS)g(images.)120
+956 y Fc(________________________)o(____)o(____)o(___)o(____)o(____)o
+(___)o(____)o(____)o(___)o(____)o(__)120 1069 y(int)47
+b(fits_get_img_type\(fitsfi)o(le)42 b(*fptr,)k(int)h(*bitpix,)e(int)i
+(*status\))120 1181 y(int)g(fits_get_img_dim\()c(fitsfile)j(*fptr,)g
+(int)h(*naxis,)93 b(int)47 b(*status\))120 1294 y(int)g
+(fits_get_img_size\(fitsfi)o(le)42 b(*fptr,)k(int)h(maxdim,)93
+b(long)47 b(*naxes,)1170 1407 y(int)g(*status\))120 1520
+y(int)g(fits_get_img_param\(fitsf)o(ile)41 b(*fptr,)46
+b(int)h(maxdim,)94 b(int)47 b(*bitpix,)1218 1633 y(int)g(*naxis,)e
+(long)i(*naxes,)f(int)h(*status\))261 1844 y Fg(Get)38
+b(information)e(ab)s(out)h(the)g(curren)m(tly)f(op)s(ened)h(image)g
+(HDU.)h(The)f(\014rst)f(routine)g(returns)g(the)120 1957
+y(datat)m(yp)s(e)41 b(of)e(the)h(image)g(as)g(\(de\014ned)f(b)m(y)g
+(the)h Fc(BITPIX)e Fg(k)m(eyw)m(ord\),)43 b(whic)m(h)38
+b(can)i(ha)m(v)m(e)h(the)f(follo)m(wing)120 2070 y(sym)m(b)s(olic)29
+b(constan)m(t)i(v)-5 b(alues:)311 2256 y Fc(BYTE_IMG)141
+b(=)i(8)g(\()47 b(8-bit)g(byte)f(pixels,)g(0)h(-)h(255\))311
+2369 y(SHORT_IMG)93 b(=)i(16)143 b(\(16)47 b(bit)g(integer)e(pixels\))
+311 2482 y(LONG_IMG)141 b(=)95 b(32)143 b(\(32-bit)46
+b(integer)f(pixels\))311 2595 y(FLOAT_IMG)93 b(=)47 b(-32)143
+b(\(32-bit)46 b(floating)f(point)h(pixels\))311 2708
+y(DOUBLE_IMG)f(=)i(-64)143 b(\(64-bit)46 b(floating)f(point)h(pixels\))
+261 2895 y Fg(The)34 b(second)g(and)f(third)f(routines)h(return)g(the)h
+(n)m(um)m(b)s(er)e(of)i(dimensions)d(in)i(the)h(image)g(\(from)g(the)
+120 3007 y Fc(NAXIS)25 b Fg(k)m(eyw)m(ord\),)j(and)e(the)h(sizes)f(of)g
+(eac)m(h)i(dimension)c(\(from)i(the)g Fc(NAXIS1,)46 b(NAXIS2)p
+Fg(,)26 b(etc.)40 b(k)m(eyw)m(ords\).)120 3120 y(The)g(last)h(routine)f
+(simply)f(com)m(bines)h(the)i(function)d(of)i(the)h(\014rst)e(3)h
+(routines.)72 b(The)40 b(input)f Fc(maxdim)120 3233 y
+Fg(parameter)28 b(in)f(this)f(routine)h(giv)m(es)h(the)g(maxim)m(um)f
+(n)m(um)m(b)s(er)f(dimensions)f(that)k(ma)m(y)f(b)s(e)f(returned)g
+(\(i.e.,)120 3346 y(the)k(dimension)c(of)k(the)f Fc(naxes)f
+Fg(arra)m(y\))120 3557 y Fc(________________________)o(____)o(____)o
+(___)o(____)o(____)o(___)o(____)o(____)o(___)o(_)120
+3670 y(int)47 b(fits_create_img\(fitsfile)41 b(*fptr,)46
+b(int)h(bitpix,)f(int)h(naxis,)1075 3783 y(long)f(*naxes,)g(int)h
+(*status\))261 3994 y Fg(Create)28 b(an)f(image)h(HDU)g(b)m(y)f
+(writing)e(the)i(required)f(k)m(eyw)m(ords)h(whic)m(h)f(de\014ne)h(the)
+g(structure)g(of)g(the)120 4107 y(image.)50 b(The)33
+b(2nd)f(through)h(4th)h(parameters)f(sp)s(eci\014ed)f(the)h(datat)m(yp)
+s(e,)j(the)d(n)m(um)m(b)s(er)f(of)i(dimensions,)120 4220
+y(and)26 b(the)h(sizes)f(of)g(the)h(dimensions.)37 b(The)26
+b(allo)m(w)m(ed)g(v)-5 b(alues)26 b(of)h(the)f Fc(bitpix)f
+Fg(parameter)i(are)g(listed)e(ab)s(o)m(v)m(e)120 4333
+y(in)32 b(the)h(description)e(of)i(the)g Fc(fits)p 1319
+4333 29 4 v 33 w(get)p 1496 4333 V 33 w(img)p 1673 4333
+V 34 w(type)f Fg(routine.)47 b(If)32 b(the)h(FITS)f(\014le)g(p)s(oin)m
+(ted)g(to)i(b)m(y)f Fc(fptr)e Fg(is)120 4446 y(empt)m(y)c(\(previously)
+d(created)j(with)e Fc(fits)p 1575 4446 V 33 w(create)p
+1896 4446 V 33 w(file)p Fg(\))g(then)h(this)f(routine)g(creates)j(a)f
+(primary)d(arra)m(y)120 4559 y(in)36 b(the)h(\014le,)h(otherwise)f(a)g
+(new)g(IMA)m(GE)h(extension)f(is)f(app)s(ended)f(to)j(end)f(of)g(the)g
+(\014le)g(follo)m(wing)e(the)120 4672 y(other)c(HDUs)g(in)e(the)h
+(\014le.)120 4883 y Fc(________________________)o(____)o(____)o(___)o
+(____)o(____)o(___)o(____)o(____)o(___)o(____)o(_)120
+4996 y(int)47 b(fits_write_pix\(fitsfile)41 b(*fptr,)46
+b(int)h(datatype,)f(long)g(*fpixel,)836 5109 y(long)h(nelements,)e
+(void)h(*array,)g(int)h(*status\);)120 5334 y(int)g
+(fits_write_pixnull\(fitsf)o(ile)41 b(*fptr,)46 b(int)h(datatype,)f
+(long)g(*fpixel,)836 5447 y(long)h(nelements,)e(void)h(*array,)g(void)h
+(*nulval,)e(int)i(*status\);)1928 5809 y Fg(9)p eop
+%%Page: 10 10
+10 9 bop 120 573 a Fc(int)47 b(fits_read_pix\(fitsfile)42
+b(*fptr,)k(int)94 b(datatype,)46 b(long)g(*fpixel,)979
+686 y(long)h(nelements,)e(void)h(*nulval,)g(void)h(*array,)979
+799 y(int)g(*anynul,)f(int)g(*status\))261 1007 y Fg(Read)32
+b(or)f(write)f(all)g(or)h(part)h(of)f(the)g(FITS)g(image.)43
+b(There)31 b(are)h(2)f(di\013eren)m(t)g('write')g(pixel)e(routines:)120
+1120 y(The)23 b(\014rst)g(simply)e(writes)i(the)h(input)e(arra)m(y)i
+(of)g(pixels)e(to)i(the)g(FITS)f(\014le.)38 b(The)23
+b(second)h(is)f(similar,)f(except)120 1233 y(that)30
+b(it)e(substitutes)g(the)h(appropriate)f(n)m(ull)f(pixel)g(v)-5
+b(alue)29 b(in)f(the)h(FITS)f(\014le)g(for)h(an)m(y)g(pixels)e(whic)m
+(h)h(ha)m(v)m(e)120 1346 y(a)j(v)-5 b(alue)29 b(equal)h(to)h
+Fc(*nulval)d Fg(\(note)j(that)g(this)e(parameter)h(giv)m(es)h(the)f
+(address)f(of)i(the)f(n)m(ull)e(pixel)h(v)-5 b(alue,)120
+1459 y(not)35 b(the)g(v)-5 b(alue)34 b(itself)7 b(\).)52
+b(Similarly)-8 b(,)33 b(when)g(reading)h(an)h(image,)h(CFITSIO)d(will)f
+(substitute)h(the)i(v)-5 b(alue)120 1572 y(giv)m(en)29
+b(b)m(y)f Fc(nulval)f Fg(for)i(an)m(y)g(unde\014ned)d(pixels)h(in)h
+(the)h(image,)g(unless)e Fc(nulval)46 b(=)i(NULL)p Fg(,)27
+b(in)h(whic)m(h)f(case)120 1685 y(no)j(c)m(hec)m(ks)i(will)c(b)s(e)i
+(made)g(for)g(unde\014ned)e(pixels)h(when)g(reading)h(the)g(FITS)g
+(image.)261 1798 y(The)35 b Fc(fpixel)f Fg(parameter)i(in)e(these)i
+(routines)e(is)h(an)g(arra)m(y)h(whic)m(h)e(giv)m(es)i(the)g(co)s
+(ordinate)f(in)f(eac)m(h)120 1910 y(dimension)22 b(of)k(the)f(\014rst)f
+(pixel)g(to)h(b)s(e)g(read)g(or)g(written,)g(and)g Fc(nelements)d
+Fg(is)i(the)h(total)h(n)m(um)m(b)s(er)e(of)h(pixels)120
+2023 y(to)i(read)g(or)f(write.)39 b Fc(array)25 b Fg(is)h(the)g
+(address)g(of)h(an)f(arra)m(y)h(whic)m(h)e(either)h(con)m(tains)h(the)g
+(pixel)e(v)-5 b(alues)26 b(to)h(b)s(e)120 2136 y(written,)k(or)g(will)e
+(hold)g(the)j(v)-5 b(alues)30 b(of)i(the)f(pixels)f(that)i(are)f(read.)
+43 b(When)31 b(reading,)g Fc(array)f Fg(m)m(ust)h(ha)m(v)m(e)120
+2249 y(b)s(een)k(allo)s(cated)h(large)g(enough)f(to)i(hold)d(all)h(the)
+h(returned)f(pixel)f(v)-5 b(alues.)56 b(These)36 b(routines)e(starts)j
+(at)120 2362 y(the)e Fc(fpixel)d Fg(lo)s(cation)i(and)g(then)g(read)h
+(or)f(write)g(the)g Fc(nelements)e Fg(pixels,)i(con)m(tin)m(uing)g(on)g
+(successiv)m(e)120 2475 y(ro)m(ws)f(of)g(the)g(image)g(if)f(necessary)
+-8 b(.)49 b(F)-8 b(or)34 b(example,)g(to)f(write)f(an)h(en)m(tire)g(2D)
+h(image,)g(set)f Fc(fpixel[0])46 b(=)120 2588 y(fpixel[1])f(=)j(1)p
+Fg(,)35 b(and)f Fc(nelements)46 b(=)h(NAXIS1)f(*)i(NAXIS2)p
+Fg(.)j(Or)34 b(to)i(read)e(just)g(the)h(10th)h(ro)m(w)e(of)h(the)120
+2701 y(image,)49 b(set)c Fc(fpixel[0])g(=)j(1,)f(fpixel[1])e(=)j(10)p
+Fg(,)g(and)c Fc(nelements)h(=)i(NAXIS1)p Fg(.)82 b(The)45
+b Fc(datatype)120 2814 y Fg(parameter)28 b(sp)s(eci\014es)d(the)j
+(datat)m(yp)s(e)g(of)f(the)g(C)g Fc(array)e Fg(in)h(the)h(program,)h
+(whic)m(h)e(need)h(not)g(b)s(e)g(the)g(same)120 2927
+y(as)32 b(the)f(datat)m(yp)s(e)i(of)e(the)h(FITS)f(image)g(itself.)43
+b(If)31 b(the)h(datat)m(yp)s(es)g(di\013er)e(then)h(CFITSIO)f(will)f
+(con)m(v)m(ert)120 3040 y(the)i(data)h(as)f(it)g(is)f(read)h(or)g
+(written.)41 b(The)31 b(follo)m(wing)e(sym)m(b)s(olic)h(constan)m(ts)i
+(are)f(allo)m(w)m(ed)g(for)g(the)g(v)-5 b(alue)120 3152
+y(of)31 b Fc(datatype)p Fg(:)215 3337 y Fc(TBYTE)238
+b(unsigned)45 b(char)215 3450 y(TSBYTE)190 b(signed)46
+b(char)215 3563 y(TSHORT)190 b(signed)46 b(short)215
+3675 y(TUSHORT)142 b(unsigned)45 b(short)215 3788 y(TINT)286
+b(signed)46 b(int)215 3901 y(TUINT)238 b(unsigned)45
+b(int)215 4014 y(TLONG)238 b(signed)46 b(long)215 4127
+y(TULONG)190 b(unsigned)45 b(long)215 4240 y(TFLOAT)190
+b(float)215 4353 y(TDOUBLE)142 b(double)120 4561 y
+(________________________)o(____)o(____)o(___)o(____)o(____)o(___)o
+(____)o(____)o(___)o(____)o(____)120 4674 y(int)47 b
+(fits_write_subset\(fitsfi)o(le)42 b(*fptr,)k(int)h(datatype,)e(long)h
+(*fpixel,)740 4787 y(long)h(*lpixel,)f(DTYPE)g(*array,)g(>)h(int)g
+(*status\))120 5013 y(int)g(fits_read_subset\(fitsfil)o(e)42
+b(*fptr,)k(int)95 b(datatype,)45 b(long)h(*fpixel,)740
+5126 y(long)h(*lpixel,)f(long)g(*inc,)h(void)f(*nulval,)94
+b(void)46 b(*array,)740 5239 y(int)h(*anynul,)f(int)h(*status\))261
+5447 y Fg(Read)i(or)g(write)e(a)i(rectangular)g(section)g(of)g(the)f
+(FITS)g(image.)96 b(These)49 b(are)g(v)m(ery)g(similar)d(to)120
+5560 y Fc(fits)p 318 5560 29 4 v 33 w(write)p 591 5560
+V 33 w(pix)37 b Fg(and)f Fc(fits)p 1180 5560 V 34 w(read)p
+1406 5560 V 33 w(pix)g Fg(except)j(that)f(y)m(ou)f(sp)s(ecify)f(the)i
+(last)f(pixel)f(co)s(ordinate)h(\(the)1905 5809 y(10)p
+eop
+%%Page: 11 11
+11 10 bop 120 573 a Fg(upp)s(er)22 b(righ)m(t)h(corner)h(of)g(the)h
+(section\))f(instead)f(of)h(the)h(n)m(um)m(b)s(er)d(of)i(pixels)f(to)h
+(b)s(e)g(read.)38 b(The)23 b(read)h(routine)120 686 y(also)38
+b(has)f(an)h Fc(inc)f Fg(parameter)h(whic)m(h)e(can)j(b)s(e)e(used)g
+(to)h(read)g(only)f(ev)m(ery)h Fc(inc-th)e Fg(pixel)g(along)i(eac)m(h)
+120 799 y(dimension)26 b(of)j(the)g(image.)40 b(Normally)28
+b Fc(inc[0])46 b(=)h(inc[1])f(=)i(1)28 b Fg(to)i(read)e(ev)m(ery)i
+(pixel)d(in)g(a)i(2D)h(image.)120 912 y(T)-8 b(o)31 b(read)f(ev)m(ery)h
+(other)g(pixel)e(in)g(the)h(en)m(tire)h(2D)g(image,)g(set)311
+1099 y Fc(fpixel[0])45 b(=)j(fpixel[1])d(=)i(1)311 1212
+y(lpixel[0])e(=)j({NAXIS1})311 1325 y(lpixel[1])d(=)j({NAXIS2})311
+1438 y(inc[0])e(=)h(inc[1])g(=)g(2)261 1626 y Fg(Or,)30
+b(to)h(read)f(the)h(8th)g(ro)m(w)f(of)h(a)f(2D)i(image,)e(set)311
+1813 y Fc(fpixel[0])45 b(=)j(1)311 1926 y(fpixel[1])d(=)j(8)311
+2039 y(lpixel[0])d(=)j({NAXIS1})311 2152 y(lpixel[1])d(=)j(8)311
+2265 y(inc[0])e(=)h(inc[1])g(=)g(1)1905 5809 y Fg(11)p
+eop
+%%Page: 12 12
+12 11 bop 120 573 a Fb(4.5)112 b(T)-9 b(able)37 b(I/O)h(Routines)120
+744 y Fg(This)29 b(section)h(lists)f(the)i(most)f(imp)s(ortan)m(t)g
+(CFITSIO)f(routines)g(whic)m(h)g(op)s(erate)i(on)f(FITS)g(tables.)120
+957 y Fc(________________________)o(____)o(____)o(___)o(____)o(____)o
+(___)o(____)o(____)o(___)o(____)o(____)o(___)o(____)o(__)120
+1070 y(int)47 b(fits_create_tbl\(fitsfile)41 b(*fptr,)46
+b(int)h(tbltype,)f(long)g(nrows,)g(int)h(tfields,)311
+1183 y(char)g(*ttype[],char)d(*tform[],)h(char)i(*tunit[],)e(char)i
+(*extname,)e(int)i(*status\))261 1395 y Fg(Create)e(a)f(new)f(table)h
+(extension)f(b)m(y)h(writing)e(the)i(required)e(k)m(eyw)m(ords)i(that)g
+(de\014ne)f(the)h(table)120 1508 y(structure.)38 b(The)22
+b(required)e(n)m(ull)h(primary)f(arra)m(y)j(will)d(b)s(e)i(created)i
+(\014rst)d(if)h(the)h(\014le)e(is)h(initially)d(completely)120
+1621 y(empt)m(y)-8 b(.)41 b Fc(tbltype)26 b Fg(de\014nes)i(the)g(t)m
+(yp)s(e)h(of)g(table)f(and)g(can)g(ha)m(v)m(e)i(v)-5
+b(alues)28 b(of)g Fc(ASCII)p 2931 1621 29 4 v 33 w(TBL)47
+b(or)g(BINARY)p 3586 1621 V 33 w(TBL)p Fg(.)120 1734
+y(Binary)33 b(tables)h(are)h(generally)e(preferred)g(b)s(ecause)h(they)
+h(are)f(more)h(e\016cien)m(t)f(and)g(supp)s(ort)f(a)h(greater)120
+1847 y(range)d(of)f(column)f(datat)m(yp)s(es)j(than)e(ASCI)s(I)f
+(tables.)261 1960 y(The)c Fc(nrows)f Fg(parameter)i(giv)m(es)g(the)f
+(initial)e(n)m(um)m(b)s(er)h(of)i(empt)m(y)g(ro)m(ws)f(to)h(b)s(e)f
+(allo)s(cated)g(for)h(the)f(table;)120 2073 y(this)g(should)g(normally)
+f(b)s(e)i(set)h(to)g(0.)40 b(The)26 b Fc(tfields)f Fg(parameter)i(giv)m
+(es)f(the)h(n)m(um)m(b)s(er)e(of)i(columns)e(in)g(the)120
+2186 y(table)e(\(maxim)m(um)f(=)g(999\).)40 b(The)22
+b Fc(ttype,)46 b(tform)p Fg(,)24 b(and)e Fc(tunit)f Fg(parameters)i
+(giv)m(e)h(the)f(name,)h(datat)m(yp)s(e,)120 2299 y(and)34
+b(ph)m(ysical)f(units)h(of)g(eac)m(h)i(column,)f(and)f
+Fc(extname)f Fg(giv)m(es)i(the)g(name)g(for)f(the)h(table)g(\(the)g(v)
+-5 b(alue)34 b(of)120 2412 y(the)j Fc(EXTNAME)e Fg(k)m(eyw)m(ord\).)61
+b(The)36 b(FITS)g(Standard)g(recommends)g(that)i(only)e(letters,)j
+(digits,)e(and)f(the)120 2524 y(underscore)27 b(c)m(haracter)h(b)s(e)f
+(used)g(in)f(column)g(names)h(with)f(no)h(em)m(b)s(edded)g(spaces.)40
+b(It)27 b(is)g(recommended)120 2637 y(that)k(all)e(the)i(column)e
+(names)h(in)f(a)i(giv)m(en)f(table)h(b)s(e)e(unique)g(within)f(the)i
+(\014rst)g(8)h(c)m(haracters.)261 2750 y(The)g(follo)m(wing)f(table)i
+(sho)m(ws)f(the)h(TF)m(ORM)g(column)e(format)i(v)-5 b(alues)31
+b(that)h(are)g(allo)m(w)m(ed)g(in)e(ASCI)s(I)120 2863
+y(tables)g(and)g(in)f(binary)g(tables:)502 3051 y Fc(ASCII)46
+b(Table)h(Column)f(Format)g(Codes)502 3164 y(------------------------)o
+(---)o(----)502 3277 y(\(w)h(=)g(column)g(width,)f(d)h(=)h(no.)e(of)i
+(decimal)d(places)i(to)g(display\))693 3390 y(Aw)142
+b(-)48 b(character)d(string)693 3502 y(Iw)142 b(-)48
+b(integer)693 3615 y(Fw.d)e(-)i(fixed)e(floating)g(point)693
+3728 y(Ew.d)g(-)i(exponential)d(floating)g(point)693
+3841 y(Dw.d)h(-)i(exponential)d(floating)g(point)502
+4067 y(Binary)h(Table)g(Column)g(Format)g(Codes)502 4180
+y(------------------------)o(---)o(----)o(-)502 4293
+y(\(r)h(=)g(vector)g(length,)e(default)h(=)i(1\))693
+4406 y(rA)95 b(-)47 b(character)e(string)693 4519 y(rAw)i(-)g(array)f
+(of)i(strings,)d(each)i(of)g(length)f(w)693 4632 y(rL)95
+b(-)47 b(logical)693 4744 y(rX)95 b(-)47 b(bit)693 4857
+y(rB)95 b(-)47 b(unsigned)f(byte)693 4970 y(rS)95 b(-)47
+b(signed)f(byte)h(**)693 5083 y(rI)95 b(-)47 b(signed)f(16-bit)g
+(integer)693 5196 y(rU)95 b(-)47 b(unsigned)f(16-bit)g(integer)g(**)693
+5309 y(rJ)95 b(-)47 b(signed)f(32-bit)g(integer)693 5422
+y(rV)95 b(-)47 b(unsigned)f(32-bit)g(integer)g(**)693
+5535 y(rK)95 b(-)47 b(64-bit)f(integer)g(***)1905 5809
+y Fg(12)p eop
+%%Page: 13 13
+13 12 bop 693 573 a Fc(rE)95 b(-)47 b(32-bit)f(floating)g(point)693
+686 y(rD)95 b(-)47 b(64-bit)f(floating)g(point)693 799
+y(rC)95 b(-)47 b(32-bit)f(complex)g(pair)693 912 y(rM)95
+b(-)47 b(64-bit)f(complex)g(pair)359 1137 y(**)h(The)g(S,)g(U)g(and)g
+(V)h(format)e(codes)g(are)h(not)g(actual)f(legal)g(TFORMn)h(values.)502
+1250 y(CFITSIO)f(substitutes)e(the)j(somewhat)f(more)g(complicated)f
+(set)i(of)502 1363 y(keywords)e(that)i(are)g(used)g(to)g(represent)e
+(unsigned)h(integers)f(or)502 1476 y(signed)h(bytes.)311
+1702 y(***)h(The)g(64-bit)f(integer)g(format)g(is)h(experimental)d(and)
+j(is)g(not)502 1815 y(officially)e(recognized)g(in)i(the)g(FITS)g
+(Standard.)261 2002 y Fg(The)27 b Fc(tunit)e Fg(and)h
+Fc(extname)f Fg(parameters)j(are)f(optional)f(and)h(ma)m(y)g(b)s(e)g
+(set)g(to)h(NULL)f(if)f(they)h(are)g(not)120 2115 y(needed.)261
+2228 y(Note)41 b(that)f(it)e(ma)m(y)i(b)s(e)f(easier)g(to)h(create)h(a)
+f(new)e(table)h(b)m(y)h(cop)m(ying)f(the)g(header)g(from)g(another)120
+2341 y(existing)29 b(table)i(with)e Fc(fits)p 1089 2341
+29 4 v 33 w(copy)p 1314 2341 V 33 w(header)g Fg(rather)h(than)g
+(calling)f(this)g(routine.)120 2554 y Fc(________________________)o
+(____)o(____)o(___)o(____)o(____)o(___)o(____)o(____)o(___)o(____)o(__)
+120 2667 y(int)47 b(fits_get_num_rows\(fitsfi)o(le)42
+b(*fptr,)k(long)g(*nrows,)g(int)h(*status\))120 2780
+y(int)g(fits_get_num_cols\(fitsfi)o(le)42 b(*fptr,)k(int)94
+b(*ncols,)46 b(int)h(*status\))261 2992 y Fg(Get)37 b(the)g(n)m(um)m(b)
+s(er)d(of)j(ro)m(ws)f(or)g(columns)f(in)f(the)j(curren)m(t)e(FITS)h
+(table.)58 b(The)35 b(n)m(um)m(b)s(er)g(of)h(ro)m(ws)g(is)120
+3105 y(giv)m(en)d(b)m(y)g(the)g Fc(NAXIS2)e Fg(k)m(eyw)m(ord)j(and)e
+(the)h(n)m(um)m(b)s(er)f(of)h(columns)f(is)g(giv)m(en)h(b)m(y)g(the)g
+Fc(TFIELDS)e Fg(k)m(eyw)m(ord)120 3218 y(in)e(the)i(header)f(of)g(the)h
+(table.)120 3430 y Fc(________________________)o(____)o(____)o(___)o
+(____)o(____)o(___)o(____)o(____)o(___)o(____)o(__)120
+3543 y(int)47 b(fits_get_colnum\(fitsfile)41 b(*fptr,)46
+b(int)h(casesen,)f(char)g(*template,)1075 3656 y(int)g(*colnum,)g(int)h
+(*status\))120 3769 y(int)g(fits_get_colname\(fitsfil)o(e)42
+b(*fptr,)k(int)h(casesen,)e(char)i(*template,)1075 3882
+y(char)f(*colname,)f(int)i(*colnum,)f(int)h(*status\))261
+4095 y Fg(Get)33 b(the)e(column)f(n)m(um)m(b)s(er)g(\(starting)i(with)e
+(1,)i(not)g(0\))g(of)f(the)h(column)e(whose)h(name)h(matc)m(hes)g(the)
+120 4208 y(sp)s(eci\014ed)37 b(template)i(name.)66 b(The)38
+b(only)g(di\013erence)g(in)f(these)i(2)g(routines)f(is)f(that)j(the)e
+(2nd)g(one)h(also)120 4320 y(returns)29 b(the)i(name)f(of)h(the)f
+(column)f(that)i(matc)m(hed)h(the)e(template)h(string.)261
+4433 y(Normally)-8 b(,)27 b Fc(casesen)d Fg(should)g(b)s(e)i(set)h(to)g
+Fc(CASEINSEN)p Fg(,)d(but)i(it)f(ma)m(y)i(b)s(e)f(set)h(to)g
+Fc(CASESEN)d Fg(to)j(force)g(the)120 4546 y(name)j(matc)m(hing)h(to)g
+(b)s(e)f(case-sensitiv)m(e.)261 4659 y(The)22 b(input)e
+Fc(template)g Fg(string)h(giv)m(es)i(the)f(name)h(of)f(the)h(desired)d
+(column)h(and)h(ma)m(y)h(include)d(wildcard)120 4772
+y(c)m(haracters:)41 b(a)30 b(`*')g(matc)m(hes)g(an)m(y)f(sequence)g(of)
+h(c)m(haracters)g(\(including)c(zero)k(c)m(haracters\),)h(`?')40
+b(matc)m(hes)120 4885 y(an)m(y)45 b(single)e(c)m(haracter,)50
+b(and)44 b(`#')h(matc)m(hes)g(an)m(y)g(consecutiv)m(e)h(string)d(of)i
+(decimal)f(digits)f(\(0-9\).)85 b(If)120 4998 y(more)27
+b(than)g(one)g(column)f(name)h(in)f(the)h(table)g(matc)m(hes)h(the)f
+(template)g(string,)g(then)g(the)g(\014rst)f(matc)m(h)i(is)120
+5111 y(returned)22 b(and)h(the)h(status)f(v)-5 b(alue)23
+b(will)e(b)s(e)i(set)h(to)g Fc(COL)p 1962 5111 V 33 w(NOT)p
+2139 5111 V 34 w(UNIQUE)e Fg(as)h(a)h(w)m(arning)e(that)i(a)g(unique)d
+(matc)m(h)120 5224 y(w)m(as)34 b(not)g(found.)50 b(T)-8
+b(o)35 b(\014nd)d(the)i(next)g(column)f(that)i(matc)m(hes)g(the)f
+(template,)h(call)f(this)e(routine)h(again)120 5337 y(lea)m(ving)d(the)
+h(input)d(status)j(v)-5 b(alue)30 b(equal)g(to)h Fc(COL)p
+1832 5337 V 33 w(NOT)p 2009 5337 V 34 w(UNIQUE)p Fg(.)e(Rep)s(eat)i
+(this)e(pro)s(cess)h(un)m(til)f Fc(status)46 b(=)120
+5450 y(COL)p 270 5450 V 34 w(NOT)p 448 5450 V 33 w(FOUND)29
+b Fg(is)g(returned.)1905 5809 y(13)p eop
+%%Page: 14 14
+14 13 bop 120 573 a Fc(________________________)o(____)o(____)o(___)o
+(____)o(____)o(___)o(____)o(____)o(___)o(____)o(__)120
+686 y(int)47 b(fits_get_coltype\(fitsfil)o(e)42 b(*fptr,)k(int)h
+(colnum,)f(int)h(*typecode,)1122 799 y(long)g(*repeat,)e(long)i
+(*width,)f(int)h(*status\))261 1011 y Fg(Return)41 b(the)h(datat)m(yp)s
+(e,)k(v)m(ector)d(rep)s(eat)f(coun)m(t,)j(and)c(the)h(width)e(in)g(b)m
+(ytes)i(of)g(a)g(single)f(column)120 1124 y(elemen)m(t)i(for)e(column)g
+(n)m(um)m(b)s(er)g Fc(colnum)p Fg(.)74 b(Allo)m(w)m(ed)42
+b(v)-5 b(alues)41 b(for)h(the)g(returned)f(datat)m(yp)s(e)i(in)e(ASCI)s
+(I)120 1237 y(tables)30 b(are:)42 b Fc(TSTRING,)j(TSHORT,)h(TLONG,)g
+(TFLOAT,)g(and)h(TDOUBLE)p Fg(.)29 b(Binary)h(tables)g(supp)s(ort)f
+(these)120 1350 y(additional)19 b(t)m(yp)s(es:)36 b Fc(TLOGICAL,)45
+b(TBIT,)h(TBYTE,)g(TINT32BIT,)f(TCOMPLEX)h(and)h(TDBLCOMPLEX)p
+Fg(.)18 b(The)120 1463 y(negativ)m(e)34 b(of)f(the)h(datat)m(yp)s(e)g
+(co)s(de)f(v)-5 b(alue)32 b(is)h(returned)e(if)h(it)h(is)f(a)h(v)-5
+b(ariable)32 b(length)h(arra)m(y)g(column.)48 b(The)120
+1576 y(rep)s(eat)31 b(coun)m(t)g(is)e(alw)m(a)m(ys)i(1)g(in)e(ASCI)s(I)
+g(tables.)261 1689 y(The)39 b('rep)s(eat')g(parameter)h(returns)e(the)h
+(v)m(ector)h(rep)s(eat)g(coun)m(t)f(on)g(the)g(binary)f(table)g(TF)m
+(ORMn)120 1802 y(k)m(eyw)m(ord)44 b(v)-5 b(alue.)78 b(\(ASCI)s(I)42
+b(table)h(columns)f(alw)m(a)m(ys)i(ha)m(v)m(e)g(rep)s(eat)g(=)e(1\).)80
+b(The)43 b('width')f(parameter)120 1914 y(returns)d(the)i(width)e(in)h
+(b)m(ytes)h(of)g(a)g(single)e(column)h(elemen)m(t)h(\(e.g.,)k(a)c
+('10D')i(binary)c(table)i(column)120 2027 y(will)c(ha)m(v)m(e)42
+b(width)c(=)i(8,)j(an)d(ASCI)s(I)e(table)i('F12.2')j(column)c(will)e
+(ha)m(v)m(e)42 b(width)c(=)i(12,)j(and)d(a)g(binary)120
+2140 y(table'60A')26 b(c)m(haracter)h(string)c(column)h(will)e(ha)m(v)m
+(e)k(width)d(=)h(60\);)k(Note)f(that)e(this)f(routine)f(supp)s(orts)g
+(the)120 2253 y(lo)s(cal)31 b(con)m(v)m(en)m(tion)j(for)e(sp)s
+(ecifying)e(arra)m(ys)i(of)h(\014xed)e(length)h(strings)f(within)f(a)i
+(binary)f(table)h(c)m(haracter)120 2366 y(column)37 b(using)f(the)j
+(syn)m(tax)f(TF)m(ORM)h(=)e('rAw')h(where)g('r')g(is)f(the)h(total)h(n)
+m(um)m(b)s(er)e(of)h(c)m(haracters)h(\(=)120 2479 y(the)d(width)d(of)j
+(the)f(column\))g(and)f('w')i(is)e(the)i(width)d(of)j(a)f(unit)f
+(string)g(within)f(the)j(column.)54 b(Th)m(us)34 b(if)120
+2592 y(the)i(column)f(has)h(TF)m(ORM)g(=)g('60A12')j(then)c(this)g
+(means)h(that)h(eac)m(h)g(ro)m(w)f(of)h(the)f(table)g(con)m(tains)g(5)
+120 2705 y(12-c)m(haracter)h(substrings)31 b(within)h(the)i(60-c)m
+(haracter)j(\014eld,)d(and)f(th)m(us)h(in)e(this)h(case)i(this)e
+(routine)g(will)120 2818 y(return)25 b(t)m(yp)s(eco)s(de)i(=)f
+(TSTRING,)f(rep)s(eat)i(=)e(60,)k(and)c(width)g(=)h(12.)40
+b(The)25 b(n)m(um)m(b)s(er)g(of)i(substings)d(in)h(an)m(y)120
+2931 y(binary)31 b(table)h(c)m(haracter)i(string)e(\014eld)f(can)i(b)s
+(e)f(calculated)h(b)m(y)f(\(rep)s(eat/width\).)47 b(A)33
+b(n)m(ull)d(p)s(oin)m(ter)i(ma)m(y)120 3044 y(b)s(e)e(giv)m(en)g(for)g
+(an)m(y)h(of)g(the)f(output)g(parameters)h(that)g(are)f(not)h(needed.)
+120 3256 y Fc(________________________)o(____)o(____)o(___)o(____)o
+(____)o(___)o(____)o(____)o(___)o(____)o(____)o(___)o(____)o(____)120
+3369 y(int)47 b(fits_insert_rows\(fitsfil)o(e)42 b(*fptr,)k(long)h
+(firstrow,)e(long)h(nrows,)h(int)f(*status\))120 3482
+y(int)h(fits_delete_rows\(fitsfil)o(e)42 b(*fptr,)k(long)h(firstrow,)e
+(long)h(nrows,)h(int)f(*status\))120 3595 y(int)h
+(fits_delete_rowrange\(fit)o(sfil)o(e)42 b(*fptr,)k(char)g(*rangelist,)
+f(int)i(*status\))120 3708 y(int)g(fits_delete_rowlist\(fits)o(file)41
+b(*fptr,)46 b(long)h(*rowlist,)e(long)i(nrows,)f(int)h(*stat\))261
+3920 y Fg(Insert)33 b(or)g(delete)g(ro)m(ws)g(in)e(a)j(table.)48
+b(The)33 b(blank)e(ro)m(ws)i(are)h(inserted)d(immediately)h(follo)m
+(wing)f(ro)m(w)120 4033 y Fc(frow)p Fg(.)54 b(Set)35
+b Fc(frow)f Fg(=)g(0)i(to)f(insert)f(ro)m(ws)h(at)h(the)f(b)s(eginning)
+e(of)i(the)g(table.)55 b(The)34 b(\014rst)h('delete')g(routine)120
+4146 y(deletes)k Fc(nrows)e Fg(ro)m(ws)i(b)s(eginning)d(with)i(ro)m(w)h
+Fc(firstrow)p Fg(.)64 b(The)38 b(2nd)g(delete)h(routine)f(tak)m(es)j
+(an)d(input)120 4259 y(string)26 b(listing)f(the)i(ro)m(ws)f(or)h(ro)m
+(w)g(ranges)g(to)h(b)s(e)e(deleted)h(\(e.g.,)i('2,4-7,)h(9-12'\).)42
+b(The)26 b(last)h(delete)g(routine)120 4372 y(tak)m(es)35
+b(an)f(input)d(long)i(in)m(teger)h(arra)m(y)h(that)f(sp)s(eci\014es)e
+(eac)m(h)j(individual)29 b(ro)m(w)34 b(to)g(b)s(e)f(deleted.)50
+b(The)33 b(ro)m(w)120 4485 y(lists)h(m)m(ust)h(b)s(e)f(sorted)i(in)e
+(ascending)g(order.)55 b(All)34 b(these)i(routines)e(up)s(date)g(the)i
+(v)-5 b(alue)34 b(of)i(the)f Fc(NAXIS2)120 4598 y Fg(k)m(eyw)m(ord)c
+(to)g(re\015ect)g(the)f(new)g(n)m(um)m(b)s(er)f(of)i(ro)m(ws)f(in)f
+(the)i(table.)120 4810 y Fc(________________________)o(____)o(____)o
+(___)o(____)o(____)o(___)o(____)o(____)o(___)o(____)o(____)o(___)o
+(____)o(_)120 4923 y(int)47 b(fits_insert_col\(fitsfile)41
+b(*fptr,)46 b(int)h(colnum,)f(char)h(*ttype,)e(char)i(*tform,)1075
+5036 y(int)f(*status\))120 5149 y(int)h(fits_insert_cols\(fitsfil)o(e)
+42 b(*fptr,)k(int)h(colnum,)f(int)h(ncols,)f(char)g(**ttype,)1122
+5262 y(char)h(**tform,)e(int)i(*status\))120 5488 y(int)g
+(fits_delete_col\(fitsfile)41 b(*fptr,)46 b(int)h(colnum,)f(int)h
+(*status\))1905 5809 y Fg(14)p eop
+%%Page: 15 15
+15 14 bop 261 573 a Fg(Insert)25 b(or)g(delete)g(columns)f(in)f(a)j
+(table.)38 b Fc(colnum)24 b Fg(giv)m(es)h(the)g(p)s(osition)e(of)i(the)
+h(column)d(to)j(b)s(e)f(inserted)120 686 y(or)34 b(deleted)f(\(where)h
+(the)g(\014rst)f(column)g(of)h(the)g(table)g(is)e(at)j(p)s(osition)d
+(1\).)52 b Fc(ttype)32 b Fg(and)h Fc(tform)g Fg(giv)m(e)h(the)120
+799 y(column)j(name)i(and)f(column)f(format,)k(where)d(the)h(allo)m(w)m
+(ed)g(format)f(co)s(des)h(are)g(listed)e(ab)s(o)m(v)m(e)j(in)d(the)120
+912 y(description)43 b(of)i(the)h Fc(fits)p 1088 912
+29 4 v 33 w(create)p 1409 912 V 33 w(table)d Fg(routine.)84
+b(The)45 b(2nd)f('insert')h(routine)f(inserts)g(m)m(ultiple)120
+1024 y(columns,)32 b(where)h Fc(ncols)e Fg(is)h(the)h(n)m(um)m(b)s(er)e
+(of)i(columns)f(to)h(insert,)g(and)f Fc(ttype)f Fg(and)h
+Fc(tform)g Fg(are)h(arra)m(ys)120 1137 y(of)e(string)e(p)s(oin)m(ters)g
+(in)g(this)g(case.)120 1312 y Fc(________________________)o(____)o
+(____)o(___)o(____)o(____)o(___)o(____)o(____)o(___)o(____)o(____)o
+(___)120 1425 y(int)47 b(fits_copy_col\(fitsfile)42 b(*infptr,)j
+(fitsfile)h(*outfptr,)f(int)i(incolnum,)502 1537 y(int)g(outcolnum,)e
+(int)i(create_col,)d(int)j(*status\);)261 1712 y Fg(Cop)m(y)31
+b(a)g(column)f(from)g(one)i(table)e(HDU)i(to)g(another.)42
+b(If)31 b Fc(create)p 2609 1712 V 32 w(col)f Fg(=)h(TR)m(UE)g(\(i.e.,)h
+(not)f(equal)120 1825 y(to)42 b(zero\),)k(then)41 b(a)h(new)f(column)f
+(will)f(b)s(e)i(inserted)f(in)h(the)g(output)g(table)h(at)g(p)s
+(osition)e Fc(outcolumn)p Fg(,)120 1937 y(otherwise)30
+b(the)g(v)-5 b(alues)30 b(in)f(the)i(existing)e(output)h(column)f(will)
+f(b)s(e)i(o)m(v)m(erwritten.)120 2112 y Fc(________________________)o
+(____)o(____)o(___)o(____)o(____)o(___)o(____)o(____)o(___)o(____)o
+(____)o(___)o(____)o(__)120 2225 y(int)47 b(fits_write_col\(fitsfile)41
+b(*fptr,)46 b(int)h(datatype,)f(int)h(colnum,)e(long)i(firstrow,)979
+2337 y(long)g(firstelem,)e(long)h(nelements,)f(void)i(*array,)f(int)h
+(*status\))120 2450 y(int)g(fits_write_colnull\(fitsf)o(ile)41
+b(*fptr,)46 b(int)h(datatype,)f(int)g(colnum,)979 2563
+y(long)h(firstrow,)e(long)i(firstelem,)e(long)h(nelements,)979
+2676 y(void)h(*array,)f(void)g(*nulval,)g(int)h(*status\))120
+2789 y(int)g(fits_write_col_null\(fits)o(file)41 b(*fptr,)46
+b(int)h(colnum,)f(long)g(firstrow,)979 2902 y(long)h(firstelem,)e(long)
+h(nelements,)f(int)i(*status\))120 3128 y(int)g
+(fits_read_col\(fitsfile)42 b(*fptr,)k(int)h(datatype,)e(int)i(colnum,)
+f(long)g(firstrow,)454 3241 y(long)h(firstelem,)e(long)h(nelements,)f
+(void)i(*nulval,)f(void)g(*array,)454 3354 y(int)h(*anynul,)f(int)g
+(*status\))261 3641 y Fg(W)-8 b(rite)44 b(or)f(read)g(elemen)m(ts)h(in)
+e(column)g(n)m(um)m(b)s(er)g Fc(colnum)p Fg(,)j(starting)e(with)f(ro)m
+(w)h Fc(firstsrow)e Fg(and)120 3754 y(elemen)m(t)33 b
+Fc(firstelem)d Fg(\(if)i(it)g(is)g(a)h(v)m(ector)h(column\).)46
+b Fc(firstelem)30 b Fg(is)i(ignored)g(if)f(it)h(is)g(a)h(scalar)f
+(column.)120 3867 y(The)d Fc(nelements)f Fg(n)m(um)m(b)s(er)g(of)i
+(elemen)m(ts)h(are)f(read)g(or)f(written)g(con)m(tin)m(uing)g(on)h
+(successiv)m(e)g(ro)m(ws)g(of)g(the)120 3980 y(table)36
+b(if)f(necessary)-8 b(.)59 b Fc(array)35 b Fg(is)g(the)i(address)e(of)h
+(an)g(arra)m(y)h(whic)m(h)e(either)h(con)m(tains)g(the)h(v)-5
+b(alues)35 b(to)i(b)s(e)120 4092 y(written,)27 b(or)f(will)e(hold)i
+(the)g(returned)g(v)-5 b(alues)26 b(that)h(are)g(read.)39
+b(When)27 b(reading,)g Fc(array)e Fg(m)m(ust)h(ha)m(v)m(e)i(b)s(een)120
+4205 y(allo)s(cated)i(large)h(enough)f(to)h(hold)e(all)g(the)i
+(returned)e(v)-5 b(alues.)261 4318 y(There)40 b(are)h(3)h(di\013eren)m
+(t)e('write')g(column)g(routines:)60 b(The)40 b(\014rst)g(simply)e
+(writes)i(the)h(input)e(arra)m(y)120 4431 y(in)m(to)32
+b(the)g(column.)43 b(The)31 b(second)h(is)f(similar,)e(except)k(that)f
+(it)f(substitutes)g(the)h(appropriate)e(n)m(ull)g(pixel)120
+4544 y(v)-5 b(alue)35 b(in)e(the)j(column)d(for)i(an)m(y)h(input)d
+(arra)m(y)i(v)-5 b(alues)35 b(whic)m(h)f(are)h(equal)g(to)h
+Fc(*nulval)d Fg(\(note)j(that)f(this)120 4657 y(parameter)k(giv)m(es)f
+(the)h(address)e(of)i(the)f(n)m(ull)e(pixel)h(v)-5 b(alue,)40
+b(not)e(the)h(v)-5 b(alue)37 b(itself)7 b(\).)64 b(The)38
+b(third)e(write)120 4770 y(routine)27 b(sets)h(the)g(sp)s(eci\014ed)e
+(table)i(elemen)m(ts)g(to)h(a)f(n)m(ull)e(v)-5 b(alue.)39
+b(New)28 b(ro)m(ws)g(will)d(b)s(e)j(automatical)g(added)120
+4883 y(to)j(the)g(table)f(if)f(the)i(write)e(op)s(eration)h(extends)h
+(b)s(ey)m(ond)e(the)i(curren)m(t)f(size)g(of)h(the)f(table.)261
+4996 y(When)42 b(reading)f(a)i(column,)h(CFITSIO)c(will)g(substitute)h
+(the)h(v)-5 b(alue)42 b(giv)m(en)g(b)m(y)g Fc(nulval)e
+Fg(for)i(an)m(y)120 5109 y(unde\014ned)25 b(elemen)m(ts)i(in)f(the)h
+(FITS)f(column,)h(unless)e Fc(nulval)g Fg(or)i Fc(*nulval)46
+b(=)h(NULL)p Fg(,)26 b(in)g(whic)m(h)f(case)j(no)120
+5222 y(c)m(hec)m(ks)k(will)c(b)s(e)h(made)i(for)f(unde\014ned)e(v)-5
+b(alues)30 b(when)f(reading)h(the)g(column.)261 5334
+y Fc(datatype)i Fg(sp)s(eci\014es)h(the)h(datat)m(yp)s(e)h(of)g(the)f
+(C)g Fc(array)e Fg(in)h(the)h(program,)i(whic)m(h)c(need)i(not)h(b)s(e)
+e(the)120 5447 y(same)42 b(as)f(the)g(in)m(trinsic)e(datat)m(yp)s(e)j
+(of)f(the)h(column)e(in)g(the)h(FITS)g(table.)73 b(The)40
+b(follo)m(wing)g(sym)m(b)s(olic)120 5560 y(constan)m(ts)32
+b(are)e(allo)m(w)m(ed)h(for)f(the)g(v)-5 b(alue)30 b(of)h
+Fc(datatype)p Fg(:)1905 5809 y(15)p eop
+%%Page: 16 16
+16 15 bop 215 573 a Fc(TSTRING)142 b(array)46 b(of)h(character)f
+(string)g(pointers)215 686 y(TBYTE)238 b(unsigned)45
+b(char)215 799 y(TSHORT)190 b(signed)46 b(short)215 912
+y(TUSHORT)142 b(unsigned)45 b(short)215 1024 y(TINT)286
+b(signed)46 b(int)215 1137 y(TUINT)238 b(unsigned)45
+b(int)215 1250 y(TLONG)238 b(signed)46 b(long)215 1363
+y(TULONG)190 b(unsigned)45 b(long)215 1476 y(TFLOAT)190
+b(float)215 1589 y(TDOUBLE)142 b(double)261 1791 y Fg(Note)35
+b(that)e Fc(TSTRING)f Fg(corresp)s(onds)g(to)h(the)h(C)f
+Fc(char**)e Fg(datat)m(yp)s(e,)k(i.e.,)g(a)e(p)s(oin)m(ter)f(to)i(an)f
+(arra)m(y)h(of)120 1904 y(p)s(oin)m(ters)29 b(to)i(an)g(arra)m(y)f(of)h
+(c)m(haracters.)261 2017 y(An)m(y)38 b(column,)i(regardless)d(of)i
+(it's)f(in)m(trinsic)d(datat)m(yp)s(e,)42 b(ma)m(y)d(b)s(e)e(read)h(as)
+h(a)f Fc(TSTRING)f Fg(c)m(haracter)120 2130 y(string.)h(The)24
+b(displa)m(y)g(format)h(of)g(the)h(returned)e(strings)f(will)g(b)s(e)h
+(determined)g(b)m(y)h(the)g Fc(TDISPn)f Fg(k)m(eyw)m(ord,)120
+2243 y(if)i(it)h(exists,)h(otherwise)f(a)g(default)g(format)h(will)c(b)
+s(e)j(used)f(dep)s(ending)f(on)j(the)f(datat)m(yp)s(e)h(of)g(the)f
+(column.)120 2356 y(The)22 b Fc(tablist)e Fg(example)i(utilit)m(y)f
+(program)h(\(a)m(v)-5 b(ailable)22 b(from)g(the)h(CFITSIO)e(w)m(eb)h
+(site\))h(uses)f(this)f(feature)120 2469 y(to)31 b(displa)m(y)e(all)g
+(the)i(v)-5 b(alues)29 b(in)g(a)i(FITS)f(table.)120 2671
+y Fc(________________________)o(____)o(____)o(___)o(____)o(____)o(___)o
+(____)o(____)o(___)o(____)o(____)o(___)o(_)120 2784 y(int)47
+b(fits_select_rows\(fitsfil)o(e)42 b(*infptr,)j(fitsfile)h(*outfptr,)f
+(char)i(*expr,)1122 2897 y(int)g(*status\))120 3010 y(int)g
+(fits_calculator\(fitsfile)41 b(*infptr,)46 b(char)g(*expr,)g(fitsfile)
+g(*outfptr,)1075 3123 y(char)g(*colname,)f(char)i(*tform,)f(int)h
+(*status\))261 3325 y Fg(These)26 b(are)h(2)g(of)g(the)f(most)h(p)s(o)m
+(w)m(erful)e(routines)h(in)f(the)i(CFITSIO)d(library)-8
+b(.)38 b(\(See)27 b(the)g(full)d(CFITSIO)120 3438 y(Reference)37
+b(Guide)e(for)h(a)h(description)d(of)i(sev)m(eral)h(related)f
+(routines\).)57 b(These)36 b(routines)f(can)i(p)s(erform)120
+3551 y(complicated)45 b(transformations)g(on)g(tables)g(based)g(on)g
+(an)g(input)f(arithmetic)g(expression)g(whic)m(h)g(is)120
+3664 y(ev)-5 b(aluated)37 b(for)f(eac)m(h)h(ro)m(w)g(of)g(the)f(table.)
+59 b(The)36 b(\014rst)g(routine)f(will)f(select)j(or)g(cop)m(y)g(ro)m
+(ws)f(of)h(the)f(table)120 3777 y(for)i(whic)m(h)f(the)h(expression)f
+(ev)-5 b(aluates)39 b(to)g(TR)m(UE)g(\(i.e.,)h(not)f(equal)f(to)h
+(zero\).)65 b(The)38 b(second)g(routine)120 3890 y(writes)c(the)h(v)-5
+b(alue)34 b(of)h(the)g(expression)f(to)i(a)f(column)f(in)f(the)i
+(output)g(table.)54 b(Rather)35 b(than)g(supplying)120
+4003 y(the)j(expression)e(directly)g(to)i(these)g(routines,)h(the)e
+(expression)g(ma)m(y)h(also)f(b)s(e)g(written)g(to)h(a)g(text)g(\014le)
+120 4116 y(\(con)m(tin)m(ued)e(o)m(v)m(er)g(m)m(ultiple)e(lines)f(if)i
+(necessary\))h(and)f(the)h(name)f(of)h(the)g(\014le,)g(prep)s(ended)d
+(with)h(a)i('@')120 4229 y(c)m(haracter,)c(ma)m(y)f(b)s(e)f(supplied)d
+(as)k(the)f(v)-5 b(alue)30 b(of)h(the)f('expr')g(parameter)h(\(e.g.)42
+b('@\014lename.txt'\).)261 4342 y(The)26 b(arithmetic)f(expression)g
+(ma)m(y)i(b)s(e)f(a)g(function)f(of)h(an)m(y)h(column)e(or)h(k)m(eyw)m
+(ord)h(in)e(the)h(input)e(table)120 4455 y(as)31 b(sho)m(wn)e(in)g
+(these)i(examples:)120 4657 y Fc(Row)47 b(Selection)e(Expressions:)263
+4770 y(counts)h(>)i(0)1240 b(uses)47 b(COUNTS)f(column)g(value)263
+4883 y(sqrt\()h(X**2)f(+)i(Y**2\))e(<)h(10.)572 b(uses)47
+b(X)g(and)g(Y)h(column)e(values)263 4996 y(\(X)h(>)h(10\))f(||)g(\(X)g
+(<)h(-10\))e(&&)h(\(Y)h(==)f(0\))142 b(used)47 b('or')g(and)g('and')f
+(operators)263 5109 y(gtifilter\(\))1190 b(filter)46
+b(on)i(Good)e(Time)h(Intervals)263 5222 y(regfilter\("myregion.reg"\))
+518 b(filter)46 b(using)h(a)g(region)f(file)263 5334
+y(@select.txt)1190 b(reads)47 b(expression)e(from)h(a)i(text)e(file)120
+5447 y(Calculator)f(Expressions:)263 5560 y(#row)i(\045)g(10)1145
+b(modulus)46 b(of)h(the)g(row)g(number)1905 5809 y Fg(16)p
+eop
+%%Page: 17 17
+17 16 bop 263 573 a Fc(counts/#exposure)807 b(Fn)47 b(of)h(COUNTS)e
+(column)g(and)h(EXPOSURE)e(keyword)263 686 y(dec)i(<)h(85)f(?)g
+(cos\(dec)f(*)h(#deg\))g(:)g(0)143 b(Conditional)45 b(expression:)g
+(evaluates)g(to)1934 799 y(cos\(dec\))g(if)i(dec)g(<)h(85,)f(else)f(0)
+263 912 y(\(count{-1}+count+count{+1)o(}\)/3)o(.)137
+b(running)46 b(mean)h(of)g(the)g(count)f(values)g(in)h(the)1934
+1024 y(previous,)e(current,)g(and)i(next)g(rows)263 1137
+y(max\(0,)f(min\(X,)g(1000\)\))619 b(returns)46 b(a)h(value)g(between)f
+(0)h(-)h(1000)263 1250 y(@calc.txt)1143 b(reads)47 b(expression)e(from)
+h(a)i(text)e(file)261 1463 y Fg(Most)40 b(standard)d(mathematical)i(op)
+s(erators)g(and)f(functions)f(are)i(supp)s(orted.)64
+b(If)38 b(the)h(expression)120 1576 y(includes)32 b(the)j(name)f(of)h
+(a)f(column,)h(than)f(the)h(v)-5 b(alue)34 b(in)f(the)h(curren)m(t)h
+(ro)m(w)f(of)h(the)f(table)h(will)c(b)s(e)j(used)120
+1689 y(when)f(ev)-5 b(aluating)33 b(the)h(expression)f(on)h(eac)m(h)h
+(ro)m(w.)51 b(An)34 b(o\013set)h(to)g(an)e(adjacen)m(t)j(ro)m(w)e(can)g
+(b)s(e)f(sp)s(eci\014ed)120 1802 y(b)m(y)d(including)d(the)j(o\013set)h
+(v)-5 b(alue)29 b(in)g(curly)g(brac)m(k)m(ets)i(after)g(the)f(column)f
+(name)h(as)g(sho)m(wn)g(in)f(one)h(of)g(the)120 1914
+y(examples.)39 b(Keyw)m(ord)27 b(v)-5 b(alues)27 b(can)g(b)s(e)g
+(included)d(in)i(the)i(expression)e(b)m(y)h(preceding)f(the)i(k)m(eyw)m
+(ord)f(name)120 2027 y(with)g(a)i(`#')f(sign.)39 b(See)28
+b(Section)h(5)f(of)h(this)e(do)s(cumen)m(t)h(for)g(more)g(discussion)e
+(of)i(the)h(expression)e(syn)m(tax.)261 2140 y Fc(gtifilter)i
+Fg(is)h(a)i(sp)s(ecial)e(function)g(whic)m(h)g(tests)i(whether)f(the)h
+Fc(TIME)e Fg(column)g(v)-5 b(alue)31 b(in)f(the)h(input)120
+2253 y(table)38 b(falls)f(within)f(one)j(or)f(more)h(Go)s(o)s(d)f(Time)
+f(In)m(terv)-5 b(als.)65 b(By)39 b(default,)g(this)f(function)f(lo)s
+(oks)h(for)g(a)120 2366 y('GTI')27 b(extension)f(in)f(the)i(same)g
+(\014le)e(as)i(the)g(input)d(table.)40 b(The)26 b('GTI')g(table)h(con)m
+(tains)g Fc(START)e Fg(and)h Fc(STOP)120 2479 y Fg(columns)f(whic)m(h)h
+(de\014ne)g(the)g(range)h(of)g(eac)m(h)h(go)s(o)s(d)f(time)f(in)m(terv)
+-5 b(al.)39 b(See)27 b(section)f(5.4.3)j(for)d(more)h(details.)261
+2592 y Fc(regfilter)35 b Fg(is)h(another)h(sp)s(ecial)f(function)g
+(whic)m(h)g(selects)h(ro)m(ws)h(based)e(on)h(whether)g(the)g(spatial)
+120 2705 y(p)s(osition)21 b(asso)s(ciated)j(with)e(eac)m(h)j(ro)m(w)e
+(is)f(lo)s(cated)i(within)d(in)h(a)h(sp)s(eci\014ed)f(region)h(of)g
+(the)h(sky)-8 b(.)38 b(By)24 b(default,)120 2818 y(the)35
+b Fc(X)g Fg(and)f Fc(Y)h Fg(columns)f(in)g(the)h(input)e(table)i(are)g
+(assumed)g(to)h(giv)m(e)f(the)g(p)s(osition)e(of)j(eac)m(h)g(ro)m(w.)55
+b(The)120 2931 y(spatial)35 b(region)g(is)f(de\014ned)h(in)f(an)h(ASCI)
+s(I)f(text)j(\014le)d(whose)i(name)f(is)g(giv)m(en)g(as)h(the)g
+(argumen)m(t)g(to)g(the)120 3044 y Fc(regfilter)28 b
+Fg(function.)39 b(See)31 b(section)f(5.4.4)j(for)d(more)g(details.)261
+3156 y(The)e Fc(infptr)e Fg(and)i Fc(outfptr)e Fg(parameters)j(in)e
+(these)h(routines)f(ma)m(y)i(p)s(oin)m(t)e(to)i(the)g(same)f(table)g
+(or)h(to)120 3269 y(di\013eren)m(t)h(tables.)42 b(In)31
+b Fc(fits)p 1092 3269 29 4 v 33 w(select)p 1413 3269
+V 33 w(rows)p Fg(,)f(if)f(the)j(input)c(and)j(output)f(tables)h(are)g
+(the)g(same)h(then)e(the)120 3382 y(ro)m(ws)e(that)h(do)f(not)g
+(satisfy)g(the)g(selection)g(expression)f(will)e(b)s(e)i(deleted)h
+(from)g(the)g(table.)40 b(Otherwise,)27 b(if)120 3495
+y(the)k(output)g(table)g(is)f(di\013eren)m(t)h(from)g(the)g(input)e
+(table)i(then)g(the)g(selected)h(ro)m(ws)f(will)e(b)s(e)h(copied)h
+(from)120 3608 y(the)g(input)d(table)i(to)h(the)g(output)f(table.)261
+3721 y(The)i(output)g(column)f(in)g Fc(fits)p 1376 3721
+V 33 w(calculator)f Fg(ma)m(y)i(or)h(ma)m(y)g(not)f(already)g(exist.)46
+b(If)32 b(it)g(exists)g(then)120 3834 y(the)44 b(calculated)f(v)-5
+b(alues)43 b(will)e(b)s(e)i(written)g(to)h(that)h(column,)h(o)m(v)m
+(erwriting)d(the)g(existing)g(v)-5 b(alues.)80 b(If)120
+3947 y(the)36 b(column)f(do)s(esn't)h(exist)f(then)h(the)g(new)g
+(column)e(will)g(b)s(e)h(app)s(ended)f(to)j(the)f(output)g(table.)57
+b(The)120 4060 y Fc(tform)37 b Fg(parameter)i(can)f(b)s(e)g(used)g(to)h
+(sp)s(ecify)e(the)h(datat)m(yp)s(e)i(of)e(the)h(new)f(column)f(\(e.g.,)
+42 b(the)d Fc(TFORM)120 4173 y Fg(k)m(eyw)m(ord)26 b(v)-5
+b(alue)25 b(as)h(in)f Fc('1E',)46 b(or)h('1J')p Fg(\).)25
+b(If)h Fc(tform)e Fg(=)h(NULL)h(then)f(a)h(default)f(datat)m(yp)s(e)i
+(will)c(b)s(e)i(used,)120 4286 y(dep)s(ending)j(on)i(the)h(expression.)
+120 4498 y Fc(________________________)o(____)o(____)o(___)o(____)o
+(____)o(___)o(____)o(____)o(___)o(____)o(____)o(___)o(_)120
+4611 y(int)47 b(fits_read_tblbytes\(fitsf)o(ile)41 b(*fptr,)46
+b(long)h(firstrow,)e(long)i(firstchar,)1122 4724 y(long)g(nchars,)f
+(unsigned)f(char)i(*array,)f(int)h(*status\))120 4837
+y(int)g(fits_write_tblbytes)42 b(\(fitsfile)k(*fptr,)g(long)g
+(firstrow,)g(long)g(firstchar,)1122 4950 y(long)h(nchars,)f(unsigned)f
+(char)i(*array,)f(int)h(*status\))261 5162 y Fg(These)35
+b(2)g(routines)e(pro)m(vide)h(lo)m(w-lev)m(el)h(access)h(to)f(tables)g
+(and)f(are)h(mainly)e(useful)g(as)i(an)g(e\016cien)m(t)120
+5275 y(w)m(a)m(y)i(to)g(cop)m(y)g(ro)m(ws)f(of)g(a)h(table)f(from)g
+(one)g(\014le)f(to)i(another.)58 b(These)36 b(routines)f(simply)f(read)
+i(or)g(write)120 5388 y(the)30 b(sp)s(eci\014ed)f(n)m(um)m(b)s(er)g(of)
+h(consecutiv)m(e)i(c)m(haracters)f(\(b)m(ytes\))h(in)d(a)i(table,)f
+(without)f(regard)h(for)h(column)120 5501 y(b)s(oundaries.)83
+b(F)-8 b(or)47 b(example,)i(to)d(read)f(or)h(write)e(the)i(\014rst)f
+(ro)m(w)g(of)h(a)g(table,)j(set)d Fc(firstrow)g(=)h(1,)1905
+5809 y Fg(17)p eop
+%%Page: 18 18
+18 17 bop 120 573 a Fc(firstchar)45 b(=)j(1)p Fg(,)38
+b(and)e Fc(nchars)46 b(=)i(NAXIS1)35 b Fg(where)h(the)h(length)f(of)h
+(a)h(ro)m(w)f(is)e(giv)m(en)i(b)m(y)g(the)g(v)-5 b(alue)36
+b(of)120 686 y(the)31 b Fc(NAXIS1)f Fg(header)h(k)m(eyw)m(ord.)43
+b(When)31 b(reading)g(a)g(table,)h Fc(array)e Fg(m)m(ust)h(ha)m(v)m(e)h
+(b)s(een)f(declared)f(at)i(least)120 799 y Fc(nchars)d
+Fg(b)m(ytes)i(long)f(to)h(hold)e(the)h(returned)f(string)h(of)g(b)m
+(ytes.)1905 5809 y(18)p eop
+%%Page: 19 19
+19 18 bop 120 573 a Fb(4.6)112 b(Header)38 b(Keyw)m(ord)f(I/O)h
+(Routines)120 744 y Fg(The)30 b(follo)m(wing)f(routines)g(read)h(and)g
+(write)g(header)g(k)m(eyw)m(ords)g(in)g(the)g(curren)m(t)g(HDU.)120
+957 y Fc(________________________)o(____)o(____)o(___)o(____)o(____)o
+(___)o(____)o(____)o(___)o(____)o(____)o(___)120 1070
+y(int)47 b(fits_get_hdrspace\(fitsfi)o(le)42 b(*fptr,)k(int)h
+(*keysexist,)d(int)j(*morekeys,)1170 1183 y(int)g(*status\))120
+1395 y Fg(Return)36 b(the)g(n)m(um)m(b)s(er)f(of)i(existing)e(k)m(eyw)m
+(ords)i(\(not)g(coun)m(ting)f(the)h(mandatory)f(END)h(k)m(eyw)m(ord\))g
+(and)120 1508 y(the)29 b(amoun)m(t)h(of)f(empt)m(y)h(space)g(curren)m
+(tly)e(a)m(v)-5 b(ailable)28 b(for)h(more)h(k)m(eyw)m(ords.)40
+b(The)29 b Fc(morekeys)e Fg(parameter)120 1621 y(ma)m(y)k(b)s(e)f(set)h
+(to)g(NULL)f(if)f(it's)h(v)-5 b(alue)30 b(is)g(not)g(needed.)120
+1834 y Fc(________________________)o(____)o(____)o(___)o(____)o(____)o
+(___)o(____)o(____)o(___)o(____)o(____)o(___)o(____)o(___)120
+1947 y(int)47 b(fits_read_record\(fitsfil)o(e)42 b(*fptr,)k(int)h
+(keynum,)f(char)g(*record,)g(int)h(*status\))120 2060
+y(int)g(fits_read_card\(fitsfile)41 b(*fptr,)46 b(char)h(*keyname,)e
+(char)i(*record,)f(int)g(*status\))120 2172 y(int)h
+(fits_read_key\(fitsfile)42 b(*fptr,)k(int)h(datatype,)e(char)i
+(*keyname,)979 2285 y(void)g(*value,)f(char)g(*comment,)f(int)i
+(*status\))120 2511 y(int)g(fits_find_nextkey\(fitsfi)o(le)42
+b(*fptr,)k(char)g(**inclist,)f(int)i(ninc,)1170 2624
+y(char)g(**exclist,)e(int)i(nexc,)f(char)h(*card,)f(int)h(*status\))120
+2850 y(int)g(fits_read_key_unit\(fitsf)o(ile)41 b(*fptr,)46
+b(char)h(*keyname,)e(char)i(*unit,)1218 2963 y(int)g(*status\))261
+3175 y Fg(These)d(routines)g(all)f(read)h(a)h(header)f(record)g(in)f
+(the)i(curren)m(t)f(HDU.)i(The)e(\014rst)f(routine)h(reads)120
+3288 y(k)m(eyw)m(ord)c(n)m(um)m(b)s(er)f Fc(keynum)f
+Fg(\(where)i(the)g(\014rst)f(k)m(eyw)m(ord)i(is)e(at)i(p)s(osition)d
+(1\).)70 b(This)38 b(routine)h(is)g(most)120 3401 y(commonly)28
+b(used)g(when)f(sequen)m(tially)g(reading)g(ev)m(ery)j(record)e(in)f
+(the)i(header)f(from)g(b)s(eginning)e(to)j(end.)120 3514
+y(The)22 b(2nd)f(and)h(3rd)f(routines)g(read)h(the)g(named)g(k)m(eyw)m
+(ord)h(and)e(return)g(either)h(the)g(whole)f(80-b)m(yte)j(record,)120
+3627 y(or)30 b(the)h(k)m(eyw)m(ord)g(v)-5 b(alue)30 b(and)f(commen)m(t)
+j(string.)261 3740 y(Wild)25 b(card)g(c)m(haracters)j(\(*,)g(?,)f(and)e
+(#\))h(ma)m(y)h(b)s(e)e(used)g(when)g(sp)s(ecifying)f(the)i(name)h(of)f
+(the)g(k)m(eyw)m(ord)120 3853 y(to)31 b(b)s(e)f(read,)g(in)f(whic)m(h)h
+(case)h(the)g(\014rst)e(matc)m(hing)i(k)m(eyw)m(ord)f(is)g(returned.)
+261 3966 y(The)41 b Fc(datatype)e Fg(parameter)j(sp)s(eci\014es)e(the)h
+(C)g(datat)m(yp)s(e)h(of)g(the)f(returned)f(k)m(eyw)m(ord)i(v)-5
+b(alue)41 b(and)120 4079 y(can)48 b(ha)m(v)m(e)h(one)f(of)g(the)f
+(follo)m(wing)f(sym)m(b)s(olic)g(constan)m(t)j(v)-5 b(alues:)75
+b Fc(TSTRING,)46 b(TLOGICAL)f Fg(\(==)i(in)m(t\),)120
+4192 y Fc(TBYTE)p Fg(,)d Fc(TSHORT)p Fg(,)f Fc(TUSHORT)p
+Fg(,)g Fc(TINT)p Fg(,)h Fc(TUINT)p Fg(,)f Fc(TLONG)p
+Fg(,)h Fc(TULONG)p Fg(,)f Fc(TFLOAT)p Fg(,)g Fc(TDOUBLE)p
+Fg(,)g Fc(TCOMPLEX)p Fg(,)g(and)120 4304 y Fc(TDBLCOMPLEX)p
+Fg(.)e(Data)k(t)m(yp)s(e)f(con)m(v)m(ersion)g(will)d(b)s(e)i(p)s
+(erformed)f(for)i(n)m(umeric)e(v)-5 b(alues)43 b(if)g(the)h(in)m
+(trinsic)120 4417 y(FITS)32 b(k)m(eyw)m(ord)h(v)-5 b(alue)32
+b(do)s(es)g(not)g(ha)m(v)m(e)i(the)f(same)g(datat)m(yp)s(e.)48
+b(The)32 b Fc(comment)e Fg(parameter)j(ma)m(y)g(b)s(e)f(set)120
+4530 y(equal)e(to)h(NULL)f(if)g(the)g(commen)m(t)i(string)d(is)g(not)i
+(needed.)261 4643 y(The)21 b(4th)h(routine)f(pro)m(vides)g(an)h(easy)g
+(w)m(a)m(y)h(to)f(\014nd)e(all)h(the)h(k)m(eyw)m(ords)g(in)f(the)g
+(header)h(that)g(matc)m(h)h(one)120 4756 y(of)29 b(the)h(name)f
+(templates)g(in)f Fc(inclist)f Fg(and)h(do)h(not)h(matc)m(h)g(an)m(y)f
+(of)g(the)h(name)f(templates)g(in)f Fc(exclist)p Fg(.)120
+4869 y Fc(ninc)37 b Fg(and)h Fc(nexc)f Fg(are)i(the)g(n)m(um)m(b)s(er)e
+(of)h(template)h(strings)e(in)g Fc(inclist)g Fg(and)h
+Fc(exclist)p Fg(,)g(resp)s(ectiv)m(ely)-8 b(.)120 4982
+y(Wild)33 b(cards)h(\(*,)i(?,)f(and)f(#\))g(ma)m(y)h(b)s(e)f(used)f(in)
+g(the)h(templates)h(to)g(matc)m(h)g(m)m(ultiple)d(k)m(eyw)m(ords.)53
+b(Eac)m(h)120 5095 y(time)35 b(this)f(routine)g(is)g(called)g(it)g
+(returns)g(the)h(next)h(matc)m(hing)f(80-b)m(yte)h(k)m(eyw)m(ord)g
+(record.)54 b(It)36 b(returns)120 5208 y(status)31 b(=)f
+Fc(KEY)p 640 5208 29 4 v 33 w(NO)p 769 5208 V 34 w(EXIST)f
+Fg(if)g(there)i(are)g(no)f(more)g(matc)m(hes.)261 5321
+y(The)f(5th)g(routine)f(returns)g(the)i(k)m(eyw)m(ord)g(v)-5
+b(alue)28 b(units)g(string,)g(if)h(an)m(y)-8 b(.)41 b(The)28
+b(units)g(are)i(recorded)f(at)120 5434 y(the)i(b)s(eginning)c(of)k(the)
+f(k)m(eyw)m(ord)h(commen)m(t)h(\014eld)d(enclosed)h(in)f(square)h(brac)
+m(k)m(ets.)1905 5809 y(19)p eop
+%%Page: 20 20
+20 19 bop 120 573 a Fc(________________________)o(____)o(____)o(___)o
+(____)o(____)o(___)o(____)o(____)o(___)o(____)o(__)120
+686 y(int)47 b(fits_write_key\(fitsfile)41 b(*fptr,)46
+b(int)h(datatype,)f(char)g(*keyname,)502 799 y(void)g(*value,)g(char)h
+(*comment,)e(int)i(*status\))120 912 y(int)g(fits_update_key\(fitsfile)
+41 b(*fptr,)46 b(int)h(datatype,)e(char)i(*keyname,)502
+1024 y(void)f(*value,)g(char)h(*comment,)e(int)i(*status\))120
+1137 y(int)g(fits_write_record\(fitsfi)o(le)42 b(*fptr,)k(char)g
+(*card,)g(int)h(*status\))120 1363 y(int)g(fits_modify_comment\(fits)o
+(file)41 b(*fptr,)46 b(char)h(*keyname,)e(char)i(*comment,)502
+1476 y(int)g(*status\))120 1589 y(int)g(fits_write_key_unit\(fits)o
+(file)41 b(*fptr,)46 b(char)h(*keyname,)e(char)i(*unit,)502
+1702 y(int)g(*status\))261 1975 y Fg(W)-8 b(rite)31 b(or)g(mo)s(dify)f
+(a)h(k)m(eyw)m(ord)g(in)f(the)h(header)g(of)g(the)g(curren)m(t)g(HDU.)h
+(The)e(\014rst)g(routine)g(app)s(ends)120 2087 y(the)g(new)g(k)m(eyw)m
+(ord)g(to)h(the)f(end)g(of)g(the)g(header,)h(whereas)e(the)i(second)f
+(routine)f(will)e(up)s(date)j(the)g(v)-5 b(alue)120 2200
+y(and)40 b(commen)m(t)h(\014elds)e(of)i(the)g(k)m(eyw)m(ord)g(if)e(it)h
+(already)h(exists,)h(otherwise)e(it)h(b)s(eha)m(v)m(es)g(lik)m(e)e(the)
+i(\014rst)120 2313 y(routine)32 b(and)g(app)s(ends)f(the)h(new)h(k)m
+(eyw)m(ord.)48 b(Note)34 b(that)f Fc(value)e Fg(giv)m(es)i(the)g
+(address)f(to)h(the)g(v)-5 b(alue)32 b(and)120 2426 y(not)f(the)g(v)-5
+b(alue)31 b(itself.)41 b(The)31 b Fc(datatype)d Fg(parameter)k(sp)s
+(eci\014es)d(the)j(C)e(datat)m(yp)s(e)i(of)f(the)g(k)m(eyw)m(ord)h(v)-5
+b(alue)120 2539 y(and)38 b(ma)m(y)g(ha)m(v)m(e)i(an)m(y)f(of)f(the)g(v)
+-5 b(alues)38 b(listed)f(in)g(the)h(description)e(of)j(the)f(k)m(eyw)m
+(ord)h(reading)e(routines,)120 2652 y(ab)s(o)m(v)m(e.)71
+b(A)40 b(NULL)g(ma)m(y)h(b)s(e)e(en)m(tered)i(for)f(the)g(commen)m(t)h
+(parameter,)i(in)c(whic)m(h)g(case)i(the)f(k)m(eyw)m(ord)120
+2765 y(commen)m(t)31 b(\014eld)e(will)f(b)s(e)i(unmo)s(di\014ed)d(or)j
+(left)h(blank.)261 2878 y(The)25 b(third)f(routine)h(is)g(more)h
+(primitiv)m(e)e(and)h(simply)e(writes)i(the)h(80-c)m(haracter)j
+Fc(card)c Fg(record)h(to)g(the)120 2991 y(header.)40
+b(It)30 b(is)f(the)h(programmer's)f(resp)s(onsibilit)m(y)d(in)i(this)h
+(case)h(to)h(ensure)e(that)h(the)g(record)g(conforms)120
+3104 y(to)h(all)e(the)i(FITS)f(format)g(requiremen)m(ts)g(for)g(a)h
+(header)f(record.)261 3217 y(The)42 b(fourth)f(routine)g(mo)s(di\014es)
+f(the)i(commen)m(t)h(string)e(in)g(an)g(existing)g(k)m(eyw)m(ord,)46
+b(and)41 b(the)h(last)120 3329 y(routine)33 b(writes)g(or)h(up)s(dates)
+f(the)h(k)m(eyw)m(ord)h(units)d(string)h(for)h(an)g(existing)f(k)m(eyw)
+m(ord.)52 b(\(The)34 b(units)e(are)120 3442 y(recorded)e(at)h(the)g(b)s
+(eginning)d(of)i(the)h(k)m(eyw)m(ord)f(commen)m(t)i(\014eld)d(enclosed)
+h(in)f(square)h(brac)m(k)m(ets\).)120 3621 y Fc
+(________________________)o(____)o(____)o(___)o(____)o(____)o(___)o
+(____)o(____)o(___)o(____)o(____)o(__)120 3734 y(int)47
+b(fits_write_comment\(fitsf)o(ile)41 b(*fptr,)46 b(char)h(*comment,)93
+b(int)47 b(*status\))120 3847 y(int)g(fits_write_history\(fitsf)o(ile)
+41 b(*fptr,)46 b(char)h(*history,)93 b(int)47 b(*status\))120
+3960 y(int)g(fits_write_date\(fitsfile)41 b(*fptr,)94
+b(int)47 b(*status\))261 4139 y Fg(W)-8 b(rite)21 b(a)g
+Fc(COMMENT,)46 b(HISTORY)p Fg(,)18 b(or)j Fc(DATE)e Fg(k)m(eyw)m(ord)i
+(to)h(the)f(curren)m(t)f(header.)37 b(The)20 b Fc(COMMENT)f
+Fg(k)m(eyw)m(ord)120 4252 y(is)37 b(t)m(ypically)g(used)g(to)h(write)g
+(a)g(commen)m(t)h(ab)s(out)e(the)i(\014le)e(or)g(the)i(data.)64
+b(The)37 b Fc(HISTORY)f Fg(k)m(eyw)m(ord)i(is)120 4365
+y(t)m(ypically)22 b(used)f(to)j(pro)m(vide)e(information)f(ab)s(out)h
+(the)h(history)e(of)i(the)g(pro)s(cessing)e(pro)s(cedures)h(that)h(ha)m
+(v)m(e)120 4478 y(b)s(een)36 b(applied)f(to)i(the)g(data.)61
+b(The)36 b Fc(comment)f Fg(or)i Fc(history)e Fg(string)h(will)e(b)s(e)i
+(con)m(tin)m(ued)h(o)m(v)m(er)h(m)m(ultiple)120 4591
+y(k)m(eyw)m(ords)31 b(if)e(it)h(is)f(more)i(than)f(70)h(c)m(haracters)h
+(long.)261 4704 y(The)k Fc(DATE)f Fg(k)m(eyw)m(ord)i(is)e(used)h(to)h
+(record)f(the)h(date)g(and)f(time)g(that)h(the)f(FITS)g(\014le)f(w)m
+(as)i(created.)120 4817 y(Note)f(that)f(this)e(\014le)h(creation)h
+(date)g(is)f(usually)e(di\013eren)m(t)i(from)g(the)h(date)g(of)g(the)f
+(observ)-5 b(ation)35 b(whic)m(h)120 4930 y(obtained)e(the)h(data)h(in)
+d(the)j(FITS)e(\014le.)50 b(The)33 b Fc(DATE)g Fg(k)m(eyw)m(ord)h(v)-5
+b(alue)34 b(is)f(a)h(c)m(haracter)i(string)c(in)h('yyyy-)120
+5042 y(mm-ddThh:mm:ss')27 b(format.)40 b(If)29 b(a)g
+Fc(DATE)f Fg(k)m(eyw)m(ord)i(already)e(exists)h(in)f(the)h(header,)h
+(then)e(this)g(routine)120 5155 y(will)g(up)s(date)h(the)i(v)-5
+b(alue)30 b(with)f(the)h(curren)m(t)g(system)h(date.)120
+5334 y Fc(________________________)o(____)o(____)o(___)o(____)o(____)o
+(___)o(____)o(____)o(___)o(____)o(____)o(__)120 5447
+y(int)47 b(fits_delete_record\(fitsf)o(ile)41 b(*fptr,)46
+b(int)h(keynum,)94 b(int)47 b(*status\))120 5560 y(int)g
+(fits_delete_key\(fitsfile)41 b(*fptr,)46 b(char)h(*keyname,)93
+b(int)47 b(*status\))1905 5809 y Fg(20)p eop
+%%Page: 21 21
+21 20 bop 261 573 a Fg(Delete)32 b(a)f(k)m(eyw)m(ord)h(record.)42
+b(The)30 b(\014rst)g(routine)g(deletes)h(a)g(k)m(eyw)m(ord)h(at)f(a)h
+(sp)s(eci\014ed)d(p)s(osition)g(\(the)120 686 y(\014rst)e(k)m(eyw)m
+(ord)h(is)e(at)i(p)s(osition)e(1,)j(not)e(0\),)i(whereas)f(the)f
+(second)h(routine)e(deletes)i(the)g(named)f(k)m(eyw)m(ord.)120
+898 y Fc(________________________)o(____)o(____)o(___)o(____)o(____)o
+(___)o(____)o(____)o(___)o(____)o(____)o(___)o(___)120
+1011 y(int)47 b(fits_copy_header\(fitsfil)o(e)42 b(*infptr,)j(fitsfile)
+h(*outfptr,)93 b(int)47 b(*status\))261 1224 y Fg(Cop)m(y)26
+b(all)f(the)h(header)g(k)m(eyw)m(ords)h(from)e(the)i(curren)m(t)e(HDU)i
+(asso)s(ciated)g(with)d(infptr)g(to)j(the)g(curren)m(t)120
+1337 y(HDU)h(asso)s(ciated)f(with)e(outfptr.)39 b(If)27
+b(the)g(curren)m(t)f(output)h(HDU)g(is)f(not)h(empt)m(y)-8
+b(,)29 b(then)d(a)h(new)f(HDU)i(will)120 1450 y(b)s(e)34
+b(app)s(ended)f(to)j(the)f(output)f(\014le.)53 b(The)35
+b(output)f(HDU)i(will)c(then)i(ha)m(v)m(e)i(the)f(iden)m(tical)f
+(structure)g(as)120 1562 y(the)d(input)d(HDU,)j(but)f(will)e(con)m
+(tain)i(no)h(data.)1905 5809 y(21)p eop
+%%Page: 22 22
+22 21 bop 120 573 a Fb(4.7)112 b(Utilit)m(y)34 b(Routines)120
+744 y Fg(This)29 b(section)h(lists)f(the)i(most)f(imp)s(ortan)m(t)g
+(CFITSIO)f(general)h(utilit)m(y)f(routines.)120 957 y
+Fc(________________________)o(____)o(____)o(___)o(____)o(____)o(___)o
+(____)o(____)o(___)o(____)o(____)o(__)120 1070 y(int)47
+b(fits_write_chksum\()c(fitsfile)i(*fptr,)h(int)h(*status\))120
+1183 y(int)g(fits_verify_chksum\(fitsf)o(ile)41 b(*fptr,)46
+b(int)h(*dataok,)f(int)h(*hduok,)f(int)g(*status\))261
+1395 y Fg(These)35 b(routines)f(compute)h(or)g(v)-5 b(alidate)34
+b(the)i(c)m(hec)m(ksums)f(for)g(the)g(currenrt)f(HDU.)i(The)e
+Fc(DATASUM)120 1508 y Fg(k)m(eyw)m(ord)d(is)e(used)g(to)i(store)g(the)f
+(n)m(umerical)f(v)-5 b(alue)29 b(of)i(the)f(32-bit,)h(1's)f(complemen)m
+(t)g(c)m(hec)m(ksum)h(for)f(the)120 1621 y(data)25 b(unit)e(alone.)39
+b(The)24 b Fc(CHECKSUM)f Fg(k)m(eyw)m(ord)i(is)f(used)f(to)j(store)f
+(the)g(ASCI)s(I)e(enco)s(ded)h(COMPLEMENT)120 1734 y(of)32
+b(the)f(c)m(hec)m(ksum)h(for)f(the)h(en)m(tire)f(HDU.)i(Storing)d(the)i
+(complemen)m(t,)g(rather)f(than)g(the)h(actual)f(c)m(hec)m(k-)120
+1847 y(sum,)26 b(forces)g(the)g(c)m(hec)m(ksum)g(for)f(the)h(whole)f
+(HDU)h(to)g(equal)f(zero.)40 b(If)25 b(the)h(\014le)f(has)g(b)s(een)g
+(mo)s(di\014ed)e(since)120 1960 y(the)31 b(c)m(hec)m(ksums)f(w)m(ere)h
+(computed,)g(then)f(the)g(HDU)i(c)m(hec)m(ksum)f(will)c(usually)h(not)j
+(equal)f(zero.)261 2073 y(The)g(returned)g Fc(dataok)f
+Fg(and)h Fc(hduok)g Fg(parameters)h(will)d(ha)m(v)m(e)k(a)f(v)-5
+b(alue)30 b(=)h(1)g(if)f(the)h(data)g(or)g(HDU)g(is)120
+2186 y(v)m(eri\014ed)c(correctly)-8 b(,)30 b(a)e(v)-5
+b(alue)28 b(=)g(0)g(if)f(the)i Fc(DATASUM)d Fg(or)i Fc(CHECKSUM)e
+Fg(k)m(eyw)m(ord)j(is)e(not)h(presen)m(t,)h(or)f(v)-5
+b(alue)28 b(=)120 2299 y(-1)j(if)e(the)i(computed)f(c)m(hec)m(ksum)h
+(is)f(not)g(correct.)120 2511 y Fc(________________________)o(____)o
+(____)o(___)o(____)o(____)o(___)o(____)o(____)o(___)o(____)o(____)o(__)
+120 2624 y(int)47 b(fits_parse_value\(char)42 b(*card,)k(char)h
+(*value,)e(char)i(*comment,)e(int)i(*status\))120 2737
+y(int)g(fits_get_keytype\(char)42 b(*value,)k(char)g(*dtype,)g(int)h
+(*status\))120 2850 y(int)g(fits_get_keyclass\(char)42
+b(*card\))120 2963 y(int)47 b(fits_parse_template\(char)41
+b(*template,)k(char)i(*card,)f(int)h(*keytype,)e(int)i(*status\))261
+3288 y(fits)p 459 3288 29 4 v 33 w(parse)p 732 3288 V
+33 w(value)29 b Fg(parses)h(the)h(input)d(80-c)m(hararacter)33
+b(header)d(k)m(eyw)m(ord)h(record,)g(returning)d(the)120
+3401 y(v)-5 b(alue)20 b(\(as)i(a)f(literal)e(c)m(haracter)k(string\))d
+(and)g(commen)m(t)i(strings.)37 b(If)20 b(the)h(k)m(eyw)m(ord)h(has)e
+(no)h(v)-5 b(alue)20 b(\(columns)120 3514 y(9-10)38 b(not)e(equal)g(to)
+h('=)f('\),)j(then)d(a)g(n)m(ull)f(v)-5 b(alue)35 b(string)h(is)f
+(returned)g(and)h(the)g(commen)m(t)h(string)f(is)f(set)120
+3627 y(equal)30 b(to)h(column)e(9)i(-)g(80)g(of)f(the)h(input)d
+(string.)261 3740 y Fc(fits)p 459 3740 V 33 w(get)p 636
+3740 V 34 w(keytype)41 b Fg(parses)i(the)g(k)m(eyw)m(ord)h(v)-5
+b(alue)42 b(string)g(to)i(determine)e(its)h(datat)m(yp)s(e.)80
+b Fc(dtype)120 3853 y Fg(returns)34 b(with)f(a)i(v)-5
+b(alue)35 b(of)g('C',)g('L',)g('I',)h('F')f(or)g('X',)h(for)f(c)m
+(haracter)h(string,)f(logical,)h(in)m(teger,)g(\015oating)120
+3966 y(p)s(oin)m(t,)30 b(or)g(complex,)g(resp)s(ectiv)m(ely)-8
+b(.)261 4079 y Fc(fits)p 459 4079 V 33 w(get)p 636 4079
+V 34 w(keyclass)31 b Fg(returns)i(a)h(classi\014cation)e(co)s(de)i
+(that)g(indicates)f(the)h(classi\014cation)e(t)m(yp)s(e)i(of)120
+4192 y(the)41 b(input)d(k)m(eyw)m(ord)j(record)f(\(e.g.,)45
+b(a)40 b(required)f(structural)g(k)m(eyw)m(ord,)44 b(a)d(TDIM)f(k)m
+(eyw)m(ord,)k(a)c(W)m(CS)120 4304 y(k)m(eyw)m(ord,)49
+b(a)d(commen)m(t)g(k)m(eyw)m(ord,)j(etc.)85 b(See)45
+b(the)h(CFITSIO)d(Reference)j(Guide)d(for)i(a)g(list)f(of)h(the)120
+4417 y(di\013eren)m(t)30 b(classi\014cation)f(co)s(des.)261
+4530 y Fc(fits)p 459 4530 V 33 w(parse)p 732 4530 V 33
+w(template)37 b Fg(tak)m(es)j(an)e(input)f(free)h(format)h(k)m(eyw)m
+(ord)g(template)g(string)f(and)g(returns)120 4643 y(a)i(formatted)g
+(80*c)m(har)h(record)e(that)h(satis\014es)f(all)g(the)g(FITS)g
+(requiremen)m(ts)g(for)g(a)h(header)f(k)m(eyw)m(ord)120
+4756 y(record.)65 b(The)38 b(template)h(should)d(generally)i(con)m
+(tain)h(3)g(tok)m(ens:)58 b(the)38 b(k)m(eyw)m(ord)h(name,)i(the)e(k)m
+(eyw)m(ord)120 4869 y(v)-5 b(alue,)28 b(and)f(the)g(k)m(eyw)m(ord)h
+(commen)m(t)h(string.)39 b(The)27 b(returned)f Fc(keytype)g
+Fg(parameter)i(indicates)e(whether)120 4982 y(the)33
+b(k)m(eyw)m(ord)g(is)f(a)h(COMMENT)g(k)m(eyw)m(ord)g(or)g(not.)48
+b(See)33 b(the)g(CFITSIO)e(Reference)j(Guide)e(for)g(more)120
+5095 y(details.)1905 5809 y(22)p eop
+%%Page: 23 23
+23 22 bop 120 573 a Fi(5)135 b(CFITSIO)44 b(File)h(Names)h(and)f
+(Filters)120 779 y Fb(5.1)112 b(Creating)37 b(New)g(Files)120
+951 y Fg(When)43 b(creating)g(a)g(new)g(output)f(\014le)g(on)h
+(magnetic)h(disk)d(with)h Fc(fits)p 2677 951 29 4 v 33
+w(create)p 2998 951 V 33 w(file)g Fg(the)h(follo)m(wing)120
+1064 y(features)31 b(are)f(supp)s(orted.)256 1251 y Fa(\017)46
+b Fg(Ov)m(erwriting,)29 b(or)h('Clobb)s(ering')e(an)j(Existing)d(File)
+347 1402 y(If)f(the)h(\014lename)f(is)g(preceded)g(b)m(y)g(an)h
+(exclamation)g(p)s(oin)m(t)e(\(!\))41 b(then)27 b(if)g(that)h(\014le)e
+(already)i(exists)f(it)347 1514 y(will)f(b)s(e)h(deleted)h(prior)e(to)j
+(creating)f(the)g(new)g(FITS)f(\014le.)39 b(Otherwise)26
+b(if)h(there)h(is)f(an)h(existing)f(\014le)347 1627 y(with)35
+b(the)g(same)h(name,)i(CFITSIO)c(will)f(not)j(o)m(v)m(erwrite)g(the)g
+(existing)e(\014le)h(and)g(will)e(return)h(an)347 1740
+y(error)28 b(status)h(co)s(de.)40 b(Note)30 b(that)f(the)f(exclamation)
+h(p)s(oin)m(t)e(is)g(a)i(sp)s(ecial)e(UNIX)h(c)m(haracter,)j(so)e(if)e
+(it)347 1853 y(is)f(used)g(on)g(the)h(command)g(line)e(rather)h(than)g
+(en)m(tered)i(at)f(a)g(task)g(prompt,)g(it)f(m)m(ust)h(b)s(e)f
+(preceded)347 1966 y(b)m(y)j(a)h(bac)m(kslash)f(to)h(force)g(the)f
+(UNIX)h(shell)d(to)k(pass)d(it)h(v)m(erbatim)g(to)h(the)g(application)d
+(program.)256 2154 y Fa(\017)46 b Fg(Compressed)30 b(Output)f(Files)347
+2304 y(If)g(the)g(output)f(disk)g(\014le)g(name)h(ends)f(with)f(the)i
+(su\016x)f('.gz',)j(then)e(CFITSIO)e(will)f(compress)j(the)347
+2417 y(\014le)38 b(using)g(the)h(gzip)g(compression)f(algorithm)g(b)s
+(efore)g(writing)f(it)i(to)h(disk.)65 b(This)37 b(can)j(reduce)347
+2530 y(the)h(amoun)m(t)g(of)g(disk)e(space)i(used)f(b)m(y)g(the)h
+(\014le.)70 b(Note)42 b(that)f(this)f(feature)h(requires)e(that)i(the)
+347 2643 y(uncompressed)e(\014le)h(b)s(e)g(constructed)h(in)e(memory)h
+(b)s(efore)g(it)g(is)g(compressed)g(and)g(written)g(to)347
+2756 y(disk,)29 b(so)i(it)f(can)h(fail)e(if)g(there)i(is)e
+(insu\016cien)m(t)g(a)m(v)-5 b(ailable)29 b(memory)-8
+b(.)347 2906 y(One)32 b(can)h(also)g(sp)s(ecify)e(that)i(an)m(y)g
+(images)g(written)f(to)h(the)g(output)f(\014le)g(should)f(b)s(e)h
+(compressed)347 3019 y(using)22 b(the)h(newly)f(dev)m(elop)s(ed)h
+(`tile-compression')f(algorithm)g(b)m(y)h(app)s(ending)e(`[compress]')j
+(to)g(the)347 3132 y(name)36 b(of)h(the)f(disk)f(\014le)g(\(as)i(in)e
+Fc(myfile.fits[compress])p Fg(\).)52 b(Refer)36 b(to)h(the)g(CFITSIO)d
+(User's)347 3245 y(Reference)d(Guide)f(for)g(more)g(information)f(ab)s
+(out)h(this)f(new)h(image)h(compression)e(format.)256
+3432 y Fa(\017)46 b Fg(Using)30 b(a)h(T)-8 b(emplate)30
+b(to)h(Create)g(a)g(New)g(FITS)e(File)347 3583 y(The)k(structure)g(of)g
+(an)m(y)h(new)f(FITS)f(\014le)h(that)h(is)e(to)i(b)s(e)f(created)h(ma)m
+(y)g(b)s(e)f(de\014ned)f(in)g(an)h(ASCI)s(I)347 3695
+y(template)c(\014le.)39 b(If)29 b(the)f(name)h(of)g(the)f(template)h
+(\014le)f(is)g(app)s(ended)e(to)k(the)e(name)h(of)g(the)f(FITS)g
+(\014le)347 3808 y(itself,)36 b(enclosed)f(in)f(paren)m(thesis)g
+(\(e.g.,)k Fc('newfile.fits\(template.tx)o(t\)')p Fg(\))29
+b(then)35 b(CFITSIO)347 3921 y(will)28 b(create)33 b(a)e(FITS)f(\014le)
+g(with)f(that)j(structure)e(b)s(efore)h(op)s(ening)e(it)h(for)h(the)g
+(application)e(to)i(use.)347 4034 y(The)h(template)h(\014le)f
+(basically)e(de\014nes)i(the)h(dimensions)c(and)j(data)h(t)m(yp)s(e)g
+(of)g(the)f(primary)f(arra)m(y)347 4147 y(and)23 b(an)m(y)h(IMA)m(GE)g
+(extensions,)h(and)e(the)g(names)g(and)g(data)h(t)m(yp)s(es)g(of)f(the)
+h(columns)e(in)g(an)m(y)i(ASCI)s(I)347 4260 y(or)35 b(binary)f(table)h
+(extensions.)54 b(The)35 b(template)g(\014le)f(can)i(also)f(b)s(e)f
+(used)h(to)g(de\014ne)g(an)m(y)g(optional)347 4373 y(k)m(eyw)m(ords)g
+(that)g(should)d(b)s(e)i(written)f(in)h(an)m(y)g(of)h(the)f(HDU)h
+(headers.)53 b(The)34 b(image)g(pixel)f(v)-5 b(alues)347
+4486 y(and)38 b(table)h(en)m(try)f(v)-5 b(alues)38 b(are)h(all)e
+(initialized)f(to)j(zero.)66 b(The)38 b(application)f(program)h(can)h
+(then)347 4599 y(write)27 b(actual)g(data)h(in)m(to)g(the)f(HDUs.)40
+b(See)28 b(the)f(CFITSIO)f(Reference)i(Guide)e(for)h(for)g(a)h
+(complete)347 4712 y(description)h(of)h(the)h(template)g(\014le)e(syn)m
+(tax.)256 4899 y Fa(\017)46 b Fg(Creating)30 b(a)h(T)-8
+b(emp)s(orary)30 b(Scratc)m(h)h(File)e(in)g(Memory)347
+5050 y(It)38 b(is)f(sometimes)h(useful)e(to)j(create)g(a)f(temp)s
+(orary)g(output)f(\014le)g(when)g(testing)h(an)g(application)347
+5162 y(program.)45 b(If)31 b(the)h(name)g(of)g(the)g(\014le)f(to)i(b)s
+(e)e(created)i(is)e(sp)s(eci\014ed)f(as)i Fc(mem:)42
+b Fg(then)32 b(CFITSIO)e(will)347 5275 y(create)39 b(the)e(\014le)g(in)
+f(memory)h(where)f(it)h(will)e(p)s(ersist)g(only)h(un)m(til)g(the)h
+(program)g(closes)h(the)f(\014le.)347 5388 y(Use)e(of)g(this)f
+Fc(mem:)48 b Fg(output)34 b(\014le)g(usually)e(enables)i(the)h(program)
+f(to)i(run)d(faster,)j(and)e(of)h(course)347 5501 y(the)c(output)f
+(\014le)f(do)s(es)h(not)h(use)f(up)f(an)m(y)i(disk)e(space.)1905
+5809 y(23)p eop
+%%Page: 24 24
+24 23 bop 120 573 a Fb(5.2)112 b(Op)s(ening)38 b(Existing)d(Files)120
+744 y Fg(When)j(op)s(ening)e(a)j(\014le)e(with)g Fc(fits)p
+1392 744 29 4 v 33 w(open)p 1617 744 V 33 w(file)p Fg(,)i(CFITSIO)e
+(can)h(read)g(a)g(v)-5 b(ariet)m(y)39 b(of)f(di\013eren)m(t)f(input)120
+857 y(\014le)30 b(formats)h(and)g(is)f(not)h(restricted)g(to)h(only)e
+(reading)g(FITS)h(format)g(\014les)f(from)h(magnetic)g(disk.)42
+b(The)120 970 y(follo)m(wing)29 b(t)m(yp)s(es)h(of)h(input)d(\014les)i
+(are)g(all)g(supp)s(orted:)256 1183 y Fa(\017)46 b Fg(FITS)30
+b(\014les)f(compressed)h(with)f Fc(zip,)47 b(gzip)29
+b Fg(or)i Fc(compress)347 1333 y Fg(If)36 b(CFITSIO)f(cannot)i(\014nd)e
+(the)i(sp)s(eci\014ed)e(\014le)g(to)i(op)s(en)f(it)g(will)e
+(automatically)i(lo)s(ok)g(for)g(a)h(\014le)347 1446
+y(with)j(the)g(same)h(ro)s(otname)h(but)d(with)h(a)h
+Fc(.gz,)46 b(.zip)p Fg(,)d(or)d Fc(.Z)g Fg(extension.)71
+b(If)41 b(it)f(\014nds)f(suc)m(h)h(a)347 1559 y(compressed)d(\014le,)g
+(it)g(will)d(allo)s(cate)j(a)g(blo)s(c)m(k)f(of)h(memory)g(and)f
+(uncompress)f(the)i(\014le)f(in)m(to)h(that)347 1672
+y(memory)25 b(space.)39 b(The)25 b(application)e(program)h(will)f(then)
+h(transparen)m(tly)g(op)s(en)g(this)g(virtual)f(FITS)347
+1785 y(\014le)35 b(in)f(memory)-8 b(.)56 b(Compressed)35
+b(\014les)f(can)i(only)f(b)s(e)f(op)s(ened)h(with)f('readonly',)j(not)f
+('readwrite')347 1898 y(\014le)30 b(access.)256 2085
+y Fa(\017)46 b Fg(FITS)30 b(\014les)f(on)h(the)h(in)m(ternet,)f(using)f
+Fc(ftp)h Fg(or)g Fc(http)f Fg(URLs)347 2236 y(Simply)20
+b(pro)m(vide)i(the)i(full)c(URL)j(as)g(the)g(name)g(of)h(the)f(\014le)f
+(that)h(y)m(ou)h(w)m(an)m(t)f(to)h(op)s(en.)38 b(F)-8
+b(or)23 b(example,)347 2348 y Fc(ftp://legacy.gsfc.nasa.go)o(v/so)o
+(ftwa)o(re/)o(fits)o(io/c)o(/te)o(stpr)o(og.s)o(td)347
+2461 y Fg(will)34 b(op)s(en)h(the)h(CFITSIO)e(test)j(FITS)e(\014le)g
+(that)i(is)d(lo)s(cated)j(on)e(the)h Fc(legacy)f Fg(mac)m(hine.)57
+b(These)347 2574 y(\014les)30 b(can)g(only)g(b)s(e)f(op)s(ened)h(with)f
+('readonly')h(\014le)g(access.)256 2762 y Fa(\017)46
+b Fg(FITS)30 b(\014les)f(on)h Fc(stdin)f Fg(or)i Fc(stdout)d
+Fg(\014le)i(streams)347 2912 y(If)k(the)g(name)h(of)f(the)h(\014le)e
+(to)i(b)s(e)f(op)s(ened)f(is)g Fc('stdin')g Fg(or)h Fc('-')f
+Fg(\(a)i(single)e(dash)g(c)m(haracter\))k(then)347 3025
+y(CFITSIO)f(will)f(read)j(the)f(\014le)g(from)g(the)h(standard)f(input)
+e(stream.)63 b(Similarly)-8 b(,)36 b(if)h(the)h(output)347
+3138 y(\014le)k(name)h(is)f Fc('stdout')f Fg(or)i Fc('-')p
+Fg(,)j(then)c(the)i(\014le)e(will)e(b)s(e)j(written)f(to)h(the)h
+(standard)e(output)347 3251 y(stream.)54 b(In)34 b(addition,)g(if)f
+(the)i(output)f(\014lename)g(is)g Fc('stdout.gz')d Fg(or)k
+Fc('-.gz')e Fg(then)h(it)g(will)e(b)s(e)347 3364 y(gzip)h(compressed)g
+(b)s(efore)g(b)s(eing)e(written)h(to)i(stdout.)49 b(This)32
+b(mec)m(hanism)g(can)i(b)s(e)e(used)g(to)i(pip)s(e)347
+3477 y(FITS)c(\014les)f(from)h(one)h(task)g(to)g(another)f(without)g
+(ha)m(ving)g(to)h(write)e(an)i(in)m(termediary)e(FITS)g(\014le)347
+3590 y(on)i(magnetic)f(disk.)256 3777 y Fa(\017)46 b
+Fg(FITS)30 b(\014les)f(that)i(exist)f(only)g(in)f(memory)-8
+b(,)31 b(or)f(shared)g(memory)-8 b(.)347 3928 y(In)38
+b(some)i(applications,)f(suc)m(h)g(as)g(real)f(time)h(data)g
+(acquisition,)h(y)m(ou)f(ma)m(y)h(w)m(an)m(t)f(to)h(ha)m(v)m(e)g(one)
+347 4040 y(pro)s(cess)31 b(write)f(a)i(FITS)e(\014le)g(in)m(to)h(a)h
+(certain)f(section)g(of)g(computer)g(memory)-8 b(,)32
+b(and)f(then)f(b)s(e)h(able)347 4153 y(to)26 b(op)s(en)f(that)g(\014le)
+f(in)g(memory)h(with)f(another)h(pro)s(cess.)39 b(There)25
+b(is)f(a)h(sp)s(ecialized)e(CFITSIO)h(op)s(en)347 4266
+y(routine)e(called)h Fc(fits)p 1102 4266 V 33 w(open)p
+1327 4266 V 33 w(memfile)f Fg(that)h(can)h(b)s(e)e(used)h(for)g(this)f
+(purp)s(ose.)37 b(See)23 b(the)g(\\CFITSIO)347 4379 y(User's)31
+b(Reference)g(Guide")f(for)g(more)g(details.)256 4567
+y Fa(\017)46 b Fg(IRAF)31 b(format)g(images)f(\(with)f
+Fc(.imh)h Fg(\014le)f(extensions\))347 4717 y(CFITSIO)38
+b(supp)s(orts)g(reading)h(IRAF)h(format)g(images)g(b)m(y)g(con)m(v)m
+(erting)g(them)g(on)f(the)h(\015y)f(in)m(to)347 4830
+y(FITS)27 b(images)h(in)e(memory)-8 b(.)40 b(The)28 b(application)d
+(program)j(then)f(reads)h(this)e(virtual)g(FITS)h(format)347
+4943 y(image)35 b(in)f(memory)-8 b(.)55 b(There)34 b(is)g(curren)m(tly)
+g(no)h(supp)s(ort)e(for)i(writing)e(IRAF)i(format)g(images,)h(or)347
+5056 y(for)30 b(reading)g(or)g(writing)f(IRAF)h(tables.)256
+5243 y Fa(\017)46 b Fg(Image)31 b(arra)m(ys)g(in)e(ra)m(w)i(binary)d
+(format)347 5394 y(If)23 b(the)h(input)d(\014le)i(is)f(a)i(ra)m(w)f
+(binary)f(data)i(arra)m(y)-8 b(,)26 b(then)d(CFITSIO)f(will)e(con)m(v)m
+(ert)25 b(it)e(on)g(the)h(\015y)f(in)m(to)g(a)347 5507
+y(virtual)f(FITS)g(image)i(with)e(the)i(basic)e(set)i(of)g(required)d
+(header)i(k)m(eyw)m(ords)h(b)s(efore)f(it)g(is)f(op)s(ened)g(b)m(y)1905
+5809 y(24)p eop
+%%Page: 25 25
+25 24 bop 347 573 a Fg(the)31 b(application)d(program.)40
+b(In)30 b(this)f(case)i(the)f(data)h(t)m(yp)s(e)g(and)e(dimensions)e
+(of)k(the)f(image)g(m)m(ust)347 686 y(b)s(e)d(sp)s(eci\014ed)e(in)h
+(square)h(brac)m(k)m(ets)h(follo)m(wing)e(the)h(\014lename)g(\(e.g.)41
+b Fc(rawfile.dat[ib512,512])p Fg(\).)347 799 y(The)30
+b(\014rst)g(c)m(haracter)i(inside)c(the)i(brac)m(k)m(ets)i(de\014nes)e
+(the)g(datat)m(yp)s(e)i(of)e(the)h(arra)m(y:)586 1049
+y Fc(b)429 b(8-bit)47 b(unsigned)e(byte)586 1161 y(i)381
+b(16-bit)47 b(signed)f(integer)586 1274 y(u)381 b(16-bit)47
+b(unsigned)e(integer)586 1387 y(j)381 b(32-bit)47 b(signed)f(integer)
+586 1500 y(r)h(or)h(f)142 b(32-bit)47 b(floating)e(point)586
+1613 y(d)381 b(64-bit)47 b(floating)e(point)347 1863
+y Fg(An)32 b(optional)e(second)i(c)m(haracter)h(sp)s(eci\014es)d(the)i
+(b)m(yte)h(order)e(of)g(the)h(arra)m(y)g(v)-5 b(alues:)43
+b(b)31 b(or)h(B)g(indi-)347 1976 y(cates)27 b(big)d(endian)f(\(as)j(in)
+e(FITS)g(\014les)g(and)g(the)i(nativ)m(e)f(format)g(of)h(SUN)e(UNIX)i
+(w)m(orkstations)f(and)347 2089 y(Mac)35 b(PCs\))d(and)h(l)f(or)h(L)g
+(indicates)f(little)g(endian)g(\(nativ)m(e)i(format)f(of)g(DEC)h(OSF)e
+(w)m(orkstations)347 2202 y(and)41 b(IBM)g(PCs\).)73
+b(If)41 b(this)f(c)m(haracter)i(is)f(omitted)g(then)f(the)i(arra)m(y)f
+(is)g(assumed)f(to)i(ha)m(v)m(e)g(the)347 2315 y(nativ)m(e)29
+b(b)m(yte)g(order)e(of)h(the)h(lo)s(cal)e(mac)m(hine.)40
+b(These)28 b(datat)m(yp)s(e)h(c)m(haracters)g(are)g(then)f(follo)m(w)m
+(ed)f(b)m(y)347 2428 y(a)f(series)f(of)g(one)h(or)f(more)h(in)m(teger)f
+(v)-5 b(alues)25 b(separated)h(b)m(y)f(commas)h(whic)m(h)e(de\014ne)h
+(the)g(size)h(of)f(eac)m(h)347 2540 y(dimension)j(of)j(the)f(ra)m(w)h
+(arra)m(y)-8 b(.)41 b(Arra)m(ys)31 b(with)e(up)g(to)i(5)g(dimensions)d
+(are)i(curren)m(tly)g(supp)s(orted.)347 2691 y(Finally)-8
+b(,)32 b(a)h(b)m(yte)g(o\013set)g(to)g(the)g(p)s(osition)d(of)i(the)h
+(\014rst)f(pixel)e(in)h(the)i(data)g(\014le)e(ma)m(y)i(b)s(e)f(sp)s
+(eci\014ed)347 2804 y(b)m(y)c(separating)g(it)g(with)e(a)j(':')40
+b(from)27 b(the)i(last)e(dimension)f(v)-5 b(alue.)39
+b(If)28 b(omitted,)h(it)e(is)g(assumed)h(that)347 2917
+y(the)h(o\013set)g(=)f(0.)41 b(This)26 b(parameter)j(ma)m(y)g(b)s(e)f
+(used)f(to)i(skip)e(o)m(v)m(er)j(an)m(y)e(header)g(information)f(in)g
+(the)347 3029 y(\014le)j(that)h(precedes)f(the)h(binary)d(data.)42
+b(F)-8 b(urther)30 b(examples:)443 3279 y Fc(raw.dat[b10000])473
+b(1-dimensional)44 b(10000)i(pixel)h(byte)f(array)443
+3392 y(raw.dat[rb400,400,12])185 b(3-dimensional)44 b(floating)i(point)
+g(big-endian)f(array)443 3505 y(img.fits[ib512,512:2880)o(])d(reads)k
+(the)h(512)g(x)h(512)e(short)h(integer)f(array)g(in)h(a)1636
+3618 y(FITS)g(file,)f(skipping)f(over)i(the)g(2880)g(byte)f(header)1905
+5809 y Fg(25)p eop
+%%Page: 26 26
+26 25 bop 120 573 a Fb(5.3)112 b(Image)37 b(Filtering)120
+744 y Fh(5.3.1)105 b(Extracting)35 b(a)g(subsection)h(of)f(an)g(image)
+120 916 y Fg(When)21 b(sp)s(ecifying)e(the)j(name)f(of)g(an)g(image)h
+(to)g(b)s(e)f(op)s(ened,)h(y)m(ou)g(can)f(select)h(a)g(rectangular)f
+(subsection)f(of)120 1029 y(the)29 b(image)f(to)h(b)s(e)f(extracted)i
+(and)e(op)s(ened)f(b)m(y)i(the)f(application)f(program.)40
+b(The)28 b(application)f(program)120 1142 y(then)k(op)s(ens)f(a)i
+(virtual)e(image)h(that)h(only)e(con)m(tains)i(the)f(pixels)f(within)e
+(the)k(sp)s(eci\014ed)d(subsection.)43 b(T)-8 b(o)120
+1255 y(do)33 b(this,)g(sp)s(ecify)f(the)i(the)f(range)h(of)f(pixels)e
+(\(start:end\))k(along)e(eac)m(h)h(axis)f(to)h(b)s(e)f(extracted)h
+(from)f(the)120 1368 y(original)28 b(image)j(enclosed)f(in)f(square)h
+(brac)m(k)m(ets.)42 b(Y)-8 b(ou)31 b(can)f(also)h(sp)s(ecify)e(an)h
+(optional)f(pixel)g(incremen)m(t)120 1481 y(\(start:end:step\))37
+b(for)f(eac)m(h)g(axis)g(of)f(the)h(input)e(image.)57
+b(A)36 b(pixel)e(step)i(=)f(1)h(will)d(b)s(e)i(assumed)g(if)g(it)g(is)
+120 1594 y(not)29 b(sp)s(eci\014ed.)38 b(If)28 b(the)h(starting)f
+(pixel)f(is)g(larger)i(then)f(the)h(end)e(pixel,)h(then)g(the)h(image)g
+(will)c(b)s(e)j(\015ipp)s(ed)120 1706 y(\(pro)s(ducing)33
+b(a)i(mirror)d(image\))j(along)g(that)g(dimension.)51
+b(An)34 b(asterisk,)i('*',)h(ma)m(y)e(b)s(e)f(used)f(to)j(sp)s(ecify)
+120 1819 y(the)25 b(en)m(tire)g(range)g(of)g(an)g(axis,)h(and)e('-*')i
+(will)d(\015ip)g(the)i(en)m(tire)g(axis.)38 b(In)24 b(the)h(follo)m
+(wing)f(examples,)i(assume)120 1932 y(that)31 b Fc(myfile.fits)c
+Fg(con)m(tains)k(a)g(512)g(x)g(512)g(pixel)e(2D)i(image.)215
+2130 y Fc(myfile.fits[201:210,)43 b(251:260])i(-)j(opens)e(a)i(10)f(x)g
+(10)g(pixel)g(subimage.)215 2356 y(myfile.fits[*,)d(512:257])i(-)h
+(opens)g(a)g(512)g(x)h(256)e(image)h(consisting)e(of)406
+2469 y(all)i(the)g(columns)f(in)h(the)g(input)f(image,)h(but)f(only)h
+(rows)g(257)406 2582 y(through)f(512.)95 b(The)46 b(image)h(will)f(be)i
+(flipped)d(along)i(the)g(Y)g(axis)406 2695 y(since)g(the)g(starting)e
+(row)i(is)g(greater)f(than)h(the)g(ending)406 2808 y(row.)215
+3033 y(myfile.fits[*:2,)d(512:257:2])h(-)i(creates)f(a)i(256)e(x)i(128)
+f(pixel)f(image.)406 3146 y(Similar)g(to)h(the)g(previous)f(example,)f
+(but)i(only)g(every)f(other)h(row)406 3259 y(and)g(column)f(is)i(read)e
+(from)h(the)g(input)f(image.)215 3485 y(myfile.fits[-*,)e(*])j(-)h
+(creates)e(an)h(image)f(containing)f(all)i(the)g(rows)g(and)406
+3598 y(columns)f(in)h(the)g(input)g(image,)f(but)h(flips)f(it)h(along)g
+(the)f(X)406 3711 y(axis.)261 3909 y Fg(If)33 b(the)g(arra)m(y)h(to)g
+(b)s(e)f(op)s(ened)f(is)h(in)f(an)h(Image)h(extension,)g(and)f(not)g
+(in)f(the)i(primary)d(arra)m(y)j(of)f(the)120 4022 y(\014le,)c(then)g
+(y)m(ou)g(need)g(to)h(sp)s(ecify)d(the)j(extension)f(name)g(or)g(n)m
+(um)m(b)s(er)f(in)f(square)i(brac)m(k)m(ets)i(b)s(efore)e(giving)120
+4135 y(the)h(subsection)e(range,)i(as)g(in)e Fc(myfile.fits[1][-*,)42
+b(*])29 b Fg(to)h(read)f(the)h(image)g(in)e(the)h(\014rst)g(extension)
+120 4248 y(in)g(the)i(\014le.)120 4485 y Fh(5.3.2)105
+b(Create)34 b(an)h(Image)f(b)m(y)h(Binning)h(T)-9 b(able)34
+b(Columns)120 4657 y Fg(Y)-8 b(ou)40 b(can)f(also)g(create)i(and)d(op)s
+(en)h(a)g(virtual)f(image)h(b)m(y)g(binning)d(the)k(v)-5
+b(alues)38 b(in)g(a)h(pair)f(of)i(columns)120 4770 y(of)f(a)h(FITS)f
+(table)g(\(in)f(other)i(w)m(ords,)h(create)g(a)e(2-D)i(histogram)e(of)g
+(the)g(v)-5 b(alues)39 b(in)f(the)h(2)h(columns\).)120
+4883 y(This)33 b(tec)m(hnique)h(is)g(often)h(used)f(in)g(X-ra)m(y)i
+(astronom)m(y)f(where)f(eac)m(h)i(detected)g(X-ra)m(y)g(photon)f
+(during)120 4996 y(an)29 b(observ)-5 b(ation)28 b(is)g(recorded)h(in)e
+(a)i(FITS)f(table.)40 b(There)29 b(are)g(t)m(ypically)e(2)j(columns)d
+(in)g(the)i(table)g(called)120 5109 y Fc(X)35 b Fg(and)h
+Fc(Y)f Fg(whic)m(h)g(record)g(the)i(pixel)d(lo)s(cation)h(of)h(that)h
+(ev)m(en)m(t)g(in)d(a)j(virtual)d(2D)i(image.)58 b(T)-8
+b(o)36 b(create)h(an)120 5222 y(image)27 b(from)f(this)g(table,)i(one)f
+(just)f(scans)h(the)g(X)g(and)f(Y)h(columns)f(and)g(coun)m(ts)h(up)f
+(ho)m(w)h(man)m(y)g(photons)120 5334 y(w)m(ere)k(recorded)g(in)f(eac)m
+(h)i(pixel)d(of)i(the)g(image.)43 b(When)30 b(table)h(binning)d(is)i
+(sp)s(eci\014ed,)g(CFITSIO)f(creates)120 5447 y(a)38
+b(temp)s(orary)e(FITS)h(primary)e(arra)m(y)j(in)e(memory)h(b)m(y)g
+(computing)g(the)g(histogram)g(of)h(the)f(v)-5 b(alues)37
+b(in)120 5560 y(the)29 b(sp)s(eci\014ed)e(columns.)39
+b(After)29 b(the)g(histogram)f(is)g(computed)h(the)g(original)e(FITS)h
+(\014le)g(con)m(taining)g(the)1905 5809 y(26)p eop
+%%Page: 27 27
+27 26 bop 120 573 a Fg(table)24 b(is)e(closed)i(and)f(the)g(temp)s
+(orary)h(FITS)e(primary)g(arra)m(y)i(is)f(op)s(ened)g(and)g(passed)g
+(to)h(the)g(application)120 686 y(program.)39 b(Th)m(us,)27
+b(the)g(application)e(program)i(nev)m(er)g(sees)h(the)f(original)e
+(FITS)h(table)h(and)f(only)g(sees)h(the)120 799 y(image)k(in)e(the)h
+(new)g(temp)s(orary)g(\014le)g(\(whic)m(h)f(has)h(no)g(extensions\).)
+261 912 y(The)f(table)g(binning)d(sp)s(eci\014er)i(is)h(enclosed)g(in)f
+(square)h(brac)m(k)m(ets)h(follo)m(wing)e(the)i(ro)s(ot)f(\014lename)g
+(and)120 1024 y(table)h(extension)g(name)h(or)f(n)m(um)m(b)s(er)f(and)h
+(b)s(egins)f(with)g(the)h(k)m(eyw)m(ord)h('bin',)f(as)g(in:)120
+1137 y Fc('myfile.fits[events][bin)41 b(\(X,Y\)]')p Fg(.)20
+b(In)h(this)g(case,)k(the)d(X)g(and)f(Y)h(columns)f(in)g(the)h('ev)m
+(en)m(ts')h(table)120 1250 y(extension)29 b(are)h(binned)e(up)g(to)j
+(create)g(the)f(image.)41 b(The)29 b(size)g(of)h(the)g(image)g(is)f
+(usually)e(determined)h(b)m(y)120 1363 y(the)22 b Fc(TLMINn)d
+Fg(and)i Fc(TLMAXn)f Fg(header)h(k)m(eyw)m(ords)h(whic)m(h)e(giv)m(e)i
+(the)f(minim)m(um)e(and)i(maxim)m(um)f(allo)m(w)m(ed)h(pixel)120
+1476 y(v)-5 b(alues)37 b(in)f(the)i(columns.)61 b(F)-8
+b(or)38 b(instance)f(if)g Fc(TLMINn)46 b(=)h(1)37 b Fg(and)g
+Fc(TLMAXn)46 b(=)i(4096)36 b Fg(for)i(b)s(oth)e(columns,)120
+1589 y(this)e(w)m(ould)g(generate)i(a)f(4096)i(x)e(4096)h(pixel)e
+(image)h(b)m(y)g(default.)53 b(This)33 b(is)h(rather)h(large,)i(so)e(y)
+m(ou)g(can)120 1702 y(also)d(sp)s(ecify)f(a)i(pixel)d(binning)f(factor)
+34 b(to)f(reduce)f(the)g(image)h(size.)46 b(F)-8 b(or)33
+b(example)f(sp)s(ecifying)e(,)j Fc('[bin)120 1815 y(\(X,Y\))46
+b(=)i(16]')29 b Fg(will)e(use)i(a)i(binning)26 b(factor)31
+b(of)f(16,)h(whic)m(h)e(will)e(pro)s(duce)i(a)h(256)h(x)f(256)h(pixel)e
+(image)h(in)120 1928 y(the)h(previous)d(example.)261
+2041 y(If)35 b(the)g(TLMIN)g(and)g(TLMAX)g(k)m(eyw)m(ords)g(don't)g
+(exist,)i(or)e(y)m(ou)g(w)m(an)m(t)h(to)g(o)m(v)m(erride)g(their)e(v)-5
+b(alues,)120 2154 y(y)m(ou)36 b(can)h(sp)s(ecify)d(the)i(image)h(range)
+f(and)f(binning)e(factor)k(directly)-8 b(,)37 b(as)f(in)f
+Fc('[bin)46 b(X)i(=)f(1:4096:16,)120 2267 y(Y=1:4096:16]')p
+Fg(.)36 b(Y)-8 b(ou)28 b(can)g(also)f(sp)s(ecify)f(the)i(datat)m(yp)s
+(e)g(of)g(the)g(created)g(image)g(b)m(y)f(app)s(ending)e(a)j(b,)g(i,)
+120 2379 y(j,)f(r,)g(or)f(d)f(\(for)h(8-bit)g(b)m(yte,)i(16-bit)f(in)m
+(tegers,)g(32-bit)f(in)m(teger,)i(32-bit)e(\015oating)g(p)s(oin)m(ts,)g
+(or)g(64-bit)h(double)120 2492 y(precision)34 b(\015oating)h(p)s(oin)m
+(t,)h(resp)s(ectiv)m(ely\))f(to)h(the)g('bin')e(k)m(eyw)m(ord)h(\(e.g.)
+58 b Fc('[binr)46 b(\(X,Y\)]')33 b Fg(creates)k(a)120
+2605 y(\015oating)i(p)s(oin)m(t)e(image\).)66 b(If)38
+b(the)h(datat)m(yp)s(e)h(is)d(not)i(sp)s(eci\014ed)e(then)h(a)h(32-bit)
+g(in)m(teger)g(image)g(will)d(b)s(e)120 2718 y(created)31
+b(b)m(y)g(default.)261 2831 y(If)39 b(the)h(column)e(name)h(is)g(not)g
+(sp)s(eci\014ed,)h(then)f(CFITSIO)f(will)f(\014rst)h(try)i(to)g(use)f
+(the)g('preferred)120 2944 y(column')34 b(as)h(sp)s(eci\014ed)e(b)m(y)i
+(the)g(CPREF)g(k)m(eyw)m(ord)g(if)f(it)h(exists)f(\(e.g.,)k('CPREF)d(=)
+g('DETX,DETY'\),)120 3057 y(otherwise)30 b(column)f(names)h('X',)i('Y')
+e(will)e(b)s(e)i(assumed)g(for)g(the)g(2)h(axes.)261
+3170 y(Note)37 b(that)f(this)e(binning)e(sp)s(eci\014er)i(is)g(not)h
+(restricted)g(to)h(only)f(2D)h(images)f(and)g(can)g(b)s(e)g(used)g(to)
+120 3283 y(create)f(1D,)f(3D,)g(or)g(4D)g(images)f(as)g(w)m(ell.)46
+b(It)32 b(is)f(also)h(p)s(ossible)e(to)j(sp)s(ecify)e(a)h(w)m(eigh)m
+(ting)g(factor)i(that)e(is)120 3396 y(applied)27 b(during)h(the)h
+(binning.)38 b(Please)29 b(refer)h(to)g(the)g(\\CFITSIO)e(User's)i
+(Reference)g(Guide")f(for)g(more)120 3509 y(details)g(on)i(these)f(adv)
+-5 b(anced)31 b(features.)1905 5809 y(27)p eop
+%%Page: 28 28
+28 27 bop 120 573 a Fb(5.4)112 b(T)-9 b(able)37 b(Filtering)120
+744 y Fh(5.4.1)105 b(Column)34 b(and)h(Keyw)m(ord)g(Filtering)120
+916 y Fg(The)29 b(column)f(or)h(k)m(eyw)m(ord)h(\014ltering)e(sp)s
+(eci\014er)g(is)g(used)h(to)h(mo)s(dify)d(the)j(column)e(structure)h
+(and/or)g(the)120 1029 y(header)h(k)m(eyw)m(ords)h(in)e(the)i(HDU)g
+(that)g(w)m(as)g(selected)g(with)e(the)i(previous)e(HDU)i(lo)s(cation)f
+(sp)s(eci\014er.)39 b(It)120 1142 y(can)31 b(b)s(e)e(used)h(to)h(p)s
+(erform)e(the)i(follo)m(wing)d(t)m(yp)s(es)j(of)f(op)s(erations.)256
+1354 y Fa(\017)46 b Fg(App)s(end)35 b(a)h(new)g(column)f(to)i(a)f
+(table)g(b)m(y)h(giving)e(the)h(column)f(name,)j(optionally)d(follo)m
+(w)m(ed)g(b)m(y)347 1467 y(the)e(datat)m(yp)s(e)h(in)d(paren)m(theses,)
+j(follo)m(w)m(ed)e(b)m(y)h(an)g(equals)f(sign)g(and)g(the)h(arithmetic)
+f(expression)347 1580 y(to)e(b)s(e)e(used)g(to)i(compute)f(the)g(v)-5
+b(alue.)40 b(The)28 b(datat)m(yp)s(e)i(is)e(sp)s(eci\014ed)f(using)h
+(the)h(same)g(syn)m(tax)h(that)347 1693 y(is)j(allo)m(w)m(ed)g(for)g
+(the)g(v)-5 b(alue)33 b(of)h(the)f(FITS)g(TF)m(ORMn)g(k)m(eyw)m(ord)h
+(\(e.g.,)i('I',)e('J',)g('E',)f('D',)i(etc.)51 b(for)347
+1806 y(binary)31 b(tables,)h(and)g('I8',)h(F12.3',)i('E20.12',)g(etc.)
+47 b(for)32 b(ASCI)s(I)f(tables\).)46 b(If)32 b(the)g(datat)m(yp)s(e)h
+(is)e(not)347 1919 y(sp)s(eci\014ed)e(then)h(a)h(default)e(datat)m(yp)s
+(e)j(will)27 b(b)s(e)j(c)m(hosen)h(dep)s(ending)d(on)i(the)h
+(expression.)256 2107 y Fa(\017)46 b Fg(Create)33 b(a)g(new)f(header)g
+(k)m(eyw)m(ord)h(b)m(y)f(giving)f(the)i(k)m(eyw)m(ord)g(name,)g
+(preceded)f(b)m(y)g(a)h(p)s(ound)d(sign)347 2220 y('#',)24
+b(follo)m(w)m(ed)c(b)m(y)h(an)g(equals)f(sign)g(and)g(an)h(arithmetic)f
+(expression)g(for)h(the)g(v)-5 b(alue)20 b(of)h(the)h(k)m(eyw)m(ord.)
+347 2332 y(The)k(expression)f(ma)m(y)i(b)s(e)f(a)h(function)e(of)i
+(other)f(header)g(k)m(eyw)m(ord)h(v)-5 b(alues.)39 b(The)26
+b(commen)m(t)h(string)347 2445 y(for)40 b(the)h(k)m(eyw)m(ord)g(ma)m(y)
+g(b)s(e)f(sp)s(eci\014ed)f(in)g(paren)m(theses)i(immediately)d(follo)m
+(wing)h(the)i(k)m(eyw)m(ord)347 2558 y(name.)256 2746
+y Fa(\017)46 b Fg(Ov)m(erwrite)29 b(the)g(v)-5 b(alues)29
+b(in)e(an)i(existing)g(column)e(or)j(k)m(eyw)m(ord)f(b)m(y)g(giving)f
+(the)i(name)f(follo)m(w)m(ed)f(b)m(y)347 2859 y(an)j(equals)e(sign)h
+(and)f(an)i(arithmetic)e(expression.)256 3046 y Fa(\017)46
+b Fg(Select)35 b(a)f(set)g(of)h(columns)d(to)j(b)s(e)e(included)f(in)g
+(the)j(\014ltered)e(\014le)g(b)m(y)h(listing)d(the)k(column)d(names)347
+3159 y(separated)d(with)e(semi-colons.)39 b(Wild)27 b(card)h(c)m
+(haracters)i(ma)m(y)e(b)s(e)g(used)f(in)g(the)i(column)e(names)h(to)347
+3272 y(matc)m(h)33 b(m)m(ultiple)d(columns.)45 b(An)m(y)32
+b(other)h(columns)d(in)h(the)i(input)d(table)i(will)d(not)k(app)s(ear)e
+(in)g(the)347 3385 y(\014ltered)f(\014le.)256 3573 y
+Fa(\017)46 b Fg(Delete)31 b(a)f(column)f(or)g(k)m(eyw)m(ord)h(b)m(y)g
+(listing)d(the)j(name)g(preceded)f(b)m(y)h(a)g(min)m(us)e(sign)g(or)i
+(an)g(excla-)347 3686 y(mation)g(mark)g(\(!\))256 3873
+y Fa(\017)46 b Fg(Rename)31 b(an)f(existing)g(column)f(or)h(k)m(eyw)m
+(ord)h(with)e(the)i(syn)m(tax)g('NewName)g(==)f(OldName'.)261
+4086 y(The)20 b(column)f(\014ltering)g(sp)s(eci\014er)f(is)i(enclosed)g
+(in)f(square)h(brac)m(k)m(ets)h(and)f(b)s(egins)f(with)g(the)h(string)g
+('col'.)120 4199 y(Multiple)29 b(op)s(erations)h(can)h(b)s(e)f(p)s
+(erformed)f(b)m(y)i(separating)f(them)h(with)e(semi-colons.)41
+b(F)-8 b(or)32 b(complex)e(or)120 4312 y(commonly)g(used)h(op)s
+(erations,)f(y)m(ou)i(can)f(write)f(the)h(column)f(\014lter)g(to)i(a)f
+(text)h(\014le,)e(and)h(then)f(use)h(it)f(b)m(y)120 4425
+y(giving)f(the)i(name)f(of)h(the)f(text)i(\014le,)d(preceded)h(b)m(y)h
+(a)f('@')h(c)m(haracter.)261 4538 y(Some)g(examples:)215
+4750 y Fc([col)47 b(PI=PHA)f(*)i(1.1)f(+)g(0.2])285 b(-)48
+b(creates)e(new)g(PI)i(column)e(from)g(PHA)h(values)215
+4976 y([col)g(rate)g(=)g(counts/exposure])91 b(-)48 b(creates)e(or)h
+(overwrites)e(the)i(rate)f(column)g(by)1743 5089 y(dividing)f(the)i
+(counts)f(column)g(by)i(the)1743 5202 y(EXPOSURE)d(keyword)h(value.)215
+5428 y([col)h(TIME;)f(X;)i(Y])667 b(-)48 b(only)e(the)h(listed)f
+(columns)g(will)h(appear)1743 5540 y(in)g(the)g(filtered)e(file)1905
+5809 y Fg(28)p eop
+%%Page: 29 29
+29 28 bop 215 686 a Fc([col)47 b(Time;*raw])713 b(-)48
+b(include)e(the)g(Time)h(column)f(and)h(any)g(other)1743
+799 y(columns)f(whose)g(name)h(ends)f(with)h('raw'.)215
+1024 y([col)g(-TIME;)f(Good)h(==)g(STATUS])141 b(-)48
+b(deletes)e(the)g(TIME)h(column)f(and)1743 1137 y(renames)g(the)g
+(STATUS)h(column)f(to)h(GOOD)215 1363 y([col)g(@colfilt.txt])569
+b(-)48 b(uses)e(the)h(filtering)f(expression)f(in)1743
+1476 y(the)i(colfilt.txt)d(text)j(file)261 1689 y Fg(The)30
+b(original)f(\014le)h(is)g(not)h(c)m(hanged)g(b)m(y)g(this)f
+(\014ltering)f(op)s(eration,)h(and)g(instead)g(the)h(mo)s
+(di\014cations)120 1802 y(are)36 b(made)f(on)h(a)f(temp)s(orary)h(cop)m
+(y)g(of)f(the)h(input)d(FITS)i(\014le)g(\(usually)e(in)h(memory\),)k
+(whic)m(h)c(includes)120 1914 y(a)42 b(cop)m(y)g(of)g(all)e(the)i
+(other)g(HDUs)g(in)e(the)i(input)e(\014le.)73 b(The)41
+b(original)f(input)g(\014le)g(is)h(closed)g(and)g(the)120
+2027 y(application)29 b(program)h(op)s(ens)f(the)i(\014ltered)e(cop)m
+(y)i(of)g(the)g(\014le.)120 2268 y Fh(5.4.2)105 b(Ro)m(w)36
+b(Filtering)120 2439 y Fg(The)22 b(ro)m(w)h(\014lter)f(is)g(used)g(to)h
+(select)g(a)h(subset)e(of)h(the)g(ro)m(ws)f(from)h(a)g(table)f(based)h
+(on)f(a)i(b)s(o)s(olean)d(expression.)120 2552 y(A)37
+b(temp)s(orary)g(new)f(FITS)g(\014le)h(is)f(created)i(on)f(the)g(\015y)
+f(\(usually)f(in)h(memory\))h(whic)m(h)f(con)m(tains)h(only)120
+2665 y(those)30 b(ro)m(ws)g(for)g(whic)m(h)f(the)h(ro)m(w)g(\014lter)f
+(expression)f(ev)-5 b(aluates)31 b(to)f(true)g(\(i.e.,)h(not)f(equal)f
+(to)i(zero\).)42 b(The)120 2778 y(primary)24 b(arra)m(y)j(and)e(an)m(y)
+h(other)h(extensions)e(in)g(the)h(input)e(\014le)h(are)i(also)f(copied)
+f(to)i(the)f(temp)s(orary)g(\014le.)120 2891 y(The)h(original)f(FITS)h
+(\014le)g(is)g(closed)g(and)h(the)g(new)f(temp)s(orary)g(\014le)g(is)g
+(then)g(op)s(ened)g(b)m(y)h(the)g(application)120 3004
+y(program.)261 3117 y(The)f(ro)m(w)g(\014lter)f(expression)g(is)g
+(enclosed)g(in)g(square)h(brac)m(k)m(ets)h(follo)m(wing)e(the)h(\014le)
+f(name)h(and)f(exten-)120 3230 y(sion)31 b(name.)48 b(F)-8
+b(or)33 b(example,)g Fc('file.fits[events][GRAD)o(E==5)o(0]')26
+b Fg(selects)33 b(only)f(those)h(ro)m(ws)f(in)f(the)120
+3342 y(EVENTS)f(table)g(where)g(the)g(GRADE)h(column)f(v)-5
+b(alue)29 b(is)h(equal)g(to)h(50\).)261 3455 y(The)d(ro)m(w)h
+(\014ltering)d(expression)i(can)g(b)s(e)g(an)h(arbitrarily)c(complex)k
+(series)e(of)i(op)s(erations)f(p)s(erformed)120 3568
+y(on)e(constan)m(ts,)i(k)m(eyw)m(ord)e(v)-5 b(alues,)26
+b(and)f(column)g(data)h(tak)m(en)h(from)e(the)h(sp)s(eci\014ed)e(FITS)h
+(T)-8 b(ABLE)26 b(exten-)120 3681 y(sion.)39 b(The)27
+b(expression)f(also)i(can)f(b)s(e)g(written)g(in)m(to)h(a)f(text)i
+(\014le)e(and)g(then)g(used)g(b)m(y)g(giving)f(the)i(\014lename)120
+3794 y(preceded)i(b)m(y)g(a)h('@')g(c)m(haracter,)h(as)e(in)f
+Fc('[@rowfilt.txt]')p Fg(.)261 3907 y(Keyw)m(ord)40 b(and)f(column)g
+(data)h(are)h(referenced)f(b)m(y)f(name.)70 b(An)m(y)40
+b(string)f(of)h(c)m(haracters)h(not)f(sur-)120 4020 y(rounded)30
+b(b)m(y)i(quotes)g(\(ie,)g(a)h(constan)m(t)g(string\))e(or)g(follo)m(w)
+m(ed)h(b)m(y)f(an)h(op)s(en)f(paren)m(theses)h(\(ie,)h(a)f(function)120
+4133 y(name\))e(will)c(b)s(e)j(initially)c(in)m(terpreted)k(as)g(a)h
+(column)e(name)h(and)g(its)g(con)m(ten)m(ts)i(for)e(the)g(curren)m(t)g
+(ro)m(w)g(in-)120 4246 y(serted)e(in)m(to)g(the)h(expression.)38
+b(If)27 b(no)g(suc)m(h)g(column)f(exists,)i(a)f(k)m(eyw)m(ord)h(of)g
+(that)f(name)h(will)c(b)s(e)j(searc)m(hed)120 4359 y(for)34
+b(and)f(its)g(v)-5 b(alue)34 b(used,)g(if)f(found.)50
+b(T)-8 b(o)35 b(force)f(the)g(name)g(to)h(b)s(e)e(in)m(terpreted)g(as)i
+(a)f(k)m(eyw)m(ord)g(\(in)f(case)120 4472 y(there)28
+b(is)f(b)s(oth)g(a)h(column)f(and)g(k)m(eyw)m(ord)h(with)f(the)h(same)g
+(name\),)h(precede)f(the)g(k)m(eyw)m(ord)h(name)e(with)g(a)120
+4584 y(single)j(p)s(ound)f(sign,)i('#',)h(as)g(in)e Fc(#NAXIS2)p
+Fg(.)41 b(Due)32 b(to)g(the)f(generalities)g(of)g(FITS)g(column)f(and)h
+(k)m(eyw)m(ord)120 4697 y(names,)c(if)d(the)i(column)f(or)g(k)m(eyw)m
+(ord)h(name)g(con)m(tains)g(a)g(space)g(or)g(a)g(c)m(haracter)h(whic)m
+(h)e(migh)m(t)g(app)s(ear)g(as)120 4810 y(an)32 b(arithmetic)f(term)h
+(then)g(inclose)f(the)h(name)g(in)e('$')j(c)m(haracters)h(as)e(in)f
+Fc($MAX)46 b(PHA$)31 b Fg(or)h Fc(#$MAX-PHA$)p Fg(.)120
+4923 y(The)e(names)g(are)h(case)g(insensitiv)m(e.)261
+5036 y(T)-8 b(o)37 b(access)g(a)g(table)f(en)m(try)h(in)e(a)h(ro)m(w)h
+(other)f(than)g(the)h(curren)m(t)f(one,)i(follo)m(w)e(the)g(column's)f
+(name)120 5149 y(with)j(a)h(ro)m(w)g(o\013set)g(within)e(curly)g
+(braces.)66 b(F)-8 b(or)40 b(example,)h Fc('PHA)p Fa(f)p
+Fc(-3)p Fa(g)p Fc(')d Fg(will)e(ev)-5 b(aluate)39 b(to)h(the)f(v)-5
+b(alue)120 5262 y(of)40 b(column)e(PHA,)i(3)g(ro)m(ws)f(ab)s(o)m(v)m(e)
+i(the)f(ro)m(w)g(curren)m(tly)e(b)s(eing)g(pro)s(cessed.)68
+b(One)39 b(cannot)h(sp)s(ecify)e(an)120 5375 y(absolute)32
+b(ro)m(w)g(n)m(um)m(b)s(er,)f(only)g(a)i(relativ)m(e)f(o\013set.)47
+b(Ro)m(ws)32 b(that)h(fall)d(outside)h(the)i(table)f(will)d(b)s(e)i
+(treated)120 5488 y(as)g(unde\014ned,)d(or)i(NULLs.)1905
+5809 y(29)p eop
+%%Page: 30 30
+30 29 bop 261 573 a Fg(Bo)s(olean)31 b(op)s(erators)g(can)g(b)s(e)g
+(used)f(in)f(the)i(expression)f(in)f(either)i(their)f(F)-8
+b(ortran)31 b(or)g(C)f(forms.)42 b(The)120 686 y(follo)m(wing)29
+b(b)s(o)s(olean)g(op)s(erators)i(are)g(a)m(v)-5 b(ailable:)311
+886 y Fc("equal")428 b(.eq.)46 b(.EQ.)h(==)95 b("not)46
+b(equal")476 b(.ne.)94 b(.NE.)h(!=)311 999 y("less)46
+b(than")238 b(.lt.)46 b(.LT.)h(<)143 b("less)46 b(than/equal")188
+b(.le.)94 b(.LE.)h(<=)47 b(=<)311 1112 y("greater)e(than")95
+b(.gt.)46 b(.GT.)h(>)143 b("greater)45 b(than/equal")g(.ge.)94
+b(.GE.)h(>=)47 b(=>)311 1225 y("or")572 b(.or.)46 b(.OR.)h(||)95
+b("and")762 b(.and.)46 b(.AND.)h(&&)311 1337 y("negation")236
+b(.not.)46 b(.NOT.)h(!)95 b("approx.)45 b(equal\(1e-7\)")92
+b(~)261 1537 y Fg(Note)34 b(that)g(the)f(exclamation)g(p)s(oin)m(t,)g
+(')10 b(!',)34 b(is)e(a)i(sp)s(ecial)d(UNIX)i(c)m(haracter,)j(so)d(if)f
+(it)g(is)g(used)g(on)h(the)120 1650 y(command)f(line)f(rather)h(than)g
+(en)m(tered)h(at)g(a)g(task)g(prompt,)f(it)g(m)m(ust)g(b)s(e)g
+(preceded)g(b)m(y)g(a)h(bac)m(kslash)f(to)120 1763 y(force)f(the)g
+(UNIX)f(shell)f(to)i(ignore)f(it.)261 1876 y(The)d(expression)e(ma)m(y)
+j(also)f(include)e(arithmetic)h(op)s(erators)h(and)f(functions.)38
+b(T)-8 b(rigonometric)27 b(func-)120 1989 y(tions)g(use)h(radians,)g
+(not)g(degrees.)40 b(The)28 b(follo)m(wing)f(arithmetic)g(op)s(erators)
+h(and)g(functions)e(can)j(b)s(e)e(used)120 2102 y(in)i(the)i
+(expression)e(\(function)g(names)h(are)h(case)h(insensitiv)m(e\):)311
+2302 y Fc("addition")522 b(+)477 b("subtraction")d(-)311
+2415 y("multiplication")234 b(*)477 b("division")618
+b(/)311 2528 y("negation")522 b(-)477 b("exponentiation")330
+b(**)143 b(^)311 2641 y("absolute)45 b(value")237 b(abs\(x\))g
+("cosine")714 b(cos\(x\))311 2754 y("sine")g(sin\(x\))237
+b("tangent")666 b(tan\(x\))311 2867 y("arc)47 b(cosine")427
+b(arccos\(x\))93 b("arc)47 b(sine")619 b(arcsin\(x\))311
+2979 y("arc)47 b(tangent")379 b(arctan\(x\))93 b("arc)47
+b(tangent")475 b(arctan2\(x,y\))311 3092 y("exponential")378
+b(exp\(x\))237 b("square)46 b(root")476 b(sqrt\(x\))311
+3205 y("natural)45 b(log")381 b(log\(x\))237 b("common)46
+b(log")524 b(log10\(x\))311 3318 y("modulus")570 b(i)48
+b(\045)f(j)286 b("random)46 b(#)h([0.0,1.0\)")141 b(random\(\))311
+3431 y("minimum")570 b(min\(x,y\))141 b("maximum")666
+b(max\(x,y\))311 3544 y("if-then-else")330 b(b?x:y)261
+3744 y Fg(The)37 b(follo)m(wing)f(t)m(yp)s(e)i(casting)f(op)s(erators)h
+(are)g(a)m(v)-5 b(ailable,)38 b(where)f(the)h(inclosing)d(paren)m
+(theses)j(are)120 3857 y(required)22 b(and)i(tak)m(en)h(from)f(the)h(C)
+f(language)g(usage.)40 b(Also,)25 b(the)f(in)m(teger)h(to)g(real)f
+(casts)h(v)-5 b(alues)24 b(to)h(double)120 3970 y(precision:)884
+4170 y Fc("real)46 b(to)h(integer")189 b(\(int\))46 b(x)239
+b(\(INT\))46 b(x)884 4283 y("integer)f(to)i(real")190
+b(\(float\))46 b(i)143 b(\(FLOAT\))45 b(i)261 4483 y
+Fg(Sev)m(eral)31 b(constan)m(ts)g(are)g(built)d(in)h(for)h(use)g(in)f
+(n)m(umerical)g(expressions:)502 4683 y Fc(#pi)667 b(3.1415...)284
+b(#e)620 b(2.7182...)502 4796 y(#deg)f(#pi/180)380 b(#row)524
+b(current)46 b(row)h(number)502 4909 y(#null)428 b(undefined)45
+b(value)142 b(#snull)428 b(undefined)45 b(string)261
+5109 y Fg(A)d(string)f(constan)m(t)i(m)m(ust)f(b)s(e)f(enclosed)h(in)f
+(quotes)h(as)g(in)f('Crab'.)75 b(The)41 b("n)m(ull")g(constan)m(ts)i
+(are)120 5222 y(useful)36 b(for)h(conditionally)e(setting)j(table)f(v)
+-5 b(alues)37 b(to)h(a)g(NULL,)g(or)f(unde\014ned,)h(v)-5
+b(alue)37 b(\(F)-8 b(or)38 b(example,)120 5334 y Fc("col1==-99)45
+b(?)95 b(#NULL)47 b(:)g(col1")p Fg(\).)261 5447 y(There)33
+b(is)g(also)g(a)h(function)f(for)g(testing)h(if)e(t)m(w)m(o)j(v)-5
+b(alues)33 b(are)h(close)g(to)g(eac)m(h)h(other,)g(i.e.,)g(if)d(they)i
+(are)120 5560 y("near")29 b(eac)m(h)g(other)f(to)g(within)e(a)i(user)f
+(sp)s(eci\014ed)f(tolerance.)41 b(The)27 b(argumen)m(ts,)i
+Fc(value)p 3184 5560 29 4 v 33 w(1)e Fg(and)h Fc(value)p
+3707 5560 V 33 w(2)1905 5809 y Fg(30)p eop
+%%Page: 31 31
+31 30 bop 120 573 a Fg(can)39 b(b)s(e)g(in)m(teger)g(or)g(real)f(and)h
+(represen)m(t)g(the)g(t)m(w)m(o)h(v)-5 b(alues)38 b(who's)h(pro)m
+(ximit)m(y)f(is)g(b)s(eing)g(tested)h(to)h(b)s(e)120
+686 y(within)28 b(the)i(sp)s(eci\014ed)f(tolerance,)i(also)g(an)f(in)m
+(teger)h(or)f(real:)1075 880 y Fc(near\(value_1,)44 b(value_2,)h
+(tolerance\))261 1074 y Fg(When)30 b(a)h(NULL,)f(or)h(unde\014ned,)d(v)
+-5 b(alue)30 b(is)f(encoun)m(tered)i(in)e(the)h(FITS)g(table,)g(the)h
+(expression)e(will)120 1186 y(ev)-5 b(aluate)42 b(to)g(NULL)g(unless)d
+(the)j(unde\014ned)d(v)-5 b(alue)41 b(is)g(not)g(actually)g(required)f
+(for)h(ev)-5 b(aluation,)44 b(e.g.)120 1299 y("TR)m(UE)e(.or.)76
+b(NULL")42 b(ev)-5 b(aluates)43 b(to)g(TR)m(UE.)f(The)f(follo)m(wing)g
+(t)m(w)m(o)i(functions)e(allo)m(w)g(some)h(NULL)120 1412
+y(detection)31 b(and)f(handling:)1027 1606 y Fc(ISNULL\(x\))1027
+1719 y(DEFNULL\(x,y\))261 1913 y Fg(The)43 b(former)g(returns)f(a)i(b)s
+(o)s(olean)e(v)-5 b(alue)43 b(of)g(TR)m(UE)h(if)e(the)i(argumen)m(t)f
+(x)h(is)e(NULL.)i(The)e(later)120 2026 y("de\014nes")e(a)g(v)-5
+b(alue)39 b(to)h(b)s(e)g(substituted)e(for)h(NULL)h(v)-5
+b(alues;)44 b(it)39 b(returns)f(the)i(v)-5 b(alue)40
+b(of)f(x)h(if)f(x)g(is)g(not)120 2139 y(NULL,)31 b(otherwise)e(it)h
+(returns)f(the)i(v)-5 b(alue)30 b(of)g(y)-8 b(.)261 2252
+y(Bit)31 b(masks)g(can)g(b)s(e)f(used)g(to)h(select)h(out)f(ro)m(ws)g
+(from)f(bit)g(columns)f(\()p Fc(TFORMn)47 b(=)g(#X)p
+Fg(\))31 b(in)e(FITS)h(\014les.)120 2365 y(T)-8 b(o)31
+b(represen)m(t)f(the)h(mask,)f(binary)-8 b(,)30 b(o)s(ctal,)h(and)e
+(hex)i(formats)f(are)h(allo)m(w)m(ed:)931 2558 y Fc(binary:)142
+b(b0110xx1010000101xxxx00)o(01)931 2671 y(octal:)190
+b(o720x1)46 b(->)h(\(b111010000xxx001\))931 2784 y(hex:)286
+b(h0FxD)94 b(->)47 b(\(b00001111xxxx1101\))261 2978 y
+Fg(In)28 b(all)g(the)i(represen)m(tations,)f(an)g(x)g(or)g(X)g(is)f
+(allo)m(w)m(ed)h(in)f(the)h(mask)g(as)h(a)f(wild)e(card.)40
+b(Note)30 b(that)g(the)120 3091 y(x)i(represen)m(ts)f(a)h(di\013eren)m
+(t)f(n)m(um)m(b)s(er)g(of)h(wild)d(card)j(bits)e(in)g(eac)m(h)j
+(represen)m(tation.)45 b(All)30 b(represen)m(tations)120
+3204 y(are)h(case)g(insensitiv)m(e.)261 3317 y(T)-8 b(o)38
+b(construct)f(the)h(b)s(o)s(olean)e(expression)g(using)g(the)h(mask)h
+(as)f(the)h(b)s(o)s(olean)e(equal)h(op)s(erator)g(de-)120
+3430 y(scrib)s(ed)29 b(ab)s(o)m(v)m(e)i(on)g(a)g(bit)f(table)g(column.)
+40 b(F)-8 b(or)32 b(example,)e(if)g(y)m(ou)h(had)f(a)h(7)g(bit)e
+(column)h(named)g(\015ags)h(in)120 3543 y(a)36 b(FITS)e(table)i(and)f
+(w)m(an)m(ted)h(all)e(ro)m(ws)h(ha)m(ving)g(the)h(bit)e(pattern)i
+(0010011,)k(the)35 b(selection)h(expression)120 3656
+y(w)m(ould)29 b(b)s(e:)1456 3850 y Fc(flags)47 b(==)g(b0010011)311
+3962 y(or)1456 4075 y(flags)g(.eq.)f(b10011)261 4269
+y Fg(It)32 b(is)e(also)i(p)s(ossible)d(to)j(test)g(if)f(a)h(range)f(of)
+h(bits)e(is)h(less)g(than,)g(less)g(than)h(equal,)f(greater)i(than)e
+(and)120 4382 y(greater)h(than)e(equal)g(to)h(a)f(particular)f(b)s(o)s
+(olean)h(v)-5 b(alue:)1456 4576 y Fc(flags)47 b(<=)g(bxxx010xx)1456
+4689 y(flags)g(.gt.)f(bxxx100xx)1456 4802 y(flags)h(.le.)f(b1xxxxxxx)
+261 4996 y Fg(Notice)31 b(the)g(use)f(of)h(the)f(x)h(bit)e(v)-5
+b(alue)30 b(to)h(limit)d(the)j(range)f(of)h(bits)e(b)s(eing)g
+(compared.)261 5109 y(It)k(is)f(not)h(necessary)g(to)g(sp)s(ecify)f
+(the)g(leading)g(\(most)h(signi\014can)m(t\))f(zero)i(\(0\))g(bits)d
+(in)h(the)h(mask,)g(as)120 5222 y(sho)m(wn)d(in)f(the)h(second)h
+(expression)e(ab)s(o)m(v)m(e.)261 5334 y(Bit)h(wise)f(AND,)h(OR)g(and)f
+(NOT)g(op)s(erations)g(are)h(also)g(p)s(ossible)d(on)i(t)m(w)m(o)i(or)f
+(more)g(bit)f(\014elds)f(using)120 5447 y(the)38 b('&'\(AND\),)h(')p
+Fa(j)p Fg('\(OR\),)g(and)e(the)h(')10 b(!'\(NOT\))38
+b(op)s(erators.)63 b(All)36 b(of)i(these)g(op)s(erators)g(result)e(in)g
+(a)i(bit)120 5560 y(\014eld)29 b(whic)m(h)g(can)i(then)f(b)s(e)g(used)f
+(with)g(the)i(equal)f(op)s(erator.)41 b(F)-8 b(or)31
+b(example:)1905 5809 y(31)p eop
+%%Page: 32 32
+32 31 bop 1361 573 a Fc(\(!flags\))45 b(==)j(b1101100)1361
+686 y(\(flags)e(&)h(b1000001\))f(==)h(bx000001)261 887
+y Fg(Bit)35 b(\014elds)e(can)h(b)s(e)g(app)s(ended)f(as)i(w)m(ell)e
+(using)g(the)i('+')g(op)s(erator.)53 b(Strings)33 b(can)i(b)s(e)f
+(concatenated)120 1000 y(this)29 b(w)m(a)m(y)-8 b(,)32
+b(to)s(o.)120 1238 y Fh(5.4.3)105 b(Go)s(o)s(d)36 b(Time)e(In)m(terv)-6
+b(al)34 b(Filtering)120 1410 y Fg(A)27 b(common)g(\014ltering)e(metho)s
+(d)i(in)m(v)m(olv)m(es)g(selecting)g(ro)m(ws)f(whic)m(h)g(ha)m(v)m(e)i
+(a)g(time)e(v)-5 b(alue)27 b(whic)m(h)e(lies)h(within)120
+1523 y(what)38 b(is)e(called)h(a)h(Go)s(o)s(d)g(Time)e(In)m(terv)-5
+b(al)38 b(or)f(GTI.)h(The)f(time)h(in)m(terv)-5 b(als)36
+b(are)i(de\014ned)f(in)f(a)i(separate)120 1636 y(FITS)31
+b(table)h(extension)f(whic)m(h)g(con)m(tains)h(2)g(columns)e(giving)h
+(the)h(start)g(and)f(stop)h(time)g(of)g(eac)m(h)g(go)s(o)s(d)120
+1749 y(in)m(terv)-5 b(al.)59 b(The)37 b(\014ltering)e(op)s(eration)h
+(accepts)i(only)e(those)h(ro)m(ws)g(of)g(the)g(input)e(table)i(whic)m
+(h)e(ha)m(v)m(e)j(an)120 1861 y(asso)s(ciated)31 b(time)g(whic)m(h)f
+(falls)f(within)f(one)k(of)f(the)g(time)f(in)m(terv)-5
+b(als)30 b(de\014ned)g(in)g(the)h(GTI)f(extension.)42
+b(A)120 1974 y(high)28 b(lev)m(el)i(function,)f
+(gti\014lter\(a,b,c,d\),)i(is)d(a)m(v)-5 b(ailable)30
+b(whic)m(h)e(ev)-5 b(aluates)31 b(eac)m(h)g(ro)m(w)f(of)g(the)g(input)d
+(table)120 2087 y(and)j(returns)g(TR)m(UE)g(or)h(F)-10
+b(ALSE)30 b(dep)s(ending)f(whether)h(the)g(ro)m(w)h(is)f(inside)e(or)j
+(outside)f(the)h(go)s(o)s(d)g(time)120 2200 y(in)m(terv)-5
+b(al.)40 b(The)30 b(syn)m(tax)h(is)406 2401 y Fc(gtifilter\()45
+b([)j("gtifile")d([,)i(expr)g([,)g("STARTCOL",)e("STOPCOL")g(])j(])f(])
+g(\))120 2603 y Fg(where)35 b(eac)m(h)i("[]")g(demarks)e(optional)f
+(parameters.)57 b(Note)37 b(that)f(the)g(quotes)g(around)e(the)i
+(gti\014le)f(and)120 2716 y(ST)-8 b(AR)g(T/STOP)31 b(column)h(are)h
+(required.)45 b(Either)32 b(single)f(or)h(double)g(quote)h(c)m
+(haracters)h(ma)m(y)f(b)s(e)f(used.)120 2828 y(The)c(gti\014le,)g(if)f
+(sp)s(eci\014ed,)h(can)g(b)s(e)g(blank)f(\(""\))j(whic)m(h)d(will)f
+(mean)j(to)g(use)f(the)g(\014rst)g(extension)g(with)f(the)120
+2941 y(name)c("*GTI*")i(in)d(the)h(curren)m(t)g(\014le,)h(a)f(plain)e
+(extension)i(sp)s(eci\014er)f(\(eg,)k("+2",)f("[2]",)i(or)c
+("[STDGTI]"\))120 3054 y(whic)m(h)f(will)f(b)s(e)i(used)g(to)i(select)f
+(an)g(extension)f(in)f(the)i(curren)m(t)g(\014le,)g(or)g(a)g(regular)e
+(\014lename)h(with)g(or)g(with-)120 3167 y(out)j(an)g(extension)g(sp)s
+(eci\014er)e(whic)m(h)h(in)f(the)j(latter)f(case)h(will)c(mean)j(to)h
+(use)f(the)g(\014rst)f(extension)h(with)e(an)120 3280
+y(extension)29 b(name)h("*GTI*".)42 b(Expr)28 b(can)i(b)s(e)f(an)m(y)g
+(arithmetic)g(expression,)g(including)d(simply)h(the)j(time)120
+3393 y(column)j(name.)52 b(A)34 b(v)m(ector)i(time)e(expression)f(will)
+e(pro)s(duce)i(a)i(v)m(ector)g(b)s(o)s(olean)f(result.)50
+b(ST)-8 b(AR)g(TCOL)120 3506 y(and)33 b(STOPCOL)f(are)j(the)f(names)g
+(of)g(the)g(ST)-8 b(AR)g(T/STOP)33 b(columns)g(in)f(the)j(GTI)e
+(extension.)52 b(If)33 b(one)120 3619 y(of)e(them)f(is)f(sp)s
+(eci\014ed,)g(they)i(b)s(oth)e(m)m(ust)i(b)s(e.)261 3732
+y(In)37 b(its)h(simplest)e(form,)k(no)e(parameters)g(need)g(to)h(b)s(e)
+e(pro)m(vided)g({)h(default)g(v)-5 b(alues)37 b(will)e(b)s(e)j(used.)
+120 3845 y(The)30 b(expression)f Fc("gtifilter\(\)")e
+Fg(is)i(equiv)-5 b(alen)m(t)30 b(to)454 4046 y Fc(gtifilter\()45
+b("",)i(TIME,)f("*START*",)f("*STOP*")h(\))120 4247 y
+Fg(This)30 b(will)g(searc)m(h)j(the)f(curren)m(t)g(\014le)g(for)g(a)g
+(GTI)g(extension,)h(\014lter)e(the)h(TIME)g(column)f(in)g(the)i(curren)
+m(t)120 4360 y(table,)47 b(using)c(ST)-8 b(AR)g(T/STOP)43
+b(times)g(tak)m(en)i(from)e(columns)g(in)g(the)h(GTI)f(extension)h
+(with)e(names)120 4473 y(con)m(taining)30 b(the)h(strings)e("ST)-8
+b(AR)g(T")31 b(and)f("STOP".)41 b(The)30 b(wildcards)e(\('*'\))k(allo)m
+(w)e(sligh)m(t)f(v)-5 b(ariations)30 b(in)120 4586 y(naming)h(con)m(v)m
+(en)m(tions)h(suc)m(h)g(as)g("TST)-8 b(AR)g(T")32 b(or)g("ST)-8
+b(AR)g(TTIME".)45 b(The)31 b(same)i(default)e(v)-5 b(alues)31
+b(apply)120 4699 y(for)g(unsp)s(eci\014ed)e(parameters)j(when)e(the)i
+(\014rst)e(one)i(or)f(t)m(w)m(o)i(parameters)f(are)g(sp)s(eci\014ed.)42
+b(The)31 b(function)120 4812 y(automatically)41 b(searc)m(hes)g(for)g
+(TIMEZER)m(O/I/F)g(k)m(eyw)m(ords)g(in)e(the)i(curren)m(t)g(and)f(GTI)h
+(extensions,)120 4924 y(applying)28 b(a)j(relativ)m(e)f(time)h
+(o\013set,)g(if)f(necessary)-8 b(.)120 5163 y Fh(5.4.4)105
+b(Spatial)35 b(Region)h(Filtering)120 5334 y Fg(Another)f(common)h
+(\014ltering)e(metho)s(d)h(selects)g(ro)m(ws)h(based)f(on)g(whether)g
+(the)h(spatial)e(p)s(osition)f(asso-)120 5447 y(ciated)40
+b(with)f(eac)m(h)j(ro)m(w)e(is)f(lo)s(cated)h(within)e(a)i(giv)m(en)h
+(2-dimensional)d(region.)69 b(The)40 b(syn)m(tax)h(for)e(this)120
+5560 y(high-lev)m(el)29 b(\014lter)h(is)1905 5809 y(32)p
+eop
+%%Page: 33 33
+33 32 bop 454 573 a Fc(regfilter\()45 b("regfilename")f([)k(,)f(Xexpr,)
+f(Yexpr)h([)g(,)h("wcs)e(cols")h(])g(])g(\))120 757 y
+Fg(where)28 b(eac)m(h)i("[)g(]")f(demarks)g(optional)f(parameters.)40
+b(The)29 b(region)f(\014le)g(name)h(is)f(required)f(and)h(m)m(ust)h(b)s
+(e)120 870 y(enclosed)g(in)f(quotes.)41 b(The)29 b(remaining)e
+(parameters)j(are)f(optional.)40 b(The)29 b(region)g(\014le)f(is)g(an)i
+(ASCI)s(I)d(text)120 983 y(\014le)36 b(whic)m(h)f(con)m(tains)i(a)g
+(list)f(of)g(one)h(or)g(more)g(geometric)h(shap)s(es)d(\(circle,)k
+(ellipse,)d(b)s(o)m(x,)i(etc.\))62 b(whic)m(h)120 1096
+y(de\014nes)30 b(a)i(region)f(on)g(the)h(celestial)f(sphere)g(or)g(an)g
+(area)h(within)d(a)j(particular)e(2D)i(image.)44 b(The)31
+b(region)120 1209 y(\014le)37 b(is)g(t)m(ypically)g(generated)i(using)e
+(an)h(image)g(displa)m(y)f(program)h(suc)m(h)f(as)i(fv/PO)m(W)f
+(\(distribute)e(b)m(y)120 1322 y(the)c(HEASAR)m(C\),)g(or)g(ds9)g
+(\(distributed)d(b)m(y)i(the)h(Smithsonian)e(Astroph)m(ysical)g(Observ)
+-5 b(atory\).)46 b(Users)120 1435 y(should)40 b(refer)i(to)h(the)f(do)s
+(cumen)m(tation)g(pro)m(vided)f(with)g(these)h(programs)g(for)g(more)g
+(details)f(on)h(the)120 1548 y(syn)m(tax)31 b(used)e(in)h(the)g(region)
+g(\014les.)261 1661 y(In)35 b(its)g(simpliest)e(form,)k(\(e.g.,)i
+Fc(regfilter\("region.reg"\))30 b Fg(\))36 b(the)f(co)s(ordinates)h(in)
+e(the)i(default)120 1774 y('X')24 b(and)e('Y')i(columns)d(will)g(b)s(e)
+h(used)g(to)i(determine)e(if)g(eac)m(h)i(ro)m(w)f(is)f(inside)f(or)i
+(outside)f(the)h(area)h(sp)s(eci\014ed)120 1886 y(in)g(the)i(region)f
+(\014le.)38 b(Alternate)26 b(p)s(osition)d(column)h(names,)j(or)e
+(expressions,)g(ma)m(y)h(b)s(e)f(en)m(tered)h(if)e(needed,)120
+1999 y(as)31 b(in)502 2184 y Fc(regfilter\("region.reg",)41
+b(XPOS,)47 b(YPOS\))120 2368 y Fg(Region)38 b(\014ltering)f(can)h(b)s
+(e)g(applied)e(most)i(unam)m(biguously)e(if)h(the)h(p)s(ositions)f(in)f
+(the)j(region)f(\014le)f(and)120 2481 y(in)e(the)i(table)g(to)h(b)s(e)e
+(\014ltered)g(are)h(b)s(oth)f(giv)m(e)h(in)f(terms)g(of)h(absolute)g
+(celestial)f(co)s(ordinate)h(units.)58 b(In)120 2594
+y(this)37 b(case)i(the)g(lo)s(cations)f(and)f(sizes)h(of)h(the)f
+(geometric)h(shap)s(es)f(in)f(the)h(region)g(\014le)f(are)i(sp)s
+(eci\014ed)e(in)120 2707 y(angular)d(units)f(on)h(the)h(sky)f(\(e.g.,)j
+(p)s(ositions)c(giv)m(en)i(in)e(R.A.)i(and)f(Dec.)54
+b(and)34 b(sizes)g(in)f(arcseconds)i(or)120 2820 y(arcmin)m(utes\).)j
+(Similarly)-8 b(,)20 b(eac)m(h)j(ro)m(w)g(of)f(the)g(\014ltered)f
+(table)h(will)d(ha)m(v)m(e)k(a)g(celestial)e(co)s(ordinate)h(asso)s
+(ciated)120 2933 y(with)32 b(it.)50 b(This)32 b(asso)s(ciation)h(is)g
+(usually)e(implemen)m(ted)h(using)h(a)g(set)i(of)e(so-called)h('W)-8
+b(orld)33 b(Co)s(ordinate)120 3046 y(System')j(\(or)h(W)m(CS\))f(FITS)f
+(k)m(eyw)m(ords)i(that)f(de\014ne)g(the)g(co)s(ordinate)g
+(transformation)f(that)i(m)m(ust)f(b)s(e)120 3159 y(applied)28
+b(to)j(the)g(v)-5 b(alues)30 b(in)f(the)h('X')h(and)f('Y')h(columns)e
+(to)i(calculate)g(the)f(co)s(ordinate.)261 3272 y(Alternativ)m(ely)-8
+b(,)37 b(one)f(can)f(p)s(erform)f(spatial)h(\014ltering)e(using)h
+(unitless)g('pixel')g(co)s(ordinates)h(for)g(the)120
+3385 y(regions)30 b(and)g(ro)m(w)h(p)s(ositions.)40 b(In)30
+b(this)f(case)j(the)f(user)f(m)m(ust)h(b)s(e)f(careful)g(to)h(ensure)f
+(that)h(the)g(p)s(ositions)120 3498 y(in)h(the)h(2)h(\014les)e(are)i
+(self-consisten)m(t.)49 b(A)34 b(t)m(ypical)e(problem)g(is)g(that)i
+(the)g(region)f(\014le)f(ma)m(y)i(b)s(e)e(generated)120
+3610 y(using)22 b(a)i(binned)e(image,)j(but)e(the)h(un)m(binned)d(co)s
+(ordinates)i(are)i(giv)m(en)e(in)g(the)h(ev)m(en)m(t)h(table.)38
+b(The)24 b(R)m(OSA)-8 b(T)120 3723 y(ev)m(en)m(ts)34
+b(\014les,)f(for)g(example,)h(ha)m(v)m(e)g(X)f(and)g(Y)g(pixel)e(co)s
+(ordinates)i(that)h(range)f(from)g(1)g(-)h(15360.)51
+b(These)120 3836 y(co)s(ordinates)32 b(are)h(t)m(ypically)f(binned)e(b)
+m(y)j(a)g(factor)g(of)g(32)h(to)f(pro)s(duce)f(a)h(480x480)i(pixel)c
+(image.)48 b(If)32 b(one)120 3949 y(then)f(uses)g(a)g(region)g(\014le)f
+(generated)j(from)d(this)g(image)i(\(in)e(image)h(pixel)f(units\))g(to)
+i(\014lter)e(the)i(R)m(OSA)-8 b(T)120 4062 y(ev)m(en)m(ts)33
+b(\014le,)e(then)g(the)g(X)g(and)g(Y)h(column)e(v)-5
+b(alues)30 b(m)m(ust)i(b)s(e)e(con)m(v)m(erted)j(to)f(corresp)s(onding)
+d(pixel)h(units)120 4175 y(as)h(in:)502 4360 y Fc
+(regfilter\("rosat.reg",)42 b(X/32.+.5,)j(Y/32.+.5\))120
+4544 y Fg(Note)30 b(that)f(this)e(binning)f(con)m(v)m(ersion)i(is)g
+(not)h(necessary)g(if)e(the)i(region)f(\014le)f(is)h(sp)s(eci\014ed)f
+(using)g(celestial)120 4657 y(co)s(ordinate)g(units)f(instead)g(of)h
+(pixel)f(units)f(b)s(ecause)i(CFITSIO)f(is)g(then)h(able)g(to)h
+(directly)d(compare)j(the)120 4770 y(celestial)34 b(co)s(ordinate)g(of)
+g(eac)m(h)h(ro)m(w)f(in)f(the)h(table)g(with)f(the)h(celestial)g(co)s
+(ordinates)g(in)e(the)j(region)e(\014le)120 4883 y(without)c(ha)m(ving)
+h(to)h(kno)m(w)g(an)m(ything)f(ab)s(out)g(ho)m(w)g(the)h(image)f(ma)m
+(y)h(ha)m(v)m(e)h(b)s(een)d(binned.)261 4996 y(The)k(last)g("w)m(cs)g
+(cols")h(parameter)f(should)e(rarely)h(b)s(e)h(needed.)48
+b(If)33 b(supplied,)d(this)i(string)g(con)m(tains)120
+5109 y(the)39 b(names)g(of)h(the)f(2)g(columns)f(\(space)i(or)f(comma)h
+(separated\))g(whic)m(h)e(ha)m(v)m(e)i(the)g(asso)s(ciated)f(W)m(CS)120
+5222 y(k)m(eyw)m(ords.)k(If)30 b(not)h(supplied,)d(the)j(\014lter)f
+(will)e(scan)j(the)g(X)g(and)g(Y)g(expressions)e(for)i(column)f(names.)
+42 b(If)120 5334 y(only)32 b(one)g(is)g(found)f(in)g(eac)m(h)j
+(expression,)e(those)h(columns)e(will)f(b)s(e)i(used,)h(otherwise)f(an)
+g(error)g(will)e(b)s(e)120 5447 y(returned.)261 5560
+y(These)g(region)g(shap)s(es)g(are)g(supp)s(orted)f(\(names)i(are)f
+(case)i(insensitiv)m(e\):)1905 5809 y(33)p eop
+%%Page: 34 34
+34 33 bop 454 573 a Fc(Point)428 b(\()48 b(X1,)f(Y1)g(\))715
+b(<-)48 b(One)f(pixel)f(square)g(region)454 686 y(Line)476
+b(\()48 b(X1,)f(Y1,)g(X2,)f(Y2)i(\))333 b(<-)48 b(One)f(pixel)f(wide)h
+(region)454 799 y(Polygon)332 b(\()48 b(X1,)f(Y1,)g(X2,)f(Y2,)h(...)g
+(\))95 b(<-)48 b(Rest)e(are)h(interiors)e(with)454 912
+y(Rectangle)236 b(\()48 b(X1,)f(Y1,)g(X2,)f(Y2,)h(A)h(\))334
+b(|)47 b(boundaries)e(considered)454 1024 y(Box)524 b(\()48
+b(Xc,)f(Yc,)g(Wdth,)f(Hght,)g(A)i(\))143 b(V)47 b(within)f(the)h
+(region)454 1137 y(Diamond)332 b(\()48 b(Xc,)f(Yc,)g(Wdth,)f(Hght,)g(A)
+i(\))454 1250 y(Circle)380 b(\()48 b(Xc,)f(Yc,)g(R)g(\))454
+1363 y(Annulus)332 b(\()48 b(Xc,)f(Yc,)g(Rin,)f(Rout)h(\))454
+1476 y(Ellipse)332 b(\()48 b(Xc,)f(Yc,)g(Rx,)f(Ry,)h(A)h(\))454
+1589 y(Elliptannulus)c(\()k(Xc,)f(Yc,)g(Rinx,)f(Riny,)g(Routx,)g
+(Routy,)g(Ain,)h(Aout)g(\))454 1702 y(Sector)380 b(\()48
+b(Xc,)f(Yc,)g(Amin,)f(Amax)h(\))120 1914 y Fg(where)33
+b(\(Xc,Yc\))j(is)d(the)i(co)s(ordinate)e(of)i(the)f(shap)s(e's)f(cen)m
+(ter;)k(\(X#,Y#\))e(are)f(the)g(co)s(ordinates)g(of)g(the)120
+2027 y(shap)s(e's)22 b(edges;)k(Rxxx)d(are)g(the)h(shap)s(es')e(v)-5
+b(arious)22 b(Radii)f(or)i(semima)5 b(jor/minor)21 b(axes;)27
+b(and)22 b(Axxx)h(are)g(the)120 2140 y(angles)i(of)g(rotation)g(\(or)g
+(b)s(ounding)d(angles)j(for)g(Sector\))h(in)d(degrees.)40
+b(F)-8 b(or)26 b(rotated)g(shap)s(es,)f(the)g(rotation)120
+2253 y(angle)36 b(can)h(b)s(e)e(left)h(o\013,)i(indicating)c(no)i
+(rotation.)59 b(Common)35 b(alternate)i(names)f(for)g(the)g(regions)g
+(can)120 2366 y(also)27 b(b)s(e)f(used:)39 b(rotb)s(o)m(x)27
+b(=)f(b)s(o)m(x;)j(rotrectangle)f(=)f(rectangle;)i(\(rot\)rhom)m(bus)d
+(=)h(\(rot\)diamond;)h(and)e(pie)120 2479 y(=)h(sector.)41
+b(When)28 b(a)g(shap)s(e's)f(name)g(is)g(preceded)g(b)m(y)h(a)g(min)m
+(us)e(sign,)i('-',)h(the)f(de\014ned)e(region)h(is)g(instead)120
+2592 y(the)36 b(area)g(*outside*)g(its)f(b)s(oundary)e(\(ie,)k(the)f
+(region)f(is)g(in)m(v)m(erted\).)56 b(All)34 b(the)i(shap)s(es)f
+(within)e(a)j(single)120 2705 y(region)e(\014le)g(are)h(OR'd)g
+(together)h(to)f(create)i(the)e(region,)g(and)g(the)g(order)f(is)g
+(signi\014can)m(t.)53 b(The)34 b(o)m(v)m(erall)120 2818
+y(w)m(a)m(y)g(of)g(lo)s(oking)e(at)i(region)f(\014les)f(is)g(that)i(if)
+e(the)i(\014rst)e(region)h(is)g(an)g(excluded)f(region)h(then)g(a)g
+(dumm)m(y)120 2931 y(included)27 b(region)j(of)g(the)g(whole)f
+(detector)j(is)d(inserted)f(in)h(the)h(fron)m(t.)41 b(Then)29
+b(eac)m(h)i(region)f(sp)s(eci\014cation)120 3044 y(as)h(it)g(is)f(pro)s
+(cessed)h(o)m(v)m(errides)g(an)m(y)g(selections)g(inside)e(of)i(that)h
+(region)f(sp)s(eci\014ed)e(b)m(y)i(previous)f(regions.)120
+3156 y(Another)f(w)m(a)m(y)i(of)e(thinking)e(ab)s(out)i(this)f(is)h
+(that)g(if)g(a)g(previous)f(excluded)g(region)h(is)g(completely)g
+(inside)120 3269 y(of)i(a)f(subsequen)m(t)g(included)e(region)i(the)g
+(excluded)f(region)h(is)g(ignored.)261 3382 y(The)20
+b(p)s(ositional)e(co)s(ordinates)i(ma)m(y)h(b)s(e)e(giv)m(en)i(either)e
+(in)g(pixel)g(units,)i(decimal)e(degrees)i(or)f(hh:mm:ss.s,)120
+3495 y(dd:mm:ss.s)25 b(units.)37 b(The)26 b(shap)s(e)f(sizes)g(ma)m(y)i
+(b)s(e)e(giv)m(en)h(in)e(pixels,)i(degrees,)h(arcmin)m(utes,)g(or)f
+(arcseconds.)120 3608 y(Lo)s(ok)k(at)i(examples)d(of)i(region)f(\014le)
+f(pro)s(duced)g(b)m(y)h(fv/PO)m(W)h(or)f(ds9)g(for)g(further)f(details)
+h(of)g(the)h(region)120 3721 y(\014le)e(format.)120 3961
+y Fh(5.4.5)105 b(Example)34 b(Ro)m(w)h(Filters)311 4133
+y Fc([double)46 b(&&)h(mag)g(<=)g(5.0])381 b(-)95 b(Extract)46
+b(all)h(double)f(stars)g(brighter)1886 4246 y(than)94
+b(fifth)47 b(magnitude)311 4472 y([#row)f(>=)h(125)g(&&)h(#row)e(<=)h
+(175])142 b(-)48 b(Extract)e(row)h(numbers)e(125)i(through)f(175)311
+4697 y([abs\(sin\(theta)e(*)j(#deg\)\))f(<)i(0.5])e(-)i(Extract)e(all)h
+(rows)f(having)g(the)1886 4810 y(absolute)f(value)i(of)g(the)g(sine)g
+(of)g(theta)1886 4923 y(less)94 b(than)47 b(a)g(half)g(where)f(the)h
+(angles)1886 5036 y(are)g(tabulated)e(in)i(degrees)311
+5262 y([@rowFilter.txt])711 b(-)48 b(Extract)e(rows)g(using)h(the)g
+(expression)1886 5375 y(contained)e(within)h(the)h(text)g(file)1886
+5488 y(rowFilter.txt)1905 5809 y Fg(34)p eop
+%%Page: 35 35
+35 34 bop 311 686 a Fc([gtifilter\(\)])855 b(-)48 b(Search)e(the)h
+(current)f(file)g(for)h(a)h(GTI)359 799 y(extension,)92
+b(filter)i(the)47 b(TIME)359 912 y(column)f(in)h(the)g(current)f
+(table,)g(using)359 1024 y(START/STOP)f(times)h(taken)g(from)359
+1137 y(columns)f(in)j(the)f(GTI)94 b(extension)311 1363
+y([regfilter\("pow.reg"\)])423 b(-)48 b(Extract)e(rows)g(which)h(have)f
+(a)i(coordinate)1886 1476 y(\(as)f(given)f(in)h(the)g(X)h(and)f(Y)g
+(columns\))1886 1589 y(within)f(the)h(spatial)f(region)g(specified)1886
+1702 y(in)h(the)g(pow.reg)f(region)g(file.)1905 5809
+y Fg(35)p eop
+%%Page: 36 36
+36 35 bop 120 573 a Fb(5.5)112 b(Com)m(bined)37 b(Filtering)e(Examples)
+120 744 y Fg(The)29 b(previous)g(sections)g(describ)s(ed)f(all)h(the)h
+(individual)25 b(t)m(yp)s(es)30 b(of)g(\014lters)e(that)j(ma)m(y)f(b)s
+(e)f(applied)f(to)i(the)120 857 y(input)i(\014le.)49
+b(In)33 b(this)f(section)i(w)m(e)g(sho)m(w)g(examples)f(whic)m(h)f(com)
+m(bine)i(sev)m(eral)f(di\013eren)m(t)h(\014lters)e(at)i(once.)120
+970 y(These)h(examples)f(all)g(use)h(the)g Fc(fitscopy)e
+Fg(program)i(that)g(is)f(distributed)e(with)i(the)h(CFITSIO)f(co)s(de.)
+120 1083 y(It)c(simply)e(copies)j(the)f(input)f(\014le)g(to)i(the)g
+(output)f(\014le.)120 1268 y Fc(fitscopy)46 b(rosat.fit)f(out.fit)261
+1453 y Fg(This)25 b(trivial)g(example)h(simply)f(mak)m(es)i(an)g(iden)m
+(tical)f(cop)m(y)h(of)g(the)g(input)e(rosat.\014t)i(\014le)f(without)g
+(an)m(y)120 1566 y(\014ltering.)120 1751 y Fc(fitscopy)46
+b('rosat.fit[events][col)41 b(Time;X;Y][#row)j(<)k(1000]')e(out.fit)261
+1936 y Fg(The)34 b(output)g(\014le)g(con)m(tains)h(only)e(the)i(Time,)g
+(X,)g(and)e(Y)i(columns,)g(and)e(only)h(the)h(\014rst)f(999)h(ro)m(ws)
+120 2049 y(from)g(the)g('EVENTS')f(table)h(extension)g(of)g(the)g
+(input)e(\014le.)54 b(All)33 b(the)j(other)f(HDUs)g(in)f(the)h(input)e
+(\014le)120 2162 y(are)e(copied)f(to)h(the)f(output)g(\014le)g(without)
+f(an)m(y)i(mo)s(di\014cation.)120 2346 y Fc(fitscopy)46
+b('rosat.fit[events][PI)c(<)47 b(50][bin)f(\(Xdet,Ydet\))f(=)i(16]')g
+(image.fit)261 2531 y Fg(This)29 b(creates)i(an)f(output)g(image)h(b)m
+(y)f(binning)d(the)j(Xdet)h(and)f(Ydet)g(columns)f(of)h(the)h(ev)m(en)m
+(ts)g(table)120 2644 y(with)25 b(a)i(pixel)e(binning)e(factor)k(of)g
+(16.)40 b(Only)25 b(the)i(ro)m(ws)f(whic)m(h)f(ha)m(v)m(e)j(a)e(PI)h
+(energy)f(less)g(than)g(50)h(are)g(used)120 2757 y(to)33
+b(construct)f(this)e(image.)45 b(The)32 b(output)f(image)h(\014le)f
+(con)m(tains)h(a)g(primary)e(arra)m(y)i(image)g(without)f(an)m(y)120
+2870 y(extensions.)120 3055 y Fc(fitscopy)46 b('rosat.fit[events][gtif)
+o(ilt)o(er\(\))41 b(&&)47 b(regfilter\("pow.reg"\)]')42
+b(out.fit)261 3240 y Fg(The)29 b(\014ltering)f(expression)g(in)g(this)h
+(example)g(uses)g(the)h Fc(gtifilter)d Fg(function)h(to)i(test)g
+(whether)f(the)120 3353 y(TIME)e(column)f(v)-5 b(alue)26
+b(in)g(eac)m(h)j(ro)m(w)e(is)f(within)f(one)i(of)g(the)h(Go)s(o)s(d)f
+(Time)f(In)m(terv)-5 b(als)26 b(de\014ned)g(in)g(the)i(GTI)120
+3466 y(extension)h(in)f(the)i(same)g(input)d(\014le,)i(and)g(also)h
+(uses)f(the)g Fc(regfilter)e Fg(function)i(to)h(test)g(if)f(the)g(p)s
+(osition)120 3579 y(asso)s(ciated)i(with)d(eac)m(h)j(ro)m(w)g(\(deriv)m
+(ed)e(b)m(y)h(default)f(from)h(the)g(v)-5 b(alues)29
+b(in)g(the)h(X)h(and)e(Y)h(columns)f(of)h(the)120 3692
+y(ev)m(en)m(ts)38 b(table\))e(is)g(lo)s(cated)h(within)c(the)k(area)g
+(de\014ned)e(in)h(the)g Fc(pow.reg)f Fg(text)i(region)f(\014le)f
+(\(whic)m(h)h(w)m(as)120 3804 y(previously)g(created)k(with)e(the)g
+Fc(fv/POW)f Fg(image)i(displa)m(y)e(program\).)66 b(Only)37
+b(the)i(ro)m(ws)f(whic)m(h)g(satisfy)120 3917 y(b)s(oth)30
+b(tests)h(are)g(copied)e(to)i(the)g(output)f(table.)120
+4102 y Fc(fitscopy)46 b('r.fit[evt][PI<50]')c(stdout)k(|)i(fitscopy)d
+(stdin[evt][col)f(X,Y])j(out.fit)261 4287 y Fg(In)25
+b(this)f(somewhat)i(con)m(v)m(oluted)f(example,)i(\014tscop)m(y)e(is)g
+(used)f(to)i(\014rst)f(select)h(the)f(ro)m(ws)g(from)g(the)h(evt)120
+4400 y(extension)j(whic)m(h)g(ha)m(v)m(e)i(PI)e(less)g(than)h(50)g(and)
+f(write)g(the)h(resulting)e(table)i(out)g(to)g(the)g(stdout)g(stream.)
+120 4513 y(This)36 b(is)g(pip)s(ed)f(to)j(a)g(2nd)f(instance)g(of)h
+(\014tscop)m(y)g(\(with)e(the)i(Unix)e(`)p Fa(j)p Fg(')i(pip)s(e)e
+(command\))h(whic)m(h)g(reads)120 4626 y(that)31 b(\014ltered)f(FITS)f
+(\014le)h(from)g(the)h(stdin)e(stream)i(and)f(copies)g(only)g(the)h(X)f
+(and)g(Y)h(columns)e(from)h(the)120 4739 y(evt)h(table)f(to)h(the)g
+(output)f(\014le.)120 4924 y Fc(fitscopy)46 b('r.fit[evt][col)d
+(RAD=sqrt\(\(X-#XCEN\)**2+\(Y-)o(#YCE)o(N\)*)o(*2\)])o([rad)o(<10)o
+(0]')e(out.fit)261 5109 y Fg(This)23 b(example)i(\014rst)f(creates)i(a)
+f(new)f(column)g(called)g(RAD)h(whic)m(h)e(giv)m(es)i(the)g(distance)g
+(b)s(et)m(w)m(een)g(the)120 5222 y(X,Y)k(co)s(ordinate)f(of)g(eac)m(h)i
+(ev)m(en)m(t)g(and)d(the)i(co)s(ordinate)f(de\014ned)f(b)m(y)h(the)h(X)
+m(CEN)f(and)g(YCEN)g(k)m(eyw)m(ords)120 5334 y(in)j(the)i(header.)47
+b(Then,)32 b(only)g(those)h(ro)m(ws)g(whic)m(h)e(ha)m(v)m(e)j(a)f
+(distance)f(less)g(than)g(100)i(are)f(copied)f(to)h(the)120
+5447 y(output)e(table.)45 b(In)31 b(other)h(w)m(ords,)f(only)g(the)h
+(ev)m(en)m(ts)h(whic)m(h)e(are)h(lo)s(cated)g(within)d(100)k(pixel)d
+(units)g(from)120 5560 y(the)h(\(X)m(CEN,)g(YCEN\))f(co)s(ordinate)h
+(are)f(copied)g(to)h(the)g(output)f(table.)1905 5809
+y(36)p eop
+%%Page: 37 37
+37 36 bop 120 573 a Fc(fitscopy)46 b('ftp://heasarc.gsfc.nas)o(a.g)o
+(ov/r)o(osat)o(.fi)o(t[ev)o(ents)o(][b)o(in)c(\(X,Y\)=16]')j(img.fit)
+261 785 y Fg(This)22 b(example)h(bins)e(the)i(X)h(and)f(Y)g(columns)f
+(of)h(the)h(h)m(yp)s(othetical)e(R)m(OSA)-8 b(T)24 b(\014le)e(at)i(the)
+f(HEASAR)m(C)120 898 y(ftp)30 b(site)g(to)h(create)h(the)f(output)f
+(image.)120 1111 y Fc(fitscopy)46 b('raw.fit[i512,512][101:)o(110)o
+(,51:)o(60]')41 b(image.fit)261 1323 y Fg(This)28 b(example)h(con)m(v)m
+(erts)i(the)e(512)i(x)e(512)i(pixel)d(ra)m(w)h(binary)f(16-bit)h(in)m
+(teger)h(image)g(to)g(a)g(FITS)e(\014le)120 1436 y(and)i(copies)g(a)h
+(10)g(x)f(10)h(pixel)e(subimage)h(from)g(it)f(to)j(the)e(output)g(FITS)
+g(image.)1905 5809 y(37)p eop
+%%Page: 38 38
+38 37 bop 120 573 a Fi(6)135 b(CFITSIO)44 b(Error)h(Status)g(Co)t(des)
+120 776 y Fg(The)34 b(follo)m(wing)e(table)i(lists)f(all)g(the)h(error)
+g(status)g(co)s(des)h(used)e(b)m(y)h(CFITSIO.)f(Programmers)h(are)g
+(en-)120 889 y(couraged)f(to)g(use)g(the)f(sym)m(b)s(olic)f(mnemonics)h
+(\(de\014ned)f(in)g(the)i(\014le)f(\014tsio.h\))g(rather)g(than)g(the)h
+(actual)120 1002 y(in)m(teger)e(status)f(v)-5 b(alues)30
+b(to)h(impro)m(v)m(e)f(the)h(readabilit)m(y)e(of)h(their)g(co)s(de.)168
+1214 y Fc(Symbolic)45 b(Const)190 b(Value)237 b(Meaning)168
+1327 y(--------------)187 b(-----)94 b(------------------------)o(----)
+o(---)o(----)o(----)o(--)1122 1440 y(0)191 b(OK,)47 b(no)g(error)168
+1553 y(SAME_FILE)427 b(101)190 b(input)46 b(and)h(output)f(files)h(are)
+g(the)f(same)168 1666 y(TOO_MANY_FILES)187 b(103)j(tried)46
+b(to)h(open)g(too)g(many)g(FITS)f(files)h(at)g(once)168
+1779 y(FILE_NOT_OPENED)139 b(104)190 b(could)46 b(not)h(open)g(the)g
+(named)f(file)168 1892 y(FILE_NOT_CREATED)91 b(105)190
+b(could)46 b(not)h(create)f(the)h(named)g(file)168 2005
+y(WRITE_ERROR)331 b(106)190 b(error)46 b(writing)g(to)h(FITS)g(file)168
+2117 y(END_OF_FILE)331 b(107)190 b(tried)46 b(to)h(move)g(past)g(end)g
+(of)g(file)168 2230 y(READ_ERROR)379 b(108)190 b(error)46
+b(reading)g(from)h(FITS)f(file)168 2343 y(FILE_NOT_CLOSED)139
+b(110)190 b(could)46 b(not)h(close)g(the)f(file)168 2456
+y(ARRAY_TOO_BIG)235 b(111)190 b(array)46 b(dimensions)f(exceed)h
+(internal)g(limit)168 2569 y(READONLY_FILE)235 b(112)190
+b(Cannot)46 b(write)g(to)i(readonly)d(file)168 2682 y
+(MEMORY_ALLOCATION)e(113)190 b(Could)46 b(not)h(allocate)f(memory)168
+2795 y(BAD_FILEPTR)331 b(114)190 b(invalid)46 b(fitsfile)f(pointer)168
+2908 y(NULL_INPUT_PTR)187 b(115)j(NULL)47 b(input)f(pointer)g(to)h
+(routine)168 3021 y(SEEK_ERROR)379 b(116)190 b(error)46
+b(seeking)g(position)g(in)h(file)168 3247 y(BAD_URL_PREFIX)235
+b(121)142 b(invalid)46 b(URL)h(prefix)f(on)h(file)g(name)168
+3359 y(TOO_MANY_DRIVERS)139 b(122)j(tried)46 b(to)h(register)f(too)h
+(many)g(IO)g(drivers)168 3472 y(DRIVER_INIT_FAILED)c(123)142
+b(driver)46 b(initialization)e(failed)168 3585 y(NO_MATCHING_DRIVER)f
+(124)142 b(matching)45 b(driver)i(is)g(not)g(registered)168
+3698 y(URL_PARSE_ERROR)187 b(125)142 b(failed)46 b(to)h(parse)g(input)f
+(file)h(URL)168 3924 y(SHARED_BADARG)235 b(151)190 b(bad)47
+b(argument)e(in)j(shared)e(memory)g(driver)168 4037 y(SHARED_NULPTR)235
+b(152)190 b(null)47 b(pointer)e(passed)h(as)i(an)f(argument)168
+4150 y(SHARED_TABFULL)187 b(153)j(no)47 b(more)g(free)f(shared)g
+(memory)h(handles)168 4263 y(SHARED_NOTINIT)187 b(154)j(shared)46
+b(memory)g(driver)g(is)h(not)g(initialized)168 4376 y(SHARED_IPCERR)235
+b(155)190 b(IPC)47 b(error)f(returned)g(by)h(a)g(system)f(call)168
+4489 y(SHARED_NOMEM)283 b(156)190 b(no)47 b(memory)f(in)h(shared)f
+(memory)h(driver)168 4601 y(SHARED_AGAIN)283 b(157)190
+b(resource)45 b(deadlock)h(would)g(occur)168 4714 y(SHARED_NOFILE)235
+b(158)190 b(attempt)46 b(to)h(open/create)e(lock)h(file)h(failed)168
+4827 y(SHARED_NORESIZE)139 b(159)190 b(shared)46 b(memory)g(block)g
+(cannot)h(be)g(resized)f(at)h(the)g(moment)168 5053 y(HEADER_NOT_EMPTY)
+91 b(201)190 b(header)46 b(already)g(contains)f(keywords)168
+5166 y(KEY_NO_EXIST)283 b(202)190 b(keyword)46 b(not)h(found)f(in)h
+(header)168 5279 y(KEY_OUT_BOUNDS)187 b(203)j(keyword)46
+b(record)g(number)g(is)h(out)g(of)g(bounds)168 5392 y(VALUE_UNDEFINED)
+139 b(204)190 b(keyword)46 b(value)g(field)g(is)i(blank)168
+5505 y(NO_QUOTE)475 b(205)190 b(string)46 b(is)h(missing)f(the)h
+(closing)f(quote)1905 5809 y Fg(38)p eop
+%%Page: 39 39
+39 38 bop 168 573 a Fc(BAD_KEYCHAR)331 b(207)190 b(illegal)46
+b(character)f(in)i(keyword)f(name)h(or)g(card)168 686
+y(BAD_ORDER)427 b(208)190 b(required)45 b(keywords)h(out)h(of)g(order)
+168 799 y(NOT_POS_INT)331 b(209)190 b(keyword)46 b(value)g(is)h(not)g
+(a)h(positive)d(integer)168 912 y(NO_END)571 b(210)190
+b(couldn't)45 b(find)i(END)g(keyword)168 1024 y(BAD_BITPIX)379
+b(211)190 b(illegal)46 b(BITPIX)g(keyword)g(value)168
+1137 y(BAD_NAXIS)427 b(212)190 b(illegal)46 b(NAXIS)g(keyword)g(value)
+168 1250 y(BAD_NAXES)427 b(213)190 b(illegal)46 b(NAXISn)g(keyword)g
+(value)168 1363 y(BAD_PCOUNT)379 b(214)190 b(illegal)46
+b(PCOUNT)g(keyword)g(value)168 1476 y(BAD_GCOUNT)379
+b(215)190 b(illegal)46 b(GCOUNT)g(keyword)g(value)168
+1589 y(BAD_TFIELDS)331 b(216)190 b(illegal)46 b(TFIELDS)g(keyword)f
+(value)168 1702 y(NEG_WIDTH)427 b(217)190 b(negative)45
+b(table)i(row)g(size)168 1815 y(NEG_ROWS)475 b(218)190
+b(negative)45 b(number)i(of)g(rows)f(in)i(table)168 1928
+y(COL_NOT_FOUND)235 b(219)190 b(column)46 b(with)h(this)f(name)h(not)g
+(found)f(in)h(table)168 2041 y(BAD_SIMPLE)379 b(220)190
+b(illegal)46 b(value)g(of)h(SIMPLE)f(keyword)168 2154
+y(NO_SIMPLE)427 b(221)190 b(Primary)46 b(array)g(doesn't)g(start)g
+(with)h(SIMPLE)168 2267 y(NO_BITPIX)427 b(222)190 b(Second)46
+b(keyword)g(not)h(BITPIX)168 2379 y(NO_NAXIS)475 b(223)190
+b(Third)46 b(keyword)g(not)h(NAXIS)168 2492 y(NO_NAXES)475
+b(224)190 b(Couldn't)45 b(find)i(all)g(the)g(NAXISn)f(keywords)168
+2605 y(NO_XTENSION)331 b(225)190 b(HDU)47 b(doesn't)f(start)g(with)h
+(XTENSION)e(keyword)168 2718 y(NOT_ATABLE)379 b(226)190
+b(the)47 b(CHDU)f(is)i(not)f(an)g(ASCII)f(table)g(extension)168
+2831 y(NOT_BTABLE)379 b(227)190 b(the)47 b(CHDU)f(is)i(not)f(a)g
+(binary)f(table)g(extension)168 2944 y(NO_PCOUNT)427
+b(228)190 b(couldn't)45 b(find)i(PCOUNT)f(keyword)168
+3057 y(NO_GCOUNT)427 b(229)190 b(couldn't)45 b(find)i(GCOUNT)f(keyword)
+168 3170 y(NO_TFIELDS)379 b(230)190 b(couldn't)45 b(find)i(TFIELDS)f
+(keyword)168 3283 y(NO_TBCOL)475 b(231)190 b(couldn't)45
+b(find)i(TBCOLn)f(keyword)168 3396 y(NO_TFORM)475 b(232)190
+b(couldn't)45 b(find)i(TFORMn)f(keyword)168 3509 y(NOT_IMAGE)427
+b(233)190 b(the)47 b(CHDU)f(is)i(not)f(an)g(IMAGE)f(extension)168
+3621 y(BAD_TBCOL)427 b(234)190 b(TBCOLn)46 b(keyword)g(value)g(<)i(0)f
+(or)g(>)h(rowlength)168 3734 y(NOT_TABLE)427 b(235)190
+b(the)47 b(CHDU)f(is)i(not)f(a)g(table)168 3847 y(COL_TOO_WIDE)283
+b(236)190 b(column)46 b(is)h(too)g(wide)g(to)g(fit)g(in)g(table)168
+3960 y(COL_NOT_UNIQUE)187 b(237)j(more)47 b(than)f(1)i(column)e(name)g
+(matches)g(template)168 4073 y(BAD_ROW_WIDTH)235 b(241)190
+b(sum)47 b(of)g(column)f(widths)g(not)h(=)h(NAXIS1)168
+4186 y(UNKNOWN_EXT)331 b(251)190 b(unrecognizable)44
+b(FITS)i(extension)g(type)168 4299 y(UNKNOWN_REC)331
+b(252)190 b(unknown)46 b(record;)g(1st)g(keyword)g(not)h(SIMPLE)f(or)h
+(XTENSION)168 4412 y(END_JUNK)475 b(253)190 b(END)47
+b(keyword)f(is)h(not)g(blank)168 4525 y(BAD_HEADER_FILL)139
+b(254)190 b(Header)46 b(fill)h(area)f(contains)g(non-blank)f(chars)168
+4638 y(BAD_DATA_FILL)235 b(255)190 b(Illegal)46 b(data)g(fill)h(bytes)f
+(\(not)h(zero)g(or)g(blank\))168 4751 y(BAD_TFORM)427
+b(261)190 b(illegal)46 b(TFORM)g(format)g(code)168 4863
+y(BAD_TFORM_DTYPE)139 b(262)190 b(unrecognizable)44 b(TFORM)i(datatype)
+g(code)168 4976 y(BAD_TDIM)475 b(263)190 b(illegal)46
+b(TDIMn)g(keyword)g(value)168 5089 y(BAD_HEAP_PTR)283
+b(264)190 b(invalid)46 b(BINTABLE)f(heap)i(pointer)f(is)h(out)g(of)g
+(range)168 5315 y(BAD_HDU_NUM)331 b(301)190 b(HDU)47
+b(number)f(<)h(1)h(or)f(>)g(MAXHDU)168 5428 y(BAD_COL_NUM)331
+b(302)190 b(column)46 b(number)g(<)i(1)f(or)g(>)h(tfields)168
+5541 y(NEG_FILE_POS)283 b(304)190 b(tried)46 b(to)h(move)g(to)g
+(negative)f(byte)g(location)g(in)h(file)1905 5809 y Fg(39)p
+eop
+%%Page: 40 40
+40 39 bop 168 573 a Fc(NEG_BYTES)427 b(306)190 b(tried)46
+b(to)h(read)g(or)g(write)g(negative)e(number)h(of)h(bytes)168
+686 y(BAD_ROW_NUM)331 b(307)190 b(illegal)46 b(starting)f(row)i(number)
+f(in)h(table)168 799 y(BAD_ELEM_NUM)283 b(308)190 b(illegal)46
+b(starting)f(element)h(number)g(in)h(vector)168 912 y(NOT_ASCII_COL)235
+b(309)190 b(this)47 b(is)g(not)g(an)g(ASCII)f(string)g(column)168
+1024 y(NOT_LOGICAL_COL)139 b(310)190 b(this)47 b(is)g(not)g(a)g
+(logical)f(datatype)f(column)168 1137 y(BAD_ATABLE_FORMAT)e(311)190
+b(ASCII)46 b(table)h(column)f(has)h(wrong)f(format)168
+1250 y(BAD_BTABLE_FORMAT)d(312)190 b(Binary)46 b(table)g(column)g(has)h
+(wrong)g(format)168 1363 y(NO_NULL)523 b(314)190 b(null)47
+b(value)f(has)h(not)g(been)f(defined)168 1476 y(NOT_VARI_LEN)283
+b(317)190 b(this)47 b(is)g(not)g(a)g(variable)f(length)g(column)168
+1589 y(BAD_DIMEN)427 b(320)190 b(illegal)46 b(number)g(of)h(dimensions)
+e(in)i(array)168 1702 y(BAD_PIX_NUM)331 b(321)190 b(first)46
+b(pixel)h(number)f(greater)g(than)g(last)h(pixel)168
+1815 y(ZERO_SCALE)379 b(322)190 b(illegal)46 b(BSCALE)g(or)h(TSCALn)f
+(keyword)g(=)h(0)168 1928 y(NEG_AXIS)475 b(323)190 b(illegal)46
+b(axis)g(length)g(<)i(1)168 2154 y(NOT_GROUP_TABLE)330
+b(340)142 b(Grouping)46 b(function)f(error)168 2267 y
+(HDU_ALREADY_MEMBER)186 b(341)168 2379 y(MEMBER_NOT_FOUND)282
+b(342)168 2492 y(GROUP_NOT_FOUND)330 b(343)168 2605 y(BAD_GROUP_ID)474
+b(344)168 2718 y(TOO_MANY_HDUS_TRACKED)42 b(345)168 2831
+y(HDU_ALREADY_TRACKED)138 b(346)168 2944 y(BAD_OPTION)570
+b(347)168 3057 y(IDENTICAL_POINTERS)186 b(348)168 3170
+y(BAD_GROUP_ATTACH)282 b(349)168 3283 y(BAD_GROUP_DETACH)g(350)168
+3509 y(NGP_NO_MEMORY)426 b(360)238 b(malloc)46 b(failed)168
+3621 y(NGP_READ_ERR)474 b(361)238 b(read)46 b(error)h(from)f(file)168
+3734 y(NGP_NUL_PTR)522 b(362)238 b(null)46 b(pointer)g(passed)g(as)h
+(an)g(argument.)1695 3847 y(Passing)f(null)g(pointer)g(as)h(a)h(name)f
+(of)1695 3960 y(template)f(file)g(raises)g(this)h(error)168
+4073 y(NGP_EMPTY_CURLINE)234 b(363)k(line)46 b(read)h(seems)f(to)h(be)h
+(empty)e(\(used)1695 4186 y(internally\))168 4299 y
+(NGP_UNREAD_QUEUE_FULL)c(364)238 b(cannot)46 b(unread)g(more)g(then)h
+(1)g(line)g(\(or)g(single)1695 4412 y(line)g(twice\))168
+4525 y(NGP_INC_NESTING)330 b(365)238 b(too)46 b(deep)h(include)f(file)h
+(nesting)e(\(infinite)1695 4638 y(loop,)h(template)g(includes)f(itself)
+i(?\))168 4751 y(NGP_ERR_FOPEN)426 b(366)238 b(fopen\(\))45
+b(failed,)h(cannot)g(open)h(template)e(file)168 4863
+y(NGP_EOF)714 b(367)238 b(end)46 b(of)i(file)e(encountered)f(and)i(not)
+g(expected)168 4976 y(NGP_BAD_ARG)522 b(368)238 b(bad)46
+b(arguments)g(passed.)g(Usually)f(means)1695 5089 y(internal)h(parser)g
+(error.)g(Should)g(not)h(happen)168 5202 y(NGP_TOKEN_NOT_EXPECT)90
+b(369)238 b(token)46 b(not)h(expected)e(here)168 5428
+y(BAD_I2C)523 b(401)190 b(bad)47 b(int)g(to)g(formatted)e(string)h
+(conversion)168 5541 y(BAD_F2C)523 b(402)190 b(bad)47
+b(float)f(to)h(formatted)f(string)g(conversion)1905 5809
+y Fg(40)p eop
+%%Page: 41 41
+41 40 bop 168 573 a Fc(BAD_INTKEY)379 b(403)190 b(can't)46
+b(interpret)g(keyword)f(value)i(as)g(integer)168 686
+y(BAD_LOGICALKEY)187 b(404)j(can't)46 b(interpret)g(keyword)f(value)i
+(as)g(logical)168 799 y(BAD_FLOATKEY)283 b(405)190 b(can't)46
+b(interpret)g(keyword)f(value)i(as)g(float)168 912 y(BAD_DOUBLEKEY)235
+b(406)190 b(can't)46 b(interpret)g(keyword)f(value)i(as)g(double)168
+1024 y(BAD_C2I)523 b(407)190 b(bad)47 b(formatted)e(string)h(to)h(int)g
+(conversion)168 1137 y(BAD_C2F)523 b(408)190 b(bad)47
+b(formatted)e(string)h(to)h(float)g(conversion)168 1250
+y(BAD_C2D)523 b(409)190 b(bad)47 b(formatted)e(string)h(to)h(double)f
+(conversion)168 1363 y(BAD_DATATYPE)283 b(410)190 b(illegal)46
+b(datatype)f(code)i(value)168 1476 y(BAD_DECIM)427 b(411)190
+b(bad)47 b(number)f(of)h(decimal)f(places)g(specified)168
+1589 y(NUM_OVERFLOW)283 b(412)190 b(overflow)45 b(during)i(datatype)e
+(conversion)168 1702 y(DATA_COMPRESSION_ERR)137 b(413)95
+b(error)46 b(compressing)f(image)168 1815 y(DATA_DECOMPRESSION_ERR)c
+(414)95 b(error)46 b(uncompressing)f(image)168 2041 y(BAD_DATE)475
+b(420)190 b(error)46 b(in)h(date)g(or)g(time)g(conversion)168
+2267 y(PARSE_SYNTAX_ERR)91 b(431)190 b(syntax)46 b(error)g(in)i(parser)
+e(expression)168 2379 y(PARSE_BAD_TYPE)187 b(432)j(expression)45
+b(did)i(not)g(evaluate)e(to)i(desired)f(type)168 2492
+y(PARSE_LRG_VECTOR)91 b(433)190 b(vector)46 b(result)g(too)h(large)f
+(to)i(return)e(in)h(array)168 2605 y(PARSE_NO_OUTPUT)139
+b(434)190 b(data)47 b(parser)f(failed)g(not)h(sent)f(an)h(out)g(column)
+168 2718 y(PARSE_BAD_COL)235 b(435)190 b(bad)47 b(data)f(encounter)g
+(while)g(parsing)g(column)168 2831 y(PARSE_BAD_OUTPUT)91
+b(436)190 b(Output)46 b(file)h(not)g(of)g(proper)f(type)168
+3057 y(ANGLE_TOO_BIG)235 b(501)190 b(celestial)45 b(angle)i(too)f
+(large)h(for)g(projection)168 3170 y(BAD_WCS_VAL)331
+b(502)190 b(bad)47 b(celestial)e(coordinate)g(or)i(pixel)g(value)168
+3283 y(WCS_ERROR)427 b(503)190 b(error)46 b(in)h(celestial)f
+(coordinate)f(calculation)168 3396 y(BAD_WCS_PROJ)283
+b(504)190 b(unsupported)45 b(type)h(of)h(celestial)f(projection)168
+3509 y(NO_WCS_KEY)379 b(505)190 b(celestial)45 b(coordinate)g(keywords)
+h(not)h(found)168 3621 y(APPROX_WCS_KEY)187 b(506)j(approximate)45
+b(wcs)i(keyword)e(values)h(were)h(returned)1905 5809
+y Fg(41)p eop
+%%Trailer
+end
+userdict /end-hook known{end-hook}if
+%%EOF
diff --git a/pkg/tbtables/cfitsio/quick.tex b/pkg/tbtables/cfitsio/quick.tex
new file mode 100644
index 00000000..28bd97ce
--- /dev/null
+++ b/pkg/tbtables/cfitsio/quick.tex
@@ -0,0 +1,2156 @@
+\documentclass[11pt]{article}
+\input{html.sty}
+\htmladdtonavigation
+ {\begin{rawhtml}
+ <A HREF="http://heasarc.gsfc.nasa.gov/docs/software/fitsio/fitsio.html">FITSIO Home</A>
+ \end{rawhtml}}
+
+\oddsidemargin=0.20in
+\evensidemargin=0.20in
+\textwidth=15.5truecm
+\textheight=21.5truecm
+
+\title{CFITSIO Quick Start Guide}
+\author{William Pence \thanks{HEASARC, NASA Goddard Space Flight Center,
+{\it William.D.Pence@nasa.gov}}}
+
+\date{January 2003}
+
+\begin{document}
+
+\maketitle
+\tableofcontents
+
+% ===================================================================
+\section{Introduction}
+
+This document is intended to help you quickly start writing C programs
+to read and write FITS files using the CFITSIO library. It covers the
+most important CFITSIO routines that are needed to perform most types
+of operations on FITS files. For more complete information about these
+and all the other available routines in the library please refer to
+the ``CFITSIO User's Reference Guide'', which is available from the
+CFITSIO Web site at {\tt http://heasarc.gsfc.nasa.gov/fitsio}.
+
+For more general information about the FITS data format, refer to the
+following web page:
+http://heasarc.gsfc.nasa.gov/docs/heasarc/fits.html
+
+FITS stands for Flexible Image Transport System and is the standard
+file format used to store most astronomical data files. There are 2
+basic types of FITS files: images and tables. FITS images often
+contain a 2-dimensional array of pixels representing an image of a
+piece of the sky, but FITS images can also contain 1-D arrays (i.e,
+a spectrum or light curve), or 3-D arrays (a data cube), or
+even higher dimensional arrays of data. An image may also have zero
+dimensions, in which case it is referred to as a null or empty array.
+The supported datatypes for the image arrays are 8, 16, and 32-bit
+integers, and 32 and 64-bit floating point real numbers. Both signed
+and unsigned integers are supported.
+
+FITS tables contain rows and columns of data, similar to a
+spreadsheet. All the values in a particular column must have the same
+datatype. A cell of a column is not restricted to a single number, and
+instead can contain an array or vector of numbers. There are actually
+2 subtypes of FITS tables: ASCII and binary. As the names imply, ASCII
+tables store the data values in an ASCII representation whereas binary
+tables store the data values in a more efficient machine-readable
+binary format. Binary tables are generally more compact and support
+more features (e.g., a wider range of datatypes, and vector columns)
+than ASCII tables.
+
+A single FITS file many contain multiple images or tables. Each table
+or image is called a Header-Data Unit, or HDU. The first HDU in a FITS
+file must be an image (but it may have zero axes) and is called the
+Primary Array. Any additional HDUs in the file (which are also
+referred to as `extensions') may contain either an image or a table.
+
+Every HDU contains a header containing keyword records. Each keyword
+record is 80 ASCII characters long and has the following format:
+
+\begin{verbatim}
+KEYWORD = value / comment string
+\end{verbatim}
+
+The keyword name can be up to 8 characters long (all uppercase). The
+value can be either an integer or floating point number, a logical
+value (T or F), or a character string enclosed in single quotes. Each
+header begins with a series of required keywords to describe the
+datatype and format of the following data unit, if any. Any number of
+other optional keywords can be included in the header to provide other
+descriptive information about the data. For the most part, the CFITSIO
+routines automatically write the required FITS keywords for each HDU,
+so you, the programmer, usually do not need to worry about them.
+
+% ===================================================================
+\section{Installing and Using CFITSIO}
+
+First, you should download the CFITSIO software and the set of example
+FITS utility programs from the web site at
+http://heasarc.gsfc.nasa.gov/fitsio. The example programs illustrate
+how to perform many common types of operations on FITS files using
+CFITSIO. They are also useful when writing a new program because it is
+often easier to take a copy of one of these utility programs as a
+template and then modify it for your own purposes, rather than writing
+the new program completely from scratch.
+
+To build the CFITSIO library on Unix platforms, `untar' the source code
+distribution file and then execute the following commands in the
+directory containing the source code:
+
+\begin{verbatim}
+> ./configure [--prefix=/target/installation/path]
+> make (or 'make shared')
+> make install (this step is optional)
+\end{verbatim}
+
+The optional
+'prefix' argument to configure gives the path to the directory where
+the CFITSIO library and include files should be installed via the later
+'make install' command. For example,
+
+\begin{verbatim}
+> ./configure --prefix=/usr1/local
+\end{verbatim}
+
+will cause the 'make install' command to copy the CFITSIO libcfitsio file
+to /usr1/local/lib and the necessary include files to /usr1/local/include
+(assuming of course that the process has permission to write to these
+directories).
+
+Pre-compiled versions of the CFITSIO DLL library are available for
+PCs. On Macintosh machines, refer to the README.MacOS file for
+instructions on building CFITSIO using CodeWarrior.
+
+Any programs that use CFITSIO must of course be linked with the CFITSIO
+library when creating the executable file. The exact procedure for
+linking a program depends on your software environment, but on Unix
+platforms, the command line to compile and link a program will look
+something like this:
+
+\begin{verbatim}
+gcc -o myprog myprog.c -L. -lcfitsio -lm -lnsl -lsocket
+\end{verbatim}
+
+You may not need to include all of the 'm', 'nsl', and 'socket' system
+libraries on your particular machine. To find out what libraries are
+required on your (Unix) system, type {\tt'make testprog'} and see what
+libraries are then included on the resulting link line.
+
+\newpage
+% ===================================================================
+\section{Example Programs}
+
+Before describing the individual CFITSIO routines in detail, it is
+instructive to first look at an actual program. The names of the
+CFITSIO routines are fairly descriptive (they all begin with {\tt
+fits\_}, so it should be reasonably clear what this program does:
+
+\begin{verbatim}
+----------------------------------------------------------------
+ #include <string.h>
+ #include <stdio.h>
+1: #include "fitsio.h"
+
+ int main(int argc, char *argv[])
+ {
+2: fitsfile *fptr;
+ char card[FLEN_CARD];
+3: int status = 0, nkeys, ii; /* MUST initialize status */
+
+4: fits_open_file(&fptr, argv[1], READONLY, &status);
+ fits_get_hdrspace(fptr, &nkeys, NULL, &status);
+
+ for (ii = 1; ii <= nkeys; ii++) {
+ fits_read_record(fptr, ii, card, &status); /* read keyword */
+ printf("%s\n", card);
+ }
+ printf("END\n\n"); /* terminate listing with END */
+ fits_close_file(fptr, &status);
+
+ if (status) /* print any error messages */
+5: fits_report_error(stderr, status);
+ return(status);
+ }
+----------------------------------------------------------------
+\end{verbatim}
+
+This program opens the specified FITS file and prints
+out all the header keywords in the current HDU.
+Some other points to notice about the program are:
+\begin{enumerate}
+
+\item
+The {\tt fitsio.h} header file must be included to define the
+various routines and symbols used in CFITSIO.
+
+\item
+
+The {\tt fitsfile} parameter is the first argument in almost every
+CFITSIO routine. It is a pointer to a structure (defined in {\tt
+fitsio.h}) that stores information about the particular FITS file that
+the routine will operate on. Memory for this structure is
+automatically allocated when the file is first opened or created, and
+is freed when the file is closed.
+
+\item
+Almost every CFITSIO routine has a {\tt status} parameter as the last
+argument. The status value is also usually returned as the value of the
+function itself. Normally status = 0, and a positive status value
+indicates an error of some sort. The status variable must always be
+initialized to zero before use, because if status is greater than zero
+on input then the CFITSIO routines will simply return without doing
+anything. This `inherited status' feature, where each CFITSIO routine
+inherits the status from the previous routine, makes it unnecessary to
+check the status value after every single CFITSIO routine call.
+Generally you should check the status after an especially important or
+complicated routine has been called, or after a block of
+closely related CFITSIO calls. This example program has taken this
+feature to the extreme and only checks the status value at the
+very end of the program.
+
+\item
+
+In this example program the file name to be opened is given as an
+argument on the command line ({\tt arg[1]}). If the file contains more
+than 1 HDU or extension, you can specify which particular HDU to be
+opened by enclosing the name or number of the HDU in square brackets
+following the root name of the file. For example, {\tt file.fts[0]}
+opens the primary array, while {\tt file.fts[2]} will move to and open
+the 2nd extension in the file, and {\tt file.fit[EVENTS]} will open the
+extension that has a {\tt EXTNAME = 'EVENTS'} keyword in the header.
+Note that on the Unix command line you must enclose the file name in
+single or double quote characters if the name contains special
+characters such as `[' or `]'.
+
+All of the CFITSIO routines which read or write header keywords,
+image data, or table data operate only within the currently opened
+HDU in the file. To read or write information in a different HDU you must
+first explicitly move to that HDU (see the {\tt fits\_movabs\_hdu} and
+{\tt fits\_movrel\_hdu} routines in section 4.3).
+
+\item
+
+The {\tt fits\_report\_error} routine provides a convenient way to print out
+diagnostic messages about any error that may have occurred.
+
+\end{enumerate}
+
+A set of example FITS utility programs are available from the CFITSIO
+web site at \newline
+http://heasarc.gsfc.nasa.gov/docs/software/fitsio/cexamples.html.
+These are real working programs which illustrate how to read, write,
+and modify FITS files using the CFITSIO library. Most of these
+programs are very short, containing only a few 10s of lines of
+executable code or less, yet they perform quite useful operations on
+FITS files. Running each program without any command line arguments
+will produce a short description of how to use the program.
+The currently available programs are:
+\begin{quote}
+fitscopy - copy a file
+\newline
+listhead - list header keywords
+\newline
+liststruc - show the structure of a FITS file.
+\newline
+modhead - write or modify a header keyword
+\newline
+imarith - add, subtract, multiply, or divide 2 images
+\newline
+imlist - list pixel values in an image
+\newline
+imstat - compute mean, min, and max pixel values in an image
+\newline
+tablist - display the contents of a FITS table
+\newline
+tabcalc - general table calculator
+\end{quote}
+
+\newpage
+
+% ===================================================================
+\section{CFITSIO Routines}
+
+This chapter describes the main CFITSIO routines that can be used to
+perform the most common types of operations on FITS files.
+
+% ===================================================================
+{\bf \subsection{Error Reporting}}
+
+\begin{verbatim}
+void fits_report_error(FILE *stream, int status)
+void fits_get_errstatus(int status, char *err_text)
+float fits_get_version(float *version)
+\end{verbatim}
+
+The first routine prints out information about any error that
+has occurred. Whenever any CFITSIO routine encounters an error it
+usually writes a message describing the nature of the error to an
+internal error message stack and then returns with a positive integer
+status value. Passing the error status value to this routine will
+cause a generic description of the error and all the messages
+from the internal CFITSIO error stack to be printed to the specified
+stream. The {\tt stream} parameter is usually set equal to
+{\tt "stdout"} or {\tt "stderr"}.
+
+The second routine simply returns a 30-character descriptive
+error message corresponding to the input status value.
+
+The last routine returns the current CFITSIO library version number.
+
+% ===================================================================
+{\bf \subsection{File Open/Close Routines}}
+
+\begin{verbatim}
+int fits_open_file( fitsfile **fptr, char *filename, int mode, int *status)
+int fits_open_data( fitsfile **fptr, char *filename, int mode, int *status)
+int fits_open_table(fitsfile **fptr, char *filename, int mode, int *status)
+int fits_open_image(fitsfile **fptr, char *filename, int mode, int *status)
+
+int fits_create_file(fitsfile **fptr, char *filename, int *status)
+int fits_close_file(fitsfile *fptr, int *status)
+\end{verbatim}
+
+These routines open or close a file. The first {\tt fitsfile}
+parameter in these and nearly every other CFITSIO routine is a pointer
+to a structure that CFITSIO uses to store relevant parameters about
+each opened file. You should never directly read or write any
+information in this structure. Memory for this structure is allocated
+automatically when the file is opened or created, and is freed when the
+file is closed.
+
+The {\tt mode} parameter in the {\tt fits\_open\_xxxx} set of routines
+can be set to either {\tt READONLY} or {\tt READWRITE} to select the
+type of file access that will be allowed. These symbolic constants are
+defined in {\tt fitsio.h}.
+
+The {\tt fits\_open\_file} routine opens the file and positions the internal
+file pointer to the beginning of the file, or to the specified
+extension if an extension name or number is appended to the file name
+(see the later section on ``CFITSIO File Names and Filters'' for a
+description of the syntax). {\tt fits\_open\_data} behaves similarly except
+that it will move to the first HDU containing significant data if a HDU
+name or number to open is not explicitly specified as part of the
+filename. It will move to the first IMAGE HDU with NAXIS greater than
+0, or the first table that does not contain the strings `GTI' (a Good
+Time Interval extension) or `OBSTABLE' in the EXTNAME keyword value.
+The {\tt fits\_open\_table} and {\tt fits\_open\_image} routines are similar
+except that they will move to the first significant table HDU or image
+HDU, respectively if a HDU name of number is not specified as part of
+the input file name.
+
+When opening an existing file, the {\tt filename} can include optional
+arguments, enclosed in square brackets that specify filtering
+operations that should be applied to the input file. For example,
+\begin{verbatim}
+ myfile.fit[EVENTS][counts > 0]
+\end{verbatim}
+opens the table in the EVENTS extension and creates a virtual table by
+selecting only those rows where the COUNTS column value is greater than
+0. See section 5 for more examples of these powerful filtering
+capabilities.
+
+In {\tt fits\_create\_file}, the {\tt filename} is simply the root name of
+the file to be created. You can overwrite an existing file by
+prefixing the name with a `!' character (on the Unix command line this
+must be prefixed with a backslash, as in \verb+`\!file.fit'+).
+If the file name ends with {\tt .gz} the file will be compressed
+using the gzip algorithm. If the
+filename is {\tt stdout} or {\tt "-"} (a single dash character)
+then the output file will be piped to the stdout stream. You can
+chain several tasks together by writing the output from the first task
+to {\tt stdout} and then reading the input file in the 2nd task from
+{\tt stdin} or {\tt "-"}.
+
+
+% ===================================================================
+{\bf \subsection{HDU-level Routines}}
+
+The routines listed in this section operate on Header-Data Units (HDUs) in a file.
+
+\begin{verbatim}
+_______________________________________________________________
+int fits_get_num_hdus(fitsfile *fptr, int *hdunum, int *status)
+int fits_get_hdu_num(fitsfile *fptr, int *hdunum)
+\end{verbatim}
+
+The first routines returns the total number of HDUs in the FITS file,
+and the second routine returns the position of the currently opened HDU in
+the FITS file (starting with 1, not 0).
+
+\begin{verbatim}
+__________________________________________________________________________
+int fits_movabs_hdu(fitsfile *fptr, int hdunum, int *hdutype, int *status)
+int fits_movrel_hdu(fitsfile *fptr, int nmove, int *hdutype, int *status)
+int fits_movnam_hdu(fitsfile *fptr, int hdutype, char *extname,
+ int extver, int *status)
+\end{verbatim}
+
+These routines enable you to move to a different HDU in the file.
+Most of the CFITSIO functions which read or write keywords or data
+operate only on the currently opened HDU in the file. The first
+routine moves to the specified absolute HDU number in the FITS
+file (the first HDU = 1), whereas the second routine moves a relative
+number of HDUs forward or backward from the currently open HDU. The
+{\tt hdutype} parameter returns the type of the newly opened HDU, and will
+be equal to one of these symbolic constant values: {\tt IMAGE\_HDU,
+ASCII\_TBL, or BINARY\_TBL}. {\tt hdutype} may be set to NULL
+if it is not needed. The third routine moves to the (first) HDU
+that matches the input extension type, name, and version number,
+as given by the {\tt XTENSION, EXTNAME} (or {\tt HDUNAME}) and {\tt EXTVER} keywords.
+If the input value of {\tt extver} = 0, then the version number will
+be ignored when looking for a matching HDU.
+
+\begin{verbatim}
+_________________________________________________________________
+int fits_get_hdu_type(fitsfile *fptr, int *hdutype, int *status)
+\end{verbatim}
+
+Get the type of the current HDU in the FITS file: {\tt IMAGE\_HDU,
+ASCII\_TBL, or BINARY\_TBL}.
+
+\begin{verbatim}
+____________________________________________________________________
+int fits_copy_hdu(fitsfile *infptr, fitsfile *outfptr, int morekeys,
+ int *status)
+int fits_copy_file(fitsfile *infptr, fitsfile *outfptr, int previous,
+ int current, int following, > int *status)
+\end{verbatim}
+
+The first routine copies the current HDU from the FITS file associated
+with infptr and appends it to the end of the FITS file associated with
+outfptr. Space may be reserved for {\tt morekeys} additional keywords
+in the output header. The second routine copies any HDUs previous
+to the current HDU, and/or the current HDU, and/or any HDUs following the
+current HDU, depending on the value (True or False) of {\tt previous,
+current}, and {\tt following}, respectively. For example,
+\begin{verbatim}
+ fits_copy_file(infptr, outfptr, 0, 1, 1, &status);
+\end{verbatim}
+will copy the current HDU and any HDUs that follow it from the input
+to the output file, but it will not copy any HDUs preceding the
+current HDU.
+
+
+\newpage
+% ===================================================================
+\subsection{Image I/O Routines}
+
+This section lists the more important CFITSIO routines which operate on
+FITS images.
+
+\begin{verbatim}
+_______________________________________________________________
+int fits_get_img_type(fitsfile *fptr, int *bitpix, int *status)
+int fits_get_img_dim( fitsfile *fptr, int *naxis, int *status)
+int fits_get_img_size(fitsfile *fptr, int maxdim, long *naxes,
+ int *status)
+int fits_get_img_param(fitsfile *fptr, int maxdim, int *bitpix,
+ int *naxis, long *naxes, int *status)
+\end{verbatim}
+
+Get information about the currently opened image HDU. The first routine
+returns the datatype of the image as (defined by the {\tt BITPIX}
+keyword), which can have the following symbolic constant values:
+\begin{verbatim}
+ BYTE_IMG = 8 ( 8-bit byte pixels, 0 - 255)
+ SHORT_IMG = 16 (16 bit integer pixels)
+ LONG_IMG = 32 (32-bit integer pixels)
+ FLOAT_IMG = -32 (32-bit floating point pixels)
+ DOUBLE_IMG = -64 (64-bit floating point pixels)
+\end{verbatim}
+
+The second and third routines return the number of dimensions in the
+image (from the {\tt NAXIS} keyword), and the sizes of each dimension
+(from the {\tt NAXIS1, NAXIS2}, etc. keywords). The last routine
+simply combines the function of the first 3 routines. The input {\tt
+maxdim} parameter in this routine gives the maximum number dimensions
+that may be returned (i.e., the dimension of the {\tt naxes}
+array)
+
+\begin{verbatim}
+__________________________________________________________
+int fits_create_img(fitsfile *fptr, int bitpix, int naxis,
+ long *naxes, int *status)
+\end{verbatim}
+
+Create an image HDU by writing the required keywords which define the
+structure of the image. The 2nd through 4th parameters specified the
+datatype, the number of dimensions, and the sizes of the dimensions.
+The allowed values of the {\tt bitpix} parameter are listed above in
+the description of the {\tt fits\_get\_img\_type} routine. If the FITS
+file pointed to by {\tt fptr} is empty (previously created with
+{\tt fits\_create\_file}) then this routine creates a primary array in
+the file, otherwise a new IMAGE extension is appended to end of the
+file following the other HDUs in the file.
+
+\begin{verbatim}
+______________________________________________________________
+int fits_write_pix(fitsfile *fptr, int datatype, long *fpixel,
+ long nelements, void *array, int *status);
+
+int fits_write_pixnull(fitsfile *fptr, int datatype, long *fpixel,
+ long nelements, void *array, void *nulval, int *status);
+
+int fits_read_pix(fitsfile *fptr, int datatype, long *fpixel,
+ long nelements, void *nulval, void *array,
+ int *anynul, int *status)
+\end{verbatim}
+
+Read or write all or part of the FITS image. There are 2 different
+'write' pixel routines: The first simply writes the input array of pixels
+to the FITS file. The second is similar, except that it substitutes
+the appropriate null pixel value in the FITS file for any pixels
+which have a value equal to {\tt *nulval} (note that this parameter
+gives the address of the null pixel value, not the value itself).
+Similarly, when reading an image, CFITSIO will substitute the value
+given by {\tt nulval} for any undefined pixels in the image, unless
+{\tt nulval = NULL}, in which case no checks will be made for undefined
+pixels when reading the FITS image.
+
+The {\tt fpixel} parameter in these routines is an array which gives
+the coordinate in each dimension of the first pixel to be read or
+written, and {\tt nelements} is the total number of pixels to read or
+write. {\tt array} is the address of an array which either contains
+the pixel values to be written, or will hold the values of the pixels
+that are read. When reading, {\tt array} must have been allocated
+large enough to hold all the returned pixel values. These routines
+starts at the {\tt fpixel} location and then read or write the {\tt
+nelements} pixels, continuing on successive rows of the image if
+necessary. For example, to write an entire 2D image, set {\tt
+fpixel[0] = fpixel[1] = 1}, and {\tt nelements = NAXIS1 * NAXIS2}. Or
+to read just the 10th row of the image, set {\tt fpixel[0] = 1,
+fpixel[1] = 10}, and {\tt nelements = NAXIS1}. The {\tt datatype}
+parameter specifies the datatype of the C {\tt array} in the program,
+which need not be the same as the datatype of the FITS image itself.
+If the datatypes differ then CFITSIO will convert the data as it is
+read or written. The following symbolic constants are allowed for the
+value of {\tt datatype}:
+\begin{verbatim}
+ TBYTE unsigned char
+ TSBYTE signed char
+ TSHORT signed short
+ TUSHORT unsigned short
+ TINT signed int
+ TUINT unsigned int
+ TLONG signed long
+ TULONG unsigned long
+ TFLOAT float
+ TDOUBLE double
+\end{verbatim}
+
+
+\begin{verbatim}
+_________________________________________________________________
+int fits_write_subset(fitsfile *fptr, int datatype, long *fpixel,
+ long *lpixel, DTYPE *array, > int *status)
+
+int fits_read_subset(fitsfile *fptr, int datatype, long *fpixel,
+ long *lpixel, long *inc, void *nulval, void *array,
+ int *anynul, int *status)
+\end{verbatim}
+
+Read or write a rectangular section of the FITS image. These are very
+similar to {\tt fits\_write\_pix} and {\tt fits\_read\_pix} except that
+you specify the last pixel coordinate (the upper right corner of the
+section) instead of the number of pixels to be read. The read routine
+also has an {\tt inc} parameter which can be used to read only every
+{\tt inc-th} pixel along each dimension of the image. Normally {\tt
+inc[0] = inc[1] = 1} to read every pixel in a 2D image. To read every
+other pixel in the entire 2D image, set
+\begin{verbatim}
+ fpixel[0] = fpixel[1] = 1
+ lpixel[0] = {NAXIS1}
+ lpixel[1] = {NAXIS2}
+ inc[0] = inc[1] = 2
+\end{verbatim}
+
+Or, to read the 8th row of a 2D image, set
+\begin{verbatim}
+ fpixel[0] = 1
+ fpixel[1] = 8
+ lpixel[0] = {NAXIS1}
+ lpixel[1] = 8
+ inc[0] = inc[1] = 1
+\end{verbatim}
+
+\newpage
+% ===================================================================
+\subsection{Table I/O Routines}
+
+This section lists the most important CFITSIO routines which operate on
+FITS tables.
+
+\begin{verbatim}
+__________________________________________________________________________
+int fits_create_tbl(fitsfile *fptr, int tbltype, long nrows, int tfields,
+ char *ttype[],char *tform[], char *tunit[], char *extname, int *status)
+\end{verbatim}
+
+Create a new table extension by writing the required keywords that
+define the table structure. The required null primary array
+will be created first if the file is initially completely empty. {\tt
+tbltype} defines the type of table and can have values of {\tt
+ASCII\_TBL or BINARY\_TBL}. Binary tables are generally preferred
+because they are more efficient and support a greater range of column
+datatypes than ASCII tables.
+
+The {\tt nrows} parameter gives the initial number of empty rows to be
+allocated for the table; this should normally be set to 0. The {\tt tfields}
+parameter gives the number of columns in the table (maximum = 999).
+The {\tt
+ttype, tform}, and {\tt tunit} parameters give the name, datatype, and
+physical units of each column, and {\tt extname} gives the name for the
+table (the value of the {\tt EXTNAME} keyword).
+The FITS Standard recommends that only
+letters, digits, and the underscore character be used in column names
+with no embedded spaces. It is recommended that all the column names
+in a given table be unique within the first 8 characters.
+
+The following table
+shows the TFORM column format values that are allowed in ASCII tables
+and in binary tables:
+\begin{verbatim}
+ ASCII Table Column Format Codes
+ -------------------------------
+ (w = column width, d = no. of decimal places to display)
+ Aw - character string
+ Iw - integer
+ Fw.d - fixed floating point
+ Ew.d - exponential floating point
+ Dw.d - exponential floating point
+
+ Binary Table Column Format Codes
+ --------------------------------
+ (r = vector length, default = 1)
+ rA - character string
+ rAw - array of strings, each of length w
+ rL - logical
+ rX - bit
+ rB - unsigned byte
+ rS - signed byte **
+ rI - signed 16-bit integer
+ rU - unsigned 16-bit integer **
+ rJ - signed 32-bit integer
+ rV - unsigned 32-bit integer **
+ rK - 64-bit integer ***
+ rE - 32-bit floating point
+ rD - 64-bit floating point
+ rC - 32-bit complex pair
+ rM - 64-bit complex pair
+
+ ** The S, U and V format codes are not actual legal TFORMn values.
+ CFITSIO substitutes the somewhat more complicated set of
+ keywords that are used to represent unsigned integers or
+ signed bytes.
+
+ *** The 64-bit integer format is experimental and is not
+ officially recognized in the FITS Standard.
+\end{verbatim}
+
+The {\tt tunit} and {\tt extname} parameters are optional and
+may be set to NULL
+if they are not needed.
+
+Note that it may be easier to create a new table by copying the
+header from another existing table with {\tt fits\_copy\_header} rather
+than calling this routine.
+
+\begin{verbatim}
+_______________________________________________________________
+int fits_get_num_rows(fitsfile *fptr, long *nrows, int *status)
+int fits_get_num_cols(fitsfile *fptr, int *ncols, int *status)
+\end{verbatim}
+
+Get the number of rows or columns in the current FITS table. The
+number of rows is given by the {\tt NAXIS2} keyword and the number of columns
+is given by the {\tt TFIELDS} keyword in the header of the table.
+
+\begin{verbatim}
+_______________________________________________________________
+int fits_get_colnum(fitsfile *fptr, int casesen, char *template,
+ int *colnum, int *status)
+int fits_get_colname(fitsfile *fptr, int casesen, char *template,
+ char *colname, int *colnum, int *status)
+\end{verbatim}
+
+Get the column number (starting with 1, not 0) of the column whose
+name matches the specified template name. The only difference in
+these 2 routines is that the 2nd one also returns the name of the
+column that matched the template string.
+
+Normally, {\tt casesen} should
+be set to {\tt CASEINSEN}, but it may be set to {\tt CASESEN} to force
+the name matching to be case-sensitive.
+
+The input {\tt template} string gives the name of the desired column and
+may include wildcard characters: a `*' matches any sequence of
+characters (including zero characters), `?' matches any single
+character, and `\#' matches any consecutive string of decimal digits
+(0-9). If more than one column name in the table matches the template
+string, then the first match is returned and the status value will be
+set to {\tt COL\_NOT\_UNIQUE} as a warning that a unique match was not
+found. To find the next column that matches the template, call this
+routine again leaving the input status value equal to {\tt
+COL\_NOT\_UNIQUE}. Repeat this process until {\tt status =
+COL\_NOT\_FOUND} is returned.
+
+\begin{verbatim}
+_______________________________________________________________
+int fits_get_coltype(fitsfile *fptr, int colnum, int *typecode,
+ long *repeat, long *width, int *status)
+
+int fits_get_eqcoltype(fitsfile *fptr, int colnum, int *typecode,
+ long *repeat, long *width, int *status)
+\end{verbatim}
+
+Return the datatype, vector repeat count, and the width in bytes of a
+single column element for column number {\tt colnum}. Allowed values
+for the returned datatype in ASCII tables are: {\tt TSTRING, TSHORT,
+TLONG, TFLOAT, and TDOUBLE}. Binary tables support these additional
+types: {\tt TLOGICAL, TBIT, TBYTE, TINT32BIT, TCOMPLEX and TDBLCOMPLEX}. The
+negative of the datatype code value is returned if it is a variable
+length array column.
+
+These 2 routines are similar, except that in the case of scaled
+integer columns the 2nd routine, fit\_get\_eqcoltype, returns the
+'equivalent' datatype that is needed to store the scaled values, which
+is not necessarily the same as the physical datatype of the unscaled values
+as stored in the FITS table. For example if a '1I' column in a binary
+table has TSCALn = 1 and TZEROn = 32768, then this column effectively
+contains unsigned short integer values, and thus the returned value of
+typecode will be TUSHORT, not TSHORT. Or, if TSCALn or TZEROn are not
+integers, then the equivalent datatype will be returned as TFLOAT or
+TDOUBLE, depending on the size of the integer.
+
+The repeat count is always 1 in ASCII tables.
+The 'repeat' parameter returns the vector repeat count on the binary
+table TFORMn keyword value. (ASCII table columns always have repeat
+= 1). The 'width' parameter returns the width in bytes of a single
+column element (e.g., a '10D' binary table column will have width =
+8, an ASCII table 'F12.2' column will have width = 12, and a binary
+table'60A' character string column will have width = 60); Note that
+this routine supports the local convention for specifying arrays of
+fixed length strings within a binary table character column using
+the syntax TFORM = 'rAw' where 'r' is the total number of
+characters (= the width of the column) and 'w' is the width of a
+unit string within the column. Thus if the column has TFORM =
+'60A12' then this means that each row of the table contains
+5 12-character substrings within the 60-character field, and thus
+in this case this routine will return typecode = TSTRING, repeat =
+60, and width = 12. The number of substings in any binary table
+character string field can be calculated by (repeat/width).
+A null pointer may be given for any of the output parameters that
+ are not needed.
+
+\begin{verbatim}
+____________________________________________________________________________
+int fits_insert_rows(fitsfile *fptr, long firstrow, long nrows, int *status)
+int fits_delete_rows(fitsfile *fptr, long firstrow, long nrows, int *status)
+int fits_delete_rowrange(fitsfile *fptr, char *rangelist, int *status)
+int fits_delete_rowlist(fitsfile *fptr, long *rowlist, long nrows, int *stat)
+\end{verbatim}
+
+Insert or delete rows in a table. The blank rows are inserted
+immediately following row {\tt frow}. Set {\tt frow} = 0 to insert rows
+at the beginning of the table. The first 'delete' routine deletes {\tt
+nrows} rows beginning with row {\tt firstrow}. The 2nd delete routine
+takes an input string listing the rows or row ranges to be deleted
+(e.g., '2,4-7, 9-12'). The last delete routine takes an input long
+integer array that specifies each individual row to be deleted. The
+row lists must be sorted in ascending order. All these routines update
+the value of the {\tt NAXIS2} keyword to reflect the new number of rows
+in the table.
+
+\begin{verbatim}
+_________________________________________________________________________
+int fits_insert_col(fitsfile *fptr, int colnum, char *ttype, char *tform,
+ int *status)
+int fits_insert_cols(fitsfile *fptr, int colnum, int ncols, char **ttype,
+ char **tform, int *status)
+
+int fits_delete_col(fitsfile *fptr, int colnum, int *status)
+\end{verbatim}
+
+Insert or delete columns in a table. {\tt colnum} gives the position
+of the column to be inserted or deleted (where the first column of the
+table is at position 1). {\tt ttype} and {\tt tform} give the column
+name and column format, where the allowed format codes are listed above
+in the description of the {\tt fits\_create\_table} routine. The 2nd
+'insert' routine inserts multiple columns, where {\tt ncols} is the
+number of columns to insert, and {\tt ttype} and {\tt tform} are
+arrays of string pointers in this case.
+
+\begin{verbatim}
+____________________________________________________________________
+int fits_copy_col(fitsfile *infptr, fitsfile *outfptr, int incolnum,
+ int outcolnum, int create_col, int *status);
+\end{verbatim}
+
+Copy a column from one table HDU to another. If {\tt create\_col} = TRUE (i.e., not equal to zero),
+then a new column will be inserted in the output table at position
+{\tt outcolumn}, otherwise the values in the existing output column will be
+overwritten.
+
+\begin{verbatim}
+__________________________________________________________________________
+int fits_write_col(fitsfile *fptr, int datatype, int colnum, long firstrow,
+ long firstelem, long nelements, void *array, int *status)
+int fits_write_colnull(fitsfile *fptr, int datatype, int colnum,
+ long firstrow, long firstelem, long nelements,
+ void *array, void *nulval, int *status)
+int fits_write_col_null(fitsfile *fptr, int colnum, long firstrow,
+ long firstelem, long nelements, int *status)
+
+int fits_read_col(fitsfile *fptr, int datatype, int colnum, long firstrow,
+ long firstelem, long nelements, void *nulval, void *array,
+ int *anynul, int *status)
+
+\end{verbatim}
+
+Write or read elements in column number {\tt colnum}, starting with row
+{\tt firstsrow} and element {\tt firstelem} (if it is a vector
+column). {\tt firstelem} is ignored if it is a scalar column. The {\tt
+nelements} number of elements are read or written continuing on
+successive rows of the table if necessary. {\tt array} is the address
+of an array which either contains the values to be written, or will
+hold the returned values that are read. When reading, {\tt array} must
+have been allocated large enough to hold all the returned values.
+
+There are 3 different 'write' column routines: The first simply writes
+the input array into the column. The second is similar, except that it
+substitutes the appropriate null pixel value in the column for any
+input array values which are equal to {\tt *nulval} (note that this
+parameter gives the address of the null pixel value, not the value
+itself). The third write routine sets the specified table elements
+to a null value. New rows will be automatical added to the table
+if the write operation extends beyond the current size of the table.
+
+When reading a column, CFITSIO will substitute the value given by {\tt
+nulval} for any undefined elements in the FITS column, unless {\tt
+nulval} or {\tt *nulval = NULL}, in which case no checks will be made
+for undefined values when reading the column.
+
+{\tt datatype} specifies the datatype of the C {\tt array} in the program,
+which need not be the same as the intrinsic datatype of the column in
+the FITS table. The following symbolic constants are allowed for the
+value of {\tt datatype}:
+
+\begin{verbatim}
+ TSTRING array of character string pointers
+ TBYTE unsigned char
+ TSHORT signed short
+ TUSHORT unsigned short
+ TINT signed int
+ TUINT unsigned int
+ TLONG signed long
+ TULONG unsigned long
+ TFLOAT float
+ TDOUBLE double
+\end{verbatim}
+
+Note that {\tt TSTRING} corresponds to the C {\tt
+char**} datatype, i.e., a pointer to an array of pointers to an array
+of characters.
+
+Any column, regardless of it's intrinsic datatype, may be read as a
+{\tt TSTRING} character string. The display format of the returned
+strings will be determined by the {\tt TDISPn} keyword, if it exists,
+otherwise a default format will be used depending on the datatype of
+the column. The {\tt tablist} example utility program (available from
+the CFITSIO web site) uses this feature to display all the values in a
+FITS table.
+
+\begin{verbatim}
+_____________________________________________________________________
+int fits_select_rows(fitsfile *infptr, fitsfile *outfptr, char *expr,
+ int *status)
+int fits_calculator(fitsfile *infptr, char *expr, fitsfile *outfptr,
+ char *colname, char *tform, int *status)
+\end{verbatim}
+
+These are 2 of the most powerful routines in the CFITSIO library. (See
+the full CFITSIO Reference Guide for a description of several related
+routines). These routines can perform complicated transformations on
+tables based on an input arithmetic expression which is evaluated for
+each row of the table. The first routine will select or copy rows of
+the table for which the expression evaluates to TRUE (i.e., not equal
+to zero). The second routine writes the value of the expression to a
+column in the output table. Rather than supplying the expression
+directly to these routines, the expression may also be written to a
+text file (continued over multiple lines if necessary) and the name of
+the file, prepended with a '@' character, may be supplied as the value
+of the 'expr' parameter (e.g. '@filename.txt').
+
+The arithmetic expression may be a function of any column or keyword in
+the input table as shown in these examples:
+
+\begin{verbatim}
+Row Selection Expressions:
+ counts > 0 uses COUNTS column value
+ sqrt( X**2 + Y**2) < 10. uses X and Y column values
+ (X > 10) || (X < -10) && (Y == 0) used 'or' and 'and' operators
+ gtifilter() filter on Good Time Intervals
+ regfilter("myregion.reg") filter using a region file
+ @select.txt reads expression from a text file
+Calculator Expressions:
+ #row % 10 modulus of the row number
+ counts/#exposure Fn of COUNTS column and EXPOSURE keyword
+ dec < 85 ? cos(dec * #deg) : 0 Conditional expression: evaluates to
+ cos(dec) if dec < 85, else 0
+ (count{-1}+count+count{+1})/3. running mean of the count values in the
+ previous, current, and next rows
+ max(0, min(X, 1000)) returns a value between 0 - 1000
+ @calc.txt reads expression from a text file
+\end{verbatim}
+
+Most standard mathematical operators and functions are supported. If
+the expression includes the name of a column, than the value in the
+current row of the table will be used when evaluating the expression on
+each row. An offset to an adjacent row can be specified by including
+the offset value in curly brackets after the column name as shown in
+one of the examples. Keyword values can be included in the expression
+by preceding the keyword name with a `\#' sign. See Section 5 of this
+document for more discussion of the expression syntax.
+
+{\tt gtifilter} is a special function which tests whether the {\tt
+TIME} column value in the input table falls within one or more Good
+Time Intervals. By default, this function looks for a 'GTI' extension
+in the same file as the input table. The 'GTI' table contains {\tt START}
+and {\tt STOP} columns which define the range of
+each good time interval. See section 5.4.3 for more details.
+
+{\tt regfilter} is another special function which selects rows based on
+whether the spatial position associated with each row is located within
+in a specified region of the sky. By default, the {\tt X} and {\tt Y}
+columns in the input table are assumed to give the position of each row.
+The spatial region is defined in an ASCII text file whose name is given
+as the argument to the {\tt regfilter} function. See section 5.4.4 for
+more details.
+
+The {\tt infptr} and {\tt outfptr} parameters in these routines may
+point to the same table or to different tables. In {\tt
+fits\_select\_rows}, if the input and output tables are the same then
+the rows that do not satisfy the selection expression will be deleted
+from the table. Otherwise, if the output table is different from the
+input table then the selected rows will be copied from the input table
+to the output table.
+
+The output column in {\tt fits\_calculator} may or may not already
+exist. If it exists then the calculated values will be written to that
+column, overwriting the existing values. If the column doesn't exist
+then the new column will be appended to the output table. The {\tt tform}
+parameter can be used to specify the datatype of the new column (e.g.,
+the {\tt TFORM} keyword value as in {\tt '1E', or '1J'}). If {\tt
+tform} = NULL then a default datatype will be used, depending on the
+expression.
+
+\begin{verbatim}
+_____________________________________________________________________
+int fits_read_tblbytes(fitsfile *fptr, long firstrow, long firstchar,
+ long nchars, unsigned char *array, int *status)
+int fits_write_tblbytes (fitsfile *fptr, long firstrow, long firstchar,
+ long nchars, unsigned char *array, int *status)
+\end{verbatim}
+
+These 2 routines provide low-level access to tables and are mainly
+useful as an efficient way to copy rows of a table from one file to
+another. These routines simply read or write the specified number of
+consecutive characters (bytes) in a table, without regard for column
+boundaries. For example, to read or write the first row of a table,
+set {\tt firstrow = 1, firstchar = 1}, and {\tt nchars = NAXIS1} where
+the length of a row is given by the value of the {\tt NAXIS1} header
+keyword. When reading a table, {\tt array} must have been declared at
+least {\tt nchars} bytes long to hold the returned string of bytes.
+
+\newpage
+% ===================================================================
+\subsection{Header Keyword I/O Routines}
+\nopagebreak
+The following routines read and write header keywords in the current HDU.
+\nopagebreak
+
+\begin{verbatim}
+____________________________________________________________________
+int fits_get_hdrspace(fitsfile *fptr, int *keysexist, int *morekeys,
+ int *status)
+\end{verbatim}
+\nopagebreak
+Return the number of existing keywords (not counting the mandatory END
+keyword) and the amount of empty space currently available for more
+keywords. The {\tt morekeys} parameter may be set to NULL if it's value is
+not needed.
+
+\begin{verbatim}
+___________________________________________________________________________
+int fits_read_record(fitsfile *fptr, int keynum, char *record, int *status)
+int fits_read_card(fitsfile *fptr, char *keyname, char *record, int *status)
+int fits_read_key(fitsfile *fptr, int datatype, char *keyname,
+ void *value, char *comment, int *status)
+
+int fits_find_nextkey(fitsfile *fptr, char **inclist, int ninc,
+ char **exclist, int nexc, char *card, int *status)
+
+int fits_read_key_unit(fitsfile *fptr, char *keyname, char *unit,
+ int *status)
+\end{verbatim}
+
+These routines all read a header record in the current HDU. The first
+routine reads keyword number {\tt keynum} (where the first keyword is
+at position 1). This routine is most commonly used when sequentially
+reading every record in the header from beginning to end. The 2nd and
+3rd routines read the named keyword and return either the whole
+80-byte record, or the keyword value and comment string.
+
+Wild card characters (*, ?, and \#) may be used when specifying the name
+of the keyword to be read, in which case the first matching keyword is
+returned.
+
+The {\tt datatype} parameter specifies the C datatype of the returned
+keyword value and can have one of the following symbolic constant
+values: {\tt TSTRING, TLOGICAL} (== int), {\tt TBYTE}, {\tt TSHORT},
+{\tt TUSHORT}, {\tt TINT}, {\tt TUINT}, {\tt TLONG}, {\tt TULONG}, {\tt
+TFLOAT}, {\tt TDOUBLE}, {\tt TCOMPLEX}, and {\tt TDBLCOMPLEX}. Data
+type conversion will be performed for numeric values if the intrinsic
+FITS keyword value does not have the same datatype. The {\tt comment}
+parameter may be set equal to NULL if the comment string is not
+needed.
+
+The 4th routine provides an easy way to find all the keywords in the
+header that match one of the name templates in {\tt inclist} and do not
+match any of the name templates in {\tt exclist}. {\tt ninc} and {\tt
+nexc} are the number of template strings in {\tt inclist} and {\tt
+exclist}, respectively. Wild cards (*, ?, and \#) may be used in the
+templates to match multiple keywords. Each time this routine is called
+it returns the next matching 80-byte keyword record. It returns status
+= {\tt KEY\_NO\_EXIST} if there are no more matches.
+
+The 5th routine returns the keyword value units string, if any.
+The units are recorded at the beginning of the keyword comment field
+enclosed in square brackets.
+\begin{verbatim}
+_______________________________________________________________
+int fits_write_key(fitsfile *fptr, int datatype, char *keyname,
+ void *value, char *comment, int *status)
+int fits_update_key(fitsfile *fptr, int datatype, char *keyname,
+ void *value, char *comment, int *status)
+int fits_write_record(fitsfile *fptr, char *card, int *status)
+
+int fits_modify_comment(fitsfile *fptr, char *keyname, char *comment,
+ int *status)
+int fits_write_key_unit(fitsfile *fptr, char *keyname, char *unit,
+ int *status)
+
+\end{verbatim}
+
+Write or modify a keyword in the header of the current HDU. The
+first routine appends the new keyword to the end of the header, whereas
+the second routine will update the value and comment fields of the
+keyword if it already exists, otherwise it behaves like the first
+routine and appends the new keyword. Note that {\tt value} gives the
+address to the value and not the value itself. The {\tt datatype}
+parameter specifies the C datatype of the keyword value and may have
+any of the values listed in the description of the keyword reading
+routines, above. A NULL may be entered for the comment parameter, in
+which case the keyword comment field will be unmodified or left
+blank.
+
+The third routine is more primitive and simply writes the 80-character
+{\tt card} record to the header. It is the programmer's responsibility
+in this case to ensure that the record conforms to all the FITS format
+requirements for a header record.
+
+The fourth routine modifies the comment string in an existing keyword,
+and the last routine writes or updates the keyword units string for an
+existing keyword. (The units are recorded at the beginning of the
+keyword comment field enclosed in square brackets).
+
+\begin{verbatim}
+___________________________________________________________________
+int fits_write_comment(fitsfile *fptr, char *comment, int *status)
+int fits_write_history(fitsfile *fptr, char *history, int *status)
+int fits_write_date(fitsfile *fptr, int *status)
+\end{verbatim}
+
+Write a {\tt COMMENT, HISTORY}, or {\tt DATE} keyword to the current
+header. The {\tt COMMENT} keyword is typically used to write a comment
+about the file or the data. The {\tt HISTORY} keyword is typically
+used to provide information about the history of the processing
+procedures that have been applied to the data. The {\tt comment} or
+{\tt history} string will be continued over multiple keywords if it is
+more than 70 characters long.
+
+The {\tt DATE} keyword is used to record the date and time that the
+FITS file was created. Note that this file creation date is usually
+different from the date of the observation which obtained the data in
+the FITS file. The {\tt DATE} keyword value is a character string in
+'yyyy-mm-ddThh:mm:ss' format. If a {\tt DATE} keyword already exists in
+the header, then this routine will update the value with the current
+system date.
+
+\begin{verbatim}
+___________________________________________________________________
+int fits_delete_record(fitsfile *fptr, int keynum, int *status)
+int fits_delete_key(fitsfile *fptr, char *keyname, int *status)
+\end{verbatim}
+
+Delete a keyword record. The first routine deletes a keyword at a
+specified position (the first keyword is at position 1, not 0),
+whereas the second routine deletes the named keyword.
+
+\begin{verbatim}
+_______________________________________________________________________
+int fits_copy_header(fitsfile *infptr, fitsfile *outfptr, int *status)
+\end{verbatim}
+
+Copy all the header keywords from the current HDU associated with
+infptr to the current HDU associated with outfptr. If the current
+output HDU is not empty, then a new HDU will be appended to the output
+file. The output HDU will then have the identical structure as the
+input HDU, but will contain no data.
+
+\newpage
+% ===================================================================
+\subsection{Utility Routines}
+
+This section lists the most important CFITSIO general utility routines.
+
+\begin{verbatim}
+___________________________________________________________________
+int fits_write_chksum( fitsfile *fptr, int *status)
+int fits_verify_chksum(fitsfile *fptr, int *dataok, int *hduok, int *status)
+\end{verbatim}
+
+These routines compute or validate the checksums for the currenrt
+HDU. The {\tt DATASUM} keyword is used to store the numerical value of
+the 32-bit, 1's complement checksum for the data unit alone. The {\tt
+CHECKSUM} keyword is used to store the ASCII encoded COMPLEMENT of the
+checksum for the entire HDU. Storing the complement, rather than the
+actual checksum, forces the checksum for the whole HDU to equal zero.
+If the file has been modified since the checksums were computed, then
+the HDU checksum will usually not equal zero.
+
+The returned {\tt dataok} and {\tt hduok} parameters will have a value
+= 1 if the data or HDU is verified correctly, a value = 0 if the
+{\tt DATASUM} or {\tt CHECKSUM} keyword is not present, or value = -1 if the
+computed checksum is not correct.
+
+
+\begin{verbatim}
+___________________________________________________________________
+int fits_parse_value(char *card, char *value, char *comment, int *status)
+int fits_get_keytype(char *value, char *dtype, int *status)
+int fits_get_keyclass(char *card)
+int fits_parse_template(char *template, char *card, int *keytype, int *status)
+
+\end{verbatim}
+
+{\tt fits\_parse\_value} parses the input 80-chararacter header keyword record, returning
+the value (as a literal character string) and comment strings. If the
+keyword has no value (columns 9-10 not equal to '= '), then a null
+value string is returned and the comment string is set equal to column
+9 - 80 of the input string.
+
+{\tt fits\_get\_keytype} parses the keyword value string to determine its
+datatype. {\tt dtype} returns with a value of 'C', 'L', 'I', 'F' or
+'X', for character string, logical, integer, floating point, or
+complex, respectively.
+
+{\tt fits\_get\_keyclass} returns a classification code that indicates
+the classification type of the input keyword record (e.g., a required
+structural keyword, a TDIM keyword, a WCS keyword, a comment keyword,
+etc. See the CFITSIO Reference Guide for a list of the different
+classification codes.
+
+{\tt fits\_parse\_template} takes an input free format keyword template
+string and returns a formatted 80*char record that satisfies all the
+FITS requirements for a header keyword record. The template should
+generally contain 3 tokens: the keyword name, the keyword value, and
+the keyword comment string. The returned {\tt keytype} parameter
+indicates whether the keyword is a COMMENT keyword or not. See the
+CFITSIO Reference Guide for more details.
+
+\newpage
+% ===================================================================
+\section{CFITSIO File Names and Filters}
+
+\subsection{Creating New Files}
+
+When creating a new output file on magnetic disk with {\tt
+fits\_create\_file} the following features are supported.
+\begin{itemize}
+\item Overwriting, or 'Clobbering' an Existing File
+
+If the filename is preceded by an exclamation
+point (!) then if that file already exists it will be deleted prior to
+creating the new FITS file. Otherwise if there is an existing file
+with the same name, CFITSIO will not overwrite the existing file and
+will return an error status code. Note that the exclamation point is
+a special UNIX character, so if it is used on the command line rather
+than entered at a task prompt, it must be preceded by a backslash to
+force the UNIX shell to pass it verbatim to the application program.
+
+\item Compressed Output Files
+
+If the output disk file name ends with the suffix '.gz', then CFITSIO
+will compress the file using the gzip compression algorithm before
+writing it to disk. This can reduce the amount of disk space used by
+the file. Note that this feature requires that the uncompressed file
+be constructed in memory before it is compressed and written to disk,
+so it can fail if there is insufficient available memory.
+
+One can also specify that any images written to the output file should
+be compressed using the newly developed `tile-compression' algorithm by
+appending `[compress]' to the name of the disk file (as in
+{\tt myfile.fits[compress]}). Refer to the CFITSIO User's Reference Guide
+for more information about this new image compression format.
+
+\item Using a Template to Create a New FITS File
+
+The structure of any new FITS file that is to be created may be defined
+in an ASCII template file. If the name of the template file is
+appended to the name of the FITS file itself, enclosed in parenthesis
+(e.g., {\tt 'newfile.fits(template.txt)'}) then CFITSIO will create a
+FITS file with that structure before opening it for the application to
+use. The template file basically defines the dimensions and data type
+of the primary array and any IMAGE extensions, and the names and data
+types of the columns in any ASCII or binary table extensions. The
+template file can also be used to define any optional keywords that
+should be written in any of the HDU headers. The image pixel values
+and table entry values are all initialized to zero. The application
+program can then write actual data into the HDUs. See the CFITSIO
+Reference Guide for for a complete description of the template file
+syntax.
+
+\item Creating a Temporary Scratch File in Memory
+
+It is sometimes useful to create a temporary output file when testing
+an application program. If the name of the file to be created is
+specified as {\tt mem:} then CFITSIO will create the file in
+memory where it will persist only until the program closes the file.
+Use of this {\tt mem:} output file usually enables the program to run
+faster, and of course the output file does not use up any disk space.
+
+
+\end{itemize}
+
+\subsection{Opening Existing Files}
+
+When opening a file with {\tt fits\_open\_file}, CFITSIO can read a
+variety of different input file formats and is not restricted to only
+reading FITS format files from magnetic disk. The following types of
+input files are all supported:
+
+\begin{itemize}
+\item FITS files compressed with {\tt zip, gzip} or {\tt compress}
+
+If CFITSIO cannot find the specified file to open it will automatically
+look for a file with the same rootname but with a {\tt .gz, .zip}, or
+{\tt .Z} extension. If it finds such a compressed file, it will
+allocate a block of memory and uncompress the file into that memory
+space. The application program will then transparently open this
+virtual FITS file in memory. Compressed
+files can only be opened with 'readonly', not 'readwrite' file access.
+
+\item FITS files on the internet, using {\tt ftp} or {\tt http} URLs
+
+Simply provide the full URL as the name of the file that you want to
+open. For example,\linebreak {\tt
+ftp://legacy.gsfc.nasa.gov/software/fitsio/c/testprog.std}\linebreak
+will open the CFITSIO test FITS file that is located on the {\tt
+legacy} machine. These files can only be opened with 'readonly' file
+access.
+
+\item FITS files on {\tt stdin} or {\tt stdout} file streams
+
+If the name of the file to be opened is {\tt 'stdin'} or {\tt '-'} (a
+single dash character) then CFITSIO will read the file from the
+standard input stream. Similarly, if the output file name is {\tt
+'stdout'} or {\tt '-'}, then the file will be written to the standard
+output stream. In addition, if the output filename is {\tt
+'stdout.gz'} or {\tt '-.gz'} then it will be gzip compressed before
+being written to stdout. This mechanism can be used to pipe FITS files
+from one task to another without having to write an intermediary FITS
+file on magnetic disk.
+
+\item FITS files that exist only in memory, or shared memory.
+
+In some applications, such as real time data acquisition, you may want
+to have one process write a FITS file into a certain section of
+computer memory, and then be able to open that file in memory with
+another process. There is a specialized CFITSIO open routine called
+{\tt fits\_open\_memfile} that can be used for this purpose. See the
+``CFITSIO User's Reference Guide'' for more details.
+
+\item IRAF format images (with {\tt .imh} file extensions)
+
+CFITSIO supports reading IRAF format images by converting them on the
+fly into FITS images in memory. The application program then reads
+this virtual FITS format image in memory. There is currently no
+support for writing IRAF format images, or for reading or writing IRAF
+tables.
+
+\item Image arrays in raw binary format
+
+If the input file is a raw binary data array, then CFITSIO will convert
+it on the fly into a virtual FITS image with the basic set of required
+header keywords before it is opened by the application program. In
+this case the data type and dimensions of the image must be specified
+in square brackets following the filename (e.g. {\tt
+rawfile.dat[ib512,512]}). The first character inside the brackets
+defines the datatype of the array:
+
+\begin{verbatim}
+ b 8-bit unsigned byte
+ i 16-bit signed integer
+ u 16-bit unsigned integer
+ j 32-bit signed integer
+ r or f 32-bit floating point
+ d 64-bit floating point
+\end{verbatim}
+An optional second character specifies the byte order of the array
+values: b or B indicates big endian (as in FITS files and the native
+format of SUN UNIX workstations and Mac PCs) and l or L indicates
+little endian (native format of DEC OSF workstations and IBM PCs). If
+this character is omitted then the array is assumed to have the native
+byte order of the local machine. These datatype characters are then
+followed by a series of one or more integer values separated by commas
+which define the size of each dimension of the raw array. Arrays with
+up to 5 dimensions are currently supported.
+
+Finally, a byte offset to the position of the first pixel in the data
+file may be specified by separating it with a ':' from the last
+dimension value. If omitted, it is assumed that the offset = 0. This
+parameter may be used to skip over any header information in the file
+that precedes the binary data. Further examples:
+
+\begin{verbatim}
+ raw.dat[b10000] 1-dimensional 10000 pixel byte array
+ raw.dat[rb400,400,12] 3-dimensional floating point big-endian array
+ img.fits[ib512,512:2880] reads the 512 x 512 short integer array in a
+ FITS file, skipping over the 2880 byte header
+\end{verbatim}
+
+\end{itemize}
+\newpage
+
+\subsection{Image Filtering}
+
+\subsubsection{Extracting a subsection of an image}
+
+When specifying the name of an image to be opened, you can select a
+rectangular subsection of the image to be extracted and opened by the
+application program. The application program then opens a virtual
+image that only contains the pixels within the specified subsection.
+To do this, specify the the range of pixels (start:end) along each axis
+to be extracted from the original image enclosed in square brackets.
+You can also specify an optional pixel increment (start:end:step) for
+each axis of the input image. A pixel step = 1 will be assumed if it
+is not specified. If the starting pixel is larger then the end pixel,
+then the image will be flipped (producing a mirror image) along that
+dimension. An asterisk, '*', may be used to specify the entire range
+of an axis, and '-*' will flip the entire axis. In the following
+examples, assume that {\tt myfile.fits} contains a 512 x 512 pixel 2D
+image.
+
+\begin{verbatim}
+ myfile.fits[201:210, 251:260] - opens a 10 x 10 pixel subimage.
+
+ myfile.fits[*, 512:257] - opens a 512 x 256 image consisting of
+ all the columns in the input image, but only rows 257
+ through 512. The image will be flipped along the Y axis
+ since the starting row is greater than the ending
+ row.
+
+ myfile.fits[*:2, 512:257:2] - creates a 256 x 128 pixel image.
+ Similar to the previous example, but only every other row
+ and column is read from the input image.
+
+ myfile.fits[-*, *] - creates an image containing all the rows and
+ columns in the input image, but flips it along the X
+ axis.
+\end{verbatim}
+
+If the array to be opened is in an Image extension, and not in the
+primary array of the file, then you need to specify the extension
+name or number in square brackets before giving the subsection range,
+as in {\tt myfile.fits[1][-*, *]} to read the image in the
+first extension in the file.
+
+\subsubsection{Create an Image by Binning Table Columns}
+
+You can also create and open a virtual image by binning the values in a
+pair of columns of a FITS table (in other words, create a 2-D histogram
+of the values in the 2 columns). This technique is often used in X-ray
+astronomy where each detected X-ray photon during an observation is
+recorded in a FITS table. There are typically 2 columns in the table
+called {\tt X} and {\tt Y} which record the pixel location of that
+event in a virtual 2D image. To create an image from this table, one
+just scans the X and Y columns and counts up how many photons were
+recorded in each pixel of the image. When table binning is specified,
+CFITSIO creates a temporary FITS primary array in memory by computing
+the histogram of the values in the specified columns. After the
+histogram is computed the original FITS file containing the table is
+closed and the temporary FITS primary array is opened and passed to the
+application program. Thus, the application program never sees the
+original FITS table and only sees the image in the new temporary file
+(which has no extensions).
+
+The table binning specifier is enclosed in square brackets following
+the root filename and table extension name or number and begins with
+the keyword 'bin', as in: \newline
+{\tt 'myfile.fits[events][bin (X,Y)]'}. In
+this case, the X and Y columns in the 'events' table extension are
+binned up to create the image. The size of the image is usually
+determined by the {\tt TLMINn} and {\tt TLMAXn} header keywords which
+give the minimum and maximum allowed pixel values in the columns. For
+instance if {\tt TLMINn = 1} and {\tt TLMAXn = 4096} for both columns, this would
+generate a 4096 x 4096 pixel image by default. This is rather large,
+so you can also specify a pixel binning factor to reduce the image
+size. For example specifying , {\tt '[bin (X,Y) = 16]'} will use a
+binning factor of 16, which will produce a 256 x 256 pixel image in the
+previous example.
+
+If the TLMIN and TLMAX keywords don't exist, or you want to override
+their values, you can specify the image range and binning factor
+directly, as in {\tt '[bin X = 1:4096:16, Y=1:4096:16]'}. You can also
+specify the datatype of the created image by appending a b, i, j, r, or
+d (for 8-bit byte, 16-bit integers, 32-bit integer, 32-bit floating
+points, or 64-bit double precision floating point, respectively) to
+the 'bin' keyword (e.g. {\tt '[binr (X,Y)]'} creates a floating point
+image). If the datatype is not specified then a 32-bit integer image
+will be created by default.
+
+If the column name is not specified, then CFITSIO will first try to use
+the 'preferred column' as specified by the CPREF keyword if it exists
+(e.g., 'CPREF = 'DETX,DETY'), otherwise column names 'X', 'Y' will be
+assumed for the 2 axes.
+
+Note that this binning specifier is not restricted to only 2D images
+and can be used to create 1D, 3D, or 4D images as well. It is also
+possible to specify a weighting factor that is applied during the
+binning. Please refer to the ``CFITSIO User's Reference Guide'' for
+more details on these advanced features.
+\newpage
+
+\subsection{Table Filtering}
+
+\subsubsection{Column and Keyword Filtering}
+
+The column or keyword filtering specifier is used to modify the
+column structure and/or the header keywords in the HDU that was
+selected with the previous HDU location specifier. It can
+be used to perform the following types of operations.
+
+\begin{itemize}
+\item
+Append a new column to a table by giving the column name, optionally
+followed by the datatype in parentheses, followed by an equals sign and
+the arithmetic expression to be used to compute the value. The
+datatype is specified using the same syntax that is allowed for the
+value of the FITS TFORMn keyword (e.g., 'I', 'J', 'E', 'D', etc. for
+binary tables, and 'I8', F12.3', 'E20.12', etc. for ASCII tables). If
+the datatype is not specified then a default datatype will be chosen
+depending on the expression.
+
+\item
+Create a new header keyword by giving the keyword name, preceded by a
+pound sign '\#', followed by an equals sign and an arithmetic
+expression for the value of the keyword. The expression may be a
+function of other header keyword values. The comment string for the
+keyword may be specified in parentheses immediately following the
+keyword name.
+
+\item
+Overwrite the values in an existing column or keyword by giving the
+name followed by an equals sign and an arithmetic expression.
+
+\item
+Select a set of columns to be included in the filtered file by listing
+the column names separated with semi-colons. Wild card characters may
+be used in the column names to match multiple columns. Any other
+columns in the input table will not appear in the filtered file.
+
+\item
+Delete a column or keyword by listing the name preceded by a minus sign
+or an exclamation mark (!)
+
+\item
+Rename an existing column or keyword with the syntax 'NewName ==
+OldName'.
+
+\end{itemize}
+
+The column filtering specifier is enclosed in square brackets and
+begins with the string 'col'. Multiple operations can be performed
+by separating them with semi-colons. For complex or commonly used
+operations, you can write the column filter to a text file, and then
+use it by giving the name of the text file, preceded by a '@'
+character.
+
+Some examples:
+
+\begin{verbatim}
+ [col PI=PHA * 1.1 + 0.2] - creates new PI column from PHA values
+
+ [col rate = counts/exposure] - creates or overwrites the rate column by
+ dividing the counts column by the
+ EXPOSURE keyword value.
+
+ [col TIME; X; Y] - only the listed columns will appear
+ in the filtered file
+
+ [col Time;*raw] - include the Time column and any other
+ columns whose name ends with 'raw'.
+
+ [col -TIME; Good == STATUS] - deletes the TIME column and
+ renames the STATUS column to GOOD
+
+ [col @colfilt.txt] - uses the filtering expression in
+ the colfilt.txt text file
+\end{verbatim}
+
+The original file is not changed by this filtering operation, and
+instead the modifications are made on a temporary copy of the input
+FITS file (usually in memory), which includes a copy of all the other
+HDUs in the input file. The original input file is closed and the
+application program opens the filtered copy of the file.
+
+\subsubsection{Row Filtering}
+
+The row filter is used to select a subset of the rows from a table
+based on a boolean expression. A temporary new FITS file is created on
+the fly (usually in memory) which contains only those rows for which
+the row filter expression evaluates to true (i.e., not equal to zero).
+The primary array and any other extensions in the input file are also
+copied to the temporary file. The original FITS file is closed and the
+new temporary file is then opened by the application program.
+
+The row filter expression is enclosed in square brackets following the
+file name and extension name. For example, {\tt
+'file.fits[events][GRADE==50]'} selects only those rows in the EVENTS
+table where the GRADE column value is equal to 50).
+
+The row filtering expression can be an arbitrarily complex series of
+operations performed on constants, keyword values, and column data
+taken from the specified FITS TABLE extension. The expression
+also can be written into a text file and then used by giving the
+filename preceded by a '@' character, as in
+{\tt '[@rowfilt.txt]'}.
+
+Keyword and column data are referenced by name. Any string of
+characters not surrounded by quotes (ie, a constant string) or
+followed by an open parentheses (ie, a function name) will be
+initially interpreted as a column name and its contents for the
+current row inserted into the expression. If no such column exists,
+a keyword of that name will be searched for and its value used, if
+found. To force the name to be interpreted as a keyword (in case
+there is both a column and keyword with the same name), precede the
+keyword name with a single pound sign, '\#', as in {\tt \#NAXIS2}. Due to
+the generalities of FITS column and keyword names, if the column or
+keyword name contains a space or a character which might appear as
+an arithmetic term then inclose the name in '\$' characters as in
+{\tt \$MAX PHA\$} or {\tt \#\$MAX-PHA\$}. The names are case insensitive.
+
+To access a table entry in a row other than the current one, follow
+the column's name with a row offset within curly braces. For
+example, {\tt'PHA\{-3\}'} will evaluate to the value of column PHA, 3 rows
+above the row currently being processed. One cannot specify an
+absolute row number, only a relative offset. Rows that fall outside
+the table will be treated as undefined, or NULLs.
+
+Boolean operators can be used in the expression in either their
+Fortran or C forms. The following boolean operators are available:
+
+\begin{verbatim}
+ "equal" .eq. .EQ. == "not equal" .ne. .NE. !=
+ "less than" .lt. .LT. < "less than/equal" .le. .LE. <= =<
+ "greater than" .gt. .GT. > "greater than/equal" .ge. .GE. >= =>
+ "or" .or. .OR. || "and" .and. .AND. &&
+ "negation" .not. .NOT. ! "approx. equal(1e-7)" ~
+\end{verbatim}
+
+Note that the exclamation point, '!', is a special UNIX character, so
+if it is used on the command line rather than entered at a task
+prompt, it must be preceded by a backslash to force the UNIX shell to
+ignore it.
+
+The expression may also include arithmetic operators and functions.
+Trigonometric functions use radians, not degrees. The following
+arithmetic operators and functions can be used in the expression
+(function names are case insensitive):
+
+
+\begin{verbatim}
+ "addition" + "subtraction" -
+ "multiplication" * "division" /
+ "negation" - "exponentiation" ** ^
+ "absolute value" abs(x) "cosine" cos(x)
+ "sine" sin(x) "tangent" tan(x)
+ "arc cosine" arccos(x) "arc sine" arcsin(x)
+ "arc tangent" arctan(x) "arc tangent" arctan2(x,y)
+ "exponential" exp(x) "square root" sqrt(x)
+ "natural log" log(x) "common log" log10(x)
+ "modulus" i % j "random # [0.0,1.0)" random()
+ "minimum" min(x,y) "maximum" max(x,y)
+ "if-then-else" b?x:y
+\end{verbatim}
+
+
+The following type casting operators are available, where the
+inclosing parentheses are required and taken from the C language
+usage. Also, the integer to real casts values to double precision:
+
+\begin{verbatim}
+ "real to integer" (int) x (INT) x
+ "integer to real" (float) i (FLOAT) i
+\end{verbatim}
+
+
+Several constants are built in for use in numerical
+expressions:
+
+
+\begin{verbatim}
+ #pi 3.1415... #e 2.7182...
+ #deg #pi/180 #row current row number
+ #null undefined value #snull undefined string
+\end{verbatim}
+
+A string constant must be enclosed in quotes as in 'Crab'. The
+"null" constants are useful for conditionally setting table values to
+a NULL, or undefined, value (For example, {\tt "col1==-99 ? \#NULL :
+col1"}).
+
+There is also a function for testing if two values are close to
+each other, i.e., if they are "near" each other to within a user
+specified tolerance. The arguments, {\tt value\_1} and {\tt value\_2} can be
+integer or real and represent the two values who's proximity is
+being tested to be within the specified tolerance, also an integer
+or real:
+
+\begin{verbatim}
+ near(value_1, value_2, tolerance)
+\end{verbatim}
+
+When a NULL, or undefined, value is encountered in the FITS table,
+the expression will evaluate to NULL unless the undefined value is
+not actually required for evaluation, e.g. "TRUE .or. NULL"
+evaluates to TRUE. The following two functions allow some NULL
+detection and handling:
+
+\begin{verbatim}
+ ISNULL(x)
+ DEFNULL(x,y)
+\end{verbatim}
+
+The former returns a boolean value of TRUE if the argument x is
+NULL. The later "defines" a value to be substituted for NULL
+values; it returns the value of x if x is not NULL, otherwise it
+returns the value of y.
+
+Bit masks can be used to select out rows from bit columns ({\tt TFORMn =
+\#X}) in FITS files. To represent the mask, binary, octal, and hex
+formats are allowed:
+
+\begin{verbatim}
+ binary: b0110xx1010000101xxxx0001
+ octal: o720x1 -> (b111010000xxx001)
+ hex: h0FxD -> (b00001111xxxx1101)
+\end{verbatim}
+
+In all the representations, an x or X is allowed in the mask as a
+wild card. Note that the x represents a different number of wild
+card bits in each representation. All representations are case
+insensitive.
+
+To construct the boolean expression using the mask as the boolean
+equal operator described above on a bit table column. For example,
+if you had a 7 bit column named flags in a FITS table and wanted
+all rows having the bit pattern 0010011, the selection expression
+would be:
+
+
+\begin{verbatim}
+ flags == b0010011
+ or
+ flags .eq. b10011
+\end{verbatim}
+
+It is also possible to test if a range of bits is less than, less
+than equal, greater than and greater than equal to a particular
+boolean value:
+
+
+\begin{verbatim}
+ flags <= bxxx010xx
+ flags .gt. bxxx100xx
+ flags .le. b1xxxxxxx
+\end{verbatim}
+
+Notice the use of the x bit value to limit the range of bits being
+compared.
+
+It is not necessary to specify the leading (most significant) zero
+(0) bits in the mask, as shown in the second expression above.
+
+Bit wise AND, OR and NOT operations are also possible on two or
+more bit fields using the '\&'(AND), '$|$'(OR), and the '!'(NOT)
+operators. All of these operators result in a bit field which can
+then be used with the equal operator. For example:
+
+
+\begin{verbatim}
+ (!flags) == b1101100
+ (flags & b1000001) == bx000001
+\end{verbatim}
+
+Bit fields can be appended as well using the '+' operator. Strings
+can be concatenated this way, too.
+
+\subsubsection{Good Time Interval Filtering}
+
+ A common filtering method involves selecting rows which have a time
+ value which lies within what is called a Good Time Interval or GTI.
+ The time intervals are defined in a separate FITS table extension
+ which contains 2 columns giving the start and stop time of each
+ good interval. The filtering operation accepts only those rows of
+ the input table which have an associated time which falls within
+ one of the time intervals defined in the GTI extension. A high
+ level function, gtifilter(a,b,c,d), is available which evaluates
+ each row of the input table and returns TRUE or FALSE depending
+ whether the row is inside or outside the good time interval. The
+ syntax is
+
+\begin{verbatim}
+ gtifilter( [ "gtifile" [, expr [, "STARTCOL", "STOPCOL" ] ] ] )
+\end{verbatim}
+ where each "[]" demarks optional parameters. Note that the quotes
+ around the gtifile and START/STOP column are required. Either single
+ or double quote characters may be used. The gtifile,
+ if specified, can be blank ("") which will mean to use the first
+ extension with the name "*GTI*" in the current file, a plain
+ extension specifier (eg, "+2", "[2]", or "[STDGTI]") which will be
+ used to select an extension in the current file, or a regular
+ filename with or without an extension specifier which in the latter
+ case will mean to use the first extension with an extension name
+ "*GTI*". Expr can be any arithmetic expression, including simply
+ the time column name. A vector time expression will produce a
+ vector boolean result. STARTCOL and STOPCOL are the names of the
+ START/STOP columns in the GTI extension. If one of them is
+ specified, they both must be.
+
+ In its simplest form, no parameters need to be provided -- default
+ values will be used. The expression {\tt "gtifilter()"} is equivalent to
+
+\begin{verbatim}
+ gtifilter( "", TIME, "*START*", "*STOP*" )
+\end{verbatim}
+ This will search the current file for a GTI extension, filter the
+ TIME column in the current table, using START/STOP times taken from
+ columns in the GTI extension with names containing the strings
+ "START" and "STOP". The wildcards ('*') allow slight variations in
+ naming conventions such as "TSTART" or "STARTTIME". The same
+ default values apply for unspecified parameters when the first one
+ or two parameters are specified. The function automatically
+ searches for TIMEZERO/I/F keywords in the current and GTI
+ extensions, applying a relative time offset, if necessary.
+
+\subsubsection{Spatial Region Filtering}
+
+ Another common filtering method selects rows based on whether the
+ spatial position associated with each row is located within a given
+ 2-dimensional region. The syntax for this high-level filter is
+
+\begin{verbatim}
+ regfilter( "regfilename" [ , Xexpr, Yexpr [ , "wcs cols" ] ] )
+\end{verbatim}
+ where each "[ ]" demarks optional parameters. The region file name
+ is required and must be enclosed in quotes. The remaining
+ parameters are optional. The region file is an ASCII text file
+ which contains a list of one or more geometric shapes (circle,
+ ellipse, box, etc.) which defines a region on the celestial sphere
+ or an area within a particular 2D image. The region file is
+ typically generated using an image display program such as fv/POW
+ (distribute by the HEASARC), or ds9 (distributed by the Smithsonian
+ Astrophysical Observatory). Users should refer to the documentation
+ provided with these programs for more details on the syntax used in
+ the region files.
+
+ In its simpliest form, (e.g., {\tt regfilter("region.reg")} ) the
+ coordinates in the default 'X' and 'Y' columns will be used to
+ determine if each row is inside or outside the area specified in
+ the region file. Alternate position column names, or expressions,
+ may be entered if needed, as in
+
+\begin{verbatim}
+ regfilter("region.reg", XPOS, YPOS)
+\end{verbatim}
+ Region filtering can be applied most unambiguously if the positions
+ in the region file and in the table to be filtered are both give in
+ terms of absolute celestial coordinate units. In this case the
+ locations and sizes of the geometric shapes in the region file are
+ specified in angular units on the sky (e.g., positions given in
+ R.A. and Dec. and sizes in arcseconds or arcminutes). Similarly,
+ each row of the filtered table will have a celestial coordinate
+ associated with it. This association is usually implemented using
+ a set of so-called 'World Coordinate System' (or WCS) FITS keywords
+ that define the coordinate transformation that must be applied to
+ the values in the 'X' and 'Y' columns to calculate the coordinate.
+
+ Alternatively, one can perform spatial filtering using unitless
+ 'pixel' coordinates for the regions and row positions. In this
+ case the user must be careful to ensure that the positions in the 2
+ files are self-consistent. A typical problem is that the region
+ file may be generated using a binned image, but the unbinned
+ coordinates are given in the event table. The ROSAT events files,
+ for example, have X and Y pixel coordinates that range from 1 -
+ 15360. These coordinates are typically binned by a factor of 32 to
+ produce a 480x480 pixel image. If one then uses a region file
+ generated from this image (in image pixel units) to filter the
+ ROSAT events file, then the X and Y column values must be converted
+ to corresponding pixel units as in:
+
+\begin{verbatim}
+ regfilter("rosat.reg", X/32.+.5, Y/32.+.5)
+\end{verbatim}
+ Note that this binning conversion is not necessary if the region
+ file is specified using celestial coordinate units instead of pixel
+ units because CFITSIO is then able to directly compare the
+ celestial coordinate of each row in the table with the celestial
+ coordinates in the region file without having to know anything
+ about how the image may have been binned.
+
+ The last "wcs cols" parameter should rarely be needed. If supplied,
+ this string contains the names of the 2 columns (space or comma
+ separated) which have the associated WCS keywords. If not supplied,
+ the filter will scan the X and Y expressions for column names.
+ If only one is found in each expression, those columns will be
+ used, otherwise an error will be returned.
+
+ These region shapes are supported (names are case insensitive):
+
+\begin{verbatim}
+ Point ( X1, Y1 ) <- One pixel square region
+ Line ( X1, Y1, X2, Y2 ) <- One pixel wide region
+ Polygon ( X1, Y1, X2, Y2, ... ) <- Rest are interiors with
+ Rectangle ( X1, Y1, X2, Y2, A ) | boundaries considered
+ Box ( Xc, Yc, Wdth, Hght, A ) V within the region
+ Diamond ( Xc, Yc, Wdth, Hght, A )
+ Circle ( Xc, Yc, R )
+ Annulus ( Xc, Yc, Rin, Rout )
+ Ellipse ( Xc, Yc, Rx, Ry, A )
+ Elliptannulus ( Xc, Yc, Rinx, Riny, Routx, Routy, Ain, Aout )
+ Sector ( Xc, Yc, Amin, Amax )
+\end{verbatim}
+ where (Xc,Yc) is the coordinate of the shape's center; (X\#,Y\#) are
+ the coordinates of the shape's edges; Rxxx are the shapes' various
+ Radii or semimajor/minor axes; and Axxx are the angles of rotation
+ (or bounding angles for Sector) in degrees. For rotated shapes, the
+ rotation angle can be left off, indicating no rotation. Common
+ alternate names for the regions can also be used: rotbox = box;
+ rotrectangle = rectangle; (rot)rhombus = (rot)diamond; and pie
+ = sector. When a shape's name is preceded by a minus sign, '-',
+ the defined region is instead the area *outside* its boundary (ie,
+ the region is inverted). All the shapes within a single region
+ file are OR'd together to create the region, and the order is
+ significant. The overall way of looking at region files is that if
+ the first region is an excluded region then a dummy included region
+ of the whole detector is inserted in the front. Then each region
+ specification as it is processed overrides any selections inside of
+ that region specified by previous regions. Another way of thinking
+ about this is that if a previous excluded region is completely
+ inside of a subsequent included region the excluded region is
+ ignored.
+
+ The positional coordinates may be given either in pixel units,
+ decimal degrees or hh:mm:ss.s, dd:mm:ss.s units. The shape sizes
+ may be given in pixels, degrees, arcminutes, or arcseconds. Look
+ at examples of region file produced by fv/POW or ds9 for further
+ details of the region file format.
+
+\subsubsection{Example Row Filters}
+
+\begin{verbatim}
+ [double && mag <= 5.0] - Extract all double stars brighter
+ than fifth magnitude
+
+ [#row >= 125 && #row <= 175] - Extract row numbers 125 through 175
+
+ [abs(sin(theta * #deg)) < 0.5] - Extract all rows having the
+ absolute value of the sine of theta
+ less than a half where the angles
+ are tabulated in degrees
+
+ [@rowFilter.txt] - Extract rows using the expression
+ contained within the text file
+ rowFilter.txt
+
+ [gtifilter()] - Search the current file for a GTI
+ extension, filter the TIME
+ column in the current table, using
+ START/STOP times taken from
+ columns in the GTI extension
+
+ [regfilter("pow.reg")] - Extract rows which have a coordinate
+ (as given in the X and Y columns)
+ within the spatial region specified
+ in the pow.reg region file.
+\end{verbatim}
+
+\newpage
+\subsection{Combined Filtering Examples}
+
+The previous sections described all the individual types of filters
+that may be applied to the input file. In this section we show
+examples which combine several different filters at once. These
+examples all use the {\tt fitscopy} program that is distributed with
+the CFITSIO code. It simply copies the input file to the output file.
+
+\begin{verbatim}
+fitscopy rosat.fit out.fit
+\end{verbatim}
+
+This trivial example simply makes an identical copy of the input
+rosat.fit file without any filtering.
+
+\begin{verbatim}
+fitscopy 'rosat.fit[events][col Time;X;Y][#row < 1000]' out.fit
+\end{verbatim}
+
+The output file contains only the Time, X, and Y columns, and only
+the first 999 rows from the 'EVENTS' table extension of the input file.
+All the other HDUs in the input file are copied to the output file
+without any modification.
+
+\begin{verbatim}
+fitscopy 'rosat.fit[events][PI < 50][bin (Xdet,Ydet) = 16]' image.fit
+\end{verbatim}
+
+This creates an output image by binning the Xdet and Ydet columns of
+the events table with a pixel binning factor of 16. Only the rows
+which have a PI energy less than 50 are used to construct this image.
+The output image file contains a primary array image without any
+extensions.
+
+\begin{verbatim}
+fitscopy 'rosat.fit[events][gtifilter() && regfilter("pow.reg")]' out.fit
+\end{verbatim}
+
+The filtering expression in this example uses the {\tt gtifilter}
+function to test whether the TIME column value in each row is within
+one of the Good Time Intervals defined in the GTI extension in the same
+input file, and also uses the {\tt regfilter} function to test if the
+position associated with each row (derived by default from the values
+in the X and Y columns of the events table) is located within the area
+defined in the {\tt pow.reg} text region file (which was previously
+created with the {\tt fv/POW} image display program). Only the rows
+which satisfy both tests are copied to the output table.
+
+\begin{verbatim}
+fitscopy 'r.fit[evt][PI<50]' stdout | fitscopy stdin[evt][col X,Y] out.fit
+\end{verbatim}
+
+In this somewhat convoluted example, fitscopy is used to first select
+the rows from the evt extension which have PI less than 50 and write the
+resulting table out to the stdout stream. This is piped to a 2nd
+instance of fitscopy (with the Unix `$|$' pipe command) which reads that
+filtered FITS file from the stdin stream and copies only the X and Y
+columns from the evt table to the output file.
+
+\begin{verbatim}
+fitscopy 'r.fit[evt][col RAD=sqrt((X-#XCEN)**2+(Y-#YCEN)**2)][rad<100]' out.fit
+\end{verbatim}
+
+This example first creates a new column called RAD which gives the
+distance between the X,Y coordinate of each event and the coordinate
+defined by the XCEN and YCEN keywords in the header. Then, only those
+rows which have a distance less than 100 are copied to the output
+table. In other words, only the events which are located within 100
+pixel units from the (XCEN, YCEN) coordinate are copied to the output
+table.
+
+\begin{verbatim}
+fitscopy 'ftp://heasarc.gsfc.nasa.gov/rosat.fit[events][bin (X,Y)=16]' img.fit
+\end{verbatim}
+
+This example bins the X and Y columns of the hypothetical ROSAT file
+at the HEASARC ftp site to create the output image.
+
+\begin{verbatim}
+fitscopy 'raw.fit[i512,512][101:110,51:60]' image.fit
+\end{verbatim}
+
+This example converts the 512 x 512 pixel raw binary 16-bit integer
+image to a FITS file and copies a 10 x 10 pixel subimage from it to the
+output FITS image.
+
+\newpage
+\section{CFITSIO Error Status Codes}
+
+The following table lists all the error status codes used by CFITSIO.
+Programmers are encouraged to use the symbolic mnemonics (defined in
+the file fitsio.h) rather than the actual integer status values to
+improve the readability of their code.
+
+\begin{verbatim}
+ Symbolic Const Value Meaning
+ -------------- ----- -----------------------------------------
+ 0 OK, no error
+ SAME_FILE 101 input and output files are the same
+ TOO_MANY_FILES 103 tried to open too many FITS files at once
+ FILE_NOT_OPENED 104 could not open the named file
+ FILE_NOT_CREATED 105 could not create the named file
+ WRITE_ERROR 106 error writing to FITS file
+ END_OF_FILE 107 tried to move past end of file
+ READ_ERROR 108 error reading from FITS file
+ FILE_NOT_CLOSED 110 could not close the file
+ ARRAY_TOO_BIG 111 array dimensions exceed internal limit
+ READONLY_FILE 112 Cannot write to readonly file
+ MEMORY_ALLOCATION 113 Could not allocate memory
+ BAD_FILEPTR 114 invalid fitsfile pointer
+ NULL_INPUT_PTR 115 NULL input pointer to routine
+ SEEK_ERROR 116 error seeking position in file
+
+ BAD_URL_PREFIX 121 invalid URL prefix on file name
+ TOO_MANY_DRIVERS 122 tried to register too many IO drivers
+ DRIVER_INIT_FAILED 123 driver initialization failed
+ NO_MATCHING_DRIVER 124 matching driver is not registered
+ URL_PARSE_ERROR 125 failed to parse input file URL
+
+ SHARED_BADARG 151 bad argument in shared memory driver
+ SHARED_NULPTR 152 null pointer passed as an argument
+ SHARED_TABFULL 153 no more free shared memory handles
+ SHARED_NOTINIT 154 shared memory driver is not initialized
+ SHARED_IPCERR 155 IPC error returned by a system call
+ SHARED_NOMEM 156 no memory in shared memory driver
+ SHARED_AGAIN 157 resource deadlock would occur
+ SHARED_NOFILE 158 attempt to open/create lock file failed
+ SHARED_NORESIZE 159 shared memory block cannot be resized at the moment
+
+ HEADER_NOT_EMPTY 201 header already contains keywords
+ KEY_NO_EXIST 202 keyword not found in header
+ KEY_OUT_BOUNDS 203 keyword record number is out of bounds
+ VALUE_UNDEFINED 204 keyword value field is blank
+ NO_QUOTE 205 string is missing the closing quote
+ BAD_KEYCHAR 207 illegal character in keyword name or card
+ BAD_ORDER 208 required keywords out of order
+ NOT_POS_INT 209 keyword value is not a positive integer
+ NO_END 210 couldn't find END keyword
+ BAD_BITPIX 211 illegal BITPIX keyword value
+ BAD_NAXIS 212 illegal NAXIS keyword value
+ BAD_NAXES 213 illegal NAXISn keyword value
+ BAD_PCOUNT 214 illegal PCOUNT keyword value
+ BAD_GCOUNT 215 illegal GCOUNT keyword value
+ BAD_TFIELDS 216 illegal TFIELDS keyword value
+ NEG_WIDTH 217 negative table row size
+ NEG_ROWS 218 negative number of rows in table
+ COL_NOT_FOUND 219 column with this name not found in table
+ BAD_SIMPLE 220 illegal value of SIMPLE keyword
+ NO_SIMPLE 221 Primary array doesn't start with SIMPLE
+ NO_BITPIX 222 Second keyword not BITPIX
+ NO_NAXIS 223 Third keyword not NAXIS
+ NO_NAXES 224 Couldn't find all the NAXISn keywords
+ NO_XTENSION 225 HDU doesn't start with XTENSION keyword
+ NOT_ATABLE 226 the CHDU is not an ASCII table extension
+ NOT_BTABLE 227 the CHDU is not a binary table extension
+ NO_PCOUNT 228 couldn't find PCOUNT keyword
+ NO_GCOUNT 229 couldn't find GCOUNT keyword
+ NO_TFIELDS 230 couldn't find TFIELDS keyword
+ NO_TBCOL 231 couldn't find TBCOLn keyword
+ NO_TFORM 232 couldn't find TFORMn keyword
+ NOT_IMAGE 233 the CHDU is not an IMAGE extension
+ BAD_TBCOL 234 TBCOLn keyword value < 0 or > rowlength
+ NOT_TABLE 235 the CHDU is not a table
+ COL_TOO_WIDE 236 column is too wide to fit in table
+ COL_NOT_UNIQUE 237 more than 1 column name matches template
+ BAD_ROW_WIDTH 241 sum of column widths not = NAXIS1
+ UNKNOWN_EXT 251 unrecognizable FITS extension type
+ UNKNOWN_REC 252 unknown record; 1st keyword not SIMPLE or XTENSION
+ END_JUNK 253 END keyword is not blank
+ BAD_HEADER_FILL 254 Header fill area contains non-blank chars
+ BAD_DATA_FILL 255 Illegal data fill bytes (not zero or blank)
+ BAD_TFORM 261 illegal TFORM format code
+ BAD_TFORM_DTYPE 262 unrecognizable TFORM datatype code
+ BAD_TDIM 263 illegal TDIMn keyword value
+ BAD_HEAP_PTR 264 invalid BINTABLE heap pointer is out of range
+
+ BAD_HDU_NUM 301 HDU number < 1 or > MAXHDU
+ BAD_COL_NUM 302 column number < 1 or > tfields
+ NEG_FILE_POS 304 tried to move to negative byte location in file
+ NEG_BYTES 306 tried to read or write negative number of bytes
+ BAD_ROW_NUM 307 illegal starting row number in table
+ BAD_ELEM_NUM 308 illegal starting element number in vector
+ NOT_ASCII_COL 309 this is not an ASCII string column
+ NOT_LOGICAL_COL 310 this is not a logical datatype column
+ BAD_ATABLE_FORMAT 311 ASCII table column has wrong format
+ BAD_BTABLE_FORMAT 312 Binary table column has wrong format
+ NO_NULL 314 null value has not been defined
+ NOT_VARI_LEN 317 this is not a variable length column
+ BAD_DIMEN 320 illegal number of dimensions in array
+ BAD_PIX_NUM 321 first pixel number greater than last pixel
+ ZERO_SCALE 322 illegal BSCALE or TSCALn keyword = 0
+ NEG_AXIS 323 illegal axis length < 1
+
+ NOT_GROUP_TABLE 340 Grouping function error
+ HDU_ALREADY_MEMBER 341
+ MEMBER_NOT_FOUND 342
+ GROUP_NOT_FOUND 343
+ BAD_GROUP_ID 344
+ TOO_MANY_HDUS_TRACKED 345
+ HDU_ALREADY_TRACKED 346
+ BAD_OPTION 347
+ IDENTICAL_POINTERS 348
+ BAD_GROUP_ATTACH 349
+ BAD_GROUP_DETACH 350
+
+ NGP_NO_MEMORY 360 malloc failed
+ NGP_READ_ERR 361 read error from file
+ NGP_NUL_PTR 362 null pointer passed as an argument.
+ Passing null pointer as a name of
+ template file raises this error
+ NGP_EMPTY_CURLINE 363 line read seems to be empty (used
+ internally)
+ NGP_UNREAD_QUEUE_FULL 364 cannot unread more then 1 line (or single
+ line twice)
+ NGP_INC_NESTING 365 too deep include file nesting (infinite
+ loop, template includes itself ?)
+ NGP_ERR_FOPEN 366 fopen() failed, cannot open template file
+ NGP_EOF 367 end of file encountered and not expected
+ NGP_BAD_ARG 368 bad arguments passed. Usually means
+ internal parser error. Should not happen
+ NGP_TOKEN_NOT_EXPECT 369 token not expected here
+
+ BAD_I2C 401 bad int to formatted string conversion
+ BAD_F2C 402 bad float to formatted string conversion
+ BAD_INTKEY 403 can't interpret keyword value as integer
+ BAD_LOGICALKEY 404 can't interpret keyword value as logical
+ BAD_FLOATKEY 405 can't interpret keyword value as float
+ BAD_DOUBLEKEY 406 can't interpret keyword value as double
+ BAD_C2I 407 bad formatted string to int conversion
+ BAD_C2F 408 bad formatted string to float conversion
+ BAD_C2D 409 bad formatted string to double conversion
+ BAD_DATATYPE 410 illegal datatype code value
+ BAD_DECIM 411 bad number of decimal places specified
+ NUM_OVERFLOW 412 overflow during datatype conversion
+ DATA_COMPRESSION_ERR 413 error compressing image
+ DATA_DECOMPRESSION_ERR 414 error uncompressing image
+
+ BAD_DATE 420 error in date or time conversion
+
+ PARSE_SYNTAX_ERR 431 syntax error in parser expression
+ PARSE_BAD_TYPE 432 expression did not evaluate to desired type
+ PARSE_LRG_VECTOR 433 vector result too large to return in array
+ PARSE_NO_OUTPUT 434 data parser failed not sent an out column
+ PARSE_BAD_COL 435 bad data encounter while parsing column
+ PARSE_BAD_OUTPUT 436 Output file not of proper type
+
+ ANGLE_TOO_BIG 501 celestial angle too large for projection
+ BAD_WCS_VAL 502 bad celestial coordinate or pixel value
+ WCS_ERROR 503 error in celestial coordinate calculation
+ BAD_WCS_PROJ 504 unsupported type of celestial projection
+ NO_WCS_KEY 505 celestial coordinate keywords not found
+ APPROX_WCS_KEY 506 approximate wcs keyword values were returned
+\end{verbatim}
+
+\end{document}
diff --git a/pkg/tbtables/cfitsio/quick.toc b/pkg/tbtables/cfitsio/quick.toc
new file mode 100644
index 00000000..9d7c7da6
--- /dev/null
+++ b/pkg/tbtables/cfitsio/quick.toc
@@ -0,0 +1,25 @@
+\contentsline {section}{\numberline {1}Introduction}{2}
+\contentsline {section}{\numberline {2}Installing and Using CFITSIO}{3}
+\contentsline {section}{\numberline {3}Example Programs}{4}
+\contentsline {section}{\numberline {4}CFITSIO Routines}{6}
+\contentsline {subsection}{\numberline {4.1}Error Reporting}{6}
+\contentsline {subsection}{\numberline {4.2}File Open/Close Routines}{6}
+\contentsline {subsection}{\numberline {4.3}HDU-level Routines}{7}
+\contentsline {subsection}{\numberline {4.4}Image I/O Routines}{9}
+\contentsline {subsection}{\numberline {4.5}Table I/O Routines}{12}
+\contentsline {subsection}{\numberline {4.6}Header Keyword I/O Routines}{19}
+\contentsline {subsection}{\numberline {4.7}Utility Routines}{22}
+\contentsline {section}{\numberline {5}CFITSIO File Names and Filters}{23}
+\contentsline {subsection}{\numberline {5.1}Creating New Files}{23}
+\contentsline {subsection}{\numberline {5.2}Opening Existing Files}{24}
+\contentsline {subsection}{\numberline {5.3}Image Filtering}{26}
+\contentsline {subsubsection}{\numberline {5.3.1}Extracting a subsection of an image}{26}
+\contentsline {subsubsection}{\numberline {5.3.2}Create an Image by Binning Table Columns}{26}
+\contentsline {subsection}{\numberline {5.4}Table Filtering}{28}
+\contentsline {subsubsection}{\numberline {5.4.1}Column and Keyword Filtering}{28}
+\contentsline {subsubsection}{\numberline {5.4.2}Row Filtering}{29}
+\contentsline {subsubsection}{\numberline {5.4.3}Good Time Interval Filtering}{32}
+\contentsline {subsubsection}{\numberline {5.4.4}Spatial Region Filtering}{32}
+\contentsline {subsubsection}{\numberline {5.4.5}Example Row Filters}{34}
+\contentsline {subsection}{\numberline {5.5}Combined Filtering Examples}{36}
+\contentsline {section}{\numberline {6}CFITSIO Error Status Codes}{38}
diff --git a/pkg/tbtables/cfitsio/region.c b/pkg/tbtables/cfitsio/region.c
new file mode 100644
index 00000000..31df9b7a
--- /dev/null
+++ b/pkg/tbtables/cfitsio/region.c
@@ -0,0 +1,919 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include "fitsio2.h"
+#include "region.h"
+
+static int Pt_in_Poly( double x, double y, int nPts, double *Pts );
+
+/*---------------------------------------------------------------------------*/
+int ffrrgn( const char *filename,
+ WCSdata *wcs,
+ SAORegion **Rgn,
+ int *status )
+/* Read regions from a SAO-style region file and return the information */
+/* in the "SAORegion" structure. If it is nonNULL, use wcs to convert the */
+/* region coordinates to pixels. Return an error if region is in degrees */
+/* but no WCS data is provided. */
+/*---------------------------------------------------------------------------*/
+{
+ char *currLine;
+ char *namePtr, *paramPtr, *currLoc;
+ char *pX, *pY, *endp;
+ long allocLen, lineLen, hh, mm, dd;
+ double *coords = 0, X, Y, R, x, y, ss, xsave= 0., ysave= 0.;
+ int nParams, nCoords, negdec;
+ int i, done;
+ FILE *rgnFile;
+ coordFmt cFmt;
+ SAORegion *aRgn;
+ RgnShape *newShape, *tmpShape;
+
+ if( *status ) return( *status );
+
+ aRgn = (SAORegion *)malloc( sizeof(SAORegion) );
+ if( ! aRgn ) {
+ ffpmsg("Couldn't allocate memory to hold Region file contents.");
+ return(*status = MEMORY_ALLOCATION );
+ }
+ aRgn->nShapes = 0;
+ aRgn->Shapes = NULL;
+ if( wcs && wcs->exists )
+ aRgn->wcs = *wcs;
+ else
+ aRgn->wcs.exists = 0;
+
+ cFmt = pixel_fmt; /* set default format */
+
+ /* Allocate Line Buffer */
+
+ allocLen = 512;
+ currLine = (char *)malloc( allocLen * sizeof(char) );
+ if( !currLine ) {
+ free( aRgn );
+ ffpmsg("Couldn't allocate memory to hold Region file contents.");
+ return(*status = MEMORY_ALLOCATION );
+ }
+
+ /* Open Region File */
+
+ if( (rgnFile = fopen( filename, "r" ))==NULL ) {
+ sprintf(currLine,"Could not open Region file %s.",filename);
+ ffpmsg( currLine );
+ free( currLine );
+ free( aRgn );
+ return( *status = FILE_NOT_OPENED );
+ }
+
+ /* Read in file, line by line */
+
+ while( fgets(currLine,allocLen,rgnFile) != NULL ) {
+
+ /* Make sure we have a full line of text */
+
+ lineLen = strlen(currLine);
+ while( lineLen==allocLen-1 && currLine[lineLen-1]!='\n' ) {
+ currLoc = (char *)realloc( currLine, 2 * allocLen * sizeof(char) );
+ if( !currLoc ) {
+ ffpmsg("Couldn't allocate memory to hold Region file contents.");
+ *status = MEMORY_ALLOCATION;
+ goto error;
+ } else {
+ currLine = currLoc;
+ }
+ fgets( currLine+lineLen, allocLen+1, rgnFile );
+ allocLen += allocLen;
+ lineLen += strlen(currLine+lineLen);
+ }
+
+ currLoc = currLine;
+ if( *currLoc == '#' ) {
+
+ /* Look to see if it is followed by a format statement... */
+ /* if not skip line */
+
+ currLoc++;
+ while( *currLoc==' ' ) currLoc++;
+ if( !strncasecmp( currLoc, "format:", 7 ) ) {
+ if( aRgn->nShapes ) {
+ ffpmsg("Format code encountered after reading 1 or more shapes.");
+ *status = PARSE_SYNTAX_ERR;
+ goto error;
+ }
+ currLoc += 7;
+ while( *currLoc==' ' ) currLoc++;
+ if( !strncasecmp( currLoc, "pixel", 5 ) ) {
+ cFmt = pixel_fmt;
+ } else if( !strncasecmp( currLoc, "degree", 6 ) ) {
+ cFmt = degree_fmt;
+ } else if( !strncasecmp( currLoc, "hhmmss", 6 ) ) {
+ cFmt = hhmmss_fmt;
+ } else if( !strncasecmp( currLoc, "hms", 3 ) ) {
+ cFmt = hhmmss_fmt;
+ } else {
+ ffpmsg("Unknown format code encountered in region file.");
+ *status = PARSE_SYNTAX_ERR;
+ goto error;
+ }
+ }
+
+ } else if( !strncasecmp( currLoc, "glob", 4 ) ) {
+ /* skip lines that begin with the word 'global' */
+
+ } else {
+
+ while( *currLoc != '\0' ) {
+
+ namePtr = currLoc;
+ paramPtr = NULL;
+ nParams = 1;
+
+ /* Search for closing parenthesis */
+
+ done = 0;
+ while( !done && !*status && *currLoc ) {
+ switch (*currLoc) {
+ case '(':
+ *currLoc = '\0';
+ currLoc++;
+ if( paramPtr ) /* Can't have two '(' in a region! */
+ *status = 1;
+ else
+ paramPtr = currLoc;
+ break;
+ case ')':
+ *currLoc = '\0';
+ currLoc++;
+ if( !paramPtr ) /* Can't have a ')' without a '(' first */
+ *status = 1;
+ else
+ done = 1;
+ break;
+ case '#':
+ case '\n':
+ *currLoc = '\0';
+ if( !paramPtr ) /* Allow for a blank line */
+ done = 1;
+ break;
+ case ':':
+ currLoc++;
+ cFmt = hhmmss_fmt;
+ break;
+ case 'd':
+ currLoc++;
+ cFmt = degree_fmt;
+ break;
+ case ',':
+ nParams++; /* Fall through to default */
+ default:
+ currLoc++;
+ break;
+ }
+ }
+ if( *status || !done ) {
+ ffpmsg( "Error reading Region file" );
+ *status = PARSE_SYNTAX_ERR;
+ goto error;
+ }
+
+ /* Skip white space in region name */
+
+ while( *namePtr==' ' ) namePtr++;
+
+ /* Was this a blank line? Or the end of the current one */
+
+ if( ! *namePtr && ! paramPtr ) continue;
+
+
+ /* Check for format code at beginning of the line */
+
+ if( !strncasecmp( namePtr, "image;", 6 ) ) {
+ namePtr += 6;
+ cFmt = pixel_fmt;
+ } else if( !strncasecmp( namePtr, "physical;", 9 ) ) {
+ namePtr += 9;
+ cFmt = pixel_fmt;
+ } else if( !strncasecmp( namePtr, "fk4;", 4 ) ) {
+ namePtr += 4;
+ cFmt = degree_fmt;
+ } else if( !strncasecmp( namePtr, "fk5;", 4 ) ) {
+ namePtr += 4;
+ cFmt = degree_fmt;
+ } else if( !strncasecmp( namePtr, "icrs;", 5 ) ) {
+ namePtr += 5;
+ cFmt = degree_fmt;
+
+ /* the following 4 cases support region files created by POW which
+ may have lines containing only a format code, not followed
+ by a ';' (and with no region specifier on the line). We use
+ the 'continue' statement to jump to the end of the loop and
+ then continue reading the next line of the region file. */
+
+ } else if( !strncasecmp( namePtr, "fk5", 3 ) ) {
+ cFmt = degree_fmt;
+ continue; /* supports POW region file format */
+ } else if( !strncasecmp( namePtr, "fk4", 3 ) ) {
+ cFmt = degree_fmt;
+ continue; /* supports POW region file format */
+ } else if( !strncasecmp( namePtr, "icrs", 4 ) ) {
+ cFmt = degree_fmt;
+ continue; /* supports POW region file format */
+ } else if( !strncasecmp( namePtr, "image", 5 ) ) {
+ cFmt = pixel_fmt;
+ continue; /* supports POW region file format */
+
+
+ } else if( !strncasecmp( namePtr, "galactic;", 9 ) ) {
+ ffpmsg( "Galactic region coordinates not supported" );
+ ffpmsg( namePtr );
+ *status = PARSE_SYNTAX_ERR;
+ goto error;
+ } else if( !strncasecmp( namePtr, "ecliptic;", 9 ) ) {
+ ffpmsg( "ecliptic region coordinates not supported" );
+ ffpmsg( namePtr );
+ *status = PARSE_SYNTAX_ERR;
+ goto error;
+ }
+
+ /**************************************************/
+ /* We've apparently found a region... Set it up */
+ /**************************************************/
+
+ if( !(aRgn->nShapes % 10) ) {
+ if( aRgn->Shapes )
+ tmpShape = (RgnShape *)realloc( aRgn->Shapes,
+ (10+aRgn->nShapes)
+ * sizeof(RgnShape) );
+ else
+ tmpShape = (RgnShape *) malloc( 10 * sizeof(RgnShape) );
+ if( tmpShape ) {
+ aRgn->Shapes = tmpShape;
+ } else {
+ ffpmsg( "Failed to allocate memory for Region data");
+ *status = MEMORY_ALLOCATION;
+ goto error;
+ }
+
+ }
+ newShape = &aRgn->Shapes[aRgn->nShapes++];
+ newShape->sign = 1;
+ newShape->shape = point_rgn;
+
+ while( *namePtr==' ' ) namePtr++;
+
+ /* Check for the shape's sign */
+
+ if( *namePtr=='+' ) {
+ namePtr++;
+ } else if( *namePtr=='-' ) {
+ namePtr++;
+ newShape->sign = 0;
+ }
+
+ /* Skip white space in region name */
+
+ while( *namePtr==' ' ) namePtr++;
+ if( *namePtr=='\0' ) {
+ ffpmsg( "Error reading Region file" );
+ *status = PARSE_SYNTAX_ERR;
+ goto error;
+ }
+ lineLen = strlen( namePtr ) - 1;
+ while( namePtr[lineLen]==' ' ) namePtr[lineLen--] = '\0';
+
+ /* Now identify the region */
+
+ if( !strcasecmp( namePtr, "circle" ) ) {
+ newShape->shape = circle_rgn;
+ if( nParams != 3 )
+ *status = PARSE_SYNTAX_ERR;
+ nCoords = 2;
+ } else if( !strcasecmp( namePtr, "annulus" ) ) {
+ newShape->shape = annulus_rgn;
+ if( nParams != 4 )
+ *status = PARSE_SYNTAX_ERR;
+ nCoords = 2;
+ } else if( !strcasecmp( namePtr, "ellipse" ) ) {
+ newShape->shape = ellipse_rgn;
+ if( nParams < 4 || nParams > 5 )
+ *status = PARSE_SYNTAX_ERR;
+ newShape->param.gen.p[4] = 0.0;
+ nCoords = 2;
+ } else if( !strcasecmp( namePtr, "elliptannulus" ) ) {
+ newShape->shape = elliptannulus_rgn;
+ if( !( nParams==8 || nParams==6 ) )
+ *status = PARSE_SYNTAX_ERR;
+ newShape->param.gen.p[6] = 0.0;
+ newShape->param.gen.p[7] = 0.0;
+ nCoords = 2;
+ } else if( !strcasecmp( namePtr, "box" )
+ || !strcasecmp( namePtr, "rotbox" ) ) {
+ newShape->shape = box_rgn;
+ if( nParams < 4 || nParams > 5 )
+ *status = PARSE_SYNTAX_ERR;
+ newShape->param.gen.p[4] = 0.0;
+ nCoords = 2;
+ } else if( !strcasecmp( namePtr, "rectangle" )
+ || !strcasecmp( namePtr, "rotrectangle" ) ) {
+ newShape->shape = rectangle_rgn;
+ if( nParams < 4 || nParams > 5 )
+ *status = PARSE_SYNTAX_ERR;
+ newShape->param.gen.p[4] = 0.0;
+ nCoords = 4;
+ } else if( !strcasecmp( namePtr, "diamond" )
+ || !strcasecmp( namePtr, "rotdiamond" )
+ || !strcasecmp( namePtr, "rhombus" )
+ || !strcasecmp( namePtr, "rotrhombus" ) ) {
+ newShape->shape = diamond_rgn;
+ if( nParams < 4 || nParams > 5 )
+ *status = PARSE_SYNTAX_ERR;
+ newShape->param.gen.p[4] = 0.0;
+ nCoords = 2;
+ } else if( !strcasecmp( namePtr, "sector" )
+ || !strcasecmp( namePtr, "pie" ) ) {
+ newShape->shape = sector_rgn;
+ if( nParams != 4 )
+ *status = PARSE_SYNTAX_ERR;
+ nCoords = 2;
+ } else if( !strcasecmp( namePtr, "point" ) ) {
+ newShape->shape = point_rgn;
+ if( nParams != 2 )
+ *status = PARSE_SYNTAX_ERR;
+ nCoords = 2;
+ } else if( !strcasecmp( namePtr, "line" ) ) {
+ newShape->shape = line_rgn;
+ if( nParams != 4 )
+ *status = PARSE_SYNTAX_ERR;
+ nCoords = 4;
+ } else if( !strcasecmp( namePtr, "polygon" ) ) {
+ newShape->shape = poly_rgn;
+ if( nParams < 6 || (nParams&1) )
+ *status = PARSE_SYNTAX_ERR;
+ nCoords = nParams;
+ } else {
+ ffpmsg( "Unrecognized region found in region file:" );
+ ffpmsg( namePtr );
+ *status = PARSE_SYNTAX_ERR;
+ goto error;
+ }
+ if( *status ) {
+ ffpmsg( "Wrong number of parameters found for region" );
+ ffpmsg( namePtr );
+ goto error;
+ }
+
+ /* Parse Parameter string... convert to pixels if necessary */
+
+ if( newShape->shape==poly_rgn ) {
+ newShape->param.poly.Pts = (double *)malloc( nParams
+ * sizeof(double) );
+ if( !newShape->param.poly.Pts ) {
+ ffpmsg(
+ "Could not allocate memory to hold polygon parameters" );
+ *status = MEMORY_ALLOCATION;
+ goto error;
+ }
+ newShape->param.poly.nPts = nParams;
+ coords = newShape->param.poly.Pts;
+ } else
+ coords = newShape->param.gen.p;
+
+ /* Parse the initial "WCS?" coordinates */
+ for( i=0; i<nCoords; i+=2 ) {
+ pX = paramPtr;
+ while( *paramPtr!=',' ) paramPtr++;
+ *(paramPtr++) = '\0';
+
+ pY = paramPtr;
+ while( *paramPtr!=',' && *paramPtr != '\0' ) paramPtr++;
+ *(paramPtr++) = '\0';
+
+ if( strchr(pX, ':' ) ) {
+ /* Read in special format & convert to decimal degrees */
+ cFmt = hhmmss_fmt;
+ mm = 0;
+ ss = 0.;
+ hh = strtol(pX, &endp, 10);
+ if (endp && *endp==':') {
+ pX = endp + 1;
+ mm = strtol(pX, &endp, 10);
+ if (endp && *endp==':') {
+ pX = endp + 1;
+ ss = atof( pX );
+ }
+ }
+ X = 15. * (hh + mm/60. + ss/3600.); /* convert to degrees */
+
+ mm = 0;
+ ss = 0.;
+ negdec = 0;
+
+ while( *pY==' ' ) pY++;
+ if (*pY=='-') {
+ negdec = 1;
+ pY++;
+ }
+ dd = strtol(pY, &endp, 10);
+ if (endp && *endp==':') {
+ pY = endp + 1;
+ mm = strtol(pY, &endp, 10);
+ if (endp && *endp==':') {
+ pY = endp + 1;
+ ss = atof( pY );
+ }
+ }
+ if (negdec)
+ Y = -dd - mm/60. - ss/3600.; /* convert to degrees */
+ else
+ Y = dd + mm/60. + ss/3600.;
+
+ } else {
+ X = atof( pX );
+ Y = atof( pY );
+ }
+ if (i==0) { /* save 1st coord. in case needed later */
+ xsave = X;
+ ysave = Y;
+ }
+
+ if( cFmt!=pixel_fmt ) {
+ /* Convert to pixels */
+ if( wcs==NULL || ! wcs->exists ) {
+ ffpmsg("WCS information needed to convert region coordinates.");
+ *status = NO_WCS_KEY;
+ goto error;
+ }
+
+ if( ffxypx( X, Y, wcs->xrefval, wcs->yrefval,
+ wcs->xrefpix, wcs->yrefpix,
+ wcs->xinc, wcs->yinc,
+ wcs->rot, wcs->type,
+ &x, &y, status ) ) {
+ ffpmsg("Error converting region to pixel coordinates.");
+ goto error;
+ }
+ X = x; Y = y;
+ }
+ coords[i] = X;
+ coords[i+1] = Y;
+ }
+
+ /* Read in remaining parameters... */
+
+ for( ; i<nParams; i++ ) {
+ pX = paramPtr;
+ while( *paramPtr!=',' && *paramPtr != '\0' ) paramPtr++;
+ *(paramPtr++) = '\0';
+ coords[i] = strtod( pX, &endp );
+
+ if (endp && *endp=='"') {
+ /* parameter given in arcsec so convert to pixels. */
+ /* Increment first Y coordinate by this amount then calc */
+ /* the distance in pixels from the original coordinate. */
+ /* NOTE: This assumes the pixels are square!! */
+ if (ysave < 0.)
+ Y = ysave + coords[i]/3600.; /* don't exceed -90 */
+ else
+ Y = ysave - coords[i]/3600.; /* don't exceed +90 */
+
+ X = xsave;
+ if( ffxypx( X, Y, wcs->xrefval, wcs->yrefval,
+ wcs->xrefpix, wcs->yrefpix,
+ wcs->xinc, wcs->yinc,
+ wcs->rot, wcs->type,
+ &x, &y, status ) ) {
+ ffpmsg("Error converting region to pixel coordinates.");
+ goto error;
+ }
+
+ coords[i] = sqrt( pow(x-coords[0],2) + pow(y-coords[1],2) );
+
+ } else if (endp && *endp=='\'') {
+ /* parameter given in arcmin so convert to pixels. */
+ /* Increment first Y coordinate by this amount, then calc */
+ /* the distance in pixels from the original coordinate. */
+ /* NOTE: This assumes the pixels are square!! */
+ if (ysave < 0.)
+ Y = ysave + coords[i]/60.; /* don't exceed -90 */
+ else
+ Y = ysave - coords[i]/60.; /* don't exceed +90 */
+
+ X = xsave;
+ if( ffxypx( X, Y, wcs->xrefval, wcs->yrefval,
+ wcs->xrefpix, wcs->yrefpix,
+ wcs->xinc, wcs->yinc,
+ wcs->rot, wcs->type,
+ &x, &y, status ) ) {
+ ffpmsg("Error converting region to pixel coordinates.");
+ goto error;
+ }
+
+ coords[i] = sqrt( pow(x-coords[0],2) + pow(y-coords[1],2) );
+
+ } else if (endp && *endp=='d') {
+ /* parameter given in degrees so convert to pixels. */
+ /* Increment first Y coordinate by this amount, then calc */
+ /* the distance in pixels from the original coordinate. */
+ /* NOTE: This assumes the pixels are square!! */
+ if (ysave < 0.)
+ Y = ysave + coords[i]; /* don't exceed -90 */
+ else
+ Y = ysave - coords[i]; /* don't exceed +90 */
+
+ X = xsave;
+ if( ffxypx( X, Y, wcs->xrefval, wcs->yrefval,
+ wcs->xrefpix, wcs->yrefpix,
+ wcs->xinc, wcs->yinc,
+ wcs->rot, wcs->type,
+ &x, &y, status ) ) {
+ ffpmsg("Error converting region to pixel coordinates.");
+ goto error;
+ }
+
+ coords[i] = sqrt( pow(x-coords[0],2) + pow(y-coords[1],2) );
+ }
+ }
+
+ /* Perform some useful calculations now to speed up filter later */
+
+ switch( newShape->shape ) {
+ case circle_rgn:
+ newShape->param.gen.a = coords[2] * coords[2];
+ break;
+ case annulus_rgn:
+ newShape->param.gen.a = coords[2] * coords[2];
+ newShape->param.gen.b = coords[3] * coords[3];
+ break;
+ case sector_rgn:
+ while( coords[2]> 180.0 ) coords[2] -= 360.0;
+ while( coords[2]<=-180.0 ) coords[2] += 360.0;
+ while( coords[3]> 180.0 ) coords[3] -= 360.0;
+ while( coords[3]<=-180.0 ) coords[3] += 360.0;
+ break;
+ case ellipse_rgn:
+ newShape->param.gen.sinT = sin( myPI * (coords[4] / 180.0) );
+ newShape->param.gen.cosT = cos( myPI * (coords[4] / 180.0) );
+ break;
+ case elliptannulus_rgn:
+ newShape->param.gen.a = sin( myPI * (coords[6] / 180.0) );
+ newShape->param.gen.b = cos( myPI * (coords[6] / 180.0) );
+ newShape->param.gen.sinT = sin( myPI * (coords[7] / 180.0) );
+ newShape->param.gen.cosT = cos( myPI * (coords[7] / 180.0) );
+ break;
+ case box_rgn:
+ newShape->param.gen.sinT = sin( myPI * (coords[4] / 180.0) );
+ newShape->param.gen.cosT = cos( myPI * (coords[4] / 180.0) );
+ break;
+ case rectangle_rgn:
+ newShape->param.gen.sinT = sin( myPI * (coords[4] / 180.0) );
+ newShape->param.gen.cosT = cos( myPI * (coords[4] / 180.0) );
+ X = 0.5 * ( coords[2]-coords[0] );
+ Y = 0.5 * ( coords[3]-coords[1] );
+ newShape->param.gen.a = fabs( X * newShape->param.gen.cosT
+ + Y * newShape->param.gen.sinT );
+ newShape->param.gen.b = fabs( Y * newShape->param.gen.cosT
+ - X * newShape->param.gen.sinT );
+ newShape->param.gen.p[5] = 0.5 * ( coords[2]+coords[0] );
+ newShape->param.gen.p[6] = 0.5 * ( coords[3]+coords[1] );
+ break;
+ case diamond_rgn:
+ newShape->param.gen.sinT = sin( myPI * (coords[4] / 180.0) );
+ newShape->param.gen.cosT = cos( myPI * (coords[4] / 180.0) );
+ break;
+ case line_rgn:
+ X = coords[2] - coords[0];
+ Y = coords[3] - coords[1];
+ R = sqrt( X*X + Y*Y );
+ newShape->param.gen.sinT = ( R ? Y/R : 0.0 );
+ newShape->param.gen.cosT = ( R ? X/R : 1.0 );
+ newShape->param.gen.a = R + 0.5;
+ break;
+ case point_rgn:
+ break;
+ case poly_rgn:
+ /* Find bounding box */
+ newShape->param.poly.xmin = coords[0];
+ newShape->param.poly.xmax = coords[0];
+ newShape->param.poly.ymin = coords[1];
+ newShape->param.poly.ymax = coords[1];
+ for( i=2; i<nParams; ) {
+ if( newShape->param.poly.xmin > coords[i] ) /* Min X */
+ newShape->param.poly.xmin = coords[i];
+ if( newShape->param.poly.xmax < coords[i] ) /* Max X */
+ newShape->param.poly.xmax = coords[i];
+ i++;
+ if( newShape->param.poly.ymin > coords[i] ) /* Min Y */
+ newShape->param.poly.ymin = coords[i];
+ if( newShape->param.poly.ymax < coords[i] ) /* Max Y */
+ newShape->param.poly.ymax = coords[i];
+ i++;
+ }
+ break;
+ }
+
+ } /* End of while( *currLoc ) */
+/*
+ if (coords)printf("%.8f %.8f %.8f %.8f %.8f\n",
+ coords[0],coords[1],coords[2],coords[3],coords[4]);
+*/
+ } /* End of if...else parse line */
+ } /* End of while( fgets(rgnFile) ) */
+
+
+error:
+
+ if( *status )
+ fits_free_region( aRgn );
+ else
+ *Rgn = aRgn;
+
+ fclose( rgnFile );
+ free( currLine );
+
+ return( *status );
+}
+
+/*---------------------------------------------------------------------------*/
+int fftrgn( double X,
+ double Y,
+ SAORegion *Rgn )
+/* Test if the given point is within the region described by Rgn. X and */
+/* Y are in pixel coordinates. */
+/*---------------------------------------------------------------------------*/
+{
+ double x, y, dx, dy, xprime, yprime, r;
+ RgnShape *Shapes;
+ int i;
+ int result = 0;
+
+ Shapes = Rgn->Shapes;
+
+ /* if an excluded region is given first, then implicitly */
+ /* assume a previous shape that includes the entire image. */
+ if (!Shapes->sign)
+ result = 1;
+
+ for( i=0; i<Rgn->nShapes; i++, Shapes++ ) {
+
+ /* only need to test if */
+ /* the point is not already included and this is an include region, */
+ /* or the point is included and this is an excluded region */
+
+ if ( (!result && Shapes->sign) || (result && !Shapes->sign) ) {
+
+ result = 1;
+
+ switch( Shapes->shape ) {
+
+ case box_rgn:
+ /* Shift origin to center of region */
+ xprime = X - Shapes->param.gen.p[0];
+ yprime = Y - Shapes->param.gen.p[1];
+
+ /* Rotate point to region's orientation */
+ x = xprime * Shapes->param.gen.cosT + yprime * Shapes->param.gen.sinT;
+ y = -xprime * Shapes->param.gen.sinT + yprime * Shapes->param.gen.cosT;
+
+ dx = 0.5 * Shapes->param.gen.p[2];
+ dy = 0.5 * Shapes->param.gen.p[3];
+ if( (x < -dx) || (x > dx) || (y < -dy) || (y > dy) )
+ result = 0;
+ break;
+
+ case rectangle_rgn:
+ /* Shift origin to center of region */
+ xprime = X - Shapes->param.gen.p[5];
+ yprime = Y - Shapes->param.gen.p[6];
+
+ /* Rotate point to region's orientation */
+ x = xprime * Shapes->param.gen.cosT + yprime * Shapes->param.gen.sinT;
+ y = -xprime * Shapes->param.gen.sinT + yprime * Shapes->param.gen.cosT;
+
+ dx = Shapes->param.gen.a;
+ dy = Shapes->param.gen.b;
+ if( (x < -dx) || (x > dx) || (y < -dy) || (y > dy) )
+ result = 0;
+ break;
+
+ case diamond_rgn:
+ /* Shift origin to center of region */
+ xprime = X - Shapes->param.gen.p[0];
+ yprime = Y - Shapes->param.gen.p[1];
+
+ /* Rotate point to region's orientation */
+ x = xprime * Shapes->param.gen.cosT + yprime * Shapes->param.gen.sinT;
+ y = -xprime * Shapes->param.gen.sinT + yprime * Shapes->param.gen.cosT;
+
+ dx = 0.5 * Shapes->param.gen.p[2];
+ dy = 0.5 * Shapes->param.gen.p[3];
+ r = fabs(x/dx) + fabs(y/dy);
+ if( r > 1 )
+ result = 0;
+ break;
+
+ case circle_rgn:
+ /* Shift origin to center of region */
+ x = X - Shapes->param.gen.p[0];
+ y = Y - Shapes->param.gen.p[1];
+
+ r = x*x + y*y;
+ if ( r > Shapes->param.gen.a )
+ result = 0;
+ break;
+
+ case annulus_rgn:
+ /* Shift origin to center of region */
+ x = X - Shapes->param.gen.p[0];
+ y = Y - Shapes->param.gen.p[1];
+
+ r = x*x + y*y;
+ if ( r < Shapes->param.gen.a || r > Shapes->param.gen.b )
+ result = 0;
+ break;
+
+ case sector_rgn:
+ /* Shift origin to center of region */
+ x = X - Shapes->param.gen.p[0];
+ y = Y - Shapes->param.gen.p[1];
+
+ if( x || y ) {
+ r = atan2( y, x ) * 180.0 / myPI;
+ if( Shapes->param.gen.p[2] <= Shapes->param.gen.p[3] ) {
+ if( r < Shapes->param.gen.p[2] || r > Shapes->param.gen.p[3] )
+ result = 0;
+ } else {
+ if( r < Shapes->param.gen.p[2] && r > Shapes->param.gen.p[3] )
+ result = 0;
+ }
+ }
+ break;
+
+ case ellipse_rgn:
+ /* Shift origin to center of region */
+ xprime = X - Shapes->param.gen.p[0];
+ yprime = Y - Shapes->param.gen.p[1];
+
+ /* Rotate point to region's orientation */
+ x = xprime * Shapes->param.gen.cosT + yprime * Shapes->param.gen.sinT;
+ y = -xprime * Shapes->param.gen.sinT + yprime * Shapes->param.gen.cosT;
+
+ x /= Shapes->param.gen.p[2];
+ y /= Shapes->param.gen.p[3];
+ r = x*x + y*y;
+ if( r>1.0 )
+ result = 0;
+ break;
+
+ case elliptannulus_rgn:
+ /* Shift origin to center of region */
+ xprime = X - Shapes->param.gen.p[0];
+ yprime = Y - Shapes->param.gen.p[1];
+
+ /* Rotate point to outer ellipse's orientation */
+ x = xprime * Shapes->param.gen.cosT + yprime * Shapes->param.gen.sinT;
+ y = -xprime * Shapes->param.gen.sinT + yprime * Shapes->param.gen.cosT;
+
+ x /= Shapes->param.gen.p[4];
+ y /= Shapes->param.gen.p[5];
+ r = x*x + y*y;
+ if( r>1.0 )
+ result = 0;
+ else {
+ /* Repeat test for inner ellipse */
+ x = xprime * Shapes->param.gen.b + yprime * Shapes->param.gen.a;
+ y = -xprime * Shapes->param.gen.a + yprime * Shapes->param.gen.b;
+
+ x /= Shapes->param.gen.p[2];
+ y /= Shapes->param.gen.p[3];
+ r = x*x + y*y;
+ if( r<1.0 )
+ result = 0;
+ }
+ break;
+
+ case line_rgn:
+ /* Shift origin to first point of line */
+ xprime = X - Shapes->param.gen.p[0];
+ yprime = Y - Shapes->param.gen.p[1];
+
+ /* Rotate point to line's orientation */
+ x = xprime * Shapes->param.gen.cosT + yprime * Shapes->param.gen.sinT;
+ y = -xprime * Shapes->param.gen.sinT + yprime * Shapes->param.gen.cosT;
+
+ if( (y < -0.5) || (y >= 0.5) || (x < -0.5)
+ || (x >= Shapes->param.gen.a) )
+ result = 0;
+ break;
+
+ case point_rgn:
+ /* Shift origin to center of region */
+ x = X - Shapes->param.gen.p[0];
+ y = Y - Shapes->param.gen.p[1];
+
+ if ( (x<-0.5) || (x>=0.5) || (y<-0.5) || (y>=0.5) )
+ result = 0;
+ break;
+
+ case poly_rgn:
+ if( X<Shapes->param.poly.xmin || X>Shapes->param.poly.xmax
+ || Y<Shapes->param.poly.ymin || Y>Shapes->param.poly.ymax )
+ result = 0;
+ else
+ result = Pt_in_Poly( X, Y, Shapes->param.poly.nPts,
+ Shapes->param.poly.Pts );
+ break;
+ }
+
+ if( !Shapes->sign ) result = !result;
+
+ }
+ }
+
+ return( result );
+}
+
+/*---------------------------------------------------------------------------*/
+void fffrgn( SAORegion *Rgn )
+/* Free up memory allocated to hold the region data. */
+/*---------------------------------------------------------------------------*/
+{
+ int i;
+
+ for( i=0; i<Rgn->nShapes; i++ )
+ if( Rgn->Shapes[i].shape == poly_rgn )
+ free( Rgn->Shapes[i].param.poly.Pts );
+ if( Rgn->Shapes )
+ free( Rgn->Shapes );
+ free( Rgn );
+}
+
+/*---------------------------------------------------------------------------*/
+static int Pt_in_Poly( double x,
+ double y,
+ int nPts,
+ double *Pts )
+/* Internal routine for testing whether the coordinate x,y is within the */
+/* polygon region traced out by the array Pts. */
+/*---------------------------------------------------------------------------*/
+{
+ int i, j, flag=0;
+ double prevX, prevY;
+ double nextX, nextY;
+ double dx, dy, Dy;
+
+ nextX = Pts[nPts-2];
+ nextY = Pts[nPts-1];
+
+ for( i=0; i<nPts; i+=2 ) {
+ prevX = nextX;
+ prevY = nextY;
+
+ nextX = Pts[i];
+ nextY = Pts[i+1];
+
+ if( (y>prevY && y>=nextY) || (y<prevY && y<=nextY)
+ || (x>prevX && x>=nextX) )
+ continue;
+
+ /* Check to see if x,y lies right on the segment */
+
+ if( x>=prevX || x>nextX ) {
+ dy = y - prevY;
+ Dy = nextY - prevY;
+
+ if( fabs(Dy)<1e-10 ) {
+ if( fabs(dy)<1e-10 )
+ return( 1 );
+ else
+ continue;
+ }
+
+ dx = prevX + ( (nextX-prevX)/(Dy) ) * dy - x;
+ if( dx < -1e-10 )
+ continue;
+ if( dx < 1e-10 )
+ return( 1 );
+ }
+
+ /* There is an intersection! Make sure it isn't a V point. */
+
+ if( y != prevY ) {
+ flag = 1 - flag;
+ } else {
+ j = i+1; /* Point to Y component */
+ do {
+ if( j>1 )
+ j -= 2;
+ else
+ j = nPts-1;
+ } while( y == Pts[j] );
+
+ if( (nextY-y)*(y-Pts[j]) > 0 )
+ flag = 1-flag;
+ }
+
+ }
+ return( flag );
+}
+
diff --git a/pkg/tbtables/cfitsio/region.h b/pkg/tbtables/cfitsio/region.h
new file mode 100644
index 00000000..4d7c96c9
--- /dev/null
+++ b/pkg/tbtables/cfitsio/region.h
@@ -0,0 +1,80 @@
+/***************************************************************/
+/* REGION STUFF */
+/***************************************************************/
+
+#define myPI 3.1415926535897932385
+
+typedef struct {
+ int exists;
+ double xrefval, yrefval;
+ double xrefpix, yrefpix;
+ double xinc, yinc;
+ double rot;
+ char type[6];
+} WCSdata;
+
+typedef enum {
+ point_rgn,
+ line_rgn,
+ circle_rgn,
+ annulus_rgn,
+ ellipse_rgn,
+ elliptannulus_rgn,
+ box_rgn,
+ rectangle_rgn,
+ diamond_rgn,
+ sector_rgn,
+ poly_rgn
+} shapeType;
+
+typedef enum { pixel_fmt, degree_fmt, hhmmss_fmt } coordFmt;
+
+typedef struct {
+ char sign; /* Include or exclude? */
+ shapeType shape; /* Shape of this region */
+
+ union { /* Parameters - In pixels */
+
+ /**** Generic Shape Data ****/
+
+ struct {
+ double p[8]; /* Region parameters */
+ double sinT, cosT; /* For rotated shapes */
+ double a, b; /* Extra scratch area */
+ } gen;
+
+ /**** Polygon Data ****/
+
+ struct {
+ int nPts; /* Number of Polygon pts */
+ double *Pts; /* Polygon points */
+ double xmin,xmax; /* Polygon bounding box */
+ double ymin,ymax;
+ } poly;
+
+ } param;
+
+} RgnShape;
+
+typedef struct {
+ int nShapes;
+ RgnShape *Shapes;
+ WCSdata wcs;
+} SAORegion;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int ffrrgn( const char *filename, WCSdata *wcs, SAORegion **Rgn, int *status );
+int fftrgn( double X, double Y, SAORegion *Rgn );
+void fffrgn( SAORegion *Rgn );
+
+#ifdef __cplusplus
+ }
+#endif
+
+#define fits_read_rgnfile ffrrgn
+#define fits_in_region fftrgn
+#define fits_free_region fffrgn
+
diff --git a/pkg/tbtables/cfitsio/ricecomp.c b/pkg/tbtables/cfitsio/ricecomp.c
new file mode 100644
index 00000000..bd184ea1
--- /dev/null
+++ b/pkg/tbtables/cfitsio/ricecomp.c
@@ -0,0 +1,510 @@
+/*
+ The following code was written by Richard White at STScI and made
+ available for use in CFITSIO in July 1999. These routines were
+ originally contained in 2 source files: rcomp.c and rdecomp.c,
+ and the 'include' file now called ricecomp.h was originally called buffer.h.
+*/
+
+/*----------------------------------------------------------*/
+/* */
+/* START OF SOURCE FILE ORIGINALLY CALLED rcomp.c */
+/* */
+/*----------------------------------------------------------*/
+/* @(#) rcomp.c 1.5 99/03/01 12:40:27 */
+/* rcomp.c Compress image line using
+ * (1) Difference of adjacent pixels
+ * (2) Rice algorithm coding
+ *
+ * Returns number of bytes written to code buffer or
+ * -1 on failure
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "ricecomp.h" /* originally included in rcomp.c file (WDP) */
+#include "fitsio2.h"
+
+
+static void start_outputing_bits(Buffer *buffer);
+static int done_outputing_bits(Buffer *buffer);
+static int output_nbits(Buffer *buffer, int bits, int n);
+
+/* this routine used to be called 'rcomp' (WDP) */
+
+int fits_rcomp(int a[], /* input array */
+ int nx, /* number of input pixels */
+ unsigned char *c, /* output buffer */
+ int clen, /* max length of output */
+ int nblock) /* coding block size */
+{
+Buffer bufmem, *buffer = &bufmem;
+int bsize, i, j, thisblock;
+int lastpix, nextpix, pdiff;
+int v, fs, fsmask, top, fsmax, fsbits, bbits;
+int lbitbuffer, lbits_to_go;
+unsigned int psum;
+double pixelsum, dpsum;
+unsigned int *diff;
+
+ /*
+ * Original size of each pixel (bsize, bytes) and coding block
+ * size (nblock, pixels)
+ * Could make bsize a parameter to allow more efficient
+ * compression of short & byte images.
+ */
+ bsize = 4;
+/* nblock = 32; */
+ /*
+ * From bsize derive:
+ * FSBITS = # bits required to store FS
+ * FSMAX = maximum value for FS
+ * BBITS = bits/pixel for direct coding
+ */
+ switch (bsize) {
+ case 1:
+ fsbits = 3;
+ fsmax = 6;
+ break;
+ case 2:
+ fsbits = 4;
+ fsmax = 14;
+ break;
+ case 4:
+ fsbits = 5;
+ fsmax = 25;
+ break;
+ default:
+ ffpmsg("rdecomp: bsize must be 1, 2, or 4 bytes");
+ return(-1);
+ }
+ bbits = 1<<fsbits;
+
+ /*
+ * Set up buffer pointers
+ */
+ buffer->start = c;
+ buffer->current = c;
+ buffer->end = c+clen;
+ buffer->bits_to_go = 8;
+ /*
+ * array for differences mapped to non-negative values
+ */
+ diff = (unsigned int *) malloc(nblock*sizeof(unsigned int));
+ if (diff == (unsigned int *) NULL) {
+ ffpmsg("fits_rcomp: insufficient memory");
+ return(-1);
+ }
+ /*
+ * Code in blocks of nblock pixels
+ */
+ start_outputing_bits(buffer);
+
+ /* write out first int value to the first 4 bytes of the buffer */
+ if (output_nbits(buffer, a[0], 32) == EOF) {
+ ffpmsg("rice_encode: end of buffer");
+ free(diff);
+ return(-1);
+ }
+
+ lastpix = a[0]; /* the first difference will always be zero */
+
+ thisblock = nblock;
+ for (i=0; i<nx; i += nblock) {
+ /* last block may be shorter */
+ if (nx-i < nblock) thisblock = nx-i;
+ /*
+ * Compute differences of adjacent pixels and map them to unsigned values.
+ * Note that this may overflow the integer variables -- that's
+ * OK, because we can recover when decompressing. If we were
+ * compressing shorts or bytes, would want to do this arithmetic
+ * with short/byte working variables (though diff will still be
+ * passed as an int.)
+ *
+ * compute sum of mapped pixel values at same time
+ * use double precision for sum to allow 32-bit integer inputs
+ */
+ pixelsum = 0.0;
+ for (j=0; j<thisblock; j++) {
+ nextpix = a[i+j];
+ pdiff = nextpix - lastpix;
+ diff[j] = (unsigned int) ((pdiff<0) ? ~(pdiff<<1) : (pdiff<<1));
+ pixelsum += diff[j];
+ lastpix = nextpix;
+ }
+ /*
+ * compute number of bits to split from sum
+ */
+ dpsum = (pixelsum - (thisblock/2) - 1)/thisblock;
+ if (dpsum < 0) dpsum = 0.0;
+ psum = ((unsigned int) dpsum ) >> 1;
+ for (fs = 0; psum>0; fs++) psum >>= 1;
+ /*
+ * write the codes
+ * fsbits ID bits used to indicate split level
+ */
+ if (fs >= fsmax) {
+ /* Special high entropy case when FS >= fsmax
+ * Just write pixel difference values directly, no Rice coding at all.
+ */
+ if (output_nbits(buffer, fsmax+1, fsbits) == EOF) {
+ ffpmsg("rice_encode: end of buffer");
+ free(diff);
+ return(-1);
+ }
+ for (j=0; j<thisblock; j++) {
+ if (output_nbits(buffer, diff[j], bbits) == EOF) {
+ ffpmsg("rice_encode: end of buffer");
+ free(diff);
+ return(-1);
+ }
+ }
+ } else if (fs == 0 && pixelsum == 0) {
+ /*
+ * special low entropy case when FS = 0 and pixelsum=0 (all
+ * pixels in block are zero.)
+ * Output a 0 and return
+ */
+ if (output_nbits(buffer, 0, fsbits) == EOF) {
+ ffpmsg("rice_encode: end of buffer");
+ free(diff);
+ return(-1);
+ }
+ } else {
+ /* normal case: not either very high or very low entropy */
+ if (output_nbits(buffer, fs+1, fsbits) == EOF) {
+ ffpmsg("rice_encode: end of buffer");
+ free(diff);
+ return(-1);
+ }
+ fsmask = (1<<fs) - 1;
+ /*
+ * local copies of bit buffer to improve optimization
+ */
+ lbitbuffer = buffer->bitbuffer;
+ lbits_to_go = buffer->bits_to_go;
+ for (j=0; j<thisblock; j++) {
+ v = diff[j];
+ top = v >> fs;
+ /*
+ * top is coded by top zeros + 1
+ */
+ if (lbits_to_go >= top+1) {
+ lbitbuffer <<= top+1;
+ lbitbuffer |= 1;
+ lbits_to_go -= top+1;
+ } else {
+ lbitbuffer <<= lbits_to_go;
+ if (putcbuf(lbitbuffer & 0xff,buffer) == EOF) {
+ ffpmsg("rice_encode: end of buffer");
+ free(diff);
+ return(-1);
+ }
+ for (top -= lbits_to_go; top>=8; top -= 8) {
+ if (putcbuf(0, buffer) == EOF) {
+ ffpmsg("rice_encode: end of buffer");
+ free(diff);
+ return(-1);
+ }
+ }
+ lbitbuffer = 1;
+ lbits_to_go = 7-top;
+ }
+ /*
+ * bottom FS bits are written without coding
+ * code is output_nbits, moved into this routine to reduce overheads
+ * This code potentially breaks if FS>24, so I am limiting
+ * FS to 24 by choice of FSMAX above.
+ */
+ if (fs > 0) {
+ lbitbuffer <<= fs;
+ lbitbuffer |= v & fsmask;
+ lbits_to_go -= fs;
+ while (lbits_to_go <= 0) {
+ if (putcbuf((lbitbuffer>>(-lbits_to_go)) & 0xff,buffer)==EOF) {
+ ffpmsg("rice_encode: end of buffer");
+ free(diff);
+ return(-1);
+ }
+ lbits_to_go += 8;
+ }
+ }
+ }
+ buffer->bitbuffer = lbitbuffer;
+ buffer->bits_to_go = lbits_to_go;
+ }
+ }
+ done_outputing_bits(buffer);
+ free(diff);
+ /*
+ * return number of bytes used
+ */
+ return(buffer->current - buffer->start);
+}
+/*---------------------------------------------------------------------------*/
+/* bit_output.c
+ *
+ * Bit output routines
+ * Procedures return zero on success, EOF on end-of-buffer
+ *
+ * Programmer: R. White Date: 20 July 1998
+ */
+
+/* Initialize for bit output */
+
+static void start_outputing_bits(Buffer *buffer)
+{
+ /*
+ * Buffer is empty to start with
+ */
+ buffer->bitbuffer = 0;
+ buffer->bits_to_go = 8;
+}
+
+/*---------------------------------------------------------------------------*/
+/* Output N bits (N must be <= 32) */
+
+static int output_nbits(Buffer *buffer, int bits, int n)
+{
+/* local copies */
+int lbitbuffer;
+int lbits_to_go;
+
+ /*
+ * insert bits at end of bitbuffer
+ */
+ lbitbuffer = buffer->bitbuffer;
+ lbits_to_go = buffer->bits_to_go;
+ if (lbits_to_go+n > 32) {
+ /*
+ * special case for large n: put out the top lbits_to_go bits first
+ * note that 0 < lbits_to_go <= 8
+ */
+ lbitbuffer <<= lbits_to_go;
+ lbitbuffer |= (bits>>(n-lbits_to_go)) & ((1<<lbits_to_go)-1);
+ if (putcbuf(lbitbuffer & 0xff,buffer) == EOF) return(EOF);
+ n -= lbits_to_go;
+ lbits_to_go = 8;
+ }
+ lbitbuffer <<= n;
+ lbitbuffer |= ( bits & ((1<<n)-1) );
+ lbits_to_go -= n;
+ while (lbits_to_go <= 0) {
+ /*
+ * bitbuffer full, put out top 8 bits
+ */
+ if (putcbuf((lbitbuffer>>(-lbits_to_go)) & 0xff,buffer) == EOF)
+ return(EOF);
+ lbits_to_go += 8;
+ }
+ buffer->bitbuffer = lbitbuffer;
+ buffer->bits_to_go = lbits_to_go;
+ return(0);
+}
+
+/*---------------------------------------------------------------------------*/
+/* Flush out the last bits */
+
+static int done_outputing_bits(Buffer *buffer)
+{
+ if(buffer->bits_to_go < 8) {
+ if (putcbuf(buffer->bitbuffer<<buffer->bits_to_go,buffer) == EOF)
+ return(EOF);
+ }
+ return(0);
+}
+/*---------------------------------------------------------------------------*/
+/*----------------------------------------------------------*/
+/* */
+/* START OF SOURCE FILE ORIGINALLY CALLED rdecomp.c */
+/* */
+/*----------------------------------------------------------*/
+
+/* @(#) rdecomp.c 1.4 99/03/01 12:38:41 */
+/* rdecomp.c Decompress image line using
+ * (1) Difference of adjacent pixels
+ * (2) Rice algorithm coding
+ *
+ * Returns 0 on success or 1 on failure
+ */
+
+/* moved these 'includes' to the beginning of the file (WDP)
+#include <stdio.h>
+#include <stdlib.h>
+*/
+
+/* this routine used to be called 'rdecomp' (WDP) */
+
+int fits_rdecomp (unsigned char *c, /* input buffer */
+ int clen, /* length of input */
+ unsigned int array[], /* output array */
+ int nx, /* number of output pixels */
+ int nblock) /* coding block size */
+{
+int bsize, i, k, imax;
+int nbits, nzero, fs;
+unsigned char *cend, bytevalue;
+unsigned int b, diff, lastpix;
+int fsmax, fsbits, bbits;
+static int *nonzero_count = (int *)NULL;
+
+ /*
+ * Original size of each pixel (bsize, bytes) and coding block
+ * size (nblock, pixels)
+ * Could make bsize a parameter to allow more efficient
+ * compression of short & byte images.
+ */
+ bsize = 4;
+/* nblock = 32; */
+ /*
+ * From bsize derive:
+ * FSBITS = # bits required to store FS
+ * FSMAX = maximum value for FS
+ * BBITS = bits/pixel for direct coding
+ */
+ switch (bsize) {
+ case 1:
+ fsbits = 3;
+ fsmax = 6;
+ break;
+ case 2:
+ fsbits = 4;
+ fsmax = 14;
+ break;
+ case 4:
+ fsbits = 5;
+ fsmax = 25;
+ break;
+ default:
+ ffpmsg("rdecomp: bsize must be 1, 2, or 4 bytes");
+ return 1;
+ }
+ bbits = 1<<fsbits;
+
+ if (nonzero_count == (int *) NULL) {
+ /*
+ * nonzero_count is lookup table giving number of bits
+ * in 8-bit values not including leading zeros
+ */
+
+ /* NOTE!!! This memory never gets freed */
+ nonzero_count = (int *) malloc(256*sizeof(int));
+ if (nonzero_count == (int *) NULL) {
+ ffpmsg("rdecomp: insufficient memory");
+ return 1;
+ }
+ nzero = 8;
+ k = 128;
+ for (i=255; i>=0; ) {
+ for ( ; i>=k; i--) nonzero_count[i] = nzero;
+ k = k/2;
+ nzero--;
+ }
+ }
+ /*
+ * Decode in blocks of nblock pixels
+ */
+
+ /* first 4 bytes of input buffer contain the value of the first */
+ /* 4 byte integer value, without any encoding */
+
+ lastpix = 0;
+ bytevalue = c[0];
+ lastpix = lastpix | (bytevalue<<24);
+ bytevalue = c[1];
+ lastpix = lastpix | (bytevalue<<16);
+ bytevalue = c[2];
+ lastpix = lastpix | (bytevalue<<8);
+ bytevalue = c[3];
+ lastpix = lastpix | bytevalue;
+
+ c += 4;
+ cend = c + clen - 4;
+
+ b = *c++; /* bit buffer */
+ nbits = 8; /* number of bits remaining in b */
+ for (i = 0; i<nx; ) {
+ /* get the FS value from first fsbits */
+ nbits -= fsbits;
+ while (nbits < 0) {
+ b = (b<<8) | (*c++);
+ nbits += 8;
+ }
+ fs = (b >> nbits) - 1;
+ b &= (1<<nbits)-1;
+ /* loop over the next block */
+ imax = i + nblock;
+ if (imax > nx) imax = nx;
+ if (fs<0) {
+ /* low-entropy case, all zero differences */
+ for ( ; i<imax; i++) array[i] = lastpix;
+ } else if (fs==fsmax) {
+ /* high-entropy case, directly coded pixel values */
+ for ( ; i<imax; i++) {
+ k = bbits - nbits;
+ diff = b<<k;
+ for (k -= 8; k >= 0; k -= 8) {
+ b = *c++;
+ diff |= b<<k;
+ }
+ if (nbits>0) {
+ b = *c++;
+ diff |= b>>(-k);
+ b &= (1<<nbits)-1;
+ } else {
+ b = 0;
+ }
+ /*
+ * undo mapping and differencing
+ * Note that some of these operations will overflow the
+ * unsigned int arithmetic -- that's OK, it all works
+ * out to give the right answers in the output file.
+ */
+ if ((diff & 1) == 0) {
+ diff = diff>>1;
+ } else {
+ diff = ~(diff>>1);
+ }
+ array[i] = diff+lastpix;
+ lastpix = array[i];
+ }
+ } else {
+ /* normal case, Rice coding */
+ for ( ; i<imax; i++) {
+ /* count number of leading zeros */
+ while (b == 0) {
+ nbits += 8;
+ b = *c++;
+ }
+ nzero = nbits - nonzero_count[b];
+ nbits -= nzero+1;
+ /* flip the leading one-bit */
+ b ^= 1<<nbits;
+ /* get the FS trailing bits */
+ nbits -= fs;
+ while (nbits < 0) {
+ b = (b<<8) | (*c++);
+ nbits += 8;
+ }
+ diff = (nzero<<fs) | (b>>nbits);
+ b &= (1<<nbits)-1;
+ /* undo mapping and differencing */
+ if ((diff & 1) == 0) {
+ diff = diff>>1;
+ } else {
+ diff = ~(diff>>1);
+ }
+ array[i] = diff+lastpix;
+ lastpix = array[i];
+ }
+ }
+ if (c > cend) {
+ ffpmsg("decompression error: hit end of compressed byte stream");
+ return 1;
+ }
+ }
+ if (c < cend) {
+ ffpmsg("decompression warning: unused bytes at end of compressed buffer");
+ }
+ return 0;
+}
diff --git a/pkg/tbtables/cfitsio/ricecomp.h b/pkg/tbtables/cfitsio/ricecomp.h
new file mode 100644
index 00000000..4a48328e
--- /dev/null
+++ b/pkg/tbtables/cfitsio/ricecomp.h
@@ -0,0 +1,107 @@
+/* @(#) buffer.h 1.1 98/07/21 12:34:27 */
+/* buffer.h: structure for compression to buffer rather than to a file, including
+ * bit I/O buffer
+ *
+ * R. White, 19 June 1998
+ */
+
+
+typedef unsigned char Buffer_t;
+
+typedef struct {
+ int bitbuffer; /* bit buffer */
+ int bits_to_go; /* bits to go in buffer */
+ Buffer_t *start; /* start of buffer */
+ Buffer_t *current; /* current position in buffer */
+ Buffer_t *end; /* end of buffer */
+} Buffer;
+
+#define buffree(mf) (free(mf->start), free(mf))
+#define bufused(mf) (mf->current - mf->start)
+#define bufreset(mf) (mf->current = mf->start)
+
+/*
+ * getcbuf, putcbuf macros for character IO to buffer
+ * putcbuf returns EOF on end of buffer, else returns 0
+ */
+#define getcbuf(mf) ((mf->current >= mf->end) ? EOF : *(mf->current)++)
+#define putcbuf(c,mf) \
+ ((mf->current >= mf->end) ? \
+ EOF :\
+ ((*(mf->current)++ = c), 0))
+
+/*
+ * bufalloc sets up buffer of length n
+ */
+
+/* not needed by CFITSIO
+
+static Buffer *bufalloc(int n)
+{
+Buffer *mf;
+
+ mf = (Buffer *) malloc(sizeof(Buffer));
+ if (mf == (Buffer *)NULL) return((Buffer *)NULL);
+
+ mf->start = (Buffer_t *) malloc(n*sizeof(Buffer_t));
+ if (mf->start == (Buffer_t *)NULL) {
+ free(mf);
+ return((Buffer *)NULL);
+ }
+ mf->bits_to_go = 8;
+ mf->end = mf->start + n;
+ mf->current = mf->start;
+ return(mf);
+}
+*/
+
+/*
+ * bufrealloc extends buffer (or truncates it) by
+ * reallocating memory
+ */
+
+/* not needed by CFITSIO
+static int bufrealloc(Buffer *mf, int n)
+{
+int len;
+
+ len = mf->current - mf->start;
+
+ * silently throw away data if buffer is already longer than n *
+ if (len>n) len = n;
+ if (len<0) len = 0;
+
+ mf->start = (Buffer_t *) realloc(mf->start, n*sizeof(Buffer_t));
+ if (mf->start == (Buffer_t *)NULL) return(0);
+
+ mf->end = mf->start + n;
+ mf->current = mf->start + len;
+ return(n);
+}
+*/
+
+/*
+ * bufdump dumps contents of buffer to outfile and resets
+ * it to be empty. Returns number of bytes written.
+ *
+ * Note we don't write out the bit buffer -- you must call
+ * done_outputing_bits() first to ensure that the bit buffer
+ * is written out. I do it this way to allow incremental
+ * buffer dumps while bit IO is still going on.
+ */
+
+/* not needed by CFITSIO
+
+static int bufdump(FILE *outfile, Buffer *buffer)
+{
+int ndump;
+
+ ndump = bufused(buffer);
+ if (fwrite(buffer->start, 1, ndump, outfile) != ndump) {
+ fprintf(stderr, "bufdump: error in write\n");
+ exit(1);
+ }
+ bufreset(buffer);
+ return(ndump);
+}
+*/
diff --git a/pkg/tbtables/cfitsio/sample.tpl b/pkg/tbtables/cfitsio/sample.tpl
new file mode 100644
index 00000000..8cfca14e
--- /dev/null
+++ b/pkg/tbtables/cfitsio/sample.tpl
@@ -0,0 +1,121 @@
+# sample template - create 9 HDUs in one FITS file
+
+# syntax :
+
+# everything which starts with a hashmark is ignored
+# the same for empty lines
+
+# one can use \include filename to include other files
+# equal sign after keyword name is optional
+# \group must be terminated by \end
+# xtension is terminated by \group, xtension or EOF
+# First HDU of type image may be defined using "SIMPLE T"
+# group may contain other groups and xtensions
+# keywords may be indented, but indentation is limited to max 7chars.
+
+# template parser processes all keywords, makes substitutions
+# when necessary (hashmarks -> index), converts keyword names
+# to uppercase and writes keywords to file.
+# For string keywords, parser uses CFITSIO long string routines
+# to store string values longer than 72 characters. Parser can
+# read/process lines of any length, as long as there is enough memory.
+# For a very limited set of keywords (like NAXIS1 for binary tables)
+# template parser ignores values specified in template file
+# (one should not specify NAXIS1 for binary tables) and computes and
+# writes values respective to table structure.
+# number of rows in binary/ascii tables can be specified with NAXIS2
+
+# if the 1st HDU is not defined with "SIMPLE T" and is defined with
+# xtension image/asciitable/bintable then dummy primary HDU is
+# created by parser.
+
+simple t
+ bitpix 16
+ naxis 1
+ naxis1 10
+COMMENT
+ comment
+ sdsdf / keyword without value (null type)
+ if line begins with 8+ spaces everything is a comment
+
+xtension image
+ bitpix 16
+ naxis 1
+ naxis1 10
+ QWERW F / dfg dfgsd fg - boolean keyword
+ FFFSDS45 3454345 /integer_or_real keyword
+ SSSDFS34 32345.453 / real keyword
+ adsfd34 (234234.34,2342342.3) / complex keyword - no space between ()
+ SDFDF# adfasdfasdfdfcvxccvzxcvcvcxv / autoindexed keyword, here idx=1
+ SDFD# 'asf dfa dfad df dfad f ad fadfdaf dfdfa df loooooong keyyywoooord - reaaalllly verrrrrrrrrryy loooooooooong' / comment is max 80 chars
+ history history record, spaces (all but 1st) after keyname are copied
+ SDFDF# strg_value_without_spaces / autoindexed keyword, here idx=2
+ comment comment record, spaces (all but 1st) after keyname are copied
+ strg45 'sdfasdfadfffdfasdfasdfasdf &'
+ continue 'sdfsdfsdfsd fsdf' / 3 spaces must follow CONTINUE keyword
+
+
+xtension image
+ bitpix 16
+ naxis 1
+ naxis1 10
+
+\group
+
+ xtension image
+ bitpix 16
+ naxis 1
+ naxis1 10
+
+# create group inside group
+
+ \group
+
+# one can specify additional columns in group HDU. The first column
+# specified will have index 7 however, since the first 6 columns are occupied
+# by grouping table itself.
+# Please note, that it is not allowed to specify EXTNAME keyword as an
+# additional keyword for group HDU, since parser automatically writes
+# EXTNAME = GROUPING keyword.
+
+ TFORM# 13A
+ TTYPE# ADDIT_COL_IN_GRP_HDU
+ TFORM# 1E
+ TTYPE# REAL_COLUMN
+ COMMENT sure, there is always place for comments
+
+# the following specifies empty ascii table (0 cols / 0 rows)
+
+ xtension asciitable
+
+ \end
+
+\end
+
+# one do not have to specify all NAXISn keywords. If not specified
+# NAXISn equals zero.
+
+xtension image
+ bitpix 16
+ naxis 1
+# naxis1 10
+
+# the following tells how to set number of rows in binary table
+# note also that the last line in template file does not have to
+# have LineFeed character as the last one.
+
+xtension bintable
+naxis2 10
+EXTNAME asdjfhsdkf
+TTYPE# MEMBER_XTENSION
+TFORM# 8A
+TTYPE# MEMBER_2
+TFORM# 8U
+TTYPE# MEMBER_3
+TFORM# 8V
+TTYPE# MEMBER_NAME
+TFORM# 32A
+TDIM# '(8,4)'
+TTYPE# MEMBER_VERSION
+TFORM# 1J
+TNULL# 0 \ No newline at end of file
diff --git a/pkg/tbtables/cfitsio/scalnull.c b/pkg/tbtables/cfitsio/scalnull.c
new file mode 100644
index 00000000..e602acf5
--- /dev/null
+++ b/pkg/tbtables/cfitsio/scalnull.c
@@ -0,0 +1,230 @@
+/* This file, scalnull.c, contains the FITSIO routines used to define */
+/* the starting heap address, the value scaling and the null values. */
+
+/* The FITSIO software was written by William Pence at the High Energy */
+/* Astrophysic Science Archive Research Center (HEASARC) at the NASA */
+/* Goddard Space Flight Center. */
+
+#include <string.h>
+#include "fitsio2.h"
+/*--------------------------------------------------------------------------*/
+int ffpthp(fitsfile *fptr, /* I - FITS file pointer */
+ long theap, /* I - starting addrss for the heap */
+ int *status) /* IO - error status */
+/*
+ Define the starting address for the heap for a binary table.
+ The default address is NAXIS1 * NAXIS2. It is in units of
+ bytes relative to the beginning of the regular binary table data.
+ This routine also writes the appropriate THEAP keyword to the
+ FITS header.
+*/
+{
+ if (*status > 0 || theap < 1)
+ return(*status);
+
+ /* reset position to the correct HDU if necessary */
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu)
+ ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
+
+ (fptr->Fptr)->heapstart = theap;
+
+ ffukyj(fptr, "THEAP", theap, "byte offset to heap area", status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpscl(fitsfile *fptr, /* I - FITS file pointer */
+ double scale, /* I - scaling factor: value of BSCALE */
+ double zero, /* I - zero point: value of BZERO */
+ int *status) /* IO - error status */
+/*
+ Define the linear scaling factor for the primary array or image extension
+ pixel values. This routine overrides the scaling values given by the
+ BSCALE and BZERO keywords if present. Note that this routine does not
+ write or modify the BSCALE and BZERO keywords, but instead only modifies
+ the values temporarily in the internal buffer. Thus, a subsequent call to
+ the ffrdef routine will reset the scaling back to the BSCALE and BZERO
+ keyword values (or 1. and 0. respectively if the keywords are not present).
+*/
+{
+ tcolumn *colptr;
+ int hdutype;
+
+ if (*status > 0)
+ return(*status);
+
+ if (scale == 0)
+ return(*status = ZERO_SCALE); /* zero scale value is illegal */
+
+ if (ffghdt(fptr, &hdutype, status) > 0) /* get HDU type */
+ return(*status);
+
+ if (hdutype != IMAGE_HDU)
+ return(*status = NOT_IMAGE); /* not proper HDU type */
+
+ if (fits_is_compressed_image(fptr, status)) /* compressed images */
+ {
+ (fptr->Fptr)->cn_bscale = scale;
+ (fptr->Fptr)->cn_bzero = zero;
+
+ return(*status);
+ }
+
+ /* set pointer to the first 'column' (contains group parameters if any) */
+ colptr = (fptr->Fptr)->tableptr;
+
+ colptr++; /* increment to the 2nd 'column' pointer (the image itself) */
+
+ colptr->tscale = scale;
+ colptr->tzero = zero;
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpnul(fitsfile *fptr, /* I - FITS file pointer */
+ long nulvalue, /* I - null pixel value: value of BLANK */
+ int *status) /* IO - error status */
+/*
+ Define the value used to represent undefined pixels in the primary array or
+ image extension. This only applies to integer image pixel (i.e. BITPIX > 0).
+ This routine overrides the null pixel value given by the BLANK keyword
+ if present. Note that this routine does not write or modify the BLANK
+ keyword, but instead only modifies the value temporarily in the internal
+ buffer. Thus, a subsequent call to the ffrdef routine will reset the null
+ value back to the BLANK keyword value (or not defined if the keyword is not
+ present).
+*/
+{
+ tcolumn *colptr;
+ int hdutype;
+
+ if (*status > 0)
+ return(*status);
+
+ if (ffghdt(fptr, &hdutype, status) > 0) /* get HDU type */
+ return(*status);
+
+ if (hdutype != IMAGE_HDU)
+ return(*status = NOT_IMAGE); /* not proper HDU type */
+
+ if (fits_is_compressed_image(fptr, status)) /* ignore compressed images */
+ return(*status);
+
+ /* set pointer to the first 'column' (contains group parameters if any) */
+ colptr = (fptr->Fptr)->tableptr;
+
+ colptr++; /* increment to the 2nd 'column' pointer (the image itself) */
+
+ colptr->tnull = nulvalue;
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fftscl(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - column number to apply scaling to */
+ double scale, /* I - scaling factor: value of TSCALn */
+ double zero, /* I - zero point: value of TZEROn */
+ int *status) /* IO - error status */
+/*
+ Define the linear scaling factor for the TABLE or BINTABLE extension
+ column values. This routine overrides the scaling values given by the
+ TSCALn and TZEROn keywords if present. Note that this routine does not
+ write or modify the TSCALn and TZEROn keywords, but instead only modifies
+ the values temporarily in the internal buffer. Thus, a subsequent call to
+ the ffrdef routine will reset the scaling back to the TSCALn and TZEROn
+ keyword values (or 1. and 0. respectively if the keywords are not present).
+*/
+{
+ tcolumn *colptr;
+ int hdutype;
+
+ if (*status > 0)
+ return(*status);
+
+ if (scale == 0)
+ return(*status = ZERO_SCALE); /* zero scale value is illegal */
+
+ if (ffghdt(fptr, &hdutype, status) > 0) /* get HDU type */
+ return(*status);
+
+ if (hdutype == IMAGE_HDU)
+ return(*status = NOT_TABLE); /* not proper HDU type */
+
+ colptr = (fptr->Fptr)->tableptr; /* set pointer to the first column */
+ colptr += (colnum - 1); /* increment to the correct column */
+
+ colptr->tscale = scale;
+ colptr->tzero = zero;
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fftnul(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - column number to apply nulvalue to */
+ long nulvalue, /* I - null pixel value: value of TNULLn */
+ int *status) /* IO - error status */
+/*
+ Define the value used to represent undefined pixels in the BINTABLE column.
+ This only applies to integer datatype columns (TFORM = B, I, or J).
+ This routine overrides the null pixel value given by the TNULLn keyword
+ if present. Note that this routine does not write or modify the TNULLn
+ keyword, but instead only modifies the value temporarily in the internal
+ buffer. Thus, a subsequent call to the ffrdef routine will reset the null
+ value back to the TNULLn keyword value (or not defined if the keyword is not
+ present).
+*/
+{
+ tcolumn *colptr;
+ int hdutype;
+
+ if (*status > 0)
+ return(*status);
+
+ if (ffghdt(fptr, &hdutype, status) > 0) /* get HDU type */
+ return(*status);
+
+ if (hdutype != BINARY_TBL)
+ return(*status = NOT_BTABLE); /* not proper HDU type */
+
+ colptr = (fptr->Fptr)->tableptr; /* set pointer to the first column */
+ colptr += (colnum - 1); /* increment to the correct column */
+
+ colptr->tnull = nulvalue;
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffsnul(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - column number to apply nulvalue to */
+ char *nulstring, /* I - null pixel value: value of TNULLn */
+ int *status) /* IO - error status */
+/*
+ Define the string used to represent undefined pixels in the ASCII TABLE
+ column. This routine overrides the null value given by the TNULLn keyword
+ if present. Note that this routine does not write or modify the TNULLn
+ keyword, but instead only modifies the value temporarily in the internal
+ buffer. Thus, a subsequent call to the ffrdef routine will reset the null
+ value back to the TNULLn keyword value (or not defined if the keyword is not
+ present).
+*/
+{
+ tcolumn *colptr;
+ int hdutype;
+
+ if (*status > 0)
+ return(*status);
+
+ if (ffghdt(fptr, &hdutype, status) > 0) /* get HDU type */
+ return(*status);
+
+ if (hdutype != ASCII_TBL)
+ return(*status = NOT_ATABLE); /* not proper HDU type */
+
+ colptr = (fptr->Fptr)->tableptr; /* set pointer to the first column */
+ colptr += (colnum - 1); /* increment to the correct column */
+
+ colptr->strnull[0] = '\0';
+ strncat(colptr->strnull, nulstring, 19); /* limit string to 19 chars */
+
+ return(*status);
+}
diff --git a/pkg/tbtables/cfitsio/smem.c b/pkg/tbtables/cfitsio/smem.c
new file mode 100644
index 00000000..3cddb764
--- /dev/null
+++ b/pkg/tbtables/cfitsio/smem.c
@@ -0,0 +1,67 @@
+#include <stdio.h>
+#include <memory.h>
+#include <string.h>
+#include <malloc.h>
+#include "fitsio.h" /* needed to define OFF_T */
+#include "drvrsmem.h" /* uses OFF_T */
+
+int main(int argc, char **argv)
+{ int cmdok, listmode, longlistmode, recovermode, deletemode, id;
+
+listmode = longlistmode = recovermode = deletemode = 0;
+id = -1;
+cmdok = 1;
+
+switch (argc)
+ { case 1: listmode = 1;
+ break;
+ case 2:
+ if (0 == strcmp("-l", argv[1])) longlistmode = 1;
+ else if (0 == strcmp("-r", argv[1])) recovermode = 1;
+ else if (0 == strcmp("-d", argv[1])) deletemode = 1;
+ else cmdok = 0;
+ break;
+ case 3:
+ if (0 == strcmp("-r", argv[1])) recovermode = 1;
+ else if (0 == strcmp("-d", argv[1])) deletemode = 1;
+ else
+ { cmdok = 0; /* signal invalid cmd line syntax */
+ break;
+ }
+ if (1 != sscanf(argv[2], "%d", &id)) cmdok = 0;
+ break;
+ default:
+ cmdok = 0;
+ break;
+ }
+
+if (0 == cmdok)
+ { printf("usage :\n\n");
+ printf("smem - list all shared memory segments\n");
+ printf("\t!\tcouldn't obtain RDONLY lock - info unreliable\n");
+ printf("\tIdx\thandle of shared memory segment (visible by application)\n");
+ printf("\tKey\tcurrent system key of shared memory segment. Key\n");
+ printf("\t\tchanges whenever shmem segment is reallocated. Use\n");
+ printf("\t\tipcs (or ipcs -a) to view all shmem segments\n");
+ printf("\tNproc\tnumber of processes attached to segment\n");
+ printf("\tSize\tsize of shmem segment in bytes\n");
+ printf("\tFlags\tRESIZABLE - realloc allowed, PERSIST - segment is not\n");
+ printf("\t\tdeleted after shared_free called by last process attached\n");
+ printf("\t\tto it.\n");
+ printf("smem -d - delete all shared memory segments (may block)\n");
+ printf("smem -d id - delete specific shared memory segment (may block)\n");
+ printf("smem -r - unconditionally reset all shared memory segments\n\t\t(does not block, recovers zombie handles left by kill -9)\n");
+ printf("smem -r id - unconditionally reset specific shared memory segment\n");
+ }
+
+if (shared_init(0))
+ { printf("couldn't initialize shared memory, aborting ...\n");
+ return(10);
+ }
+
+if (listmode) shared_list(id);
+else if (recovermode) shared_recover(id);
+else if (deletemode) shared_uncond_delete(id);
+
+return(0);
+}
diff --git a/pkg/tbtables/cfitsio/speed.c b/pkg/tbtables/cfitsio/speed.c
new file mode 100644
index 00000000..2a948b43
--- /dev/null
+++ b/pkg/tbtables/cfitsio/speed.c
@@ -0,0 +1,485 @@
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+/*
+ Every program which uses the CFITSIO interface must include the
+ the fitsio.h header file. This contains the prototypes for all
+ the routines and defines the error status values and other symbolic
+ constants used in the interface.
+*/
+#include "fitsio.h"
+
+#define minvalue(A,B) ((A) < (B) ? (A) : (B))
+
+/* size of the image */
+#define XSIZE 3000
+#define YSIZE 3000
+
+/* size of data buffer */
+#define SHTSIZE 20000
+static long sarray[ SHTSIZE ] = {SHTSIZE * 0};
+
+/* no. of rows in binary table */
+#define BROWS 2500000
+
+/* no. of rows in ASCII table */
+#define AROWS 400000
+
+/* CLOCKS_PER_SEC should be defined by most compilers */
+#if defined(CLOCKS_PER_SEC)
+#define CLOCKTICKS CLOCKS_PER_SEC
+#else
+/* on SUN OS machine, CLOCKS_PER_SEC is not defined, so set its value */
+#define CLOCKTICKS 1000000
+#define difftime(A,B) ((double) A - (double) B)
+#endif
+
+/* define variables for measuring elapsed time */
+clock_t scpu, ecpu;
+time_t start, finish;
+
+int writeimage(fitsfile *fptr, int *status);
+int writebintable(fitsfile *fptr, int *status);
+int writeasctable(fitsfile *fptr, int *status);
+int readimage(fitsfile *fptr, int *status);
+int readatable(fitsfile *fptr, int *status);
+int readbtable(fitsfile *fptr, int *status);
+void printerror( int status);
+int marktime(int *status);
+int gettime(double *elapse, float *elapscpu, int *status);
+
+main()
+{
+/*************************************************************************
+ This program tests the speed of writing/reading FITS files with cfitsio
+**************************************************************************/
+
+ FILE *diskfile;
+ fitsfile *fptr; /* pointer to the FITS file, defined in fitsio.h */
+ int status, ii;
+ long rawloop;
+ char filename[] = "speedcc.fit"; /* name for new FITS file */
+ char buffer[2880] = {2880 * 0};
+ time_t tbegin, tend;
+ float rate, size, elapcpu, cpufrac;
+ double elapse;
+
+ tbegin = time(0);
+
+ remove(filename); /* Delete old file if it already exists */
+
+ diskfile = fopen(filename,"w+b");
+ rawloop = XSIZE * YSIZE / 720;
+
+ printf(" ");
+ printf(" SIZE / ELAPSE(%%CPU) = RATE\n");
+ printf("RAW fwrite (2880 bytes/loop)... ");
+ marktime(&status);
+
+ for (ii = 0; ii < rawloop; ii++)
+ if (fwrite(buffer, 1, 2880, diskfile) != 2880)
+ printf("write error \n");
+
+ gettime(&elapse, &elapcpu, &status);
+
+ cpufrac = elapcpu / elapse * 100.;
+ size = 2880. * rawloop / 1000000.;
+ rate = size / elapse;
+ printf(" %4.1fMB/%4.1fs(%3.0f) = %5.2fMB/s\n", size, elapse, cpufrac,rate);
+
+ /* read back the binary records */
+ fseek(diskfile, 0, 0);
+
+ printf("RAW fread (2880 bytes/loop)... ");
+ marktime(&status);
+
+ for (ii = 0; ii < rawloop; ii++)
+ if (fread(buffer, 1, 2880, diskfile) != 2880)
+ printf("read error \n");
+
+ gettime(&elapse, &elapcpu, &status);
+
+ cpufrac = elapcpu / elapse * 100.;
+ size = 2880. * rawloop / 1000000.;
+ rate = size / elapse;
+ printf(" %4.1fMB/%4.1fs(%3.0f) = %5.2fMB/s\n", size, elapse, cpufrac,rate);
+
+ fclose(diskfile);
+ remove(filename);
+
+ status = 0;
+ fptr = 0;
+
+ if (fits_create_file(&fptr, filename, &status)) /* create new FITS file */
+ printerror( status);
+
+ if (writeimage(fptr, &status))
+ printerror( status);
+
+ if (writebintable(fptr, &status))
+ printerror( status);
+
+ if (writeasctable(fptr, &status))
+ printerror( status);
+
+ if (readimage(fptr, &status))
+ printerror( status);
+
+ if (readbtable(fptr, &status))
+ printerror( status);
+
+ if (readatable(fptr, &status))
+ printerror( status);
+
+ if (fits_close_file(fptr, &status))
+ printerror( status );
+
+ tend = time(0);
+ elapse = difftime(tend, tbegin) + 0.5;
+ printf("Total elapsed time = %.1fs, status = %d\n",elapse, status);
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int writeimage(fitsfile *fptr, int *status)
+
+ /**************************************************/
+ /* write the primary array containing a 2-D image */
+ /**************************************************/
+{
+ long nremain, ii;
+ float rate, size, elapcpu, cpufrac;
+ double elapse;
+
+ /* initialize FITS image parameters */
+ int bitpix = 32; /* 32-bit signed integer pixel values */
+ long naxis = 2; /* 2-dimensional image */
+ long naxes[2] = {XSIZE, YSIZE }; /* image size */
+
+ /* write the required keywords for the primary array image */
+ if ( fits_create_img(fptr, bitpix, naxis, naxes, status) )
+ printerror( *status );
+
+ printf("\nWrite %dx%d I*4 image, %d pixels/loop: ",XSIZE,YSIZE,SHTSIZE);
+ marktime(status);
+
+ nremain = XSIZE * YSIZE;
+ for (ii = 1; ii <= nremain; ii += SHTSIZE)
+ {
+ ffpprj(fptr, 0, ii, SHTSIZE, sarray, status);
+ }
+
+ ffflus(fptr, status); /* flush all buffers to disk */
+
+ gettime(&elapse, &elapcpu, status);
+
+ cpufrac = elapcpu / elapse * 100.;
+ size = XSIZE * 4. * YSIZE / 1000000.;
+ rate = size / elapse;
+ printf(" %4.1fMB/%4.1fs(%3.0f) = %5.2fMB/s\n", size, elapse, cpufrac,rate);
+
+ return( *status );
+}
+/*--------------------------------------------------------------------------*/
+int writebintable (fitsfile *fptr, int *status)
+
+ /*********************************************************/
+ /* Create a binary table extension containing 3 columns */
+ /*********************************************************/
+{
+ int hdutype, tfields = 2;
+ long nremain, ntodo, firstrow = 1, firstelem = 1, nrows;
+ float rate, size, elapcpu, cpufrac;
+ double elapse;
+
+ char extname[] = "Speed_Test"; /* extension name */
+
+ /* define the name, datatype, and physical units for the columns */
+ char *ttype[] = { "first", "second" };
+ char *tform[] = {"1J", "1J" };
+ char *tunit[] = { " ", " " };
+
+ /* append a new empty binary table onto the FITS file */
+
+ if ( fits_create_tbl( fptr, BINARY_TBL, BROWS, tfields, ttype, tform,
+ tunit, extname, status) )
+ printerror( *status );
+
+ /* get table row size and optimum number of rows to write per loop */
+ fits_get_rowsize(fptr, &nrows, status);
+ nrows = minvalue(nrows, SHTSIZE);
+ nremain = BROWS;
+
+ printf("Write %7drow x %dcol bintable %4d rows/loop:", BROWS, tfields,
+ nrows);
+ marktime(status);
+
+ while(nremain)
+ {
+ ntodo = minvalue(nrows, nremain);
+ ffpclj(fptr, 1, firstrow, firstelem, ntodo, sarray, status);
+ ffpclj(fptr, 2, firstrow, firstelem, ntodo, sarray, status);
+ firstrow += ntodo;
+ nremain -= ntodo;
+ }
+
+ ffflus(fptr, status); /* flush all buffers to disk */
+
+ gettime(&elapse, &elapcpu, status);
+
+ cpufrac = elapcpu / elapse * 100.;
+ size = BROWS * 8. / 1000000.;
+ rate = size / elapse;
+ printf(" %4.1fMB/%4.1fs(%3.0f) = %5.2fMB/s\n", size, elapse, cpufrac,rate);
+
+ return( *status );
+}
+/*--------------------------------------------------------------------------*/
+int writeasctable (fitsfile *fptr, int *status)
+
+ /*********************************************************/
+ /* Create an ASCII table extension containing 2 columns */
+ /*********************************************************/
+{
+ int hdutype, tfields = 2;
+ long nremain, ntodo, firstrow = 1, firstelem = 1;
+ long nrows;
+ float rate, size, elapcpu, cpufrac;
+ double elapse;
+
+ char extname[] = "Speed_Test"; /* extension name */
+
+ /* define the name, datatype, and physical units for the columns */
+ char *ttype[] = { "first", "second" };
+ char *tform[] = {"I6", "I6" };
+ char *tunit[] = { " ", " " };
+
+ /* append a new empty ASCII table onto the FITS file */
+ if ( fits_create_tbl( fptr, ASCII_TBL, AROWS, tfields, ttype, tform,
+ tunit, extname, status) )
+ printerror( *status );
+
+ /* get table row size and optimum number of rows to write per loop */
+ fits_get_rowsize(fptr, &nrows, status);
+ nrows = minvalue(nrows, SHTSIZE);
+ nremain = AROWS;
+
+ printf("Write %7drow x %dcol asctable %4d rows/loop:", AROWS, tfields,
+ nrows);
+ marktime(status);
+
+ while(nremain)
+ {
+ ntodo = minvalue(nrows, nremain);
+ ffpclj(fptr, 1, firstrow, firstelem, ntodo, sarray, status);
+ ffpclj(fptr, 2, firstrow, firstelem, ntodo, sarray, status);
+ firstrow += ntodo;
+ nremain -= ntodo;
+ }
+
+ ffflus(fptr, status); /* flush all buffers to disk */
+
+ gettime(&elapse, &elapcpu, status);
+
+ cpufrac = elapcpu / elapse * 100.;
+ size = AROWS * 13. / 1000000.;
+ rate = size / elapse;
+ printf(" %4.1fMB/%4.1fs(%3.0f) = %5.2fMB/s\n", size, elapse, cpufrac,rate);
+
+ return( *status );
+}
+/*--------------------------------------------------------------------------*/
+int readimage( fitsfile *fptr, int *status )
+
+ /*********************/
+ /* Read a FITS image */
+ /*********************/
+{
+ int anynull, hdutype;
+ long nremain, ii;
+ long longnull = 0;
+ float rate, size, elapcpu, cpufrac;
+ double elapse;
+
+ /* move to the primary array */
+ if ( fits_movabs_hdu(fptr, 1, &hdutype, status) )
+ printerror( *status );
+
+ printf("\nRead back image ");
+ marktime(status);
+
+ nremain = XSIZE * YSIZE;
+ for (ii=1; ii <= nremain; ii += SHTSIZE)
+ {
+ ffgpvj(fptr, 0, ii, SHTSIZE, longnull, sarray, &anynull, status);
+ }
+
+ gettime(&elapse, &elapcpu, status);
+
+ cpufrac = elapcpu / elapse * 100.;
+ size = XSIZE * 4. * YSIZE / 1000000.;
+ rate = size / elapse;
+ printf(" %4.1fMB/%4.1fs(%3.0f) = %5.2fMB/s\n", size, elapse, cpufrac,rate);
+
+ return( *status );
+}
+/*--------------------------------------------------------------------------*/
+int readbtable( fitsfile *fptr, int *status )
+
+ /************************************************************/
+ /* read and print data values from the binary table */
+ /************************************************************/
+{
+ int hdutype, anynull;
+ long nremain, ntodo, firstrow = 1, firstelem = 1;
+ long nrows;
+ long lnull = 0;
+ float rate, size, elapcpu, cpufrac;
+ double elapse;
+
+ /* move to the table */
+ if ( fits_movrel_hdu(fptr, 1, &hdutype, status) )
+ printerror( *status );
+
+ /* get table row size and optimum number of rows to read per loop */
+ fits_get_rowsize(fptr, &nrows, status);
+ nrows = minvalue(nrows, SHTSIZE);
+
+ /* read the columns */
+ nremain = BROWS;
+
+ printf("Read back BINTABLE ");
+ marktime(status);
+
+ while(nremain)
+ {
+ ntodo = minvalue(nrows, nremain);
+ ffgcvj(fptr, 1, firstrow, firstelem, ntodo,
+ lnull, sarray, &anynull, status);
+ ffgcvj(fptr, 2, firstrow, firstelem, ntodo,
+ lnull, sarray, &anynull, status);
+ firstrow += ntodo;
+ nremain -= ntodo;
+ }
+
+ gettime(&elapse, &elapcpu, status);
+
+ cpufrac = elapcpu / elapse * 100.;
+ size = BROWS * 8. / 1000000.;
+ rate = size / elapse;
+ printf(" %4.1fMB/%4.1fs(%3.0f) = %5.2fMB/s\n", size, elapse, cpufrac,rate);
+
+ return( *status );
+}
+/*--------------------------------------------------------------------------*/
+int readatable( fitsfile *fptr, int *status )
+
+ /************************************************************/
+ /* read and print data values from an ASCII or binary table */
+ /************************************************************/
+{
+ int hdutype, anynull;
+ long nremain, ntodo, firstrow = 1, firstelem = 1;
+ long nrows;
+ long lnull = 0;
+ float rate, size, elapcpu, cpufrac;
+ double elapse;
+
+ /* move to the table */
+ if ( fits_movrel_hdu(fptr, 1, &hdutype, status) )
+ printerror( *status );
+
+ /* get table row size and optimum number of rows to read per loop */
+ fits_get_rowsize(fptr, &nrows, status);
+ nrows = minvalue(nrows, SHTSIZE);
+
+ /* read the columns */
+ nremain = AROWS;
+
+ printf("Read back ASCII Table ");
+ marktime(status);
+
+ while(nremain)
+ {
+ ntodo = minvalue(nrows, nremain);
+ ffgcvj(fptr, 1, firstrow, firstelem, ntodo,
+ lnull, sarray, &anynull, status);
+ ffgcvj(fptr, 2, firstrow, firstelem, ntodo,
+ lnull, sarray, &anynull, status);
+ firstrow += ntodo;
+ nremain -= ntodo;
+ }
+
+ gettime(&elapse, &elapcpu, status);
+
+ cpufrac = elapcpu / elapse * 100.;
+ size = AROWS * 13. / 1000000.;
+ rate = size / elapse;
+ printf(" %4.1fMB/%4.1fs(%3.0f) = %5.2fMB/s\n", size, elapse, cpufrac,rate);
+
+ return( *status );
+}
+/*--------------------------------------------------------------------------*/
+void printerror( int status)
+{
+ /*****************************************************/
+ /* Print out cfitsio error messages and exit program */
+ /*****************************************************/
+
+ char status_str[FLEN_STATUS], errmsg[FLEN_ERRMSG];
+
+ if (status)
+ fprintf(stderr, "\n*** Error occurred during program execution ***\n");
+
+ fits_get_errstatus(status, status_str); /* get the error description */
+ fprintf(stderr, "\nstatus = %d: %s\n", status, status_str);
+
+ /* get first message; null if stack is empty */
+ if ( fits_read_errmsg(errmsg) )
+ {
+ fprintf(stderr, "\nError message stack:\n");
+ fprintf(stderr, " %s\n", errmsg);
+
+ while ( fits_read_errmsg(errmsg) ) /* get remaining messages */
+ fprintf(stderr, " %s\n", errmsg);
+ }
+
+ exit( status ); /* terminate the program, returning error status */
+}
+/*--------------------------------------------------------------------------*/
+int marktime( int *status)
+{
+ double telapse;
+ time_t temp;
+
+ temp = time(0);
+
+ /* Since elapsed time is only measured to the nearest second */
+ /* keep getting the time until the seconds tick just changes. */
+ /* This provides more consistent timing measurements since the */
+ /* intervals all start on an integer seconds. */
+
+ telapse = 0.;
+ while (telapse == 0.)
+ {
+ scpu = clock();
+ start = time(0);
+ telapse = difftime( start, temp );
+ }
+ return( *status );
+}
+/*--------------------------------------------------------------------------*/
+int gettime(double *elapse, float *elapscpu, int *status)
+{
+ clock_t ecpu;
+ time_t finish;
+
+ ecpu = clock();
+ finish = time(0);
+
+ *elapse = difftime(finish, start) + 0.5;
+ *elapscpu = (ecpu - scpu) * 1.0 / CLOCKTICKS;
+
+ return( *status );
+}
diff --git a/pkg/tbtables/cfitsio/swapproc.c b/pkg/tbtables/cfitsio/swapproc.c
new file mode 100644
index 00000000..247e4933
--- /dev/null
+++ b/pkg/tbtables/cfitsio/swapproc.c
@@ -0,0 +1,98 @@
+/* This file, swapproc.c, contains general utility routines that are */
+/* used by other FITSIO routines to swap bytes. */
+
+/* The FITSIO software was written by William Pence at the High Energy */
+/* Astrophysic Science Archive Research Center (HEASARC) at the NASA */
+/* Goddard Space Flight Center. */
+
+#include <string.h>
+#include <stdlib.h>
+#include "fitsio2.h"
+/*--------------------------------------------------------------------------*/
+void ffswap2(short *svalues, /* IO - pointer to shorts to be swapped */
+ long nvals) /* I - number of shorts to be swapped */
+/*
+ swap the bytes in the input short integers: ( 0 1 -> 1 0 )
+*/
+{
+ register char *cvalues;
+ register long ii;
+
+ union u_tag {
+ char cvals[2]; /* equivalence an array of 4 bytes with */
+ short sval; /* a short */
+ } u;
+
+ cvalues = (char *) svalues; /* copy the initial pointer value */
+
+ for (ii = 0; ii < nvals;)
+ {
+ u.sval = svalues[ii++]; /* copy next short to temporary buffer */
+
+ *cvalues++ = u.cvals[1]; /* copy the 2 bytes to output in turn */
+ *cvalues++ = u.cvals[0];
+ }
+ return;
+}
+/*--------------------------------------------------------------------------*/
+void ffswap4(INT32BIT *ivalues, /* IO - pointer to floats to be swapped */
+ long nvals) /* I - number of floats to be swapped */
+/*
+ swap the bytes in the input 4-byte integer: ( 0 1 2 3 -> 3 2 1 0 )
+*/
+{
+ register char *cvalues;
+ register long ii;
+
+ union u_tag {
+ char cvals[4]; /* equivalence an array of 4 bytes with */
+ INT32BIT ival; /* a float */
+ } u;
+
+ cvalues = (char *) ivalues; /* copy the initial pointer value */
+
+ for (ii = 0; ii < nvals;)
+ {
+ u.ival = ivalues[ii++]; /* copy next float to buffer */
+
+ *cvalues++ = u.cvals[3]; /* copy the 4 bytes in turn */
+ *cvalues++ = u.cvals[2];
+ *cvalues++ = u.cvals[1];
+ *cvalues++ = u.cvals[0];
+ }
+ return;
+}
+/*--------------------------------------------------------------------------*/
+void ffswap8(double *dvalues, /* IO - pointer to doubles to be swapped */
+ long nvals) /* I - number of doubles to be swapped */
+/*
+ swap the bytes in the input doubles: ( 01234567 -> 76543210 )
+*/
+{
+ register char *cvalues;
+ register long ii;
+ register char temp;
+
+ cvalues = (char *) dvalues; /* copy the pointer value */
+
+ for (ii = 0; ii < nvals*8; ii += 8)
+ {
+ temp = cvalues[ii];
+ cvalues[ii] = cvalues[ii+7];
+ cvalues[ii+7] = temp;
+
+ temp = cvalues[ii+1];
+ cvalues[ii+1] = cvalues[ii+6];
+ cvalues[ii+6] = temp;
+
+ temp = cvalues[ii+2];
+ cvalues[ii+2] = cvalues[ii+5];
+ cvalues[ii+5] = temp;
+
+ temp = cvalues[ii+3];
+ cvalues[ii+3] = cvalues[ii+4];
+ cvalues[ii+4] = temp;
+ }
+ return;
+}
+
diff --git a/pkg/tbtables/cfitsio/testf77.f b/pkg/tbtables/cfitsio/testf77.f
new file mode 100644
index 00000000..ac3bc217
--- /dev/null
+++ b/pkg/tbtables/cfitsio/testf77.f
@@ -0,0 +1,2488 @@
+C This is a big and complicated program that tests most of
+C the fitsio routines. This code does not represent
+C the most efficient method of reading or writing FITS files
+C because this code is primarily designed to stress the fitsio
+C library routines.
+
+ character asciisum*17
+ character*3 cval
+ character*1 xinarray(21), binarray(21), boutarray(21), bnul
+ character colname*70, tdisp*40, nulstr*40
+ character oskey*15
+ character iskey*21
+ character lstr*200
+ character comm*73
+ character*30 inskey(21)
+ character*30 onskey(3)
+ character filename*40, card*78, card2*78
+ character keyword*8
+ character value*68, comment*72
+ character uchars*78
+ character*15 ttype(10), tform(10), tunit(10)
+ character*15 tblname
+ character*15 binname
+ character errmsg*75
+ character*8 inclist(2),exclist(2)
+ character*8 xctype,yctype,ctype
+ character*18 kunit
+
+ logical simple,extend,larray(42), larray2(42)
+ logical olkey, ilkey, onlkey(3), inlkey(3), anynull
+
+ integer*2 imgarray(19,30), imgarray2(10,20)
+ integer*2 iinarray(21), ioutarray(21), inul
+
+ integer naxes(3), pcount, gcount, npixels, nrows, rowlen
+ integer existkeys, morekeys, keynum
+ integer datastatus, hdustatus
+ integer status, bitpix, naxis, block
+ integer ii, jj, jjj, hdutype, hdunum, tfields
+ integer nkeys, nfound, colnum, typecode, signval,nmsg
+ integer repeat, offset, width, jnulval
+ integer kinarray(21), koutarray(21), knul
+ integer jinarray(21), joutarray(21), jnul
+ integer ojkey, ijkey, otint
+ integer onjkey(3), injkey(3)
+ integer tbcol(5)
+ integer iunit, tmpunit
+ integer fpixels(2), lpixels(2), inc(2)
+
+ real estatus, vers
+ real einarray(21), eoutarray(21), enul, cinarray(42)
+ real ofkey, oekey, iekey, onfkey(3),onekey(3), inekey(3)
+
+ double precision dinarray(21),doutarray(21),dnul, minarray(42)
+ double precision scale, zero
+ double precision ogkey, odkey, idkey, otfrac, ongkey(3)
+ double precision ondkey(3), indkey(3)
+ double precision checksum, datsum
+ double precision xrval,yrval,xrpix,yrpix,xinc,yinc,rot
+ double precision xpos,ypos,xpix,ypix
+
+ tblname = 'Test-ASCII'
+ binname = 'Test-BINTABLE'
+ onskey(1) = 'first string'
+ onskey(2) = 'second string'
+ onskey(3) = ' '
+ oskey = 'value_string'
+ inclist(1)='key*'
+ inclist(2)='newikys'
+ exclist(1)='key_pr*'
+ exclist(2)='key_pkls'
+ xctype='RA---TAN'
+ yctype='DEC--TAN'
+
+ olkey = .true.
+ ojkey = 11
+ otint = 12345678
+ ofkey = 12.121212
+ oekey = 13.131313
+ ogkey = 14.1414141414141414D+00
+ odkey = 15.1515151515151515D+00
+ otfrac = .1234567890123456D+00
+ onlkey(1) = .true.
+ onlkey(2) = .false.
+ onlkey(3) = .true.
+ onjkey(1) = 11
+ onjkey(2) = 12
+ onjkey(3) = 13
+ onfkey(1) = 12.121212
+ onfkey(2) = 13.131313
+ onfkey(3) = 14.141414
+ onekey(1) = 13.131313
+ onekey(2) = 14.141414
+ onekey(3) = 15.151515
+ ongkey(1) = 14.1414141414141414D+00
+ ongkey(2) = 15.1515151515151515D+00
+ ongkey(3) = 16.1616161616161616D+00
+ ondkey(1) = 15.1515151515151515D+00
+ ondkey(2) = 16.1616161616161616D+00
+ ondkey(3) = 17.1717171717171717D+00
+
+ tbcol(1) = 1
+ tbcol(2) = 17
+ tbcol(3) = 28
+ tbcol(4) = 43
+ tbcol(5) = 56
+ status = 0
+
+ call ftvers(vers)
+ write(*,'(1x,A,F7.3)') 'FITSIO TESTPROG, v', vers
+ write(*, '(1x,A)')' '
+
+ iunit = 15
+ tmpunit = 16
+
+ write(*,'(1x,A)') 'Try opening then closing a nonexistent file: '
+ call ftopen(iunit, 'tq123x.kjl', 1, block, status)
+ write(*,'(1x,A,2i4)')' ftopen iunit, status (expect an error) ='
+ & ,iunit, status
+ call ftclos(iunit, status)
+ write(*,'(1x,A,i4)')' ftclos status = ', status
+ write(*,'(1x,A)')' '
+
+ call ftcmsg
+ status = 0
+
+ filename = 'testf77.fit'
+
+C delete previous version of the file, if it exists
+
+ call ftopen(iunit, filename, 1, block, status)
+ if (status .eq. 0)then
+ call ftdelt(iunit, status)
+ else
+C clear the error message stack
+ call ftcmsg
+ end if
+
+ status = 0
+
+C
+C #####################
+C # create FITS file #
+C #####################
+
+
+ call ftinit(iunit, filename, 1, status)
+ write(*,'(1x,A,i4)')'ftinit create new file status = ', status
+ write(*,'(1x,A)')' '
+
+ if (status .ne. 0)go to 999
+
+ simple = .true.
+ bitpix = 32
+ naxis = 2
+ naxes(1) = 10
+ naxes(2) = 2
+ npixels = 20
+ pcount = 0
+ gcount = 1
+ extend = .true.
+
+C ############################
+C # write single keywords #
+C ############################
+
+ call ftphpr(iunit,simple, bitpix, naxis, naxes,
+ & 0,1,extend,status)
+
+ call ftprec(iunit,
+ &'key_prec= ''This keyword was written by fxprec'' / '//
+ & 'comment goes here', status)
+
+ write(*,'(1x,A)') 'test writing of long string keywords: '
+ card = '1234567890123456789012345678901234567890'//
+ & '12345678901234567890123456789012345'
+ call ftpkys(iunit, 'card1', card, ' ', status)
+ call ftgkey(iunit, 'card1', card2, comment, status)
+
+ write(*,'(1x,A)') card
+ write(*,'(1x,A)') card2
+
+ card = '1234567890123456789012345678901234567890'//
+ & '123456789012345678901234''6789012345'
+ call ftpkys(iunit, 'card2', card, ' ', status)
+ call ftgkey(iunit, 'card2', card2, comment, status)
+ write(*,'(1x,A)') card
+ write(*,'(1x,A)') card2
+
+ card = '1234567890123456789012345678901234567890'//
+ & '123456789012345678901234''''789012345'
+ call ftpkys(iunit, 'card3', card, ' ', status)
+ call ftgkey(iunit, 'card3', card2, comment, status)
+ write(*,'(1x,A)') card
+ write(*,'(1x,A)') card2
+
+ card = '1234567890123456789012345678901234567890'//
+ & '123456789012345678901234567''9012345'
+ call ftpkys(iunit, 'card4', card, ' ', status)
+ call ftgkey(iunit, 'card4', card2, comment, status)
+ write(*,'(1x,A)') card
+ write(*,'(1x,A)') card2
+
+ call ftpkys(iunit, 'key_pkys', oskey, 'fxpkys comment', status)
+ call ftpkyl(iunit, 'key_pkyl', olkey, 'fxpkyl comment', status)
+ call ftpkyj(iunit, 'key_pkyj', ojkey, 'fxpkyj comment', status)
+ call ftpkyf(iunit,'key_pkyf',ofkey,5, 'fxpkyf comment', status)
+ call ftpkye(iunit,'key_pkye',oekey,6, 'fxpkye comment', status)
+ call ftpkyg(iunit,'key_pkyg',ogkey,14, 'fxpkyg comment',status)
+ call ftpkyd(iunit,'key_pkyd',odkey,14, 'fxpkyd comment',status)
+
+ lstr='This is a very long string '//
+ & 'value that is continued over more than one keyword.'
+
+ call ftpkls(iunit,'key_pkls',lstr,'fxpkls comment',status)
+
+ call ftplsw(iunit, status)
+ call ftpkyt(iunit,'key_pkyt',otint,otfrac,'fxpkyt comment',
+ & status)
+ call ftpcom(iunit, 'This keyword was written by fxpcom.',
+ & status)
+ call ftphis(iunit,
+ &' This keyword written by fxphis (w/ 2 leading spaces).',
+ & status)
+
+ call ftpdat(iunit, status)
+
+ if (status .gt. 0)go to 999
+
+C
+C ###############################
+C # write arrays of keywords #
+C ###############################
+
+ nkeys = 3
+
+ comm = 'fxpkns comment&'
+ call ftpkns(iunit, 'ky_pkns', 1, nkeys, onskey, comm, status)
+ comm = 'fxpknl comment&'
+ call ftpknl(iunit, 'ky_pknl', 1, nkeys, onlkey, comm, status)
+
+ comm = 'fxpknj comment&'
+ call ftpknj(iunit, 'ky_pknj', 1, nkeys, onjkey, comm, status)
+
+ comm = 'fxpknf comment&'
+ call ftpknf(iunit, 'ky_pknf', 1, nkeys, onfkey,5,comm,status)
+
+ comm = 'fxpkne comment&'
+ call ftpkne(iunit, 'ky_pkne', 1, nkeys, onekey,6,comm,status)
+
+ comm = 'fxpkng comment&'
+ call ftpkng(iunit, 'ky_pkng', 1, nkeys, ongkey,13,comm,status)
+
+ comm = 'fxpknd comment&'
+ call ftpknd(iunit, 'ky_pknd', 1, nkeys, ondkey,14,comm,status)
+
+ if (status .gt. 0)go to 999
+
+C ############################
+C # write generic keywords #
+C ############################
+
+
+ oskey = '1'
+ call ftpkys(iunit, 'tstring', oskey, 'tstring comment',status)
+
+ olkey = .true.
+ call ftpkyl(iunit, 'tlogical', olkey, 'tlogical comment',
+ & status)
+
+ ojkey = 11
+ call ftpkyj(iunit, 'tbyte', ojkey, 'tbyte comment', status)
+
+ ojkey = 21
+ call ftpkyj(iunit, 'tshort', ojkey, 'tshort comment', status)
+
+ ojkey = 31
+ call ftpkyj(iunit, 'tint', ojkey, 'tint comment', status)
+
+ ojkey = 41
+ call ftpkyj(iunit, 'tlong', ojkey, 'tlong comment', status)
+
+ oekey = 42
+ call ftpkye(iunit, 'tfloat', oekey, 6,'tfloat comment', status)
+
+ odkey = 82.D+00
+ call ftpkyd(iunit, 'tdouble', odkey, 14, 'tdouble comment',
+ & status)
+
+ if (status .gt. 0)go to 999
+ write(*,'(1x,A)') 'Wrote all Keywords successfully '
+
+
+C ############################
+C # write data #
+C ############################
+
+
+C define the null value (must do this before writing any data)
+ call ftpkyj(iunit,'BLANK',-99,
+ & 'value to use for undefined pixels', status)
+
+C initialize arrays of values to write to primary array
+ do ii = 1, npixels
+ boutarray(ii) = char(ii)
+ ioutarray(ii) = ii
+ joutarray(ii) = ii
+ eoutarray(ii) = ii
+ doutarray(ii) = ii
+ end do
+
+C write a few pixels with each datatype
+C set the last value in each group of 4 as undefined
+ call ftpprb(iunit, 1, 1, 2, boutarray(1), status)
+ call ftppri(iunit, 1, 5, 2, ioutarray(5), status)
+ call ftpprj(iunit, 1, 9, 2, joutarray(9), status)
+ call ftppre(iunit, 1, 13, 2, eoutarray(13), status)
+ call ftpprd(iunit, 1, 17, 2, doutarray(17), status)
+ bnul = char(4)
+ call ftppnb(iunit, 1, 3, 2, boutarray(3), bnul, status)
+ inul = 8
+ call ftppni(iunit, 1, 7, 2, ioutarray(7), inul, status)
+ call ftppnj(iunit, 1, 11, 2, joutarray(11), 12, status)
+ call ftppne(iunit, 1, 15, 2, eoutarray(15), 16., status)
+ dnul = 20.
+ call ftppnd(iunit, 1, 19, 2, doutarray(19), dnul, status)
+ call ftppru(iunit, 1, 1, 1, status)
+
+ if (status .gt. 0)then
+ write(*,'(1x,A,I4)')'ftppnx status = ', status
+ goto 999
+ end if
+
+ call ftflus(iunit, status)
+C flush all data to the disk file
+ write(*,'(1x,A,I4)')'ftflus status = ', status
+ write(*,'(1x,A)')' '
+
+ call ftghdn(iunit, hdunum)
+ write(*,'(1x,A,I4)')'HDU number = ', hdunum
+
+C ############################
+C # read data #
+C ############################
+
+
+C read back the data, setting null values = 99
+ write(*,'(1x,A)')
+ & 'Values read back from primary array (99 = null pixel)'
+ write(*,'(1x,A)')
+ & 'The 1st, and every 4th pixel should be undefined: '
+
+ anynull = .false.
+ bnul = char(99)
+ call ftgpvb(iunit, 1, 1, 10, bnul, binarray, anynull, status)
+ call ftgpvb(iunit, 1, 11, 10, bnul, binarray(11),anynull,status)
+
+ do ii = 1,npixels
+ iinarray(ii) = ichar(binarray(ii))
+ end do
+
+ write(*,1101) (iinarray(ii), ii = 1, npixels), anynull,
+ & ' (ftgpvb) '
+1101 format(1x,20i3,l3,a)
+
+ inul = 99
+ call ftgpvi(iunit, 1, 1, npixels, inul, iinarray,anynull,status)
+
+ write(*,1101) (iinarray(ii), ii = 1, npixels), anynull,
+ & ' (ftgpvi) '
+
+ call ftgpvj(iunit, 1, 1, npixels, 99, jinarray,anynull,status)
+
+ write(*,1101) (jinarray(ii), ii = 1, npixels), anynull,
+ & ' (ftgpvj) '
+
+ call ftgpve(iunit, 1, 1, npixels, 99., einarray,anynull,status)
+
+ write(*,1102) (einarray(ii), ii = 1, npixels), anynull,
+ & ' (ftgpve) '
+
+1102 format(2x,20f3.0,l2,a)
+
+ dnul = 99.
+ call ftgpvd(iunit, 1, 1, 10, dnul, dinarray, anynull, status)
+ call ftgpvd(iunit, 1, 11, 10, dnul,dinarray(11),anynull,status)
+
+ write(*,1102) (dinarray(ii), ii = 1, npixels), anynull,
+ & ' (ftgpvd) '
+
+ if (status .gt. 0)then
+ write(*,'(1x,A,I4)')'ERROR: ftgpv_ status = ', status
+ goto 999
+ end if
+
+ if (.not. anynull)then
+ write(*,'(1x,A)') 'ERROR: ftgpv_ did not detect null values '
+ go to 999
+ end if
+
+C reset the output null value to the expected input value
+
+ do ii = 4, npixels, 4
+ boutarray(ii) = char(99)
+ ioutarray(ii) = 99
+ joutarray(ii) = 99
+ eoutarray(ii) = 99.
+ doutarray(ii) = 99.
+ end do
+
+ ii = 1
+ boutarray(ii) = char(99)
+ ioutarray(ii) = 99
+ joutarray(ii) = 99
+ eoutarray(ii) = 99.
+ doutarray(ii) = 99.
+
+
+C compare the output with the input flag any differences
+ do ii = 1, npixels
+
+ if (boutarray(ii) .ne. binarray(ii))then
+ write(*,'(1x,A,2A2)') 'bout != bin ', boutarray(ii),
+ & binarray(ii)
+ end if
+
+ if (ioutarray(ii) .ne. iinarray(ii))then
+ write(*,'(1x,A,2I8)') 'bout != bin ', ioutarray(ii),
+ & iinarray(ii)
+ end if
+
+ if (joutarray(ii) .ne. jinarray(ii))then
+ write(*,'(1x,A,2I12)') 'bout != bin ', joutarray(ii),
+ & jinarray(ii)
+ end if
+
+ if (eoutarray(ii) .ne. einarray(ii))then
+ write(*,'(1x,A,2E15.3)') 'bout != bin ', eoutarray(ii),
+ & einarray(ii)
+ end if
+
+ if (doutarray(ii) .ne. dinarray(ii))then
+ write(*,'(1x,A,2D20.6)') 'bout != bin ', doutarray(ii),
+ & dinarray(ii)
+ end if
+ end do
+
+ do ii = 1, npixels
+ binarray(ii) = char(0)
+ iinarray(ii) = 0
+ jinarray(ii) = 0
+ einarray(ii) = 0.
+ dinarray(ii) = 0.
+ end do
+
+ anynull = .false.
+ call ftgpfb(iunit, 1, 1, 10, binarray, larray, anynull,status)
+ call ftgpfb(iunit, 1, 11, 10, binarray(11), larray(11),
+ & anynull, status)
+
+ do ii = 1, npixels
+ if (larray(ii))binarray(ii) = char(0)
+ end do
+
+ do ii = 1,npixels
+ iinarray(ii) = ichar(binarray(ii))
+ end do
+
+ write(*,1101)(iinarray(ii),ii = 1,npixels),anynull,' (ftgpfb)'
+
+ call ftgpfi(iunit, 1, 1, npixels, iinarray, larray, anynull,
+ & status)
+
+ do ii = 1, npixels
+ if (larray(ii))iinarray(ii) = 0
+ end do
+
+ write(*,1101)(iinarray(ii),ii = 1,npixels),anynull,' (ftgpfi)'
+
+ call ftgpfj(iunit, 1, 1, npixels, jinarray, larray, anynull,
+ & status)
+
+ do ii = 1, npixels
+ if (larray(ii))jinarray(ii) = 0
+ end do
+
+ write(*,1101)(jinarray(ii),ii = 1,npixels),anynull,' (ftgpfj)'
+
+ call ftgpfe(iunit, 1, 1, npixels, einarray, larray, anynull,
+ & status)
+
+ do ii = 1, npixels
+ if (larray(ii))einarray(ii) = 0.
+ end do
+
+ write(*,1102)(einarray(ii),ii = 1,npixels),anynull,' (ftgpfe)'
+
+ call ftgpfd(iunit, 1, 1, 10, dinarray, larray, anynull,status)
+ call ftgpfd(iunit, 1, 11, 10, dinarray(11), larray(11),
+ & anynull, status)
+
+ do ii = 1, npixels
+ if (larray(ii))dinarray(ii) = 0.
+ end do
+
+ write(*,1102)(dinarray(ii),ii = 1,npixels),anynull,' (ftgpfd)'
+
+ if (status .gt. 0)then
+ write(*,'(1x,A,I4)')'ERROR: ftgpf_ status = ', status
+ go to 999
+ end if
+
+ if (.not. anynull)then
+ write(*,'(1x,A)') 'ERROR: ftgpf_ did not detect null values'
+ go to 999
+ end if
+
+
+C ##########################################
+C # close and reopen file multiple times #
+C ##########################################
+
+
+ do ii = 1, 10
+ call ftclos(iunit, status)
+
+ if (status .gt. 0)then
+ write(*,'(1x,A,I4)')'ERROR in ftclos (1) = ', status
+ go to 999
+ end if
+
+ call ftopen(iunit, filename, 1, block, status)
+
+ if (status .gt. 0)then
+ write(*,'(1x,A,I4)')'ERROR: ftopen open file status = ',
+ & status
+ go to 999
+ end if
+ end do
+
+ write(*,'(1x,A)') ' '
+ write(*,'(1x,A)') 'Closed then reopened the FITS file 10 times.'
+ write(*,'(1x,A)')' '
+
+ call ftghdn(iunit, hdunum)
+ write(*,'(1x,A,I4)')'HDU number = ', hdunum
+
+
+C ############################
+C # read single keywords #
+C ############################
+
+
+ simple = .false.
+ bitpix = 0
+ naxis = 0
+ naxes(1) = 0
+ naxes(2) = 0
+ pcount = -99
+ gcount = -99
+ extend = .false.
+ write(*,'(1x,A)') 'Read back keywords: '
+ call ftghpr(iunit, 3, simple, bitpix, naxis, naxes, pcount,
+ & gcount, extend, status)
+ write(*,'(1x,A,L4,4I4)')'simple, bitpix, naxis, naxes = ',
+ & simple, bitpix, naxis, naxes(1), naxes(2)
+ write(*,'(1x,A,2I4,L4)')' pcount, gcount, extend = ',
+ & pcount, gcount, extend
+
+ call ftgrec(iunit, 9, card, status)
+ write(*,'(1x,A)') card
+ if (card(1:15) .ne. 'KEY_PREC= ''This')
+ & write(*,'(1x,A)') 'ERROR in ftgrec '
+
+ call ftgkyn(iunit, 9, keyword, value, comment, status)
+ write(*,'(1x,5A)') keyword,' ', value(1:35),' ', comment(1:20)
+
+ if (keyword(1:8) .ne. 'KEY_PREC' )
+ & write(*,'(1x,2A)') 'ERROR in ftgkyn: ', keyword
+
+ call ftgcrd(iunit, keyword, card, status)
+ write(*,'(1x,A)') card
+
+ if (keyword(1:8) .ne. card(1:8) )
+ & write(*,'(1x,2A)') 'ERROR in ftgcrd: ', keyword
+
+ call ftgkey(iunit, 'KY_PKNS1', value, comment, status)
+ write(*,'(1x,5A)') 'KY_PKNS1 ',':', value(1:15),':', comment(1:16)
+
+ if (value(1:14) .ne. '''first string''')
+ & write(*,'(1x,2A)') 'ERROR in ftgkey: ', value
+
+ call ftgkys(iunit, 'key_pkys', iskey, comment, status)
+ write(*,'(1x,5A,I4)')'KEY_PKYS ',':',iskey,':',comment(1:16),
+ & status
+
+ call ftgkyl(iunit, 'key_pkyl', ilkey, comment, status)
+ write(*,'(1x,2A,L4,2A,I4)') 'KEY_PKYL ',':', ilkey,':',
+ &comment(1:16), status
+
+ call ftgkyj(iunit, 'KEY_PKYJ', ijkey, comment, status)
+ write(*,'(1x,2A,I4,2A,I4)') 'KEY_PKYJ ',':',ijkey,':',
+ & comment(1:16), status
+
+ call ftgkye(iunit, 'KEY_PKYJ', iekey, comment, status)
+ write(*,'(1x,2A,f12.5,2A,I4)') 'KEY_PKYE ',':',iekey,':',
+ & comment(1:16), status
+
+ call ftgkyd(iunit, 'KEY_PKYJ', idkey, comment, status)
+ write(*,'(1x,2A,F12.5,2A,I4)') 'KEY_PKYD ',':',idkey,':',
+ & comment(1:16), status
+
+ if (ijkey .ne. 11 .or. iekey .ne. 11. .or. idkey .ne. 11.)
+ & write(*,'(1x,A,I4,2F5.1)') 'ERROR in ftgky(jed): ',
+ & ijkey, iekey, idkey
+
+ iskey= ' '
+ call ftgkys(iunit, 'key_pkys', iskey, comment, status)
+ write(*,'(1x,5A,I4)') 'KEY_PKYS ',':', iskey,':', comment(1:16),
+ & status
+
+ ilkey = .false.
+ call ftgkyl(iunit, 'key_pkyl', ilkey, comment, status)
+ write(*,'(1x,2A,L4,2A,I4)') 'KEY_PKYL ',':', ilkey,':',
+ & comment(1:16), status
+
+ ijkey = 0
+ call ftgkyj(iunit, 'KEY_PKYJ', ijkey, comment, status)
+ write(*,'(1x,2A,I4,2A,I4)') 'KEY_PKYJ ',':',ijkey,':',
+ & comment(1:16), status
+
+ iekey = 0
+ call ftgkye(iunit, 'KEY_PKYE', iekey, comment, status)
+ write(*,'(1x,2A,f12.5,2A,I4)') 'KEY_PKYE ',':',iekey,':',
+ & comment(1:16), status
+
+ idkey = 0
+ call ftgkyd(iunit, 'KEY_PKYD', idkey, comment, status)
+ write(*,'(1x,2A,F12.5,2A,I4)') 'KEY_PKYD ',':',idkey,':',
+ & comment(1:16), status
+
+ iekey = 0
+ call ftgkye(iunit, 'KEY_PKYF', iekey, comment, status)
+ write(*,'(1x,2A,f12.5,2A,I4)') 'KEY_PKYF ',':',iekey,':',
+ & comment(1:16), status
+
+ iekey = 0
+ call ftgkye(iunit, 'KEY_PKYE', iekey, comment, status)
+ write(*,'(1x,2A,f12.5,2A,I4)') 'KEY_PKYE ',':',iekey,':',
+ & comment(1:16), status
+
+ idkey = 0
+ call ftgkyd(iunit, 'KEY_PKYG', idkey, comment, status)
+ write(*,'(1x,2A,f16.12,2A,I4)') 'KEY_PKYG ',':',idkey,':',
+ & comment(1:16), status
+
+ idkey = 0
+ call ftgkyd(iunit, 'KEY_PKYD', idkey, comment, status)
+ write(*,'(1x,2A,f16.12,2A,I4)') 'KEY_PKYD ',':',idkey,':',
+ & comment(1:16), status
+
+ call ftgkyt(iunit, 'KEY_PKYT', ijkey, idkey, comment, status)
+ write(*,'(1x,2A,i10,A,f16.14,A,I4)') 'KEY_PKYT ',':',
+ & ijkey,':', idkey, comment(1:16), status
+
+ call ftpunt(iunit, 'KEY_PKYJ', 'km/s/Mpc', status)
+ ijkey = 0
+ call ftgkyj(iunit, 'KEY_PKYJ', ijkey, comment, status)
+ write(*,'(1x,2A,I4,2A,I4)') 'KEY_PKYJ ',':',ijkey,':',
+ & comment(1:38), status
+ call ftgunt(iunit,'KEY_PKYJ',kunit,status)
+ write(*,'(1x,2A)') 'keyword unit=', kunit
+
+ call ftpunt(iunit, 'KEY_PKYJ', ' ', status)
+ ijkey = 0
+ call ftgkyj(iunit, 'KEY_PKYJ', ijkey, comment, status)
+ write(*,'(1x,2A,I4,2A,I4)') 'KEY_PKYJ ',':',ijkey,':',
+ & comment(1:38), status
+ call ftgunt(iunit,'KEY_PKYJ',kunit,status)
+ write(*,'(1x,2A)') 'keyword unit=', kunit
+
+ call ftpunt(iunit, 'KEY_PKYJ', 'feet/second/second', status)
+ ijkey = 0
+ call ftgkyj(iunit, 'KEY_PKYJ', ijkey, comment, status)
+ write(*,'(1x,2A,I4,2A,I4)') 'KEY_PKYJ ',':',ijkey,':',
+ & comment(1:38), status
+ call ftgunt(iunit,'KEY_PKYJ',kunit,status)
+ write(*,'(1x,2A)') 'keyword unit=', kunit
+
+ call ftgkys(iunit, 'key_pkls', lstr, comment, status)
+ write(*,'(1x,2A)') 'KEY_PKLS long string value = ', lstr(1:50)
+ write(*,'(1x,A)')lstr(51:120)
+
+C get size and position in header
+ call ftghps(iunit, existkeys, keynum, status)
+ write(*,'(1x,A,I4,A,I4)') 'header contains ', existkeys,
+ & ' keywords; located at keyword ', keynum
+
+C ############################
+C # read array keywords #
+C ############################
+
+ call ftgkns(iunit, 'ky_pkns', 1, 3, inskey, nfound, status)
+ write(*,'(1x,4A)') 'ftgkns: ', inskey(1)(1:14), inskey(2)(1:14),
+ & inskey(3)(1:14)
+ if (nfound .ne. 3 .or. status .gt. 0)
+ & write(*,'(1x,A,2I4)') ' ERROR in ftgkns ', nfound, status
+
+ call ftgknl(iunit, 'ky_pknl', 1, 3, inlkey, nfound, status)
+ write(*,'(1x,A,3L4)') 'ftgknl: ', inlkey(1), inlkey(2), inlkey(3)
+ if (nfound .ne. 3 .or. status .gt. 0)
+ & write(*,'(1x,A,2I4)') ' ERROR in ftgknl ', nfound, status
+
+ call ftgknj(iunit, 'ky_pknj', 1, 3, injkey, nfound, status)
+ write(*,'(1x,A,3I4)') 'ftgknj: ', injkey(1), injkey(2), injkey(3)
+ if (nfound .ne. 3 .or. status .gt. 0)
+ & write(*,'(1x,A,2I4)') ' ERROR in ftgknj ', nfound, status
+
+ call ftgkne(iunit, 'ky_pkne', 1, 3, inekey, nfound, status)
+ write(*,'(1x,A,3F10.5)') 'ftgkne: ',inekey(1),inekey(2),inekey(3)
+ if (nfound .ne. 3 .or. status .gt. 0)
+ & write(*,'(1x,A,2I4)') ' ERROR in ftgkne ', nfound, status
+
+ call ftgknd(iunit, 'ky_pknd', 1, 3, indkey, nfound, status)
+ write(*,'(1x,A,3F10.5)') 'ftgknd: ',indkey(1),indkey(2),indkey(3)
+ if (nfound .ne. 3 .or. status .gt. 0)
+ & write(*,'(1x,A,2I4)') ' ERROR in ftgknd ', nfound, status
+
+ write(*,'(1x,A)')' '
+ write(*,'(1x,A)')
+ & 'Before deleting the HISTORY and DATE keywords...'
+ do ii = 29, 32
+ call ftgrec(iunit, ii, card, status)
+ write(*,'(1x,A)') card(1:8)
+ end do
+
+C don't print date value, so that
+C the output will always be the same
+
+
+C ############################
+C # delete keywords #
+C ############################
+
+
+ call ftdrec(iunit, 30, status)
+ call ftdkey(iunit, 'DATE', status)
+
+ write(*,'(1x,A)')' '
+ write(*,'(1x,A)') 'After deleting the keywords... '
+ do ii = 29, 30
+ call ftgrec(iunit, ii, card, status)
+ write(*,'(1x,A)') card
+ end do
+
+ if (status .gt. 0)
+ & write(*,'(1x,A)') ' ERROR deleting keywords '
+
+
+C ############################
+C # insert keywords #
+C ############################
+
+ call ftirec(iunit,26,
+ & 'KY_IREC = ''This keyword inserted by fxirec''',
+ & status)
+ call ftikys(iunit, 'KY_IKYS', 'insert_value_string',
+ & 'ikys comment', status)
+ call ftikyj(iunit, 'KY_IKYJ', 49, 'ikyj comment', status)
+ call ftikyl(iunit, 'KY_IKYL', .true., 'ikyl comment', status)
+ call ftikye(iunit, 'KY_IKYE',12.3456,4,'ikye comment',status)
+ odkey = 12.345678901234567D+00
+ call ftikyd(iunit, 'KY_IKYD', odkey, 14,
+ & 'ikyd comment', status)
+ call ftikyf(iunit, 'KY_IKYF', 12.3456, 4, 'ikyf comment',
+ & status)
+ call ftikyg(iunit, 'KY_IKYG', odkey, 13,
+ & 'ikyg comment', status)
+
+ write(*,'(1x,A)')' '
+ write(*,'(1x,A)') 'After inserting the keywords... '
+ do ii = 25, 34
+ call ftgrec(iunit, ii, card, status)
+ write(*,'(1x,A)') card
+ end do
+
+ if (status .gt. 0)
+ & write(*,'(1x,A)') ' ERROR inserting keywords '
+
+
+C ############################
+C # modify keywords #
+C ############################
+
+ call ftmrec(iunit, 25,
+ & 'COMMENT This keyword was modified by fxmrec', status)
+ call ftmcrd(iunit, 'KY_IREC',
+ & 'KY_MREC = ''This keyword was modified by fxmcrd''', status)
+ call ftmnam(iunit, 'KY_IKYS', 'NEWIKYS', status)
+
+ call ftmcom(iunit,'KY_IKYJ','This is a modified comment',
+ & status)
+ call ftmkyj(iunit, 'KY_IKYJ', 50, '&', status)
+ call ftmkyl(iunit, 'KY_IKYL', .false., '&', status)
+ call ftmkys(iunit, 'NEWIKYS', 'modified_string', '&', status)
+ call ftmkye(iunit, 'KY_IKYE', -12.3456, 4, '&', status)
+ odkey = -12.345678901234567D+00
+
+ call ftmkyd(iunit, 'KY_IKYD', odkey, 14,
+ & 'modified comment', status)
+ call ftmkyf(iunit, 'KY_IKYF', -12.3456, 4, '&', status)
+ call ftmkyg(iunit,'KY_IKYG', odkey,13,'&',status)
+
+ write(*,'(1x,A)')' '
+ write(*,'(1x,A)') 'After modifying the keywords... '
+ do ii = 25, 34
+ call ftgrec(iunit, ii, card, status)
+ write(*,'(1x,A)') card
+ end do
+
+ if (status .gt. 0)then
+ write(*,'(1x,A)') ' ERROR modifying keywords '
+ go to 999
+ end if
+
+C ############################
+C # update keywords #
+C ############################
+
+ call ftucrd(iunit, 'KY_MREC',
+ & 'KY_UCRD = ''This keyword was updated by fxucrd''',
+ & status)
+
+ call ftukyj(iunit, 'KY_IKYJ', 51, '&', status)
+ call ftukyl(iunit, 'KY_IKYL', .true., '&', status)
+ call ftukys(iunit, 'NEWIKYS', 'updated_string', '&', status)
+ call ftukye(iunit, 'KY_IKYE', -13.3456, 4, '&', status)
+ odkey = -13.345678901234567D+00
+
+ call ftukyd(iunit, 'KY_IKYD',odkey , 14,
+ & 'modified comment', status)
+ call ftukyf(iunit, 'KY_IKYF', -13.3456, 4, '&', status)
+ call ftukyg(iunit, 'KY_IKYG', odkey, 13, '&', status)
+
+ write(*,'(1x,A)')' '
+ write(*,'(1x,A)') 'After updating the keywords... '
+ do ii = 25, 34
+ call ftgrec(iunit, ii, card, status)
+ write(*,'(1x,A)') card
+ end do
+
+ if (status .gt. 0)then
+ write(*,'(1x,A)') ' ERROR modifying keywords '
+ go to 999
+ end if
+
+C move to top of header and find keywords using wild cards
+ call ftgrec(iunit, 0, card, status)
+
+ write(*,'(1x,A)')' '
+ write(*,'(1x,A)')
+ & 'Keywords found using wildcard search (should be 9)...'
+ nfound = -1
+91 nfound = nfound +1
+ call ftgnxk(iunit, inclist, 2, exclist, 2, card, status)
+ if (status .eq. 0)then
+ write(*,'(1x,A)') card
+ go to 91
+ end if
+
+ if (nfound .ne. 9)then
+ write(*,'(1x,A)')
+ & 'ERROR reading keywords using wildcards (ftgnxk)'
+ go to 999
+ end if
+ status = 0
+
+C ############################
+C # create binary table #
+C ############################
+
+ tform(1) = '15A'
+ tform(2) = '1L'
+ tform(3) = '16X'
+ tform(4) = '1B'
+ tform(5) = '1I'
+ tform(6) = '1J'
+ tform(7) = '1E'
+ tform(8) = '1D'
+ tform(9) = '1C'
+ tform(10)= '1M'
+
+ ttype(1) = 'Avalue'
+ ttype(2) = 'Lvalue'
+ ttype(3) = 'Xvalue'
+ ttype(4) = 'Bvalue'
+ ttype(5) = 'Ivalue'
+ ttype(6) = 'Jvalue'
+ ttype(7) = 'Evalue'
+ ttype(8) = 'Dvalue'
+ ttype(9) = 'Cvalue'
+ ttype(10)= 'Mvalue'
+
+ tunit(1) = ' '
+ tunit(2) = 'm**2'
+ tunit(3) = 'cm'
+ tunit(4) = 'erg/s'
+ tunit(5) = 'km/s'
+ tunit(6) = ' '
+ tunit(7) = ' '
+ tunit(8) = ' '
+ tunit(9) = ' '
+ tunit(10)= ' '
+
+ nrows = 21
+ tfields = 10
+ pcount = 0
+
+ call ftibin(iunit, nrows, tfields, ttype, tform, tunit,
+ & binname, pcount, status)
+ write(*,'(1x,A)')' '
+ write(*,'(1x,A,I4)') 'ftibin status = ', status
+ call ftghdn(iunit, hdunum)
+ write(*,'(1x,A,I4)') 'HDU number = ', hdunum
+
+C get size and position in header, and reserve space for more keywords
+ call ftghps(iunit, existkeys, keynum, status)
+ write(*,'(1x,A,I4,A,I4)') 'header contains ',existkeys,
+ & ' keywords located at keyword ', keynum
+
+ morekeys = 40
+ call fthdef(iunit, morekeys, status)
+ call ftghsp(iunit, existkeys, morekeys, status)
+ write(*,'(1x,A,I4,A,I4,A)') 'header contains ', existkeys,
+ &' keywords with room for ', morekeys,' more'
+
+C define null value for int cols
+ call fttnul(iunit, 4, 99, status)
+ call fttnul(iunit, 5, 99, status)
+ call fttnul(iunit, 6, 99, status)
+
+ call ftpkyj(iunit, 'TNULL4', 99, 'value for undefined pixels',
+ & status)
+ call ftpkyj(iunit, 'TNULL5', 99, 'value for undefined pixels',
+ & status)
+ call ftpkyj(iunit, 'TNULL6', 99, 'value for undefined pixels',
+ & status)
+
+ naxis = 3
+ naxes(1) = 1
+ naxes(2) = 2
+ naxes(3) = 8
+ call ftptdm(iunit, 3, naxis, naxes, status)
+
+ naxis = 0
+ naxes(1) = 0
+ naxes(2) = 0
+ naxes(3) = 0
+ call ftgtdm(iunit, 3, 3, naxis, naxes, status)
+ call ftgkys(iunit, 'TDIM3', iskey, comment, status)
+ write(*,'(1x,2A,4I4)') 'TDIM3 = ', iskey, naxis, naxes(1),
+ & naxes(2), naxes(3)
+
+C force header to be scanned (not required)
+ call ftrdef(iunit, status)
+
+C ############################
+C # write data to columns #
+C ############################
+
+C initialize arrays of values to write to table
+ signval = -1
+ do ii = 1, 21
+ signval = signval * (-1)
+ boutarray(ii) = char(ii)
+ ioutarray(ii) = (ii) * signval
+ joutarray(ii) = (ii) * signval
+ koutarray(ii) = (ii) * signval
+ eoutarray(ii) = (ii) * signval
+ doutarray(ii) = (ii) * signval
+ end do
+
+ call ftpcls(iunit, 1, 1, 1, 3, onskey, status)
+C write string values
+ call ftpclu(iunit, 1, 4, 1, 1, status)
+C write null value
+
+ larray(1) = .false.
+ larray(2) =.true.
+ larray(3) = .false.
+ larray(4) = .false.
+ larray(5) =.true.
+ larray(6) =.true.
+ larray(7) = .false.
+ larray(8) = .false.
+ larray(9) = .false.
+ larray(10) =.true.
+ larray(11) =.true.
+ larray(12) = .true.
+ larray(13) = .false.
+ larray(14) = .false.
+ larray(15) =.false.
+ larray(16) =.false.
+ larray(17) = .true.
+ larray(18) = .true.
+ larray(19) = .true.
+ larray(20) = .true.
+ larray(21) =.false.
+ larray(22) =.false.
+ larray(23) =.false.
+ larray(24) =.false.
+ larray(25) =.false.
+ larray(26) = .true.
+ larray(27) = .true.
+ larray(28) = .true.
+ larray(29) = .true.
+ larray(30) = .true.
+ larray(31) =.false.
+ larray(32) =.false.
+ larray(33) =.false.
+ larray(34) =.false.
+ larray(35) =.false.
+ larray(36) =.false.
+
+C write bits
+ call ftpclx(iunit, 3, 1, 1, 36, larray, status)
+
+C loop over cols 4 - 8
+ do ii = 4, 8
+ call ftpclb(iunit, ii, 1, 1, 2, boutarray, status)
+ if (status .eq. 412) status = 0
+
+ call ftpcli(iunit, ii, 3, 1, 2, ioutarray(3), status)
+ if (status .eq. 412) status = 0
+
+ call ftpclj(iunit, ii, 5, 1, 2, koutarray(5), status)
+ if (status .eq. 412) status = 0
+
+ call ftpcle(iunit, ii, 7, 1, 2, eoutarray(7), status)
+ if (status .eq. 412)status = 0
+
+ call ftpcld(iunit, ii, 9, 1, 2, doutarray(9), status)
+ if (status .eq. 412)status = 0
+
+C write null value
+ call ftpclu(iunit, ii, 11, 1, 1, status)
+ end do
+
+ call ftpclc(iunit, 9, 1, 1, 10, eoutarray, status)
+ call ftpclm(iunit, 10, 1, 1, 10, doutarray, status)
+
+C loop over cols 4 - 8
+ do ii = 4, 8
+ bnul = char(13)
+ call ftpcnb(iunit, ii, 12, 1, 2, boutarray(12),bnul,status)
+ if (status .eq. 412) status = 0
+ inul=15
+ call ftpcni(iunit, ii, 14, 1, 2, ioutarray(14),inul,status)
+ if (status .eq. 412) status = 0
+ call ftpcnj(iunit, ii, 16, 1, 2, koutarray(16), 17, status)
+ if (status .eq. 412) status = 0
+ call ftpcne(iunit, ii, 18, 1, 2, eoutarray(18), 19.,status)
+ if (status .eq. 412) status = 0
+ dnul = 21.
+ call ftpcnd(iunit, ii, 20, 1, 2, doutarray(20),dnul,status)
+ if (status .eq. 412) status = 0
+ end do
+
+C write logicals
+ call ftpcll(iunit, 2, 1, 1, 21, larray, status)
+C write null value
+ call ftpclu(iunit, 2, 11, 1, 1, status)
+ write(*,'(1x,A,I4)') 'ftpcl_ status = ', status
+ if (status .gt. 0)go to 999
+
+C #########################################
+C # get information about the columns #
+C #########################################
+
+ write(*,'(1x,A)')' '
+ write(*,'(1x,A)')
+ & 'Find the column numbers a returned status value'//
+ & ' of 237 is'
+ write(*,'(1x,A)')
+ & 'expected and indicates that more than one column'//
+ & ' name matches'
+ write(*,'(1x,A)')'the input column name template.'//
+ & ' Status = 219 indicates that'
+ write(*,'(1x,A)') 'there was no matching column name.'
+
+ call ftgcno(iunit, 0, 'Xvalue', colnum, status)
+ write(*,'(1x,A,I4,A,I4)') 'Column Xvalue is number', colnum,
+ &' status =',status
+
+219 continue
+ if (status .ne. 219)then
+ call ftgcnn(iunit, 1, '*ue', colname, colnum, status)
+ write(*,'(1x,3A,I4,A,I4)') 'Column ',colname(1:6),' is number',
+ & colnum,' status = ', status
+ go to 219
+ end if
+
+ status = 0
+
+ write(*,'(1x,A)')' '
+ write(*,'(1x,A)') 'Information about each column: '
+
+ do ii = 1, tfields
+ call ftgtcl(iunit, ii, typecode, repeat, width, status)
+ call ftgbcl(iunit,ii,ttype,tunit,cval,repeat,scale,
+ & zero, jnulval, tdisp, status)
+
+ write(*,'(1x,A,3I4,5A,2F8.2,I12,A)')
+ & tform(ii)(1:3), typecode, repeat, width,' ',
+ & ttype(1)(1:6),' ',tunit(1)(1:6), cval, scale, zero, jnulval,
+ & tdisp(1:8)
+ end do
+
+ write(*,'(1x,A)') ' '
+
+C ###############################################
+C # insert ASCII table before the binary table #
+C ###############################################
+
+ call ftmrhd(iunit, -1, hdutype, status)
+ if (status .gt. 0)goto 999
+
+ tform(1) = 'A15'
+ tform(2) = 'I10'
+ tform(3) = 'F14.6'
+ tform(4) = 'E12.5'
+ tform(5) = 'D21.14'
+
+ ttype(1) = 'Name'
+ ttype(2) = 'Ivalue'
+ ttype(3) = 'Fvalue'
+ ttype(4) = 'Evalue'
+ ttype(5) = 'Dvalue'
+
+ tunit(1) = ' '
+ tunit(2) = 'm**2'
+ tunit(3) = 'cm'
+ tunit(4) = 'erg/s'
+ tunit(5) = 'km/s'
+
+ rowlen = 76
+ nrows = 11
+ tfields = 5
+
+ call ftitab(iunit, rowlen, nrows, tfields, ttype, tbcol,
+ & tform, tunit, tblname, status)
+ write(*,'(1x,A,I4)') 'ftitab status = ', status
+ call ftghdn(iunit, hdunum)
+ write(*,'(1x,A,I4)') 'HDU number = ', hdunum
+
+C define null value for int cols
+ call ftsnul(iunit, 1, 'null1', status)
+ call ftsnul(iunit, 2, 'null2', status)
+ call ftsnul(iunit, 3, 'null3', status)
+ call ftsnul(iunit, 4, 'null4', status)
+ call ftsnul(iunit, 5, 'null5', status)
+
+ call ftpkys(iunit, 'TNULL1', 'null1',
+ & 'value for undefined pixels', status)
+ call ftpkys(iunit, 'TNULL2', 'null2',
+ & 'value for undefined pixels', status)
+ call ftpkys(iunit, 'TNULL3', 'null3',
+ & 'value for undefined pixels', status)
+ call ftpkys(iunit, 'TNULL4', 'null4',
+ & 'value for undefined pixels', status)
+ call ftpkys(iunit, 'TNULL5', 'null5',
+ & 'value for undefined pixels', status)
+
+ if (status .gt. 0) goto 999
+
+C ############################
+C # write data to columns #
+C ############################
+
+C initialize arrays of values to write to table
+ do ii = 1,21
+ boutarray(ii) = char(ii)
+ ioutarray(ii) = ii
+ joutarray(ii) = ii
+ eoutarray(ii) = ii
+ doutarray(ii) = ii
+ end do
+
+C write string values
+ call ftpcls(iunit, 1, 1, 1, 3, onskey, status)
+C write null value
+ call ftpclu(iunit, 1, 4, 1, 1, status)
+
+ do ii = 2,5
+C loop over cols 2 - 5
+ call ftpclb(iunit, ii, 1, 1, 2, boutarray, status)
+C char array
+ if (status .eq. 412) status = 0
+
+ call ftpcli(iunit, ii, 3, 1, 2, ioutarray(3), status)
+C short array
+ if (status .eq. 412) status = 0
+
+ call ftpclj(iunit, ii, 5, 1, 2, joutarray(5), status)
+C long array
+ if (status .eq. 412)status = 0
+
+ call ftpcle(iunit, ii, 7, 1, 2, eoutarray(7), status)
+C float array
+ if (status .eq. 412) status = 0
+
+ call ftpcld(iunit, ii, 9, 1, 2, doutarray(9), status)
+C double array
+ if (status .eq. 412) status = 0
+
+ call ftpclu(iunit, ii, 11, 1, 1, status)
+C write null value
+ end do
+ write(*,'(1x,A,I4)') 'ftpcl_ status = ', status
+ write(*,'(1x,A)')' '
+
+C ################################
+C # read data from ASCII table #
+C ################################
+
+ call ftghtb(iunit, 99, rowlen, nrows, tfields, ttype, tbcol,
+ & tform, tunit, tblname, status)
+
+ write(*,'(1x,A,3I3,2A)')
+ & 'ASCII table: rowlen, nrows, tfields, extname:',
+ & rowlen, nrows, tfields,' ',tblname
+
+ do ii = 1,tfields
+ write(*,'(1x,A,I4,3A)')
+ & ttype(ii)(1:7), tbcol(ii),' ',tform(ii)(1:7), tunit(ii)(1:7)
+ end do
+
+ nrows = 11
+ call ftgcvs(iunit, 1, 1, 1, nrows, 'UNDEFINED', inskey,
+ & anynull, status)
+ bnul = char(99)
+ call ftgcvb(iunit, 2, 1, 1, nrows, bnul, binarray,
+ & anynull, status)
+ inul = 99
+ call ftgcvi(iunit, 2, 1, 1, nrows, inul, iinarray,
+ & anynull, status)
+ call ftgcvj(iunit, 3, 1, 1, nrows, 99, jinarray,
+ & anynull, status)
+ call ftgcve(iunit, 4, 1, 1, nrows, 99., einarray,
+ & anynull, status)
+ dnul = 99.
+ call ftgcvd(iunit, 5, 1, 1, nrows, dnul, dinarray,
+ & anynull, status)
+
+ write(*,'(1x,A)')' '
+ write(*,'(1x,A)') 'Data values read from ASCII table: '
+ do ii = 1, nrows
+ jj = ichar(binarray(ii))
+ write(*,1011) inskey(ii), jj,
+ & iinarray(ii), jinarray(ii), einarray(ii), dinarray(ii)
+1011 format(1x,a15,3i3,1x,2f3.0)
+ end do
+
+ call ftgtbs(iunit, 1, 20, 78, uchars, status)
+ write(*,'(1x,A)')' '
+ write(*,'(1x,A)') uchars
+ call ftptbs(iunit, 1, 20, 78, uchars, status)
+
+C #########################################
+C # get information about the columns #
+C #########################################
+
+ call ftgcno(iunit, 0, 'name', colnum, status)
+ write(*,'(1x,A)')' '
+ write(*,'(1x,A,I4,A,I4)')
+ & 'Column name is number',colnum,' status = ', status
+
+2190 continue
+ if (status .ne. 219)then
+ if (status .gt. 0 .and. status .ne. 237)go to 999
+
+ call ftgcnn(iunit, 1, '*ue', colname, colnum, status)
+ write(*,'(1x,3A,I4,A,I4)')
+ & 'Column ',colname(1:6),' is number',colnum,' status = ',status
+ go to 2190
+ end if
+
+ status = 0
+
+ do ii = 1, tfields
+ call ftgtcl(iunit, ii, typecode, repeat, width, status)
+ call ftgacl(iunit, ii, ttype, tbcol,tunit,tform,
+ & scale,zero, nulstr, tdisp, status)
+
+ write(*,'(1x,A,3I4,2A,I4,2A,2F10.2,3A)')
+ & tform(ii)(1:7), typecode, repeat, width,' ',
+ & ttype(1)(1:6), tbcol(1), ' ',tunit(1)(1:5),
+ & scale, zero, ' ', nulstr(1:6), tdisp(1:2)
+
+ end do
+
+ write(*,'(1x,A)') ' '
+
+C ###############################################
+C # test the insert/delete row/column routines #
+C ###############################################
+
+ call ftirow(iunit, 2, 3, status)
+ if (status .gt. 0) goto 999
+
+ nrows = 14
+ call ftgcvs(iunit, 1, 1, 1, nrows, 'UNDEFINED',
+ & inskey, anynull, status)
+ call ftgcvb(iunit, 2, 1, 1, nrows, bnul, binarray,
+ & anynull, status)
+ call ftgcvi(iunit, 2, 1, 1, nrows, inul, iinarray,
+ & anynull, status)
+ call ftgcvj(iunit, 3, 1, 1, nrows, 99, jinarray,
+ & anynull, status)
+ call ftgcve(iunit, 4, 1, 1, nrows, 99., einarray,
+ & anynull, status)
+ call ftgcvd(iunit, 5, 1, 1, nrows, dnul, dinarray,
+ & anynull, status)
+
+ write(*,'(1x,A)')' '
+ write(*,'(1x,A)')'Data values after inserting 3 rows after row 2:'
+ do ii = 1, nrows
+ jj = ichar(binarray(ii))
+ write(*,1011) inskey(ii), jj,
+ & iinarray(ii), jinarray(ii), einarray(ii), dinarray(ii)
+ end do
+
+ call ftdrow(iunit, 10, 2, status)
+
+ nrows = 12
+ call ftgcvs(iunit, 1, 1, 1, nrows, 'UNDEFINED', inskey,
+ & anynull, status)
+ call ftgcvb(iunit, 2, 1, 1, nrows, bnul, binarray, anynull,
+ & status)
+ call ftgcvi(iunit, 2, 1, 1, nrows, inul, iinarray, anynull,
+ & status)
+ call ftgcvj(iunit, 3, 1, 1, nrows, 99, jinarray, anynull,
+ & status)
+ call ftgcve(iunit, 4, 1, 1, nrows, 99., einarray, anynull,
+ & status)
+ call ftgcvd(iunit, 5, 1, 1, nrows, dnul, dinarray, anynull,
+ & status)
+
+ write(*,'(1x,A)')' '
+ write(*,'(1x,A)') 'Data values after deleting 2 rows at row 10: '
+ do ii = 1, nrows
+ jj = ichar(binarray(ii))
+ write(*,1011) inskey(ii), jj,
+ & iinarray(ii), jinarray(ii), einarray(ii), dinarray(ii)
+ end do
+ call ftdcol(iunit, 3, status)
+
+ call ftgcvs(iunit, 1, 1, 1, nrows, 'UNDEFINED', inskey,
+ & anynull, status)
+ call ftgcvb(iunit, 2, 1, 1, nrows, bnul, binarray, anynull,
+ & status)
+ call ftgcvi(iunit, 2, 1, 1, nrows, inul, iinarray, anynull,
+ & status)
+ call ftgcve(iunit, 3, 1, 1, nrows, 99., einarray, anynull,
+ & status)
+ call ftgcvd(iunit, 4, 1, 1, nrows, dnul, dinarray, anynull,
+ & status)
+
+ write(*,'(1x,A)')' '
+ write(*,'(1x,A)') 'Data values after deleting column 3: '
+ do ii = 1,nrows
+ jj = ichar(binarray(ii))
+ write(*,1012) inskey(ii), jj,
+ & iinarray(ii), einarray(ii), dinarray(ii)
+1012 format(1x,a15,2i3,1x,2f3.0)
+
+ end do
+
+ call fticol(iunit, 5, 'INSERT_COL', 'F14.6', status)
+
+ call ftgcvs(iunit, 1, 1, 1, nrows, 'UNDEFINED', inskey,
+ & anynull, status)
+ call ftgcvb(iunit, 2, 1, 1, nrows, bnul, binarray, anynull,
+ & status)
+ call ftgcvi(iunit, 2, 1, 1, nrows, inul, iinarray, anynull,
+ & status)
+ call ftgcve(iunit, 3, 1, 1, nrows, 99., einarray, anynull,
+ & status)
+ call ftgcvd(iunit, 4, 1, 1, nrows, dnul, dinarray, anynull,
+ & status)
+ call ftgcvj(iunit, 5, 1, 1, nrows, 99, jinarray, anynull,
+ & status)
+
+ write(*,'(1x,A)')' '
+ write(*,'(1x,A)') ' Data values after inserting column 5: '
+ do ii = 1, nrows
+ jj = ichar(binarray(ii))
+ write(*,1013) inskey(ii), jj,
+ & iinarray(ii), einarray(ii), dinarray(ii) , jinarray(ii)
+1013 format(1x,a15,2i3,1x,2f3.0,i2)
+
+ end do
+
+C ################################
+C # read data from binary table #
+C ################################
+
+
+ call ftmrhd(iunit, 1, hdutype, status)
+ if (status .gt. 0)go to 999
+ call ftghdn(iunit, hdunum)
+ write(*,'(1x,A,I4)') 'HDU number = ', hdunum
+
+ call ftghsp(iunit, existkeys, morekeys, status)
+ write(*,'(1x,A)')' '
+ write(*,'(1x,A)')'Moved to binary table'
+ write(*,'(1x,A,I4,A,I4,A)') 'header contains ',existkeys,
+ & ' keywords with room for ',morekeys,' more '
+
+ call ftghbn(iunit, 99, nrows, tfields, ttype,
+ & tform, tunit, binname, pcount, status)
+
+ write(*,'(1x,A)')' '
+ write(*,'(1x,A,2I4,A,I4)')
+ & 'Binary table: nrows, tfields, extname, pcount:',
+ & nrows, tfields, binname, pcount
+
+ do ii = 1,tfields
+ write(*,'(1x,3A)') ttype(ii), tform(ii), tunit(ii)
+ end do
+
+ do ii = 1, 40
+ larray(ii) = .false.
+ end do
+
+ write(*,'(1x,A)')' '
+ write(*,'(1x,A)') 'Data values read from binary table: '
+ write(*,'(1x,A)') ' Bit column (X) data values: '
+
+ call ftgcx(iunit, 3, 1, 1, 36, larray, status)
+ write(*,1014) (larray(ii), ii = 1,40)
+1014 format(1x,8l1,' ',8l1,' ',8l1,' ',8l1,' ',8l1)
+
+ nrows = 21
+ do ii = 1, nrows
+ larray(ii) = .false.
+ xinarray(ii) = ' '
+ binarray(ii) = ' '
+ iinarray(ii) = 0
+ kinarray(ii) = 0
+ einarray(ii) = 0.
+ dinarray(ii) = 0.
+ cinarray(ii * 2 -1) = 0.
+ minarray(ii * 2 -1) = 0.
+ cinarray(ii * 2 ) = 0.
+ minarray(ii * 2 ) = 0.
+ end do
+
+ write(*,'(1x,A)') ' '
+ call ftgcvs(iunit, 1, 4, 1, 1, ' ', inskey, anynull,status)
+ if (ichar(inskey(1)(1:1)) .eq. 0)inskey(1)=' '
+ write(*,'(1x,2A)') 'null string column value (should be blank):',
+ & inskey(1)
+
+ call ftgcvs(iunit, 1, 1, 1, nrows, 'NOT DEFINED', inskey,
+ & anynull, status)
+ call ftgcl( iunit, 2, 1, 1, nrows, larray, status)
+ bnul = char(98)
+ call ftgcvb(iunit, 3, 1, 1,nrows,bnul, xinarray,anynull,status)
+ call ftgcvb(iunit, 4, 1, 1,nrows,bnul, binarray,anynull,status)
+ inul = 98
+ call ftgcvi(iunit, 5, 1, 1,nrows,inul, iinarray,anynull,status)
+ call ftgcvj(iunit, 6, 1, 1, nrows, 98, kinarray,anynull,status)
+ call ftgcve(iunit, 7, 1, 1, nrows, 98.,einarray,anynull,status)
+ dnul = 98.
+ call ftgcvd(iunit, 8, 1, 1, nrows,dnul,dinarray,anynull,status)
+ call ftgcvc(iunit, 9, 1, 1, nrows, 98.,cinarray,anynull,status)
+ call ftgcvm(iunit,10, 1, 1, nrows,dnul,minarray,anynull,status)
+
+ write(*,'(1x,A)')' '
+ write(*,'(1x,A)') 'Read columns with ftgcv_: '
+ do ii = 1,nrows
+ jj = ichar(xinarray(ii))
+ jjj = ichar(binarray(ii))
+ write(*,1201)inskey(ii),larray(ii),jj,jjj,iinarray(ii),
+ & kinarray(ii), einarray(ii), dinarray(ii), cinarray(ii * 2 -1),
+ &cinarray(ii * 2 ), minarray(ii * 2 -1), minarray(ii * 2 )
+ end do
+1201 format(1x,a14,l4,4i4,6f5.0)
+
+ do ii = 1, nrows
+ larray(ii) = .false.
+ xinarray(ii) = ' '
+ binarray(ii) = ' '
+ iinarray(ii) = 0
+ kinarray(ii) = 0
+ einarray(ii) = 0.
+ dinarray(ii) = 0.
+ cinarray(ii * 2 -1) = 0.
+ minarray(ii * 2 -1) = 0.
+ cinarray(ii * 2 ) = 0.
+ minarray(ii * 2 ) = 0.
+ end do
+
+ call ftgcfs(iunit, 1, 1, 1, nrows, inskey, larray2, anynull,
+ & status)
+C put blanks in strings if they are undefined. (contain nulls)
+ do ii = 1, nrows
+ if (larray2(ii))inskey(ii) = ' '
+ end do
+
+ call ftgcfl(iunit, 2, 1, 1, nrows, larray, larray2, anynull,
+ & status)
+ call ftgcfb(iunit, 3, 1, 1, nrows, xinarray, larray2, anynull,
+ & status)
+ call ftgcfb(iunit, 4, 1, 1, nrows, binarray, larray2, anynull,
+ & status)
+ call ftgcfi(iunit, 5, 1, 1, nrows, iinarray, larray2, anynull,
+ & status)
+ call ftgcfj(iunit, 6, 1, 1, nrows, kinarray, larray2, anynull,
+ & status)
+ call ftgcfe(iunit, 7, 1, 1, nrows, einarray, larray2, anynull,
+ & status)
+ call ftgcfd(iunit, 8, 1, 1, nrows, dinarray, larray2, anynull,
+ & status)
+ call ftgcfc(iunit, 9, 1, 1, nrows, cinarray, larray2, anynull,
+ & status)
+ call ftgcfm(iunit, 10,1, 1, nrows, minarray, larray2, anynull,
+ & status)
+
+ write(*,'(1x,A)')' '
+ write(*,'(1x,A)') ' Read columns with ftgcf_: '
+ do ii = 1, 10
+ jj = ichar(xinarray(ii))
+ jjj = ichar(binarray(ii))
+ write(*,1201)
+ & inskey(ii),larray(ii),jj,jjj,iinarray(ii),
+ & kinarray(ii), einarray(ii), dinarray(ii), cinarray(ii * 2 -1),
+ & cinarray(ii * 2 ), minarray(ii * 2 -1), minarray(ii * 2)
+ end do
+
+ do ii = 11, 21
+C don't try to print the NaN values
+ jj = ichar(xinarray(ii))
+ jjj = ichar(binarray(ii))
+ write(*,1201) inskey(ii), larray(ii), jj,
+ & jjj, iinarray(ii)
+ end do
+
+ call ftprec(iunit,'key_prec= '//
+ &'''This keyword was written by f_prec'' / comment here',
+ & status)
+
+C ###############################################
+C # test the insert/delete row/column routines #
+C ###############################################
+
+ call ftirow(iunit, 2, 3, status)
+ if (status .gt. 0) go to 999
+
+ nrows = 14
+ call ftgcvs(iunit, 1, 1, 1, nrows, 'NOT DEFINED', inskey,
+ & anynull, status)
+ call ftgcvb(iunit, 4, 1, 1, nrows,bnul,binarray,anynull,status)
+ call ftgcvi(iunit, 5, 1, 1, nrows,inul,iinarray,anynull,status)
+ call ftgcvj(iunit, 6, 1, 1, nrows, 98, jinarray,anynull,status)
+ call ftgcve(iunit, 7, 1, 1, nrows, 98.,einarray,anynull,status)
+ call ftgcvd(iunit, 8, 1, 1, nrows,dnul,dinarray,anynull,status)
+
+ write(*,'(1x,A)')' '
+ write(*,'(1x,A)')'Data values after inserting 3 rows after row 2:'
+ do ii = 1, nrows
+ jj = ichar(binarray(ii))
+ write(*,1202) inskey(ii), jj,
+ & iinarray(ii), jinarray(ii), einarray(ii), dinarray(ii)
+ end do
+1202 format(1x,a14,3i4,2f5.0)
+
+ call ftdrow(iunit, 10, 2, status)
+ if (status .gt. 0)goto 999
+
+ nrows = 12
+ call ftgcvs(iunit, 1, 1, 1, nrows, 'NOT DEFINED', inskey,
+ & anynull, status)
+ call ftgcvb(iunit, 4, 1, 1, nrows,bnul,binarray,anynull,status)
+ call ftgcvi(iunit, 5, 1, 1, nrows,inul,iinarray,anynull,status)
+ call ftgcvj(iunit, 6, 1, 1, nrows, 98,jinarray,anynull,status)
+ call ftgcve(iunit, 7, 1, 1, nrows, 98.,einarray,anynull,status)
+ call ftgcvd(iunit, 8, 1, 1, nrows,dnul,dinarray,anynull,status)
+
+ write(*,'(1x,A)')' '
+ write(*,'(1x,A)') 'Data values after deleting 2 rows at row 10: '
+ do ii = 1, nrows
+ jj = ichar(binarray(ii))
+ write(*,1202) inskey(ii), jj,
+ & iinarray(ii), jinarray(ii), einarray(ii), dinarray(ii)
+ end do
+
+ call ftdcol(iunit, 6, status)
+
+ call ftgcvs(iunit, 1, 1, 1, nrows, 'NOT DEFINED', inskey,
+ & anynull, status)
+ call ftgcvb(iunit, 4, 1, 1, nrows,bnul,binarray,anynull,status)
+ call ftgcvi(iunit, 5, 1, 1, nrows,inul,iinarray,anynull,status)
+ call ftgcve(iunit, 6, 1, 1, nrows, 98.,einarray,anynull,status)
+ call ftgcvd(iunit, 7, 1, 1, nrows,dnul,dinarray,anynull,status)
+
+ write(*,'(1x,A)')' '
+ write(*,'(1x,A)') 'Data values after deleting column 6: '
+ do ii = 1, nrows
+ jj = ichar(binarray(ii))
+ write(*,1203) inskey(ii), jj,
+ & iinarray(ii), einarray(ii), dinarray(ii)
+1203 format(1x,a14,2i4,2f5.0)
+
+ end do
+ call fticol(iunit, 8, 'INSERT_COL', '1E', status)
+
+ call ftgcvs(iunit, 1, 1, 1, nrows, 'NOT DEFINED', inskey,
+ & anynull, status)
+ call ftgcvb(iunit, 4, 1, 1, nrows,bnul,binarray,anynull,status)
+ call ftgcvi(iunit, 5, 1, 1, nrows,inul,iinarray,anynull,status)
+ call ftgcve(iunit, 6, 1, 1, nrows, 98.,einarray,anynull,status)
+ call ftgcvd(iunit, 7, 1, 1, nrows,dnul,dinarray,anynull,status)
+ call ftgcvj(iunit, 8, 1, 1, nrows, 98,jinarray,anynull,status)
+
+ write(*,'(1x,A)')' '
+ write(*,'(1x,A)') 'Data values after inserting column 8: '
+ do ii = 1, nrows
+ jj = ichar(binarray(ii))
+ write(*,1204) inskey(ii), jj,
+ & iinarray(ii), einarray(ii), dinarray(ii) , jinarray(ii)
+1204 format(1x,a14,2i4,2f5.0,i3)
+ end do
+ call ftpclu(iunit, 8, 1, 1, 10, status)
+
+ call ftgcvs(iunit, 1, 1, 1, nrows, 'NOT DEFINED', inskey,
+ & anynull, status)
+ call ftgcvb(iunit, 4,1,1,nrows,bnul,binarray,anynull,status)
+ call ftgcvi(iunit, 5,1,1,nrows,inul,iinarray,anynull,status)
+ call ftgcve(iunit, 6,1,1,nrows,98., einarray,anynull,status)
+ call ftgcvd(iunit, 7,1,1,nrows,dnul, dinarray,anynull,status)
+ call ftgcvj(iunit, 8,1,1,nrows,98, jinarray,anynull, status)
+
+ write(*,'(1x,A)')' '
+ write(*,'(1x,A)')
+ & 'Values after setting 1st 10 elements in column 8 = null: '
+ do ii = 1, nrows
+ jj = ichar(binarray(ii))
+ write(*,1204) inskey(ii), jj,
+ & iinarray(ii), einarray(ii), dinarray(ii) , jinarray(ii)
+ end do
+
+C ####################################################
+C # insert binary table following the primary array #
+C ####################################################
+
+ call ftmahd(iunit, 1, hdutype, status)
+
+ tform(1) = '15A'
+ tform(2) = '1L'
+ tform(3) = '16X'
+ tform(4) = '1B'
+ tform(5) = '1I'
+ tform(6) = '1J'
+ tform(7) = '1E'
+ tform(8) = '1D'
+ tform(9) = '1C'
+ tform(10)= '1M'
+
+ ttype(1) = 'Avalue'
+ ttype(2) = 'Lvalue'
+ ttype(3) = 'Xvalue'
+ ttype(4) = 'Bvalue'
+ ttype(5) = 'Ivalue'
+ ttype(6) = 'Jvalue'
+ ttype(7) = 'Evalue'
+ ttype(8) = 'Dvalue'
+ ttype(9) = 'Cvalue'
+ ttype(10)= 'Mvalue'
+
+ tunit(1)= ' '
+ tunit(2)= 'm**2'
+ tunit(3)= 'cm'
+ tunit(4)= 'erg/s'
+ tunit(5)= 'km/s'
+ tunit(6)= ' '
+ tunit(7)= ' '
+ tunit(8)= ' '
+ tunit(9)= ' '
+ tunit(10)= ' '
+
+ nrows = 20
+ tfields = 10
+ pcount = 0
+
+ call ftibin(iunit, nrows, tfields, ttype, tform, tunit,
+ & binname, pcount, status)
+ write(*,'(1x,A)')' '
+ write(*,'(1x,A,I4)') 'ftibin status = ', status
+ call ftghdn(iunit, hdunum)
+ write(*,'(1x,A,I4)') 'HDU number = ', hdunum
+
+ call ftpkyj(iunit, 'TNULL4', 77,
+ & 'value for undefined pixels', status)
+ call ftpkyj(iunit, 'TNULL5', 77,
+ & 'value for undefined pixels', status)
+ call ftpkyj(iunit, 'TNULL6', 77,
+ & 'value for undefined pixels', status)
+
+ call ftpkyj(iunit, 'TSCAL4', 1000, 'scaling factor', status)
+ call ftpkyj(iunit, 'TSCAL5', 1, 'scaling factor', status)
+ call ftpkyj(iunit, 'TSCAL6', 100, 'scaling factor', status)
+
+ call ftpkyj(iunit, 'TZERO4', 0, 'scaling offset', status)
+ call ftpkyj(iunit, 'TZERO5', 32768, 'scaling offset', status)
+ call ftpkyj(iunit, 'TZERO6', 100, 'scaling offset', status)
+
+ call fttnul(iunit, 4, 77, status)
+C define null value for int cols
+ call fttnul(iunit, 5, 77, status)
+ call fttnul(iunit, 6, 77, status)
+
+C set scaling
+ scale=1000.
+ zero = 0.
+ call fttscl(iunit, 4, scale, zero, status)
+ scale=1.
+ zero = 32768.
+ call fttscl(iunit, 5, scale, zero, status)
+ scale=100.
+ zero = 100.
+ call fttscl(iunit, 6, scale, zero, status)
+
+C for some reason, it is still necessary to call ftrdef at this point
+ call ftrdef(iunit,status)
+
+C ############################
+C # write data to columns #
+C ############################
+
+C initialize arrays of values to write to table
+
+ joutarray(1) = 0
+ joutarray(2) = 1000
+ joutarray(3) = 10000
+ joutarray(4) = 32768
+ joutarray(5) = 65535
+
+
+ do ii = 4,6
+
+ call ftpclj(iunit, ii, 1, 1, 5, joutarray, status)
+ if (status .eq. 412)then
+ write(*,'(1x,A,I4)') 'Overflow writing to column ', ii
+ status = 0
+ end if
+
+ call ftpclu(iunit, ii, 6, 1, 1, status)
+C write null value
+ end do
+
+ do jj = 4,6
+ call ftgcvj(iunit, jj, 1,1,6, -999,jinarray,anynull,status)
+ write(*,'(1x,6I6)') (jinarray(ii), ii=1,6)
+ end do
+
+ write(*,'(1x,A)') ' '
+
+C turn off scaling, and read the unscaled values
+ scale = 1.
+ zero = 0.
+ call fttscl(iunit, 4, scale, zero, status)
+ call fttscl(iunit, 5, scale, zero, status)
+ call fttscl(iunit, 6, scale, zero, status)
+
+ do jj = 4,6
+ call ftgcvj(iunit, jj,1,1,6,-999,jinarray,anynull,status)
+ write(*,'(1x,6I6)') (jinarray(ii), ii = 1,6)
+ end do
+
+ if (status .gt. 0)go to 999
+
+C ######################################################
+C # insert image extension following the binary table #
+C ######################################################
+
+ bitpix = -32
+ naxis = 2
+ naxes(1) = 15
+ naxes(2) = 25
+ call ftiimg(iunit, bitpix, naxis, naxes, status)
+ write(*,'(1x,A)')' '
+ write(*,'(1x,A,I4)')
+ & ' Create image extension: ftiimg status = ', status
+ call ftghdn(iunit, hdunum)
+ write(*,'(1x,A,I4)') 'HDU number = ', hdunum
+
+ do jj = 0,29
+ do ii = 0,18
+ imgarray(ii+1,jj+1) = (jj * 10) + ii
+ end do
+ end do
+
+ call ftp2di(iunit, 1, 19, naxes(1),naxes(2),imgarray,status)
+ write(*,'(1x,A)') ' '
+ write(*,'(1x,A,I4)')'Wrote whole 2D array: ftp2di status =',
+ & status
+
+ do jj =1, 30
+ do ii = 1, 19
+ imgarray(ii,jj) = 0
+ end do
+ end do
+
+ call ftg2di(iunit,1,0,19,naxes(1),naxes(2),imgarray,anynull,
+ & status)
+ write(*,'(1x,A)')' '
+ write(*,'(1x,A,I4)')'Read whole 2D array: ftg2di status =',status
+
+ do jj =1, 30
+ write (*,1301)(imgarray(ii,jj),ii=1,19)
+1301 format(1x,19I4)
+ end do
+
+ write(*,'(1x,A)') ' '
+
+
+ do jj =1, 30
+ do ii = 1, 19
+ imgarray(ii,jj) = 0
+ end do
+ end do
+
+ do jj =0, 19
+ do ii = 0, 9
+ imgarray2(ii+1,jj+1) = (jj * (-10)) - ii
+ end do
+ end do
+
+ fpixels(1) = 5
+ fpixels(2) = 5
+ lpixels(1) = 14
+ lpixels(2) = 14
+ call ftpssi(iunit, 1, naxis, naxes, fpixels, lpixels,
+ & imgarray2, status)
+ write(*,'(1x,A)')' '
+ write(*,'(1x,A,I4)')'Wrote subset 2D array: ftpssi status =',
+ & status
+
+ call ftg2di(iunit,1,0,19,naxes(1), naxes(2),imgarray,anynull,
+ & status)
+ write(*,'(1x,A)')' '
+ write(*,'(1x,A,I4)')'Read whole 2D array: ftg2di status =',status
+
+ do jj =1, 30
+ write (*,1301)(imgarray(ii,jj),ii=1,19)
+ end do
+ write(*,'(1x,A)') ' '
+
+
+ fpixels(1) = 2
+ fpixels(2) = 5
+ lpixels(1) = 10
+ lpixels(2) = 8
+ inc(1) = 2
+ inc(2) = 3
+
+ do jj = 1,30
+ do ii = 1, 19
+ imgarray(ii,jj) = 0
+ end do
+ end do
+
+ call ftgsvi(iunit, 1, naxis, naxes, fpixels, lpixels, inc, 0,
+ & imgarray, anynull, status)
+ write(*,'(1x,A)')' '
+ write(*,'(1x,A,I4)')
+ & 'Read subset of 2D array: ftgsvi status = ',status
+
+ write(*,'(1x,10I5)')(imgarray(ii,1),ii = 1,10)
+
+
+C ###########################################################
+C # insert another image extension #
+C # copy the image extension to primary array of tmp file. #
+C # then delete the tmp file, and the image extension #
+C ###########################################################
+
+ bitpix = 16
+ naxis = 2
+ naxes(1) = 15
+ naxes(2) = 25
+ call ftiimg(iunit, bitpix, naxis, naxes, status)
+ write(*,'(1x,A)') ' '
+ write(*,'(1x,A,I4)')'Create image extension: ftiimg status =',
+ & status
+ call ftrdef(iunit, status)
+ call ftghdn(iunit, hdunum)
+ write(*,'(1x,A,I4)') 'HDU number = ', hdunum
+
+
+ filename = 't1q2s3v4.tmp'
+ call ftinit(tmpunit, filename, 1, status)
+ write(*,'(1x,A,I4)')'Create temporary file: ftinit status = ',
+ & status
+
+ call ftcopy(iunit, tmpunit, 0, status)
+ write(*,'(1x,A)')
+ & 'Copy image extension to primary array of tmp file.'
+ write(*,'(1x,A,I4)')'ftcopy status = ',status
+
+
+ call ftgrec(tmpunit, 1, card, status)
+ write(*,'(1x,A)') card
+ call ftgrec(tmpunit, 2, card, status)
+ write(*,'(1x,A)') card
+ call ftgrec(tmpunit, 3, card, status)
+ write(*,'(1x,A)') card
+ call ftgrec(tmpunit, 4, card, status)
+ write(*,'(1x,A)') card
+ call ftgrec(tmpunit, 5, card, status)
+ write(*,'(1x,A)') card
+ call ftgrec(tmpunit, 6, card, status)
+ write(*,'(1x,A)') card
+
+ call ftdelt(tmpunit, status)
+ write(*,'(1x,A,I4)')'Delete the tmp file: ftdelt status =',status
+ call ftdhdu(iunit, hdutype, status)
+ write(*,'(1x,A,2I4)')
+ & 'Delete the image extension hdutype, status =',
+ & hdutype, status
+ call ftghdn(iunit, hdunum)
+ write(*,'(1x,A,I4)') 'HDU number = ', hdunum
+
+
+C ###########################################################
+C # append bintable extension with variable length columns #
+C ###########################################################
+
+ call ftcrhd(iunit, status)
+ write(*,'(1x,A,I4)') 'ftcrhd status = ', status
+
+ tform(1)= '1PA'
+ tform(2)= '1PL'
+ tform(3)= '1PB'
+C Fortran FITSIO doesn't support 1PX
+ tform(4)= '1PB'
+ tform(5)= '1PI'
+ tform(6)= '1PJ'
+ tform(7)= '1PE'
+ tform(8)= '1PD'
+ tform(9)= '1PC'
+ tform(10)= '1PM'
+
+ ttype(1)= 'Avalue'
+ ttype(2)= 'Lvalue'
+ ttype(3)= 'Xvalue'
+ ttype(4)= 'Bvalue'
+ ttype(5)= 'Ivalue'
+ ttype(6)= 'Jvalue'
+ ttype(7)= 'Evalue'
+ ttype(8)= 'Dvalue'
+ ttype(9)= 'Cvalue'
+ ttype(10)= 'Mvalue'
+
+ tunit(1)= ' '
+ tunit(2)= 'm**2'
+ tunit(3)= 'cm'
+ tunit(4)= 'erg/s'
+ tunit(5)= 'km/s'
+ tunit(6)= ' '
+ tunit(7)= ' '
+ tunit(8)= ' '
+ tunit(9)= ' '
+ tunit(10)= ' '
+
+ nrows = 20
+ tfields = 10
+ pcount = 0
+
+ call ftphbn(iunit, nrows, tfields, ttype, tform,
+ & tunit, binname, pcount, status)
+ write(*,'(1x,A,I4)')'Variable length arrays: ftphbn status =',
+ & status
+ call ftpkyj(iunit, 'TNULL4', 88, 'value for undefined pixels',
+ & status)
+ call ftpkyj(iunit, 'TNULL5', 88, 'value for undefined pixels',
+ & status)
+ call ftpkyj(iunit, 'TNULL6', 88, 'value for undefined pixels',
+ & status)
+
+C ############################
+C # write data to columns #
+C ############################
+
+C initialize arrays of values to write to table
+ iskey='abcdefghijklmnopqrst'
+
+ do ii = 1, 20
+
+ boutarray(ii) = char(ii)
+ ioutarray(ii) = ii
+ joutarray(ii) = ii
+ eoutarray(ii) = ii
+ doutarray(ii) = ii
+ end do
+
+ larray(1) = .false.
+ larray(2) = .true.
+ larray(3) = .false.
+ larray(4) = .false.
+ larray(5) = .true.
+ larray(6) = .true.
+ larray(7) = .false.
+ larray(8) = .false.
+ larray(9) = .false.
+ larray(10) = .true.
+ larray(11) = .true.
+ larray(12) = .true.
+ larray(13) = .false.
+ larray(14) = .false.
+ larray(15) = .false.
+ larray(16) = .false.
+ larray(17) = .true.
+ larray(18) = .true.
+ larray(19) = .true.
+ larray(20) = .true.
+
+C inskey(1) = iskey(1:1)
+ inskey(1) = ' '
+
+ call ftpcls(iunit, 1, 1, 1, 1, inskey, status)
+C write string values
+ call ftpcll(iunit, 2, 1, 1, 1, larray, status)
+C write logicals
+ call ftpclx(iunit, 3, 1, 1, 1, larray, status)
+C write bits
+ call ftpclb(iunit, 4, 1, 1, 1, boutarray, status)
+ call ftpcli(iunit, 5, 1, 1, 1, ioutarray, status)
+ call ftpclj(iunit, 6, 1, 1, 1, joutarray, status)
+ call ftpcle(iunit, 7, 1, 1, 1, eoutarray, status)
+ call ftpcld(iunit, 8, 1, 1, 1, doutarray, status)
+
+ do ii = 2, 20
+C loop over rows 1 - 20
+
+ inskey(1) = iskey(1:ii)
+ call ftpcls(iunit, 1, ii, 1, ii, inskey, status)
+C write string values
+
+ call ftpcll(iunit, 2, ii, 1, ii, larray, status)
+C write logicals
+ call ftpclu(iunit, 2, ii, ii-1, 1, status)
+
+ call ftpclx(iunit, 3, ii, 1, ii, larray, status)
+C write bits
+
+ call ftpclb(iunit, 4, ii, 1, ii, boutarray, status)
+ call ftpclu(iunit, 4, ii, ii-1, 1, status)
+
+ call ftpcli(iunit, 5, ii, 1, ii, ioutarray, status)
+ call ftpclu(iunit, 5, ii, ii-1, 1, status)
+
+ call ftpclj(iunit, 6, ii, 1, ii, joutarray, status)
+ call ftpclu(iunit, 6, ii, ii-1, 1, status)
+
+ call ftpcle(iunit, 7, ii, 1, ii, eoutarray, status)
+ call ftpclu(iunit, 7, ii, ii-1, 1, status)
+
+ call ftpcld(iunit, 8, ii, 1, ii, doutarray, status)
+ call ftpclu(iunit, 8, ii, ii-1, 1, status)
+ end do
+
+C it is no longer necessary to update the PCOUNT keyword;
+C FITSIO now does this automatically when the HDU is closed.
+C call ftmkyj(iunit,'PCOUNT',4446, '&',status)
+ write(*,'(1x,A,I4)') 'ftpcl_ status = ', status
+
+C #################################
+C # close then reopen this HDU #
+C #################################
+
+ call ftmrhd(iunit, -1, hdutype, status)
+ call ftmrhd(iunit, 1, hdutype, status)
+
+C #############################
+C # read data from columns #
+C #############################
+
+
+ call ftgkyj(iunit, 'PCOUNT', pcount, comm, status)
+ write(*,'(1x,A,I4)') 'PCOUNT = ', pcount
+
+C initialize the variables to be read
+ inskey(1) =' '
+ iskey = ' '
+
+ do jj = 1, ii
+ larray(jj) = .false.
+ boutarray(jj) = char(0)
+ ioutarray(jj) = 0
+ joutarray(jj) = 0
+ eoutarray(jj) = 0
+ doutarray(jj) = 0
+ end do
+
+ call ftghdn(iunit, hdunum)
+ write(*,'(1x,A,I4)') 'HDU number = ', hdunum
+
+ do ii = 1, 20
+C loop over rows 1 - 20
+
+ do jj = 1, ii
+ larray(jj) = .false.
+ boutarray(jj) = char(0)
+ ioutarray(jj) = 0
+ joutarray(jj) = 0
+ eoutarray(jj) = 0
+ doutarray(jj) = 0
+ end do
+
+ call ftgcvs(iunit, 1, ii, 1,1,iskey,inskey,anynull,status)
+ write(*,'(1x,2A,I4)') 'A ', inskey(1), status
+
+ call ftgcl( iunit, 2, ii, 1, ii, larray, status)
+ write(*,1400)'L',status,(larray(jj),jj=1,ii)
+1400 format(1x,a1,i3,20l3)
+1401 format(1x,a1,21i3)
+
+ call ftgcx(iunit, 3, ii, 1, ii, larray, status)
+ write(*,1400)'X',status,(larray(jj),jj=1,ii)
+
+ bnul = char(99)
+ call ftgcvb(iunit, 4, ii, 1,ii,bnul,boutarray,anynull,status)
+ do jj = 1,ii
+ jinarray(jj) = ichar(boutarray(jj))
+ end do
+ write(*,1401)'B',(jinarray(jj),jj=1,ii),status
+
+ inul = 99
+ call ftgcvi(iunit, 5, ii, 1,ii,inul,ioutarray,anynull,status)
+ write(*,1401)'I',(ioutarray(jj),jj=1,ii),status
+
+ call ftgcvj(iunit, 6, ii, 1, ii,99,joutarray,anynull,status)
+ write(*,1401)'J',(joutarray(jj),jj=1,ii),status
+
+ call ftgcve(iunit, 7, ii, 1,ii,99.,eoutarray,anynull,status)
+ estatus=status
+ write(*,1402)'E',(eoutarray(jj),jj=1,ii),estatus
+1402 format(1x,a1,1x,21f3.0)
+
+ dnul = 99.
+ call ftgcvd(iunit, 8, ii,1,ii,dnul,doutarray,anynull,status)
+ estatus=status
+ write(*,1402)'D',(doutarray(jj),jj=1,ii),estatus
+
+ call ftgdes(iunit, 8, ii, repeat, offset, status)
+ write(*,'(1x,A,2I5)')'Column 8 repeat and offset =',
+ & repeat,offset
+ end do
+
+C #####################################
+C # create another image extension #
+C #####################################
+
+
+ bitpix = 32
+ naxis = 2
+ naxes(1) = 10
+ naxes(2) = 2
+ npixels = 20
+
+ call ftiimg(iunit, bitpix, naxis, naxes, status)
+ write(*,'(1x,A)')' '
+ write(*,'(1x,A,I4)')'Create image extension: ftiimg status =',
+ & status
+
+C initialize arrays of values to write to primary array
+ do ii = 1, npixels
+ boutarray(ii) = char(ii * 2 -2)
+ ioutarray(ii) = ii * 2 -2
+ joutarray(ii) = ii * 2 -2
+ koutarray(ii) = ii * 2 -2
+ eoutarray(ii) = ii * 2 -2
+ doutarray(ii) = ii * 2 -2
+ end do
+
+C write a few pixels with each datatype
+ call ftpprb(iunit, 1, 1, 2, boutarray(1), status)
+ call ftppri(iunit, 1, 3, 2, ioutarray(3), status)
+ call ftpprj(iunit, 1, 5, 2, koutarray(5), status)
+ call ftppri(iunit, 1, 7, 2, ioutarray(7), status)
+ call ftpprj(iunit, 1, 9, 2, joutarray(9), status)
+ call ftppre(iunit, 1, 11, 2, eoutarray(11), status)
+ call ftpprd(iunit, 1, 13, 2, doutarray(13), status)
+ write(*,'(1x,A,I4)') 'ftppr status = ', status
+
+
+C read back the pixels with each datatype
+ bnul = char(0)
+ inul = 0
+ knul = 0
+ jnul = 0
+ enul = 0.
+ dnul = 0.
+
+ call ftgpvb(iunit, 1, 1, 14, bnul, binarray, anynull, status)
+ call ftgpvi(iunit, 1, 1, 14, inul, iinarray, anynull, status)
+ call ftgpvj(iunit, 1, 1, 14, knul, kinarray, anynull, status)
+ call ftgpvj(iunit, 1, 1, 14, jnul, jinarray, anynull, status)
+ call ftgpve(iunit, 1, 1, 14, enul, einarray, anynull, status)
+ call ftgpvd(iunit, 1, 1, 14, dnul, dinarray, anynull, status)
+
+ write(*,'(1x,A)')' '
+ write(*,'(1x,A)')
+ & 'Image values written with ftppr and read with ftgpv:'
+ npixels = 14
+ do jj = 1,ii
+ joutarray(jj) = ichar(binarray(jj))
+ end do
+
+ write(*,1501)(joutarray(ii),ii=1,npixels),anynull,'(byte)'
+1501 format(1x,14i3,l3,1x,a)
+ write(*,1501)(iinarray(ii),ii=1,npixels),anynull,'(short)'
+ write(*,1501)(kinarray(ii),ii=1,npixels),anynull,'(int)'
+ write(*,1501)(jinarray(ii),ii=1,npixels),anynull,'(long)'
+ write(*,1502)(einarray(ii),ii=1,npixels),anynull,'(float)'
+ write(*,1502)(dinarray(ii),ii=1,npixels),anynull,'(double)'
+1502 format(2x,14f3.0,l2,1x,a)
+
+C ##########################################
+C # test world coordinate system routines #
+C ##########################################
+
+ xrval = 45.83D+00
+ yrval = 63.57D+00
+ xrpix = 256.D+00
+ yrpix = 257.D+00
+ xinc = -.00277777D+00
+ yinc = .00277777D+00
+
+C write the WCS keywords
+C use example values from the latest WCS document
+ call ftpkyd(iunit, 'CRVAL1', xrval, 10, 'comment', status)
+ call ftpkyd(iunit, 'CRVAL2', yrval, 10, 'comment', status)
+ call ftpkyd(iunit, 'CRPIX1', xrpix, 10, 'comment', status)
+ call ftpkyd(iunit, 'CRPIX2', yrpix, 10, 'comment', status)
+ call ftpkyd(iunit, 'CDELT1', xinc, 10, 'comment', status)
+ call ftpkyd(iunit, 'CDELT2', yinc, 10, 'comment', status)
+C call ftpkyd(iunit, 'CROTA2', rot, 10, 'comment', status)
+ call ftpkys(iunit, 'CTYPE1', xctype, 'comment', status)
+ call ftpkys(iunit, 'CTYPE2', yctype, 'comment', status)
+ write(*,'(1x,A)')' '
+ write(*,'(1x,A,I4)')'Wrote WCS keywords status =', status
+
+C reset value, to make sure they are reread correctly
+ xrval = 0.D+00
+ yrval = 0.D+00
+ xrpix = 0.D+00
+ yrpix = 0.D+00
+ xinc = 0.D+00
+ yinc = 0.D+00
+ rot = 67.D+00
+
+ call ftgics(iunit, xrval, yrval, xrpix,
+ & yrpix, xinc, yinc, rot, ctype, status)
+ write(*,'(1x,A,I4)')'Read WCS keywords with ftgics status =',
+ & status
+
+ xpix = 0.5D+00
+ ypix = 0.5D+00
+
+ call ftwldp(xpix,ypix,xrval,yrval,xrpix,yrpix,xinc,yinc,
+ & rot,ctype, xpos, ypos,status)
+
+ write(*,'(1x,A,2f8.3)')' CRVAL1, CRVAL2 =', xrval,yrval
+ write(*,'(1x,A,2f8.3)')' CRPIX1, CRPIX2 =', xrpix,yrpix
+ write(*,'(1x,A,2f12.8)')' CDELT1, CDELT2 =', xinc,yinc
+ write(*,'(1x,A,f8.3,2A)')' Rotation =',rot,' CTYPE =',ctype
+ write(*,'(1x,A,I4)')'Calculated sky coord. with ftwldp status =',
+ & status
+ write(*,6501)xpix,ypix,xpos,ypos
+6501 format(' Pixels (',f10.6,f10.6,') --> (',f10.6,f10.6,') Sky')
+
+ call ftxypx(xpos,ypos,xrval,yrval,xrpix,yrpix,xinc,yinc,
+ & rot,ctype, xpix, ypix,status)
+ write(*,'(1x,A,I4)')
+ & 'Calculated pixel coord. with ftxypx status =', status
+ write(*,6502)xpos,ypos,xpix,ypix
+6502 format(' Sky (',f10.6,f10.6,') --> (',f10.6,f10.6,') Pixels')
+
+
+C ######################################
+C # append another ASCII table #
+C ######################################
+
+
+ tform(1)= 'A15'
+ tform(2)= 'I11'
+ tform(3)= 'F15.6'
+ tform(4)= 'E13.5'
+ tform(5)= 'D22.14'
+
+ tbcol(1)= 1
+ tbcol(2)= 17
+ tbcol(3)= 29
+ tbcol(4)= 45
+ tbcol(5)= 59
+ rowlen = 80
+
+ ttype(1)= 'Name'
+ ttype(2)= 'Ivalue'
+ ttype(3)= 'Fvalue'
+ ttype(4)= 'Evalue'
+ ttype(5)= 'Dvalue'
+
+ tunit(1)= ' '
+ tunit(2)= 'm**2'
+ tunit(3)= 'cm'
+ tunit(4)= 'erg/s'
+ tunit(5)= 'km/s'
+
+ nrows = 11
+ tfields = 5
+ tblname = 'new_table'
+
+ call ftitab(iunit, rowlen, nrows, tfields, ttype, tbcol,
+ & tform, tunit, tblname, status)
+ write(*,'(1x,A)') ' '
+ write(*,'(1x,A,I4)') 'ftitab status = ', status
+
+ call ftpcls(iunit, 1, 1, 1, 3, onskey, status)
+C write string values
+
+C initialize arrays of values to write to primary array
+
+ do ii = 1,npixels
+ boutarray(ii) = char(ii * 3 -3)
+ ioutarray(ii) = ii * 3 -3
+ joutarray(ii) = ii * 3 -3
+ koutarray(ii) = ii * 3 -3
+ eoutarray(ii) = ii * 3 -3
+ doutarray(ii) = ii * 3 -3
+ end do
+
+ do ii = 2,5
+C loop over cols 2 - 5
+
+ call ftpclb(iunit, ii, 1, 1, 2, boutarray, status)
+ call ftpcli(iunit, ii, 3, 1, 2,ioutarray(3),status)
+ call ftpclj(iunit, ii, 5, 1, 2,joutarray(5),status)
+ call ftpcle(iunit, ii, 7, 1, 2,eoutarray(7),status)
+ call ftpcld(iunit, ii, 9, 1, 2,doutarray(9),status)
+ end do
+ write(*,'(1x,A,I4)') 'ftpcl status = ', status
+
+C read back the pixels with each datatype
+ call ftgcvb(iunit, 2, 1, 1, 10, bnul, binarray,anynull,
+ & status)
+ call ftgcvi(iunit, 2, 1, 1, 10, inul, iinarray,anynull,
+ & status)
+ call ftgcvj(iunit, 3, 1, 1, 10, knul, kinarray,anynull,
+ & status)
+ call ftgcvj(iunit, 3, 1, 1, 10, jnul, jinarray,anynull,
+ & status)
+ call ftgcve(iunit, 4, 1, 1, 10, enul, einarray,anynull,
+ & status)
+ call ftgcvd(iunit, 5, 1, 1, 10, dnul, dinarray,anynull,
+ & status)
+
+ write(*,'(1x,A)')
+ &'Column values written with ftpcl and read with ftgcl: '
+ npixels = 10
+ do ii = 1,npixels
+ joutarray(ii) = ichar(binarray(ii))
+ end do
+ write(*,1601)(joutarray(ii),ii = 1, npixels),anynull,'(byte) '
+ write(*,1601)(iinarray(ii),ii = 1, npixels),anynull,'(short) '
+ write(*,1601)(kinarray(ii),ii = 1, npixels),anynull,'(int) '
+ write(*,1601)(jinarray(ii),ii = 1, npixels),anynull,'(long) '
+ write(*,1602)(einarray(ii),ii = 1, npixels),anynull,'(float) '
+ write(*,1602)(dinarray(ii),ii = 1, npixels),anynull,'(double) '
+1601 format(1x,10i3,l3,1x,a)
+1602 format(2x,10f3.0,l2,1x,a)
+
+C ###########################################################
+C # perform stress test by cycling thru all the extensions #
+C ###########################################################
+ write(*,'(1x,A)')' '
+ write(*,'(1x,A)')'Repeatedly move to the 1st 4 HDUs of the file: '
+
+ do ii = 1,10
+ call ftmahd(iunit, 1, hdutype, status)
+ call ftghdn(iunit, hdunum)
+ call ftmrhd(iunit, 1, hdutype, status)
+ call ftghdn(iunit, hdunum)
+ call ftmrhd(iunit, 1, hdutype, status)
+ call ftghdn(iunit, hdunum)
+ call ftmrhd(iunit, 1, hdutype, status)
+ call ftghdn(iunit, hdunum)
+ call ftmrhd(iunit, -1, hdutype, status)
+ call ftghdn(iunit, hdunum)
+ if (status .gt. 0) go to 999
+ end do
+
+ write(*,'(1x,A)') ' '
+
+ checksum = 1234567890.D+00
+ call ftesum(checksum, .false., asciisum)
+ write(*,'(1x,A,F13.1,2A)')'Encode checksum: ',checksum,' -> ',
+ & asciisum
+ checksum = 0
+ call ftdsum(asciisum, 0, checksum)
+ write(*,'(1x,3A,F13.1)') 'Decode checksum: ',asciisum,' -> ',
+ & checksum
+
+ call ftpcks(iunit, status)
+
+C don't print the CHECKSUM value because it is different every day
+C because the current date is in the comment field.
+
+ call ftgcrd(iunit, 'CHECKSUM', card, status)
+C write(*,'(1x,A)') card
+
+ call ftgcrd(iunit, 'DATASUM', card, status)
+ write(*,'(1x,A)') card(1:22)
+
+ call ftgcks(iunit, datsum, checksum, status)
+ write(*,'(1x,A,F13.1,I4)') 'ftgcks data checksum, status = ',
+ & datsum, status
+
+ call ftvcks(iunit, datastatus, hdustatus, status)
+ write(*,'(1x,A,3I4)')'ftvcks datastatus, hdustatus, status = ',
+ & datastatus, hdustatus, status
+
+ call ftprec(iunit,
+ & 'new_key = ''written by fxprec'' / to change checksum',status)
+ call ftucks(iunit, status)
+ write(*,'(1x,A,I4)') 'ftupck status = ', status
+
+ call ftgcrd(iunit, 'DATASUM', card, status)
+ write(*,'(1x,A)') card(1:22)
+ call ftvcks(iunit, datastatus, hdustatus, status)
+ write(*,'(1x,A,3I4)') 'ftvcks datastatus, hdustatus, status = ',
+ & datastatus, hdustatus, status
+
+C delete the checksum keywords, so that the FITS file is always
+C the same, regardless of the date of when testprog is run.
+
+ call ftdkey(iunit, 'CHECKSUM', status)
+ call ftdkey(iunit, 'DATASUM', status)
+
+
+C ############################
+C # close file and quit #
+C ############################
+
+
+999 continue
+C jump here on error
+
+ call ftclos(iunit, status)
+ write(*,'(1x,A,I4)') 'ftclos status = ', status
+ write(*,'(1x,A)')' '
+
+ write(*,'(1x,A)')
+ & 'Normally, there should be 8 error messages on the'
+ write(*,'(1x,A)') 'stack all regarding ''numerical overflows'':'
+
+ call ftgmsg(errmsg)
+ nmsg = 0
+
+998 continue
+ if (errmsg .ne. ' ')then
+ write(*,'(1x,A)') errmsg
+ nmsg = nmsg + 1
+ call ftgmsg(errmsg)
+ go to 998
+ end if
+
+ if (nmsg .ne. 8)write(*,'(1x,A)')
+ & ' WARNING: Did not find the expected 8 error messages!'
+
+ call ftgerr(status, errmsg)
+ write(*,'(1x,A)')' '
+ write(*,'(1x,A,I4,2A)') 'Status =', status,': ', errmsg(1:50)
+ end
diff --git a/pkg/tbtables/cfitsio/testf77.out b/pkg/tbtables/cfitsio/testf77.out
new file mode 100644
index 00000000..56755b86
--- /dev/null
+++ b/pkg/tbtables/cfitsio/testf77.out
@@ -0,0 +1,746 @@
+ FITSIO TESTPROG, v 2.401
+
+ Try opening then closing a nonexistent file:
+ ftopen iunit, status (expect an error) = 15 104
+ ftclos status = 104
+
+ ftinit create new file status = 0
+
+ test writing of long string keywords:
+ 123456789012345678901234567890123456789012345678901234567890123456789012345
+ '12345678901234567890123456789012345678901234567890123456789012345678'
+ 1234567890123456789012345678901234567890123456789012345678901234'6789012345
+ '1234567890123456789012345678901234567890123456789012345678901234''67'
+ 1234567890123456789012345678901234567890123456789012345678901234''789012345
+ '1234567890123456789012345678901234567890123456789012345678901234'''''
+ 1234567890123456789012345678901234567890123456789012345678901234567'9012345
+ '1234567890123456789012345678901234567890123456789012345678901234567'
+ Wrote all Keywords successfully
+ ftflus status = 0
+
+ HDU number = 1
+ Values read back from primary array (99 = null pixel)
+ The 1st, and every 4th pixel should be undefined:
+ 99 2 3 99 5 6 7 99 9 10 11 99 13 14 15 99 17 18 19 99 T (ftgpvb)
+ 99 2 3 99 5 6 7 99 9 10 11 99 13 14 15 99 17 18 19 99 T (ftgpvi)
+ 99 2 3 99 5 6 7 99 9 10 11 99 13 14 15 99 17 18 19 99 T (ftgpvj)
+ 99. 2. 3.99. 5. 6. 7.99. 9.10.11.99.13.14.15.99.17.18.19.99. T (ftgpve)
+ 99. 2. 3.99. 5. 6. 7.99. 9.10.11.99.13.14.15.99.17.18.19.99. T (ftgpvd)
+ 0 2 3 0 5 6 7 0 9 10 11 0 13 14 15 0 17 18 19 0 T (ftgpfb)
+ 0 2 3 0 5 6 7 0 9 10 11 0 13 14 15 0 17 18 19 0 T (ftgpfi)
+ 0 2 3 0 5 6 7 0 9 10 11 0 13 14 15 0 17 18 19 0 T (ftgpfj)
+ 0. 2. 3. 0. 5. 6. 7. 0. 9.10.11. 0.13.14.15. 0.17.18.19. 0. T (ftgpfe)
+ 0. 2. 3. 0. 5. 6. 7. 0. 9.10.11. 0.13.14.15. 0.17.18.19. 0. T (ftgpfd)
+
+ Closed then reopened the FITS file 10 times.
+
+ HDU number = 1
+ Read back keywords:
+ simple, bitpix, naxis, naxes = T 32 2 10 2
+ pcount, gcount, extend = 0 1 T
+ KEY_PREC= 'This keyword was written by fxprec' / comment goes here
+ KEY_PREC 'This keyword was written by fxprec comment goes here
+ KEY_PREC= 'This keyword was written by fxprec' / comment goes here
+ KY_PKNS1 :'first string' :fxpkns comment
+ KEY_PKYS :value_string :fxpkys comment 0
+ KEY_PKYL : T:fxpkyl comment 0
+ KEY_PKYJ : 11:fxpkyj comment 0
+ KEY_PKYE : 11.00000:fxpkyj comment 0
+ KEY_PKYD : 11.00000:fxpkyj comment 0
+ KEY_PKYS :value_string :fxpkys comment 0
+ KEY_PKYL : T:fxpkyl comment 0
+ KEY_PKYJ : 11:fxpkyj comment 0
+ KEY_PKYE : 13.13131:fxpkye comment 0
+ KEY_PKYD : 15.15152:fxpkyd comment 0
+ KEY_PKYF : 12.12121:fxpkyf comment 0
+ KEY_PKYE : 13.13131:fxpkye comment 0
+ KEY_PKYG : 14.141414141414:fxpkyg comment 0
+ KEY_PKYD : 15.151515151515:fxpkyd comment 0
+ KEY_PKYT : 12345678:0.12345678901235fxpkyt comment 0
+ KEY_PKYJ : 11:[km/s/Mpc] fxpkyj comment 0
+ keyword unit=km/s/Mpc
+ KEY_PKYJ : 11:fxpkyj comment 0
+ keyword unit=
+ KEY_PKYJ : 11:[feet/second/second] fxpkyj comment 0
+ keyword unit=feet/second/second
+ KEY_PKLS long string value = This is a very long string value that is continued
+ over more than one keyword.
+ header contains 61 keywords; located at keyword 23
+ ftgkns: first string second string
+ ftgknl: T F T
+ ftgknj: 11 12 13
+ ftgkne: 13.13131 14.14141 15.15152
+ ftgknd: 15.15152 16.16162 17.17172
+
+ Before deleting the HISTORY and DATE keywords...
+ COMMENT
+ HISTORY
+ DATE
+ KY_PKNS1
+
+ After deleting the keywords...
+ COMMENT This keyword was written by fxpcom.
+ KY_PKNS1= 'first string' / fxpkns comment
+
+ After inserting the keywords...
+ COMMENT continued over multiple keywords. The HEASARC convention uses the &
+ KY_IREC = 'This keyword inserted by fxirec'
+ KY_IKYS = 'insert_value_string' / ikys comment
+ KY_IKYJ = 49 / ikyj comment
+ KY_IKYL = T / ikyl comment
+ KY_IKYE = 1.2346E+01 / ikye comment
+ KY_IKYD = 1.23456789012346E+01 / ikyd comment
+ KY_IKYF = 12.3456 / ikyf comment
+ KY_IKYG = 12.3456789012346 / ikyg comment
+ COMMENT character at the end of each substring which is then continued
+
+ After modifying the keywords...
+ COMMENT This keyword was modified by fxmrec
+ KY_MREC = 'This keyword was modified by fxmcrd'
+ NEWIKYS = 'modified_string' / ikys comment
+ KY_IKYJ = 50 / This is a modified comment
+ KY_IKYL = F / ikyl comment
+ KY_IKYE = -1.2346E+01 / ikye comment
+ KY_IKYD = -1.23456789012346E+01 / modified comment
+ KY_IKYF = -12.3456 / ikyf comment
+ KY_IKYG = -12.3456789012346 / ikyg comment
+ COMMENT character at the end of each substring which is then continued
+
+ After updating the keywords...
+ COMMENT This keyword was modified by fxmrec
+ KY_UCRD = 'This keyword was updated by fxucrd'
+ NEWIKYS = 'updated_string' / ikys comment
+ KY_IKYJ = 51 / This is a modified comment
+ KY_IKYL = T / ikyl comment
+ KY_IKYE = -1.3346E+01 / ikye comment
+ KY_IKYD = -1.33456789012346E+01 / modified comment
+ KY_IKYF = -13.3456 / ikyf comment
+ KY_IKYG = -13.3456789012346 / ikyg comment
+ COMMENT character at the end of each substring which is then continued
+
+ Keywords found using wildcard search (should be 9)...
+ KEY_PKYS= 'value_string' / fxpkys comment
+ KEY_PKYL= T / fxpkyl comment
+ KEY_PKYJ= 11 / [feet/second/second] fxpkyj comment
+ KEY_PKYF= 12.12121 / fxpkyf comment
+ KEY_PKYE= 1.313131E+01 / fxpkye comment
+ KEY_PKYG= 14.14141414141414 / fxpkyg comment
+ KEY_PKYD= 1.51515151515152E+01 / fxpkyd comment
+ NEWIKYS = 'updated_string' / ikys comment
+ KEY_PKYT= 12345678.1234567890123456 / fxpkyt comment
+
+ ftibin status = 0
+ HDU number = 2
+ header contains 33 keywords located at keyword 1
+ header contains 33 keywords with room for 74 more
+ TDIM3 = (1,2,8) 3 1 2 8
+ ftpcl_ status = 0
+
+ Find the column numbers a returned status value of 237 is
+ expected and indicates that more than one column name matches
+ the input column name template. Status = 219 indicates that
+ there was no matching column name.
+ Column Xvalue is number 3 status = 0
+ Column Avalue is number 1 status = 237
+ Column Lvalue is number 2 status = 237
+ Column Xvalue is number 3 status = 237
+ Column Bvalue is number 4 status = 237
+ Column Ivalue is number 5 status = 237
+ Column Jvalue is number 6 status = 237
+ Column Evalue is number 7 status = 237
+ Column Dvalue is number 8 status = 237
+ Column Cvalue is number 9 status = 237
+ Column Mvalue is number 10 status = 237
+ Column is number 0 status = 219
+
+ Information about each column:
+ 15A 16 15 15 Avalue A 1.00 0.00 1234554321
+ 1L 14 1 1 Lvalue m**2 L 1.00 0.00 1234554321
+ 16X 1 16 1 Xvalue cm X 1.00 0.00 1234554321
+ 1B 11 1 1 Bvalue erg/s B 1.00 0.00 99
+ 1I 21 1 2 Ivalue km/s I 1.00 0.00 99
+ 1J 41 1 4 Jvalue J 1.00 0.00 99
+ 1E 42 1 4 Evalue E 1.00 0.00 1234554321
+ 1D 82 1 8 Dvalue D 1.00 0.00 1234554321
+ 1C 83 1 8 Cvalue C 1.00 0.00 1234554321
+ 1M 163 1 16 Mvalue M 1.00 0.00 1234554321
+
+ ftitab status = 0
+ HDU number = 2
+ ftpcl_ status = 0
+
+ ASCII table: rowlen, nrows, tfields, extname: 76 11 5 Test-ASCII
+ Name 1 A15
+ Ivalue 17 I10 m**2
+ Fvalue 28 F14.6 cm
+ Evalue 43 E12.5 erg/s
+ Dvalue 56 D21.14 km/s
+
+ Data values read from ASCII table:
+ first string 1 1 1 1. 1.
+ second string 2 2 2 2. 2.
+ 3 3 3 3. 3.
+ UNDEFINED 4 4 4 4. 4.
+ 5 5 5 5. 5.
+ 6 6 6 6. 6.
+ 7 7 7 7. 7.
+ 8 8 8 8. 8.
+ 9 9 9 9. 9.
+ 10 10 10 10.10.
+ 99 99 99 99.99.
+
+ 1 1.000000 1.00000E+00 1.00000000000000E+00second string
+
+ Column name is number 1 status = 0
+ Column Ivalue is number 2 status = 237
+ Column Fvalue is number 3 status = 237
+ Column Evalue is number 4 status = 237
+ Column Dvalue is number 5 status = 237
+ Column is number 0 status = 219
+ A15 16 1 15 Name 1 1.00 0.00 null1
+ I10 41 1 10 Ivalue 17 m**2 1.00 0.00 null2
+ F14.6 82 1 14 Fvalue 28 cm 1.00 0.00 null3
+ E12.5 42 1 12 Evalue 43 erg/s 1.00 0.00 null4
+ D21.14 82 1 21 Dvalue 56 km/s 1.00 0.00 null5
+
+
+ Data values after inserting 3 rows after row 2:
+ first string 1 1 1 1. 1.
+ second string 2 2 2 2. 2.
+ 0 0 0 0. 0.
+ 0 0 0 0. 0.
+ 0 0 0 0. 0.
+ 3 3 3 3. 3.
+ UNDEFINED 4 4 4 4. 4.
+ 5 5 5 5. 5.
+ 6 6 6 6. 6.
+ 7 7 7 7. 7.
+ 8 8 8 8. 8.
+ 9 9 9 9. 9.
+ 10 10 10 10.10.
+ 99 99 99 99.99.
+
+ Data values after deleting 2 rows at row 10:
+ first string 1 1 1 1. 1.
+ second string 2 2 2 2. 2.
+ 0 0 0 0. 0.
+ 0 0 0 0. 0.
+ 0 0 0 0. 0.
+ 3 3 3 3. 3.
+ UNDEFINED 4 4 4 4. 4.
+ 5 5 5 5. 5.
+ 6 6 6 6. 6.
+ 9 9 9 9. 9.
+ 10 10 10 10.10.
+ 99 99 99 99.99.
+
+ Data values after deleting column 3:
+ first string 1 1 1. 1.
+ second string 2 2 2. 2.
+ 0 0 0. 0.
+ 0 0 0. 0.
+ 0 0 0. 0.
+ 3 3 3. 3.
+ UNDEFINED 4 4 4. 4.
+ 5 5 5. 5.
+ 6 6 6. 6.
+ 9 9 9. 9.
+ 10 10 10.10.
+ 99 99 99.99.
+
+ Data values after inserting column 5:
+ first string 1 1 1. 1. 0
+ second string 2 2 2. 2. 0
+ 0 0 0. 0. 0
+ 0 0 0. 0. 0
+ 0 0 0. 0. 0
+ 3 3 3. 3. 0
+ UNDEFINED 4 4 4. 4. 0
+ 5 5 5. 5. 0
+ 6 6 6. 6. 0
+ 9 9 9. 9. 0
+ 10 10 10.10. 0
+ 99 99 99.99. 0
+ HDU number = 3
+
+ Moved to binary table
+ header contains 37 keywords with room for 70 more
+
+ Binary table: nrows, tfields, extname, pcount: 21 10Test-BINTABLE 0
+ Avalue 15A
+ Lvalue 1L m**2
+ Xvalue 16X cm
+ Bvalue 1B erg/s
+ Ivalue 1I km/s
+ Jvalue 1J
+ Evalue 1E
+ Dvalue 1D
+ Cvalue 1C
+ Mvalue 1M
+
+ Data values read from binary table:
+ Bit column (X) data values:
+ FTFFTTFF FTTTFFFF TTTTFFFF FTTTTTFF FFFFFFFF
+
+ null string column value (should be blank):
+
+ Read columns with ftgcv_:
+ first string F 76 1 1 1 1. 1. 1. -2. 1. -2.
+ second string T 112 2 2 2 2. 2. 3. -4. 3. -4.
+ F 240 3 3 3 3. 3. 5. -6. 5. -6.
+ NOT DEFINED F 124 0 -4 -4 -4. -4. 7. -8. 7. -8.
+ NOT DEFINED T 0 5 5 5 5. 5. 9. -10. 9. -10.
+ NOT DEFINED T 0 0 -6 -6 -6. -6. 11. -12. 11. -12.
+ NOT DEFINED F 0 7 7 7 7. 7. 13. -14. 13. -14.
+ NOT DEFINED F 0 0 -8 -8 -8. -8. 15. -16. 15. -16.
+ NOT DEFINED F 0 9 9 9 9. 9. 17. -18. 17. -18.
+ NOT DEFINED T 0 0 -10 -10 -10. -10. 19. -20. 19. -20.
+ NOT DEFINED F 0 98 98 98 98. 98. 0. 0. 0. 0.
+ NOT DEFINED T 0 12 12 12 12. 12. 0. 0. 0. 0.
+ NOT DEFINED F 0 98 98 98 98. 98. 0. 0. 0. 0.
+ NOT DEFINED F 0 0 -14 -14 -14. -14. 0. 0. 0. 0.
+ NOT DEFINED F 0 0 98 98 98. 98. 0. 0. 0. 0.
+ NOT DEFINED F 0 0 -16 -16 -16. -16. 0. 0. 0. 0.
+ NOT DEFINED T 0 0 98 98 98. 98. 0. 0. 0. 0.
+ NOT DEFINED T 0 0 -18 -18 -18. -18. 0. 0. 0. 0.
+ NOT DEFINED T 0 0 98 98 98. 98. 0. 0. 0. 0.
+ NOT DEFINED T 0 0 -20 -20 -20. -20. 0. 0. 0. 0.
+ NOT DEFINED F 0 0 98 98 98. 98. 0. 0. 0. 0.
+
+ Read columns with ftgcf_:
+ first string F 76 1 1 1 1. 1. 1. -2. 1. -2.
+ second string T 112 2 2 2 2. 2. 3. -4. 3. -4.
+ F 240 3 3 3 3. 3. 5. -6. 5. -6.
+ F 124 0 -4 -4 -4. -4. 7. -8. 7. -8.
+ T 0 5 5 5 5. 5. 9. -10. 9. -10.
+ T 0 0 -6 -6 -6. -6. 11. -12. 11. -12.
+ F 0 7 7 7 7. 7. 13. -14. 13. -14.
+ F 0 0 -8 -8 -8. -8. 15. -16. 15. -16.
+ F 0 9 9 9 9. 9. 17. -18. 17. -18.
+ T 0 0 -10 -10 -10. -10. 19. -20. 19. -20.
+ F 0 99 99
+ T 0 12 12
+ F 0 99 99
+ F 0 0 -14
+ F 0 0 99
+ F 0 0 -16
+ T 0 0 99
+ T 0 0 -18
+ T 0 0 99
+ T 0 0 -20
+ F 0 0 99
+
+ Data values after inserting 3 rows after row 2:
+ first string 1 1 1 1. 1.
+ second string 2 2 2 2. 2.
+ NOT DEFINED 0 0 0 0. 0.
+ NOT DEFINED 0 0 0 0. 0.
+ NOT DEFINED 0 0 0 0. 0.
+ 3 3 3 3. 3.
+ NOT DEFINED 0 -4 -4 -4. -4.
+ NOT DEFINED 5 5 5 5. 5.
+ NOT DEFINED 0 -6 -6 -6. -6.
+ NOT DEFINED 7 7 7 7. 7.
+ NOT DEFINED 0 -8 -8 -8. -8.
+ NOT DEFINED 9 9 9 9. 9.
+ NOT DEFINED 0 -10 -10 -10. -10.
+ NOT DEFINED 98 98 98 98. 98.
+
+ Data values after deleting 2 rows at row 10:
+ first string 1 1 1 1. 1.
+ second string 2 2 2 2. 2.
+ NOT DEFINED 0 0 0 0. 0.
+ NOT DEFINED 0 0 0 0. 0.
+ NOT DEFINED 0 0 0 0. 0.
+ 3 3 3 3. 3.
+ NOT DEFINED 0 -4 -4 -4. -4.
+ NOT DEFINED 5 5 5 5. 5.
+ NOT DEFINED 0 -6 -6 -6. -6.
+ NOT DEFINED 9 9 9 9. 9.
+ NOT DEFINED 0 -10 -10 -10. -10.
+ NOT DEFINED 98 98 98 98. 98.
+
+ Data values after deleting column 6:
+ first string 1 1 1. 1.
+ second string 2 2 2. 2.
+ NOT DEFINED 0 0 0. 0.
+ NOT DEFINED 0 0 0. 0.
+ NOT DEFINED 0 0 0. 0.
+ 3 3 3. 3.
+ NOT DEFINED 0 -4 -4. -4.
+ NOT DEFINED 5 5 5. 5.
+ NOT DEFINED 0 -6 -6. -6.
+ NOT DEFINED 9 9 9. 9.
+ NOT DEFINED 0 -10 -10. -10.
+ NOT DEFINED 98 98 98. 98.
+
+ Data values after inserting column 8:
+ first string 1 1 1. 1. 0
+ second string 2 2 2. 2. 0
+ NOT DEFINED 0 0 0. 0. 0
+ NOT DEFINED 0 0 0. 0. 0
+ NOT DEFINED 0 0 0. 0. 0
+ 3 3 3. 3. 0
+ NOT DEFINED 0 -4 -4. -4. 0
+ NOT DEFINED 5 5 5. 5. 0
+ NOT DEFINED 0 -6 -6. -6. 0
+ NOT DEFINED 9 9 9. 9. 0
+ NOT DEFINED 0 -10 -10. -10. 0
+ NOT DEFINED 98 98 98. 98. 0
+
+ Values after setting 1st 10 elements in column 8 = null:
+ first string 1 1 1. 1. 98
+ second string 2 2 2. 2. 98
+ NOT DEFINED 0 0 0. 0. 98
+ NOT DEFINED 0 0 0. 0. 98
+ NOT DEFINED 0 0 0. 0. 98
+ 3 3 3. 3. 98
+ NOT DEFINED 0 -4 -4. -4. 98
+ NOT DEFINED 5 5 5. 5. 98
+ NOT DEFINED 0 -6 -6. -6. 98
+ NOT DEFINED 9 9 9. 9. 98
+ NOT DEFINED 0 -10 -10. -10. 0
+ NOT DEFINED 98 98 98. 98. 0
+
+ ftibin status = 0
+ HDU number = 2
+ 0 1000 10000 33000 66000 -999
+ 0 1000 10000 32768 65535 -999
+ 0 1000 10000 32800 65500 -999
+
+ 0 1 10 33 66 -999
+ -32768-31768-22768 0 32767 -999
+ -1 9 99 327 654 -999
+
+ Create image extension: ftiimg status = 0
+ HDU number = 3
+
+ Wrote whole 2D array: ftp2di status = 0
+
+ Read whole 2D array: ftg2di status = 0
+ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 0 0 0 0
+ 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 0 0 0 0
+ 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 0 0 0 0
+ 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 0 0 0 0
+ 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 0 0 0 0
+ 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 0 0 0 0
+ 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 0 0 0 0
+ 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 0 0 0 0
+ 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 0 0 0 0
+ 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 0 0 0 0
+ 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 0 0 0 0
+ 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 0 0 0 0
+ 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 0 0 0 0
+ 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 0 0 0 0
+ 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 0 0 0 0
+ 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 0 0 0 0
+ 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 0 0 0 0
+ 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 0 0 0 0
+ 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 0 0 0 0
+ 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 0 0 0 0
+ 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 0 0 0 0
+ 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 0 0 0 0
+ 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 0 0 0 0
+ 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 0 0 0 0
+ 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+
+
+ Wrote subset 2D array: ftpssi status = 0
+
+ Read whole 2D array: ftg2di status = 0
+ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 0 0 0 0
+ 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 0 0 0 0
+ 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 0 0 0 0
+ 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 0 0 0 0
+ 40 41 42 43 0 -1 -2 -3 -4 -5 -6 -7 -8 -9 54 0 0 0 0
+ 50 51 52 53 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 64 0 0 0 0
+ 60 61 62 63 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 74 0 0 0 0
+ 70 71 72 73 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 84 0 0 0 0
+ 80 81 82 83 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 94 0 0 0 0
+ 90 91 92 93 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 104 0 0 0 0
+ 100 101 102 103 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 114 0 0 0 0
+ 110 111 112 113 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 124 0 0 0 0
+ 120 121 122 123 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 134 0 0 0 0
+ 130 131 132 133 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 144 0 0 0 0
+ 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 0 0 0 0
+ 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 0 0 0 0
+ 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 0 0 0 0
+ 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 0 0 0 0
+ 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 0 0 0 0
+ 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 0 0 0 0
+ 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 0 0 0 0
+ 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 0 0 0 0
+ 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 0 0 0 0
+ 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 0 0 0 0
+ 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+
+
+ Read subset of 2D array: ftgsvi status = 0
+ 41 43 -1 -3 -5 71 73 -31 -33 -35
+
+ Create image extension: ftiimg status = 0
+ HDU number = 4
+ Create temporary file: ftinit status = 0
+ Copy image extension to primary array of tmp file.
+ ftcopy status = 0
+ SIMPLE = T / file does conform to FITS standard
+ BITPIX = 16 / number of bits per data pixel
+ NAXIS = 2 / number of data axes
+ NAXIS1 = 15 / length of data axis 1
+ NAXIS2 = 25 / length of data axis 2
+ EXTEND = T / FITS dataset may contain extensions
+ Delete the tmp file: ftdelt status = 0
+ Delete the image extension hdutype, status = 1 0
+ HDU number = 4
+ ftcrhd status = 0
+ Variable length arrays: ftphbn status = 0
+ ftpcl_ status = 0
+ PCOUNT = 4446
+ HDU number = 6
+ A 0
+ L 0 F
+ X 0 F
+ B 1 0
+ I 1 0
+ J 1 0
+ E 1. 0.
+ D 1. 0.
+ Column 8 repeat and offset = 1 14
+ A ab 0
+ L 0 F T
+ X 0 F T
+ B 99 2 0
+ I 99 2 0
+ J 99 2 0
+ E 99. 2. 0.
+ D 99. 2. 0.
+ Column 8 repeat and offset = 2 49
+ A abc 0
+ L 0 F F F
+ X 0 F T F
+ B 1 99 3 0
+ I 1 99 3 0
+ J 1 99 3 0
+ E 1.99. 3. 0.
+ D 1.99. 3. 0.
+ Column 8 repeat and offset = 3 105
+ A abcd 0
+ L 0 F T F F
+ X 0 F T F F
+ B 1 2 99 4 0
+ I 1 2 99 4 0
+ J 1 2 99 4 0
+ E 1. 2.99. 4. 0.
+ D 1. 2.99. 4. 0.
+ Column 8 repeat and offset = 4 182
+ A abcde 0
+ L 0 F T F F T
+ X 0 F T F F T
+ B 1 2 3 99 5 0
+ I 1 2 3 99 5 0
+ J 1 2 3 99 5 0
+ E 1. 2. 3.99. 5. 0.
+ D 1. 2. 3.99. 5. 0.
+ Column 8 repeat and offset = 5 280
+ A abcdef 0
+ L 0 F T F F F T
+ X 0 F T F F T T
+ B 1 2 3 4 99 6 0
+ I 1 2 3 4 99 6 0
+ J 1 2 3 4 99 6 0
+ E 1. 2. 3. 4.99. 6. 0.
+ D 1. 2. 3. 4.99. 6. 0.
+ Column 8 repeat and offset = 6 399
+ A abcdefg 0
+ L 0 F T F F T F F
+ X 0 F T F F T T F
+ B 1 2 3 4 5 99 7 0
+ I 1 2 3 4 5 99 7 0
+ J 1 2 3 4 5 99 7 0
+ E 1. 2. 3. 4. 5.99. 7. 0.
+ D 1. 2. 3. 4. 5.99. 7. 0.
+ Column 8 repeat and offset = 7 539
+ A abcdefgh 0
+ L 0 F T F F T T F F
+ X 0 F T F F T T F F
+ B 1 2 3 4 5 6 99 8 0
+ I 1 2 3 4 5 6 99 8 0
+ J 1 2 3 4 5 6 99 8 0
+ E 1. 2. 3. 4. 5. 6.99. 8. 0.
+ D 1. 2. 3. 4. 5. 6.99. 8. 0.
+ Column 8 repeat and offset = 8 700
+ A abcdefghi 0
+ L 0 F T F F T T F F F
+ X 0 F T F F T T F F F
+ B 1 2 3 4 5 6 7 99 9 0
+ I 1 2 3 4 5 6 7 99 9 0
+ J 1 2 3 4 5 6 7 99 9 0
+ E 1. 2. 3. 4. 5. 6. 7.99. 9. 0.
+ D 1. 2. 3. 4. 5. 6. 7.99. 9. 0.
+ Column 8 repeat and offset = 9 883
+ A abcdefghij 0
+ L 0 F T F F T T F F F T
+ X 0 F T F F T T F F F T
+ B 1 2 3 4 5 6 7 8 99 10 0
+ I 1 2 3 4 5 6 7 8 99 10 0
+ J 1 2 3 4 5 6 7 8 99 10 0
+ E 1. 2. 3. 4. 5. 6. 7. 8.99.10. 0.
+ D 1. 2. 3. 4. 5. 6. 7. 8.99.10. 0.
+ Column 8 repeat and offset = 10 1087
+ A abcdefghijk 0
+ L 0 F T F F T T F F F F T
+ X 0 F T F F T T F F F T T
+ B 1 2 3 4 5 6 7 8 9 99 11 0
+ I 1 2 3 4 5 6 7 8 9 99 11 0
+ J 1 2 3 4 5 6 7 8 9 99 11 0
+ E 1. 2. 3. 4. 5. 6. 7. 8. 9.99.11. 0.
+ D 1. 2. 3. 4. 5. 6. 7. 8. 9.99.11. 0.
+ Column 8 repeat and offset = 11 1312
+ A abcdefghijkl 0
+ L 0 F T F F T T F F F T F T
+ X 0 F T F F T T F F F T T T
+ B 1 2 3 4 5 6 7 8 9 10 99 12 0
+ I 1 2 3 4 5 6 7 8 9 10 99 12 0
+ J 1 2 3 4 5 6 7 8 9 10 99 12 0
+ E 1. 2. 3. 4. 5. 6. 7. 8. 9.10.99.12. 0.
+ D 1. 2. 3. 4. 5. 6. 7. 8. 9.10.99.12. 0.
+ Column 8 repeat and offset = 12 1558
+ A abcdefghijklm 0
+ L 0 F T F F T T F F F T T F F
+ X 0 F T F F T T F F F T T T F
+ B 1 2 3 4 5 6 7 8 9 10 11 99 13 0
+ I 1 2 3 4 5 6 7 8 9 10 11 99 13 0
+ J 1 2 3 4 5 6 7 8 9 10 11 99 13 0
+ E 1. 2. 3. 4. 5. 6. 7. 8. 9.10.11.99.13. 0.
+ D 1. 2. 3. 4. 5. 6. 7. 8. 9.10.11.99.13. 0.
+ Column 8 repeat and offset = 13 1825
+ A abcdefghijklmn 0
+ L 0 F T F F T T F F F T T T F F
+ X 0 F T F F T T F F F T T T F F
+ B 1 2 3 4 5 6 7 8 9 10 11 12 99 14 0
+ I 1 2 3 4 5 6 7 8 9 10 11 12 99 14 0
+ J 1 2 3 4 5 6 7 8 9 10 11 12 99 14 0
+ E 1. 2. 3. 4. 5. 6. 7. 8. 9.10.11.12.99.14. 0.
+ D 1. 2. 3. 4. 5. 6. 7. 8. 9.10.11.12.99.14. 0.
+ Column 8 repeat and offset = 14 2113
+ A abcdefghijklmno 0
+ L 0 F T F F T T F F F T T T F F F
+ X 0 F T F F T T F F F T T T F F F
+ B 1 2 3 4 5 6 7 8 9 10 11 12 13 99 15 0
+ I 1 2 3 4 5 6 7 8 9 10 11 12 13 99 15 0
+ J 1 2 3 4 5 6 7 8 9 10 11 12 13 99 15 0
+ E 1. 2. 3. 4. 5. 6. 7. 8. 9.10.11.12.13.99.15. 0.
+ D 1. 2. 3. 4. 5. 6. 7. 8. 9.10.11.12.13.99.15. 0.
+ Column 8 repeat and offset = 15 2422
+ A abcdefghijklmnop 0
+ L 0 F T F F T T F F F T T T F F F F
+ X 0 F T F F T T F F F T T T F F F F
+ B 1 2 3 4 5 6 7 8 9 10 11 12 13 14 99 16 0
+ I 1 2 3 4 5 6 7 8 9 10 11 12 13 14 99 16 0
+ J 1 2 3 4 5 6 7 8 9 10 11 12 13 14 99 16 0
+ E 1. 2. 3. 4. 5. 6. 7. 8. 9.10.11.12.13.14.99.16. 0.
+ D 1. 2. 3. 4. 5. 6. 7. 8. 9.10.11.12.13.14.99.16. 0.
+ Column 8 repeat and offset = 16 2752
+ A abcdefghijklmnopq 0
+ L 0 F T F F T T F F F T T T F F F F T
+ X 0 F T F F T T F F F T T T F F F F T
+ B 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 99 17 0
+ I 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 99 17 0
+ J 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 99 17 0
+ E 1. 2. 3. 4. 5. 6. 7. 8. 9.10.11.12.13.14.15.99.17. 0.
+ D 1. 2. 3. 4. 5. 6. 7. 8. 9.10.11.12.13.14.15.99.17. 0.
+ Column 8 repeat and offset = 17 3104
+ A abcdefghijklmnopqr 0
+ L 0 F T F F T T F F F T T T F F F F F T
+ X 0 F T F F T T F F F T T T F F F F T T
+ B 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 99 18 0
+ I 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 99 18 0
+ J 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 99 18 0
+ E 1. 2. 3. 4. 5. 6. 7. 8. 9.10.11.12.13.14.15.16.99.18. 0.
+ D 1. 2. 3. 4. 5. 6. 7. 8. 9.10.11.12.13.14.15.16.99.18. 0.
+ Column 8 repeat and offset = 18 3477
+ A abcdefghijklmnopqrs 0
+ L 0 F T F F T T F F F T T T F F F F T F T
+ X 0 F T F F T T F F F T T T F F F F T T T
+ B 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 99 19 0
+ I 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 99 19 0
+ J 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 99 19 0
+ E 1. 2. 3. 4. 5. 6. 7. 8. 9.10.11.12.13.14.15.16.17.99.19. 0.
+ D 1. 2. 3. 4. 5. 6. 7. 8. 9.10.11.12.13.14.15.16.17.99.19. 0.
+ Column 8 repeat and offset = 19 3871
+ A abcdefghijklmnopqrst 0
+ L 0 F T F F T T F F F T T T F F F F T T F T
+ X 0 F T F F T T F F F T T T F F F F T T T T
+ B 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 99 20 0
+ I 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 99 20 0
+ J 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 99 20 0
+ E 1. 2. 3. 4. 5. 6. 7. 8. 9.10.11.12.13.14.15.16.17.18.99.20. 0.
+ D 1. 2. 3. 4. 5. 6. 7. 8. 9.10.11.12.13.14.15.16.17.18.99.20. 0.
+ Column 8 repeat and offset = 20 4286
+
+ Create image extension: ftiimg status = 0
+ ftppr status = 0
+
+ Image values written with ftppr and read with ftgpv:
+ 0 2 4 6 8 10 12 14 16 18 20 22 24 26 F (byte)
+ 0 2 4 6 8 10 12 14 16 18 20 22 24 26 F (short)
+ 0 2 4 6 8 10 12 14 16 18 20 22 24 26 F (int)
+ 0 2 4 6 8 10 12 14 16 18 20 22 24 26 F (long)
+ 0. 2. 4. 6. 8.10.12.14.16.18.20.22.24.26. F (float)
+ 0. 2. 4. 6. 8.10.12.14.16.18.20.22.24.26. F (double)
+
+ Wrote WCS keywords status = 0
+ Read WCS keywords with ftgics status = 0
+ CRVAL1, CRVAL2 = 45.830 63.570
+ CRPIX1, CRPIX2 = 256.000 257.000
+ CDELT1, CDELT2 = -0.00277777 0.00277777
+ Rotation = 0.000 CTYPE =-TAN
+ Calculated sky coord. with ftwldp status = 0
+ Pixels ( 0.500000 0.500000) --> ( 47.385204 62.848968) Sky
+ Calculated pixel coord. with ftxypx status = 0
+ Sky ( 47.385204 62.848968) --> ( 0.500000 0.500000) Pixels
+
+ ftitab status = 0
+ ftpcl status = 0
+ Column values written with ftpcl and read with ftgcl:
+ 0 3 6 9 12 15 18 21 24 27 F (byte)
+ 0 3 6 9 12 15 18 21 24 27 F (short)
+ 0 3 6 9 12 15 18 21 24 27 F (int)
+ 0 3 6 9 12 15 18 21 24 27 F (long)
+ 0. 3. 6. 9.12.15.18.21.24.27. F (float)
+ 0. 3. 6. 9.12.15.18.21.24.27. F (double)
+
+ Repeatedly move to the 1st 4 HDUs of the file:
+
+ Encode checksum: 1234567890.0 -> dCW2fBU0dBU0dBU0
+ Decode checksum: dCW2fBU0dBU0dBU0 -> 1234567890.0
+ DATASUM = '2338390162'
+ ftgcks data checksum, status = 2338390162.0 0
+ ftvcks datastatus, hdustatus, status = 1 1 0
+ ftupck status = 0
+ DATASUM = '2338390162'
+ ftvcks datastatus, hdustatus, status = 1 1 0
+ ftclos status = 0
+
+ Normally, there should be 8 error messages on the
+ stack all regarding 'numerical overflows':
+ Numerical overflow during type conversion while writing FITS data.
+ Numerical overflow during type conversion while writing FITS data.
+ Numerical overflow during type conversion while writing FITS data.
+ Numerical overflow during type conversion while writing FITS data.
+ Numerical overflow during type conversion while writing FITS data.
+ Numerical overflow during type conversion while writing FITS data.
+ Numerical overflow during type conversion while writing FITS data.
+ Numerical overflow during type conversion while writing FITS data.
+
+ Status = 0: OK - no error
diff --git a/pkg/tbtables/cfitsio/testf77.std b/pkg/tbtables/cfitsio/testf77.std
new file mode 100644
index 00000000..ec1281fc
--- /dev/null
+++ b/pkg/tbtables/cfitsio/testf77.std
Binary files differ
diff --git a/pkg/tbtables/cfitsio/testprog.c b/pkg/tbtables/cfitsio/testprog.c
new file mode 100644
index 00000000..cd4724ea
--- /dev/null
+++ b/pkg/tbtables/cfitsio/testprog.c
@@ -0,0 +1,2588 @@
+#include <string.h>
+#include <stdlib.h>
+#include "fitsio.h"
+int main(void);
+
+int main()
+{
+/*
+ This is a big and complicated program that tests most of
+ the cfitsio routines. This code does not represent
+ the most efficient method of reading or writing FITS files
+ because this code is primarily designed to stress the cfitsio
+ library routines.
+*/
+ char asciisum[17];
+ unsigned long checksum, datsum;
+ int datastatus, hdustatus, filemode;
+ int status, simple, bitpix, naxis, extend, hdutype, hdunum, tfields;
+ long ii, jj, extvers;
+ int nkeys, nfound, colnum, typecode, signval,nmsg;
+ char cval;
+ long repeat, offset, width, jnulval;
+ int anynull;
+ float vers;
+ unsigned char xinarray[21], binarray[21], boutarray[21], bnul;
+ short iinarray[21], ioutarray[21], inul;
+ int kinarray[21], koutarray[21], knul;
+ long jinarray[21], joutarray[21], jnul;
+ float einarray[21], eoutarray[21], enul, cinarray[42];
+ double dinarray[21], doutarray[21], dnul, minarray[42];
+ double scale, zero;
+ long naxes[3], pcount, gcount, npixels, nrows, rowlen, firstpix[3];
+ int existkeys, morekeys, keynum;
+
+ char larray[42], larray2[42], colname[70], tdisp[40], nulstr[40];
+ char oskey[] = "value_string";
+ char iskey[21];
+ int olkey = 1;
+ int ilkey;
+ short oshtkey, ishtkey;
+ long ojkey = 11, ijkey;
+ long otint = 12345678;
+ float ofkey = 12.121212;
+ float oekey = 13.131313, iekey;
+ double ogkey = 14.1414141414141414;
+ double odkey = 15.1515151515151515, idkey;
+ double otfrac = .1234567890123456;
+
+ double xrval,yrval,xrpix,yrpix,xinc,yinc,rot,xpos,ypos,xpix,ypix;
+ char xcoordtype[] = "RA---TAN";
+ char ycoordtype[] = "DEC--TAN";
+ char ctype[5];
+
+ char *lsptr; /* pointer to long string value */
+ char comm[73];
+ char *comms[3];
+ char *inskey[21];
+ char *onskey[3] = {"first string", "second string", " "};
+ char *inclist[2] = {"key*", "newikys"};
+ char *exclist[2] = {"key_pr*", "key_pkls"};
+
+ int onlkey[3] = {1, 0, 1}, inlkey[3];
+ long onjkey[3] = {11, 12, 13}, injkey[3];
+ float onfkey[3] = {12.121212, 13.131313, 14.141414};
+ float onekey[3] = {13.131313, 14.141414, 15.151515}, inekey[3];
+ double ongkey[3] = {14.1414141414141414, 15.1515151515151515,
+ 16.1616161616161616};
+ double ondkey[3] = {15.1515151515151515, 16.1616161616161616,
+ 17.1717171717171717}, indkey[3];
+
+ long tbcol[5] = {1, 17, 28, 43, 56};
+
+ char filename[40], card[FLEN_CARD], card2[FLEN_CARD];
+ char keyword[FLEN_KEYWORD];
+ char value[FLEN_VALUE], comment[FLEN_COMMENT];
+ unsigned char uchars[80];
+
+ fitsfile *fptr, *tmpfptr;
+ char *ttype[10], *tform[10], *tunit[10];
+ char tblname[40];
+ char binname[] = "Test-BINTABLE";
+ char templt[] = "testprog.tpt";
+ char errmsg[FLEN_ERRMSG];
+ short imgarray[30][19], imgarray2[20][10];
+ long fpixels[2], lpixels[2], inc[2];
+
+ status = 0;
+ strcpy(tblname, "Test-ASCII");
+
+ ffvers(&vers);
+ printf("CFITSIO TESTPROG, v%.3f\n\n",vers);
+
+ printf("Try opening then closing a nonexistent file:\n");
+ ffopen(&fptr, "tq123x.kjl", READWRITE, &status);
+ printf(" ffopen fptr, status = %lu %d (expect an error)\n",
+ (unsigned long) fptr, status);
+ ffclos(fptr, &status);
+ printf(" ffclos status = %d\n\n", status);
+ ffcmsg();
+ status = 0;
+
+ for (ii = 0; ii < 21; ii++) /* allocate space for string column value */
+ inskey[ii] = (char *) malloc(21);
+
+ for (ii = 0; ii < 10; ii++)
+ {
+ ttype[ii] = (char *) malloc(20);
+ tform[ii] = (char *) malloc(20);
+ tunit[ii] = (char *) malloc(20);
+ }
+
+ comms[0] = comm;
+
+ /* delete previous version of the file, if it exists (with ! prefix) */
+ strcpy(filename, "!testprog.fit");
+
+ status = 0;
+
+ /*
+ #####################
+ # create FITS file #
+ #####################
+ */
+
+ ffinit(&fptr, filename, &status);
+ printf("ffinit create new file status = %d\n", status);
+ if (status)
+ goto errstatus;
+
+ filename[0] = '\0';
+ ffflnm(fptr, filename, &status);
+
+ ffflmd(fptr, &filemode, &status);
+ printf("Name of file = %s, I/O mode = %d\n", filename, filemode);
+ simple = 1;
+ bitpix = 32;
+ naxis = 2;
+ naxes[0] = 10;
+ naxes[1] = 2;
+ npixels = 20;
+ pcount = 0;
+ gcount = 1;
+ extend = 1;
+ /*
+ ############################
+ # write single keywords #
+ ############################
+ */
+
+ if (ffphps(fptr, bitpix, naxis, naxes, &status) > 0)
+ printf("ffphps status = %d\n", status);
+
+ if (ffprec(fptr,
+ "key_prec= 'This keyword was written by fxprec' / comment goes here",
+ &status) > 0 )
+ printf("ffprec status = %d\n", status);
+
+ printf("\ntest writing of long string keywords:\n");
+ strcpy(card, "1234567890123456789012345678901234567890");
+ strcat(card, "12345678901234567890123456789012345");
+ ffpkys(fptr, "card1", card, "", &status);
+ ffgkey(fptr, "card1", card2, comment, &status);
+ printf(" %s\n%s\n", card, card2);
+
+ strcpy(card, "1234567890123456789012345678901234567890");
+ strcat(card, "123456789012345678901234'6789012345");
+ ffpkys(fptr, "card2", card, "", &status);
+ ffgkey(fptr, "card2", card2, comment, &status);
+ printf(" %s\n%s\n", card, card2);
+
+ strcpy(card, "1234567890123456789012345678901234567890");
+ strcat(card, "123456789012345678901234''789012345");
+ ffpkys(fptr, "card3", card, "", &status);
+ ffgkey(fptr, "card3", card2, comment, &status);
+ printf(" %s\n%s\n", card, card2);
+
+ strcpy(card, "1234567890123456789012345678901234567890");
+ strcat(card, "123456789012345678901234567'9012345");
+ ffpkys(fptr, "card4", card, "", &status);
+ ffgkey(fptr, "card4", card2, comment, &status);
+ printf(" %s\n%s\n", card, card2);
+
+ if (ffpkys(fptr, "key_pkys", oskey, "fxpkys comment", &status) > 0)
+ printf("ffpkys status = %d\n", status);
+
+ if (ffpkyl(fptr, "key_pkyl", olkey, "fxpkyl comment", &status) > 0)
+ printf("ffpkyl status = %d\n", status);
+
+ if (ffpkyj(fptr, "key_pkyj", ojkey, "fxpkyj comment", &status) > 0)
+ printf("ffpkyj status = %d\n", status);
+
+ if (ffpkyf(fptr, "key_pkyf", ofkey, 5, "fxpkyf comment", &status) > 0)
+ printf("ffpkyf status = %d\n", status);
+
+ if (ffpkye(fptr, "key_pkye", oekey, 6, "fxpkye comment", &status) > 0)
+ printf("ffpkye status = %d\n", status);
+
+ if (ffpkyg(fptr, "key_pkyg", ogkey, 14, "fxpkyg comment", &status) > 0)
+ printf("ffpkyg status = %d\n", status);
+
+ if (ffpkyd(fptr, "key_pkyd", odkey, 14, "fxpkyd comment", &status) > 0)
+ printf("ffpkyd status = %d\n", status);
+
+ if (ffpkyc(fptr, "key_pkyc", onekey, 6, "fxpkyc comment", &status) > 0)
+ printf("ffpkyc status = %d\n", status);
+
+ if (ffpkym(fptr, "key_pkym", ondkey, 14, "fxpkym comment", &status) > 0)
+ printf("ffpkym status = %d\n", status);
+
+ if (ffpkfc(fptr, "key_pkfc", onekey, 6, "fxpkfc comment", &status) > 0)
+ printf("ffpkfc status = %d\n", status);
+
+ if (ffpkfm(fptr, "key_pkfm", ondkey, 14, "fxpkfm comment", &status) > 0)
+ printf("ffpkfm status = %d\n", status);
+
+ if (ffpkls(fptr, "key_pkls",
+"This is a very long string value that is continued over more than one keyword.",
+ "fxpkls comment", &status) > 0)
+ printf("ffpkls status = %d\n", status);
+
+ if (ffplsw(fptr, &status) > 0 )
+ printf("ffplsw status = %d\n", status);
+
+ if (ffpkyt(fptr, "key_pkyt", otint, otfrac, "fxpkyt comment", &status) > 0)
+ printf("ffpkyt status = %d\n", status);
+
+ if (ffpcom(fptr, " This keyword was written by fxpcom.", &status) > 0)
+ printf("ffpcom status = %d\n", status);
+
+ if (ffphis(fptr, " This keyword written by fxphis (w/ 2 leading spaces).",
+ &status) > 0)
+ printf("ffphis status = %d\n", status);
+
+ if (ffpdat(fptr, &status) > 0)
+ {
+ printf("ffpdat status = %d\n", status);
+ goto errstatus;
+ }
+
+ /*
+ ###############################
+ # write arrays of keywords #
+ ###############################
+ */
+ nkeys = 3;
+
+ comms[0] = comm; /* use the inskey array of pointers for the comments */
+
+ strcpy(comm, "fxpkns comment&");
+ if (ffpkns(fptr, "ky_pkns", 1, nkeys, onskey, comms, &status) > 0)
+ printf("ffpkns status = %d\n", status);
+
+ strcpy(comm, "fxpknl comment&");
+ if (ffpknl(fptr, "ky_pknl", 1, nkeys, onlkey, comms, &status) > 0)
+ printf("ffpknl status = %d\n", status);
+
+ strcpy(comm, "fxpknj comment&");
+ if (ffpknj(fptr, "ky_pknj", 1, nkeys, onjkey, comms, &status) > 0)
+ printf("ffpknj status = %d\n", status);
+
+ strcpy(comm, "fxpknf comment&");
+ if (ffpknf(fptr, "ky_pknf", 1, nkeys, onfkey, 5, comms, &status) > 0)
+ printf("ffpknf status = %d\n", status);
+
+ strcpy(comm, "fxpkne comment&");
+ if (ffpkne(fptr, "ky_pkne", 1, nkeys, onekey, 6, comms, &status) > 0)
+ printf("ffpkne status = %d\n", status);
+
+ strcpy(comm, "fxpkng comment&");
+ if (ffpkng(fptr, "ky_pkng", 1, nkeys, ongkey, 13, comms, &status) > 0)
+ printf("ffpkng status = %d\n", status);
+
+ strcpy(comm, "fxpknd comment&");
+ if (ffpknd(fptr, "ky_pknd", 1, nkeys, ondkey, 14, comms, &status) > 0)
+ {
+ printf("ffpknd status = %d\n", status);
+ goto errstatus;
+ }
+ /*
+ ############################
+ # write generic keywords #
+ ############################
+ */
+
+ strcpy(oskey, "1");
+ if (ffpky(fptr, TSTRING, "tstring", oskey, "tstring comment", &status) > 0)
+ printf("ffpky status = %d\n", status);
+
+ olkey = TLOGICAL;
+ if (ffpky(fptr, TLOGICAL, "tlogical", &olkey, "tlogical comment",
+ &status) > 0)
+ printf("ffpky status = %d\n", status);
+
+ cval = TBYTE;
+ if (ffpky(fptr, TBYTE, "tbyte", &cval, "tbyte comment", &status) > 0)
+ printf("ffpky status = %d\n", status);
+
+ oshtkey = TSHORT;
+ if (ffpky(fptr, TSHORT, "tshort", &oshtkey, "tshort comment", &status) > 0)
+ printf("ffpky status = %d\n", status);
+
+ olkey = TINT;
+ if (ffpky(fptr, TINT, "tint", &olkey, "tint comment", &status) > 0)
+ printf("ffpky status = %d\n", status);
+
+ ojkey = TLONG;
+ if (ffpky(fptr, TLONG, "tlong", &ojkey, "tlong comment", &status) > 0)
+ printf("ffpky status = %d\n", status);
+
+ oekey = TFLOAT;
+ if (ffpky(fptr, TFLOAT, "tfloat", &oekey, "tfloat comment", &status) > 0)
+ printf("ffpky status = %d\n", status);
+
+ odkey = TDOUBLE;
+ if (ffpky(fptr, TDOUBLE, "tdouble", &odkey, "tdouble comment",
+ &status) > 0)
+ printf("ffpky status = %d\n", status);
+
+ /*
+ ############################
+ # write data #
+ ############################
+ */
+ /* define the null value (must do this before writing any data) */
+ if (ffpkyj(fptr, "BLANK", -99, "value to use for undefined pixels",
+ &status) > 0)
+ printf("BLANK keyword status = %d\n", status);
+
+ /* initialize arrays of values to write to primary array */
+ for (ii = 0; ii < npixels; ii++)
+ {
+ boutarray[ii] = ii + 1;
+ ioutarray[ii] = ii + 1;
+ joutarray[ii] = ii + 1;
+ eoutarray[ii] = ii + 1;
+ doutarray[ii] = ii + 1;
+ }
+
+ /* write a few pixels with each datatype */
+ /* set the last value in each group of 4 as undefined */
+
+/*
+ ffpprb(fptr, 1, 1, 2, &boutarray[0], &status);
+ ffppri(fptr, 1, 5, 2, &ioutarray[4], &status);
+ ffpprj(fptr, 1, 9, 2, &joutarray[8], &status);
+ ffppre(fptr, 1, 13, 2, &eoutarray[12], &status);
+ ffpprd(fptr, 1, 17, 2, &doutarray[16], &status);
+*/
+
+/* test the newer ffpx routine, instead of the older ffppr_ routines */
+ firstpix[0]=1;
+ firstpix[1]=1;
+ ffppx(fptr, TBYTE, firstpix, 2, &boutarray[0], &status);
+ firstpix[0]=5;
+ ffppx(fptr, TSHORT, firstpix, 2, &ioutarray[4], &status);
+ firstpix[0]=9;
+ ffppx(fptr, TLONG, firstpix, 2, &joutarray[8], &status);
+ firstpix[0]=3;
+ firstpix[1]=2;
+ ffppx(fptr, TFLOAT, firstpix, 2, &eoutarray[12], &status);
+ firstpix[0]=7;
+ ffppx(fptr, TDOUBLE, firstpix, 2, &doutarray[16], &status);
+
+/*
+ ffppnb(fptr, 1, 3, 2, &boutarray[2], 4, &status);
+ ffppni(fptr, 1, 7, 2, &ioutarray[6], 8, &status);
+ ffppnj(fptr, 1, 11, 2, &joutarray[10], 12, &status);
+ ffppne(fptr, 1, 15, 2, &eoutarray[14], 16., &status);
+ ffppnd(fptr, 1, 19, 2, &doutarray[18], 20., &status);
+*/
+ firstpix[0]=3;
+ firstpix[1]=1;
+ bnul = 4;
+ ffppxn(fptr, TBYTE, firstpix, 2, &boutarray[2], &bnul, &status);
+ firstpix[0]=7;
+ inul = 8;
+ ffppxn(fptr, TSHORT, firstpix, 2, &ioutarray[6], &inul, &status);
+ firstpix[0]=1;
+ firstpix[1]=2;
+ jnul = 12;
+ ffppxn(fptr, TLONG, firstpix, 2, &joutarray[10], &jnul, &status);
+ firstpix[0]=5;
+ enul = 16.;
+ ffppxn(fptr, TFLOAT, firstpix, 2, &eoutarray[14], &enul, &status);
+ firstpix[0]=9;
+ dnul = 20.;
+ ffppxn(fptr, TDOUBLE, firstpix, 2, &doutarray[18], &dnul, &status);
+
+ ffppru(fptr, 1, 1, 1, &status);
+
+
+ if (status > 0)
+ {
+ printf("ffppnx status = %d\n", status);
+ goto errstatus;
+ }
+
+ ffflus(fptr, &status); /* flush all data to the disk file */
+ printf("ffflus status = %d\n", status);
+ printf("HDU number = %d\n", ffghdn(fptr, &hdunum));
+
+ /*
+ ############################
+ # read data #
+ ############################
+ */
+ /* read back the data, setting null values = 99 */
+ printf("\nValues read back from primary array (99 = null pixel)\n");
+ printf("The 1st, and every 4th pixel should be undefined:\n");
+
+ anynull = 0;
+ ffgpvb(fptr, 1, 1, 10, 99, binarray, &anynull, &status);
+
+ ffgpvb(fptr, 1, 11, 10, 99, &binarray[10], &anynull, &status);
+
+ for (ii = 0; ii < npixels; ii++)
+ printf(" %2d", binarray[ii]);
+ printf(" %d (ffgpvb)\n", anynull);
+
+ ffgpvi(fptr, 1, 1, npixels, 99, iinarray, &anynull, &status);
+
+ for (ii = 0; ii < npixels; ii++)
+ printf(" %2d", iinarray[ii]);
+ printf(" %d (ffgpvi)\n", anynull);
+
+ ffgpvj(fptr, 1, 1, npixels, 99, jinarray, &anynull, &status);
+
+ for (ii = 0; ii < npixels; ii++)
+ printf(" %2ld", jinarray[ii]);
+ printf(" %d (ffgpvj)\n", anynull);
+
+ ffgpve(fptr, 1, 1, npixels, 99., einarray, &anynull, &status);
+
+ for (ii = 0; ii < npixels; ii++)
+ printf(" %2.0f", einarray[ii]);
+ printf(" %d (ffgpve)\n", anynull);
+
+ ffgpvd(fptr, 1, 1, 10, 99., dinarray, &anynull, &status);
+ ffgpvd(fptr, 1, 11, 10, 99., &dinarray[10], &anynull, &status);
+
+ for (ii = 0; ii < npixels; ii++)
+ printf(" %2.0f", dinarray[ii]);
+ printf(" %d (ffgpvd)\n", anynull);
+
+ if (status > 0)
+ {
+ printf("ERROR: ffgpv_ status = %d\n", status);
+ goto errstatus;
+ }
+ if (anynull == 0)
+ printf("ERROR: ffgpv_ did not detect null values\n");
+
+ /* reset the output null value to the expected input value */
+ for (ii = 3; ii < npixels; ii += 4)
+ {
+ boutarray[ii] = 99;
+ ioutarray[ii] = 99;
+ joutarray[ii] = 99;
+ eoutarray[ii] = 99.;
+ doutarray[ii] = 99.;
+ }
+ ii = 0;
+ boutarray[ii] = 99;
+ ioutarray[ii] = 99;
+ joutarray[ii] = 99;
+ eoutarray[ii] = 99.;
+ doutarray[ii] = 99.;
+
+ /* compare the output with the input; flag any differences */
+ for (ii = 0; ii < npixels; ii++)
+ {
+ if (boutarray[ii] != binarray[ii])
+ printf("bout != bin = %u %u \n", boutarray[ii], binarray[ii]);
+
+ if (ioutarray[ii] != iinarray[ii])
+ printf("iout != iin = %d %d \n", ioutarray[ii], iinarray[ii]);
+
+ if (joutarray[ii] != jinarray[ii])
+ printf("jout != jin = %ld %ld \n", joutarray[ii], jinarray[ii]);
+
+ if (eoutarray[ii] != einarray[ii])
+ printf("eout != ein = %f %f \n", eoutarray[ii], einarray[ii]);
+
+ if (doutarray[ii] != dinarray[ii])
+ printf("dout != din = %f %f \n", doutarray[ii], dinarray[ii]);
+ }
+
+ for (ii = 0; ii < npixels; ii++)
+ {
+ binarray[ii] = 0;
+ iinarray[ii] = 0;
+ jinarray[ii] = 0;
+ einarray[ii] = 0.;
+ dinarray[ii] = 0.;
+ }
+
+ anynull = 0;
+ ffgpfb(fptr, 1, 1, 10, binarray, larray, &anynull, &status);
+ ffgpfb(fptr, 1, 11, 10, &binarray[10], &larray[10], &anynull, &status);
+
+ for (ii = 0; ii < npixels; ii++)
+ if (larray[ii])
+ printf(" *");
+ else
+ printf(" %2d", binarray[ii]);
+ printf(" %d (ffgpfb)\n", anynull);
+
+ ffgpfi(fptr, 1, 1, npixels, iinarray, larray, &anynull, &status);
+
+ for (ii = 0; ii < npixels; ii++)
+ if (larray[ii])
+ printf(" *");
+ else
+ printf(" %2d", iinarray[ii]);
+ printf(" %d (ffgpfi)\n", anynull);
+
+ ffgpfj(fptr, 1, 1, npixels, jinarray, larray, &anynull, &status);
+
+ for (ii = 0; ii < npixels; ii++)
+ if (larray[ii])
+ printf(" *");
+ else
+ printf(" %2ld", jinarray[ii]);
+ printf(" %d (ffgpfj)\n", anynull);
+
+ ffgpfe(fptr, 1, 1, npixels, einarray, larray, &anynull, &status);
+
+ for (ii = 0; ii < npixels; ii++)
+ if (larray[ii])
+ printf(" *");
+ else
+ printf(" %2.0f", einarray[ii]);
+ printf(" %d (ffgpfe)\n", anynull);
+
+ ffgpfd(fptr, 1, 1, 10, dinarray, larray, &anynull, &status);
+ ffgpfd(fptr, 1, 11, 10, &dinarray[10], &larray[10], &anynull, &status);
+
+ for (ii = 0; ii < npixels; ii++)
+ if (larray[ii])
+ printf(" *");
+ else
+ printf(" %2.0f", dinarray[ii]);
+ printf(" %d (ffgpfd)\n", anynull);
+
+ if (status > 0)
+ {
+ printf("ERROR: ffgpf_ status = %d\n", status);
+ goto errstatus;
+ }
+ if (anynull == 0)
+ printf("ERROR: ffgpf_ did not detect null values\n");
+
+
+ /*
+ ##########################################
+ # close and reopen file multiple times #
+ ##########################################
+ */
+
+ for (ii = 0; ii < 10; ii++)
+ {
+ if (ffclos(fptr, &status) > 0)
+ {
+ printf("ERROR in ftclos (1) = %d", status);
+ goto errstatus;
+ }
+
+ if (ffopen(&fptr, filename, READWRITE, &status) > 0)
+ {
+ printf("ERROR: ffopen open file status = %d\n", status);
+ goto errstatus;
+ }
+ }
+ printf("\nClosed then reopened the FITS file 10 times.\n");
+ printf("HDU number = %d\n", ffghdn(fptr, &hdunum));
+
+ filename[0] = '\0';
+ ffflnm(fptr, filename, &status);
+
+ ffflmd(fptr, &filemode, &status);
+ printf("Name of file = %s, I/O mode = %d\n", filename, filemode);
+
+ /*
+ ############################
+ # read single keywords #
+ ############################
+ */
+
+ simple = 0;
+ bitpix = 0;
+ naxis = 0;
+ naxes[0] = 0;
+ naxes[1] = 0;
+ pcount = -99;
+ gcount = -99;
+ extend = -99;
+ printf("\nRead back keywords:\n");
+ ffghpr(fptr, 99, &simple, &bitpix, &naxis, naxes, &pcount,
+ &gcount, &extend, &status);
+ printf("simple = %d, bitpix = %d, naxis = %d, naxes = (%ld, %ld)\n",
+ simple, bitpix, naxis, naxes[0], naxes[1]);
+ printf(" pcount = %ld, gcount = %ld, extend = %d\n",
+ pcount, gcount, extend);
+
+ ffgrec(fptr, 9, card, &status);
+ printf("%s\n", card);
+ if (strncmp(card, "KEY_PREC= 'This", 15) )
+ printf("ERROR in ffgrec\n");
+
+ ffgkyn(fptr, 9, keyword, value, comment, &status);
+ printf("%s : %s : %s :\n",keyword, value, comment);
+ if (strncmp(keyword, "KEY_PREC", 8) )
+ printf("ERROR in ffgkyn: %s\n", keyword);
+
+ ffgcrd(fptr, keyword, card, &status);
+ printf("%s\n", card);
+
+ if (strncmp(keyword, card, 8) )
+ printf("ERROR in ffgcrd: %s\n", keyword);
+
+ ffgkey(fptr, "KY_PKNS1", value, comment, &status);
+ printf("KY_PKNS1 : %s : %s :\n", value, comment);
+
+ if (strncmp(value, "'first string'", 14) )
+ printf("ERROR in ffgkey: %s\n", value);
+
+ ffgkys(fptr, "key_pkys", iskey, comment, &status);
+ printf("KEY_PKYS %s %s %d\n", iskey, comment, status);
+
+ ffgkyl(fptr, "key_pkyl", &ilkey, comment, &status);
+ printf("KEY_PKYL %d %s %d\n", ilkey, comment, status);
+
+ ffgkyj(fptr, "KEY_PKYJ", &ijkey, comment, &status);
+ printf("KEY_PKYJ %ld %s %d\n",ijkey, comment, status);
+
+ ffgkye(fptr, "KEY_PKYJ", &iekey, comment, &status);
+ printf("KEY_PKYJ %f %s %d\n",iekey, comment, status);
+
+ ffgkyd(fptr, "KEY_PKYJ", &idkey, comment, &status);
+ printf("KEY_PKYJ %f %s %d\n",idkey, comment, status);
+
+ if (ijkey != 11 || iekey != 11. || idkey != 11.)
+ printf("ERROR in ffgky[jed]: %ld, %f, %f\n",ijkey, iekey, idkey);
+
+ iskey[0] = '\0';
+ ffgky(fptr, TSTRING, "key_pkys", iskey, comment, &status);
+ printf("KEY_PKY S %s %s %d\n", iskey, comment, status);
+
+ ilkey = 0;
+ ffgky(fptr, TLOGICAL, "key_pkyl", &ilkey, comment, &status);
+ printf("KEY_PKY L %d %s %d\n", ilkey, comment, status);
+
+ ffgky(fptr, TBYTE, "KEY_PKYJ", &cval, comment, &status);
+ printf("KEY_PKY BYTE %d %s %d\n",cval, comment, status);
+
+ ffgky(fptr, TSHORT, "KEY_PKYJ", &ishtkey, comment, &status);
+ printf("KEY_PKY SHORT %d %s %d\n",ishtkey, comment, status);
+
+ ffgky(fptr, TINT, "KEY_PKYJ", &ilkey, comment, &status);
+ printf("KEY_PKY INT %d %s %d\n",ilkey, comment, status);
+
+ ijkey = 0;
+ ffgky(fptr, TLONG, "KEY_PKYJ", &ijkey, comment, &status);
+ printf("KEY_PKY J %ld %s %d\n",ijkey, comment, status);
+
+ iekey = 0;
+ ffgky(fptr, TFLOAT, "KEY_PKYE", &iekey, comment, &status);
+ printf("KEY_PKY E %f %s %d\n",iekey, comment, status);
+
+ idkey = 0;
+ ffgky(fptr, TDOUBLE, "KEY_PKYD", &idkey, comment, &status);
+ printf("KEY_PKY D %f %s %d\n",idkey, comment, status);
+
+ ffgkyd(fptr, "KEY_PKYF", &idkey, comment, &status);
+ printf("KEY_PKYF %f %s %d\n",idkey, comment, status);
+
+ ffgkyd(fptr, "KEY_PKYE", &idkey, comment, &status);
+ printf("KEY_PKYE %f %s %d\n",idkey, comment, status);
+
+ ffgkyd(fptr, "KEY_PKYG", &idkey, comment, &status);
+ printf("KEY_PKYG %.14f %s %d\n",idkey, comment, status);
+
+ ffgkyd(fptr, "KEY_PKYD", &idkey, comment, &status);
+ printf("KEY_PKYD %.14f %s %d\n",idkey, comment, status);
+
+ ffgkyc(fptr, "KEY_PKYC", inekey, comment, &status);
+ printf("KEY_PKYC %f %f %s %d\n",inekey[0], inekey[1], comment, status);
+
+ ffgkyc(fptr, "KEY_PKFC", inekey, comment, &status);
+ printf("KEY_PKFC %f %f %s %d\n",inekey[0], inekey[1], comment, status);
+
+ ffgkym(fptr, "KEY_PKYM", indkey, comment, &status);
+ printf("KEY_PKYM %f %f %s %d\n",indkey[0], indkey[1], comment, status);
+
+ ffgkym(fptr, "KEY_PKFM", indkey, comment, &status);
+ printf("KEY_PKFM %f %f %s %d\n",indkey[0], indkey[1], comment, status);
+
+ ffgkyt(fptr, "KEY_PKYT", &ijkey, &idkey, comment, &status);
+ printf("KEY_PKYT %ld %.14f %s %d\n",ijkey, idkey, comment, status);
+
+ ffpunt(fptr, "KEY_PKYJ", "km/s/Mpc", &status);
+ ijkey = 0;
+ ffgky(fptr, TLONG, "KEY_PKYJ", &ijkey, comment, &status);
+ printf("KEY_PKY J %ld %s %d\n",ijkey, comment, status);
+ ffgunt(fptr,"KEY_PKYJ", comment, &status);
+ printf("KEY_PKY units = %s\n",comment);
+
+ ffpunt(fptr, "KEY_PKYJ", "", &status);
+ ijkey = 0;
+ ffgky(fptr, TLONG, "KEY_PKYJ", &ijkey, comment, &status);
+ printf("KEY_PKY J %ld %s %d\n",ijkey, comment, status);
+ ffgunt(fptr,"KEY_PKYJ", comment, &status);
+ printf("KEY_PKY units = %s\n",comment);
+
+ ffpunt(fptr, "KEY_PKYJ", "feet/second/second", &status);
+ ijkey = 0;
+ ffgky(fptr, TLONG, "KEY_PKYJ", &ijkey, comment, &status);
+ printf("KEY_PKY J %ld %s %d\n",ijkey, comment, status);
+ ffgunt(fptr,"KEY_PKYJ", comment, &status);
+ printf("KEY_PKY units = %s\n",comment);
+
+ ffgkls(fptr, "key_pkls", &lsptr, comment, &status);
+ printf("KEY_PKLS long string value = \n%s\n", lsptr);
+
+ /* free the memory for the long string value */
+ free(lsptr);
+
+ /* get size and position in header */
+ ffghps(fptr, &existkeys, &keynum, &status);
+ printf("header contains %d keywords; located at keyword %d \n",existkeys,
+ keynum);
+
+ /*
+ ############################
+ # read array keywords #
+ ############################
+ */
+ ffgkns(fptr, "ky_pkns", 1, 3, inskey, &nfound, &status);
+ printf("ffgkns: %s, %s, %s\n", inskey[0], inskey[1], inskey[2]);
+ if (nfound != 3 || status > 0)
+ printf("\nERROR in ffgkns %d, %d\n", nfound, status);
+
+ ffgknl(fptr, "ky_pknl", 1, 3, inlkey, &nfound, &status);
+ printf("ffgknl: %d, %d, %d\n", inlkey[0], inlkey[1], inlkey[2]);
+ if (nfound != 3 || status > 0)
+ printf("\nERROR in ffgknl %d, %d\n", nfound, status);
+
+ ffgknj(fptr, "ky_pknj", 1, 3, injkey, &nfound, &status);
+ printf("ffgknj: %ld, %ld, %ld\n", injkey[0], injkey[1], injkey[2]);
+ if (nfound != 3 || status > 0)
+ printf("\nERROR in ffgknj %d, %d\n", nfound, status);
+
+ ffgkne(fptr, "ky_pkne", 1, 3, inekey, &nfound, &status);
+ printf("ffgkne: %f, %f, %f\n", inekey[0], inekey[1], inekey[2]);
+ if (nfound != 3 || status > 0)
+ printf("\nERROR in ffgkne %d, %d\n", nfound, status);
+
+ ffgknd(fptr, "ky_pknd", 1, 3, indkey, &nfound, &status);
+ printf("ffgknd: %f, %f, %f\n", indkey[0], indkey[1], indkey[2]);
+ if (nfound != 3 || status > 0)
+ printf("\nERROR in ffgknd %d, %d\n", nfound, status);
+
+ /* get position of HISTORY keyword for subsequent deletes and inserts */
+ ffgcrd(fptr, "HISTORY", card, &status);
+ ffghps(fptr, &existkeys, &keynum, &status);
+ keynum -= 2;
+
+ printf("\nBefore deleting the HISTORY and DATE keywords...\n");
+ for (ii = keynum; ii <= keynum + 3; ii++)
+ {
+ ffgrec(fptr, ii, card, &status);
+ printf("%.8s\n", card); /* don't print date value, so that */
+ } /* the output will always be the same */
+ /*
+ ############################
+ # delete keywords #
+ ############################
+ */
+
+ ffdrec(fptr, keynum + 1, &status);
+ ffdkey(fptr, "DATE", &status);
+
+ printf("\nAfter deleting the keywords...\n");
+ for (ii = keynum; ii <= keynum + 1; ii++)
+ {
+ ffgrec(fptr, ii, card, &status);
+ printf("%s\n", card);
+ }
+
+ if (status > 0)
+ printf("\nERROR deleting keywords\n");
+ /*
+ ############################
+ # insert keywords #
+ ############################
+ */
+ keynum += 4;
+ ffirec(fptr, keynum - 3, "KY_IREC = 'This keyword inserted by fxirec'",
+ &status);
+ ffikys(fptr, "KY_IKYS", "insert_value_string", "ikys comment", &status);
+ ffikyj(fptr, "KY_IKYJ", 49, "ikyj comment", &status);
+ ffikyl(fptr, "KY_IKYL", 1, "ikyl comment", &status);
+ ffikye(fptr, "KY_IKYE", 12.3456, 4, "ikye comment", &status);
+ ffikyd(fptr, "KY_IKYD", 12.345678901234567, 14, "ikyd comment", &status);
+ ffikyf(fptr, "KY_IKYF", 12.3456, 4, "ikyf comment", &status);
+ ffikyg(fptr, "KY_IKYG", 12.345678901234567, 13, "ikyg comment", &status);
+
+ printf("\nAfter inserting the keywords...\n");
+ for (ii = keynum - 4; ii <= keynum + 5; ii++)
+ {
+ ffgrec(fptr, ii, card, &status);
+ printf("%s\n", card);
+ }
+
+ if (status > 0)
+ printf("\nERROR inserting keywords\n");
+ /*
+ ############################
+ # modify keywords #
+ ############################
+ */
+ ffmrec(fptr, keynum - 4, "COMMENT This keyword was modified by fxmrec", &status);
+ ffmcrd(fptr, "KY_IREC", "KY_MREC = 'This keyword was modified by fxmcrd'",
+ &status);
+ ffmnam(fptr, "KY_IKYS", "NEWIKYS", &status);
+
+ ffmcom(fptr, "KY_IKYJ","This is a modified comment", &status);
+ ffmkyj(fptr, "KY_IKYJ", 50, "&", &status);
+ ffmkyl(fptr, "KY_IKYL", 0, "&", &status);
+ ffmkys(fptr, "NEWIKYS", "modified_string", "&", &status);
+ ffmkye(fptr, "KY_IKYE", -12.3456, 4, "&", &status);
+ ffmkyd(fptr, "KY_IKYD", -12.345678901234567, 14, "modified comment",
+ &status);
+ ffmkyf(fptr, "KY_IKYF", -12.3456, 4, "&", &status);
+ ffmkyg(fptr, "KY_IKYG", -12.345678901234567, 13, "&", &status);
+
+ printf("\nAfter modifying the keywords...\n");
+ for (ii = keynum - 4; ii <= keynum + 5; ii++)
+ {
+ ffgrec(fptr, ii, card, &status);
+ printf("%s\n", card);
+ }
+ if (status > 0)
+ printf("\nERROR modifying keywords\n");
+
+ /*
+ ############################
+ # update keywords #
+ ############################
+ */
+ ffucrd(fptr, "KY_MREC", "KY_UCRD = 'This keyword was updated by fxucrd'",
+ &status);
+
+ ffukyj(fptr, "KY_IKYJ", 51, "&", &status);
+ ffukyl(fptr, "KY_IKYL", 1, "&", &status);
+ ffukys(fptr, "NEWIKYS", "updated_string", "&", &status);
+ ffukye(fptr, "KY_IKYE", -13.3456, 4, "&", &status);
+ ffukyd(fptr, "KY_IKYD", -13.345678901234567, 14, "modified comment",
+ &status);
+ ffukyf(fptr, "KY_IKYF", -13.3456, 4, "&", &status);
+ ffukyg(fptr, "KY_IKYG", -13.345678901234567, 13, "&", &status);
+
+ printf("\nAfter updating the keywords...\n");
+ for (ii = keynum - 4; ii <= keynum + 5; ii++)
+ {
+ ffgrec(fptr, ii, card, &status);
+ printf("%s\n", card);
+ }
+ if (status > 0)
+ printf("\nERROR modifying keywords\n");
+
+ /* move to top of header and find keywords using wild cards */
+ ffgrec(fptr, 0, card, &status);
+
+ printf("\nKeywords found using wildcard search (should be 13)...\n");
+ nfound = 0;
+ while (!ffgnxk(fptr,inclist, 2, exclist, 2, card, &status))
+ {
+ nfound++;
+ printf("%s\n", card);
+ }
+ if (nfound != 13)
+ {
+ printf("\nERROR reading keywords using wildcards (ffgnxk)\n");
+ goto errstatus;
+ }
+ status = 0;
+
+ /*
+ ############################
+ # copy index keyword #
+ ############################
+ */
+ ffcpky(fptr, fptr, 1, 4, "KY_PKNE", &status);
+ ffgkne(fptr, "ky_pkne", 2, 4, inekey, &nfound, &status);
+ printf("\nCopied keyword: ffgkne: %f, %f, %f\n", inekey[0], inekey[1],
+ inekey[2]);
+
+ if (status > 0)
+ {
+ printf("\nERROR in ffgkne %d, %d\n", nfound, status);
+ goto errstatus;
+ }
+
+ /*
+ ######################################
+ # modify header using template file #
+ ######################################
+ */
+ if (ffpktp(fptr, templt, &status))
+ {
+ printf("\nERROR returned by ffpktp:\n");
+ printf("Could not open or process the file 'testprog.tpt'.\n");
+ printf(" This file is included with the CFITSIO distribution\n");
+ printf(" and should be copied into the current directory\n");
+ printf(" before running the testprog program.\n");
+ status = 0;
+ }
+ printf("Updated header using template file (ffpktp)\n");
+ /*
+ ############################
+ # create binary table #
+ ############################
+ */
+
+ strcpy(tform[0], "15A");
+ strcpy(tform[1], "1L");
+ strcpy(tform[2], "16X");
+ strcpy(tform[3], "1B");
+ strcpy(tform[4], "1I");
+ strcpy(tform[5], "1J");
+ strcpy(tform[6], "1E");
+ strcpy(tform[7], "1D");
+ strcpy(tform[8], "1C");
+ strcpy(tform[9], "1M");
+
+ strcpy(ttype[0], "Avalue");
+ strcpy(ttype[1], "Lvalue");
+ strcpy(ttype[2], "Xvalue");
+ strcpy(ttype[3], "Bvalue");
+ strcpy(ttype[4], "Ivalue");
+ strcpy(ttype[5], "Jvalue");
+ strcpy(ttype[6], "Evalue");
+ strcpy(ttype[7], "Dvalue");
+ strcpy(ttype[8], "Cvalue");
+ strcpy(ttype[9], "Mvalue");
+
+ strcpy(tunit[0], "");
+ strcpy(tunit[1], "m**2");
+ strcpy(tunit[2], "cm");
+ strcpy(tunit[3], "erg/s");
+ strcpy(tunit[4], "km/s");
+ strcpy(tunit[5], "");
+ strcpy(tunit[6], "");
+ strcpy(tunit[7], "");
+ strcpy(tunit[8], "");
+ strcpy(tunit[9], "");
+
+ nrows = 21;
+ tfields = 10;
+ pcount = 0;
+
+/*
+ ffcrtb(fptr, BINARY_TBL, nrows, tfields, ttype, tform, tunit, binname,
+ &status);
+*/
+ ffibin(fptr, nrows, tfields, ttype, tform, tunit, binname, 0L,
+ &status);
+
+ printf("\nffibin status = %d\n", status);
+ printf("HDU number = %d\n", ffghdn(fptr, &hdunum));
+
+ /* get size and position in header, and reserve space for more keywords */
+ ffghps(fptr, &existkeys, &keynum, &status);
+ printf("header contains %d keywords; located at keyword %d \n",existkeys,
+ keynum);
+
+ morekeys = 40;
+ ffhdef(fptr, morekeys, &status);
+ ffghsp(fptr, &existkeys, &morekeys, &status);
+ printf("header contains %d keywords with room for %d more\n",existkeys,
+ morekeys);
+
+ fftnul(fptr, 4, 99, &status); /* define null value for int cols */
+ fftnul(fptr, 5, 99, &status);
+ fftnul(fptr, 6, 99, &status);
+
+ extvers = 1;
+ ffpkyj(fptr, "EXTVER", extvers, "extension version number", &status);
+ ffpkyj(fptr, "TNULL4", 99, "value for undefined pixels", &status);
+ ffpkyj(fptr, "TNULL5", 99, "value for undefined pixels", &status);
+ ffpkyj(fptr, "TNULL6", 99, "value for undefined pixels", &status);
+
+ naxis = 3;
+ naxes[0] = 1;
+ naxes[1] = 2;
+ naxes[2] = 8;
+ ffptdm(fptr, 3, naxis, naxes, &status);
+
+ naxis = 0;
+ naxes[0] = 0;
+ naxes[1] = 0;
+ naxes[2] = 0;
+ ffgtdm(fptr, 3, 3, &naxis, naxes, &status);
+ ffgkys(fptr, "TDIM3", iskey, comment, &status);
+ printf("TDIM3 = %s, %d, %ld, %ld, %ld\n", iskey, naxis, naxes[0],
+ naxes[1], naxes[2]);
+
+ ffrdef(fptr, &status); /* force header to be scanned (not required) */
+
+ /*
+ ############################
+ # write data to columns #
+ ############################
+ */
+
+ /* initialize arrays of values to write to table */
+ signval = -1;
+ for (ii = 0; ii < 21; ii++)
+ {
+ signval *= -1;
+ boutarray[ii] = (ii + 1);
+ ioutarray[ii] = (ii + 1) * signval;
+ joutarray[ii] = (ii + 1) * signval;
+ koutarray[ii] = (ii + 1) * signval;
+ eoutarray[ii] = (ii + 1) * signval;
+ doutarray[ii] = (ii + 1) * signval;
+ }
+
+ ffpcls(fptr, 1, 1, 1, 3, onskey, &status); /* write string values */
+ ffpclu(fptr, 1, 4, 1, 1, &status); /* write null value */
+
+ larray[0] = 0;
+ larray[1] = 1;
+ larray[2] = 0;
+ larray[3] = 0;
+ larray[4] = 1;
+ larray[5] = 1;
+ larray[6] = 0;
+ larray[7] = 0;
+ larray[8] = 0;
+ larray[9] = 1;
+ larray[10] = 1;
+ larray[11] = 1;
+ larray[12] = 0;
+ larray[13] = 0;
+ larray[14] = 0;
+ larray[15] = 0;
+ larray[16] = 1;
+ larray[17] = 1;
+ larray[18] = 1;
+ larray[19] = 1;
+ larray[20] = 0;
+ larray[21] = 0;
+ larray[22] = 0;
+ larray[23] = 0;
+ larray[24] = 0;
+ larray[25] = 1;
+ larray[26] = 1;
+ larray[27] = 1;
+ larray[28] = 1;
+ larray[29] = 1;
+ larray[30] = 0;
+ larray[31] = 0;
+ larray[32] = 0;
+ larray[33] = 0;
+ larray[34] = 0;
+ larray[35] = 0;
+
+
+ ffpclx(fptr, 3, 1, 1, 36, larray, &status); /*write bits*/
+
+ for (ii = 4; ii < 9; ii++) /* loop over cols 4 - 8 */
+ {
+ ffpclb(fptr, ii, 1, 1, 2, boutarray, &status);
+ if (status == NUM_OVERFLOW)
+ status = 0;
+ ffpcli(fptr, ii, 3, 1, 2, &ioutarray[2], &status);
+ if (status == NUM_OVERFLOW)
+ status = 0;
+ ffpclk(fptr, ii, 5, 1, 2, &koutarray[4], &status);
+ if (status == NUM_OVERFLOW)
+ status = 0;
+ ffpcle(fptr, ii, 7, 1, 2, &eoutarray[6], &status);
+ if (status == NUM_OVERFLOW)
+ status = 0;
+ ffpcld(fptr, ii, 9, 1, 2, &doutarray[8], &status);
+ if (status == NUM_OVERFLOW)
+ status = 0;
+
+ ffpclu(fptr, ii, 11, 1, 1, &status); /* write null value */
+ }
+
+ ffpclc(fptr, 9, 1, 1, 10, eoutarray, &status);
+ ffpclm(fptr, 10, 1, 1, 10, doutarray, &status);
+
+ for (ii = 4; ii < 9; ii++) /* loop over cols 4 - 8 */
+ {
+ ffpcnb(fptr, ii, 12, 1, 2, &boutarray[11], 13, &status);
+ if (status == NUM_OVERFLOW)
+ status = 0;
+ ffpcni(fptr, ii, 14, 1, 2, &ioutarray[13], 15, &status);
+ if (status == NUM_OVERFLOW)
+ status = 0;
+ ffpcnk(fptr, ii, 16, 1, 2, &koutarray[15], 17, &status);
+ if (status == NUM_OVERFLOW)
+ status = 0;
+ ffpcne(fptr, ii, 18, 1, 2, &eoutarray[17], 19., &status);
+ if (status == NUM_OVERFLOW)
+ status = 0;
+ ffpcnd(fptr, ii, 20, 1, 2, &doutarray[19], 21., &status);
+ if (status == NUM_OVERFLOW)
+ status = 0;
+
+ }
+ ffpcll(fptr, 2, 1, 1, 21, larray, &status); /*write logicals*/
+ ffpclu(fptr, 2, 11, 1, 1, &status); /* write null value */
+ printf("ffpcl_ status = %d\n", status);
+
+ /*
+ #########################################
+ # get information about the columns #
+ #########################################
+ */
+
+ printf("\nFind the column numbers; a returned status value of 237 is");
+ printf("\nexpected and indicates that more than one column name matches");
+ printf("\nthe input column name template. Status = 219 indicates that");
+ printf("\nthere was no matching column name.");
+
+ ffgcno(fptr, 0, "Xvalue", &colnum, &status);
+ printf("\nColumn Xvalue is number %d; status = %d.\n", colnum, status);
+
+ while (status != COL_NOT_FOUND)
+ {
+ ffgcnn(fptr, 1, "*ue", colname, &colnum, &status);
+ printf("Column %s is number %d; status = %d.\n",
+ colname, colnum, status);
+ }
+ status = 0;
+
+ printf("\nInformation about each column:\n");
+
+ for (ii = 0; ii < tfields; ii++)
+ {
+ ffgtcl(fptr, ii + 1, &typecode, &repeat, &width, &status);
+ printf("%4s %3d %2ld %2ld", tform[ii], typecode, repeat, width);
+ ffgbcl(fptr, ii + 1, ttype[0], tunit[0], &cval, &repeat, &scale,
+ &zero, &jnulval, tdisp, &status);
+ printf(" %s, %s, %c, %ld, %f, %f, %ld, %s.\n",
+ ttype[0], tunit[0], cval, repeat, scale, zero, jnulval, tdisp);
+ }
+
+ printf("\n");
+
+ /*
+ ###############################################
+ # insert ASCII table before the binary table #
+ ###############################################
+ */
+
+ if (ffmrhd(fptr, -1, &hdutype, &status) > 0)
+ goto errstatus;
+
+ strcpy(tform[0], "A15");
+ strcpy(tform[1], "I10");
+ strcpy(tform[2], "F14.6");
+ strcpy(tform[3], "E12.5");
+ strcpy(tform[4], "D21.14");
+
+ strcpy(ttype[0], "Name");
+ strcpy(ttype[1], "Ivalue");
+ strcpy(ttype[2], "Fvalue");
+ strcpy(ttype[3], "Evalue");
+ strcpy(ttype[4], "Dvalue");
+
+ strcpy(tunit[0], "");
+ strcpy(tunit[1], "m**2");
+ strcpy(tunit[2], "cm");
+ strcpy(tunit[3], "erg/s");
+ strcpy(tunit[4], "km/s");
+
+ rowlen = 76;
+ nrows = 11;
+ tfields = 5;
+
+ ffitab(fptr, rowlen, nrows, tfields, ttype, tbcol, tform, tunit, tblname,
+ &status);
+ printf("ffitab status = %d\n", status);
+ printf("HDU number = %d\n", ffghdn(fptr, &hdunum));
+
+ ffsnul(fptr, 1, "null1", &status); /* define null value for int cols */
+ ffsnul(fptr, 2, "null2", &status);
+ ffsnul(fptr, 3, "null3", &status);
+ ffsnul(fptr, 4, "null4", &status);
+ ffsnul(fptr, 5, "null5", &status);
+
+ extvers = 2;
+ ffpkyj(fptr, "EXTVER", extvers, "extension version number", &status);
+
+ ffpkys(fptr, "TNULL1", "null1", "value for undefined pixels", &status);
+ ffpkys(fptr, "TNULL2", "null2", "value for undefined pixels", &status);
+ ffpkys(fptr, "TNULL3", "null3", "value for undefined pixels", &status);
+ ffpkys(fptr, "TNULL4", "null4", "value for undefined pixels", &status);
+ ffpkys(fptr, "TNULL5", "null5", "value for undefined pixels", &status);
+
+ if (status > 0)
+ goto errstatus;
+
+ /*
+ ############################
+ # write data to columns #
+ ############################
+ */
+
+ /* initialize arrays of values to write to table */
+ for (ii = 0; ii < 21; ii++)
+ {
+ boutarray[ii] = ii + 1;
+ ioutarray[ii] = ii + 1;
+ joutarray[ii] = ii + 1;
+ eoutarray[ii] = ii + 1;
+ doutarray[ii] = ii + 1;
+ }
+
+ ffpcls(fptr, 1, 1, 1, 3, onskey, &status); /* write string values */
+ ffpclu(fptr, 1, 4, 1, 1, &status); /* write null value */
+
+ for (ii = 2; ii < 6; ii++) /* loop over cols 2 - 5 */
+ {
+ ffpclb(fptr, ii, 1, 1, 2, boutarray, &status); /* char array */
+ if (status == NUM_OVERFLOW)
+ status = 0;
+ ffpcli(fptr, ii, 3, 1, 2, &ioutarray[2], &status); /* short array */
+ if (status == NUM_OVERFLOW)
+ status = 0;
+ ffpclj(fptr, ii, 5, 1, 2, &joutarray[4], &status); /* long array */
+ if (status == NUM_OVERFLOW)
+ status = 0;
+ ffpcle(fptr, ii, 7, 1, 2, &eoutarray[6], &status); /* float array */
+ if (status == NUM_OVERFLOW)
+ status = 0;
+ ffpcld(fptr, ii, 9, 1, 2, &doutarray[8], &status); /* double array */
+ if (status == NUM_OVERFLOW)
+ status = 0;
+
+ ffpclu(fptr, ii, 11, 1, 1, &status); /* write null value */
+ }
+ printf("ffpcl_ status = %d\n", status);
+
+ /*
+ ################################
+ # read data from ASCII table #
+ ################################
+ */
+ ffghtb(fptr, 99, &rowlen, &nrows, &tfields, ttype, tbcol,
+ tform, tunit, tblname, &status);
+
+ printf("\nASCII table: rowlen, nrows, tfields, extname: %ld %ld %d %s\n",
+ rowlen, nrows, tfields, tblname);
+
+ for (ii = 0; ii < tfields; ii++)
+ printf("%8s %3ld %8s %8s \n", ttype[ii], tbcol[ii],
+ tform[ii], tunit[ii]);
+
+ nrows = 11;
+ ffgcvs(fptr, 1, 1, 1, nrows, "UNDEFINED", inskey, &anynull, &status);
+ ffgcvb(fptr, 2, 1, 1, nrows, 99, binarray, &anynull, &status);
+ ffgcvi(fptr, 2, 1, 1, nrows, 99, iinarray, &anynull, &status);
+ ffgcvj(fptr, 3, 1, 1, nrows, 99, jinarray, &anynull, &status);
+ ffgcve(fptr, 4, 1, 1, nrows, 99., einarray, &anynull, &status);
+ ffgcvd(fptr, 5, 1, 1, nrows, 99., dinarray, &anynull, &status);
+
+ printf("\nData values read from ASCII table:\n");
+ for (ii = 0; ii < nrows; ii++)
+ {
+ printf("%15s %2d %2d %2ld %4.1f %4.1f\n", inskey[ii], binarray[ii],
+ iinarray[ii], jinarray[ii], einarray[ii], dinarray[ii]);
+ }
+
+ ffgtbb(fptr, 1, 20, 78, uchars, &status);
+ uchars[78] = '\0';
+ printf("\n%s\n", uchars);
+ ffptbb(fptr, 1, 20, 78, uchars, &status);
+
+ /*
+ #########################################
+ # get information about the columns #
+ #########################################
+ */
+
+ ffgcno(fptr, 0, "name", &colnum, &status);
+ printf("\nColumn name is number %d; status = %d.\n", colnum, status);
+
+ while (status != COL_NOT_FOUND)
+ {
+ ffgcnn(fptr, 1, "*ue", colname, &colnum, &status);
+ printf("Column %s is number %d; status = %d.\n",
+ colname, colnum, status);
+ }
+ status = 0;
+
+ for (ii = 0; ii < tfields; ii++)
+ {
+ ffgtcl(fptr, ii + 1, &typecode, &repeat, &width, &status);
+ printf("%4s %3d %2ld %2ld", tform[ii], typecode, repeat, width);
+ ffgacl(fptr, ii + 1, ttype[0], tbcol, tunit[0], tform[0], &scale,
+ &zero, nulstr, tdisp, &status);
+ printf(" %s, %ld, %s, %s, %f, %f, %s, %s.\n",
+ ttype[0], tbcol[0], tunit[0], tform[0], scale, zero,
+ nulstr, tdisp);
+ }
+
+ printf("\n");
+
+ /*
+ ###############################################
+ # test the insert/delete row/column routines #
+ ###############################################
+ */
+
+ if (ffirow(fptr, 2, 3, &status) > 0)
+ goto errstatus;
+
+ nrows = 14;
+ ffgcvs(fptr, 1, 1, 1, nrows, "UNDEFINED", inskey, &anynull, &status);
+ ffgcvb(fptr, 2, 1, 1, nrows, 99, binarray, &anynull, &status);
+ ffgcvi(fptr, 2, 1, 1, nrows, 99, iinarray, &anynull, &status);
+ ffgcvj(fptr, 3, 1, 1, nrows, 99, jinarray, &anynull, &status);
+ ffgcve(fptr, 4, 1, 1, nrows, 99., einarray, &anynull, &status);
+ ffgcvd(fptr, 5, 1, 1, nrows, 99., dinarray, &anynull, &status);
+
+
+ printf("\nData values after inserting 3 rows after row 2:\n");
+ for (ii = 0; ii < nrows; ii++)
+ {
+ printf("%15s %2d %2d %2ld %4.1f %4.1f\n", inskey[ii], binarray[ii],
+ iinarray[ii], jinarray[ii], einarray[ii], dinarray[ii]);
+ }
+
+ if (ffdrow(fptr, 10, 2, &status) > 0)
+ goto errstatus;
+
+ nrows = 12;
+ ffgcvs(fptr, 1, 1, 1, nrows, "UNDEFINED", inskey, &anynull, &status);
+ ffgcvb(fptr, 2, 1, 1, nrows, 99, binarray, &anynull, &status);
+ ffgcvi(fptr, 2, 1, 1, nrows, 99, iinarray, &anynull, &status);
+ ffgcvj(fptr, 3, 1, 1, nrows, 99, jinarray, &anynull, &status);
+ ffgcve(fptr, 4, 1, 1, nrows, 99., einarray, &anynull, &status);
+ ffgcvd(fptr, 5, 1, 1, nrows, 99., dinarray, &anynull, &status);
+
+ printf("\nData values after deleting 2 rows at row 10:\n");
+ for (ii = 0; ii < nrows; ii++)
+ {
+ printf("%15s %2d %2d %2ld %4.1f %4.1f\n", inskey[ii], binarray[ii],
+ iinarray[ii], jinarray[ii], einarray[ii], dinarray[ii]);
+ }
+ if (ffdcol(fptr, 3, &status) > 0)
+ goto errstatus;
+
+ ffgcvs(fptr, 1, 1, 1, nrows, "UNDEFINED", inskey, &anynull, &status);
+ ffgcvb(fptr, 2, 1, 1, nrows, 99, binarray, &anynull, &status);
+ ffgcvi(fptr, 2, 1, 1, nrows, 99, iinarray, &anynull, &status);
+ ffgcve(fptr, 3, 1, 1, nrows, 99., einarray, &anynull, &status);
+ ffgcvd(fptr, 4, 1, 1, nrows, 99., dinarray, &anynull, &status);
+
+ printf("\nData values after deleting column 3:\n");
+ for (ii = 0; ii < nrows; ii++)
+ {
+ printf("%15s %2d %2d %4.1f %4.1f\n", inskey[ii], binarray[ii],
+ iinarray[ii], einarray[ii], dinarray[ii]);
+ }
+
+ if (fficol(fptr, 5, "INSERT_COL", "F14.6", &status) > 0)
+ goto errstatus;
+
+ ffgcvs(fptr, 1, 1, 1, nrows, "UNDEFINED", inskey, &anynull, &status);
+ ffgcvb(fptr, 2, 1, 1, nrows, 99, binarray, &anynull, &status);
+ ffgcvi(fptr, 2, 1, 1, nrows, 99, iinarray, &anynull, &status);
+ ffgcve(fptr, 3, 1, 1, nrows, 99., einarray, &anynull, &status);
+ ffgcvd(fptr, 4, 1, 1, nrows, 99., dinarray, &anynull, &status);
+ ffgcvj(fptr, 5, 1, 1, nrows, 99, jinarray, &anynull, &status);
+
+ printf("\nData values after inserting column 5:\n");
+ for (ii = 0; ii < nrows; ii++)
+ {
+ printf("%15s %2d %2d %4.1f %4.1f %ld\n", inskey[ii], binarray[ii],
+ iinarray[ii], einarray[ii], dinarray[ii] , jinarray[ii]);
+ }
+
+ /*
+ ############################################################
+ # create a temporary file and copy the ASCII table to it, #
+ # column by column. #
+ ############################################################
+ */
+ bitpix = 16;
+ naxis = 0;
+
+ strcpy(filename, "!t1q2s3v6.tmp");
+ ffinit(&tmpfptr, filename, &status);
+ printf("Create temporary file: ffinit status = %d\n", status);
+
+ ffiimg(tmpfptr, bitpix, naxis, naxes, &status);
+ printf("\nCreate null primary array: ffiimg status = %d\n", status);
+
+ /* create an empty table with 12 rows and 0 columns */
+ nrows = 12;
+ tfields = 0;
+ rowlen = 0;
+ ffitab(tmpfptr, rowlen, nrows, tfields, ttype, tbcol, tform, tunit,
+ tblname, &status);
+ printf("\nCreate ASCII table with 0 columns: ffitab status = %d\n",
+ status);
+
+ /* copy columns from one table to the other */
+ ffcpcl(fptr, tmpfptr, 4, 1, TRUE, &status);
+ printf("copy column, ffcpcl status = %d\n", status);
+ ffcpcl(fptr, tmpfptr, 3, 1, TRUE, &status);
+ printf("copy column, ffcpcl status = %d\n", status);
+ ffcpcl(fptr, tmpfptr, 2, 1, TRUE, &status);
+ printf("copy column, ffcpcl status = %d\n", status);
+ ffcpcl(fptr, tmpfptr, 1, 1, TRUE, &status);
+ printf("copy column, ffcpcl status = %d\n", status);
+
+ /* now repeat by copying ASCII input to Binary output table */
+ ffibin(tmpfptr, nrows, tfields, ttype, tform, tunit,
+ tblname, 0L, &status);
+ printf("\nCreate Binary table with 0 columns: ffibin status = %d\n",
+ status);
+
+ /* copy columns from one table to the other */
+ ffcpcl(fptr, tmpfptr, 4, 1, TRUE, &status);
+ printf("copy column, ffcpcl status = %d\n", status);
+ ffcpcl(fptr, tmpfptr, 3, 1, TRUE, &status);
+ printf("copy column, ffcpcl status = %d\n", status);
+ ffcpcl(fptr, tmpfptr, 2, 1, TRUE, &status);
+ printf("copy column, ffcpcl status = %d\n", status);
+ ffcpcl(fptr, tmpfptr, 1, 1, TRUE, &status);
+ printf("copy column, ffcpcl status = %d\n", status);
+
+
+/*
+ ffclos(tmpfptr, &status);
+ printf("Close the tmp file: ffclos status = %d\n", status);
+*/
+
+ ffdelt(tmpfptr, &status);
+ printf("Delete the tmp file: ffdelt status = %d\n", status);
+
+ if (status > 0)
+ {
+ goto errstatus;
+ }
+
+ /*
+ ################################
+ # read data from binary table #
+ ################################
+ */
+
+ if (ffmrhd(fptr, 1, &hdutype, &status) > 0)
+ goto errstatus;
+
+ printf("HDU number = %d\n", ffghdn(fptr, &hdunum));
+
+ ffghsp(fptr, &existkeys, &morekeys, &status);
+ printf("header contains %d keywords with room for %d more\n",existkeys,
+ morekeys);
+
+ ffghbn(fptr, 99, &nrows, &tfields, ttype,
+ tform, tunit, binname, &pcount, &status);
+
+ printf("\nBinary table: nrows, tfields, extname, pcount: %ld %d %s %ld\n",
+ nrows, tfields, binname, pcount);
+
+ for (ii = 0; ii < tfields; ii++)
+ printf("%8s %8s %8s \n", ttype[ii], tform[ii], tunit[ii]);
+
+ for (ii = 0; ii < 40; ii++)
+ larray[ii] = 0;
+
+ printf("\nData values read from binary table:\n");
+ printf(" Bit column (X) data values: \n\n");
+
+ ffgcx(fptr, 3, 1, 1, 36, larray, &status);
+ for (jj = 0; jj < 5; jj++)
+ {
+ for (ii = 0; ii < 8; ii++)
+ printf("%1d",larray[jj * 8 + ii]);
+ printf(" ");
+ }
+
+ for (ii = 0; ii < nrows; ii++)
+ {
+ larray[ii] = 0;
+ xinarray[ii] = 0;
+ binarray[ii] = 0;
+ iinarray[ii] = 0;
+ kinarray[ii] = 0;
+ einarray[ii] = 0.;
+ dinarray[ii] = 0.;
+ cinarray[ii * 2] = 0.;
+ minarray[ii * 2] = 0.;
+ cinarray[ii * 2 + 1] = 0.;
+ minarray[ii * 2 + 1] = 0.;
+ }
+
+ printf("\n\n");
+ ffgcvs(fptr, 1, 4, 1, 1, "", inskey, &anynull, &status);
+ printf("null string column value = -%s- (should be --)\n",inskey[0]);
+
+ nrows = 21;
+ ffgcvs(fptr, 1, 1, 1, nrows, "NOT DEFINED", inskey, &anynull, &status);
+ ffgcl( fptr, 2, 1, 1, nrows, larray, &status);
+ ffgcvb(fptr, 3, 1, 1, nrows, 98, xinarray, &anynull, &status);
+ ffgcvb(fptr, 4, 1, 1, nrows, 98, binarray, &anynull, &status);
+ ffgcvi(fptr, 5, 1, 1, nrows, 98, iinarray, &anynull, &status);
+ ffgcvk(fptr, 6, 1, 1, nrows, 98, kinarray, &anynull, &status);
+ ffgcve(fptr, 7, 1, 1, nrows, 98., einarray, &anynull, &status);
+ ffgcvd(fptr, 8, 1, 1, nrows, 98., dinarray, &anynull, &status);
+ ffgcvc(fptr, 9, 1, 1, nrows, 98., cinarray, &anynull, &status);
+ ffgcvm(fptr, 10, 1, 1, nrows, 98., minarray, &anynull, &status);
+
+ printf("\nRead columns with ffgcv_:\n");
+ for (ii = 0; ii < nrows; ii++)
+ {
+ printf("%15s %d %3d %2d %3d %3d %5.1f %5.1f (%5.1f,%5.1f) (%5.1f,%5.1f) \n",
+ inskey[ii], larray[ii], xinarray[ii], binarray[ii], iinarray[ii],
+ kinarray[ii], einarray[ii], dinarray[ii], cinarray[ii * 2],
+ cinarray[ii * 2 + 1], minarray[ii * 2], minarray[ii * 2 + 1]);
+ }
+
+ for (ii = 0; ii < nrows; ii++)
+ {
+ larray[ii] = 0;
+ xinarray[ii] = 0;
+ binarray[ii] = 0;
+ iinarray[ii] = 0;
+ kinarray[ii] = 0;
+ einarray[ii] = 0.;
+ dinarray[ii] = 0.;
+ cinarray[ii * 2] = 0.;
+ minarray[ii * 2] = 0.;
+ cinarray[ii * 2 + 1] = 0.;
+ minarray[ii * 2 + 1] = 0.;
+ }
+
+ ffgcfs(fptr, 1, 1, 1, nrows, inskey, larray2, &anynull, &status);
+ ffgcfl(fptr, 2, 1, 1, nrows, larray, larray2, &anynull, &status);
+ ffgcfb(fptr, 3, 1, 1, nrows, xinarray, larray2, &anynull, &status);
+ ffgcfb(fptr, 4, 1, 1, nrows, binarray, larray2, &anynull, &status);
+ ffgcfi(fptr, 5, 1, 1, nrows, iinarray, larray2, &anynull, &status);
+ ffgcfk(fptr, 6, 1, 1, nrows, kinarray, larray2, &anynull, &status);
+ ffgcfe(fptr, 7, 1, 1, nrows, einarray, larray2, &anynull, &status);
+ ffgcfd(fptr, 8, 1, 1, nrows, dinarray, larray2, &anynull, &status);
+ ffgcfc(fptr, 9, 1, 1, nrows, cinarray, larray2, &anynull, &status);
+ ffgcfm(fptr, 10, 1, 1, nrows, minarray, larray2, &anynull, &status);
+
+ printf("\nRead columns with ffgcf_:\n");
+ for (ii = 0; ii < 10; ii++)
+ {
+
+ printf("%15s %d %3d %2d %3d %3d %5.1f %5.1f (%5.1f,%5.1f) (%5.1f,%5.1f)\n",
+ inskey[ii], larray[ii], xinarray[ii], binarray[ii], iinarray[ii],
+ kinarray[ii], einarray[ii], dinarray[ii], cinarray[ii * 2],
+ cinarray[ii * 2 + 1], minarray[ii * 2], minarray[ii * 2 + 1]);
+ }
+ for (ii = 10; ii < nrows; ii++)
+ {
+ /* don't try to print the NaN values */
+ printf("%15s %d %3d %2d %3d \n",
+ inskey[ii], larray[ii], xinarray[ii], binarray[ii], iinarray[ii]);
+ }
+ ffprec(fptr,
+ "key_prec= 'This keyword was written by f_prec' / comment here", &status);
+
+ /*
+ ###############################################
+ # test the insert/delete row/column routines #
+ ###############################################
+ */
+ if (ffirow(fptr, 2, 3, &status) > 0)
+ goto errstatus;
+
+ nrows = 14;
+ ffgcvs(fptr, 1, 1, 1, nrows, "NOT DEFINED", inskey, &anynull, &status);
+ ffgcvb(fptr, 4, 1, 1, nrows, 98, binarray, &anynull, &status);
+ ffgcvi(fptr, 5, 1, 1, nrows, 98, iinarray, &anynull, &status);
+ ffgcvj(fptr, 6, 1, 1, nrows, 98, jinarray, &anynull, &status);
+ ffgcve(fptr, 7, 1, 1, nrows, 98., einarray, &anynull, &status);
+ ffgcvd(fptr, 8, 1, 1, nrows, 98., dinarray, &anynull, &status);
+
+ printf("\nData values after inserting 3 rows after row 2:\n");
+ for (ii = 0; ii < nrows; ii++)
+ {
+ printf("%15s %2d %3d %3ld %5.1f %5.1f\n", inskey[ii], binarray[ii],
+ iinarray[ii], jinarray[ii], einarray[ii], dinarray[ii]);
+ }
+
+ if (ffdrow(fptr, 10, 2, &status) > 0)
+ goto errstatus;
+
+ nrows = 12;
+ ffgcvs(fptr, 1, 1, 1, nrows, "NOT DEFINED", inskey, &anynull, &status);
+ ffgcvb(fptr, 4, 1, 1, nrows, 98, binarray, &anynull, &status);
+ ffgcvi(fptr, 5, 1, 1, nrows, 98, iinarray, &anynull, &status);
+ ffgcvj(fptr, 6, 1, 1, nrows, 98, jinarray, &anynull, &status);
+ ffgcve(fptr, 7, 1, 1, nrows, 98., einarray, &anynull, &status);
+ ffgcvd(fptr, 8, 1, 1, nrows, 98., dinarray, &anynull, &status);
+
+ printf("\nData values after deleting 2 rows at row 10:\n");
+ for (ii = 0; ii < nrows; ii++)
+ {
+ printf("%15s %2d %3d %3ld %5.1f %5.1f\n", inskey[ii], binarray[ii],
+ iinarray[ii], jinarray[ii], einarray[ii], dinarray[ii]);
+ }
+
+ if (ffdcol(fptr, 6, &status) > 0)
+ goto errstatus;
+
+ ffgcvs(fptr, 1, 1, 1, nrows, "NOT DEFINED", inskey, &anynull, &status);
+ ffgcvb(fptr, 4, 1, 1, nrows, 98, binarray, &anynull, &status);
+ ffgcvi(fptr, 5, 1, 1, nrows, 98, iinarray, &anynull, &status);
+ ffgcve(fptr, 6, 1, 1, nrows, 98., einarray, &anynull, &status);
+ ffgcvd(fptr, 7, 1, 1, nrows, 98., dinarray, &anynull, &status);
+
+ printf("\nData values after deleting column 6:\n");
+ for (ii = 0; ii < nrows; ii++)
+ {
+ printf("%15s %2d %3d %5.1f %5.1f\n", inskey[ii], binarray[ii],
+ iinarray[ii], einarray[ii], dinarray[ii]);
+ }
+
+ if (fficol(fptr, 8, "INSERT_COL", "1E", &status) > 0)
+ goto errstatus;
+
+ ffgcvs(fptr, 1, 1, 1, nrows, "NOT DEFINED", inskey, &anynull, &status);
+ ffgcvb(fptr, 4, 1, 1, nrows, 98, binarray, &anynull, &status);
+ ffgcvi(fptr, 5, 1, 1, nrows, 98, iinarray, &anynull, &status);
+ ffgcve(fptr, 6, 1, 1, nrows, 98., einarray, &anynull, &status);
+ ffgcvd(fptr, 7, 1, 1, nrows, 98., dinarray, &anynull, &status);
+ ffgcvj(fptr, 8, 1, 1, nrows, 98, jinarray, &anynull, &status);
+
+ printf("\nData values after inserting column 8:\n");
+ for (ii = 0; ii < nrows; ii++)
+ {
+ printf("%15s %2d %3d %5.1f %5.1f %ld\n", inskey[ii], binarray[ii],
+ iinarray[ii], einarray[ii], dinarray[ii] , jinarray[ii]);
+ }
+
+ ffpclu(fptr, 8, 1, 1, 10, &status);
+
+ ffgcvs(fptr, 1, 1, 1, nrows, "NOT DEFINED", inskey, &anynull, &status);
+ ffgcvb(fptr, 4, 1, 1, nrows, 98, binarray, &anynull, &status);
+ ffgcvi(fptr, 5, 1, 1, nrows, 98, iinarray, &anynull, &status);
+ ffgcve(fptr, 6, 1, 1, nrows, 98., einarray, &anynull, &status);
+ ffgcvd(fptr, 7, 1, 1, nrows, 98., dinarray, &anynull, &status);
+ ffgcvj(fptr, 8, 1, 1, nrows, 98, jinarray, &anynull, &status);
+
+ printf("\nValues after setting 1st 10 elements in column 8 = null:\n");
+ for (ii = 0; ii < nrows; ii++)
+ {
+ printf("%15s %2d %3d %5.1f %5.1f %ld\n", inskey[ii], binarray[ii],
+ iinarray[ii], einarray[ii], dinarray[ii] , jinarray[ii]);
+ }
+
+ /*
+ ############################################################
+ # create a temporary file and copy the binary table to it,#
+ # column by column. #
+ ############################################################
+ */
+ bitpix = 16;
+ naxis = 0;
+
+ strcpy(filename, "!t1q2s3v5.tmp");
+ ffinit(&tmpfptr, filename, &status);
+ printf("Create temporary file: ffinit status = %d\n", status);
+
+ ffiimg(tmpfptr, bitpix, naxis, naxes, &status);
+ printf("\nCreate null primary array: ffiimg status = %d\n", status);
+
+ /* create an empty table with 22 rows and 0 columns */
+ nrows = 22;
+ tfields = 0;
+ ffibin(tmpfptr, nrows, tfields, ttype, tform, tunit, binname, 0L,
+ &status);
+ printf("\nCreate binary table with 0 columns: ffibin status = %d\n",
+ status);
+
+ /* copy columns from one table to the other */
+ ffcpcl(fptr, tmpfptr, 7, 1, TRUE, &status);
+ printf("copy column, ffcpcl status = %d\n", status);
+ ffcpcl(fptr, tmpfptr, 6, 1, TRUE, &status);
+ printf("copy column, ffcpcl status = %d\n", status);
+ ffcpcl(fptr, tmpfptr, 5, 1, TRUE, &status);
+ printf("copy column, ffcpcl status = %d\n", status);
+ ffcpcl(fptr, tmpfptr, 4, 1, TRUE, &status);
+ printf("copy column, ffcpcl status = %d\n", status);
+ ffcpcl(fptr, tmpfptr, 3, 1, TRUE, &status);
+ printf("copy column, ffcpcl status = %d\n", status);
+ ffcpcl(fptr, tmpfptr, 2, 1, TRUE, &status);
+ printf("copy column, ffcpcl status = %d\n", status);
+ ffcpcl(fptr, tmpfptr, 1, 1, TRUE, &status);
+ printf("copy column, ffcpcl status = %d\n", status);
+
+/*
+ ffclos(tmpfptr, &status);
+ printf("Close the tmp file: ffclos status = %d\n", status);
+*/
+
+ ffdelt(tmpfptr, &status);
+ printf("Delete the tmp file: ffdelt status = %d\n", status);
+ if (status > 0)
+ {
+ goto errstatus;
+ }
+ /*
+ ####################################################
+ # insert binary table following the primary array #
+ ####################################################
+ */
+
+ ffmahd(fptr, 1, &hdutype, &status);
+
+ strcpy(tform[0], "15A");
+ strcpy(tform[1], "1L");
+ strcpy(tform[2], "16X");
+ strcpy(tform[3], "1B");
+ strcpy(tform[4], "1I");
+ strcpy(tform[5], "1J");
+ strcpy(tform[6], "1E");
+ strcpy(tform[7], "1D");
+ strcpy(tform[8], "1C");
+ strcpy(tform[9], "1M");
+
+ strcpy(ttype[0], "Avalue");
+ strcpy(ttype[1], "Lvalue");
+ strcpy(ttype[2], "Xvalue");
+ strcpy(ttype[3], "Bvalue");
+ strcpy(ttype[4], "Ivalue");
+ strcpy(ttype[5], "Jvalue");
+ strcpy(ttype[6], "Evalue");
+ strcpy(ttype[7], "Dvalue");
+ strcpy(ttype[8], "Cvalue");
+ strcpy(ttype[9], "Mvalue");
+
+ strcpy(tunit[0], "");
+ strcpy(tunit[1], "m**2");
+ strcpy(tunit[2], "cm");
+ strcpy(tunit[3], "erg/s");
+ strcpy(tunit[4], "km/s");
+ strcpy(tunit[5], "");
+ strcpy(tunit[6], "");
+ strcpy(tunit[7], "");
+ strcpy(tunit[8], "");
+ strcpy(tunit[9], "");
+
+ nrows = 20;
+ tfields = 10;
+ pcount = 0;
+
+ ffibin(fptr, nrows, tfields, ttype, tform, tunit, binname, pcount,
+ &status);
+ printf("ffibin status = %d\n", status);
+ printf("HDU number = %d\n", ffghdn(fptr, &hdunum));
+
+ extvers = 3;
+ ffpkyj(fptr, "EXTVER", extvers, "extension version number", &status);
+
+
+ ffpkyj(fptr, "TNULL4", 77, "value for undefined pixels", &status);
+ ffpkyj(fptr, "TNULL5", 77, "value for undefined pixels", &status);
+ ffpkyj(fptr, "TNULL6", 77, "value for undefined pixels", &status);
+
+ ffpkyj(fptr, "TSCAL4", 1000, "scaling factor", &status);
+ ffpkyj(fptr, "TSCAL5", 1, "scaling factor", &status);
+ ffpkyj(fptr, "TSCAL6", 100, "scaling factor", &status);
+
+ ffpkyj(fptr, "TZERO4", 0, "scaling offset", &status);
+ ffpkyj(fptr, "TZERO5", 32768, "scaling offset", &status);
+ ffpkyj(fptr, "TZERO6", 100, "scaling offset", &status);
+
+ fftnul(fptr, 4, 77, &status); /* define null value for int cols */
+ fftnul(fptr, 5, 77, &status);
+ fftnul(fptr, 6, 77, &status);
+ /* set scaling */
+ fftscl(fptr, 4, 1000., 0., &status);
+ fftscl(fptr, 5, 1., 32768., &status);
+ fftscl(fptr, 6, 100., 100., &status);
+
+ /*
+ ############################
+ # write data to columns #
+ ############################
+ */
+
+ /* initialize arrays of values to write to table */
+
+ joutarray[0] = 0;
+ joutarray[1] = 1000;
+ joutarray[2] = 10000;
+ joutarray[3] = 32768;
+ joutarray[4] = 65535;
+
+
+ for (ii = 4; ii < 7; ii++)
+ {
+ ffpclj(fptr, ii, 1, 1, 5, joutarray, &status);
+ if (status == NUM_OVERFLOW)
+ {
+ printf("Overflow writing to column %ld\n", ii);
+ status = 0;
+ }
+
+ ffpclu(fptr, ii, 6, 1, 1, &status); /* write null value */
+ }
+
+ for (jj = 4; jj < 7; jj++)
+ {
+ ffgcvj(fptr, jj, 1, 1, 6, -999, jinarray, &anynull, &status);
+ for (ii = 0; ii < 6; ii++)
+ {
+ printf(" %6ld", jinarray[ii]);
+ }
+ printf("\n");
+ }
+
+ printf("\n");
+ /* turn off scaling, and read the unscaled values */
+ fftscl(fptr, 4, 1., 0., &status);
+ fftscl(fptr, 5, 1., 0., &status);
+ fftscl(fptr, 6, 1., 0., &status);
+
+ for (jj = 4; jj < 7; jj++)
+ {
+ ffgcvj(fptr, jj, 1, 1, 6, -999, jinarray, &anynull, &status);
+ for (ii = 0; ii < 6; ii++)
+ {
+ printf(" %6ld", jinarray[ii]);
+ }
+ printf("\n");
+ }
+ /*
+ ######################################################
+ # insert image extension following the binary table #
+ ######################################################
+ */
+
+ bitpix = -32;
+ naxis = 2;
+ naxes[0] = 15;
+ naxes[1] = 25;
+ ffiimg(fptr, bitpix, naxis, naxes, &status);
+ printf("\nCreate image extension: ffiimg status = %d\n", status);
+ printf("HDU number = %d\n", ffghdn(fptr, &hdunum));
+
+ for (jj = 0; jj < 30; jj++)
+ {
+ for (ii = 0; ii < 19; ii++)
+ {
+ imgarray[jj][ii] = (jj * 10) + ii;
+ }
+ }
+
+ ffp2di(fptr, 1, 19, naxes[0], naxes[1], imgarray[0], &status);
+ printf("\nWrote whole 2D array: ffp2di status = %d\n", status);
+
+ for (jj = 0; jj < 30; jj++)
+ {
+ for (ii = 0; ii < 19; ii++)
+ {
+ imgarray[jj][ii] = 0;
+ }
+ }
+
+ ffg2di(fptr, 1, 0, 19, naxes[0], naxes[1], imgarray[0], &anynull,
+ &status);
+ printf("\nRead whole 2D array: ffg2di status = %d\n", status);
+
+ for (jj = 0; jj < 30; jj++)
+ {
+ for (ii = 0; ii < 19; ii++)
+ {
+ printf(" %3d", imgarray[jj][ii]);
+ }
+ printf("\n");
+ }
+
+ for (jj = 0; jj < 30; jj++)
+ {
+ for (ii = 0; ii < 19; ii++)
+ {
+ imgarray[jj][ii] = 0;
+ }
+ }
+
+ for (jj = 0; jj < 20; jj++)
+ {
+ for (ii = 0; ii < 10; ii++)
+ {
+ imgarray2[jj][ii] = (jj * -10) - ii;
+ }
+ }
+
+ fpixels[0] = 5;
+ fpixels[1] = 5;
+ lpixels[0] = 14;
+ lpixels[1] = 14;
+ ffpssi(fptr, 1, naxis, naxes, fpixels, lpixels,
+ imgarray2[0], &status);
+ printf("\nWrote subset 2D array: ffpssi status = %d\n", status);
+
+ ffg2di(fptr, 1, 0, 19, naxes[0], naxes[1], imgarray[0], &anynull,
+ &status);
+ printf("\nRead whole 2D array: ffg2di status = %d\n", status);
+
+ for (jj = 0; jj < 30; jj++)
+ {
+ for (ii = 0; ii < 19; ii++)
+ {
+ printf(" %3d", imgarray[jj][ii]);
+ }
+ printf("\n");
+ }
+
+ fpixels[0] = 2;
+ fpixels[1] = 5;
+ lpixels[0] = 10;
+ lpixels[1] = 8;
+ inc[0] = 2;
+ inc[1] = 3;
+
+ for (jj = 0; jj < 30; jj++)
+ {
+ for (ii = 0; ii < 19; ii++)
+ {
+ imgarray[jj][ii] = 0;
+ }
+ }
+
+ ffgsvi(fptr, 1, naxis, naxes, fpixels, lpixels, inc, 0,
+ imgarray[0], &anynull, &status);
+ printf("\nRead subset of 2D array: ffgsvi status = %d\n", status);
+
+ for (ii = 0; ii < 10; ii++)
+ {
+ printf(" %3d", imgarray[0][ii]);
+ }
+ printf("\n");
+
+ /*
+ ###########################################################
+ # insert another image extension #
+ # copy the image extension to primary array of tmp file. #
+ # then delete the tmp file, and the image extension #
+ ###########################################################
+ */
+ bitpix = 16;
+ naxis = 2;
+ naxes[0] = 15;
+ naxes[1] = 25;
+ ffiimg(fptr, bitpix, naxis, naxes, &status);
+ printf("\nCreate image extension: ffiimg status = %d\n", status);
+ printf("HDU number = %d\n", ffghdn(fptr, &hdunum));
+
+ strcpy(filename, "t1q2s3v4.tmp");
+ ffinit(&tmpfptr, filename, &status);
+ printf("Create temporary file: ffinit status = %d\n", status);
+
+ ffcopy(fptr, tmpfptr, 0, &status);
+ printf("Copy image extension to primary array of tmp file.\n");
+ printf("ffcopy status = %d\n", status);
+
+ ffgrec(tmpfptr, 1, card, &status);
+ printf("%s\n", card);
+ ffgrec(tmpfptr, 2, card, &status);
+ printf("%s\n", card);
+ ffgrec(tmpfptr, 3, card, &status);
+ printf("%s\n", card);
+ ffgrec(tmpfptr, 4, card, &status);
+ printf("%s\n", card);
+ ffgrec(tmpfptr, 5, card, &status);
+ printf("%s\n", card);
+ ffgrec(tmpfptr, 6, card, &status);
+ printf("%s\n", card);
+
+ ffdelt(tmpfptr, &status);
+ printf("Delete the tmp file: ffdelt status = %d\n", status);
+
+ ffdhdu(fptr, &hdutype, &status);
+ printf("Delete the image extension; hdutype, status = %d %d\n",
+ hdutype, status);
+ printf("HDU number = %d\n", ffghdn(fptr, &hdunum));
+
+ /*
+ ###########################################################
+ # append bintable extension with variable length columns #
+ ###########################################################
+ */
+
+ ffcrhd(fptr, &status);
+ printf("ffcrhd status = %d\n", status);
+
+ strcpy(tform[0], "1PA");
+ strcpy(tform[1], "1PL");
+ strcpy(tform[2], "1PB"); /* Fortran FITSIO doesn't support 1PX */
+ strcpy(tform[3], "1PB");
+ strcpy(tform[4], "1PI");
+ strcpy(tform[5], "1PJ");
+ strcpy(tform[6], "1PE");
+ strcpy(tform[7], "1PD");
+ strcpy(tform[8], "1PC");
+ strcpy(tform[9], "1PM");
+
+ strcpy(ttype[0], "Avalue");
+ strcpy(ttype[1], "Lvalue");
+ strcpy(ttype[2], "Xvalue");
+ strcpy(ttype[3], "Bvalue");
+ strcpy(ttype[4], "Ivalue");
+ strcpy(ttype[5], "Jvalue");
+ strcpy(ttype[6], "Evalue");
+ strcpy(ttype[7], "Dvalue");
+ strcpy(ttype[8], "Cvalue");
+ strcpy(ttype[9], "Mvalue");
+
+ strcpy(tunit[0], "");
+ strcpy(tunit[1], "m**2");
+ strcpy(tunit[2], "cm");
+ strcpy(tunit[3], "erg/s");
+ strcpy(tunit[4], "km/s");
+ strcpy(tunit[5], "");
+ strcpy(tunit[6], "");
+ strcpy(tunit[7], "");
+ strcpy(tunit[8], "");
+ strcpy(tunit[9], "");
+
+ nrows = 20;
+ tfields = 10;
+ pcount = 0;
+
+ ffphbn(fptr, nrows, tfields, ttype, tform, tunit, binname, pcount,
+ &status);
+ printf("Variable length arrays: ffphbn status = %d\n", status);
+
+
+ extvers = 4;
+ ffpkyj(fptr, "EXTVER", extvers, "extension version number", &status);
+
+ ffpkyj(fptr, "TNULL4", 88, "value for undefined pixels", &status);
+ ffpkyj(fptr, "TNULL5", 88, "value for undefined pixels", &status);
+ ffpkyj(fptr, "TNULL6", 88, "value for undefined pixels", &status);
+
+ /*
+ ############################
+ # write data to columns #
+ ############################
+ */
+
+ /* initialize arrays of values to write to table */
+ strcpy(iskey,"abcdefghijklmnopqrst");
+
+ for (ii = 0; ii < 20; ii++)
+ {
+ boutarray[ii] = ii + 1;
+ ioutarray[ii] = ii + 1;
+ joutarray[ii] = ii + 1;
+ eoutarray[ii] = ii + 1;
+ doutarray[ii] = ii + 1;
+ }
+
+ larray[0] = 0;
+ larray[1] = 1;
+ larray[2] = 0;
+ larray[3] = 0;
+ larray[4] = 1;
+ larray[5] = 1;
+ larray[6] = 0;
+ larray[7] = 0;
+ larray[8] = 0;
+ larray[9] = 1;
+ larray[10] = 1;
+ larray[11] = 1;
+ larray[12] = 0;
+ larray[13] = 0;
+ larray[14] = 0;
+ larray[15] = 0;
+ larray[16] = 1;
+ larray[17] = 1;
+ larray[18] = 1;
+ larray[19] = 1;
+
+ /* write values in 1st row */
+ /* strncpy(inskey[0], iskey, 1); */
+ inskey[0][0] = '\0'; /* write a null string (i.e., a blank) */
+ ffpcls(fptr, 1, 1, 1, 1, inskey, &status); /* write string values */
+ ffpcll(fptr, 2, 1, 1, 1, larray, &status); /* write logicals */
+ ffpclx(fptr, 3, 1, 1, 1, larray, &status); /* write bits */
+ ffpclb(fptr, 4, 1, 1, 1, boutarray, &status);
+ ffpcli(fptr, 5, 1, 1, 1, ioutarray, &status);
+ ffpclj(fptr, 6, 1, 1, 1, joutarray, &status);
+ ffpcle(fptr, 7, 1, 1, 1, eoutarray, &status);
+ ffpcld(fptr, 8, 1, 1, 1, doutarray, &status);
+
+ for (ii = 2; ii <= 20; ii++) /* loop over rows 1 - 20 */
+ {
+ strncpy(inskey[0], iskey, ii);
+ inskey[0][ii] = '\0';
+ ffpcls(fptr, 1, ii, 1, 1, inskey, &status); /* write string values */
+
+ ffpcll(fptr, 2, ii, 1, ii, larray, &status); /* write logicals */
+ ffpclu(fptr, 2, ii, ii-1, 1, &status);
+
+ ffpclx(fptr, 3, ii, 1, ii, larray, &status); /* write bits */
+
+ ffpclb(fptr, 4, ii, 1, ii, boutarray, &status);
+ ffpclu(fptr, 4, ii, ii-1, 1, &status);
+
+ ffpcli(fptr, 5, ii, 1, ii, ioutarray, &status);
+ ffpclu(fptr, 5, ii, ii-1, 1, &status);
+
+ ffpclj(fptr, 6, ii, 1, ii, joutarray, &status);
+ ffpclu(fptr, 6, ii, ii-1, 1, &status);
+
+ ffpcle(fptr, 7, ii, 1, ii, eoutarray, &status);
+ ffpclu(fptr, 7, ii, ii-1, 1, &status);
+
+ ffpcld(fptr, 8, ii, 1, ii, doutarray, &status);
+ ffpclu(fptr, 8, ii, ii-1, 1, &status);
+ }
+ printf("ffpcl_ status = %d\n", status);
+
+ /*
+ #################################
+ # close then reopen this HDU #
+ #################################
+ */
+
+
+ ffmrhd(fptr, -1, &hdutype, &status);
+ ffmrhd(fptr, 1, &hdutype, &status);
+
+ /*
+ #############################
+ # read data from columns #
+ #############################
+ */
+
+ ffgkyj(fptr, "PCOUNT", &pcount, comm, &status);
+ printf("PCOUNT = %ld\n", pcount);
+
+ /* initialize the variables to be read */
+ strcpy(inskey[0]," ");
+ strcpy(iskey," ");
+
+
+ printf("HDU number = %d\n", ffghdn(fptr, &hdunum));
+ for (ii = 1; ii <= 20; ii++) /* loop over rows 1 - 20 */
+ {
+ for (jj = 0; jj < ii; jj++)
+ {
+ larray[jj] = 0;
+ boutarray[jj] = 0;
+ ioutarray[jj] = 0;
+ joutarray[jj] = 0;
+ eoutarray[jj] = 0;
+ doutarray[jj] = 0;
+ }
+
+ ffgcvs(fptr, 1, ii, 1, 1, iskey, inskey, &anynull, &status);
+ printf("A %s %d\nL", inskey[0], status);
+
+ ffgcl( fptr, 2, ii, 1, ii, larray, &status);
+ for (jj = 0; jj < ii; jj++)
+ printf(" %2d", larray[jj]);
+ printf(" %d\nX", status);
+
+ ffgcx(fptr, 3, ii, 1, ii, larray, &status);
+ for (jj = 0; jj < ii; jj++)
+ printf(" %2d", larray[jj]);
+ printf(" %d\nB", status);
+
+ ffgcvb(fptr, 4, ii, 1, ii, 99, boutarray, &anynull, &status);
+ for (jj = 0; jj < ii; jj++)
+ printf(" %2d", boutarray[jj]);
+ printf(" %d\nI", status);
+
+ ffgcvi(fptr, 5, ii, 1, ii, 99, ioutarray, &anynull, &status);
+ for (jj = 0; jj < ii; jj++)
+ printf(" %2d", ioutarray[jj]);
+ printf(" %d\nJ", status);
+
+ ffgcvj(fptr, 6, ii, 1, ii, 99, joutarray, &anynull, &status);
+ for (jj = 0; jj < ii; jj++)
+ printf(" %2ld", joutarray[jj]);
+ printf(" %d\nE", status);
+
+ ffgcve(fptr, 7, ii, 1, ii, 99., eoutarray, &anynull, &status);
+ for (jj = 0; jj < ii; jj++)
+ printf(" %2.0f", eoutarray[jj]);
+ printf(" %d\nD", status);
+
+ ffgcvd(fptr, 8, ii, 1, ii, 99., doutarray, &anynull, &status);
+ for (jj = 0; jj < ii; jj++)
+ printf(" %2.0f", doutarray[jj]);
+ printf(" %d\n", status);
+
+ ffgdes(fptr, 8, ii, &repeat, &offset, &status);
+ printf("Column 8 repeat and offset = %ld %ld\n", repeat, offset);
+ }
+
+ /*
+ #####################################
+ # create another image extension #
+ #####################################
+ */
+
+ bitpix = 32;
+ naxis = 2;
+ naxes[0] = 10;
+ naxes[1] = 2;
+ npixels = 20;
+
+/* ffcrim(fptr, bitpix, naxis, naxes, &status); */
+ ffiimg(fptr, bitpix, naxis, naxes, &status);
+ printf("\nffcrim status = %d\n", status);
+
+ /* initialize arrays of values to write to primary array */
+ for (ii = 0; ii < npixels; ii++)
+ {
+ boutarray[ii] = ii * 2;
+ ioutarray[ii] = ii * 2;
+ joutarray[ii] = ii * 2;
+ koutarray[ii] = ii * 2;
+ eoutarray[ii] = ii * 2;
+ doutarray[ii] = ii * 2;
+ }
+
+ /* write a few pixels with each datatype */
+ ffppr(fptr, TBYTE, 1, 2, &boutarray[0], &status);
+ ffppr(fptr, TSHORT, 3, 2, &ioutarray[2], &status);
+ ffppr(fptr, TINT, 5, 2, &koutarray[4], &status);
+ ffppr(fptr, TSHORT, 7, 2, &ioutarray[6], &status);
+ ffppr(fptr, TLONG, 9, 2, &joutarray[8], &status);
+ ffppr(fptr, TFLOAT, 11, 2, &eoutarray[10], &status);
+ ffppr(fptr, TDOUBLE, 13, 2, &doutarray[12], &status);
+ printf("ffppr status = %d\n", status);
+
+ /* read back the pixels with each datatype */
+ bnul = 0;
+ inul = 0;
+ knul = 0;
+ jnul = 0;
+ enul = 0.;
+ dnul = 0.;
+
+ ffgpv(fptr, TBYTE, 1, 14, &bnul, binarray, &anynull, &status);
+ ffgpv(fptr, TSHORT, 1, 14, &inul, iinarray, &anynull, &status);
+ ffgpv(fptr, TINT, 1, 14, &knul, kinarray, &anynull, &status);
+ ffgpv(fptr, TLONG, 1, 14, &jnul, jinarray, &anynull, &status);
+ ffgpv(fptr, TFLOAT, 1, 14, &enul, einarray, &anynull, &status);
+ ffgpv(fptr, TDOUBLE, 1, 14, &dnul, dinarray, &anynull, &status);
+
+ printf("\nImage values written with ffppr and read with ffgpv:\n");
+ npixels = 14;
+ for (ii = 0; ii < npixels; ii++)
+ printf(" %2d", binarray[ii]);
+ printf(" %d (byte)\n", anynull);
+ for (ii = 0; ii < npixels; ii++)
+ printf(" %2d", iinarray[ii]);
+ printf(" %d (short)\n", anynull);
+ for (ii = 0; ii < npixels; ii++)
+ printf(" %2d", kinarray[ii]);
+ printf(" %d (int)\n", anynull);
+ for (ii = 0; ii < npixels; ii++)
+ printf(" %2ld", jinarray[ii]);
+ printf(" %d (long)\n", anynull);
+ for (ii = 0; ii < npixels; ii++)
+ printf(" %2.0f", einarray[ii]);
+ printf(" %d (float)\n", anynull);
+ for (ii = 0; ii < npixels; ii++)
+ printf(" %2.0f", dinarray[ii]);
+ printf(" %d (double)\n", anynull);
+
+ /*
+ ##########################################
+ # test world coordinate system routines #
+ ##########################################
+ */
+
+ xrval = 45.83;
+ yrval = 63.57;
+ xrpix = 256.;
+ yrpix = 257.;
+ xinc = -.00277777;
+ yinc = .00277777;
+
+ /* write the WCS keywords */
+ /* use example values from the latest WCS document */
+ ffpkyd(fptr, "CRVAL1", xrval, 10, "comment", &status);
+ ffpkyd(fptr, "CRVAL2", yrval, 10, "comment", &status);
+ ffpkyd(fptr, "CRPIX1", xrpix, 10, "comment", &status);
+ ffpkyd(fptr, "CRPIX2", yrpix, 10, "comment", &status);
+ ffpkyd(fptr, "CDELT1", xinc, 10, "comment", &status);
+ ffpkyd(fptr, "CDELT2", yinc, 10, "comment", &status);
+ /* ffpkyd(fptr, "CROTA2", rot, 10, "comment", &status); */
+ ffpkys(fptr, "CTYPE1", xcoordtype, "comment", &status);
+ ffpkys(fptr, "CTYPE2", ycoordtype, "comment", &status);
+ printf("\nWrote WCS keywords status = %d\n",status);
+
+ xrval = 0.;
+ yrval = 0.;
+ xrpix = 0.;
+ yrpix = 0.;
+ xinc = 0.;
+ yinc = 0.;
+ rot = 0.;
+
+ ffgics(fptr, &xrval, &yrval, &xrpix,
+ &yrpix, &xinc, &yinc, &rot, ctype, &status);
+ printf("Read WCS keywords with ffgics status = %d\n",status);
+
+ xpix = 0.5;
+ ypix = 0.5;
+
+ ffwldp(xpix,ypix,xrval,yrval,xrpix,yrpix,xinc,yinc,rot,ctype,
+ &xpos, &ypos,&status);
+
+ printf(" CRVAL1, CRVAL2 = %16.12f, %16.12f\n", xrval,yrval);
+ printf(" CRPIX1, CRPIX2 = %16.12f, %16.12f\n", xrpix,yrpix);
+ printf(" CDELT1, CDELT2 = %16.12f, %16.12f\n", xinc,yinc);
+ printf(" Rotation = %10.3f, CTYPE = %s\n", rot, ctype);
+ printf("Calculated sky coordinate with ffwldp status = %d\n",status);
+ printf(" Pixels (%8.4f,%8.4f) --> (%11.6f, %11.6f) Sky\n",
+ xpix,ypix,xpos,ypos);
+ ffxypx(xpos,ypos,xrval,yrval,xrpix,yrpix,xinc,yinc,rot,ctype,
+ &xpix, &ypix,&status);
+ printf("Calculated pixel coordinate with ffxypx status = %d\n",status);
+ printf(" Sky (%11.6f, %11.6f) --> (%8.4f,%8.4f) Pixels\n",
+ xpos,ypos,xpix,ypix);
+ /*
+ ######################################
+ # append another ASCII table #
+ ######################################
+ */
+
+ strcpy(tform[0], "A15");
+ strcpy(tform[1], "I11");
+ strcpy(tform[2], "F15.6");
+ strcpy(tform[3], "E13.5");
+ strcpy(tform[4], "D22.14");
+
+ strcpy(ttype[0], "Name");
+ strcpy(ttype[1], "Ivalue");
+ strcpy(ttype[2], "Fvalue");
+ strcpy(ttype[3], "Evalue");
+ strcpy(ttype[4], "Dvalue");
+
+ strcpy(tunit[0], "");
+ strcpy(tunit[1], "m**2");
+ strcpy(tunit[2], "cm");
+ strcpy(tunit[3], "erg/s");
+ strcpy(tunit[4], "km/s");
+
+ nrows = 11;
+ tfields = 5;
+ strcpy(tblname, "new_table");
+
+ ffcrtb(fptr, ASCII_TBL, nrows, tfields, ttype, tform, tunit, tblname,
+ &status);
+ printf("\nffcrtb status = %d\n", status);
+
+ extvers = 5;
+ ffpkyj(fptr, "EXTVER", extvers, "extension version number", &status);
+
+ ffpcl(fptr, TSTRING, 1, 1, 1, 3, onskey, &status); /* write string values */
+
+ /* initialize arrays of values to write */
+
+ for (ii = 0; ii < npixels; ii++)
+ {
+ boutarray[ii] = ii * 3;
+ ioutarray[ii] = ii * 3;
+ joutarray[ii] = ii * 3;
+ koutarray[ii] = ii * 3;
+ eoutarray[ii] = ii * 3;
+ doutarray[ii] = ii * 3;
+ }
+
+ for (ii = 2; ii < 6; ii++) /* loop over cols 2 - 5 */
+ {
+ ffpcl(fptr, TBYTE, ii, 1, 1, 2, boutarray, &status);
+ ffpcl(fptr, TSHORT, ii, 3, 1, 2, &ioutarray[2], &status);
+ ffpcl(fptr, TLONG, ii, 5, 1, 2, &joutarray[4], &status);
+ ffpcl(fptr, TFLOAT, ii, 7, 1, 2, &eoutarray[6], &status);
+ ffpcl(fptr, TDOUBLE, ii, 9, 1, 2, &doutarray[8], &status);
+ }
+ printf("ffpcl status = %d\n", status);
+
+ /* read back the pixels with each datatype */
+ ffgcv(fptr, TBYTE, 2, 1, 1, 10, &bnul, binarray, &anynull, &status);
+ ffgcv(fptr, TSHORT, 2, 1, 1, 10, &inul, iinarray, &anynull, &status);
+ ffgcv(fptr, TINT, 3, 1, 1, 10, &knul, kinarray, &anynull, &status);
+ ffgcv(fptr, TLONG, 3, 1, 1, 10, &jnul, jinarray, &anynull, &status);
+ ffgcv(fptr, TFLOAT, 4, 1, 1, 10, &enul, einarray, &anynull, &status);
+ ffgcv(fptr, TDOUBLE, 5, 1, 1, 10, &dnul, dinarray, &anynull, &status);
+
+ printf("\nColumn values written with ffpcl and read with ffgcl:\n");
+ npixels = 10;
+ for (ii = 0; ii < npixels; ii++)
+ printf(" %2d", binarray[ii]);
+ printf(" %d (byte)\n", anynull);
+ for (ii = 0; ii < npixels; ii++)
+ printf(" %2d", iinarray[ii]);
+ printf(" %d (short)\n", anynull);
+
+ for (ii = 0; ii < npixels; ii++)
+ printf(" %2d", kinarray[ii]);
+ printf(" %d (int)\n", anynull);
+
+ for (ii = 0; ii < npixels; ii++)
+ printf(" %2ld", jinarray[ii]);
+ printf(" %d (long)\n", anynull);
+ for (ii = 0; ii < npixels; ii++)
+ printf(" %2.0f", einarray[ii]);
+ printf(" %d (float)\n", anynull);
+ for (ii = 0; ii < npixels; ii++)
+ printf(" %2.0f", dinarray[ii]);
+ printf(" %d (double)\n", anynull);
+
+ /*
+ ###########################################################
+ # perform stress test by cycling thru all the extensions #
+ ###########################################################
+ */
+ printf("\nRepeatedly move to the 1st 4 HDUs of the file:\n");
+ for (ii = 0; ii < 10; ii++)
+ {
+ ffmahd(fptr, 1, &hdutype, &status);
+ printf("%d", ffghdn(fptr, &hdunum));
+ ffmrhd(fptr, 1, &hdutype, &status);
+ printf("%d", ffghdn(fptr, &hdunum));
+ ffmrhd(fptr, 1, &hdutype, &status);
+ printf("%d", ffghdn(fptr, &hdunum));
+ ffmrhd(fptr, 1, &hdutype, &status);
+ printf("%d", ffghdn(fptr, &hdunum));
+ ffmrhd(fptr, -1, &hdutype, &status);
+ printf("%d", ffghdn(fptr, &hdunum));
+ if (status > 0)
+ break;
+ }
+ printf("\n");
+
+ printf("Move to extensions by name and version number: (ffmnhd)\n");
+ extvers = 1;
+ ffmnhd(fptr, ANY_HDU, binname, (int) extvers, &status);
+ ffghdn(fptr, &hdunum);
+ printf(" %s, %ld = hdu %d, %d\n", binname, extvers, hdunum, status);
+ extvers = 3;
+ ffmnhd(fptr, ANY_HDU, binname, (int) extvers, &status);
+ ffghdn(fptr, &hdunum);
+ printf(" %s, %ld = hdu %d, %d\n", binname, extvers, hdunum, status);
+ extvers = 4;
+ ffmnhd(fptr, ANY_HDU, binname, (int) extvers, &status);
+ ffghdn(fptr, &hdunum);
+ printf(" %s, %ld = hdu %d, %d\n", binname, extvers, hdunum, status);
+
+
+ strcpy(tblname, "Test-ASCII");
+ extvers = 2;
+ ffmnhd(fptr, ANY_HDU, tblname, (int) extvers, &status);
+ ffghdn(fptr, &hdunum);
+ printf(" %s, %ld = hdu %d, %d\n", tblname, extvers, hdunum, status);
+
+ strcpy(tblname, "new_table");
+ extvers = 5;
+ ffmnhd(fptr, ANY_HDU, tblname, (int) extvers, &status);
+ ffghdn(fptr, &hdunum);
+ printf(" %s, %ld = hdu %d, %d\n", tblname, extvers, hdunum, status);
+ extvers = 0;
+ ffmnhd(fptr, ANY_HDU, binname, (int) extvers, &status);
+ ffghdn(fptr, &hdunum);
+ printf(" %s, %ld = hdu %d, %d\n", binname, extvers, hdunum, status);
+ extvers = 17;
+ ffmnhd(fptr, ANY_HDU, binname, (int) extvers, &status);
+ ffghdn(fptr, &hdunum);
+ printf(" %s, %ld = hdu %d, %d", binname, extvers, hdunum, status);
+ printf (" (expect a 301 error status here)\n");
+ status = 0;
+
+ ffthdu(fptr, &hdunum, &status);
+ printf("Total number of HDUs in the file = %d\n", hdunum);
+ /*
+ ########################
+ # checksum tests #
+ ########################
+ */
+ checksum = 1234567890;
+ ffesum(checksum, 0, asciisum);
+ printf("\nEncode checksum: %lu -> %s\n", checksum, asciisum);
+ checksum = 0;
+ ffdsum(asciisum, 0, &checksum);
+ printf("Decode checksum: %s -> %lu\n", asciisum, checksum);
+
+ ffpcks(fptr, &status);
+
+ /*
+ don't print the CHECKSUM value because it is different every day
+ because the current date is in the comment field.
+
+ ffgcrd(fptr, "CHECKSUM", card, &status);
+ printf("%s\n", card);
+ */
+
+ ffgcrd(fptr, "DATASUM", card, &status);
+ printf("%.30s\n", card);
+
+ ffgcks(fptr, &datsum, &checksum, &status);
+ printf("ffgcks data checksum, status = %lu, %d\n",
+ datsum, status);
+
+ ffvcks(fptr, &datastatus, &hdustatus, &status);
+ printf("ffvcks datastatus, hdustatus, status = %d %d %d\n",
+ datastatus, hdustatus, status);
+
+ ffprec(fptr,
+ "new_key = 'written by fxprec' / to change checksum", &status);
+ ffupck(fptr, &status);
+ printf("ffupck status = %d\n", status);
+
+ ffgcrd(fptr, "DATASUM", card, &status);
+ printf("%.30s\n", card);
+ ffvcks(fptr, &datastatus, &hdustatus, &status);
+ printf("ffvcks datastatus, hdustatus, status = %d %d %d\n",
+ datastatus, hdustatus, status);
+
+ /*
+ delete the checksum keywords, so that the FITS file is always
+ the same, regardless of the date of when testprog is run.
+ */
+
+ ffdkey(fptr, "CHECKSUM", &status);
+ ffdkey(fptr, "DATASUM", &status);
+
+ /*
+ ############################
+ # close file and quit #
+ ############################
+ */
+
+ errstatus: /* jump here on error */
+
+ ffclos(fptr, &status);
+ printf("ffclos status = %d\n", status);
+
+ printf("\nNormally, there should be 8 error messages on the stack\n");
+ printf("all regarding 'numerical overflows':\n");
+
+ ffgmsg(errmsg);
+ nmsg = 0;
+
+ while (errmsg[0])
+ {
+ printf(" %s\n", errmsg);
+ nmsg++;
+ ffgmsg(errmsg);
+ }
+
+ if (nmsg != 8)
+ printf("\nWARNING: Did not find the expected 8 error messages!\n");
+
+ ffgerr(status, errmsg);
+ printf("\nStatus = %d: %s\n", status, errmsg);
+
+ /* free the allocated memory */
+ for (ii = 0; ii < 21; ii++)
+ free(inskey[ii]);
+ for (ii = 0; ii < 10; ii++)
+ {
+ free(ttype[ii]);
+ free(tform[ii]);
+ free(tunit[ii]);
+ }
+
+ return(0);
+}
+
diff --git a/pkg/tbtables/cfitsio/testprog.out b/pkg/tbtables/cfitsio/testprog.out
new file mode 100644
index 00000000..c57d16f3
--- /dev/null
+++ b/pkg/tbtables/cfitsio/testprog.out
@@ -0,0 +1,797 @@
+CFITSIO TESTPROG, v2.401
+
+Try opening then closing a nonexistent file:
+ ffopen fptr, status = 0 104 (expect an error)
+ ffclos status = 115
+
+ffinit create new file status = 0
+Name of file = testprog.fit, I/O mode = 1
+
+test writing of long string keywords:
+ 123456789012345678901234567890123456789012345678901234567890123456789012345
+'12345678901234567890123456789012345678901234567890123456789012345678'
+ 1234567890123456789012345678901234567890123456789012345678901234'6789012345
+'1234567890123456789012345678901234567890123456789012345678901234''67'
+ 1234567890123456789012345678901234567890123456789012345678901234''789012345
+'1234567890123456789012345678901234567890123456789012345678901234'''''
+ 1234567890123456789012345678901234567890123456789012345678901234567'9012345
+'1234567890123456789012345678901234567890123456789012345678901234567'
+ffflus status = 0
+HDU number = 1
+
+Values read back from primary array (99 = null pixel)
+The 1st, and every 4th pixel should be undefined:
+ 99 2 3 99 5 6 7 99 9 10 11 99 13 14 15 99 17 18 19 99 1 (ffgpvb)
+ 99 2 3 99 5 6 7 99 9 10 11 99 13 14 15 99 17 18 19 99 1 (ffgpvi)
+ 99 2 3 99 5 6 7 99 9 10 11 99 13 14 15 99 17 18 19 99 1 (ffgpvj)
+ 99 2 3 99 5 6 7 99 9 10 11 99 13 14 15 99 17 18 19 99 1 (ffgpve)
+ 99 2 3 99 5 6 7 99 9 10 11 99 13 14 15 99 17 18 19 99 1 (ffgpvd)
+ * 2 3 * 5 6 7 * 9 10 11 * 13 14 15 * 17 18 19 * 1 (ffgpfb)
+ * 2 3 * 5 6 7 * 9 10 11 * 13 14 15 * 17 18 19 * 1 (ffgpfi)
+ * 2 3 * 5 6 7 * 9 10 11 * 13 14 15 * 17 18 19 * 1 (ffgpfj)
+ * 2 3 * 5 6 7 * 9 10 11 * 13 14 15 * 17 18 19 * 1 (ffgpfe)
+ * 2 3 * 5 6 7 * 9 10 11 * 13 14 15 * 17 18 19 * 1 (ffgpfd)
+
+Closed then reopened the FITS file 10 times.
+HDU number = 1
+Name of file = testprog.fit, I/O mode = 1
+
+Read back keywords:
+simple = 1, bitpix = 32, naxis = 2, naxes = (10, 2)
+ pcount = 0, gcount = 1, extend = 1
+KEY_PREC= 'This keyword was written by fxprec' / comment goes here
+KEY_PREC : 'This keyword was written by fxprec' : comment goes here :
+KEY_PREC= 'This keyword was written by fxprec' / comment goes here
+KY_PKNS1 : 'first string' : fxpkns comment :
+KEY_PKYS value_string fxpkys comment 0
+KEY_PKYL 1 fxpkyl comment 0
+KEY_PKYJ 11 fxpkyj comment 0
+KEY_PKYJ 11.000000 fxpkyj comment 0
+KEY_PKYJ 11.000000 fxpkyj comment 0
+KEY_PKY S value_string fxpkys comment 0
+KEY_PKY L 1 fxpkyl comment 0
+KEY_PKY BYTE 11 fxpkyj comment 0
+KEY_PKY SHORT 11 fxpkyj comment 0
+KEY_PKY INT 11 fxpkyj comment 0
+KEY_PKY J 11 fxpkyj comment 0
+KEY_PKY E 13.131310 fxpkye comment 0
+KEY_PKY D 15.151515 fxpkyd comment 0
+KEY_PKYF 12.121210 fxpkyf comment 0
+KEY_PKYE 13.131310 fxpkye comment 0
+KEY_PKYG 14.14141414141414 fxpkyg comment 0
+KEY_PKYD 15.15151515151520 fxpkyd comment 0
+KEY_PKYC 13.131310 14.141410 fxpkyc comment 0
+KEY_PKFC 13.131313 14.141414 fxpkfc comment 0
+KEY_PKYM 15.151515 16.161616 fxpkym comment 0
+KEY_PKFM 15.151515 16.161616 fxpkfm comment 0
+KEY_PKYT 12345678 0.12345678901235 fxpkyt comment 0
+KEY_PKY J 11 [km/s/Mpc] fxpkyj comment 0
+KEY_PKY units = km/s/Mpc
+KEY_PKY J 11 fxpkyj comment 0
+KEY_PKY units =
+KEY_PKY J 11 [feet/second/second] fxpkyj comment 0
+KEY_PKY units = feet/second/second
+KEY_PKLS long string value =
+This is a very long string value that is continued over more than one keyword.
+header contains 65 keywords; located at keyword 27
+ffgkns: first string, second string,
+ffgknl: 1, 0, 1
+ffgknj: 11, 12, 13
+ffgkne: 13.131310, 14.141410, 15.151520
+ffgknd: 15.151515, 16.161616, 17.171717
+
+Before deleting the HISTORY and DATE keywords...
+COMMENT
+HISTORY
+DATE
+KY_PKNS1
+
+After deleting the keywords...
+COMMENT This keyword was written by fxpcom.
+KY_PKNS1= 'first string' / fxpkns comment
+
+After inserting the keywords...
+COMMENT This keyword was written by fxpcom.
+KY_IREC = 'This keyword inserted by fxirec'
+KY_IKYS = 'insert_value_string' / ikys comment
+KY_IKYJ = 49 / ikyj comment
+KY_IKYL = T / ikyl comment
+KY_IKYE = 1.2346E+01 / ikye comment
+KY_IKYD = 1.23456789012346E+01 / ikyd comment
+KY_IKYF = 12.3456 / ikyf comment
+KY_IKYG = 12.3456789012346 / ikyg comment
+KY_PKNS1= 'first string' / fxpkns comment
+
+After modifying the keywords...
+COMMENT This keyword was modified by fxmrec
+KY_MREC = 'This keyword was modified by fxmcrd'
+NEWIKYS = 'modified_string' / ikys comment
+KY_IKYJ = 50 / This is a modified comment
+KY_IKYL = F / ikyl comment
+KY_IKYE = -1.2346E+01 / ikye comment
+KY_IKYD = -1.23456789012346E+01 / modified comment
+KY_IKYF = -12.3456 / ikyf comment
+KY_IKYG = -12.3456789012346 / ikyg comment
+KY_PKNS1= 'first string' / fxpkns comment
+
+After updating the keywords...
+COMMENT This keyword was modified by fxmrec
+KY_UCRD = 'This keyword was updated by fxucrd'
+NEWIKYS = 'updated_string' / ikys comment
+KY_IKYJ = 51 / This is a modified comment
+KY_IKYL = T / ikyl comment
+KY_IKYE = -1.3346E+01 / ikye comment
+KY_IKYD = -1.33456789012346E+01 / modified comment
+KY_IKYF = -13.3456 / ikyf comment
+KY_IKYG = -13.3456789012346 / ikyg comment
+KY_PKNS1= 'first string' / fxpkns comment
+
+Keywords found using wildcard search (should be 13)...
+KEY_PKYS= 'value_string' / fxpkys comment
+KEY_PKYL= T / fxpkyl comment
+KEY_PKYJ= 11 / [feet/second/second] fxpkyj comment
+KEY_PKYF= 12.12121 / fxpkyf comment
+KEY_PKYE= 1.313131E+01 / fxpkye comment
+KEY_PKYG= 14.14141414141414 / fxpkyg comment
+KEY_PKYD= 1.51515151515152E+01 / fxpkyd comment
+KEY_PKYC= (1.313131E+01, 1.414141E+01) / fxpkyc comment
+KEY_PKYM= (1.51515151515152E+01, 1.61616161616162E+01) / fxpkym comment
+KEY_PKFC= (13.131313, 14.141414) / fxpkfc comment
+KEY_PKFM= (15.15151515151515, 16.16161616161616) / fxpkfm comment
+KEY_PKYT= 12345678.1234567890123456 / fxpkyt comment
+NEWIKYS = 'updated_string' / ikys comment
+
+Copied keyword: ffgkne: 14.141410, 15.151520, 13.131310
+Updated header using template file (ffpktp)
+
+ffibin status = 0
+HDU number = 2
+header contains 33 keywords; located at keyword 1
+header contains 33 keywords with room for 74 more
+TDIM3 = (1,2,8), 3, 1, 2, 8
+ffpcl_ status = 0
+
+Find the column numbers; a returned status value of 237 is
+expected and indicates that more than one column name matches
+the input column name template. Status = 219 indicates that
+there was no matching column name.
+Column Xvalue is number 3; status = 0.
+Column Avalue is number 1; status = 237.
+Column Lvalue is number 2; status = 237.
+Column Xvalue is number 3; status = 237.
+Column Bvalue is number 4; status = 237.
+Column Ivalue is number 5; status = 237.
+Column Jvalue is number 6; status = 237.
+Column Evalue is number 7; status = 237.
+Column Dvalue is number 8; status = 237.
+Column Cvalue is number 9; status = 237.
+Column Mvalue is number 10; status = 237.
+Column is number 0; status = 219.
+
+Information about each column:
+ 15A 16 15 15 Avalue, , A, 15, 1.000000, 0.000000, 1234554321, .
+ 1L 14 1 1 Lvalue, m**2, L, 1, 1.000000, 0.000000, 1234554321, .
+ 16X 1 16 1 Xvalue, cm, X, 16, 1.000000, 0.000000, 1234554321, .
+ 1B 11 1 1 Bvalue, erg/s, B, 1, 1.000000, 0.000000, 99, .
+ 1I 21 1 2 Ivalue, km/s, I, 1, 1.000000, 0.000000, 99, .
+ 1J 41 1 4 Jvalue, , J, 1, 1.000000, 0.000000, 99, .
+ 1E 42 1 4 Evalue, , E, 1, 1.000000, 0.000000, 1234554321, .
+ 1D 82 1 8 Dvalue, , D, 1, 1.000000, 0.000000, 1234554321, .
+ 1C 83 1 8 Cvalue, , C, 1, 1.000000, 0.000000, 1234554321, .
+ 1M 163 1 16 Mvalue, , M, 1, 1.000000, 0.000000, 1234554321, .
+
+ffitab status = 0
+HDU number = 2
+ffpcl_ status = 0
+
+ASCII table: rowlen, nrows, tfields, extname: 76 11 5 Test-ASCII
+ Name 1 A15
+ Ivalue 17 I10 m**2
+ Fvalue 28 F14.6 cm
+ Evalue 43 E12.5 erg/s
+ Dvalue 56 D21.14 km/s
+
+Data values read from ASCII table:
+ first string 1 1 1 1.0 1.0
+ second string 2 2 2 2.0 2.0
+ 3 3 3 3.0 3.0
+ UNDEFINED 4 4 4 4.0 4.0
+ 5 5 5 5.0 5.0
+ 6 6 6 6.0 6.0
+ 7 7 7 7.0 7.0
+ 8 8 8 8.0 8.0
+ 9 9 9 9.0 9.0
+ 10 10 10 10.0 10.0
+ 99 99 99 99.0 99.0
+
+ 1 1.000000 1.00000E+00 1.00000000000000E+00second string
+
+Column name is number 1; status = 0.
+Column Ivalue is number 2; status = 237.
+Column Fvalue is number 3; status = 237.
+Column Evalue is number 4; status = 237.
+Column Dvalue is number 5; status = 237.
+Column is number 0; status = 219.
+ A15 16 1 15 Name, 1, , A15, 1.000000, 0.000000, null1, .
+ I10 41 1 10 Ivalue, 17, m**2, I10, 1.000000, 0.000000, null2, .
+F14.6 82 1 14 Fvalue, 28, cm, F14.6, 1.000000, 0.000000, null3, .
+E12.5 42 1 12 Evalue, 43, erg/s, E12.5, 1.000000, 0.000000, null4, .
+D21.14 82 1 21 Dvalue, 56, km/s, D21.14, 1.000000, 0.000000, null5, .
+
+
+Data values after inserting 3 rows after row 2:
+ first string 1 1 1 1.0 1.0
+ second string 2 2 2 2.0 2.0
+ 0 0 0 0.0 0.0
+ 0 0 0 0.0 0.0
+ 0 0 0 0.0 0.0
+ 3 3 3 3.0 3.0
+ UNDEFINED 4 4 4 4.0 4.0
+ 5 5 5 5.0 5.0
+ 6 6 6 6.0 6.0
+ 7 7 7 7.0 7.0
+ 8 8 8 8.0 8.0
+ 9 9 9 9.0 9.0
+ 10 10 10 10.0 10.0
+ 99 99 99 99.0 99.0
+
+Data values after deleting 2 rows at row 10:
+ first string 1 1 1 1.0 1.0
+ second string 2 2 2 2.0 2.0
+ 0 0 0 0.0 0.0
+ 0 0 0 0.0 0.0
+ 0 0 0 0.0 0.0
+ 3 3 3 3.0 3.0
+ UNDEFINED 4 4 4 4.0 4.0
+ 5 5 5 5.0 5.0
+ 6 6 6 6.0 6.0
+ 9 9 9 9.0 9.0
+ 10 10 10 10.0 10.0
+ 99 99 99 99.0 99.0
+
+Data values after deleting column 3:
+ first string 1 1 1.0 1.0
+ second string 2 2 2.0 2.0
+ 0 0 0.0 0.0
+ 0 0 0.0 0.0
+ 0 0 0.0 0.0
+ 3 3 3.0 3.0
+ UNDEFINED 4 4 4.0 4.0
+ 5 5 5.0 5.0
+ 6 6 6.0 6.0
+ 9 9 9.0 9.0
+ 10 10 10.0 10.0
+ 99 99 99.0 99.0
+
+Data values after inserting column 5:
+ first string 1 1 1.0 1.0 0
+ second string 2 2 2.0 2.0 0
+ 0 0 0.0 0.0 0
+ 0 0 0.0 0.0 0
+ 0 0 0.0 0.0 0
+ 3 3 3.0 3.0 0
+ UNDEFINED 4 4 4.0 4.0 0
+ 5 5 5.0 5.0 0
+ 6 6 6.0 6.0 0
+ 9 9 9.0 9.0 0
+ 10 10 10.0 10.0 0
+ 99 99 99.0 99.0 0
+Create temporary file: ffinit status = 0
+
+Create null primary array: ffiimg status = 0
+
+Create ASCII table with 0 columns: ffitab status = 0
+copy column, ffcpcl status = 0
+copy column, ffcpcl status = 0
+copy column, ffcpcl status = 0
+copy column, ffcpcl status = 0
+
+Create Binary table with 0 columns: ffibin status = 0
+copy column, ffcpcl status = 0
+copy column, ffcpcl status = 0
+copy column, ffcpcl status = 0
+copy column, ffcpcl status = 0
+Delete the tmp file: ffdelt status = 0
+HDU number = 3
+header contains 38 keywords with room for 69 more
+
+Binary table: nrows, tfields, extname, pcount: 21 10 Test-BINTABLE 0
+ Avalue 15A
+ Lvalue 1L m**2
+ Xvalue 16X cm
+ Bvalue 1B erg/s
+ Ivalue 1I km/s
+ Jvalue 1J
+ Evalue 1E
+ Dvalue 1D
+ Cvalue 1C
+ Mvalue 1M
+
+Data values read from binary table:
+ Bit column (X) data values:
+
+01001100 01110000 11110000 01111100 00000000
+
+null string column value = -- (should be --)
+
+Read columns with ffgcv_:
+ first string 0 76 1 1 1 1.0 1.0 ( 1.0, -2.0) ( 1.0, -2.0)
+ second string 1 112 2 2 2 2.0 2.0 ( 3.0, -4.0) ( 3.0, -4.0)
+ 0 240 3 3 3 3.0 3.0 ( 5.0, -6.0) ( 5.0, -6.0)
+ NOT DEFINED 0 124 0 -4 -4 -4.0 -4.0 ( 7.0, -8.0) ( 7.0, -8.0)
+ NOT DEFINED 1 0 5 5 5 5.0 5.0 ( 9.0,-10.0) ( 9.0,-10.0)
+ NOT DEFINED 1 0 0 -6 -6 -6.0 -6.0 ( 11.0,-12.0) ( 11.0,-12.0)
+ NOT DEFINED 0 0 7 7 7 7.0 7.0 ( 13.0,-14.0) ( 13.0,-14.0)
+ NOT DEFINED 0 0 0 -8 -8 -8.0 -8.0 ( 15.0,-16.0) ( 15.0,-16.0)
+ NOT DEFINED 0 0 9 9 9 9.0 9.0 ( 17.0,-18.0) ( 17.0,-18.0)
+ NOT DEFINED 1 0 0 -10 -10 -10.0 -10.0 ( 19.0,-20.0) ( 19.0,-20.0)
+ NOT DEFINED 0 0 98 98 98 98.0 98.0 ( 0.0, 0.0) ( 0.0, 0.0)
+ NOT DEFINED 1 0 12 12 12 12.0 12.0 ( 0.0, 0.0) ( 0.0, 0.0)
+ NOT DEFINED 0 0 98 98 98 98.0 98.0 ( 0.0, 0.0) ( 0.0, 0.0)
+ NOT DEFINED 0 0 0 -14 -14 -14.0 -14.0 ( 0.0, 0.0) ( 0.0, 0.0)
+ NOT DEFINED 0 0 0 98 98 98.0 98.0 ( 0.0, 0.0) ( 0.0, 0.0)
+ NOT DEFINED 0 0 0 -16 -16 -16.0 -16.0 ( 0.0, 0.0) ( 0.0, 0.0)
+ NOT DEFINED 1 0 0 98 98 98.0 98.0 ( 0.0, 0.0) ( 0.0, 0.0)
+ NOT DEFINED 1 0 0 -18 -18 -18.0 -18.0 ( 0.0, 0.0) ( 0.0, 0.0)
+ NOT DEFINED 1 0 0 98 98 98.0 98.0 ( 0.0, 0.0) ( 0.0, 0.0)
+ NOT DEFINED 1 0 0 -20 -20 -20.0 -20.0 ( 0.0, 0.0) ( 0.0, 0.0)
+ NOT DEFINED 0 0 0 98 98 98.0 98.0 ( 0.0, 0.0) ( 0.0, 0.0)
+
+Read columns with ffgcf_:
+ first string 0 76 1 1 1 1.0 1.0 ( 1.0, -2.0) ( 1.0, -2.0)
+ second string 1 112 2 2 2 2.0 2.0 ( 3.0, -4.0) ( 3.0, -4.0)
+ 0 240 3 3 3 3.0 3.0 ( 5.0, -6.0) ( 5.0, -6.0)
+ 0 124 0 -4 -4 -4.0 -4.0 ( 7.0, -8.0) ( 7.0, -8.0)
+ 1 0 5 5 5 5.0 5.0 ( 9.0,-10.0) ( 9.0,-10.0)
+ 1 0 0 -6 -6 -6.0 -6.0 ( 11.0,-12.0) ( 11.0,-12.0)
+ 0 0 7 7 7 7.0 7.0 ( 13.0,-14.0) ( 13.0,-14.0)
+ 0 0 0 -8 -8 -8.0 -8.0 ( 15.0,-16.0) ( 15.0,-16.0)
+ 0 0 9 9 9 9.0 9.0 ( 17.0,-18.0) ( 17.0,-18.0)
+ 1 0 0 -10 -10 -10.0 -10.0 ( 19.0,-20.0) ( 19.0,-20.0)
+ 0 0 99 99
+ 1 0 12 12
+ 0 0 99 99
+ 0 0 0 -14
+ 0 0 0 99
+ 0 0 0 -16
+ 1 0 0 99
+ 1 0 0 -18
+ 1 0 0 99
+ 1 0 0 -20
+ 0 0 0 99
+
+Data values after inserting 3 rows after row 2:
+ first string 1 1 1 1.0 1.0
+ second string 2 2 2 2.0 2.0
+ NOT DEFINED 0 0 0 0.0 0.0
+ NOT DEFINED 0 0 0 0.0 0.0
+ NOT DEFINED 0 0 0 0.0 0.0
+ 3 3 3 3.0 3.0
+ NOT DEFINED 0 -4 -4 -4.0 -4.0
+ NOT DEFINED 5 5 5 5.0 5.0
+ NOT DEFINED 0 -6 -6 -6.0 -6.0
+ NOT DEFINED 7 7 7 7.0 7.0
+ NOT DEFINED 0 -8 -8 -8.0 -8.0
+ NOT DEFINED 9 9 9 9.0 9.0
+ NOT DEFINED 0 -10 -10 -10.0 -10.0
+ NOT DEFINED 98 98 98 98.0 98.0
+
+Data values after deleting 2 rows at row 10:
+ first string 1 1 1 1.0 1.0
+ second string 2 2 2 2.0 2.0
+ NOT DEFINED 0 0 0 0.0 0.0
+ NOT DEFINED 0 0 0 0.0 0.0
+ NOT DEFINED 0 0 0 0.0 0.0
+ 3 3 3 3.0 3.0
+ NOT DEFINED 0 -4 -4 -4.0 -4.0
+ NOT DEFINED 5 5 5 5.0 5.0
+ NOT DEFINED 0 -6 -6 -6.0 -6.0
+ NOT DEFINED 9 9 9 9.0 9.0
+ NOT DEFINED 0 -10 -10 -10.0 -10.0
+ NOT DEFINED 98 98 98 98.0 98.0
+
+Data values after deleting column 6:
+ first string 1 1 1.0 1.0
+ second string 2 2 2.0 2.0
+ NOT DEFINED 0 0 0.0 0.0
+ NOT DEFINED 0 0 0.0 0.0
+ NOT DEFINED 0 0 0.0 0.0
+ 3 3 3.0 3.0
+ NOT DEFINED 0 -4 -4.0 -4.0
+ NOT DEFINED 5 5 5.0 5.0
+ NOT DEFINED 0 -6 -6.0 -6.0
+ NOT DEFINED 9 9 9.0 9.0
+ NOT DEFINED 0 -10 -10.0 -10.0
+ NOT DEFINED 98 98 98.0 98.0
+
+Data values after inserting column 8:
+ first string 1 1 1.0 1.0 0
+ second string 2 2 2.0 2.0 0
+ NOT DEFINED 0 0 0.0 0.0 0
+ NOT DEFINED 0 0 0.0 0.0 0
+ NOT DEFINED 0 0 0.0 0.0 0
+ 3 3 3.0 3.0 0
+ NOT DEFINED 0 -4 -4.0 -4.0 0
+ NOT DEFINED 5 5 5.0 5.0 0
+ NOT DEFINED 0 -6 -6.0 -6.0 0
+ NOT DEFINED 9 9 9.0 9.0 0
+ NOT DEFINED 0 -10 -10.0 -10.0 0
+ NOT DEFINED 98 98 98.0 98.0 0
+
+Values after setting 1st 10 elements in column 8 = null:
+ first string 1 1 1.0 1.0 98
+ second string 2 2 2.0 2.0 98
+ NOT DEFINED 0 0 0.0 0.0 98
+ NOT DEFINED 0 0 0.0 0.0 98
+ NOT DEFINED 0 0 0.0 0.0 98
+ 3 3 3.0 3.0 98
+ NOT DEFINED 0 -4 -4.0 -4.0 98
+ NOT DEFINED 5 5 5.0 5.0 98
+ NOT DEFINED 0 -6 -6.0 -6.0 98
+ NOT DEFINED 9 9 9.0 9.0 98
+ NOT DEFINED 0 -10 -10.0 -10.0 0
+ NOT DEFINED 98 98 98.0 98.0 0
+Create temporary file: ffinit status = 0
+
+Create null primary array: ffiimg status = 0
+
+Create binary table with 0 columns: ffibin status = 0
+copy column, ffcpcl status = 0
+copy column, ffcpcl status = 0
+copy column, ffcpcl status = 0
+copy column, ffcpcl status = 0
+copy column, ffcpcl status = 0
+copy column, ffcpcl status = 0
+copy column, ffcpcl status = 0
+Delete the tmp file: ffdelt status = 0
+ffibin status = 0
+HDU number = 2
+ 0 1000 10000 33000 66000 -999
+ 0 1000 10000 32768 65535 -999
+ 0 1000 10000 32800 65500 -999
+
+ 0 1 10 33 66 -999
+ -32768 -31768 -22768 0 32767 -999
+ -1 9 99 327 654 -999
+
+Create image extension: ffiimg status = 0
+HDU number = 3
+
+Wrote whole 2D array: ffp2di status = 0
+
+Read whole 2D array: ffg2di status = 0
+ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 0 0 0 0
+ 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 0 0 0 0
+ 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 0 0 0 0
+ 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 0 0 0 0
+ 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 0 0 0 0
+ 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 0 0 0 0
+ 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 0 0 0 0
+ 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 0 0 0 0
+ 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 0 0 0 0
+ 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 0 0 0 0
+ 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 0 0 0 0
+ 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 0 0 0 0
+ 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 0 0 0 0
+ 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 0 0 0 0
+ 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 0 0 0 0
+ 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 0 0 0 0
+ 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 0 0 0 0
+ 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 0 0 0 0
+ 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 0 0 0 0
+ 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 0 0 0 0
+ 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 0 0 0 0
+ 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 0 0 0 0
+ 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 0 0 0 0
+ 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 0 0 0 0
+ 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+
+Wrote subset 2D array: ffpssi status = 0
+
+Read whole 2D array: ffg2di status = 0
+ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 0 0 0 0
+ 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 0 0 0 0
+ 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 0 0 0 0
+ 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 0 0 0 0
+ 40 41 42 43 0 -1 -2 -3 -4 -5 -6 -7 -8 -9 54 0 0 0 0
+ 50 51 52 53 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 64 0 0 0 0
+ 60 61 62 63 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 74 0 0 0 0
+ 70 71 72 73 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 84 0 0 0 0
+ 80 81 82 83 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 94 0 0 0 0
+ 90 91 92 93 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 104 0 0 0 0
+ 100 101 102 103 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 114 0 0 0 0
+ 110 111 112 113 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 124 0 0 0 0
+ 120 121 122 123 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 134 0 0 0 0
+ 130 131 132 133 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 144 0 0 0 0
+ 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 0 0 0 0
+ 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 0 0 0 0
+ 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 0 0 0 0
+ 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 0 0 0 0
+ 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 0 0 0 0
+ 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 0 0 0 0
+ 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 0 0 0 0
+ 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 0 0 0 0
+ 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 0 0 0 0
+ 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 0 0 0 0
+ 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+
+Read subset of 2D array: ffgsvi status = 0
+ 41 43 -1 -3 -5 71 73 -31 -33 -35
+
+Create image extension: ffiimg status = 0
+HDU number = 4
+Create temporary file: ffinit status = 0
+Copy image extension to primary array of tmp file.
+ffcopy status = 0
+SIMPLE = T / file does conform to FITS standard
+BITPIX = 16 / number of bits per data pixel
+NAXIS = 2 / number of data axes
+NAXIS1 = 15 / length of data axis 1
+NAXIS2 = 25 / length of data axis 2
+EXTEND = T / FITS dataset may contain extensions
+Delete the tmp file: ffdelt status = 0
+Delete the image extension; hdutype, status = 1 0
+HDU number = 4
+ffcrhd status = 0
+Variable length arrays: ffphbn status = 0
+ffpcl_ status = 0
+PCOUNT = 4446
+HDU number = 6
+A 0
+L 0 0
+X 0 0
+B 1 0
+I 1 0
+J 1 0
+E 1 0
+D 1 0
+Column 8 repeat and offset = 1 14
+A ab 0
+L 0 1 0
+X 0 1 0
+B 99 2 0
+I 99 2 0
+J 99 2 0
+E 99 2 0
+D 99 2 0
+Column 8 repeat and offset = 2 49
+A abc 0
+L 0 0 0 0
+X 0 1 0 0
+B 1 99 3 0
+I 1 99 3 0
+J 1 99 3 0
+E 1 99 3 0
+D 1 99 3 0
+Column 8 repeat and offset = 3 105
+A abcd 0
+L 0 1 0 0 0
+X 0 1 0 0 0
+B 1 2 99 4 0
+I 1 2 99 4 0
+J 1 2 99 4 0
+E 1 2 99 4 0
+D 1 2 99 4 0
+Column 8 repeat and offset = 4 182
+A abcde 0
+L 0 1 0 0 1 0
+X 0 1 0 0 1 0
+B 1 2 3 99 5 0
+I 1 2 3 99 5 0
+J 1 2 3 99 5 0
+E 1 2 3 99 5 0
+D 1 2 3 99 5 0
+Column 8 repeat and offset = 5 280
+A abcdef 0
+L 0 1 0 0 0 1 0
+X 0 1 0 0 1 1 0
+B 1 2 3 4 99 6 0
+I 1 2 3 4 99 6 0
+J 1 2 3 4 99 6 0
+E 1 2 3 4 99 6 0
+D 1 2 3 4 99 6 0
+Column 8 repeat and offset = 6 399
+A abcdefg 0
+L 0 1 0 0 1 0 0 0
+X 0 1 0 0 1 1 0 0
+B 1 2 3 4 5 99 7 0
+I 1 2 3 4 5 99 7 0
+J 1 2 3 4 5 99 7 0
+E 1 2 3 4 5 99 7 0
+D 1 2 3 4 5 99 7 0
+Column 8 repeat and offset = 7 539
+A abcdefgh 0
+L 0 1 0 0 1 1 0 0 0
+X 0 1 0 0 1 1 0 0 0
+B 1 2 3 4 5 6 99 8 0
+I 1 2 3 4 5 6 99 8 0
+J 1 2 3 4 5 6 99 8 0
+E 1 2 3 4 5 6 99 8 0
+D 1 2 3 4 5 6 99 8 0
+Column 8 repeat and offset = 8 700
+A abcdefghi 0
+L 0 1 0 0 1 1 0 0 0 0
+X 0 1 0 0 1 1 0 0 0 0
+B 1 2 3 4 5 6 7 99 9 0
+I 1 2 3 4 5 6 7 99 9 0
+J 1 2 3 4 5 6 7 99 9 0
+E 1 2 3 4 5 6 7 99 9 0
+D 1 2 3 4 5 6 7 99 9 0
+Column 8 repeat and offset = 9 883
+A abcdefghij 0
+L 0 1 0 0 1 1 0 0 0 1 0
+X 0 1 0 0 1 1 0 0 0 1 0
+B 1 2 3 4 5 6 7 8 99 10 0
+I 1 2 3 4 5 6 7 8 99 10 0
+J 1 2 3 4 5 6 7 8 99 10 0
+E 1 2 3 4 5 6 7 8 99 10 0
+D 1 2 3 4 5 6 7 8 99 10 0
+Column 8 repeat and offset = 10 1087
+A abcdefghijk 0
+L 0 1 0 0 1 1 0 0 0 0 1 0
+X 0 1 0 0 1 1 0 0 0 1 1 0
+B 1 2 3 4 5 6 7 8 9 99 11 0
+I 1 2 3 4 5 6 7 8 9 99 11 0
+J 1 2 3 4 5 6 7 8 9 99 11 0
+E 1 2 3 4 5 6 7 8 9 99 11 0
+D 1 2 3 4 5 6 7 8 9 99 11 0
+Column 8 repeat and offset = 11 1312
+A abcdefghijkl 0
+L 0 1 0 0 1 1 0 0 0 1 0 1 0
+X 0 1 0 0 1 1 0 0 0 1 1 1 0
+B 1 2 3 4 5 6 7 8 9 10 99 12 0
+I 1 2 3 4 5 6 7 8 9 10 99 12 0
+J 1 2 3 4 5 6 7 8 9 10 99 12 0
+E 1 2 3 4 5 6 7 8 9 10 99 12 0
+D 1 2 3 4 5 6 7 8 9 10 99 12 0
+Column 8 repeat and offset = 12 1558
+A abcdefghijklm 0
+L 0 1 0 0 1 1 0 0 0 1 1 0 0 0
+X 0 1 0 0 1 1 0 0 0 1 1 1 0 0
+B 1 2 3 4 5 6 7 8 9 10 11 99 13 0
+I 1 2 3 4 5 6 7 8 9 10 11 99 13 0
+J 1 2 3 4 5 6 7 8 9 10 11 99 13 0
+E 1 2 3 4 5 6 7 8 9 10 11 99 13 0
+D 1 2 3 4 5 6 7 8 9 10 11 99 13 0
+Column 8 repeat and offset = 13 1825
+A abcdefghijklmn 0
+L 0 1 0 0 1 1 0 0 0 1 1 1 0 0 0
+X 0 1 0 0 1 1 0 0 0 1 1 1 0 0 0
+B 1 2 3 4 5 6 7 8 9 10 11 12 99 14 0
+I 1 2 3 4 5 6 7 8 9 10 11 12 99 14 0
+J 1 2 3 4 5 6 7 8 9 10 11 12 99 14 0
+E 1 2 3 4 5 6 7 8 9 10 11 12 99 14 0
+D 1 2 3 4 5 6 7 8 9 10 11 12 99 14 0
+Column 8 repeat and offset = 14 2113
+A abcdefghijklmno 0
+L 0 1 0 0 1 1 0 0 0 1 1 1 0 0 0 0
+X 0 1 0 0 1 1 0 0 0 1 1 1 0 0 0 0
+B 1 2 3 4 5 6 7 8 9 10 11 12 13 99 15 0
+I 1 2 3 4 5 6 7 8 9 10 11 12 13 99 15 0
+J 1 2 3 4 5 6 7 8 9 10 11 12 13 99 15 0
+E 1 2 3 4 5 6 7 8 9 10 11 12 13 99 15 0
+D 1 2 3 4 5 6 7 8 9 10 11 12 13 99 15 0
+Column 8 repeat and offset = 15 2422
+A abcdefghijklmnop 0
+L 0 1 0 0 1 1 0 0 0 1 1 1 0 0 0 0 0
+X 0 1 0 0 1 1 0 0 0 1 1 1 0 0 0 0 0
+B 1 2 3 4 5 6 7 8 9 10 11 12 13 14 99 16 0
+I 1 2 3 4 5 6 7 8 9 10 11 12 13 14 99 16 0
+J 1 2 3 4 5 6 7 8 9 10 11 12 13 14 99 16 0
+E 1 2 3 4 5 6 7 8 9 10 11 12 13 14 99 16 0
+D 1 2 3 4 5 6 7 8 9 10 11 12 13 14 99 16 0
+Column 8 repeat and offset = 16 2752
+A abcdefghijklmnopq 0
+L 0 1 0 0 1 1 0 0 0 1 1 1 0 0 0 0 1 0
+X 0 1 0 0 1 1 0 0 0 1 1 1 0 0 0 0 1 0
+B 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 99 17 0
+I 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 99 17 0
+J 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 99 17 0
+E 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 99 17 0
+D 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 99 17 0
+Column 8 repeat and offset = 17 3104
+A abcdefghijklmnopqr 0
+L 0 1 0 0 1 1 0 0 0 1 1 1 0 0 0 0 0 1 0
+X 0 1 0 0 1 1 0 0 0 1 1 1 0 0 0 0 1 1 0
+B 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 99 18 0
+I 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 99 18 0
+J 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 99 18 0
+E 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 99 18 0
+D 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 99 18 0
+Column 8 repeat and offset = 18 3477
+A abcdefghijklmnopqrs 0
+L 0 1 0 0 1 1 0 0 0 1 1 1 0 0 0 0 1 0 1 0
+X 0 1 0 0 1 1 0 0 0 1 1 1 0 0 0 0 1 1 1 0
+B 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 99 19 0
+I 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 99 19 0
+J 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 99 19 0
+E 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 99 19 0
+D 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 99 19 0
+Column 8 repeat and offset = 19 3871
+A abcdefghijklmnopqrst 0
+L 0 1 0 0 1 1 0 0 0 1 1 1 0 0 0 0 1 1 0 1 0
+X 0 1 0 0 1 1 0 0 0 1 1 1 0 0 0 0 1 1 1 1 0
+B 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 99 20 0
+I 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 99 20 0
+J 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 99 20 0
+E 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 99 20 0
+D 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 99 20 0
+Column 8 repeat and offset = 20 4286
+
+ffcrim status = 0
+ffppr status = 0
+
+Image values written with ffppr and read with ffgpv:
+ 0 2 4 6 8 10 12 14 16 18 20 22 24 26 0 (byte)
+ 0 2 4 6 8 10 12 14 16 18 20 22 24 26 0 (short)
+ 0 2 4 6 8 10 12 14 16 18 20 22 24 26 0 (int)
+ 0 2 4 6 8 10 12 14 16 18 20 22 24 26 0 (long)
+ 0 2 4 6 8 10 12 14 16 18 20 22 24 26 0 (float)
+ 0 2 4 6 8 10 12 14 16 18 20 22 24 26 0 (double)
+
+Wrote WCS keywords status = 0
+Read WCS keywords with ffgics status = 0
+ CRVAL1, CRVAL2 = 45.830000000000, 63.570000000000
+ CRPIX1, CRPIX2 = 256.000000000000, 257.000000000000
+ CDELT1, CDELT2 = -0.002777770000, 0.002777770000
+ Rotation = 0.000, CTYPE = -TAN
+Calculated sky coordinate with ffwldp status = 0
+ Pixels ( 0.5000, 0.5000) --> ( 47.385204, 62.848968) Sky
+Calculated pixel coordinate with ffxypx status = 0
+ Sky ( 47.385204, 62.848968) --> ( 0.5000, 0.5000) Pixels
+
+ffcrtb status = 0
+ffpcl status = 0
+
+Column values written with ffpcl and read with ffgcl:
+ 0 3 6 9 12 15 18 21 24 27 0 (byte)
+ 0 3 6 9 12 15 18 21 24 27 0 (short)
+ 0 3 6 9 12 15 18 21 24 27 0 (int)
+ 0 3 6 9 12 15 18 21 24 27 0 (long)
+ 0 3 6 9 12 15 18 21 24 27 0 (float)
+ 0 3 6 9 12 15 18 21 24 27 0 (double)
+
+Repeatedly move to the 1st 4 HDUs of the file:
+12343123431234312343123431234312343123431234312343
+Move to extensions by name and version number: (ffmnhd)
+ Test-BINTABLE, 1 = hdu 5, 0
+ Test-BINTABLE, 3 = hdu 2, 0
+ Test-BINTABLE, 4 = hdu 6, 0
+ Test-ASCII, 2 = hdu 4, 0
+ new_table, 5 = hdu 8, 0
+ Test-BINTABLE, 0 = hdu 2, 0
+ Test-BINTABLE, 17 = hdu 2, 301 (expect a 301 error status here)
+Total number of HDUs in the file = 8
+
+Encode checksum: 1234567890 -> dCW2fBU0dBU0dBU0
+Decode checksum: dCW2fBU0dBU0dBU0 -> 1234567890
+DATASUM = '475248536'
+ffgcks data checksum, status = 475248536, 0
+ffvcks datastatus, hdustatus, status = 1 1 0
+ffupck status = 0
+DATASUM = '475248536'
+ffvcks datastatus, hdustatus, status = 1 1 0
+ffclos status = 0
+
+Normally, there should be 8 error messages on the stack
+all regarding 'numerical overflows':
+ Numerical overflow during type conversion while writing FITS data.
+ Numerical overflow during type conversion while writing FITS data.
+ Numerical overflow during type conversion while writing FITS data.
+ Numerical overflow during type conversion while writing FITS data.
+ Numerical overflow during type conversion while writing FITS data.
+ Numerical overflow during type conversion while writing FITS data.
+ Numerical overflow during type conversion while writing FITS data.
+ Numerical overflow during type conversion while writing FITS data.
+
+Status = 0: OK - no error
diff --git a/pkg/tbtables/cfitsio/testprog.std b/pkg/tbtables/cfitsio/testprog.std
new file mode 100644
index 00000000..2f2a10cc
--- /dev/null
+++ b/pkg/tbtables/cfitsio/testprog.std
@@ -0,0 +1,48 @@
+SIMPLE = T / file does conform to FITS standard BITPIX = 32 / number of bits per data pixel NAXIS = 2 / number of data axes NAXIS1 = 10 / length of data axis 1 NAXIS2 = 2 / length of data axis 2 EXTEND = T / FITS dataset may contain extensions COMMENT FITS (Flexible Image Transport System) format is defined in 'AstronomyCOMMENT and Astrophysics', volume 376, page 359; bibcode: 2001A&A...376..359H KEY_PREC= 'This keyword was written by fxprec' / comment goes here CARD1 = '12345678901234567890123456789012345678901234567890123456789012345678'CARD2 = '1234567890123456789012345678901234567890123456789012345678901234''67'CARD3 = '1234567890123456789012345678901234567890123456789012345678901234'''''CARD4 = '1234567890123456789012345678901234567890123456789012345678901234567' KEY_PKYS= 'value_string' / fxpkys comment KEY_PKYL= T / fxpkyl comment KEY_PKYJ= 11 / [feet/second/second] fxpkyj comment KEY_PKYF= 12.12121 / fxpkyf comment KEY_PKYE= 1.313131E+01 / fxpkye comment KEY_PKYG= 14.14141414141414 / fxpkyg comment KEY_PKYD= 1.51515151515152E+01 / fxpkyd comment KEY_PKYC= (1.313131E+01, 1.414141E+01) / fxpkyc comment KEY_PKYM= (1.51515151515152E+01, 1.61616161616162E+01) / fxpkym comment KEY_PKFC= (13.131313, 14.141414) / fxpkfc comment KEY_PKFM= (15.15151515151515, 16.16161616161616) / fxpkfm comment KEY_PKLS= 'This is a very long string value that is continued over more than o&'CONTINUE 'ne keyword.' / fxpkls comment LONGSTRN= 'OGIP 1.0' / The HEASARC Long String Convention may be used.COMMENT This FITS file may contain long string keyword values that are COMMENT continued over multiple keywords. The HEASARC convention uses the & COMMENT character at the end of each substring which is then continued COMMENT on the next keyword which has the name CONTINUE. KEY_PKYT= 12345678.1234567890123456 / fxpkyt comment COMMENT This keyword was modified by fxmrec KY_UCRD = 'This keyword was updated by fxucrd' NEWIKYS = 'updated_string' / ikys comment KY_IKYJ = 51 / This is a modified comment KY_IKYL = T / ikyl comment KY_IKYE = -1.3346E+01 / ikye comment KY_IKYD = -1.33456789012346E+01 / modified comment KY_IKYF = -13.3456 / ikyf comment KY_IKYG = -13.3456789012346 / ikyg comment KY_PKNS1= 'first string' / fxpkns comment KY_PKNS2= 'second string' / fxpkns comment KY_PKNS3= ' ' / fxpkns comment KY_PKNL1= T / fxpknl comment KY_PKNL2= F / fxpknl comment KY_PKNL3= T / fxpknl comment KY_PKNJ1= 11 / fxpknj comment KY_PKNJ2= 12 / fxpknj comment KY_PKNJ3= 13 / fxpknj comment KY_PKNF1= 12.12121 / fxpknf comment KY_PKNF2= 13.13131 / fxpknf comment KY_PKNF3= 14.14141 / fxpknf comment KY_PKNE1= 1.313131E+01 / fxpkne comment KY_PKNE2= 1.414141E+01 / fxpkne comment KY_PKNE3= 1.515152E+01 / fxpkne comment KY_PKNG1= 14.1414141414141 / fxpkng comment KY_PKNG2= 15.1515151515152 / fxpkng comment KY_PKNG3= 16.1616161616162 / fxpkng comment KY_PKND1= 1.51515151515152E+01 / fxpknd comment KY_PKND2= 1.61616161616162E+01 / fxpknd comment KY_PKND3= 1.71717171717172E+01 / fxpknd comment TSTRING = '1 ' / tstring comment TLOGICAL= T / tlogical comment TBYTE = 11 / tbyte comment TSHORT = 21 / tshort comment TINT = 31 / tint comment TLONG = 41 / tlong comment TFLOAT = 42. / tfloat comment TDOUBLE = 82. / tdouble comment BLANK = -99 / value to use for undefined pixels KY_PKNE4= 1.313131E+01 / fxpkne comment TMPCARDA= 1001 / this is the 1st template card TMPCARD2= 'ABCD ' / this is the 2nd template card TMPCARD3= 1001.23 / this is the 3rd template card COMMENT this is the 5th template card HISTORY this is the 6th template card TMPCARD7= / comment for null keyword END ÿÿÿ
+
+§
+
+
+
+
+
+
+
+
+
+
+
+@
+€
+
+
+?€
+X
+
+
+ X
+
+
+ X
+
+
+ X
+
+
+ X
+
+
+ X
+
+
+ X
+
+
+ X
+
+
+ X
+
+
+
diff --git a/pkg/tbtables/cfitsio/testprog.tpt b/pkg/tbtables/cfitsio/testprog.tpt
new file mode 100644
index 00000000..def9dcb2
--- /dev/null
+++ b/pkg/tbtables/cfitsio/testprog.tpt
@@ -0,0 +1,12 @@
+tmpcard1 1001 this is the 1st template card
+tmpcard2 ABCD this is the 2nd template card
+tmpcard3 1001.23 this is the 3rd template card
+tmpcard4 1001.45 this is the 4rd template card
+comment this is the 5th template card
+history this is the 6th template card
+tmpcard7 = / comment for null keyword
+-tmpcard1 tmpcarda change the name of tmpcard1
+-tmpcard4
+end
+
+junk will be ignored
diff --git a/pkg/tbtables/cfitsio/vmsieee.c b/pkg/tbtables/cfitsio/vmsieee.c
new file mode 100644
index 00000000..5ddc7486
--- /dev/null
+++ b/pkg/tbtables/cfitsio/vmsieee.c
@@ -0,0 +1,130 @@
+#include <cvtdef.h>
+#include <cvtmsg.h>
+
+unsigned long CVT$CONVERT_FLOAT();
+
+/* IEEVPAKR -- Pack a native floating point vector into an IEEE one.
+*/
+void ieevpr (unsigned int *native, unsigned int *ieee, int *nelem)
+{
+ unsigned long status;
+ unsigned long options;
+ unsigned int *unanval;
+ int nanval = -1;
+ int i,n;
+
+ unanval = (unsigned int *) &nanval;
+ options = CVT$M_BIG_ENDIAN;
+
+ n = *nelem;
+ status = CVT$_NORMAL;
+
+ for (i = 0; i < n ; i++) {
+
+ status = CVT$CONVERT_FLOAT (&native[i], CVT$K_VAX_F,
+ &ieee[i], CVT$K_IEEE_S,
+ options);
+ if (status != CVT$_NORMAL) {
+ ieee[i] = *unanval;
+ }
+ }
+
+}
+/* IEEVPAKD -- Pack a native double floating point vector into an IEEE one.
+*/
+void ieevpd (unsigned long *native, unsigned long *ieee, int *nelem)
+{
+ unsigned long status;
+ unsigned long options;
+ unsigned long *unanval;
+ long nanval = -1;
+ int i,n;
+
+ unanval = (unsigned long *) &nanval;
+ options = CVT$M_BIG_ENDIAN;
+
+ n = *nelem * 2;
+ status = CVT$_NORMAL;
+
+ for (i = 0; i < n ; i=i+2) {
+
+ status = CVT$CONVERT_FLOAT (&native[i], CVT$K_VAX_D,
+ &ieee[i], CVT$K_IEEE_T,
+ options);
+ if (status != CVT$_NORMAL) {
+ ieee[i] = *unanval;
+ ieee[i+1] = *unanval;
+ }
+ }
+
+}
+/* IEEVUPKR -- Unpack an ieee vector into native single floating point vector.
+*/
+void ieevur (unsigned int *ieee, unsigned int *native, int *nelem)
+{
+ unsigned long status;
+ unsigned long options;
+ unsigned int *unanval;
+ int nanval = -1;
+ int j,n;
+
+ unanval = (unsigned int *) &nanval;
+ options = CVT$M_ERR_UNDERFLOW+CVT$M_BIG_ENDIAN;
+
+ n = *nelem;
+
+ status = CVT$_NORMAL;
+
+ for (j = 0; j < n ; j++) {
+ status = CVT$CONVERT_FLOAT (&ieee[j], CVT$K_IEEE_S,
+ &native[j], CVT$K_VAX_F,
+ options);
+ if (status != CVT$_NORMAL)
+ switch(status) {
+ case CVT$_INVVAL:
+ case CVT$_NEGINF:
+ case CVT$_OVERFLOW:
+ case CVT$_POSINF:
+ native[j] = *unanval;
+ break;
+ default:
+ native[j] = 0;
+ }
+ }
+}
+/* IEEVUPKD -- Unpack an ieee vector into native double floating point vector.
+*/
+void ieevud (unsigned long *ieee, unsigned long *native, int *nelem)
+{
+ unsigned long status;
+ unsigned long options;
+ unsigned long *unanval;
+ long nanval = -1;
+ int j,n;
+
+ unanval = (unsigned long *) &nanval;
+ options = CVT$M_BIG_ENDIAN + CVT$M_ERR_UNDERFLOW;
+
+ n = *nelem * 2;
+
+ status = CVT$_NORMAL;
+
+ for (j = 0; j < n ; j=j+2) {
+ status = CVT$CONVERT_FLOAT (&ieee[j], CVT$K_IEEE_T,
+ &native[j], CVT$K_VAX_D,
+ options);
+ if (status != CVT$_NORMAL)
+ switch(status) {
+ case CVT$_INVVAL:
+ case CVT$_NEGINF:
+ case CVT$_OVERFLOW:
+ case CVT$_POSINF:
+ native[j] = *unanval;
+ native[j+1] = *unanval;
+ break;
+ default:
+ native[j] = 0;
+ native[j+1] = 0;
+ }
+ }
+}
diff --git a/pkg/tbtables/cfitsio/vmsieeed.mar b/pkg/tbtables/cfitsio/vmsieeed.mar
new file mode 100644
index 00000000..f9928dda
--- /dev/null
+++ b/pkg/tbtables/cfitsio/vmsieeed.mar
@@ -0,0 +1,137 @@
+ .TITLE ieeed - ieee double to vax floating conversions
+ .ident /v1.0/
+
+;# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+;#
+;# IEEED.S -- IEEE double to VAX double floating conversions.
+;#
+;# ieepakd (x) # scalar, vax->ieee
+;# ieeupkd (x) # scalar, ieee->vax
+;# ieevpakd (native, ieee, nelem) # vector, vax->ieee
+;# ieevupkd (ieee, native, nelem) # vector, ieee->vax
+;# ieesnand (NaN) # set VAX NaN value
+;# ieegnand (NaN) # get VAX NaN value
+;#
+;# These routines convert between the VAX and IEEE double floating formats,
+;# operating upon a single value or an array of values. +/- zero is converted
+;# to zero. When converting IEEE to VAX, underflow maps to zero, and exponent
+;# overflow and NaN input values map to the value set by IEESNAND (default 0).
+;# These routines are functionally equivalent to the semi-portable versions of
+;# the IRAF ieee/native floating conversion routines in osb$ieeed.x.
+;# TODO - Add a function callback option for processing NaN values.
+
+; Vax NaN *MUST* be 11111... or the fitsio code will break horribly.
+; It is explicitly tested for in a couple of places, so be warned.
+
+ .PSECT IEEED$CODE, PIC,USR,CON,REL,LCL,SHR,EXE,RD,NOWRT,NOVEC
+
+ .ENTRY IEEPAD ^M<R2,R3,R4,R5>
+;_ieepad_: ;# IEEPAKD (X)
+ movl 4(ap), r4 ;# data addr -> r4
+ movl r4, r5 ;# output clobbers input
+ jsb cvt_vax_ieee ;# convert value
+ ret
+ .ENTRY IEEVPD ^M<R2,R3,R4,R5,R6>
+;_ieevpd_: ;# IEEVPAKD (VAX, IEEE, NELEM)
+ movl 4(ap), r4 ;# input vector -> r4
+ movl 8(ap), r5 ;# output vector -> r5
+ movl @12(ap), r6 ;# loop counter
+L1: jsb cvt_vax_ieee ;# convert one value
+ sobgtr r6, L1 ;# loop
+ ret
+ .ENTRY IEEUPD ^M<R2,R3,R4,R5>
+;_ieeupd_: ;# IEEUPKD (X)
+ movl 4(ap), r4 ;# data addr -> r4
+ movl r4, r5 ;# output clobbers input
+ jsb cvt_ieee_vax ;# convert value
+ ret
+ .ENTRY IEEVUD ^M<R2,R3,R4,R5,R6>
+;_ieevud_: ;# IEEVUPKD (IEEE, VAX, NELEM)
+ movl 4(ap), r4 ;# input vector -> r4
+ movl 8(ap), r5 ;# output vector -> r5
+ movl @12(ap), r6 ;# loop counter
+L2: jsb cvt_ieee_vax ;# convert one value
+ sobgtr r6, L2 ;# loop
+ ret
+ .ENTRY IEESND ^M<>
+;_ieesnd_: ;# IEESNAND (VAXNAN)
+bugger::nop ; real no-op added to enable
+ ; enbuging.
+; movq @4(ap), vaxnan ; no-oped. See above.
+ ret ; This could be no-oped in
+ ; the vector, but isn't.
+ .ENTRY IEEGND ^M<>
+;_ieegnd_: ;# IEEGNAND (VAXNAN)
+ movq #-1, @4(ap) ; See above
+ ret
+
+cvt_vax_ieee: ;# R4=in, R5=out
+ rotl #16, (r4)+, r1 ;# swap words -> r1
+ rotl #16, (r4)+, r0 ;# swap words -> r0
+
+ extzv #23, #8, r1, r2 ;# 8 bit exponent -> r2
+ beql L6 ;# branch if zero exponent
+ extzv #2, #1, r0, r3 ;# get round bit -> r3
+ ashq #-3, r0, r0 ;# shift 64 data bits by 3
+ addw2 #<1024-130>, r2 ;# adjust exponent bias
+ insv r2, #20, #11, r1 ;# insert new exponent
+ blbc r3, L5 ;# branch if round bit clear
+ incl r0 ;# round low longword
+ adwc #0, r1 ;# carry to high longword
+L5:
+ movl sp, r3 ;# r3 points to input byte
+ pushl r1 ;# push r1 on stack
+ pushl r0 ;# push r0 on stack
+ movb -(r3), (r5)+ ;# output quadword, swapped
+ movb -(r3), (r5)+
+ movb -(r3), (r5)+
+ movb -(r3), (r5)+
+ movb -(r3), (r5)+
+ movb -(r3), (r5)+
+ movb -(r3), (r5)+
+ movb -(r3), (r5)+
+ addl2 #8, sp ;# pop stack
+ rsb ;# all done
+L6:
+ clrl r0 ;# return all 64 bits zero
+ clrl r1
+ brb L5
+
+cvt_ieee_vax: ;# R4=in, R5=out
+ movb (r4)+, -(sp) ;# byte swap quadword onto stack
+ movb (r4)+, -(sp)
+ movb (r4)+, -(sp)
+ movb (r4)+, -(sp)
+ movb (r4)+, -(sp)
+ movb (r4)+, -(sp)
+ movb (r4)+, -(sp)
+ movb (r4)+, -(sp)
+
+ movl (sp)+, r0 ;# pop low bits
+ movl (sp)+, r1 ;# pop high bits
+ extzv #20, #11, r1, r2 ;# exponent -> r2
+ beql L10 ;# zero exponent
+ extzv #31, #1, r1, r3 ;# save sign bit
+ ashq #3, r0, r0 ;# shift 64 bits left 3 bits
+ subw2 #<1024-130>, r2 ;# adjust exponent bias
+ bleq L10 ;# return zero if underflow
+ cmpw r2, #256 ;# compare with max VAX exponent
+ bgeq L11 ;# return VAX-NaN if overflow
+ insv r2, #23, #8, r1 ;# insert VAX-D exponent
+ insv r3, #31, #1, r1 ;# restore sign bit
+
+ rotl #16, r1, (r5)+ ;# output VAX double
+ rotl #16, r0, (r5)+ ;# output VAX double
+ rsb
+L10:
+ clrl (r5)+ ;# return all 64 bits zero
+ clrl (r5)+
+ rsb
+L11:
+ movl #-1, r3 ;# return VAX equiv. of NaN
+ movl r3, (r5)+
+ movl r3, (r5)+ ; changed to only return -1
+ rsb
+
+ .END
+
diff --git a/pkg/tbtables/cfitsio/vmsieeer.mar b/pkg/tbtables/cfitsio/vmsieeer.mar
new file mode 100644
index 00000000..f3105880
--- /dev/null
+++ b/pkg/tbtables/cfitsio/vmsieeer.mar
@@ -0,0 +1,106 @@
+ .TITLE ieeer - ieee real to vax floating conversions
+ .ident /v1.0/
+
+;# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+;#
+;# IEEER.S -- IEEE real to VAX single precision floating conversions.
+;#
+;# ieepakr (x) # scalar, vax->ieee
+;# ieeupkr (x) # scalar, ieee->vax
+;# ieevpakr (native, ieee, nelem) # vector, vax->ieee
+;# ieevupkr (ieee, native, nelem) # vector, ieee->vax
+;# ieesnanr (NaN) # set VAX NaN value
+;# ieegnanr (NaN) # get VAX NaN value
+;#
+;# These routines convert between the VAX and IEEE real floating formats,
+;# operating upon a single value or an array of values. +/- zero is converted
+;# to zero. When converting IEEE to VAX, underflow maps to zero, and exponent
+;# overflow and NaN input values map to the value set by IEESNANR (default 0).
+;# These routines are functionally equivalent to the semi-portable versions of
+;# the IRAF ieee/native floating conversion routines in osb$ieeer.x.
+;# TODO - Add a function callback option for processing NaN values.
+
+; See IEEED for details about NaNs.
+
+ .PSECT IEEER$CODE, PIC,USR,CON,REL,LCL,SHR,EXE,RD,NOWRT,NOVEC
+
+ .ENTRY IEEPAR ^M<R2,R3>
+;_ieepar_: ;# IEEPAKR (X)
+ movl 4(ap), r2 ;# data addr -> r2
+ movl r2, r3 ;# output clobbers input
+ jsb cvt_vax_ieee ;# convert value
+ ret
+ .ENTRY IEEVPR ^M<R2,R3,R4>
+;_ieevpr_: ;# IEEVPAKR (VAX, IEEE, NELEM)
+ movl 4(ap), r2 ;# input vector -> r2
+ movl 8(ap), r3 ;# output vector -> r3
+ movl @12(ap), r4 ;# loop counter
+L1: jsb cvt_vax_ieee ;# convert one value
+ sobgtr r4, L1 ;# loop
+ ret
+ .ENTRY IEEUPR ^M<R2,R3>
+;_ieeupr_: ;# IEEUPKR (X)
+ movl 4(ap), r2 ;# data addr -> r2
+ movl r2, r3 ;# output clobbers input
+ jsb cvt_ieee_vax ;# convert value
+ ret
+ .ENTRY IEEVUR ^M<R2,R3,R4>
+;_ieevur_: ;# IEEVUPKR (IEEE, VAX, NELEM)
+ movl 4(ap), r2 ;# input vector -> r2
+ movl 8(ap), r3 ;# output vector -> r3
+ movl @12(ap), r4 ;# loop counter
+L2: jsb cvt_ieee_vax ;# convert one value
+ sobgtr r4, L2 ;# loop
+ ret
+ .ENTRY IEESNR ^M<>
+;_ieesnr_: ;# IEESNANR (VAXNAN)
+buger:: nop ; plug bpt here for crap catching.
+; movl @4(ap), vaxnan
+ ret
+ .ENTRY IEEGNR ^M<>
+;_ieegnr_: ;# IEEGNANR (VAXNAN)
+ movl #-1, @4(ap)
+ ret
+
+cvt_vax_ieee: ;# R2=in, R3=out
+ rotl #16, (r2)+, r0 ;# swap words -> r0
+ extzv #23, #8, r0, r1 ;# 8 bit exponent -> r1
+ beql L6 ;# branch if zero exponent
+ subw2 #2, r1 ;# adjust exponent bias
+ bleq L6 ;# return zero if underflow
+ insv r1, #23, #8, r0 ;# insert new exponent
+L5:
+ movl sp, r1 ;# r3 points to input byte
+ pushl r0 ;# push r0 on stack
+ movb -(r1), (r3)+ ;# output longword, swapped
+ movb -(r1), (r3)+
+ movb -(r1), (r3)+
+ movb -(r1), (r3)+
+ tstl (sp)+ ;# pop stack
+ rsb ;# all done
+L6:
+ clrl r0 ;# return all 32 bits zero
+ brb L5
+
+cvt_ieee_vax: ;# R2=in, R3=out
+ movb (r2)+, -(sp) ;# byte swap longword onto stack
+ movb (r2)+, -(sp)
+ movb (r2)+, -(sp)
+ movb (r2)+, -(sp)
+ movl (sp)+, r0 ;# pop swapped value -> r0
+ extzv #23, #8, r0, r1 ;# exponent -> r1
+ beql L10 ;# zero exponent
+ addw2 #2, r1 ;# adjust exponent bias
+ cmpw r1, #256 ;# compare with max VAX exponent
+ bgeq L11 ;# return VAX-NaN if overflow
+ insv r1, #23, #8, r0 ;# insert VAX-D exponent
+ rotl #16, r0, (r3)+ ;# output VAX value
+ rsb
+L10:
+ clrl (r3)+ ;# return all 32 bits zero
+ rsb
+L11:
+ movl #-1, (r3)+ ; return fixed NaN value...
+ rsb
+
+ .END
diff --git a/pkg/tbtables/cfitsio/wcssub.c b/pkg/tbtables/cfitsio/wcssub.c
new file mode 100644
index 00000000..c523f357
--- /dev/null
+++ b/pkg/tbtables/cfitsio/wcssub.c
@@ -0,0 +1,327 @@
+#include <stdlib.h>
+#include <string.h>
+#include "fitsio2.h"
+
+/*--------------------------------------------------------------------------*/
+int ffgiwcs(fitsfile *fptr, /* I - FITS file pointer */
+ char **header, /* O - pointer to the WCS related keywords */
+ int *status) /* IO - error status */
+/*
+ int fits_get_image_wcs_keys
+ return a string containing all the image WCS header keywords.
+ This string is then used as input to the wcsinit WCSlib routine.
+*/
+{
+ int hdutype;
+
+ if (*status > 0)
+ return(*status);
+
+ fits_get_hdu_type(fptr, &hdutype, status);
+ if (hdutype != IMAGE_HDU)
+ {
+ ffpmsg(
+ "Error in ffgiwcs. This HDU is not an image. Can't read WCS keywords");
+ return(*status = NOT_IMAGE);
+ }
+
+ /* read header keywords into a long string of chars */
+ if (ffh2st(fptr, header, status) > 0)
+ {
+ ffpmsg("error creating string of image WCS keywords (ffgiwcs)");
+ return(*status);
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgtwcs(fitsfile *fptr, /* I - FITS file pointer */
+ int xcol, /* I - column number for the X column */
+ int ycol, /* I - column number for the Y column */
+ char **header, /* O - string of all the WCS keywords */
+ int *status) /* IO - error status */
+/*
+ int fits_get_table_wcs_keys
+ Return string containing all the WCS keywords appropriate for the
+ pair of X and Y columns containing the coordinate
+ of each event in an event list table. This string may then be passed
+ to Doug Mink's WCS library wcsinit routine, to create and initialize the
+ WCS structure. The calling routine must free the header character string
+ when it is no longer needed.
+*/
+{
+ int hdutype, ncols, tstatus, length;
+ int naxis1 = 1, naxis2 = 1;
+ long tlmin, tlmax;
+ char keyname[FLEN_KEYWORD];
+ char valstring[FLEN_VALUE];
+ char comm[2];
+ char *cptr;
+ /* construct a string of 80 blanks, for adding fill to the keywords */
+ /* 12345678901234567890123456789012345678901234567890123456789012345678901234567890 */
+ char blanks[] = " ";
+
+ if (*status > 0)
+ return(*status);
+
+ fits_get_hdu_type(fptr, &hdutype, status);
+ if (hdutype == IMAGE_HDU)
+ {
+ ffpmsg("Can't read table WSC keywords. This HDU is not a table");
+ return(*status = NOT_TABLE);
+ }
+
+ fits_get_num_cols(fptr, &ncols, status);
+
+ if (xcol < 1 || xcol > ncols)
+ {
+ ffpmsg("illegal X axis column number in fftwcs");
+ return(*status = BAD_COL_NUM);
+ }
+
+ if (ycol < 1 || ycol > ncols)
+ {
+ ffpmsg("illegal Y axis column number in fftwcs");
+ return(*status = BAD_COL_NUM);
+ }
+
+ /* allocate character string for all the WCS keywords */
+ *header = calloc(1, 2401); /* room for up to 30 keywords */
+ if (*header == 0)
+ {
+ ffpmsg("error allocating memory for WCS header keywords (fftwcs)");
+ return(*status = MEMORY_ALLOCATION);
+ }
+
+ cptr = *header;
+ comm[0] = '\0';
+
+ tstatus = 0;
+ ffkeyn("TLMIN",xcol,keyname,status);
+ ffgkyj(fptr,keyname, &tlmin,NULL,&tstatus);
+
+ if (!tstatus)
+ {
+ ffkeyn("TLMAX",xcol,keyname,status);
+ ffgkyj(fptr,keyname, &tlmax,NULL,&tstatus);
+ }
+
+ if (!tstatus)
+ {
+ naxis1 = tlmax - tlmin + 1;
+ }
+
+ tstatus = 0;
+ ffkeyn("TLMIN",ycol,keyname,status);
+ ffgkyj(fptr,keyname, &tlmin,NULL,&tstatus);
+
+ if (!tstatus)
+ {
+ ffkeyn("TLMAX",ycol,keyname,status);
+ ffgkyj(fptr,keyname, &tlmax,NULL,&tstatus);
+ }
+
+ if (!tstatus)
+ {
+ naxis2 = tlmax - tlmin + 1;
+ }
+
+ /* 123456789012345678901234567890 */
+ strcat(cptr, "NAXIS = 2");
+ strncat(cptr, blanks, 50);
+ cptr += 80;
+
+ ffi2c(naxis1, valstring, status); /* convert to formatted string */
+ ffmkky("NAXIS1", valstring, comm, cptr, status); /* construct the keyword*/
+ strncat(cptr, blanks, 50); /* pad with blanks */
+ cptr += 80;
+
+ strcpy(keyname, "NAXIS2");
+ ffi2c(naxis2, valstring, status); /* convert to formatted string */
+ ffmkky(keyname, valstring, comm, cptr, status); /* construct the keyword*/
+ strncat(cptr, blanks, 50); /* pad with blanks */
+ cptr += 80;
+
+ /* read the required header keywords (use defaults if not found) */
+
+ /* CTYPE1 keyword */
+ tstatus = 0;
+ ffkeyn("TCTYP",xcol,keyname,status);
+ if (ffgkey(fptr, keyname, valstring, NULL, &tstatus) )
+ valstring[0] = '\0';
+ ffmkky("CTYPE1", valstring, comm, cptr, status); /* construct the keyword*/
+ length = strlen(cptr);
+ strncat(cptr, blanks, 80 - length); /* pad with blanks */
+ cptr += 80;
+
+ /* CTYPE2 keyword */
+ tstatus = 0;
+ ffkeyn("TCTYP",ycol,keyname,status);
+ if (ffgkey(fptr, keyname, valstring, NULL, &tstatus) )
+ valstring[0] = '\0';
+ ffmkky("CTYPE2", valstring, comm, cptr, status); /* construct the keyword*/
+ length = strlen(cptr);
+ strncat(cptr, blanks, 80 - length); /* pad with blanks */
+ cptr += 80;
+
+ /* CRPIX1 keyword */
+ tstatus = 0;
+ ffkeyn("TCRPX",xcol,keyname,status);
+ if (ffgkey(fptr, keyname, valstring, NULL, &tstatus) )
+ strcpy(valstring, "1");
+ ffmkky("CRPIX1", valstring, comm, cptr, status); /* construct the keyword*/
+ strncat(cptr, blanks, 50); /* pad with blanks */
+ cptr += 80;
+
+ /* CRPIX2 keyword */
+ tstatus = 0;
+ ffkeyn("TCRPX",ycol,keyname,status);
+ if (ffgkey(fptr, keyname, valstring, NULL, &tstatus) )
+ strcpy(valstring, "1");
+ ffmkky("CRPIX2", valstring, comm, cptr, status); /* construct the keyword*/
+ strncat(cptr, blanks, 50); /* pad with blanks */
+ cptr += 80;
+
+ /* CRVAL1 keyword */
+ tstatus = 0;
+ ffkeyn("TCRVL",xcol,keyname,status);
+ if (ffgkey(fptr, keyname, valstring, NULL, &tstatus) )
+ strcpy(valstring, "1");
+ ffmkky("CRVAL1", valstring, comm, cptr, status); /* construct the keyword*/
+ strncat(cptr, blanks, 50); /* pad with blanks */
+ cptr += 80;
+
+ /* CRVAL2 keyword */
+ tstatus = 0;
+ ffkeyn("TCRVL",ycol,keyname,status);
+ if (ffgkey(fptr, keyname, valstring, NULL, &tstatus) )
+ strcpy(valstring, "1");
+ ffmkky("CRVAL2", valstring, comm, cptr, status); /* construct the keyword*/
+ strncat(cptr, blanks, 50); /* pad with blanks */
+ cptr += 80;
+
+ /* CDELT1 keyword */
+ tstatus = 0;
+ ffkeyn("TCDLT",xcol,keyname,status);
+ if (ffgkey(fptr, keyname, valstring, NULL, &tstatus) )
+ strcpy(valstring, "1");
+ ffmkky("CDELT1", valstring, comm, cptr, status); /* construct the keyword*/
+ strncat(cptr, blanks, 50); /* pad with blanks */
+ cptr += 80;
+
+ /* CDELT2 keyword */
+ tstatus = 0;
+ ffkeyn("TCDLT",ycol,keyname,status);
+ if (ffgkey(fptr, keyname, valstring, NULL, &tstatus) )
+ strcpy(valstring, "1");
+ ffmkky("CDELT2", valstring, comm, cptr, status); /* construct the keyword*/
+ strncat(cptr, blanks, 50); /* pad with blanks */
+ cptr += 80;
+
+ /* the following keywords may not exist */
+
+ /* CROTA2 keyword */
+ tstatus = 0;
+ ffkeyn("TCROT",ycol,keyname,status);
+ if (ffgkey(fptr, keyname, valstring, NULL, &tstatus) == 0 )
+ {
+ ffmkky("CROTA2", valstring, comm, cptr, status); /* construct keyword*/
+ strncat(cptr, blanks, 50); /* pad with blanks */
+ cptr += 80;
+ }
+
+ /* EPOCH keyword */
+ tstatus = 0;
+ if (ffgkey(fptr, "EPOCH", valstring, NULL, &tstatus) == 0 )
+ {
+ ffmkky("EPOCH", valstring, comm, cptr, status); /* construct keyword*/
+ length = strlen(cptr);
+ strncat(cptr, blanks, 80 - length); /* pad with blanks */
+ cptr += 80;
+ }
+
+ /* EQUINOX keyword */
+ tstatus = 0;
+ if (ffgkey(fptr, "EQUINOX", valstring, NULL, &tstatus) == 0 )
+ {
+ ffmkky("EQUINOX", valstring, comm, cptr, status); /* construct keyword*/
+ length = strlen(cptr);
+ strncat(cptr, blanks, 80 - length); /* pad with blanks */
+ cptr += 80;
+ }
+
+ /* RADECSYS keyword */
+ tstatus = 0;
+ if (ffgkey(fptr, "RADECSYS", valstring, NULL, &tstatus) == 0 )
+ {
+ ffmkky("RADECSYS", valstring, comm, cptr, status); /*construct keyword*/
+ length = strlen(cptr);
+ strncat(cptr, blanks, 80 - length); /* pad with blanks */
+ cptr += 80;
+ }
+
+ /* TELESCOPE keyword */
+ tstatus = 0;
+ if (ffgkey(fptr, "TELESCOP", valstring, NULL, &tstatus) == 0 )
+ {
+ ffmkky("TELESCOP", valstring, comm, cptr, status);
+ length = strlen(cptr);
+ strncat(cptr, blanks, 80 - length); /* pad with blanks */
+ cptr += 80;
+ }
+
+ /* INSTRUME keyword */
+ tstatus = 0;
+ if (ffgkey(fptr, "INSTRUME", valstring, NULL, &tstatus) == 0 )
+ {
+ ffmkky("INSTRUME", valstring, comm, cptr, status);
+ length = strlen(cptr);
+ strncat(cptr, blanks, 80 - length); /* pad with blanks */
+ cptr += 80;
+ }
+
+ /* DETECTOR keyword */
+ tstatus = 0;
+ if (ffgkey(fptr, "DETECTOR", valstring, NULL, &tstatus) == 0 )
+ {
+ ffmkky("DETECTOR", valstring, comm, cptr, status);
+ length = strlen(cptr);
+ strncat(cptr, blanks, 80 - length); /* pad with blanks */
+ cptr += 80;
+ }
+
+ /* MJD-OBS keyword */
+ tstatus = 0;
+ if (ffgkey(fptr, "MJD-OBS", valstring, NULL, &tstatus) == 0 )
+ {
+ ffmkky("MJD-OBS", valstring, comm, cptr, status);
+ length = strlen(cptr);
+ strncat(cptr, blanks, 80 - length); /* pad with blanks */
+ cptr += 80;
+ }
+
+ /* DATE-OBS keyword */
+ tstatus = 0;
+ if (ffgkey(fptr, "DATE-OBS", valstring, NULL, &tstatus) == 0 )
+ {
+ ffmkky("DATE-OBS", valstring, comm, cptr, status);
+ length = strlen(cptr);
+ strncat(cptr, blanks, 80 - length); /* pad with blanks */
+ cptr += 80;
+ }
+
+ /* DATE keyword */
+ tstatus = 0;
+ if (ffgkey(fptr, "DATE", valstring, NULL, &tstatus) == 0 )
+ {
+ ffmkky("DATE", valstring, comm, cptr, status);
+ length = strlen(cptr);
+ strncat(cptr, blanks, 80 - length); /* pad with blanks */
+ cptr += 80;
+ }
+
+ strcat(cptr, "END");
+ strncat(cptr, blanks, 77);
+
+ return(*status);
+}
diff --git a/pkg/tbtables/cfitsio/wcsutil.c b/pkg/tbtables/cfitsio/wcsutil.c
new file mode 100644
index 00000000..95d93c3c
--- /dev/null
+++ b/pkg/tbtables/cfitsio/wcsutil.c
@@ -0,0 +1,72 @@
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+#include "fitsio2.h"
+
+/* ======================================================================
+This file contains stubs for the AIPS WCS routines that are
+contained in the source file wcsutil.c. The routines in wcsutil.c
+should only be used by software that adheres to the terms of
+the GNU General Public License. Users who want to use CFITSIO but are
+unwilling to release their code under the terms of the GNU General
+Public License should replace the wcsutil.c file with this current
+file before building the CFITSIO library. This alternate version of
+CFITSIO will behave the same as the standard version, except that it
+will not support the ffwldp and ffxypx routines that calculate
+image coordinate transformation from pixel coordinates to world
+coordinates (e.g. Right Ascension and Declination) and vise versa.
+======================================================================== */
+
+int ffgics(fitsfile *fptr,
+ double *xrval,
+ double *yrval,
+ double *xrpix,
+ double *yrpix,
+ double *xinc,
+ double *yinc,
+ double *rot,
+ char *type,
+ int *status) {
+ return(*status = NO_WCS_KEY);
+}
+
+int ffgtcs(fitsfile *fptr,
+ int xcol,
+ int ycol,
+ double *xrval,
+ double *yrval,
+ double *xrpix,
+ double *yrpix,
+ double *xinc,
+ double *yinc,
+ double *rot,
+ char *type,
+ int *status) {
+ return(*status = NO_WCS_KEY);
+}
+
+
+/*--------------------------------------------------------------------------*/
+int ffwldp(double xpix, double ypix, double xref, double yref,
+ double xrefpix, double yrefpix, double xinc, double yinc, double rot,
+ char *type, double *xpos, double *ypos, int *status)
+{
+ if (*status > 0)
+ return(*status);
+
+ ffpmsg("This non-GNU version of CFITSIO does not support");
+ ffpmsg(" celestial coordinate transformations.");
+ return(*status = 503);
+}
+/*--------------------------------------------------------------------------*/
+int ffxypx(double xpos, double ypos, double xref, double yref,
+ double xrefpix, double yrefpix, double xinc, double yinc, double rot,
+ char *type, double *xpix, double *ypix, int *status)
+{
+ if (*status > 0)
+ return(*status);
+
+ ffpmsg("This non-GNU version of CFITSIO does not support");
+ ffpmsg(" celestial coordinate transformations.");
+ return(*status = 503);
+}
diff --git a/pkg/tbtables/cfitsio/wcsutil.c.OLD b/pkg/tbtables/cfitsio/wcsutil.c.OLD
new file mode 100644
index 00000000..c5b87fa8
--- /dev/null
+++ b/pkg/tbtables/cfitsio/wcsutil.c.OLD
@@ -0,0 +1,786 @@
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+#include "fitsio2.h"
+/*--------------------------------------------------------------------------*/
+int ffgics(fitsfile *fptr, /* I - FITS file pointer */
+ double *xrval, /* O - X reference value */
+ double *yrval, /* O - Y reference value */
+ double *xrpix, /* O - X reference pixel */
+ double *yrpix, /* O - Y reference pixel */
+ double *xinc, /* O - X increment per pixel */
+ double *yinc, /* O - Y increment per pixel */
+ double *rot, /* O - rotation angle (degrees) */
+ char *type, /* O - type of projection ('-tan') */
+ int *status) /* IO - error status */
+/*
+ read the values of the celestial coordinate system keywords.
+ These values may be used as input to the subroutines that
+ calculate celestial coordinates. (ffxypx, ffwldp)
+
+ Modified in Nov 1999 to convert the CD matrix keywords back
+ to the old CDELTn form, and to swap the axes if the dec-like
+ axis is given first, and to assume default values if any of the
+ keywords are not present.
+*/
+{
+ int tstat = 0, cd_exists = 0, pc_exists = 0;
+ char ctype[FLEN_VALUE];
+ double cd11 = 0.0, cd21 = 0.0, cd22 = 0.0, cd12 = 0.0;
+ double pc11 = 1.0, pc21 = 0.0, pc22 = 1.0, pc12 = 0.0;
+ double pi = 3.1415926535897932;
+ double phia, phib, temp;
+ double toler = .0002; /* tolerance for angles to agree (radians) */
+ /* (= approximately 0.01 degrees) */
+
+ if (*status > 0)
+ return(*status);
+
+ tstat = 0;
+ if (ffgkyd(fptr, "CRVAL1", xrval, NULL, &tstat))
+ *xrval = 0.;
+
+ tstat = 0;
+ if (ffgkyd(fptr, "CRVAL2", yrval, NULL, &tstat))
+ *yrval = 0.;
+
+ tstat = 0;
+ if (ffgkyd(fptr, "CRPIX1", xrpix, NULL, &tstat))
+ *xrpix = 0.;
+
+ tstat = 0;
+ if (ffgkyd(fptr, "CRPIX2", yrpix, NULL, &tstat))
+ *yrpix = 0.;
+
+ /* look for CDELTn first, then CDi_j keywords */
+ tstat = 0;
+ if (ffgkyd(fptr, "CDELT1", xinc, NULL, &tstat))
+ {
+ /* CASE 1: no CDELTn keyword, so look for the CD matrix */
+ tstat = 0;
+ if (ffgkyd(fptr, "CD1_1", &cd11, NULL, &tstat))
+ tstat = 0; /* reset keyword not found error */
+ else
+ cd_exists = 1; /* found at least 1 CD_ keyword */
+
+ if (ffgkyd(fptr, "CD2_1", &cd21, NULL, &tstat))
+ tstat = 0; /* reset keyword not found error */
+ else
+ cd_exists = 1; /* found at least 1 CD_ keyword */
+
+ if (ffgkyd(fptr, "CD1_2", &cd12, NULL, &tstat))
+ tstat = 0; /* reset keyword not found error */
+ else
+ cd_exists = 1; /* found at least 1 CD_ keyword */
+
+ if (ffgkyd(fptr, "CD2_2", &cd22, NULL, &tstat))
+ tstat = 0; /* reset keyword not found error */
+ else
+ cd_exists = 1; /* found at least 1 CD_ keyword */
+
+ if (cd_exists) /* convert CDi_j back to CDELTn */
+ {
+ /* there are 2 ways to compute the angle: */
+ phia = atan2( cd21, cd11);
+ phib = atan2(-cd12, cd22);
+
+ /* ensure that phia <= phib */
+ temp = minvalue(phia, phib);
+ phib = maxvalue(phia, phib);
+ phia = temp;
+
+ /* there is a possible 180 degree ambiguity in the angles */
+ /* so add 180 degress to the smaller value if the values */
+ /* differ by more than 90 degrees = pi/2 radians. */
+ /* (Later, we may decide to take the other solution by */
+ /* subtracting 180 degrees from the larger value). */
+
+ if ((phib - phia) > (pi / 2.))
+ phia += pi;
+
+ if (fabs(phia - phib) > toler)
+ {
+ /* angles don't agree, so looks like there is some skewness */
+ /* between the axes. Return with an error to be safe. */
+ *status = APPROX_WCS_KEY;
+ }
+
+ phia = (phia + phib) /2.; /* use the average of the 2 values */
+ *xinc = cd11 / cos(phia);
+ *yinc = cd22 / cos(phia);
+ *rot = phia * 180. / pi;
+
+ /* common usage is to have a positive yinc value. If it is */
+ /* negative, then subtract 180 degrees from rot and negate */
+ /* both xinc and yinc. */
+
+ if (*yinc < 0)
+ {
+ *xinc = -(*xinc);
+ *yinc = -(*yinc);
+ *rot = *rot - 180.;
+ }
+ }
+ else /* no CD matrix keywords either */
+ {
+ *xinc = 1.;
+
+ /* there was no CDELT1 keyword, but check for CDELT2 just in case */
+ tstat = 0;
+ if (ffgkyd(fptr, "CDELT2", yinc, NULL, &tstat))
+ *yinc = 1.;
+
+ tstat = 0;
+ if (ffgkyd(fptr, "CROTA2", rot, NULL, &tstat))
+ *rot=0.;
+ }
+ }
+ else /* Case 2: CDELTn + optional PC matrix */
+ {
+ if (ffgkyd(fptr, "CDELT2", yinc, NULL, &tstat))
+ *yinc = 1.;
+
+ tstat = 0;
+ if (ffgkyd(fptr, "CROTA2", rot, NULL, &tstat))
+ {
+ *rot=0.;
+
+ /* no CROTA2 keyword, so look for the PC matrix */
+ tstat = 0;
+ if (ffgkyd(fptr, "PC1_1", &pc11, NULL, &tstat))
+ tstat = 0; /* reset keyword not found error */
+ else
+ pc_exists = 1; /* found at least 1 PC_ keyword */
+
+ if (ffgkyd(fptr, "PC2_1", &pc21, NULL, &tstat))
+ tstat = 0; /* reset keyword not found error */
+ else
+ pc_exists = 1; /* found at least 1 PC_ keyword */
+
+ if (ffgkyd(fptr, "PC1_2", &pc12, NULL, &tstat))
+ tstat = 0; /* reset keyword not found error */
+ else
+ pc_exists = 1; /* found at least 1 PC_ keyword */
+
+ if (ffgkyd(fptr, "PC2_2", &pc22, NULL, &tstat))
+ tstat = 0; /* reset keyword not found error */
+ else
+ pc_exists = 1; /* found at least 1 PC_ keyword */
+
+ if (pc_exists) /* convert PCi_j back to CDELTn */
+ {
+ /* there are 2 ways to compute the angle: */
+ phia = atan2( pc21, pc11);
+ phib = atan2(-pc12, pc22);
+
+ /* ensure that phia <= phib */
+ temp = minvalue(phia, phib);
+ phib = maxvalue(phia, phib);
+ phia = temp;
+
+ /* there is a possible 180 degree ambiguity in the angles */
+ /* so add 180 degress to the smaller value if the values */
+ /* differ by more than 90 degrees = pi/2 radians. */
+ /* (Later, we may decide to take the other solution by */
+ /* subtracting 180 degrees from the larger value). */
+
+ if ((phib - phia) > (pi / 2.))
+ phia += pi;
+
+ if (fabs(phia - phib) > toler)
+ {
+ /* angles don't agree, so looks like there is some skewness */
+ /* between the axes. Return with an error to be safe. */
+ *status = APPROX_WCS_KEY;
+ }
+
+ phia = (phia + phib) /2.; /* use the average of the 2 values */
+ *rot = phia * 180. / pi;
+ }
+ }
+ }
+
+ /* get the type of projection, if any */
+ tstat = 0;
+ if (ffgkys(fptr, "CTYPE1", ctype, NULL, &tstat))
+ type[0] = '\0';
+ else
+ {
+ /* copy the projection type string */
+ strncpy(type, &ctype[4], 4);
+ type[4] = '\0';
+
+ /* check if RA and DEC are inverted */
+ if (!strncmp(ctype, "DEC-", 4) || !strncmp(ctype+1, "LAT", 3))
+ {
+ /* the latitudinal axis is given first, so swap them */
+
+/*
+ this case was removed on 12/9. Apparently not correct.
+
+ if ((*xinc / *yinc) < 0. )
+ *rot = -90. - (*rot);
+ else
+*/
+ *rot = 90. - (*rot);
+
+ /* Empirical tests with ds9 show the y-axis sign must be negated */
+ /* and the xinc and yinc values must NOT be swapped. */
+ *yinc = -(*yinc);
+
+ temp = *xrval;
+ *xrval = *yrval;
+ *yrval = temp;
+ }
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgtcs(fitsfile *fptr, /* I - FITS file pointer */
+ int xcol, /* I - column containing the RA coordinate */
+ int ycol, /* I - column containing the DEC coordinate */
+ double *xrval, /* O - X reference value */
+ double *yrval, /* O - Y reference value */
+ double *xrpix, /* O - X reference pixel */
+ double *yrpix, /* O - Y reference pixel */
+ double *xinc, /* O - X increment per pixel */
+ double *yinc, /* O - Y increment per pixel */
+ double *rot, /* O - rotation angle (degrees) */
+ char *type, /* O - type of projection ('-sin') */
+ int *status) /* IO - error status */
+/*
+ read the values of the celestial coordinate system keywords
+ from a FITS table where the X and Y or RA and DEC coordinates
+ are stored in separate column.
+ These values may be used as input to the subroutines that
+ calculate celestial coordinates. (ffxypx, ffwldp)
+*/
+{
+ char comm[FLEN_COMMENT],ctype[FLEN_VALUE],keynam[FLEN_KEYWORD];
+ int tstatus = 0;
+
+ if (*status > 0)
+ return(*status);
+
+ ffkeyn("TCRVL",xcol,keynam,status);
+ ffgkyd(fptr,keynam,xrval,comm,status);
+
+ ffkeyn("TCRVL",ycol,keynam,status);
+ ffgkyd(fptr,keynam,yrval,comm,status);
+
+ ffkeyn("TCRPX",xcol,keynam,status);
+ ffgkyd(fptr,keynam,xrpix,comm,status);
+
+ ffkeyn("TCRPX",ycol,keynam,status);
+ ffgkyd(fptr,keynam,yrpix,comm,status);
+
+ ffkeyn("TCDLT",xcol,keynam,status);
+ ffgkyd(fptr,keynam,xinc,comm,status);
+
+ ffkeyn("TCDLT",ycol,keynam,status);
+ ffgkyd(fptr,keynam,yinc,comm,status);
+
+ ffkeyn("TCTYP",xcol,keynam,status);
+ ffgkys(fptr,keynam,ctype,comm,status);
+
+ if (*status > 0)
+ {
+ ffpmsg
+ ("ffgtcs could not find all the celestial coordinate keywords");
+ return(*status = NO_WCS_KEY);
+ }
+
+ /* copy the projection type string */
+ strncpy(type, &ctype[4], 4);
+ type[4] = '\0';
+
+ *rot=0.; /* default rotation is 0 */
+ ffkeyn("TCROT",ycol,keynam,status);
+ ffgkyd(fptr,keynam,rot,comm,&tstatus); /* keyword may not exist */
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffwldp(double xpix, double ypix, double xref, double yref,
+ double xrefpix, double yrefpix, double xinc, double yinc, double rot,
+ char *type, double *xpos, double *ypos, int *status)
+
+/* WDP 1/97: change the name of the routine from 'worldpos' to 'ffwldp' */
+
+/* worldpos.c -- WCS Algorithms from Classic AIPS.
+ Copyright (C) 1994
+ Associated Universities, Inc. Washington DC, USA.
+
+ This library is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Library 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 Library General Public
+ License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; if not, write to the Free Software Foundation,
+ Inc., 675 Massachusetts Ave, Cambridge, MA 02139, 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 xypix(), perform
+ forward and reverse WCS computations for 8 types of projective
+ geometries ("-SIN", "-TAN", "-ARC", "-NCP", "-GLS", "-MER", "-AIT"
+ and "-STG"):
+
+ worldpos() converts from pixel location to RA,Dec
+ xypix() 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 xypix() and worldpos().
+ 6) E.Greisen recommended removal of various redundant if-statements,
+ and addition of a 360d difference test to MER case of worldpos().
+*/
+
+/*-----------------------------------------------------------------------*/
+/* routine to determine accurate position for pixel coordinates */
+/* returns 0 if successful otherwise: */
+/* 1 = angle too large for projection; */
+/* (WDP 1/97: changed the return value to 501 instead of 1) */
+/* does: -SIN, -TAN, -ARC, -NCP, -GLS, -MER, -AIT projections */
+/* anything else is linear (== -CAR) */
+/* Input: */
+/* f xpix x pixel number (RA or long without rotation) */
+/* f ypiy y pixel number (dec or lat without rotation) */
+/* d xref x reference coordinate value (deg) */
+/* d yref y reference coordinate value (deg) */
+/* f xrefpix x reference pixel */
+/* f yrefpix y reference pixel */
+/* f xinc x coordinate increment (deg) */
+/* f yinc y coordinate increment (deg) */
+/* f rot rotation (deg) (from N through E) */
+/* c *type projection type code e.g. "-SIN"; */
+/* Output: */
+/* d *xpos x (RA) coordinate (deg) */
+/* d *ypos y (dec) coordinate (deg) */
+/*-----------------------------------------------------------------------*/
+ {double cosr, sinr, dx, dy, dz, temp, x, y, z;
+ double sins, coss, dect, rat, dt, l, m, mg, da, dd, cos0, sin0;
+ double dec0, ra0, decout, raout;
+ double geo1, geo2, geo3;
+ double cond2r=1.745329252e-2;
+ double twopi = 6.28318530717959, deps = 1.0e-5;
+ int i, itype;
+ char ctypes[9][5] ={"-CAR","-SIN","-TAN","-ARC","-NCP", "-GLS", "-MER",
+ "-AIT", "-STG"};
+
+ if (*status > 0)
+ return(*status);
+
+/* Offset from ref pixel */
+ dx = (xpix-xrefpix) * xinc;
+ dy = (ypix-yrefpix) * yinc;
+/* Take out rotation */
+ cosr = cos(rot*cond2r);
+ sinr = sin(rot*cond2r);
+ if (rot!=0.0)
+ {temp = dx * cosr - dy * sinr;
+ dy = dy * cosr + dx * sinr;
+ dx = temp;}
+/* find type */
+/* WDP 1/97: removed support for default type for better error checking */
+/* itype = 0; default type is linear */
+ itype = -1; /* no default type */
+ for (i=0;i<9;i++) if (!strncmp(type, ctypes[i], 4)) itype = i;
+/* default, linear result for error return */
+ *xpos = xref + dx;
+ *ypos = yref + dy;
+/* convert to radians */
+ ra0 = xref * cond2r;
+ dec0 = yref * cond2r;
+ l = dx * cond2r;
+ m = dy * cond2r;
+ sins = l*l + m*m;
+ cos0 = cos(dec0);
+ sin0 = sin(dec0);
+
+/* process by case */
+ switch (itype) {
+ case 0: /* linear -CAR */
+ rat = ra0 + l;
+ dect = dec0 + m;
+ break;
+ case 1: /* -SIN sin*/
+ if (sins>1.0) return(*status = 501);
+ coss = sqrt (1.0 - sins);
+ dt = sin0 * coss + cos0 * m;
+ if ((dt>1.0) || (dt<-1.0)) return(*status = 501);
+ dect = asin (dt);
+ rat = cos0 * coss - sin0 * m;
+ if ((rat==0.0) && (l==0.0)) return(*status = 501);
+ rat = atan2 (l, rat) + ra0;
+ break;
+ case 2: /* -TAN tan */
+ x = cos0*cos(ra0) - l*sin(ra0) - m*cos(ra0)*sin0;
+ y = cos0*sin(ra0) + l*cos(ra0) - m*sin(ra0)*sin0;
+ z = sin0 + m* cos0;
+ rat = atan2( y, x );
+ dect = atan ( z / sqrt(x*x+y*y) );
+ break;
+ case 3: /* -ARC Arc*/
+ if (sins>=twopi*twopi/4.0) return(*status = 501);
+ 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(*status = 501);
+ dect = asin (dt);
+ da = coss - dt * sin0;
+ dt = l * sins * cos0;
+ if ((da==0.0) && (dt==0.0)) return(*status = 501);
+ rat = ra0 + atan2 (dt, da);
+ break;
+ case 4: /* -NCP North celestial pole*/
+ dect = cos0 - m * sin0;
+ if (dect==0.0) return(*status = 501);
+ rat = ra0 + atan2 (l, dect);
+ dt = cos (rat-ra0);
+ if (dt==0.0) return(*status = 501);
+ dect = dect / dt;
+ if ((dect>1.0) || (dect<-1.0)) return(*status = 501);
+ dect = acos (dect);
+ if (dec0<0.0) dect = -dect;
+ break;
+ case 5: /* -GLS global sinusoid */
+ dect = dec0 + m;
+ if (fabs(dect)>twopi/4.0) return(*status = 501);
+ coss = cos (dect);
+ if (fabs(l)>twopi*coss/2.0) return(*status = 501);
+ rat = ra0;
+ if (coss>deps) rat = rat + l / coss;
+ break;
+ case 6: /* -MER mercator*/
+ dt = yinc * cosr + xinc * sinr;
+ if (dt==0.0) dt = 1.0;
+ dy = (yref/2.0 + 45.0) * cond2r;
+ dx = dy + dt / 2.0 * cond2r;
+ dy = log (tan (dy));
+ dx = log (tan (dx));
+ geo2 = dt * cond2r / (dx - dy);
+ geo3 = geo2 * dy;
+ geo1 = cos (yref*cond2r);
+ if (geo1<=0.0) geo1 = 1.0;
+ rat = l / geo1 + ra0;
+ if (fabs(rat - ra0) > twopi) return(*status = 501); /* 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 7: /* -AIT Aitoff*/
+ dt = yinc*cosr + xinc*sinr;
+ if (dt==0.0) dt = 1.0;
+ dt = dt * cond2r;
+ dy = yref * cond2r;
+ 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 = dt * cond2r;
+ 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(*status = 501);;
+ dz = 0.5 * sqrt (dz);
+ dd = (m+geo3) * dz / geo2;
+ if (fabs(dd)>1.0) return(*status = 501);;
+ dd = asin (dd);
+ if (fabs(cos(dd))<deps) return(*status = 501);;
+ da = l * dz / (2.0 * geo1 * cos(dd));
+ if (fabs(da)>1.0) return(*status = 501);;
+ da = asin (da);
+ rat = ra0 + 2.0 * da;
+ dect = dd;
+ break;
+ case 8: /* -STG Sterographic*/
+ dz = (4.0 - sins) / (4.0 + sins);
+ if (fabs(dz)>1.0) return(*status = 501);
+ dect = dz * sin0 + m * cos0 * (1.0+dz) / 2.0;
+ if (fabs(dect)>1.0) return(*status = 501);
+ dect = asin (dect);
+ rat = cos(dect);
+ if (fabs(rat)<deps) return(*status = 501);
+ rat = l * (1.0+dz) / (2.0 * rat);
+ if (fabs(rat)>1.0) return(*status = 501);
+ rat = asin (rat);
+ mg = 1.0 + sin(dect) * sin0 + cos(dect) * cos0 * cos(rat);
+ if (fabs(mg)<deps) return(*status = 501);
+ 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;
+
+ default:
+ /* fall through to here on error */
+ return(*status = 504);
+ }
+
+/* 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 */
+
+/* correct units back to degrees */
+ *xpos = raout / cond2r;
+ *ypos = decout / cond2r;
+ return(*status);
+} /* End of worldpos */
+/*--------------------------------------------------------------------------*/
+int ffxypx(double xpos, double ypos, double xref, double yref,
+ double xrefpix, double yrefpix, double xinc, double yinc, double rot,
+ char *type, double *xpix, double *ypix, int *status)
+/* WDP 1/97: changed name of routine from xypix to ffxypx */
+/*-----------------------------------------------------------------------*/
+/* 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 */
+/* WDP 1/97: changed the return values to 501 and 502 instead of 1 and 2 */
+/* does: -SIN, -TAN, -ARC, -NCP, -GLS, -MER, -AIT projections */
+/* anything else is linear */
+/* Input: */
+/* d xpos x (RA) coordinate (deg) */
+/* d ypos y (dec) coordinate (deg) */
+/* d xref x reference coordinate value (deg) */
+/* d yref y reference coordinate value (deg) */
+/* f xrefpix x reference pixel */
+/* f yrefpix y reference pixel */
+/* f xinc x coordinate increment (deg) */
+/* f yinc y coordinate increment (deg) */
+/* f rot rotation (deg) (from N through E) */
+/* c *type projection type code e.g. "-SIN"; */
+/* Output: */
+/* f *xpix x pixel number (RA or long without rotation) */
+/* f *ypiy y pixel number (dec or lat without rotation) */
+/*-----------------------------------------------------------------------*/
+ {double dx, dy, dz, r, ra0, dec0, ra, dec, coss, sins, dt, da, dd, sint;
+ double l, m, geo1, geo2, geo3, sinr, cosr, cos0, sin0;
+ double cond2r=1.745329252e-2, deps=1.0e-5, twopi=6.28318530717959;
+ int i, itype;
+ char ctypes[9][5] ={"-CAR","-SIN","-TAN","-ARC","-NCP", "-GLS", "-MER",
+ "-AIT", "-STG"};
+
+ /* 0h wrap-around tests added by D.Wells 10/12/94: */
+ dt = (xpos - xref);
+ if (dt > 180) xpos -= 360;
+ if (dt < -180) xpos += 360;
+ /* NOTE: changing input argument xpos is OK (call-by-value in C!) */
+
+/* default values - linear */
+ dx = xpos - xref;
+ dy = ypos - yref;
+/* dz = 0.0; */
+/* Correct for rotation */
+ r = rot * cond2r;
+ cosr = cos (r);
+ sinr = sin (r);
+ dz = dx*cosr + dy*sinr;
+ dy = dy*cosr - dx*sinr;
+ dx = dz;
+/* check axis increments - bail out if either 0 */
+ if ((xinc==0.0) || (yinc==0.0)) {*xpix=0.0; *ypix=0.0; return(*status = 502);}
+/* convert to pixels */
+ *xpix = dx / xinc + xrefpix;
+ *ypix = dy / yinc + yrefpix;
+
+/* find type */
+/* WDP 1/97: removed support for default type for better error checking */
+/* itype = 0; default type is linear */
+ itype = -1; /* no default type */
+ for (i=0;i<9;i++) if (!strncmp(type, ctypes[i], 4)) itype = i;
+ if (itype==0) return(*status); /* done if linear */
+
+/* Non linear position */
+ ra0 = xref * cond2r;
+ dec0 = yref * cond2r;
+ ra = xpos * cond2r;
+ dec = ypos * cond2r;
+
+/* compute direction cosine */
+ coss = cos (dec);
+ sins = sin (dec);
+ cos0 = cos (dec0);
+ sin0 = sin (dec0);
+ l = sin(ra-ra0) * coss;
+ sint = sins * sin0 + coss * cos0 * cos(ra-ra0);
+
+/* process by case */
+ switch (itype) {
+ case 1: /* -SIN sin*/
+ if (sint<0.0) return(*status = 501);
+ m = sins * cos(dec0) - coss * sin(dec0) * cos(ra-ra0);
+ break;
+ case 2: /* -TAN tan */
+ if (sint<=0.0) return(*status = 501);
+ if( cos0<0.001 ) {
+ /* Do a first order expansion around pole */
+ m = (coss * cos(ra-ra0)) / (sins * sin0);
+ m = (-m + cos0 * (1.0 + m*m)) / sin0;
+ } else {
+ m = ( sins/sint - sin0 ) / cos0;
+ }
+ if( fabs(sin(ra0)) < 0.3 ) {
+ l = coss*sin(ra)/sint - cos0*sin(ra0) + m*sin(ra0)*sin0;
+ l /= cos(ra0);
+ } else {
+ l = coss*cos(ra)/sint - cos0*cos(ra0) + m*cos(ra0)*sin0;
+ l /= -sin(ra0);
+ }
+ break;
+ case 3: /* -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 4: /* -NCP North celestial pole*/
+ if (dec0==0.0)
+ return(*status = 501); /* can't stand the equator */
+ else
+ m = (cos(dec0) - coss * cos(ra-ra0)) / sin(dec0);
+ break;
+ case 5: /* -GLS global sinusoid */
+ dt = ra - ra0;
+ if (fabs(dec)>twopi/4.0) return(*status = 501);
+ if (fabs(dec0)>twopi/4.0) return(*status = 501);
+ m = dec - dec0;
+ l = dt * coss;
+ break;
+ case 6: /* -MER mercator*/
+ dt = yinc * cosr + xinc * sinr;
+ if (dt==0.0) dt = 1.0;
+ dy = (yref/2.0 + 45.0) * cond2r;
+ dx = dy + dt / 2.0 * cond2r;
+ dy = log (tan (dy));
+ dx = log (tan (dx));
+ geo2 = dt * cond2r / (dx - dy);
+ geo3 = geo2 * dy;
+ geo1 = cos (yref*cond2r);
+ 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(*status = 502);
+ m = geo2 * log (dt) - geo3;
+ break;
+ case 7: /* -AIT Aitoff*/
+ da = (ra - ra0) / 2.0;
+ if (fabs(da)>twopi/4.0) return(*status = 501);
+ dt = yinc*cosr + xinc*sinr;
+ if (dt==0.0) dt = 1.0;
+ dt = dt * cond2r;
+ dy = yref * cond2r;
+ 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 = dt * cond2r;
+ 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(*status = 503);
+ l = 2.0 * geo1 * cos(dec) * sin(da) / dt;
+ m = geo2 * sin(dec) / dt - geo3;
+ break;
+ case 8: /* -STG Sterographic*/
+ da = ra - ra0;
+ if (fabs(dec)>twopi/4.0) return(*status = 501);
+ dd = 1.0 + sins * sin(dec0) + coss * cos(dec0) * cos(da);
+ if (fabs(dd)<deps) return(*status = 501);
+ dd = 2.0 / dd;
+ l = l * dd;
+ m = dd * (sins * cos(dec0) - coss * sin(dec0) * cos(da));
+ break;
+
+ default:
+ /* fall through to here on error */
+ return(*status = 504);
+
+ } /* end of itype switch */
+
+/* back to degrees */
+ dx = l / cond2r;
+ dy = m / cond2r;
+/* Correct for rotation */
+ dz = dx*cosr + dy*sinr;
+ dy = dy*cosr - dx*sinr;
+ dx = dz;
+/* convert to pixels */
+ *xpix = dx / xinc + xrefpix;
+ *ypix = dy / yinc + yrefpix;
+ return(*status);
+} /* end xypix */
diff --git a/pkg/tbtables/cfitsio/winDumpExts.mak b/pkg/tbtables/cfitsio/winDumpExts.mak
new file mode 100644
index 00000000..84e79aed
--- /dev/null
+++ b/pkg/tbtables/cfitsio/winDumpExts.mak
@@ -0,0 +1,191 @@
+# Microsoft Developer Studio Generated NMAKE File, Based on winDumpExts.dsp
+!IF "$(CFG)" == ""
+CFG=winDumpExts - Win32 Debug
+!MESSAGE No configuration specified. Defaulting to winDumpExts - Win32 Debug.
+!ENDIF
+
+!IF "$(CFG)" != "winDumpExts - Win32 Release" && "$(CFG)" != "winDumpExts - Win32 Debug"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "winDumpExts.mak" CFG="winDumpExts - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "winDumpExts - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "winDumpExts - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+!ERROR An invalid configuration is specified.
+!ENDIF
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+
+!IF "$(CFG)" == "winDumpExts - Win32 Release"
+
+OUTDIR=.\Release
+INTDIR=.\Release
+# Begin Custom Macros
+OutDir=.\Release
+# End Custom Macros
+
+ALL : "$(OUTDIR)\winDumpExts.exe"
+
+
+CLEAN :
+ -@erase "$(INTDIR)\vc60.idb"
+ -@erase "$(INTDIR)\winDumpExts.obj"
+ -@erase "$(OUTDIR)\winDumpExts.exe"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+"$(INTDIR)" :
+ if not exist "$(INTDIR)/$(NULL)" mkdir "$(INTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /ML /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Fp"$(INTDIR)\winDumpExts.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+RSC=rc.exe
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\winDumpExts.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /incremental:no /pdb:"$(OUTDIR)\winDumpExts.pdb" /machine:I386 /out:"$(OUTDIR)\winDumpExts.exe"
+LINK32_OBJS= \
+ "$(INTDIR)\winDumpExts.obj"
+
+"$(OUTDIR)\winDumpExts.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ELSEIF "$(CFG)" == "winDumpExts - Win32 Debug"
+
+OUTDIR=.
+INTDIR=.\Debug
+# Begin Custom Macros
+OutDir=.
+# End Custom Macros
+
+ALL : "$(OUTDIR)\winDumpExts.exe"
+
+
+CLEAN :
+ -@erase "$(INTDIR)\vc60.idb"
+ -@erase "$(INTDIR)\vc60.pdb"
+ -@erase "$(INTDIR)\winDumpExts.obj"
+ -@erase "$(OUTDIR)\winDumpExts.exe"
+ -@erase "$(OUTDIR)\winDumpExts.ilk"
+ -@erase "$(OUTDIR)\winDumpExts.pdb"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+"$(INTDIR)" :
+ if not exist "$(INTDIR)/$(NULL)" mkdir "$(INTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MLd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Fp"$(INTDIR)\winDumpExts.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /GZ /c
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+RSC=rc.exe
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\winDumpExts.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /incremental:yes /pdb:"$(OUTDIR)\winDumpExts.pdb" /debug /machine:I386 /out:"$(OUTDIR)\winDumpExts.exe" /pdbtype:sept
+LINK32_OBJS= \
+ "$(INTDIR)\winDumpExts.obj"
+
+"$(OUTDIR)\winDumpExts.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ENDIF
+
+
+!IF "$(NO_EXTERNAL_DEPS)" != "1"
+!IF EXISTS("winDumpExts.dep")
+!INCLUDE "winDumpExts.dep"
+!ELSE
+!MESSAGE Warning: cannot find "winDumpExts.dep"
+!ENDIF
+!ENDIF
+
+
+!IF "$(CFG)" == "winDumpExts - Win32 Release" || "$(CFG)" == "winDumpExts - Win32 Debug"
+SOURCE=.\winDumpExts.c
+
+"$(INTDIR)\winDumpExts.obj" : $(SOURCE) "$(INTDIR)"
+
+
+
+!ENDIF
+
diff --git a/pkg/tbtables/cfitsio/windumpexts.c b/pkg/tbtables/cfitsio/windumpexts.c
new file mode 100644
index 00000000..1ea527b9
--- /dev/null
+++ b/pkg/tbtables/cfitsio/windumpexts.c
@@ -0,0 +1,503 @@
+/*
+ * winDumpExts.c --
+ * Author: Gordon Chaffee, Scott Stanton
+ *
+ * History: The real functionality of this file was written by
+ * Matt Pietrek in 1993 in his pedump utility. I've
+ * modified it to dump the externals in a bunch of object
+ * files to create a .def file.
+ *
+ * 10/12/95 Modified by Scott Stanton to support Relocatable Object Module
+ * Format files for Borland C++ 4.5.
+ *
+ * Notes: Visual C++ puts an underscore before each exported symbol.
+ * This file removes them. I don't know if this is a problem
+ * this other compilers. If _MSC_VER is defined,
+ * the underscore is removed. If not, it isn't. To get a
+ * full dump of an object file, use the -f option. This can
+ * help determine the something that may be different with a
+ * compiler other than Visual C++.
+ *----------------------------------------------------------------------
+ *
+ * RCS: @(#) $Id: windumpexts.c,v 1.2 2002/02/22 14:16:05 hodge Exp $
+ */
+
+#include <windows.h>
+#include <stdio.h>
+#include <string.h>
+#include <process.h>
+
+#ifdef _ALPHA_
+#define e_magic_number IMAGE_FILE_MACHINE_ALPHA
+#else
+#define e_magic_number IMAGE_FILE_MACHINE_I386
+#endif
+
+/*
+ *----------------------------------------------------------------------
+ * GetArgcArgv --
+ *
+ * Break up a line into argc argv
+ *----------------------------------------------------------------------
+ */
+int
+GetArgcArgv(char *s, char **argv)
+{
+ int quote = 0;
+ int argc = 0;
+ char *bp;
+
+ bp = s;
+ while (1) {
+ while (isspace(*bp)) {
+ bp++;
+ }
+ if (*bp == '\n' || *bp == '\0') {
+ *bp = '\0';
+ return argc;
+ }
+ if (*bp == '\"') {
+ quote = 1;
+ bp++;
+ }
+ argv[argc++] = bp;
+
+ while (*bp != '\0') {
+ if (quote) {
+ if (*bp == '\"') {
+ quote = 0;
+ *bp = '\0';
+ bp++;
+ break;
+ }
+ bp++;
+ continue;
+ }
+ if (isspace(*bp)) {
+ *bp = '\0';
+ bp++;
+ break;
+ }
+ bp++;
+ }
+ }
+}
+
+/*
+ * The names of the first group of possible symbol table storage classes
+ */
+char * SzStorageClass1[] = {
+ "NULL","AUTOMATIC","EXTERNAL","STATIC","REGISTER","EXTERNAL_DEF","LABEL",
+ "UNDEFINED_LABEL","MEMBER_OF_STRUCT","ARGUMENT","STRUCT_TAG",
+ "MEMBER_OF_UNION","UNION_TAG","TYPE_DEFINITION","UNDEFINED_STATIC",
+ "ENUM_TAG","MEMBER_OF_ENUM","REGISTER_PARAM","BIT_FIELD"
+};
+
+/*
+ * The names of the second group of possible symbol table storage classes
+ */
+char * SzStorageClass2[] = {
+ "BLOCK","FUNCTION","END_OF_STRUCT","FILE","SECTION","WEAK_EXTERNAL"
+};
+
+/*
+ *----------------------------------------------------------------------
+ * GetSZStorageClass --
+ *
+ * Given a symbol storage class value, return a descriptive
+ * ASCII string
+ *----------------------------------------------------------------------
+ */
+PSTR
+GetSZStorageClass(BYTE storageClass)
+{
+ if ( storageClass <= IMAGE_SYM_CLASS_BIT_FIELD )
+ return SzStorageClass1[storageClass];
+ else if ( (storageClass >= IMAGE_SYM_CLASS_BLOCK)
+ && (storageClass <= IMAGE_SYM_CLASS_WEAK_EXTERNAL) )
+ return SzStorageClass2[storageClass-IMAGE_SYM_CLASS_BLOCK];
+ else
+ return "???";
+}
+
+/*
+ *----------------------------------------------------------------------
+ * GetSectionName --
+ *
+ * Used by DumpSymbolTable, it gives meaningful names to
+ * the non-normal section number.
+ *
+ * Results:
+ * A name is returned in buffer
+ *----------------------------------------------------------------------
+ */
+void
+GetSectionName(WORD section, PSTR buffer, unsigned cbBuffer)
+{
+ char tempbuffer[10];
+
+ switch ( (SHORT)section )
+ {
+ case IMAGE_SYM_UNDEFINED: strcpy(tempbuffer, "UNDEF"); break;
+ case IMAGE_SYM_ABSOLUTE: strcpy(tempbuffer, "ABS "); break;
+ case IMAGE_SYM_DEBUG: strcpy(tempbuffer, "DEBUG"); break;
+ default: wsprintf(tempbuffer, "%-5X", section);
+ }
+
+ strncpy(buffer, tempbuffer, cbBuffer-1);
+}
+
+/*
+ *----------------------------------------------------------------------
+ * DumpSymbolTable --
+ *
+ * Dumps a COFF symbol table from an EXE or OBJ. We only use
+ * it to dump tables from OBJs.
+ *----------------------------------------------------------------------
+ */
+void
+DumpSymbolTable(PIMAGE_SYMBOL pSymbolTable, FILE *fout, unsigned cSymbols)
+{
+ unsigned i;
+ PSTR stringTable;
+ char sectionName[10];
+
+ fprintf(fout, "Symbol Table - %X entries (* = auxillary symbol)\n",
+ cSymbols);
+
+ fprintf(fout,
+ "Indx Name Value Section cAux Type Storage\n"
+ "---- -------------------- -------- ---------- ----- ------- --------\n");
+
+ /*
+ * The string table apparently starts right after the symbol table
+ */
+ stringTable = (PSTR)&pSymbolTable[cSymbols];
+
+ for ( i=0; i < cSymbols; i++ ) {
+ fprintf(fout, "%04X ", i);
+ if ( pSymbolTable->N.Name.Short != 0 )
+ fprintf(fout, "%-20.8s", pSymbolTable->N.ShortName);
+ else
+ fprintf(fout, "%-20s", stringTable + pSymbolTable->N.Name.Long);
+
+ fprintf(fout, " %08X", pSymbolTable->Value);
+
+ GetSectionName(pSymbolTable->SectionNumber, sectionName,
+ sizeof(sectionName));
+ fprintf(fout, " sect:%s aux:%X type:%02X st:%s\n",
+ sectionName,
+ pSymbolTable->NumberOfAuxSymbols,
+ pSymbolTable->Type,
+ GetSZStorageClass(pSymbolTable->StorageClass) );
+#if 0
+ if ( pSymbolTable->NumberOfAuxSymbols )
+ DumpAuxSymbols(pSymbolTable);
+#endif
+
+ /*
+ * Take into account any aux symbols
+ */
+ i += pSymbolTable->NumberOfAuxSymbols;
+ pSymbolTable += pSymbolTable->NumberOfAuxSymbols;
+ pSymbolTable++;
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ * DumpExternals --
+ *
+ * Dumps a COFF symbol table from an EXE or OBJ. We only use
+ * it to dump tables from OBJs.
+ *----------------------------------------------------------------------
+ */
+void
+DumpExternals(PIMAGE_SYMBOL pSymbolTable, FILE *fout, unsigned cSymbols)
+{
+ unsigned i;
+ PSTR stringTable;
+ char *s, *f;
+ char symbol[1024];
+
+ /*
+ * The string table apparently starts right after the symbol table
+ */
+ stringTable = (PSTR)&pSymbolTable[cSymbols];
+
+ for ( i=0; i < cSymbols; i++ ) {
+ if (pSymbolTable->SectionNumber > 0 && pSymbolTable->Type == 0x20) {
+ if (pSymbolTable->StorageClass == IMAGE_SYM_CLASS_EXTERNAL) {
+ if (pSymbolTable->N.Name.Short != 0) {
+ strncpy(symbol, pSymbolTable->N.ShortName, 8);
+ symbol[8] = 0;
+ } else {
+ s = stringTable + pSymbolTable->N.Name.Long;
+ strcpy(symbol, s);
+ }
+ s = symbol;
+ f = strchr(s, '@');
+ if (f) {
+ *f = 0;
+ }
+#if defined(_MSC_VER) && defined(_X86_)
+ if (symbol[0] == '_') {
+ s = &symbol[1];
+ }
+#endif
+ if ((stricmp(s, "DllEntryPoint") != 0)
+ && (stricmp(s, "DllMain") != 0)) {
+ fprintf(fout, "\t%s\n", s);
+ }
+ }
+ }
+
+ /*
+ * Take into account any aux symbols
+ */
+ i += pSymbolTable->NumberOfAuxSymbols;
+ pSymbolTable += pSymbolTable->NumberOfAuxSymbols;
+ pSymbolTable++;
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ * DumpObjFile --
+ *
+ * Dump an object file--either a full listing or just the exported
+ * symbols.
+ *----------------------------------------------------------------------
+ */
+void
+DumpObjFile(PIMAGE_FILE_HEADER pImageFileHeader, FILE *fout, int full)
+{
+ PIMAGE_SYMBOL PCOFFSymbolTable;
+ DWORD COFFSymbolCount;
+
+ PCOFFSymbolTable = (PIMAGE_SYMBOL)
+ ((DWORD)pImageFileHeader + pImageFileHeader->PointerToSymbolTable);
+ COFFSymbolCount = pImageFileHeader->NumberOfSymbols;
+
+ if (full) {
+ DumpSymbolTable(PCOFFSymbolTable, fout, COFFSymbolCount);
+ } else {
+ DumpExternals(PCOFFSymbolTable, fout, COFFSymbolCount);
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ * SkipToNextRecord --
+ *
+ * Skip over the current ROMF record and return the type of the
+ * next record.
+ *----------------------------------------------------------------------
+ */
+
+BYTE
+SkipToNextRecord(BYTE **ppBuffer)
+{
+ int length;
+ (*ppBuffer)++; /* Skip over the type.*/
+ length = *((WORD*)(*ppBuffer))++; /* Retrieve the length. */
+ *ppBuffer += length; /* Skip over the rest. */
+ return **ppBuffer; /* Return the type. */
+}
+
+/*
+ *----------------------------------------------------------------------
+ * DumpROMFObjFile --
+ *
+ * Dump a Relocatable Object Module Format file, displaying only
+ * the exported symbols.
+ *----------------------------------------------------------------------
+ */
+void
+DumpROMFObjFile(LPVOID pBuffer, FILE *fout)
+{
+ BYTE type, length;
+ char symbol[1024], *s;
+
+ while (1) {
+ type = SkipToNextRecord(&(BYTE*)pBuffer);
+ if (type == 0x90) { /* PUBDEF */
+ if (((BYTE*)pBuffer)[4] != 0) {
+ length = ((BYTE*)pBuffer)[5];
+ strncpy(symbol, ((char*)pBuffer) + 6, length);
+ symbol[length] = '\0';
+ s = symbol;
+ if ((stricmp(s, "DllEntryPoint") != 0)
+ && (stricmp(s, "DllMain") != 0)) {
+ if (s[0] == '_') {
+ s++;
+ fprintf(fout, "\t_%s\n\t%s=_%s\n", s, s, s);
+ } else {
+ fprintf(fout, "\t%s\n", s);
+ }
+ }
+ }
+ } else if (type == 0x8B || type == 0x8A) { /* MODEND */
+ break;
+ }
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ * DumpFile --
+ *
+ * Open up a file, memory map it, and call the appropriate
+ * dumping routine
+ *----------------------------------------------------------------------
+ */
+void
+DumpFile(LPSTR filename, FILE *fout, int full)
+{
+ HANDLE hFile;
+ HANDLE hFileMapping;
+ LPVOID lpFileBase;
+ PIMAGE_DOS_HEADER dosHeader;
+
+ hFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL,
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
+
+ if (hFile == INVALID_HANDLE_VALUE) {
+ fprintf(stderr, "Couldn't open file with CreateFile()\n");
+ return;
+ }
+
+ hFileMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
+ if (hFileMapping == 0) {
+ CloseHandle(hFile);
+ fprintf(stderr, "Couldn't open file mapping with CreateFileMapping()\n");
+ return;
+ }
+
+ lpFileBase = MapViewOfFile(hFileMapping, FILE_MAP_READ, 0, 0, 0);
+ if (lpFileBase == 0) {
+ CloseHandle(hFileMapping);
+ CloseHandle(hFile);
+ fprintf(stderr, "Couldn't map view of file with MapViewOfFile()\n");
+ return;
+ }
+
+ dosHeader = (PIMAGE_DOS_HEADER)lpFileBase;
+ if (dosHeader->e_magic == IMAGE_DOS_SIGNATURE) {
+#if 0
+ DumpExeFile( dosHeader );
+#else
+ fprintf(stderr, "File is an executable. I don't dump those.\n");
+ return;
+#endif
+ }
+ /* Does it look like a i386 COFF OBJ file??? */
+ else if ((dosHeader->e_magic == e_magic_number)
+ && (dosHeader->e_sp == 0)) {
+ /*
+ * The two tests above aren't what they look like. They're
+ * really checking for IMAGE_FILE_HEADER.Machine == i386 (0x14C)
+ * and IMAGE_FILE_HEADER.SizeOfOptionalHeader == 0;
+ */
+ DumpObjFile((PIMAGE_FILE_HEADER) lpFileBase, fout, full);
+ } else if (*((BYTE *)lpFileBase) == 0x80) {
+ /*
+ * This file looks like it might be a ROMF file.
+ */
+ DumpROMFObjFile(lpFileBase, fout);
+ } else {
+ printf("unrecognized file format\n");
+ }
+ UnmapViewOfFile(lpFileBase);
+ CloseHandle(hFileMapping);
+ CloseHandle(hFile);
+}
+
+void
+main(int argc, char **argv)
+{
+ char *fargv[1000];
+ char cmdline[10000];
+ int i, arg;
+ FILE *fout;
+ int pos;
+ int full = 0;
+ char *outfile = NULL;
+
+ if (argc < 3) {
+ Usage:
+ fprintf(stderr, "Usage: %s ?-o outfile? ?-f(ull)? <dllname> <object filenames> ..\n", argv[0]);
+ exit(1);
+ }
+
+ arg = 1;
+ while (argv[arg][0] == '-') {
+ if (strcmp(argv[arg], "--") == 0) {
+ arg++;
+ break;
+ } else if (strcmp(argv[arg], "-f") == 0) {
+ full = 1;
+ } else if (strcmp(argv[arg], "-o") == 0) {
+ arg++;
+ if (arg == argc) {
+ goto Usage;
+ }
+ outfile = argv[arg];
+ }
+ arg++;
+ }
+ if (arg == argc) {
+ goto Usage;
+ }
+
+ if (outfile) {
+ fout = fopen(outfile, "w+");
+ if (fout == NULL) {
+ fprintf(stderr, "Unable to open \'%s\' for writing:\n",
+ argv[arg]);
+ perror("");
+ exit(1);
+ }
+ } else {
+ fout = stdout;
+ }
+
+ if (! full) {
+ char *dllname = argv[arg];
+ arg++;
+ if (arg == argc) {
+ goto Usage;
+ }
+ fprintf(fout, "LIBRARY %s\n", dllname);
+ fprintf(fout, "EXETYPE WINDOWS\n");
+ fprintf(fout, "CODE PRELOAD MOVEABLE DISCARDABLE\n");
+ fprintf(fout, "DATA PRELOAD MOVEABLE MULTIPLE\n\n");
+ fprintf(fout, "EXPORTS\n");
+ }
+
+ for (; arg < argc; arg++) {
+ if (argv[arg][0] == '@') {
+ FILE *fargs = fopen(&argv[arg][1], "r");
+ if (fargs == NULL) {
+ fprintf(stderr, "Unable to open \'%s\' for reading:\n",
+ argv[arg]);
+ perror("");
+ exit(1);
+ }
+ pos = 0;
+ for (i = 0; i < arg; i++) {
+ strcpy(&cmdline[pos], argv[i]);
+ pos += strlen(&cmdline[pos]) + 1;
+ fargv[i] = argv[i];
+ }
+ fgets(&cmdline[pos], sizeof(cmdline), fargs);
+ fprintf(stderr, "%s\n", &cmdline[pos]);
+ fclose(fargs);
+ i += GetArgcArgv(&cmdline[pos], &fargv[i]);
+ argc = i;
+ argv = fargv;
+ }
+ DumpFile(argv[arg], fout, full);
+ }
+ exit(0);
+}